Skip to main content

FnTransformerOps

Trait FnTransformerOps 

Source
pub trait FnTransformerOps<T, R>: Fn(T) -> R + Sized {
    // Provided methods
    fn and_then<S, F>(self, after: F) -> BoxTransformer<T, S>
       where Self: 'static,
             S: 'static,
             F: Transformer<R, S> + 'static,
             T: 'static,
             R: 'static { ... }
    fn compose<S, F>(self, before: F) -> BoxTransformer<S, R>
       where Self: 'static,
             S: 'static,
             F: Transformer<S, T> + 'static,
             T: 'static,
             R: 'static { ... }
    fn when<P>(self, predicate: P) -> BoxConditionalTransformer<T, R>
       where Self: 'static,
             P: Predicate<T> + 'static,
             T: 'static,
             R: 'static { ... }
}
Expand description

Extension trait for closures implementing the base transformer trait

Provides composition methods (and_then, compose, when) for closures and function pointers without requiring explicit wrapping.

This trait is automatically implemented for all closures and function pointers that implement the base transformer trait.

§Design Rationale

While closures automatically implement the base transformer trait through blanket implementation, they don’t have access to instance methods like and_then, compose, and when. This extension trait provides those methods, returning the appropriate Box-based transformer type for maximum flexibility.

Provided Methods§

Source

fn and_then<S, F>(self, after: F) -> BoxTransformer<T, S>
where Self: 'static, S: 'static, F: Transformer<R, S> + 'static, T: 'static, R: 'static,

Chain composition - applies self first, then after

Creates a new transformer that applies this transformer first, then applies the after transformer to the result. Consumes self and returns a Box-based transformer.

§Type Parameters
  • S - The output type of the after transformer
  • F - The type of the after transformer (must implement the transformer trait)
§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
    • A function pointer
    • A Box-based transformer
    • An Rc-based transformer
    • An Arc-based transformer
    • Any type implementing the transformer trait
§Returns

A new Box-based transformer representing the composition

§Examples
§Direct value passing (ownership transfer)
use qubit_function::{BoxTransformer, FnTransformerOps, Transformer};

let double = |x: i32| x * 2;
let to_string = BoxTransformer::new(|x: i32| x.to_string());

// to_string is moved here
let composed = double.and_then(to_string);
assert_eq!(composed.apply(21), "42");
// to_string.apply(5); // Would not compile - moved
§Preserving behavior with separate closures
use qubit_function::{BoxTransformer, FnTransformerOps, Transformer};

let double = |x: i32| x * 2;
let to_string_for_validation = |x: i32| x.to_string();

let composed = double.and_then(BoxTransformer::new(|x: i32| x.to_string()));
assert_eq!(composed.apply(21), "42");

assert_eq!(to_string_for_validation(5), "5");
Examples found in repository?
examples/transformers/fn_transformer_ops_demo.rs (line 27)
20fn main() {
21    println!("=== FnTransformerOps Example ===\n");
22
23    // 1. Basic and_then composition
24    println!("1. Basic and_then composition:");
25    let double = |x: i32| x * 2;
26    let to_string = |x: i32| x.to_string();
27    let composed = double.and_then(to_string);
28    println!("   double.and_then(to_string).apply(21) = {}", composed.apply(21));
29    println!();
30
31    // 2. Chained and_then composition
32    println!("2. Chained and_then composition:");
33    let add_one = |x: i32| x + 1;
34    let double = |x: i32| x * 2;
35    let to_string = |x: i32| x.to_string();
36    let chained = add_one.and_then(double).and_then(to_string);
37    println!(
38        "   add_one.and_then(double).and_then(to_string).apply(5) = {}",
39        chained.apply(5)
40    ); // (5 + 1) * 2 = 12
41    println!();
42
43    // 3. compose reverse composition
44    println!("3. compose reverse composition:");
45    let double = |x: i32| x * 2;
46    let add_one = |x: i32| x + 1;
47    let composed = double.compose(add_one);
48    println!("   double.compose(add_one).apply(5) = {}", composed.apply(5)); // (5 + 1) * 2 = 12
49    println!();
50
51    // 4. Conditional transformation when
52    println!("4. Conditional transformation when:");
53    let double = |x: i32| x * 2;
54    let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
55    println!("   double.when(x > 0).or_else(negate):");
56    println!("     transform(5) = {}", conditional.apply(5)); // 10
57    println!("     transform(-5) = {}", conditional.apply(-5)); // 5
58    println!();
59
60    // 5. Complex composition
61    println!("5. Complex composition:");
62    let add_one = |x: i32| x + 1;
63    let double = |x: i32| x * 2;
64    let triple = |x: i32| x * 3;
65    let to_string = |x: i32| x.to_string();
66
67    let complex = add_one
68        .and_then(double.when(|x: &i32| *x > 5).or_else(triple))
69        .and_then(to_string);
70
71    println!("   add_one.and_then(double.when(x > 5).or_else(triple)).and_then(to_string):");
72    println!("     transform(1) = {}", complex.apply(1)); // (1 + 1) = 2 <= 5, so 2 * 3 = 6
73    println!("     transform(5) = {}", complex.apply(5)); // (5 + 1) = 6 > 5, so 6 * 2 = 12
74    println!("     transform(10) = {}", complex.apply(10)); // (10 + 1) = 11 > 5, so 11 * 2 = 22
75    println!();
76
77    // 6. Type conversion
78    println!("6. Type conversion:");
79    let to_string = |x: i32| x.to_string();
80    let get_length = |s: String| s.len();
81    let length_transformer = to_string.and_then(get_length);
82    println!(
83        "   to_string.and_then(get_length).apply(12345) = {}",
84        length_transformer.apply(12345)
85    ); // 5
86    println!();
87
88    // 7. Closures that capture environment
89    println!("7. Closures that capture environment:");
90    let multiplier = 3;
91    let multiply = move |x: i32| x * multiplier;
92    let add_ten = |x: i32| x + 10;
93    let with_capture = multiply.and_then(add_ten);
94    println!("   multiply(3).and_then(add_ten).apply(5) = {}", with_capture.apply(5)); // 5 * 3 + 10 = 25
95    println!();
96
97    // 8. Function pointers
98    println!("8. Function pointers:");
99    fn double_fn(x: i32) -> i32 {
100        x * 2
101    }
102    fn add_one_fn(x: i32) -> i32 {
103        x + 1
104    }
105    let fn_composed = double_fn.and_then(add_one_fn);
106    println!("   double_fn.and_then(add_one_fn).apply(5) = {}", fn_composed.apply(5)); // 5 * 2 + 1 = 11
107    println!();
108
109    // 9. Multi-conditional transformation
110    println!("9. Multi-conditional transformation:");
111    let abs = |x: i32| x.abs();
112    let double = |x: i32| x * 2;
113    let transformer = abs.when(|x: &i32| *x < 0).or_else(double);
114    println!("   abs.when(x < 0).or_else(double):");
115    println!("     transform(-5) = {}", transformer.apply(-5)); // abs(-5) = 5
116    println!("     transform(5) = {}", transformer.apply(5)); // 5 * 2 = 10
117    println!("     transform(0) = {}", transformer.apply(0)); // 0 * 2 = 0
118    println!();
119
120    println!("=== Example completed ===");
121}
Source

fn compose<S, F>(self, before: F) -> BoxTransformer<S, R>
where Self: 'static, S: 'static, F: Transformer<S, T> + 'static, T: 'static, R: 'static,

Reverse composition - applies before first, then self.

Creates a new transformer that applies the before transformer first, then applies this transformer to the result. Consumes self and returns a Box-based transformer.

§Type Parameters
  • S - The input type of the before transformer
  • F - The type of the before transformer
§Parameters
  • before - The transformer to apply before self.
§Returns

A new Box-based transformer representing the reverse composition.

Examples found in repository?
examples/transformers/fn_transformer_ops_demo.rs (line 47)
20fn main() {
21    println!("=== FnTransformerOps Example ===\n");
22
23    // 1. Basic and_then composition
24    println!("1. Basic and_then composition:");
25    let double = |x: i32| x * 2;
26    let to_string = |x: i32| x.to_string();
27    let composed = double.and_then(to_string);
28    println!("   double.and_then(to_string).apply(21) = {}", composed.apply(21));
29    println!();
30
31    // 2. Chained and_then composition
32    println!("2. Chained and_then composition:");
33    let add_one = |x: i32| x + 1;
34    let double = |x: i32| x * 2;
35    let to_string = |x: i32| x.to_string();
36    let chained = add_one.and_then(double).and_then(to_string);
37    println!(
38        "   add_one.and_then(double).and_then(to_string).apply(5) = {}",
39        chained.apply(5)
40    ); // (5 + 1) * 2 = 12
41    println!();
42
43    // 3. compose reverse composition
44    println!("3. compose reverse composition:");
45    let double = |x: i32| x * 2;
46    let add_one = |x: i32| x + 1;
47    let composed = double.compose(add_one);
48    println!("   double.compose(add_one).apply(5) = {}", composed.apply(5)); // (5 + 1) * 2 = 12
49    println!();
50
51    // 4. Conditional transformation when
52    println!("4. Conditional transformation when:");
53    let double = |x: i32| x * 2;
54    let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
55    println!("   double.when(x > 0).or_else(negate):");
56    println!("     transform(5) = {}", conditional.apply(5)); // 10
57    println!("     transform(-5) = {}", conditional.apply(-5)); // 5
58    println!();
59
60    // 5. Complex composition
61    println!("5. Complex composition:");
62    let add_one = |x: i32| x + 1;
63    let double = |x: i32| x * 2;
64    let triple = |x: i32| x * 3;
65    let to_string = |x: i32| x.to_string();
66
67    let complex = add_one
68        .and_then(double.when(|x: &i32| *x > 5).or_else(triple))
69        .and_then(to_string);
70
71    println!("   add_one.and_then(double.when(x > 5).or_else(triple)).and_then(to_string):");
72    println!("     transform(1) = {}", complex.apply(1)); // (1 + 1) = 2 <= 5, so 2 * 3 = 6
73    println!("     transform(5) = {}", complex.apply(5)); // (5 + 1) = 6 > 5, so 6 * 2 = 12
74    println!("     transform(10) = {}", complex.apply(10)); // (10 + 1) = 11 > 5, so 11 * 2 = 22
75    println!();
76
77    // 6. Type conversion
78    println!("6. Type conversion:");
79    let to_string = |x: i32| x.to_string();
80    let get_length = |s: String| s.len();
81    let length_transformer = to_string.and_then(get_length);
82    println!(
83        "   to_string.and_then(get_length).apply(12345) = {}",
84        length_transformer.apply(12345)
85    ); // 5
86    println!();
87
88    // 7. Closures that capture environment
89    println!("7. Closures that capture environment:");
90    let multiplier = 3;
91    let multiply = move |x: i32| x * multiplier;
92    let add_ten = |x: i32| x + 10;
93    let with_capture = multiply.and_then(add_ten);
94    println!("   multiply(3).and_then(add_ten).apply(5) = {}", with_capture.apply(5)); // 5 * 3 + 10 = 25
95    println!();
96
97    // 8. Function pointers
98    println!("8. Function pointers:");
99    fn double_fn(x: i32) -> i32 {
100        x * 2
101    }
102    fn add_one_fn(x: i32) -> i32 {
103        x + 1
104    }
105    let fn_composed = double_fn.and_then(add_one_fn);
106    println!("   double_fn.and_then(add_one_fn).apply(5) = {}", fn_composed.apply(5)); // 5 * 2 + 1 = 11
107    println!();
108
109    // 9. Multi-conditional transformation
110    println!("9. Multi-conditional transformation:");
111    let abs = |x: i32| x.abs();
112    let double = |x: i32| x * 2;
113    let transformer = abs.when(|x: &i32| *x < 0).or_else(double);
114    println!("   abs.when(x < 0).or_else(double):");
115    println!("     transform(-5) = {}", transformer.apply(-5)); // abs(-5) = 5
116    println!("     transform(5) = {}", transformer.apply(5)); // 5 * 2 = 10
117    println!("     transform(0) = {}", transformer.apply(0)); // 0 * 2 = 0
118    println!();
119
120    println!("=== Example completed ===");
121}
Source

fn when<P>(self, predicate: P) -> BoxConditionalTransformer<T, R>
where Self: 'static, P: Predicate<T> + 'static, T: 'static, R: 'static,

Creates a conditional transformer

Returns a transformer that only executes when a predicate is satisfied. You must call or_else() to provide an alternative 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 predicate, clone it first (if it implements Clone). Can be:
    • A closure: |x: &T| -> bool
    • A function pointer: fn(&T) -> bool
    • A BoxPredicate<T>
    • An RcPredicate<T>
    • An ArcPredicate<T>
    • Any type implementing Predicate<T>
§Returns

Returns the appropriate conditional transformer type

§Examples
§Basic usage with or_else
use qubit_function::{Transformer, FnTransformerOps};

let double = |x: i32| x * 2;
let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);

assert_eq!(conditional.apply(5), 10);
assert_eq!(conditional.apply(-5), 5);
§Reusing equivalent predicate logic
use qubit_function::{FnTransformerOps, Transformer};

let double = |x: i32| x * 2;
let is_positive_for_validation = |x: &i32| *x > 0;

let conditional = double.when(|x: &i32| *x > 0)
    .or_else(|x: i32| -x);

assert_eq!(conditional.apply(5), 10);
assert!(is_positive_for_validation(&3));
Examples found in repository?
examples/transformers/fn_transformer_ops_demo.rs (line 54)
20fn main() {
21    println!("=== FnTransformerOps Example ===\n");
22
23    // 1. Basic and_then composition
24    println!("1. Basic and_then composition:");
25    let double = |x: i32| x * 2;
26    let to_string = |x: i32| x.to_string();
27    let composed = double.and_then(to_string);
28    println!("   double.and_then(to_string).apply(21) = {}", composed.apply(21));
29    println!();
30
31    // 2. Chained and_then composition
32    println!("2. Chained and_then composition:");
33    let add_one = |x: i32| x + 1;
34    let double = |x: i32| x * 2;
35    let to_string = |x: i32| x.to_string();
36    let chained = add_one.and_then(double).and_then(to_string);
37    println!(
38        "   add_one.and_then(double).and_then(to_string).apply(5) = {}",
39        chained.apply(5)
40    ); // (5 + 1) * 2 = 12
41    println!();
42
43    // 3. compose reverse composition
44    println!("3. compose reverse composition:");
45    let double = |x: i32| x * 2;
46    let add_one = |x: i32| x + 1;
47    let composed = double.compose(add_one);
48    println!("   double.compose(add_one).apply(5) = {}", composed.apply(5)); // (5 + 1) * 2 = 12
49    println!();
50
51    // 4. Conditional transformation when
52    println!("4. Conditional transformation when:");
53    let double = |x: i32| x * 2;
54    let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
55    println!("   double.when(x > 0).or_else(negate):");
56    println!("     transform(5) = {}", conditional.apply(5)); // 10
57    println!("     transform(-5) = {}", conditional.apply(-5)); // 5
58    println!();
59
60    // 5. Complex composition
61    println!("5. Complex composition:");
62    let add_one = |x: i32| x + 1;
63    let double = |x: i32| x * 2;
64    let triple = |x: i32| x * 3;
65    let to_string = |x: i32| x.to_string();
66
67    let complex = add_one
68        .and_then(double.when(|x: &i32| *x > 5).or_else(triple))
69        .and_then(to_string);
70
71    println!("   add_one.and_then(double.when(x > 5).or_else(triple)).and_then(to_string):");
72    println!("     transform(1) = {}", complex.apply(1)); // (1 + 1) = 2 <= 5, so 2 * 3 = 6
73    println!("     transform(5) = {}", complex.apply(5)); // (5 + 1) = 6 > 5, so 6 * 2 = 12
74    println!("     transform(10) = {}", complex.apply(10)); // (10 + 1) = 11 > 5, so 11 * 2 = 22
75    println!();
76
77    // 6. Type conversion
78    println!("6. Type conversion:");
79    let to_string = |x: i32| x.to_string();
80    let get_length = |s: String| s.len();
81    let length_transformer = to_string.and_then(get_length);
82    println!(
83        "   to_string.and_then(get_length).apply(12345) = {}",
84        length_transformer.apply(12345)
85    ); // 5
86    println!();
87
88    // 7. Closures that capture environment
89    println!("7. Closures that capture environment:");
90    let multiplier = 3;
91    let multiply = move |x: i32| x * multiplier;
92    let add_ten = |x: i32| x + 10;
93    let with_capture = multiply.and_then(add_ten);
94    println!("   multiply(3).and_then(add_ten).apply(5) = {}", with_capture.apply(5)); // 5 * 3 + 10 = 25
95    println!();
96
97    // 8. Function pointers
98    println!("8. Function pointers:");
99    fn double_fn(x: i32) -> i32 {
100        x * 2
101    }
102    fn add_one_fn(x: i32) -> i32 {
103        x + 1
104    }
105    let fn_composed = double_fn.and_then(add_one_fn);
106    println!("   double_fn.and_then(add_one_fn).apply(5) = {}", fn_composed.apply(5)); // 5 * 2 + 1 = 11
107    println!();
108
109    // 9. Multi-conditional transformation
110    println!("9. Multi-conditional transformation:");
111    let abs = |x: i32| x.abs();
112    let double = |x: i32| x * 2;
113    let transformer = abs.when(|x: &i32| *x < 0).or_else(double);
114    println!("   abs.when(x < 0).or_else(double):");
115    println!("     transform(-5) = {}", transformer.apply(-5)); // abs(-5) = 5
116    println!("     transform(5) = {}", transformer.apply(5)); // 5 * 2 = 10
117    println!("     transform(0) = {}", transformer.apply(0)); // 0 * 2 = 0
118    println!();
119
120    println!("=== Example completed ===");
121}

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl<T, R, F> FnTransformerOps<T, R> for F
where F: Fn(T) -> R,

Blanket implementation for all closures

Automatically implements the extension trait for any type that implements the base transformer trait.