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

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, 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.