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 semimonad;
110pub mod traversable;
111pub mod traversable_with_index;
112pub mod witherable;
113
114#[cfg(test)]
115mod tests {
116	use {
117		super::{
118			functor::explicit::map,
119			lift::explicit::lift2,
120			semimonad::explicit::bind,
121		},
122		crate::{
123			brands::*,
124			types::*,
125		},
126	};
127
128	#[test]
129	fn test_val_option_map() {
130		let result = map::<OptionBrand, _, _, _, _>(|x: i32| x * 2, Some(5));
131		assert_eq!(result, Some(10));
132	}
133
134	#[test]
135	fn test_val_vec_map() {
136		let result = map::<VecBrand, _, _, _, _>(|x: i32| x + 1, vec![1, 2, 3]);
137		assert_eq!(result, vec![2, 3, 4]);
138	}
139
140	#[test]
141	fn test_ref_lazy_map() {
142		let lazy = RcLazy::pure(10);
143		let result = map::<LazyBrand<RcLazyConfig>, _, _, _, _>(|x: &i32| *x * 2, &lazy);
144		assert_eq!(*result.evaluate(), 20);
145	}
146
147	#[test]
148	fn test_val_none_map() {
149		let result = map::<OptionBrand, i32, i32, _, _>(|x| x * 2, None);
150		assert_eq!(result, None);
151	}
152
153	#[test]
154	fn test_val_option_bind() {
155		let result = bind::<OptionBrand, _, _, _, _>(Some(5), |x: i32| Some(x * 2));
156		assert_eq!(result, Some(10));
157	}
158
159	#[test]
160	fn test_val_option_lift2() {
161		let result = lift2::<OptionBrand, _, _, _, _, _, _>(|a, b| a + b, Some(1), Some(2));
162		assert_eq!(result, Some(3));
163	}
164
165	// -- FilterMapDispatch tests --
166
167	#[test]
168	fn test_val_option_filter_map() {
169		use super::filterable::explicit::filter_map;
170		let result = filter_map::<OptionBrand, _, _, _, _>(
171			|x: i32| if x > 3 { Some(x * 2) } else { None },
172			Some(5),
173		);
174		assert_eq!(result, Some(10));
175	}
176
177	#[test]
178	fn test_val_option_filter_map_none() {
179		use super::filterable::explicit::filter_map;
180		let result = filter_map::<OptionBrand, _, _, _, _>(
181			|x: i32| if x > 10 { Some(x) } else { None },
182			Some(5),
183		);
184		assert_eq!(result, None);
185	}
186
187	#[test]
188	fn test_ref_option_filter_map() {
189		use super::filterable::explicit::filter_map;
190		let result = filter_map::<OptionBrand, _, _, _, _>(
191			|x: &i32| if *x > 3 { Some(*x * 2) } else { None },
192			&Some(5),
193		);
194		assert_eq!(result, Some(10));
195	}
196
197	#[test]
198	fn test_val_vec_filter_map() {
199		use super::filterable::explicit::filter_map;
200		let result = filter_map::<VecBrand, _, _, _, _>(
201			|x: i32| if x > 2 { Some(x * 10) } else { None },
202			vec![1, 2, 3, 4],
203		);
204		assert_eq!(result, vec![30, 40]);
205	}
206
207	#[test]
208	fn test_ref_vec_filter_map() {
209		use super::filterable::explicit::filter_map;
210		let v = vec![1, 2, 3, 4];
211		let result = filter_map::<VecBrand, _, _, _, _>(
212			|x: &i32| if *x > 2 { Some(*x * 10) } else { None },
213			&v,
214		);
215		assert_eq!(result, vec![30, 40]);
216	}
217
218	// -- TraverseDispatch tests --
219
220	#[test]
221	fn test_val_option_traverse() {
222		use super::traversable::explicit::traverse;
223		let result = traverse::<RcFnBrand, OptionBrand, _, _, OptionBrand, _, _>(
224			|x: i32| Some(x * 2),
225			Some(5),
226		);
227		assert_eq!(result, Some(Some(10)));
228	}
229
230	#[test]
231	fn test_val_option_traverse_none() {
232		use super::traversable::explicit::traverse;
233		let result = traverse::<RcFnBrand, OptionBrand, _, _, OptionBrand, _, _>(
234			|_: i32| None::<i32>,
235			Some(5),
236		);
237		assert_eq!(result, None);
238	}
239
240	#[test]
241	fn test_ref_option_traverse() {
242		use super::traversable::explicit::traverse;
243		let result = traverse::<RcFnBrand, OptionBrand, _, _, OptionBrand, _, _>(
244			|x: &i32| Some(*x * 2),
245			&Some(5),
246		);
247		assert_eq!(result, Some(Some(10)));
248	}
249
250	#[test]
251	fn test_val_vec_traverse() {
252		use super::traversable::explicit::traverse;
253		let result: Option<Vec<i32>> = traverse::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(
254			|x: i32| Some(x * 2),
255			vec![1, 2, 3],
256		);
257		assert_eq!(result, Some(vec![2, 4, 6]));
258	}
259
260	#[test]
261	fn test_ref_vec_traverse() {
262		use super::traversable::explicit::traverse;
263		let v = vec![1, 2, 3];
264		let result: Option<Vec<i32>> =
265			traverse::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(|x: &i32| Some(*x * 2), &v);
266		assert_eq!(result, Some(vec![2, 4, 6]));
267	}
268
269	// -- FilterDispatch tests --
270
271	#[test]
272	fn test_val_option_filter() {
273		use super::filterable::explicit::filter;
274		let result = filter::<OptionBrand, _, _, _>(|x: i32| x > 3, Some(5));
275		assert_eq!(result, Some(5));
276	}
277
278	#[test]
279	fn test_ref_option_filter() {
280		use super::filterable::explicit::filter;
281		let result = filter::<OptionBrand, _, _, _>(|x: &i32| *x > 3, &Some(5));
282		assert_eq!(result, Some(5));
283	}
284
285	#[test]
286	fn test_val_vec_filter() {
287		use super::filterable::explicit::filter;
288		let result = filter::<VecBrand, _, _, _>(|x: i32| x > 3, vec![1, 2, 3, 4, 5]);
289		assert_eq!(result, vec![4, 5]);
290	}
291
292	#[test]
293	fn test_ref_vec_filter() {
294		use super::filterable::explicit::filter;
295		let v = vec![1, 2, 3, 4, 5];
296		let result = filter::<VecBrand, _, _, _>(|x: &i32| *x > 3, &v);
297		assert_eq!(result, vec![4, 5]);
298	}
299
300	// -- PartitionDispatch tests --
301
302	#[test]
303	fn test_val_option_partition() {
304		use super::filterable::explicit::partition;
305		let (no, yes) = partition::<OptionBrand, _, _, _>(|x: i32| x > 3, Some(5));
306		assert_eq!(yes, Some(5));
307		assert_eq!(no, None);
308	}
309
310	#[test]
311	fn test_ref_option_partition() {
312		use super::filterable::explicit::partition;
313		let (no, yes) = partition::<OptionBrand, _, _, _>(|x: &i32| *x > 3, &Some(5));
314		assert_eq!(yes, Some(5));
315		assert_eq!(no, None);
316	}
317
318	// -- PartitionMapDispatch tests --
319
320	#[test]
321	fn test_val_option_partition_map() {
322		use super::filterable::explicit::partition_map;
323		let (errs, oks) =
324			partition_map::<OptionBrand, _, _, _, _, _>(|x: i32| Ok::<i32, i32>(x * 2), Some(5));
325		assert_eq!(errs, None);
326		assert_eq!(oks, Some(10));
327	}
328
329	#[test]
330	fn test_ref_option_partition_map() {
331		use super::filterable::explicit::partition_map;
332		let (errs, oks) =
333			partition_map::<OptionBrand, _, _, _, _, _>(|x: &i32| Ok::<i32, i32>(*x * 2), &Some(5));
334		assert_eq!(errs, None);
335		assert_eq!(oks, Some(10));
336	}
337
338	// -- MapWithIndexDispatch tests --
339
340	#[test]
341	fn test_val_vec_map_with_index() {
342		use super::functor_with_index::explicit::map_with_index;
343		let result =
344			map_with_index::<VecBrand, _, _, _, _>(|i, x: i32| x + i as i32, vec![10, 20, 30]);
345		assert_eq!(result, vec![10, 21, 32]);
346	}
347
348	#[test]
349	fn test_ref_vec_map_with_index() {
350		use super::functor_with_index::explicit::map_with_index;
351		let v = vec![10, 20, 30];
352		let result = map_with_index::<VecBrand, _, _, _, _>(|i, x: &i32| *x + i as i32, &v);
353		assert_eq!(result, vec![10, 21, 32]);
354	}
355
356	// -- FilterWithIndexDispatch tests --
357
358	#[test]
359	fn test_val_vec_filter_with_index() {
360		use super::filterable_with_index::explicit::filter_with_index;
361		let result =
362			filter_with_index::<VecBrand, _, _, _>(|i, _x: i32| i < 2, vec![10, 20, 30, 40]);
363		assert_eq!(result, vec![10, 20]);
364	}
365
366	#[test]
367	fn test_ref_vec_filter_with_index() {
368		use super::filterable_with_index::explicit::filter_with_index;
369		let v = vec![10, 20, 30, 40];
370		let result = filter_with_index::<VecBrand, _, _, _>(|i, _x: &i32| i < 2, &v);
371		assert_eq!(result, vec![10, 20]);
372	}
373
374	// -- FilterMapWithIndexDispatch tests --
375
376	#[test]
377	fn test_val_vec_filter_map_with_index() {
378		use super::filterable_with_index::explicit::filter_map_with_index;
379		let result = filter_map_with_index::<VecBrand, _, _, _, _>(
380			|i, x: i32| if i % 2 == 0 { Some(x * 2) } else { None },
381			vec![10, 20, 30, 40],
382		);
383		assert_eq!(result, vec![20, 60]);
384	}
385
386	#[test]
387	fn test_ref_vec_filter_map_with_index() {
388		use super::filterable_with_index::explicit::filter_map_with_index;
389		let v = vec![10, 20, 30, 40];
390		let result = filter_map_with_index::<VecBrand, _, _, _, _>(
391			|i, x: &i32| if i % 2 == 0 { Some(*x * 2) } else { None },
392			&v,
393		);
394		assert_eq!(result, vec![20, 60]);
395	}
396
397	// -- PartitionWithIndexDispatch tests --
398
399	#[test]
400	fn test_val_vec_partition_with_index() {
401		use super::filterable_with_index::explicit::partition_with_index;
402		let (not_satisfied, satisfied) =
403			partition_with_index::<VecBrand, _, _, _>(|i, _x: i32| i < 2, vec![10, 20, 30, 40]);
404		assert_eq!(satisfied, vec![10, 20]);
405		assert_eq!(not_satisfied, vec![30, 40]);
406	}
407
408	#[test]
409	fn test_ref_vec_partition_with_index() {
410		use super::filterable_with_index::explicit::partition_with_index;
411		let v = vec![10, 20, 30, 40];
412		let (not_satisfied, satisfied) =
413			partition_with_index::<VecBrand, _, _, _>(|i, _x: &i32| i < 2, &v);
414		assert_eq!(satisfied, vec![10, 20]);
415		assert_eq!(not_satisfied, vec![30, 40]);
416	}
417
418	// -- PartitionMapWithIndexDispatch tests --
419
420	#[test]
421	fn test_val_vec_partition_map_with_index() {
422		use super::filterable_with_index::explicit::partition_map_with_index;
423		let (errs, oks) = partition_map_with_index::<VecBrand, _, _, _, _, _>(
424			|i, x: i32| if i < 2 { Ok(x) } else { Err(x) },
425			vec![10, 20, 30, 40],
426		);
427		assert_eq!(oks, vec![10, 20]);
428		assert_eq!(errs, vec![30, 40]);
429	}
430
431	#[test]
432	fn test_ref_vec_partition_map_with_index() {
433		use super::filterable_with_index::explicit::partition_map_with_index;
434		let v = vec![10, 20, 30, 40];
435		let (errs, oks) = partition_map_with_index::<VecBrand, _, _, _, _, _>(
436			|i, x: &i32| if i < 2 { Ok(*x) } else { Err(*x) },
437			&v,
438		);
439		assert_eq!(oks, vec![10, 20]);
440		assert_eq!(errs, vec![30, 40]);
441	}
442
443	// -- FoldMapWithIndexDispatch tests --
444
445	#[test]
446	fn test_val_vec_fold_map_with_index() {
447		use super::foldable_with_index::explicit::fold_map_with_index;
448		let result = fold_map_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
449			|i, x: i32| format!("{i}:{x}"),
450			vec![10, 20, 30],
451		);
452		assert_eq!(result, "0:101:202:30");
453	}
454
455	#[test]
456	fn test_ref_vec_fold_map_with_index() {
457		use super::foldable_with_index::explicit::fold_map_with_index;
458		let v = vec![10, 20, 30];
459		let result = fold_map_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
460			|i, x: &i32| format!("{i}:{x}"),
461			&v,
462		);
463		assert_eq!(result, "0:101:202:30");
464	}
465
466	// -- FoldRightWithIndexDispatch tests --
467
468	#[test]
469	fn test_val_vec_fold_right_with_index() {
470		use super::foldable_with_index::explicit::fold_right_with_index;
471		let result = fold_right_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
472			|i, x: i32, acc: String| format!("{acc}{i}:{x},"),
473			String::new(),
474			vec![10, 20, 30],
475		);
476		assert_eq!(result, "2:30,1:20,0:10,");
477	}
478
479	#[test]
480	fn test_ref_vec_fold_right_with_index() {
481		use super::foldable_with_index::explicit::fold_right_with_index;
482		let v = vec![10, 20, 30];
483		let result = fold_right_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
484			|i, x: &i32, acc: String| format!("{acc}{i}:{x},"),
485			String::new(),
486			&v,
487		);
488		assert_eq!(result, "2:30,1:20,0:10,");
489	}
490
491	// -- FoldLeftWithIndexDispatch tests --
492
493	#[test]
494	fn test_val_vec_fold_left_with_index() {
495		use super::foldable_with_index::explicit::fold_left_with_index;
496		let result = fold_left_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
497			|i, acc: String, x: i32| format!("{acc}{i}:{x},"),
498			String::new(),
499			vec![10, 20, 30],
500		);
501		assert_eq!(result, "0:10,1:20,2:30,");
502	}
503
504	#[test]
505	fn test_ref_vec_fold_left_with_index() {
506		use super::foldable_with_index::explicit::fold_left_with_index;
507		let v = vec![10, 20, 30];
508		let result = fold_left_with_index::<RcFnBrand, VecBrand, _, _, _, _>(
509			|i, acc: String, x: &i32| format!("{acc}{i}:{x},"),
510			String::new(),
511			&v,
512		);
513		assert_eq!(result, "0:10,1:20,2:30,");
514	}
515
516	// -- TraverseWithIndexDispatch tests --
517
518	#[test]
519	fn test_val_vec_traverse_with_index() {
520		use super::traversable_with_index::explicit::traverse_with_index;
521		let result = traverse_with_index::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(
522			|_i, x: i32| Some(x * 2),
523			vec![1, 2, 3],
524		);
525		assert_eq!(result, Some(vec![2, 4, 6]));
526	}
527
528	#[test]
529	fn test_ref_vec_traverse_with_index() {
530		use super::traversable_with_index::explicit::traverse_with_index;
531		let v = vec![1, 2, 3];
532		let result = traverse_with_index::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(
533			|_i, x: &i32| Some(*x * 2),
534			&v,
535		);
536		assert_eq!(result, Some(vec![2, 4, 6]));
537	}
538
539	// -- WiltDispatch tests --
540
541	#[test]
542	fn test_val_option_wilt() {
543		use super::witherable::explicit::wilt;
544		let result = wilt::<RcFnBrand, OptionBrand, OptionBrand, _, _, _, _, _>(
545			|a: i32| Some(if a > 2 { Ok(a) } else { Err(a) }),
546			Some(5),
547		);
548		assert_eq!(result, Some((None, Some(5))));
549	}
550
551	#[test]
552	fn test_ref_vec_wilt() {
553		use super::witherable::explicit::wilt;
554		let v = vec![1, 2, 3, 4, 5];
555		let result: Option<(Vec<i32>, Vec<i32>)> =
556			wilt::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _, _>(
557				|x: &i32| Some(if *x > 3 { Ok(*x) } else { Err(*x) }),
558				&v,
559			);
560		assert_eq!(result, Some((vec![1, 2, 3], vec![4, 5])));
561	}
562
563	// -- WitherDispatch tests --
564
565	#[test]
566	fn test_val_option_wither() {
567		use super::witherable::explicit::wither;
568		let result = wither::<RcFnBrand, OptionBrand, OptionBrand, _, _, _, _>(
569			|a: i32| Some(if a > 2 { Some(a * 2) } else { None }),
570			Some(5),
571		);
572		assert_eq!(result, Some(Some(10)));
573	}
574
575	#[test]
576	fn test_ref_vec_wither() {
577		use super::witherable::explicit::wither;
578		let v = vec![1, 2, 3, 4, 5];
579		let result: Option<Vec<i32>> = wither::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _>(
580			|x: &i32| if *x > 3 { Some(Some(*x)) } else { Some(None) },
581			&v,
582		);
583		assert_eq!(result, Some(vec![4, 5]));
584	}
585
586	// -- BimapDispatch tests --
587
588	#[test]
589	fn test_val_result_bimap() {
590		use super::bifunctor::explicit::bimap;
591		let x = Result::<i32, i32>::Ok(5);
592		let y = bimap::<ResultBrand, _, _, _, _, _, _>((|e| e + 1, |s| s * 2), x);
593		assert_eq!(y, Ok(10));
594	}
595
596	#[test]
597	fn test_val_result_bimap_err() {
598		use super::bifunctor::explicit::bimap;
599		let x = Result::<i32, i32>::Err(3);
600		let y = bimap::<ResultBrand, _, _, _, _, _, _>((|e| e + 1, |s| s * 2), x);
601		assert_eq!(y, Err(4));
602	}
603
604	#[test]
605	fn test_ref_result_bimap() {
606		use super::bifunctor::explicit::bimap;
607		let x = Result::<i32, i32>::Ok(5);
608		let y = bimap::<ResultBrand, _, _, _, _, _, _>((|e: &i32| *e + 1, |s: &i32| *s * 2), &x);
609		assert_eq!(y, Ok(10));
610	}
611
612	// -- BiFoldRightDispatch tests --
613
614	#[test]
615	fn test_val_result_bi_fold_right() {
616		use super::bifoldable::explicit::bi_fold_right;
617		let x: Result<i32, i32> = Err(3);
618		let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
619			(|e, acc| acc - e, |s, acc| acc + s),
620			10,
621			x,
622		);
623		assert_eq!(y, 7);
624	}
625
626	#[test]
627	fn test_ref_result_bi_fold_right() {
628		use super::bifoldable::explicit::bi_fold_right;
629		let x: Result<i32, i32> = Err(3);
630		let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
631			(|e: &i32, acc| acc - *e, |s: &i32, acc| acc + *s),
632			10,
633			&x,
634		);
635		assert_eq!(y, 7);
636	}
637
638	// -- BiFoldLeftDispatch tests --
639
640	#[test]
641	fn test_val_result_bi_fold_left() {
642		use super::bifoldable::explicit::bi_fold_left;
643		let x: Result<i32, i32> = Ok(5);
644		let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
645			(|acc, e| acc - e, |acc, s| acc + s),
646			10,
647			x,
648		);
649		assert_eq!(y, 15);
650	}
651
652	#[test]
653	fn test_ref_result_bi_fold_left() {
654		use super::bifoldable::explicit::bi_fold_left;
655		let x: Result<i32, i32> = Ok(5);
656		let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
657			(|acc, e: &i32| acc - *e, |acc, s: &i32| acc + *s),
658			10,
659			&x,
660		);
661		assert_eq!(y, 15);
662	}
663
664	// -- BiFoldMapDispatch tests --
665
666	#[test]
667	fn test_val_result_bi_fold_map() {
668		use super::bifoldable::explicit::bi_fold_map;
669		let x: Result<i32, i32> = Ok(5);
670		let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
671			(|e: i32| e.to_string(), |s: i32| s.to_string()),
672			x,
673		);
674		assert_eq!(y, "5".to_string());
675	}
676
677	#[test]
678	fn test_ref_result_bi_fold_map() {
679		use super::bifoldable::explicit::bi_fold_map;
680		let x: Result<i32, i32> = Ok(5);
681		let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
682			(|e: &i32| e.to_string(), |s: &i32| s.to_string()),
683			&x,
684		);
685		assert_eq!(y, "5".to_string());
686	}
687
688	// -- BiTraverseDispatch tests --
689
690	#[test]
691	fn test_val_result_bi_traverse() {
692		use super::bitraversable::explicit::bi_traverse;
693		let x: Result<i32, i32> = Ok(5);
694		let y = bi_traverse::<RcFnBrand, ResultBrand, _, _, _, _, OptionBrand, _, _>(
695			(|e: i32| Some(e + 1), |s: i32| Some(s * 2)),
696			x,
697		);
698		assert_eq!(y, Some(Ok(10)));
699	}
700
701	#[test]
702	fn test_ref_result_bi_traverse() {
703		use super::bitraversable::explicit::bi_traverse;
704		let x: Result<i32, i32> = Ok(5);
705		let y = bi_traverse::<RcFnBrand, ResultBrand, _, _, _, _, OptionBrand, _, _>(
706			(|e: &i32| Some(*e + 1), |s: &i32| Some(*s * 2)),
707			&x,
708		);
709		assert_eq!(y, Some(Ok(10)));
710	}
711}