@@ -25,10 +25,35 @@ pub trait NestedTupleOption {
2525 /// The transposed type: an option of the nested tuple of the inner types.
2626 type Transposed : IntoNestedTupleOption < IntoOptions = Self > ;
2727
28+ /// A nested homogeneous tuple type with the same shape as `Self` where each element is `H`.
29+ ///
30+ /// Example: for `Self = (Option<T>, (Option<U>,))` then
31+ /// `Self::SameDepth<H>` == `(H, (H,))`.
32+ type SameDepth < H > ;
33+
2834 /// Transposes the nested tuple of options into an option of the nested tuple.
2935 ///
3036 /// Returns `Some(nested_tuple)` if all elements are `Some`, otherwise `None`.
3137 fn transpose ( self ) -> Option < Self :: Transposed > ;
38+
39+ /// Given a parallel homogeneous nested tuple `xs` (same shape as `self`),
40+ /// returns the first `H` that corresponds to the first `None` in `self`,
41+ /// or `None` if no elements are `None`.
42+ fn first_none_with < H > ( self , xs : Self :: SameDepth < H > ) -> Option < H > ;
43+
44+ /// Given a parallel homogeneous nested tuple `xs` (same shape as `self`),
45+ /// returns the first `H` that corresponds to the first `Some` in `self`,
46+ /// or `None` if no elements are `Some`.
47+ fn first_some_with < H > ( self , xs : Self :: SameDepth < H > ) -> Option < H > ;
48+
49+ /// Like `transpose`, but returns a `Result` with `Ok(Transposed)` when all elements
50+ /// are `Some`, or `Err(H)` with the first `H` corresponding to the first `None`.
51+ ///
52+ /// # Errors
53+ ///
54+ /// Returns `Err(H)` if any element is `None`, where `H` is from the parallel
55+ /// homogeneous nested tuple `xs`.
56+ fn transpose_or < H > ( self , xs : Self :: SameDepth < H > ) -> Result < Self :: Transposed , H > ;
3257}
3358
3459/// A trait for converting nested tuples into nested tuples of options.
@@ -56,28 +81,73 @@ pub trait IntoNestedTupleOption {
5681
5782impl NestedTupleOption for ( ) {
5883 type Transposed = ( ) ;
84+ type SameDepth < H > = ( ) ;
5985
6086 #[ inline]
6187 fn transpose ( self ) -> Option < Self :: Transposed > {
6288 Some ( ( ) )
6389 }
90+
91+ #[ inline]
92+ fn first_none_with < H > ( self , _xs : Self :: SameDepth < H > ) -> Option < H > {
93+ None
94+ }
95+
96+ #[ inline]
97+ fn first_some_with < H > ( self , _xs : Self :: SameDepth < H > ) -> Option < H > {
98+ None
99+ }
100+
101+ #[ inline]
102+ fn transpose_or < H > ( self , _xs : Self :: SameDepth < H > ) -> Result < Self :: Transposed , H > {
103+ Ok ( ( ) )
104+ }
64105}
65106
66107impl < T > NestedTupleOption for ( Option < T > , ) {
67108 type Transposed = ( T , ) ;
109+ type SameDepth < H > = ( H , ) ;
68110
69111 #[ inline]
70112 fn transpose ( self ) -> Option < Self :: Transposed > {
71113 let ( opt, ) = self ;
72114 opt. map ( |t| ( t, ) )
73115 }
116+
117+ #[ inline]
118+ fn first_none_with < H > ( self , xs : Self :: SameDepth < H > ) -> Option < H > {
119+ let ( opt, ) = self ;
120+ let ( h, ) = xs;
121+ match opt {
122+ None => Some ( h) ,
123+ Some ( _) => None ,
124+ }
125+ }
126+
127+ #[ inline]
128+ fn first_some_with < H > ( self , xs : Self :: SameDepth < H > ) -> Option < H > {
129+ let ( opt, ) = self ;
130+ let ( h, ) = xs;
131+ opt. map ( |_| h)
132+ }
133+
134+ #[ inline]
135+ fn transpose_or < H > ( self , xs : Self :: SameDepth < H > ) -> Result < Self :: Transposed , H > {
136+ let ( opt, ) = self ;
137+ let ( h, ) = xs;
138+ match opt {
139+ Some ( t) => Ok ( ( t, ) ) ,
140+ None => Err ( h) ,
141+ }
142+ }
74143}
75144
76145impl < Head , Tail > NestedTupleOption for ( Option < Head > , Tail )
77146where
78147 Tail : NestedTupleOption ,
79148{
80149 type Transposed = ( Head , Tail :: Transposed ) ;
150+ type SameDepth < H > = ( H , Tail :: SameDepth < H > ) ;
81151
82152 #[ inline]
83153 fn transpose ( self ) -> Option < Self :: Transposed > {
@@ -87,6 +157,39 @@ where
87157 _ => None ,
88158 }
89159 }
160+
161+ #[ inline]
162+ fn first_none_with < H > ( self , xs : Self :: SameDepth < H > ) -> Option < H > {
163+ let ( head_opt, tail) = self ;
164+ let ( h_head, h_tail) = xs;
165+ match head_opt {
166+ None => Some ( h_head) ,
167+ Some ( _) => tail. first_none_with ( h_tail) ,
168+ }
169+ }
170+
171+ #[ inline]
172+ fn first_some_with < H > ( self , xs : Self :: SameDepth < H > ) -> Option < H > {
173+ let ( head_opt, tail) = self ;
174+ let ( h_head, h_tail) = xs;
175+ match head_opt {
176+ Some ( _) => Some ( h_head) ,
177+ None => tail. first_some_with ( h_tail) ,
178+ }
179+ }
180+
181+ #[ inline]
182+ fn transpose_or < H > ( self , xs : Self :: SameDepth < H > ) -> Result < Self :: Transposed , H > {
183+ let ( head_opt, tail) = self ;
184+ let ( h_head, h_tail) = xs;
185+ match head_opt {
186+ None => Err ( h_head) ,
187+ Some ( head) => match tail. transpose_or ( h_tail) {
188+ Ok ( tail_transposed) => Ok ( ( head, tail_transposed) ) ,
189+ Err ( h) => Err ( h) ,
190+ } ,
191+ }
192+ }
90193}
91194
92195// Implementations for IntoNestedTupleOption
@@ -124,6 +227,8 @@ where
124227#[ cfg( test) ]
125228mod tests {
126229 use super :: * ;
230+ #[ derive( Debug , PartialEq , Eq ) ]
231+ struct NoCopy ( i32 ) ;
127232
128233 #[ test]
129234 fn test_transpose_empty ( ) {
@@ -189,4 +294,86 @@ mod tests {
189294 let back = options. transpose ( ) . unwrap ( ) ;
190295 assert_eq ! ( original, back) ;
191296 }
297+
298+ #[ test]
299+ fn test_first_none_and_first_some_with_homogeneous ( ) {
300+ let options = ( Some ( 1 ) , ( None :: < i32 > , ( Some ( 3 ) , ) ) ) ;
301+ let hom = ( 10 , ( 20 , ( 30 , ) ) ) ;
302+ assert_eq ! ( options. first_none_with( hom) , Some ( 20 ) ) ;
303+
304+ let hom2 = ( 11 , ( 12 , ( 13 , ) ) ) ;
305+ assert_eq ! ( options. first_some_with( hom2) , Some ( 11 ) ) ;
306+ }
307+
308+ #[ test]
309+ fn test_all_some_first_none_returns_none ( ) {
310+ let options = ( Some ( 1 ) , ( Some ( 2 ) , ( Some ( 3 ) , ) ) ) ;
311+ let hom = ( 10 , ( 20 , ( 30 , ) ) ) ;
312+ assert_eq ! ( options. first_none_with( hom) , None ) ;
313+ }
314+
315+ #[ test]
316+ fn test_all_none_first_some_returns_none ( ) {
317+ let options = ( None :: < i32 > , ( None :: < i32 > , ( None :: < i32 > , ) ) ) ;
318+ let hom = ( 10 , ( 20 , ( 30 , ) ) ) ;
319+ assert_eq ! ( options. first_some_with( hom) , None ) ;
320+ }
321+
322+ #[ test]
323+ fn test_deeply_nested_first_none_prefers_leftmost ( ) {
324+ let options = ( Some ( 1 ) , ( None :: < i32 > , ( None :: < i32 > , ) ) ) ;
325+ let hom = ( 10 , ( 20 , ( 30 , ) ) ) ;
326+ assert_eq ! ( options. first_none_with( hom) , Some ( 20 ) ) ;
327+ }
328+
329+ #[ test]
330+ fn test_deeply_nested_first_some_returns_deeper_value_when_head_none ( ) {
331+ let options = ( None :: < i32 > , ( Some ( 2 ) , ( Some ( 3 ) , ) ) ) ;
332+ let hom = ( 10 , ( 20 , ( 30 , ) ) ) ;
333+ assert_eq ! ( options. first_some_with( hom) , Some ( 20 ) ) ;
334+ }
335+
336+ #[ test]
337+ fn test_first_none_with_noncopy_hom_movable ( ) {
338+ let options = ( Some ( 1 ) , ( None :: < i32 > , ( Some ( 3 ) , ) ) ) ;
339+ let hom = ( NoCopy ( 10 ) , ( NoCopy ( 20 ) , ( NoCopy ( 30 ) , ) ) ) ;
340+ assert_eq ! ( options. first_none_with( hom) , Some ( NoCopy ( 20 ) ) ) ;
341+ }
342+
343+ #[ test]
344+ fn test_first_some_with_noncopy_hom_movable ( ) {
345+ let options = ( None :: < i32 > , ( Some ( 2 ) , ( None :: < i32 > , ) ) ) ;
346+ let hom = ( NoCopy ( 11 ) , ( NoCopy ( 22 ) , ( NoCopy ( 33 ) , ) ) ) ;
347+ assert_eq ! ( options. first_some_with( hom) , Some ( NoCopy ( 22 ) ) ) ;
348+ }
349+
350+ #[ test]
351+ fn test_all_none_first_none_returns_head ( ) {
352+ let options = ( None :: < i32 > , ( None :: < i32 > , ( None :: < i32 > , ) ) ) ;
353+ let hom = ( 10 , ( 20 , ( 30 , ) ) ) ;
354+ assert_eq ! ( options. first_none_with( hom) , Some ( 10 ) ) ;
355+ }
356+
357+ #[ test]
358+ fn test_transpose_or_ok_and_err ( ) {
359+ let options = ( Some ( 1 ) , ( None :: < i32 > , ( Some ( 3 ) , ) ) ) ;
360+ let hom = ( 10 , ( 20 , ( 30 , ) ) ) ;
361+ // Since the second element is None, we expect Err(20)
362+ assert_eq ! ( options. transpose_or( hom) , Err ( 20 ) ) ;
363+
364+ let options2 = ( Some ( 1 ) , ( Some ( 2 ) , ( Some ( 3 ) , ) ) ) ;
365+ let hom2 = ( 10 , ( 20 , ( 30 , ) ) ) ;
366+ assert_eq ! ( options2. transpose_or( hom2) , Ok ( ( 1 , ( 2 , ( 3 , ) ) ) ) ) ;
367+ }
368+
369+ #[ test]
370+ fn test_transpose_or_single_ok_and_err ( ) {
371+ let options = ( None :: < i32 > , ) ;
372+ let hom = ( 99 , ) ;
373+ assert_eq ! ( options. transpose_or( hom) , Err ( 99 ) ) ;
374+
375+ let some = ( Some ( 5 ) , ) ;
376+ let hom2 = ( 77 , ) ;
377+ assert_eq ! ( some. transpose_or( hom2) , Ok ( ( 5 , ) ) ) ;
378+ }
192379}
0 commit comments