@@ -27,9 +27,9 @@ use crate::{
27
27
make_option_branching, make_result_branching, AddOperation , AsMap , Buffer , BufferKey ,
28
28
BufferKeys , Bufferable , Buffered , Builder , Collect , CreateCancelFilter , CreateDisposalFilter ,
29
29
ForkTargetStorage , Gate , GateRequest , InputSlot , IntoAsyncMap , IntoBlockingCallback ,
30
- IntoBlockingMap , Node , Noop , OperateBufferAccess , OperateDynamicGate , OperateStaticGate ,
31
- Output , ProvideOnce , Provider , Scope , ScopeSettings , Sendish , Service , Spread , StreamOf ,
32
- StreamPack , StreamTargetMap , Trim , TrimBranch , UnusedTarget ,
30
+ IntoBlockingMap , Node , Noop , OperateBufferAccess , OperateDynamicGate , OperateSplit ,
31
+ OperateStaticGate , Output , ProvideOnce , Provider , Scope , ScopeSettings , Sendish , Service ,
32
+ Spread , StreamOf , StreamPack , StreamTargetMap , Trim , TrimBranch , UnusedTarget ,
33
33
} ;
34
34
35
35
pub mod fork_clone_builder;
@@ -38,6 +38,9 @@ pub use fork_clone_builder::*;
38
38
pub ( crate ) mod premade;
39
39
use premade:: * ;
40
40
41
+ pub mod split;
42
+ pub use split:: * ;
43
+
41
44
pub mod unzip;
42
45
pub use unzip:: * ;
43
46
@@ -601,6 +604,71 @@ impl<'w, 's, 'a, 'b, T: 'static + Send + Sync> Chain<'w, 's, 'a, 'b, T> {
601
604
self . map_async ( |r| r)
602
605
}
603
606
607
+ /// If the chain's response implements the [`Splittable`] trait, then this
608
+ /// will insert a split operation and provide your `build` function with the
609
+ /// [`SplitBuilder`] for it. This returns the return value of your build
610
+ /// function.
611
+ pub fn split < U > ( self , build : impl FnOnce ( SplitBuilder < T > ) -> U ) -> U
612
+ where
613
+ T : Splittable ,
614
+ {
615
+ let source = self . target ;
616
+ self . builder . commands . add ( AddOperation :: new (
617
+ Some ( self . builder . scope ) ,
618
+ source,
619
+ OperateSplit :: < T > :: default ( ) ,
620
+ ) ) ;
621
+
622
+ build ( SplitBuilder :: new ( source, self . builder ) )
623
+ }
624
+
625
+ /// If the chain's response implements the [`Splittable`] trait, then this
626
+ /// will insert a split and provide a container for its available outputs.
627
+ /// To build connections to these outputs later, use [`SplitOutputs::build`].
628
+ ///
629
+ /// This is equivalent to
630
+ /// ```text
631
+ /// .split(|split| split.outputs())
632
+ /// ```
633
+ pub fn split_outputs ( self ) -> SplitOutputs < T >
634
+ where
635
+ T : Splittable ,
636
+ {
637
+ self . split ( |b| b. outputs ( ) )
638
+ }
639
+
640
+ /// If the chain's response can be turned into an iterator with an appropriate
641
+ /// item type, this will allow it to be split in a list-like way.
642
+ ///
643
+ /// This is equivalent to
644
+ /// ```text
645
+ /// .map_block(SplitAsList::new).split(build)
646
+ /// ```
647
+ pub fn split_as_list < U > ( self , build : impl FnOnce ( SplitBuilder < SplitAsList < T > > ) -> U ) -> U
648
+ where
649
+ T : IntoIterator ,
650
+ T :: Item : ' static + Send + Sync ,
651
+ {
652
+ self . map_block ( SplitAsList :: new) . split ( build)
653
+ }
654
+
655
+ /// If the chain's response can be turned into an iterator with an appropriate
656
+ /// item type, this will insert a split and provide a container for its
657
+ /// available outputs. To build connections to these outputs later, use
658
+ /// [`SplitOutputs::build`].
659
+ ///
660
+ /// This is equivalent to
661
+ /// ```text
662
+ /// .split_as_list(|split| split.outputs())
663
+ /// ```
664
+ pub fn split_as_list_outputs ( self ) -> SplitOutputs < SplitAsList < T > >
665
+ where
666
+ T : IntoIterator ,
667
+ T :: Item : ' static + Send + Sync ,
668
+ {
669
+ self . split_as_list ( |b| b. outputs ( ) )
670
+ }
671
+
604
672
/// Add a [no-op][1] to the current end of the chain.
605
673
///
606
674
/// As the name suggests, a no-op will not actually do anything, but it adds
@@ -633,10 +701,12 @@ impl<'w, 's, 'a, 'b, T: 'static + Send + Sync> Chain<'w, 's, 'a, 'b, T> {
633
701
}
634
702
}
635
703
704
+ /// The scope that the chain is building inside of.
636
705
pub fn scope ( & self ) -> Entity {
637
706
self . builder . scope
638
707
}
639
708
709
+ /// The target where the chain will be sending its latest output.
640
710
pub fn target ( & self ) -> Entity {
641
711
self . target
642
712
}
@@ -942,6 +1012,38 @@ where
942
1012
}
943
1013
}
944
1014
1015
+ impl < ' w , ' s , ' a , ' b , K , V , T > Chain < ' w , ' s , ' a , ' b , T >
1016
+ where
1017
+ K : ' static + Send + Sync + Eq + std:: hash:: Hash + Clone + std:: fmt:: Debug ,
1018
+ V : ' static + Send + Sync ,
1019
+ T : ' static + Send + Sync + IntoIterator < Item = ( K , V ) > ,
1020
+ {
1021
+ /// If the chain's response type can be turned into an iterator that returns
1022
+ /// `(key, value)` pairs, then this will split it in a map-like way, whether
1023
+ /// or not it is a conventional map data structure.
1024
+ ///
1025
+ /// This is equivalent to
1026
+ /// ```text
1027
+ /// .map_block(SplitAsMap::new).split(build)
1028
+ /// ```
1029
+ pub fn split_as_map < U > ( self , build : impl FnOnce ( SplitBuilder < SplitAsMap < K , V , T > > ) -> U ) -> U {
1030
+ self . map_block ( SplitAsMap :: new) . split ( build)
1031
+ }
1032
+
1033
+ /// If the chain's response type can be turned into an iterator that returns
1034
+ /// `(key, value)` pairs, then this will split it in a map-like way and
1035
+ /// provide a container for its available outputs. To build connections to
1036
+ /// these outputs later, use [`SplitOutputs::build`].
1037
+ ///
1038
+ /// This is equivalent to
1039
+ /// ```text
1040
+ /// .split_as_map(|split| split.outputs())
1041
+ /// ```
1042
+ pub fn split_as_map_outputs ( self ) -> SplitOutputs < SplitAsMap < K , V , T > > {
1043
+ self . split_as_map ( |b| b. outputs ( ) )
1044
+ }
1045
+ }
1046
+
945
1047
impl < ' w , ' s , ' a , ' b , Request , Response , Streams >
946
1048
Chain < ' w , ' s , ' a , ' b , ( Request , Service < Request , Response , Streams > ) >
947
1049
where
@@ -1030,6 +1132,24 @@ impl<'w, 's, 'a, 'b, T: 'static + Send + Sync> Chain<'w, 's, 'a, 'b, T> {
1030
1132
}
1031
1133
}
1032
1134
1135
+ impl < ' w , ' s , ' a , ' b , K , V > Chain < ' w , ' s , ' a , ' b , ( K , V ) >
1136
+ where
1137
+ K : ' static + Send + Sync ,
1138
+ V : ' static + Send + Sync ,
1139
+ {
1140
+ /// If the chain's response contains a `(key, value)` pair, get the `key`
1141
+ /// component from it (the first element of the tuple).
1142
+ pub fn key ( self ) -> Chain < ' w , ' s , ' a , ' b , K > {
1143
+ self . map_block ( |( key, _) | key)
1144
+ }
1145
+
1146
+ /// If the chain's response contains a `(key, value)` pair, get the `value`
1147
+ /// component from it (the second element of the tuple).
1148
+ pub fn value ( self ) -> Chain < ' w , ' s , ' a , ' b , V > {
1149
+ self . map_block ( |( _, value) | value)
1150
+ }
1151
+ }
1152
+
1033
1153
#[ cfg( test) ]
1034
1154
mod tests {
1035
1155
use crate :: { prelude:: * , testing:: * } ;
0 commit comments