Skip to main content

fp_library/
dispatch.rs

1//! Dispatch infrastructure for unified free functions that route to either
2//! by-value or by-reference trait methods based on the closure's argument type.
3//!
4//! The dispatch system uses marker types ([`Val`] and [`Ref`]) to select the
5//! appropriate trait at compile time. The compiler infers the marker from the
6//! closure's argument type: `Fn(A) -> B` resolves to [`Val`], `Fn(&A) -> B`
7//! resolves to [`Ref`].
8//!
9//! The [`ClosureMode`] trait maps each marker to the corresponding `dyn Fn`
10//! trait object type, used by [`CloneFn`](crate::classes::CloneFn) and
11//! [`SendCloneFn`](crate::classes::SendCloneFn) to parameterize the `Deref`
12//! target of wrapped closures.
13//!
14//! ### Sub-modules
15//!
16//! Each sub-module provides a dispatch trait and unified free function for
17//! a specific type class operation, mirroring the corresponding `classes/`
18//! module:
19//!
20//! - [`functor`]: `FunctorDispatch` + `map`
21//! - [`semimonad`]: `BindDispatch` + `bind`
22//! - [`lift`]: `Lift2Dispatch`-`Lift5Dispatch` + `lift2`-`lift5`
23//! - [`foldable`]: `FoldRightDispatch`, `FoldLeftDispatch`, `FoldMapDispatch` + `fold_right`, `fold_left`, `fold_map`
24//!
25//! ### Examples
26//!
27//! ```
28//! use fp_library::{
29//! 	brands::*,
30//! 	functions::explicit::*,
31//! 	types::*,
32//! };
33//!
34//! // Closure takes i32 -> dispatches to Functor::map
35//! let y = map::<OptionBrand, _, _, _, _>(|x: i32| x * 2, Some(5));
36//! assert_eq!(y, Some(10));
37//!
38//! // Closure takes &i32 -> dispatches to RefFunctor::ref_map
39//! let lazy = RcLazy::pure(10);
40//! let mapped = map::<LazyBrand<RcLazyConfig>, _, _, _, _>(|x: &i32| *x * 2, &lazy);
41//! assert_eq!(*mapped.evaluate(), 20);
42//! ```
43
44#[fp_macros::document_module]
45mod inner {
46	// -- Marker types --
47
48	/// Marker type indicating the closure receives owned values.
49	///
50	/// Selected automatically by the compiler when the closure's argument
51	/// type is `A` (not `&A`). Routes to by-value trait methods
52	/// (e.g., [`Functor::map`](crate::classes::Functor::map),
53	/// [`Semimonad::bind`](crate::classes::Semimonad::bind)).
54	pub struct Val;
55
56	/// Marker type indicating the closure receives references.
57	///
58	/// Selected automatically by the compiler when the closure's argument
59	/// type is `&A`. Routes to by-reference trait methods
60	/// (e.g., [`RefFunctor::ref_map`](crate::classes::RefFunctor::ref_map),
61	/// [`RefSemimonad::ref_bind`](crate::classes::RefSemimonad::ref_bind)).
62	pub struct Ref;
63
64	// -- Closure mode --
65
66	/// Trait that maps a closure mode marker ([`Val`] or [`Ref`]) to the
67	/// corresponding `dyn Fn` trait object type.
68	///
69	/// Used by [`CloneFn`](crate::classes::CloneFn) to parameterize
70	/// the `Deref` target of wrapped closures. `Val` produces
71	/// `dyn Fn(A) -> B` (by-value), `Ref` produces `dyn Fn(&A) -> B`
72	/// (by-reference).
73	pub trait ClosureMode {
74		/// The unsized closure trait object type for this mode.
75		type Target<'a, A: 'a, B: 'a>: ?Sized + 'a;
76
77		/// The unsized closure trait object type for this mode with `Send + Sync` bounds.
78		type SendTarget<'a, A: 'a, B: 'a>: ?Sized + 'a;
79	}
80
81	impl ClosureMode for Val {
82		type SendTarget<'a, A: 'a, B: 'a> = dyn 'a + Fn(A) -> B + Send + Sync;
83		type Target<'a, A: 'a, B: 'a> = dyn 'a + Fn(A) -> B;
84	}
85
86	impl ClosureMode for Ref {
87		type SendTarget<'a, A: 'a, B: 'a> = dyn 'a + Fn(&A) -> B + Send + Sync;
88		type Target<'a, A: 'a, B: 'a> = dyn 'a + Fn(&A) -> B;
89	}
90}
91
92pub use inner::*;
93
94pub mod alt;
95pub mod apply_first;
96pub mod apply_second;
97pub mod bifoldable;
98pub mod bifunctor;
99pub mod bitraversable;
100pub mod compactable;
101pub mod contravariant;
102pub mod filterable;
103pub mod filterable_with_index;
104pub mod foldable;
105pub mod foldable_with_index;
106pub mod functor;
107pub mod functor_with_index;
108pub mod lift;
109pub mod map_first;
110pub mod map_second;
111pub mod semiapplicative;
112pub mod semimonad;
113pub mod traversable;
114pub mod traversable_with_index;
115pub mod witherable;
116
117#[cfg(test)]
118mod tests {
119	use {
120		super::{
121			functor::explicit::map,
122			lift::explicit::lift2,
123			semimonad::explicit::bind,
124		},
125		crate::{
126			brands::*,
127			types::*,
128		},
129	};
130
131	#[test]
132	fn test_val_option_map() {
133		let result = map::<OptionBrand, _, _, _, _>(|x: i32| x * 2, Some(5));
134		assert_eq!(result, Some(10));
135	}
136
137	#[test]
138	fn test_val_vec_map() {
139		let result = map::<VecBrand, _, _, _, _>(|x: i32| x + 1, vec![1, 2, 3]);
140		assert_eq!(result, vec![2, 3, 4]);
141	}
142
143	#[test]
144	fn test_ref_lazy_map() {
145		let lazy = RcLazy::pure(10);
146		let result = map::<LazyBrand<RcLazyConfig>, _, _, _, _>(|x: &i32| *x * 2, &lazy);
147		assert_eq!(*result.evaluate(), 20);
148	}
149
150	#[test]
151	fn test_val_none_map() {
152		let result = map::<OptionBrand, i32, i32, _, _>(|x| x * 2, None);
153		assert_eq!(result, None);
154	}
155
156	#[test]
157	fn test_val_option_bind() {
158		let result = bind::<OptionBrand, _, _, _, _>(Some(5), |x: i32| Some(x * 2));
159		assert_eq!(result, Some(10));
160	}
161
162	#[test]
163	fn test_val_option_lift2() {
164		let result = lift2::<OptionBrand, _, _, _, _, _, _>(|a, b| a + b, Some(1), Some(2));
165		assert_eq!(result, Some(3));
166	}
167
168	// -- FilterMapDispatch tests --
169
170	#[test]
171	fn test_val_option_filter_map() {
172		use super::filterable::explicit::filter_map;
173		let result = filter_map::<OptionBrand, _, _, _, _>(
174			|x: i32| if x > 3 { Some(x * 2) } else { None },
175			Some(5),
176		);
177		assert_eq!(result, Some(10));
178	}
179
180	#[test]
181	fn test_val_option_filter_map_none() {
182		use super::filterable::explicit::filter_map;
183		let result = filter_map::<OptionBrand, _, _, _, _>(
184			|x: i32| if x > 10 { Some(x) } else { None },
185			Some(5),
186		);
187		assert_eq!(result, None);
188	}
189
190	#[test]
191	fn test_ref_option_filter_map() {
192		use super::filterable::explicit::filter_map;
193		let result = filter_map::<OptionBrand, _, _, _, _>(
194			|x: &i32| if *x > 3 { Some(*x * 2) } else { None },
195			&Some(5),
196		);
197		assert_eq!(result, Some(10));
198	}
199
200	#[test]
201	fn test_val_vec_filter_map() {
202		use super::filterable::explicit::filter_map;
203		let result = filter_map::<VecBrand, _, _, _, _>(
204			|x: i32| if x > 2 { Some(x * 10) } else { None },
205			vec![1, 2, 3, 4],
206		);
207		assert_eq!(result, vec![30, 40]);
208	}
209
210	#[test]
211	fn test_ref_vec_filter_map() {
212		use super::filterable::explicit::filter_map;
213		let v = vec![1, 2, 3, 4];
214		let result = filter_map::<VecBrand, _, _, _, _>(
215			|x: &i32| if *x > 2 { Some(*x * 10) } else { None },
216			&v,
217		);
218		assert_eq!(result, vec![30, 40]);
219	}
220
221	// -- TraverseDispatch tests --
222
223	#[test]
224	fn test_val_option_traverse() {
225		use super::traversable::explicit::traverse;
226		let result = traverse::<RcFnBrand, OptionBrand, _, _, OptionBrand, _, _>(
227			|x: i32| Some(x * 2),
228			Some(5),
229		);
230		assert_eq!(result, Some(Some(10)));
231	}
232
233	#[test]
234	fn test_val_option_traverse_none() {
235		use super::traversable::explicit::traverse;
236		let result = traverse::<RcFnBrand, OptionBrand, _, _, OptionBrand, _, _>(
237			|_: i32| None::<i32>,
238			Some(5),
239		);
240		assert_eq!(result, None);
241	}
242
243	#[test]
244	fn test_ref_option_traverse() {
245		use super::traversable::explicit::traverse;
246		let result = traverse::<RcFnBrand, OptionBrand, _, _, OptionBrand, _, _>(
247			|x: &i32| Some(*x * 2),
248			&Some(5),
249		);
250		assert_eq!(result, Some(Some(10)));
251	}
252
253	#[test]
254	fn test_val_vec_traverse() {
255		use super::traversable::explicit::traverse;
256		let result: Option<Vec<i32>> = traverse::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(
257			|x: i32| Some(x * 2),
258			vec![1, 2, 3],
259		);
260		assert_eq!(result, Some(vec![2, 4, 6]));
261	}
262
263	#[test]
264	fn test_ref_vec_traverse() {
265		use super::traversable::explicit::traverse;
266		let v = vec![1, 2, 3];
267		let result: Option<Vec<i32>> =
268			traverse::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(|x: &i32| Some(*x * 2), &v);
269		assert_eq!(result, Some(vec![2, 4, 6]));
270	}
271
272	// -- FilterDispatch tests --
273
274	#[test]
275	fn test_val_option_filter() {
276		use super::filterable::explicit::filter;
277		let result = filter::<OptionBrand, _, _, _>(|x: i32| x > 3, Some(5));
278		assert_eq!(result, Some(5));
279	}
280
281	#[test]
282	fn test_ref_option_filter() {
283		use super::filterable::explicit::filter;
284		let result = filter::<OptionBrand, _, _, _>(|x: &i32| *x > 3, &Some(5));
285		assert_eq!(result, Some(5));
286	}
287
288	#[test]
289	fn test_val_vec_filter() {
290		use super::filterable::explicit::filter;
291		let result = filter::<VecBrand, _, _, _>(|x: i32| x > 3, vec![1, 2, 3, 4, 5]);
292		assert_eq!(result, vec![4, 5]);
293	}
294
295	#[test]
296	fn test_ref_vec_filter() {
297		use super::filterable::explicit::filter;
298		let v = vec![1, 2, 3, 4, 5];
299		let result = filter::<VecBrand, _, _, _>(|x: &i32| *x > 3, &v);
300		assert_eq!(result, vec![4, 5]);
301	}
302
303	// -- PartitionDispatch tests --
304
305	#[test]
306	fn test_val_option_partition() {
307		use super::filterable::explicit::partition;
308		let (no, yes) = partition::<OptionBrand, _, _, _>(|x: i32| x > 3, Some(5));
309		assert_eq!(yes, Some(5));
310		assert_eq!(no, None);
311	}
312
313	#[test]
314	fn test_ref_option_partition() {
315		use super::filterable::explicit::partition;
316		let (no, yes) = partition::<OptionBrand, _, _, _>(|x: &i32| *x > 3, &Some(5));
317		assert_eq!(yes, Some(5));
318		assert_eq!(no, None);
319	}
320
321	// -- PartitionMapDispatch tests --
322
323	#[test]
324	fn test_val_option_partition_map() {
325		use super::filterable::explicit::partition_map;
326		let (errs, oks) =
327			partition_map::<OptionBrand, _, _, _, _, _>(|x: i32| Ok::<i32, i32>(x * 2), Some(5));
328		assert_eq!(errs, None);
329		assert_eq!(oks, Some(10));
330	}
331
332	#[test]
333	fn test_ref_option_partition_map() {
334		use super::filterable::explicit::partition_map;
335		let (errs, oks) =
336			partition_map::<OptionBrand, _, _, _, _, _>(|x: &i32| Ok::<i32, i32>(*x * 2), &Some(5));
337		assert_eq!(errs, None);
338		assert_eq!(oks, Some(10));
339	}
340
341	// -- MapWithIndexDispatch tests --
342
343	#[test]
344	fn test_val_vec_map_with_index() {
345		use super::functor_with_index::explicit::map_with_index;
346		let result =
347			map_with_index::<VecBrand, _, _, _, _>(|i, x: i32| x + i as i32, vec![10, 20, 30]);
348		assert_eq!(result, vec![10, 21, 32]);
349	}
350
351	#[test]
352	fn test_ref_vec_map_with_index() {
353		use super::functor_with_index::explicit::map_with_index;
354		let v = vec![10, 20, 30];
355		let result = map_with_index::<VecBrand, _, _, _, _>(|i, x: &i32| *x + i as i32, &v);
356		assert_eq!(result, vec![10, 21, 32]);
357	}
358
359	// -- FilterWithIndexDispatch tests --
360
361	#[test]
362	fn test_val_vec_filter_with_index() {
363		use super::filterable_with_index::explicit::filter_with_index;
364		let result =
365			filter_with_index::<VecBrand, _, _, _>(|i, _x: i32| i < 2, vec![10, 20, 30, 40]);
366		assert_eq!(result, vec![10, 20]);
367	}
368
369	#[test]
370	fn test_ref_vec_filter_with_index() {
371		use super::filterable_with_index::explicit::filter_with_index;
372		let v = vec![10, 20, 30, 40];
373		let result = filter_with_index::<VecBrand, _, _, _>(|i, _x: &i32| i < 2, &v);
374		assert_eq!(result, vec![10, 20]);
375	}
376
377	// -- FilterMapWithIndexDispatch tests --
378
379	#[test]
380	fn test_val_vec_filter_map_with_index() {
381		use super::filterable_with_index::explicit::filter_map_with_index;
382		let result = filter_map_with_index::<VecBrand, _, _, _, _>(
383			|i, x: i32| if i % 2 == 0 { Some(x * 2) } else { None },
384			vec![10, 20, 30, 40],
385		);
386		assert_eq!(result, vec![20, 60]);
387	}
388
389	#[test]
390	fn test_ref_vec_filter_map_with_index() {
391		use super::filterable_with_index::explicit::filter_map_with_index;
392		let v = vec![10, 20, 30, 40];
393		let result = filter_map_with_index::<VecBrand, _, _, _, _>(
394			|i, x: &i32| if i % 2 == 0 { Some(*x * 2) } else { None },
395			&v,
396		);
397		assert_eq!(result, vec![20, 60]);
398	}
399
400	// -- PartitionWithIndexDispatch tests --
401
402	#[test]
403	fn test_val_vec_partition_with_index() {
404		use super::filterable_with_index::explicit::partition_with_index;
405		let (not_satisfied, satisfied) =
406			partition_with_index::<VecBrand, _, _, _>(|i, _x: i32| i < 2, vec![10, 20, 30, 40]);
407		assert_eq!(satisfied, vec![10, 20]);
408		assert_eq!(not_satisfied, vec![30, 40]);
409	}
410
411	#[test]
412	fn test_ref_vec_partition_with_index() {
413		use super::filterable_with_index::explicit::partition_with_index;
414		let v = vec![10, 20, 30, 40];
415		let (not_satisfied, satisfied) =
416			partition_with_index::<VecBrand, _, _, _>(|i, _x: &i32| i < 2, &v);
417		assert_eq!(satisfied, vec![10, 20]);
418		assert_eq!(not_satisfied, vec![30, 40]);
419	}
420
421	// -- PartitionMapWithIndexDispatch tests --
422
423	#[test]
424	fn test_val_vec_partition_map_with_index() {
425		use super::filterable_with_index::explicit::partition_map_with_index;
426		let (errs, oks) = partition_map_with_index::<VecBrand, _, _, _, _, _>(
427			|i, x: i32| if i < 2 { Ok(x) } else { Err(x) },
428			vec![10, 20, 30, 40],
429		);
430		assert_eq!(oks, vec![10, 20]);
431		assert_eq!(errs, vec![30, 40]);
432	}
433
434	#[test]
435	fn test_ref_vec_partition_map_with_index() {
436		use super::filterable_with_index::explicit::partition_map_with_index;
437		let v = vec![10, 20, 30, 40];
438		let (errs, oks) = partition_map_with_index::<VecBrand, _, _, _, _, _>(
439			|i, x: &i32| if i < 2 { Ok(*x) } else { Err(*x) },
440			&v,
441		);
442		assert_eq!(oks, vec![10, 20]);
443		assert_eq!(errs, vec![30, 40]);
444	}
445
446	// -- FoldMapWithIndexDispatch tests --
447
448	#[test]
449	fn test_val_vec_fold_map_with_index() {
450		use super::foldable_with_index::explicit::fold_map_with_index;
451		let result = fold_map_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
452			|i, x: i32| format!("{i}:{x}"),
453			vec![10, 20, 30],
454		);
455		assert_eq!(result, "0:101:202:30");
456	}
457
458	#[test]
459	fn test_ref_vec_fold_map_with_index() {
460		use super::foldable_with_index::explicit::fold_map_with_index;
461		let v = vec![10, 20, 30];
462		let result = fold_map_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
463			|i, x: &i32| format!("{i}:{x}"),
464			&v,
465		);
466		assert_eq!(result, "0:101:202:30");
467	}
468
469	// -- FoldRightWithIndexDispatch tests --
470
471	#[test]
472	fn test_val_vec_fold_right_with_index() {
473		use super::foldable_with_index::explicit::fold_right_with_index;
474		let result = fold_right_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
475			|i, x: i32, acc: String| format!("{acc}{i}:{x},"),
476			String::new(),
477			vec![10, 20, 30],
478		);
479		assert_eq!(result, "2:30,1:20,0:10,");
480	}
481
482	#[test]
483	fn test_ref_vec_fold_right_with_index() {
484		use super::foldable_with_index::explicit::fold_right_with_index;
485		let v = vec![10, 20, 30];
486		let result = fold_right_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
487			|i, x: &i32, acc: String| format!("{acc}{i}:{x},"),
488			String::new(),
489			&v,
490		);
491		assert_eq!(result, "2:30,1:20,0:10,");
492	}
493
494	// -- FoldLeftWithIndexDispatch tests --
495
496	#[test]
497	fn test_val_vec_fold_left_with_index() {
498		use super::foldable_with_index::explicit::fold_left_with_index;
499		let result = fold_left_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
500			|i, acc: String, x: i32| format!("{acc}{i}:{x},"),
501			String::new(),
502			vec![10, 20, 30],
503		);
504		assert_eq!(result, "0:10,1:20,2:30,");
505	}
506
507	#[test]
508	fn test_ref_vec_fold_left_with_index() {
509		use super::foldable_with_index::explicit::fold_left_with_index;
510		let v = vec![10, 20, 30];
511		let result = fold_left_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
512			|i, acc: String, x: &i32| format!("{acc}{i}:{x},"),
513			String::new(),
514			&v,
515		);
516		assert_eq!(result, "0:10,1:20,2:30,");
517	}
518
519	// -- TraverseWithIndexDispatch tests --
520
521	#[test]
522	fn test_val_vec_traverse_with_index() {
523		use super::traversable_with_index::explicit::traverse_with_index;
524		let result = traverse_with_index::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(
525			|_i, x: i32| Some(x * 2),
526			vec![1, 2, 3],
527		);
528		assert_eq!(result, Some(vec![2, 4, 6]));
529	}
530
531	#[test]
532	fn test_ref_vec_traverse_with_index() {
533		use super::traversable_with_index::explicit::traverse_with_index;
534		let v = vec![1, 2, 3];
535		let result = traverse_with_index::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(
536			|_i, x: &i32| Some(*x * 2),
537			&v,
538		);
539		assert_eq!(result, Some(vec![2, 4, 6]));
540	}
541
542	// -- WiltDispatch tests --
543
544	#[test]
545	fn test_val_option_wilt() {
546		use super::witherable::explicit::wilt;
547		let result = wilt::<RcFnBrand, OptionBrand, OptionBrand, _, _, _, _, _>(
548			|a: i32| Some(if a > 2 { Ok(a) } else { Err(a) }),
549			Some(5),
550		);
551		assert_eq!(result, Some((None, Some(5))));
552	}
553
554	#[test]
555	fn test_ref_vec_wilt() {
556		use super::witherable::explicit::wilt;
557		let v = vec![1, 2, 3, 4, 5];
558		let result: Option<(Vec<i32>, Vec<i32>)> =
559			wilt::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _, _>(
560				|x: &i32| Some(if *x > 3 { Ok(*x) } else { Err(*x) }),
561				&v,
562			);
563		assert_eq!(result, Some((vec![1, 2, 3], vec![4, 5])));
564	}
565
566	// -- WitherDispatch tests --
567
568	#[test]
569	fn test_val_option_wither() {
570		use super::witherable::explicit::wither;
571		let result = wither::<RcFnBrand, OptionBrand, OptionBrand, _, _, _, _>(
572			|a: i32| Some(if a > 2 { Some(a * 2) } else { None }),
573			Some(5),
574		);
575		assert_eq!(result, Some(Some(10)));
576	}
577
578	#[test]
579	fn test_ref_vec_wither() {
580		use super::witherable::explicit::wither;
581		let v = vec![1, 2, 3, 4, 5];
582		let result: Option<Vec<i32>> = wither::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _>(
583			|x: &i32| if *x > 3 { Some(Some(*x)) } else { Some(None) },
584			&v,
585		);
586		assert_eq!(result, Some(vec![4, 5]));
587	}
588
589	// -- BimapDispatch tests --
590
591	#[test]
592	fn test_val_result_bimap() {
593		use super::bifunctor::explicit::bimap;
594		let x = Result::<i32, i32>::Ok(5);
595		let y = bimap::<ResultBrand, _, _, _, _, _, _>((|e| e + 1, |s| s * 2), x);
596		assert_eq!(y, Ok(10));
597	}
598
599	#[test]
600	fn test_val_result_bimap_err() {
601		use super::bifunctor::explicit::bimap;
602		let x = Result::<i32, i32>::Err(3);
603		let y = bimap::<ResultBrand, _, _, _, _, _, _>((|e| e + 1, |s| s * 2), x);
604		assert_eq!(y, Err(4));
605	}
606
607	#[test]
608	fn test_ref_result_bimap() {
609		use super::bifunctor::explicit::bimap;
610		let x = Result::<i32, i32>::Ok(5);
611		let y = bimap::<ResultBrand, _, _, _, _, _, _>((|e: &i32| *e + 1, |s: &i32| *s * 2), &x);
612		assert_eq!(y, Ok(10));
613	}
614
615	// -- BiFoldRightDispatch tests --
616
617	#[test]
618	fn test_val_result_bi_fold_right() {
619		use super::bifoldable::explicit::bi_fold_right;
620		let x: Result<i32, i32> = Err(3);
621		let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
622			(|e, acc| acc - e, |s, acc| acc + s),
623			10,
624			x,
625		);
626		assert_eq!(y, 7);
627	}
628
629	#[test]
630	fn test_ref_result_bi_fold_right() {
631		use super::bifoldable::explicit::bi_fold_right;
632		let x: Result<i32, i32> = Err(3);
633		let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
634			(|e: &i32, acc| acc - *e, |s: &i32, acc| acc + *s),
635			10,
636			&x,
637		);
638		assert_eq!(y, 7);
639	}
640
641	// -- BiFoldLeftDispatch tests --
642
643	#[test]
644	fn test_val_result_bi_fold_left() {
645		use super::bifoldable::explicit::bi_fold_left;
646		let x: Result<i32, i32> = Ok(5);
647		let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
648			(|acc, e| acc - e, |acc, s| acc + s),
649			10,
650			x,
651		);
652		assert_eq!(y, 15);
653	}
654
655	#[test]
656	fn test_ref_result_bi_fold_left() {
657		use super::bifoldable::explicit::bi_fold_left;
658		let x: Result<i32, i32> = Ok(5);
659		let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
660			(|acc, e: &i32| acc - *e, |acc, s: &i32| acc + *s),
661			10,
662			&x,
663		);
664		assert_eq!(y, 15);
665	}
666
667	// -- BiFoldMapDispatch tests --
668
669	#[test]
670	fn test_val_result_bi_fold_map() {
671		use super::bifoldable::explicit::bi_fold_map;
672		let x: Result<i32, i32> = Ok(5);
673		let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
674			(|e: i32| e.to_string(), |s: i32| s.to_string()),
675			x,
676		);
677		assert_eq!(y, "5".to_string());
678	}
679
680	#[test]
681	fn test_ref_result_bi_fold_map() {
682		use super::bifoldable::explicit::bi_fold_map;
683		let x: Result<i32, i32> = Ok(5);
684		let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
685			(|e: &i32| e.to_string(), |s: &i32| s.to_string()),
686			&x,
687		);
688		assert_eq!(y, "5".to_string());
689	}
690
691	// -- BiTraverseDispatch tests --
692
693	#[test]
694	fn test_val_result_bi_traverse() {
695		use super::bitraversable::explicit::bi_traverse;
696		let x: Result<i32, i32> = Ok(5);
697		let y = bi_traverse::<RcFnBrand, ResultBrand, _, _, _, _, OptionBrand, _, _>(
698			(|e: i32| Some(e + 1), |s: i32| Some(s * 2)),
699			x,
700		);
701		assert_eq!(y, Some(Ok(10)));
702	}
703
704	#[test]
705	fn test_ref_result_bi_traverse() {
706		use super::bitraversable::explicit::bi_traverse;
707		let x: Result<i32, i32> = Ok(5);
708		let y = bi_traverse::<RcFnBrand, ResultBrand, _, _, _, _, OptionBrand, _, _>(
709			(|e: &i32| Some(*e + 1), |s: &i32| Some(*s * 2)),
710			&x,
711		);
712		assert_eq!(y, Some(Ok(10)));
713	}
714}