tuple_combinator/lib.rs
1//! A helper trait to improve the ergonomics when working with multiple [`Option`]s. After
2//! importing [`TupleCombinator`], you can treat a tuple of `Option`s as one `Option`.
3//!
4//! # Example
5//!
6//! ```
7//! use tuple_combinator::TupleCombinator;
8//!
9//! fn main() {
10//! let tuples = (Some(1), Some(2), Some(3));
11//!
12//! assert_eq!(tuples.map(|(a,b,c)| a + b + c), Some(6));
13//! assert_eq!(tuples.and_then(|(a,b,c)| Some(a + b - c)), Some(0));
14//! assert_eq!(tuples.transpose(), Some((1,2,3)));
15//! assert_eq!((Some(1), None).map(|(a, b): (i32, i32)| 100), None);
16//! }
17//! ```
18
19use std::any::Any;
20
21/// The traits that provides helper functions for tuples. This trait implementation mirros most of
22/// the methods defined in [`Option`].
23#[doc(inline)]
24pub trait TupleCombinator: Sized {
25 type Tuple;
26
27 /// Transposes a tuple of [`Option`]s into an `Option` of tuples. This function returns `None`
28 /// if any of the `Option` is `None`.
29 /// ```
30 /// # use tuple_combinator::TupleCombinator;
31 /// let left = (Some("foo"), Some(123));
32 /// assert_eq!(left.transpose(), Some(("foo", 123)));
33 /// ```
34 fn transpose(self) -> Option<Self::Tuple>;
35
36 /// See [`Option::map`].
37 ///
38 /// # Examples
39 ///
40 /// ```
41 /// # use tuple_combinator::TupleCombinator;
42 /// let tuples = (Some("foo"), Some("bar"));
43 /// assert_eq!(tuples.map(|(a, b)| format!("{}{}", a, b)).unwrap(), "foobar");
44 /// ```
45 fn map<U, F: FnOnce(Self::Tuple) -> U>(self, f: F) -> Option<U> {
46 self.transpose().map(f)
47 }
48
49 /// See [`Option::expect`].
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// # use tuple_combinator::TupleCombinator;
55 /// let tuples = (Some("foo"), Some(123));
56 /// assert_eq!(tuples.expect("should not panic"), ("foo", 123));
57 /// ```
58 ///
59 /// ```{.should_panic}
60 /// # use tuple_combinator::TupleCombinator;
61 /// let tuples: (_, Option<i32>) = (Some("foo"), None);
62 /// tuples.expect("will panic");
63 /// ```
64 fn expect(self, msg: &str) -> Self::Tuple {
65 self.transpose().expect(msg)
66 }
67
68 /// See [`Option::unwrap`].
69 /// ```
70 /// # use tuple_combinator::TupleCombinator;
71 /// let tuples = (Some("foo"), Some(123));
72 /// assert_eq!(tuples.unwrap(), ("foo", 123));
73 /// ```
74 ///
75 /// This example will panic:
76 ///
77 /// ```{.should_panic}
78 /// # use tuple_combinator::TupleCombinator;
79 /// let tuples: (_, Option<i32>) = (Some("foo"), None);
80 /// tuples.unwrap();
81 /// ```
82 fn unwrap(self) -> Self::Tuple {
83 self.transpose().unwrap()
84 }
85
86 /// See [`Option::and`].
87 /// ```
88 /// # use tuple_combinator::TupleCombinator;
89 /// let left = (Some("foo"), Some(123));
90 /// let right = Some(("bar", 456));
91 /// assert_eq!(left.and(right), right);
92 ///
93 /// let left_none = (None, Some(123));
94 /// assert_eq!(left_none.and(right), None);
95 /// ```
96 fn and(self, optb: Option<Self::Tuple>) -> Option<Self::Tuple> {
97 self.transpose().and(optb)
98 }
99
100 /// See [`Option::and_then`].
101 /// ```
102 /// # use tuple_combinator::TupleCombinator;
103 /// let tuples = (Some("foobar"), Some(123));
104 /// assert_eq!(tuples.and_then(|(a, b)| Some(a.len() + b)), Some(129));
105 ///
106 /// assert_eq!(tuples.and_then(|(a, b)| if b % 2 != 1 { Some(b) } else { None }), None);
107 /// ```
108 fn and_then<U, F: FnOnce(Self::Tuple) -> Option<U>>(self, f: F) -> Option<U> {
109 self.transpose().and_then(f)
110 }
111
112 /// See [`Option::filter`].
113 /// ```
114 /// # use tuple_combinator::TupleCombinator;
115 /// let tuples = (Some("foobar"), Some(123));
116 /// assert_eq!(tuples.filter(|(a, b)| b % 2 == 1), Some(("foobar", 123)));
117 /// assert_eq!(tuples.filter(|(a, b)| b % 2 != 1), None);
118 /// ```
119 fn filter<P: FnOnce(&Self::Tuple) -> bool>(self, predicate: P) -> Option<Self::Tuple> {
120 self.transpose().filter(predicate)
121 }
122
123 /// See [`Option::or`].
124 /// ```
125 /// # use tuple_combinator::TupleCombinator;
126 /// let left = (Some("foo"), Some(123));
127 /// let right = Some(("bar", 456));
128 /// assert_eq!(left.or(right), left.transpose());
129 ///
130 /// let left_none = (None, Some(123));
131 /// assert_eq!(left_none.or(right), right);
132 /// ```
133 fn or(self, optb: Option<Self::Tuple>) -> Option<Self::Tuple> {
134 self.transpose().or(optb)
135 }
136
137 /// See [`Option::or_else`].
138 /// ```
139 /// # use tuple_combinator::TupleCombinator;
140 /// let left = (Some("foo"), Some(123));
141 /// let right = Some(("bar", 456));
142 /// assert_eq!(left.or_else(|| right), left.transpose());
143 /// assert_eq!((None, Some(456)).or_else(|| right), right);
144 /// ```
145 fn or_else<F: FnOnce() -> Option<Self::Tuple>>(self, f: F) -> Option<Self::Tuple> {
146 self.transpose().or_else(f)
147 }
148
149 /// See [`Option::xor`].
150 /// ```
151 /// # use tuple_combinator::TupleCombinator;
152 /// let left = (Some("foo"), Some(123));
153 /// let right = Some(("bar", 456));
154 /// assert_eq!(left.xor(None), left.transpose());
155 /// assert_eq!(None.xor(left.transpose()), left.transpose());
156 /// assert_eq!(left.xor(right), None);
157 /// ```
158 fn xor(self, optb: Option<Self::Tuple>) -> Option<Self::Tuple> {
159 self.transpose().xor(optb)
160 }
161}
162
163/// Reduce tuples of [`Option`]s into results of various form, act in comparable to the iterators.
164/// ```
165/// use tuple_combinator::TupleReducer;
166///
167/// let res = (Some(1), Some(5), Some("rust_tuple")).fold(0, |sum, item| {
168/// sum.and_then(|s| {
169/// if let Some(raw_i32) = item.downcast_ref::<Option<i32>>() {
170/// return raw_i32.as_ref()
171/// .and_then(|val| {
172/// Some(s + val)
173/// });
174/// }
175///
176/// if let Some(raw_str) = item.downcast_ref::<Option<&str>>() {
177/// return raw_str.as_ref()
178/// .and_then(|val| {
179/// Some(s + val.len() as i32)
180/// });
181/// }
182///
183/// Some(s)
184/// })
185/// });
186///
187/// assert_eq!(res, Some(16));
188/// ```
189#[doc(inline)]
190pub trait TupleReducer: Sized {
191 /// Fold the tuple to obtain a final outcome. Depending on the implementation of the handler
192 /// function, the fold can behave differently on various option types or values.
193 ///
194 /// # Examples
195 ///
196 /// Reduce tuples of i32 options to the sum of the contained values:
197 ///
198 /// ```rust
199 /// use tuple_combinator::TupleReducer;
200 ///
201 /// let res = (Some(17), Some(20)).fold(5, |sum, item| {
202 /// sum.and_then(|s| {
203 /// item.downcast_ref::<Option<i32>>()
204 /// .and_then(|raw| raw.as_ref())
205 /// .and_then(|val| {
206 /// Some(s + val)
207 /// })
208 /// })
209 /// });
210 ///
211 /// assert_eq!(res, Some(42));
212 /// ```
213 fn fold<U, F: Fn(Option<U>, &dyn Any) -> Option<U>>(&self, init: U, f: F) -> Option<U>;
214
215 /// `fold_strict` works very much like `fold`, except that only options with the same wrapped data
216 /// type as the output type will be "folded", i.e. invoking the supplied folding function. This
217 /// function will come into handy when the caller only care about the options in the tuples that
218 /// match the output type.
219 ///
220 /// # Examples
221 /// ```rust
222 /// use tuple_combinator::TupleReducer;
223 ///
224 /// let res = (Some(40), Some("noise"), None as Option<i32>, Some(2))
225 /// .fold_strict(0i32, |sum, item| {
226 /// sum.and_then(|s| {
227 /// Some(s + item)
228 /// })
229 /// });
230 ///
231 /// assert_eq!(res, Some(42));
232 /// ```
233 fn fold_strict<U: Any, F: Fn(Option<U>, &U) -> Option<U>>(&self, init: U, f: F) -> Option<U>;
234
235 /// Convert the tuples to a reference slice, where caller can use native iteration tools. Note
236 /// that this is re-export of the tuples' internal content, hence the slice can't live longer
237 /// than the tuple self.
238 ///
239 /// # Examples
240 ///
241 /// ```rust
242 /// use std::any::Any;
243 /// use tuple_combinator::TupleReducer;
244 ///
245 /// let mut src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
246 ///
247 /// // convert the tuples to a slice of `Any` type
248 /// let slice: Box<[&dyn Any]> = src.ref_slice();
249 ///
250 /// // the slice has the same amount of elements as in the tuples.
251 /// assert_eq!(slice.len(), 5);
252 ///
253 /// // downcast the element to its actual type; wrong type cast will be rejected with a `None`
254 /// // output from the API call.
255 /// assert_eq!(slice[0].downcast_ref::<Option<i32>>().unwrap(), &Some(1));
256 /// assert_eq!(slice[0].downcast_ref::<Option<&str>>(), None);
257 /// assert_eq!(slice[1].downcast_ref::<Option<&str>>().unwrap(), &None);
258 ///
259 /// // unlike `mut_slice` API, the line below won't compile even if adding the `mut` keyword
260 /// // to the `slice` variable, because the source slice is immutable.
261 /// // let first = slice[0].downcast_mut::<Option<i32>>().unwrap().take();
262 /// ```
263 fn ref_slice(&self) -> Box<[&dyn Any]>;
264
265 /// Convert the tuples to a reference slice which only include options wrapping the data of the
266 /// desired type [`T`]. Options with types other than the given one will be excluded from the slice.
267 /// Note that if the slice length is 0, it means the source tuple does not contain elements in
268 /// options that can be converted to type ['T'].
269 ///
270 /// # Examples
271 /// ```rust
272 /// use tuple_combinator::TupleReducer;
273 ///
274 /// let src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
275 /// let slice = src.strict_ref_slice::<i32>();
276 ///
277 /// // The above variable initiation is equivalent to the following:
278 /// // let slice: Box<[&i32]> = src.strict_ref_slice();
279 ///
280 /// assert_eq!(slice.len(), 3);
281 /// assert_eq!(
282 /// slice,
283 /// vec![&Some(1), &Some(2), &None as &Option<i32>].into_boxed_slice()
284 /// );
285 ///
286 /// // The line below won't compile because the immutability of the slice.
287 /// // let first = slice[0].downcast_mut::<Option<i32>>().unwrap().take();
288 /// ```
289 fn strict_ref_slice<T: Any>(&self) -> Box<[&Option<T>]>;
290
291 /// This method works similar to `ref_slice`, except that the members of the slice are mutable,
292 /// such that it is possible to make updates, or taking ownership from the underlying tuples data.
293 /// Note that modifying or altering the slice data will also cause the same data in the tuples to
294 /// be altered.
295 ///
296 /// # Examples
297 ///
298 /// ```rust
299 /// use std::any::Any;
300 /// use tuple_combinator::TupleReducer;
301 ///
302 /// let mut src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
303 /// let slice: Box<[&mut dyn Any]> = src.mut_slice();
304 ///
305 /// assert_eq!(slice.len(), 5);
306 /// assert_eq!(slice[0].downcast_ref::<Option<i32>>().unwrap(), &Some(1));
307 /// assert_eq!(slice[1].downcast_ref::<Option<&str>>().unwrap(), &None);
308 ///
309 /// let first = slice[0].downcast_mut::<Option<i32>>().unwrap().take();
310 /// assert_eq!(first, Some(1));
311 /// ```
312 fn mut_slice(&mut self) -> Box<[&mut dyn Any]>;
313
314 /// This method works similar to `strict_ref_slice`, except that the members of the slice are
315 /// mutable, such that it is possible to make updates, or taking ownership from the underlying
316 /// tuples data. Note that modifying or altering the slice data will also cause the same data
317 /// in the tuples to be altered.
318 ///
319 /// # Examples
320 ///
321 /// ```rust
322 /// use tuple_combinator::TupleReducer;
323 ///
324 /// let mut src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
325 /// let slice = src.strict_mut_slice::<i32>();
326 ///
327 /// // The above variable initiation is equivalent to the following:
328 /// // let slice: Box<[&mut i32]> = src.strict_mut_slice();
329 ///
330 /// assert_eq!(slice.len(), 3);
331 /// assert_eq!(
332 /// slice,
333 /// vec![&mut Some(1), &mut Some(2), &mut None as &mut Option<i32>].into_boxed_slice()
334 /// );
335 ///
336 /// // Now you can take the wrapped content out of the tuples/slice and operate on the element.
337 /// // Note that operations on the slice element will take the same effect on the origin tuples,
338 /// // since slice elements are merely mutable borrows.
339 /// let first = slice[0].take();
340 /// assert_eq!(first, Some(1));
341 /// assert_eq!(slice[0], &mut None);
342 /// ```
343 fn strict_mut_slice<T: Any>(&mut self) -> Box<[&mut Option<T>]>;
344}
345
346macro_rules! tuple_impls {
347 ( $( $v:ident: $T:ident, )* ) => {
348 impl<$($T,)*> TupleCombinator for ($(Option<$T>,)*) {
349 type Tuple = ($($T,)*);
350
351 fn transpose(self) -> Option<Self::Tuple> {
352 if let ($(Some($v),)*) = self {
353 Some(($($v,)*))
354 } else {
355 None
356 }
357 }
358 }
359
360 };
361}
362
363macro_rules! tuple_impl_reduce {
364 () => {};
365
366 ( $( $ntyp:ident => $nidx:tt, )+ ) => {
367
368 impl<$( $ntyp, )+> TupleReducer for ( $( Option<$ntyp>, )+ )
369 where
370 $( $ntyp: Any, )*
371 {
372 fn fold<U, F: Fn(Option<U>, &dyn Any) -> Option<U>>(&self, init: U, f: F) -> Option<U> {
373 let mut accu = Some(init);
374
375 $(
376 accu = f(accu, &self.$nidx);
377 )*
378
379 accu
380 }
381
382 fn fold_strict<U: Any, F: Fn(Option<U>, &U) -> Option<U>>(&self, init: U, f: F) -> Option<U> {
383 let mut accu = Some(init);
384
385 $(
386 let opt = (&self.$nidx as &dyn Any)
387 .downcast_ref::<Option<U>>()
388 .and_then(|opt| opt.as_ref());
389
390 // avoid using combinator here since closure will cause `accu` to move and lead
391 // to all sorts of headache.
392 if let Some(value) = opt {
393 accu = f(accu, value);
394 }
395 )*
396
397 accu
398 }
399
400 fn ref_slice(&self) -> Box<[&dyn Any]> {
401 // The maximum amount of elements in a tuple is 12, that's the upper-bound
402 let mut vec: Vec<&dyn Any> = Vec::with_capacity(12);
403
404 $(
405 vec.push(&self.$nidx);
406 )*
407
408 vec.into_boxed_slice()
409 }
410
411 fn strict_ref_slice<T: Any>(&self) -> Box<[&Option<T>]> {
412 // The maximum amount of elements in a tuple is 12, that's the upper-bound
413 let mut vec: Vec<&Option<T>> = Vec::with_capacity(12);
414
415 $(
416 (&self.$nidx as &dyn Any)
417 .downcast_ref::<Option<T>>()
418 .and_then(|opt| {
419 vec.push(opt);
420 Some(())
421 });
422 )*
423
424 vec.into_boxed_slice()
425 }
426
427 fn mut_slice(&mut self) -> Box<[&mut dyn Any]> {
428 // The maximum amount of elements in a tuple is 12, that's the upper-bound
429 let mut vec: Vec<&mut dyn Any> = Vec::with_capacity(12);
430
431 $(
432 vec.push(&mut self.$nidx);
433 )*
434
435 vec.into_boxed_slice()
436 }
437
438 fn strict_mut_slice<T: Any>(&mut self) -> Box<[&mut Option<T>]> {
439 // The maximum amount of elements in a tuple is 12, that's the upper-bound
440 let mut vec: Vec<&mut Option<T>> = Vec::with_capacity(12);
441
442 $(
443 (&mut self.$nidx as &mut dyn Any)
444 .downcast_mut::<Option<T>>()
445 .and_then(|opt| {
446 vec.push(opt);
447 Some(())
448 });
449 )*
450
451 vec.into_boxed_slice()
452 }
453 }
454 };
455}
456
457// Impl TupleCombinator
458tuple_impls! { t1: T1, }
459tuple_impls! { t1: T1, t2: T2, }
460tuple_impls! { t1: T1, t2: T2, t3: T3, }
461tuple_impls! { t1: T1, t2: T2, t3: T3, t4: T4, }
462tuple_impls! { t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, }
463tuple_impls! { t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, }
464tuple_impls! { t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, }
465tuple_impls! { t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, }
466tuple_impls! { t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, }
467tuple_impls! { t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, t10: T10, }
468
469// Impl TupleReducer
470tuple_impl_reduce! { T0 => 0, }
471tuple_impl_reduce! { T0 => 0, T1 => 1, }
472tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, }
473tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, T3 => 3, }
474tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, T3 => 3, T4 => 4, }
475tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, T3 => 3, T4 => 4, T5 => 5, }
476tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, T3 => 3, T4 => 4, T5 => 5, T6 => 6, }
477tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, T3 => 3, T4 => 4, T5 => 5, T6 => 6, T7 => 7, }
478tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, T3 => 3, T4 => 4, T5 => 5, T6 => 6, T7 => 7, T8 => 8, }
479tuple_impl_reduce! { T0 => 0, T1 => 1, T2 => 2, T3 => 3, T4 => 4, T5 => 5, T6 => 6, T7 => 7, T8 => 8, T9 => 9, }
480
481#[cfg(test)]
482mod impl_tests {
483 use super::TupleReducer;
484 use std::any::Any;
485
486 #[test]
487 fn fold_sum() {
488 let res = (Some(17), Some(20)).fold(5, |sum, item| {
489 sum.and_then(|s| {
490 item.downcast_ref::<Option<i32>>()
491 .and_then(|raw| raw.as_ref())
492 .and_then(|val| Some(s + val))
493 })
494 });
495
496 assert_eq!(res, Some(42));
497 }
498
499 #[test]
500 fn fold_mixed() {
501 let res = (
502 Some(1),
503 Some(5),
504 Some("rust_tuple"),
505 Some(String::from("tuple_reducer")),
506 Some(vec![0u8, 1, 42]), // the vec that wraps all the wisdom of this universe
507 ).fold(0, |sum, item| {
508 sum.and_then(|s| {
509 if let Some(raw_i32) = item.downcast_ref::<Option<i32>>() {
510 return raw_i32.as_ref().and_then(|val| Some(s + val));
511 }
512
513 if let Some(raw_str) = item.downcast_ref::<Option<&str>>() {
514 return raw_str.as_ref().and_then(|val| Some(s + val.len() as i32));
515 }
516
517 if let Some(raw_string) = item.downcast_ref::<Option<String>>() {
518 return raw_string.as_ref().and_then(|val| Some(s + val.len() as i32));
519 }
520
521 if let Some(raw_vec) = item.downcast_ref::<Option<Vec<u8>>>() {
522 return raw_vec.as_ref().and_then(|val| Some(s + val.len() as i32));
523 }
524
525 Some(s)
526 })
527 });
528
529 assert_eq!(res, Some(32));
530 }
531
532 #[test]
533 fn fold_none_as_nuke() {
534 let none: Option<i32> = None;
535
536 let res = (Some(1), none, Some(5)).fold(0, |sum, item| {
537 sum.and_then(|s| {
538 item.downcast_ref::<Option<i32>>()
539 .and_then(|raw| raw.as_ref())
540 .and_then(|val| Some(s + val))
541 })
542 });
543
544 assert_eq!(res, None);
545 }
546
547 #[test]
548 fn fold_none_as_reset() {
549 let none: Option<i32> = None;
550 let init = 0;
551
552 let res = (Some(1), none, Some(5)).fold(init, |sum, item| {
553 item.downcast_ref::<Option<i32>>()
554 .and_then(|raw| raw.as_ref())
555 .and_then(|val| {
556 if let Some(s) = sum {
557 Some(s + val)
558 } else {
559 Some(init + val)
560 }
561 })
562 });
563
564 assert_eq!(res, Some(5));
565 }
566
567 #[test]
568 fn fold_strict_base() {
569 let res = (Some(40), Some("noise"), None as Option<i32>, Some(2))
570 .fold_strict(0i32, |sum, item| {
571 sum.and_then(|s| {
572 Some(s + item)
573 })
574 });
575
576 assert_eq!(res, Some(42));
577 }
578
579 #[test]
580 fn ref_slice_base() {
581 let src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
582
583 // convert the tuples to a slice of `Any` type
584 let slice: Box<[&dyn Any]> = src.ref_slice();
585
586 // the slice has the same amount of elements as in the tuples.
587 assert_eq!(slice.len(), 5);
588
589 // downcast the element to its actual type; wrong type cast will be rejected with a `None`
590 // output from the API call.
591 assert_eq!(slice[0].downcast_ref::<Option<i32>>().unwrap(), &Some(1));
592 assert_eq!(slice[0].downcast_ref::<Option<&str>>(), None);
593 assert_eq!(slice[1].downcast_ref::<Option<&str>>().unwrap(), &None);
594 }
595
596 #[test]
597 fn strict_ref_slice_base() {
598 let src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
599 let slice = src.strict_ref_slice::<i32>();
600
601 // The above variable initiation is equivalent to the following:
602 // let slice: Box<[&i32]> = src.strict_ref_slice();
603
604 assert_eq!(slice.len(), 3);
605 assert_eq!(
606 slice,
607 vec![&Some(1), &Some(2), &None as &Option<i32>].into_boxed_slice()
608 );
609 }
610
611 #[test]
612 fn mut_slice_base() {
613 let mut src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
614 let slice: Box<[&mut dyn Any]> = src.mut_slice();
615
616 assert_eq!(slice.len(), 5);
617 assert_eq!(slice[0].downcast_ref::<Option<i32>>().unwrap(), &Some(1));
618 assert_eq!(slice[1].downcast_ref::<Option<&str>>().unwrap(), &None);
619
620 let first = slice[0].downcast_mut::<Option<i32>>().unwrap().take();
621 assert_eq!(first, Some(1));
622 }
623
624 #[test]
625 fn strict_mut_slice_base() {
626 let mut src = (Some(1), None as Option<&str>, Some(2), None as Option<i32>, Some(()));
627 let slice = src.strict_mut_slice::<i32>();
628
629 // The above variable initiation is equivalent to the following:
630 // let slice: Box<[&mut i32]> = src.strict_mut_slice();
631
632 assert_eq!(slice.len(), 3);
633 assert_eq!(
634 slice,
635 vec![&mut Some(1), &mut Some(2), &mut None as &mut Option<i32>].into_boxed_slice()
636 );
637
638 let first = slice[0].take();
639 assert_eq!(first, Some(1));
640 assert_eq!(slice[0], &mut None);
641 }
642}