pub trait FnBiTransformerOps<T, U, R>: Fn(T, U) -> R + Sized {
// Provided methods
fn and_then<S, F>(self, after: F) -> BoxBiTransformer<T, U, S>
where Self: 'static,
S: 'static,
F: Transformer<R, S> + 'static,
T: 'static,
U: 'static,
R: 'static { ... }
fn when<P>(self, predicate: P) -> BoxConditionalBiTransformer<T, U, R>
where Self: 'static,
P: BiPredicate<T, U> + 'static,
T: 'static,
U: 'static,
R: 'static { ... }
}Expand description
Extension trait for closures implementing Fn(T, U) -> R
Provides composition methods (and_then, when) for bi-transformer
closures and function pointers without requiring explicit wrapping in
BoxBiTransformer.
This trait is automatically implemented for all closures and function
pointers that implement Fn(T, U) -> R.
§Design Rationale
While closures automatically implement BiTransformer<T, U, R> through
blanket implementation, they don’t have access to instance methods like
and_then and when. This extension trait provides those methods,
returning BoxBiTransformer for maximum flexibility.
§Examples
§Chain composition with and_then
use qubit_function::{BiTransformer, FnBiTransformerOps};
let add = |x: i32, y: i32| x + y;
let double = |x: i32| x * 2;
let composed = add.and_then(double);
assert_eq!(composed.apply(3, 5), 16); // (3 + 5) * 2§Conditional execution with when
use qubit_function::{BiTransformer, FnBiTransformerOps};
let add = |x: i32, y: i32| x + y;
let multiply = |x: i32, y: i32| x * y;
let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply);
assert_eq!(conditional.apply(5, 3), 8); // add
assert_eq!(conditional.apply(-5, 3), -15); // multiplyProvided Methods§
Sourcefn and_then<S, F>(self, after: F) -> BoxBiTransformer<T, U, S>where
Self: 'static,
S: 'static,
F: Transformer<R, S> + 'static,
T: 'static,
U: 'static,
R: 'static,
fn and_then<S, F>(self, after: F) -> BoxBiTransformer<T, U, S>where
Self: 'static,
S: 'static,
F: Transformer<R, S> + 'static,
T: 'static,
U: 'static,
R: 'static,
Chain composition - applies self first, then after
Creates a new bi-transformer that applies this bi-transformer first,
then applies the after transformer to the result. Consumes self and
returns a BoxBiTransformer.
§Type Parameters
S- The output type of the after transformerF- The type of the after transformer (must implement Transformer<R, S>)
§Parameters
after- The transformer to apply after self. Note: This parameter is passed by value and will transfer ownership. If you need to preserve the original transformer, clone it first (if it implementsClone). Can be:- A closure:
|x: R| -> S - A function pointer:
fn(R) -> S - A
BoxTransformer<R, S> - An
RcTransformer<R, S> - An
ArcTransformer<R, S> - Any type implementing
Transformer<R, S>
- A closure:
§Returns
A new BoxBiTransformer<T, U, S> representing the composition
§Examples
§Direct value passing (ownership transfer)
use qubit_function::{BiTransformer, FnBiTransformerOps,
BoxTransformer};
let add = |x: i32, y: i32| x + y;
let to_string = BoxTransformer::new(|x: i32| x.to_string());
// to_string is moved here
let composed = add.and_then(to_string);
assert_eq!(composed.apply(20, 22), "42");
// to_string.apply(10); // Would not compile - moved§Preserving original with separate transformers
use qubit_function::{BiTransformer, FnBiTransformerOps};
let add = |x: i32, y: i32| x + y;
let to_string = |x: i32| x.to_string();
let to_string_for_validation = |x: i32| x.to_string();
let composed = add.and_then(to_string);
assert_eq!(composed.apply(20, 22), "42");
// Original still usable
assert_eq!(to_string_for_validation(10), "10");Examples found in repository?
20fn main() {
21 println!("=== FnBiTransformerOps Demo ===\n");
22
23 // Example 1: Basic and_then composition
24 println!("1. Basic and_then composition:");
25 let add = |x: i32, y: i32| x + y;
26 let double = |x: i32| x * 2;
27
28 let composed = add.and_then(double);
29 let result = composed.apply(3, 5);
30 println!(" (3 + 5) * 2 = {}", result);
31 println!();
32
33 // Example 2: Type conversion and_then
34 println!("2. Type conversion and_then:");
35 let multiply = |x: i32, y: i32| x * y;
36 let to_string = |x: i32| format!("Result: {}", x);
37
38 let composed = multiply.and_then(to_string);
39 let result = composed.apply(6, 7);
40 println!(" 6 * 7 = {}", result);
41 println!();
42
43 // Example 3: Conditional execution - when
44 println!("3. Conditional execution - when:");
45 let add = |x: i32, y: i32| x + y;
46 let multiply = |x: i32, y: i32| x * y;
47
48 let conditional = add
49 .when(|x: &i32, y: &i32| *x > 0 && *y > 0)
50 .or_else(multiply);
51
52 println!(" When both numbers are positive, perform addition, otherwise multiplication:");
53 println!(" conditional(5, 3) = {}", conditional.apply(5, 3));
54 println!(" conditional(-5, 3) = {}", conditional.apply(-5, 3));
55 println!();
56
57 // Example 4: Complex conditional logic
58 println!("4. Complex conditional logic:");
59 let add = |x: i32, y: i32| x + y;
60 let subtract = |x: i32, y: i32| x - y;
61
62 let conditional = add
63 .when(|x: &i32, y: &i32| (*x + *y) < 100)
64 .or_else(subtract);
65
66 println!(" When sum is less than 100, perform addition, otherwise subtraction:");
67 println!(" conditional(30, 40) = {}", conditional.apply(30, 40));
68 println!(" conditional(60, 50) = {}", conditional.apply(60, 50));
69 println!();
70
71 // Example 5: String operations
72 println!("5. String operations:");
73 let concat = |x: String, y: String| format!("{}-{}", x, y);
74 let uppercase = |s: String| s.to_uppercase();
75
76 let composed = concat.and_then(uppercase);
77 let result = composed.apply("hello".to_string(), "world".to_string());
78 println!(" concat + uppercase: {}", result);
79 println!();
80
81 // Example 6: Function pointers can also be used
82 println!("6. Function pointers can also be used:");
83 fn add_fn(x: i32, y: i32) -> i32 {
84 x + y
85 }
86 fn triple(x: i32) -> i32 {
87 x * 3
88 }
89
90 let composed = add_fn.and_then(triple);
91 let result = composed.apply(4, 6);
92 println!(" (4 + 6) * 3 = {}", result);
93 println!();
94
95 // Example 7: Real application - Calculator
96 println!("7. Real application - Simple calculator:");
97 let calculate = |x: i32, y: i32| x + y;
98 let format_result = |result: i32| {
99 if result >= 0 {
100 format!("✓ Result: {}", result)
101 } else {
102 format!("✗ Negative result: {}", result)
103 }
104 };
105
106 let calculator = calculate.and_then(format_result);
107 println!(" 10 + 5 = {}", calculator.apply(10, 5));
108 println!(" -10 + 3 = {}", calculator.apply(-10, 3));
109 println!();
110
111 // Example 8: Combining multiple operations
112 println!("8. Combining multiple operations:");
113 let add = |x: i32, y: i32| x + y;
114
115 // First calculate the sum, then choose different formatting based on whether it's even
116 let sum_and_format = add.and_then(|n| {
117 if n % 2 == 0 {
118 format!("{} is even", n)
119 } else {
120 format!("{} is odd", n)
121 }
122 });
123
124 println!(" 3 + 5 = {}", sum_and_format.apply(3, 5));
125 println!(" 4 + 6 = {}", sum_and_format.apply(4, 6));
126
127 println!("\n=== Demo completed ===");
128}Sourcefn when<P>(self, predicate: P) -> BoxConditionalBiTransformer<T, U, R>where
Self: 'static,
P: BiPredicate<T, U> + 'static,
T: 'static,
U: 'static,
R: 'static,
fn when<P>(self, predicate: P) -> BoxConditionalBiTransformer<T, U, R>where
Self: 'static,
P: BiPredicate<T, U> + 'static,
T: 'static,
U: 'static,
R: 'static,
Creates a conditional bi-transformer
Returns a bi-transformer that only executes when a bi-predicate is
satisfied. You must call or_else() to provide an alternative
bi-transformer for when the condition is not satisfied.
§Parameters
predicate- The condition to check. Note: This parameter is passed by value and will transfer ownership. If you need to preserve the original bi-predicate, clone it first (if it implementsClone). Can be:- A closure:
|x: &T, y: &U| -> bool - A function pointer:
fn(&T, &U) -> bool - A
BoxBiPredicate<T, U> - An
RcBiPredicate<T, U> - An
ArcBiPredicate<T, U> - Any type implementing
BiPredicate<T, U>
- A closure:
§Returns
Returns BoxConditionalBiTransformer<T, U, R>
§Examples
§Basic usage with or_else
use qubit_function::{BiTransformer, FnBiTransformerOps};
let add = |x: i32, y: i32| x + y;
let conditional = add.when(|x: &i32, y: &i32| *x > 0)
.or_else(|x: i32, y: i32| x * y);
assert_eq!(conditional.apply(5, 3), 8);
assert_eq!(conditional.apply(-5, 3), -15);§Preserving original with separate bi-predicates
use qubit_function::{BiTransformer, FnBiTransformerOps};
let add = |x: i32, y: i32| x + y;
let both_positive = |x: &i32, y: &i32| *x > 0 && *y > 0;
let both_positive_for_validation = |x: &i32, y: &i32|
*x > 0 && *y > 0;
let conditional = add.when(both_positive)
.or_else(|x: i32, y: i32| x * y);
assert_eq!(conditional.apply(5, 3), 8);
// Original bi-predicate still usable
assert!(both_positive_for_validation(&5, &3));Examples found in repository?
20fn main() {
21 println!("=== FnBiTransformerOps Demo ===\n");
22
23 // Example 1: Basic and_then composition
24 println!("1. Basic and_then composition:");
25 let add = |x: i32, y: i32| x + y;
26 let double = |x: i32| x * 2;
27
28 let composed = add.and_then(double);
29 let result = composed.apply(3, 5);
30 println!(" (3 + 5) * 2 = {}", result);
31 println!();
32
33 // Example 2: Type conversion and_then
34 println!("2. Type conversion and_then:");
35 let multiply = |x: i32, y: i32| x * y;
36 let to_string = |x: i32| format!("Result: {}", x);
37
38 let composed = multiply.and_then(to_string);
39 let result = composed.apply(6, 7);
40 println!(" 6 * 7 = {}", result);
41 println!();
42
43 // Example 3: Conditional execution - when
44 println!("3. Conditional execution - when:");
45 let add = |x: i32, y: i32| x + y;
46 let multiply = |x: i32, y: i32| x * y;
47
48 let conditional = add
49 .when(|x: &i32, y: &i32| *x > 0 && *y > 0)
50 .or_else(multiply);
51
52 println!(" When both numbers are positive, perform addition, otherwise multiplication:");
53 println!(" conditional(5, 3) = {}", conditional.apply(5, 3));
54 println!(" conditional(-5, 3) = {}", conditional.apply(-5, 3));
55 println!();
56
57 // Example 4: Complex conditional logic
58 println!("4. Complex conditional logic:");
59 let add = |x: i32, y: i32| x + y;
60 let subtract = |x: i32, y: i32| x - y;
61
62 let conditional = add
63 .when(|x: &i32, y: &i32| (*x + *y) < 100)
64 .or_else(subtract);
65
66 println!(" When sum is less than 100, perform addition, otherwise subtraction:");
67 println!(" conditional(30, 40) = {}", conditional.apply(30, 40));
68 println!(" conditional(60, 50) = {}", conditional.apply(60, 50));
69 println!();
70
71 // Example 5: String operations
72 println!("5. String operations:");
73 let concat = |x: String, y: String| format!("{}-{}", x, y);
74 let uppercase = |s: String| s.to_uppercase();
75
76 let composed = concat.and_then(uppercase);
77 let result = composed.apply("hello".to_string(), "world".to_string());
78 println!(" concat + uppercase: {}", result);
79 println!();
80
81 // Example 6: Function pointers can also be used
82 println!("6. Function pointers can also be used:");
83 fn add_fn(x: i32, y: i32) -> i32 {
84 x + y
85 }
86 fn triple(x: i32) -> i32 {
87 x * 3
88 }
89
90 let composed = add_fn.and_then(triple);
91 let result = composed.apply(4, 6);
92 println!(" (4 + 6) * 3 = {}", result);
93 println!();
94
95 // Example 7: Real application - Calculator
96 println!("7. Real application - Simple calculator:");
97 let calculate = |x: i32, y: i32| x + y;
98 let format_result = |result: i32| {
99 if result >= 0 {
100 format!("✓ Result: {}", result)
101 } else {
102 format!("✗ Negative result: {}", result)
103 }
104 };
105
106 let calculator = calculate.and_then(format_result);
107 println!(" 10 + 5 = {}", calculator.apply(10, 5));
108 println!(" -10 + 3 = {}", calculator.apply(-10, 3));
109 println!();
110
111 // Example 8: Combining multiple operations
112 println!("8. Combining multiple operations:");
113 let add = |x: i32, y: i32| x + y;
114
115 // First calculate the sum, then choose different formatting based on whether it's even
116 let sum_and_format = add.and_then(|n| {
117 if n % 2 == 0 {
118 format!("{} is even", n)
119 } else {
120 format!("{} is odd", n)
121 }
122 });
123
124 println!(" 3 + 5 = {}", sum_and_format.apply(3, 5));
125 println!(" 4 + 6 = {}", sum_and_format.apply(4, 6));
126
127 println!("\n=== Demo completed ===");
128}Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.
Implementors§
impl<T, U, R, F> FnBiTransformerOps<T, U, R> for Fwhere
F: Fn(T, U) -> R,
Blanket implementation of FnBiTransformerOps for all closures
Automatically implements FnBiTransformerOps<T, U, R> for any type that
implements Fn(T, U) -> R.