@@ -474,6 +474,172 @@ impl Resolvable for crate::style::Rgb<u8> {
474
474
}
475
475
}
476
476
477
+ impl Resolvable for crate :: style:: gradient:: Dynterpolator {
478
+ fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
479
+ where
480
+ Self : Sized ,
481
+ {
482
+ let config = config
483
+ . as_object ( )
484
+ . ok_or_else ( || Error :: invalid_config ( "Expected object" , config) ) ?;
485
+ match config
486
+ . iter ( )
487
+ . next ( )
488
+ . map ( |( key, config) | ( key. as_str ( ) , config) )
489
+ . ok_or_else ( || Error :: invalid_config ( "Expected non-empty object" , config) ) ?
490
+ {
491
+ ( "radial" , config) => {
492
+ let radial: crate :: style:: gradient:: Radial = context. resolve ( config) ?;
493
+ Ok ( Box :: new ( radial) )
494
+ }
495
+ ( "angled" , config) => {
496
+ let angled: crate :: style:: gradient:: Angled = context. resolve ( config) ?;
497
+ Ok ( Box :: new ( angled) )
498
+ }
499
+ ( "bilinear" , config) => {
500
+ let bilinear: crate :: style:: gradient:: Bilinear = context. resolve ( config) ?;
501
+ Ok ( Box :: new ( bilinear) )
502
+ }
503
+ // TODO: Allow external libraries to define their own recipes to be used here?
504
+ // Something like a type-map of recipes?...
505
+ ( key, _) => Err ( Error :: invalid_config (
506
+ format ! ( "Received unsupported gradient type {key}." ) ,
507
+ config,
508
+ ) ) ,
509
+ }
510
+ }
511
+ }
512
+
513
+ impl Resolvable for crate :: style:: gradient:: Bilinear {
514
+ fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
515
+ where
516
+ Self : Sized ,
517
+ {
518
+ let top_left = context. resolve ( & config[ "top_left" ] ) ?;
519
+ let top_right = context. resolve ( & config[ "top_right" ] ) ?;
520
+ let bottom_right = context. resolve ( & config[ "bottom_right" ] ) ?;
521
+ let bottom_left = context. resolve ( & config[ "bottom_left" ] ) ?;
522
+ Ok ( Self {
523
+ top_left,
524
+ top_right,
525
+ bottom_right,
526
+ bottom_left,
527
+ } )
528
+ }
529
+ }
530
+
531
+ impl Resolvable for crate :: style:: gradient:: Angled {
532
+ fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
533
+ where
534
+ Self : Sized ,
535
+ {
536
+ let angle_rad = match context. resolve ( & config[ "angle_rad" ] ) {
537
+ Ok ( angle_rad) => angle_rad,
538
+ Err ( err1) => match context. resolve :: < f32 > ( & config[ "angle_deg" ] ) {
539
+ Ok ( angle_deg) => angle_deg * std:: f32:: consts:: PI / 180f32 ,
540
+ Err ( err2) => {
541
+ return Err ( Error :: AllVariantsFailed {
542
+ config : config. clone ( ) ,
543
+ errors : vec ! [ err1, err2] ,
544
+ } )
545
+ }
546
+ } ,
547
+ } ;
548
+ let gradient = context. resolve ( & config[ "gradient" ] ) ?;
549
+ Ok ( Self {
550
+ angle_rad,
551
+ gradient,
552
+ } )
553
+ }
554
+ }
555
+
556
+ impl Resolvable for crate :: style:: gradient:: Radial {
557
+ fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
558
+ where
559
+ Self : Sized ,
560
+ {
561
+ let center = context. resolve ( & config[ "center" ] ) ?;
562
+ let gradient = context. resolve ( & config[ "gradient" ] ) ?;
563
+ Ok ( Self { center, gradient } )
564
+ }
565
+ }
566
+
567
+ impl Resolvable for crate :: style:: gradient:: Linear {
568
+ fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
569
+ where
570
+ Self : Sized ,
571
+ {
572
+ use crate :: style:: Rgb ;
573
+
574
+ // Options:
575
+ // - A list of Rgb (evenly spaced)
576
+ // - A list of (f32, Rgb)
577
+ // - An object with start, end, and optionally middle, with a list of (f32, Rgb)
578
+ // - Some presets strings? Rainbow?
579
+ match config {
580
+ Config :: Array ( array) => {
581
+ let mut errors = Vec :: new ( ) ;
582
+
583
+ match array
584
+ . iter ( )
585
+ . map ( |config| context. resolve :: < Rgb < f32 > > ( config) )
586
+ . collect :: < Result < Vec < _ > , _ > > ( )
587
+ {
588
+ Ok ( colors) => return Ok ( Self :: evenly_spaced ( & colors) ) ,
589
+ Err ( err) => errors. push ( err) ,
590
+ }
591
+
592
+ match array
593
+ . iter ( )
594
+ . map ( |config| context. resolve ( config) )
595
+ . collect :: < Result < Vec < _ > , _ > > ( )
596
+ {
597
+ Ok ( points) => return Ok ( Self :: new ( points) ) ,
598
+ Err ( err) => errors. push ( err) ,
599
+ }
600
+
601
+ return Err ( Error :: AllVariantsFailed {
602
+ config : config. clone ( ) ,
603
+ errors,
604
+ } ) ;
605
+ }
606
+ Config :: Object ( object) => {
607
+ if let ( Some ( start) , Some ( end) ) = ( object. get ( "start" ) , object. get ( "end" ) ) {
608
+ return Ok ( Self :: simple (
609
+ context. resolve :: < Rgb < f32 > > ( start) ?,
610
+ context. resolve :: < Rgb < f32 > > ( end) ?,
611
+ ) ) ;
612
+ }
613
+
614
+ if let Some ( points) = object. get ( "points" ) {
615
+ let points = points
616
+ . as_array ( )
617
+ . ok_or_else ( || Error :: invalid_config ( "Expected array" , config) ) ?;
618
+
619
+ let points = points
620
+ . iter ( )
621
+ . map ( |config| context. resolve ( config) )
622
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
623
+
624
+ return Ok ( Self :: new ( points) ) ;
625
+ }
626
+ }
627
+ Config :: String ( string) => match string. as_str ( ) {
628
+ // TODO: Allow external libs to define their own aliases to resolve here?
629
+ "rainbow" => return Ok ( Self :: rainbow ( ) ) ,
630
+ "black_to_white" | "black to white" => return Ok ( Self :: black_to_white ( ) ) ,
631
+ _ => ( ) ,
632
+ } ,
633
+ _ => ( ) ,
634
+ }
635
+
636
+ Err ( Error :: invalid_config (
637
+ "Expected array, object or string" ,
638
+ config,
639
+ ) )
640
+ }
641
+ }
642
+
477
643
// ```yaml
478
644
// color: red
479
645
// color:
@@ -602,6 +768,45 @@ impl Resolvable for String {
602
768
}
603
769
}
604
770
771
+ impl < A , B > Resolvable for ( A , B )
772
+ where
773
+ A : Resolvable + ' static ,
774
+ B : Resolvable + ' static ,
775
+ {
776
+ fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
777
+ where
778
+ Self : Sized ,
779
+ {
780
+ let config = config
781
+ . as_array ( )
782
+ . ok_or_else ( || Error :: invalid_config ( "Expected array" , config) ) ?;
783
+
784
+ Ok ( ( context. resolve ( & config[ 0 ] ) ?, context. resolve ( & config[ 1 ] ) ?) )
785
+ }
786
+ }
787
+
788
+ impl < A , B , C > Resolvable for ( A , B , C )
789
+ where
790
+ A : Resolvable + ' static ,
791
+ B : Resolvable + ' static ,
792
+ C : Resolvable + ' static ,
793
+ {
794
+ fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
795
+ where
796
+ Self : Sized ,
797
+ {
798
+ let config = config
799
+ . as_array ( )
800
+ . ok_or_else ( || Error :: invalid_config ( "Expected array" , config) ) ?;
801
+
802
+ Ok ( (
803
+ context. resolve ( & config[ 0 ] ) ?,
804
+ context. resolve ( & config[ 1 ] ) ?,
805
+ context. resolve ( & config[ 2 ] ) ?,
806
+ ) )
807
+ }
808
+ }
809
+
605
810
impl Resolvable for crate :: utils:: markup:: StyledString {
606
811
fn from_config ( config : & Config , context : & Context ) -> Result < Self , Error >
607
812
where
0 commit comments