Skip to main content

FnBiTransformerOps

Trait FnBiTransformerOps 

Source
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); // multiply

§Author

Haixing Hu

Provided Methods§

Source

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 transformer
  • F - 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 implements Clone). 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>
§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?
examples/transformers/fn_bi_transformer_ops_demo.rs (line 27)
19fn main() {
20    println!("=== FnBiTransformerOps Demo ===\n");
21
22    // Example 1: Basic and_then composition
23    println!("1. Basic and_then composition:");
24    let add = |x: i32, y: i32| x + y;
25    let double = |x: i32| x * 2;
26
27    let composed = add.and_then(double);
28    let result = composed.apply(3, 5);
29    println!("   (3 + 5) * 2 = {}", result);
30    println!();
31
32    // Example 2: Type conversion and_then
33    println!("2. Type conversion and_then:");
34    let multiply = |x: i32, y: i32| x * y;
35    let to_string = |x: i32| format!("Result: {}", x);
36
37    let composed = multiply.and_then(to_string);
38    let result = composed.apply(6, 7);
39    println!("   6 * 7 = {}", result);
40    println!();
41
42    // Example 3: Conditional execution - when
43    println!("3. Conditional execution - when:");
44    let add = |x: i32, y: i32| x + y;
45    let multiply = |x: i32, y: i32| x * y;
46
47    let conditional = add
48        .when(|x: &i32, y: &i32| *x > 0 && *y > 0)
49        .or_else(multiply);
50
51    println!("   When both numbers are positive, perform addition, otherwise multiplication:");
52    println!("   conditional(5, 3) = {}", conditional.apply(5, 3));
53    println!("   conditional(-5, 3) = {}", conditional.apply(-5, 3));
54    println!();
55
56    // Example 4: Complex conditional logic
57    println!("4. Complex conditional logic:");
58    let add = |x: i32, y: i32| x + y;
59    let subtract = |x: i32, y: i32| x - y;
60
61    let conditional = add
62        .when(|x: &i32, y: &i32| (*x + *y) < 100)
63        .or_else(subtract);
64
65    println!("   When sum is less than 100, perform addition, otherwise subtraction:");
66    println!("   conditional(30, 40) = {}", conditional.apply(30, 40));
67    println!("   conditional(60, 50) = {}", conditional.apply(60, 50));
68    println!();
69
70    // Example 5: String operations
71    println!("5. String operations:");
72    let concat = |x: String, y: String| format!("{}-{}", x, y);
73    let uppercase = |s: String| s.to_uppercase();
74
75    let composed = concat.and_then(uppercase);
76    let result = composed.apply("hello".to_string(), "world".to_string());
77    println!("   concat + uppercase: {}", result);
78    println!();
79
80    // Example 6: Function pointers can also be used
81    println!("6. Function pointers can also be used:");
82    fn add_fn(x: i32, y: i32) -> i32 {
83        x + y
84    }
85    fn triple(x: i32) -> i32 {
86        x * 3
87    }
88
89    let composed = add_fn.and_then(triple);
90    let result = composed.apply(4, 6);
91    println!("   (4 + 6) * 3 = {}", result);
92    println!();
93
94    // Example 7: Real application - Calculator
95    println!("7. Real application - Simple calculator:");
96    let calculate = |x: i32, y: i32| x + y;
97    let format_result = |result: i32| {
98        if result >= 0 {
99            format!("✓ Result: {}", result)
100        } else {
101            format!("✗ Negative result: {}", result)
102        }
103    };
104
105    let calculator = calculate.and_then(format_result);
106    println!("   10 + 5 = {}", calculator.apply(10, 5));
107    println!("   -10 + 3 = {}", calculator.apply(-10, 3));
108    println!();
109
110    // Example 8: Combining multiple operations
111    println!("8. Combining multiple operations:");
112    let add = |x: i32, y: i32| x + y;
113
114    // First calculate the sum, then choose different formatting based on whether it's even
115    let sum_and_format = add.and_then(|n| {
116        if n % 2 == 0 {
117            format!("{} is even", n)
118        } else {
119            format!("{} is odd", n)
120        }
121    });
122
123    println!("   3 + 5 = {}", sum_and_format.apply(3, 5));
124    println!("   4 + 6 = {}", sum_and_format.apply(4, 6));
125
126    println!("\n=== Demo completed ===");
127}
Source

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 implements Clone). 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>
§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?
examples/transformers/fn_bi_transformer_ops_demo.rs (line 48)
19fn main() {
20    println!("=== FnBiTransformerOps Demo ===\n");
21
22    // Example 1: Basic and_then composition
23    println!("1. Basic and_then composition:");
24    let add = |x: i32, y: i32| x + y;
25    let double = |x: i32| x * 2;
26
27    let composed = add.and_then(double);
28    let result = composed.apply(3, 5);
29    println!("   (3 + 5) * 2 = {}", result);
30    println!();
31
32    // Example 2: Type conversion and_then
33    println!("2. Type conversion and_then:");
34    let multiply = |x: i32, y: i32| x * y;
35    let to_string = |x: i32| format!("Result: {}", x);
36
37    let composed = multiply.and_then(to_string);
38    let result = composed.apply(6, 7);
39    println!("   6 * 7 = {}", result);
40    println!();
41
42    // Example 3: Conditional execution - when
43    println!("3. Conditional execution - when:");
44    let add = |x: i32, y: i32| x + y;
45    let multiply = |x: i32, y: i32| x * y;
46
47    let conditional = add
48        .when(|x: &i32, y: &i32| *x > 0 && *y > 0)
49        .or_else(multiply);
50
51    println!("   When both numbers are positive, perform addition, otherwise multiplication:");
52    println!("   conditional(5, 3) = {}", conditional.apply(5, 3));
53    println!("   conditional(-5, 3) = {}", conditional.apply(-5, 3));
54    println!();
55
56    // Example 4: Complex conditional logic
57    println!("4. Complex conditional logic:");
58    let add = |x: i32, y: i32| x + y;
59    let subtract = |x: i32, y: i32| x - y;
60
61    let conditional = add
62        .when(|x: &i32, y: &i32| (*x + *y) < 100)
63        .or_else(subtract);
64
65    println!("   When sum is less than 100, perform addition, otherwise subtraction:");
66    println!("   conditional(30, 40) = {}", conditional.apply(30, 40));
67    println!("   conditional(60, 50) = {}", conditional.apply(60, 50));
68    println!();
69
70    // Example 5: String operations
71    println!("5. String operations:");
72    let concat = |x: String, y: String| format!("{}-{}", x, y);
73    let uppercase = |s: String| s.to_uppercase();
74
75    let composed = concat.and_then(uppercase);
76    let result = composed.apply("hello".to_string(), "world".to_string());
77    println!("   concat + uppercase: {}", result);
78    println!();
79
80    // Example 6: Function pointers can also be used
81    println!("6. Function pointers can also be used:");
82    fn add_fn(x: i32, y: i32) -> i32 {
83        x + y
84    }
85    fn triple(x: i32) -> i32 {
86        x * 3
87    }
88
89    let composed = add_fn.and_then(triple);
90    let result = composed.apply(4, 6);
91    println!("   (4 + 6) * 3 = {}", result);
92    println!();
93
94    // Example 7: Real application - Calculator
95    println!("7. Real application - Simple calculator:");
96    let calculate = |x: i32, y: i32| x + y;
97    let format_result = |result: i32| {
98        if result >= 0 {
99            format!("✓ Result: {}", result)
100        } else {
101            format!("✗ Negative result: {}", result)
102        }
103    };
104
105    let calculator = calculate.and_then(format_result);
106    println!("   10 + 5 = {}", calculator.apply(10, 5));
107    println!("   -10 + 3 = {}", calculator.apply(-10, 3));
108    println!();
109
110    // Example 8: Combining multiple operations
111    println!("8. Combining multiple operations:");
112    let add = |x: i32, y: i32| x + y;
113
114    // First calculate the sum, then choose different formatting based on whether it's even
115    let sum_and_format = add.and_then(|n| {
116        if n % 2 == 0 {
117            format!("{} is even", n)
118        } else {
119            format!("{} is odd", n)
120        }
121    });
122
123    println!("   3 + 5 = {}", sum_and_format.apply(3, 5));
124    println!("   4 + 6 = {}", sum_and_format.apply(4, 6));
125
126    println!("\n=== Demo completed ===");
127}

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§

Source§

impl<T, U, R, F> FnBiTransformerOps<T, U, R> for F
where 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.

§Author

Haixing Hu