prism3_function/mapper_once.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025.
4 * 3-Prism Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # MapperOnce Types
10//!
11//! Provides Rust implementations of consuming mapper traits similar to
12//! Rust's `FnOnce` trait, but with value-oriented semantics for functional
13//! programming patterns with state consumption.
14//!
15//! This module provides the `MapperOnce<T, R>` trait and one-time use
16//! implementation:
17//!
18//! - [`BoxMapperOnce`]: Single ownership, one-time use
19//!
20//! # Author
21//!
22//! 胡海星
23
24use crate::predicate::{BoxPredicate, Predicate};
25
26// ============================================================================
27// Core Trait
28// ============================================================================
29
30/// MapperOnce trait - consuming mapper that takes ownership
31///
32/// Defines the behavior of a consuming mapper: converting a value of
33/// type `T` to a value of type `R` by taking ownership of both self and the
34/// input. This trait is analogous to `FnOnce(T) -> R`.
35///
36/// Unlike `Mapper` (which is like `FnMut`), `MapperOnce` consumes itself on
37/// the first call, making it suitable for one-time transformations that may
38/// own or consume resources.
39///
40/// # Type Parameters
41///
42/// * `T` - The type of the input value (consumed)
43/// * `R` - The type of the output value
44///
45/// # Author
46///
47/// 胡海星
48pub trait MapperOnce<T, R> {
49 /// Applies the mapping to the input value, consuming both self and input
50 ///
51 /// # Parameters
52 ///
53 /// * `input` - The input value (consumed)
54 ///
55 /// # Returns
56 ///
57 /// The mapped output value
58 fn apply_once(self, input: T) -> R;
59
60 /// Converts to BoxMapperOnce
61 ///
62 /// **⚠️ Consumes `self`**: The original mapper becomes unavailable
63 /// after calling this method.
64 ///
65 /// # Returns
66 ///
67 /// Returns `BoxMapperOnce<T, R>`
68 ///
69 /// # Examples
70 ///
71 /// ```rust
72 /// use prism3_function::MapperOnce;
73 ///
74 /// let double = |x: i32| x * 2;
75 /// let boxed = double.into_box_once();
76 /// assert_eq!(boxed.apply_once(21), 42);
77 /// ```
78 fn into_box_once(self) -> BoxMapperOnce<T, R>
79 where
80 Self: Sized + 'static,
81 T: 'static,
82 R: 'static,
83 {
84 BoxMapperOnce::new(move |input: T| self.apply_once(input))
85 }
86
87 /// Converts mapper to a closure
88 ///
89 /// **⚠️ Consumes `self`**: The original mapper becomes unavailable
90 /// after calling this method.
91 ///
92 /// # Returns
93 ///
94 /// Returns a closure that implements `FnOnce(T) -> R`
95 ///
96 /// # Examples
97 ///
98 /// ```rust
99 /// use prism3_function::MapperOnce;
100 ///
101 /// let double = |x: i32| x * 2;
102 /// let func = double.into_fn_once();
103 /// assert_eq!(func(21), 42);
104 /// ```
105 fn into_fn_once(self) -> impl FnOnce(T) -> R
106 where
107 Self: Sized + 'static,
108 T: 'static,
109 R: 'static,
110 {
111 move |input: T| self.apply_once(input)
112 }
113
114 /// Converts to BoxMapperOnce without consuming self
115 ///
116 /// **📌 Borrows `&self`**: The original mapper remains usable
117 /// after calling this method.
118 ///
119 /// # Default Implementation
120 ///
121 /// The default implementation creates a new `BoxMapperOnce` that
122 /// captures a clone. Types implementing `Clone` can override this method
123 /// to provide more efficient conversions.
124 ///
125 /// # Returns
126 ///
127 /// Returns `BoxMapperOnce<T, R>`
128 ///
129 /// # Examples
130 ///
131 /// ```rust
132 /// use prism3_function::MapperOnce;
133 ///
134 /// let double = |x: i32| x * 2;
135 /// let boxed = double.to_box_once();
136 /// assert_eq!(boxed.apply_once(21), 42);
137 /// ```
138 fn to_box_once(&self) -> BoxMapperOnce<T, R>
139 where
140 Self: Clone + 'static,
141 T: 'static,
142 R: 'static,
143 {
144 self.clone().into_box_once()
145 }
146
147 /// Converts mapper to a closure without consuming self
148 ///
149 /// **📌 Borrows `&self`**: The original mapper remains usable
150 /// after calling this method.
151 ///
152 /// # Default Implementation
153 ///
154 /// The default implementation creates a closure that captures a
155 /// clone of `self` and calls its `apply` method. Types can
156 /// override this method to provide more efficient conversions.
157 ///
158 /// # Returns
159 ///
160 /// Returns a closure that implements `FnOnce(T) -> R`
161 ///
162 /// # Examples
163 ///
164 /// ```rust
165 /// use prism3_function::MapperOnce;
166 ///
167 /// let double = |x: i32| x * 2;
168 /// let func = double.to_fn_once();
169 /// assert_eq!(func(21), 42);
170 /// ```
171 fn to_fn_once(&self) -> impl FnOnce(T) -> R
172 where
173 Self: Clone + 'static,
174 T: 'static,
175 R: 'static,
176 {
177 self.clone().into_fn_once()
178 }
179}
180
181// ============================================================================
182// BoxMapperOnce - Box<dyn FnOnce(T) -> R>
183// ============================================================================
184
185/// BoxMapperOnce - consuming mapper wrapper based on `Box<dyn FnOnce>`
186///
187/// A mapper wrapper that provides single ownership with one-time use
188/// semantics. Consumes both self and the input value.
189///
190/// # Features
191///
192/// - **Based on**: `Box<dyn FnOnce(T) -> R>`
193/// - **Ownership**: Single ownership, cannot be cloned
194/// - **Reusability**: Can only be called once (consumes self and input)
195/// - **Thread Safety**: Not thread-safe (no `Send + Sync` requirement)
196///
197/// # Author
198///
199/// 胡海星
200pub struct BoxMapperOnce<T, R> {
201 function: Box<dyn FnOnce(T) -> R>,
202}
203
204impl<T, R> BoxMapperOnce<T, R>
205where
206 T: 'static,
207 R: 'static,
208{
209 /// Creates a new BoxMapperOnce
210 ///
211 /// # Parameters
212 ///
213 /// * `f` - The closure or function to wrap
214 ///
215 /// # Examples
216 ///
217 /// ```rust
218 /// use prism3_function::{BoxMapperOnce, MapperOnce};
219 ///
220 /// let parse = BoxMapperOnce::new(|s: String| {
221 /// s.parse::<i32>().unwrap_or(0)
222 /// });
223 ///
224 /// assert_eq!(parse.apply_once("42".to_string()), 42);
225 /// ```
226 pub fn new<F>(f: F) -> Self
227 where
228 F: FnOnce(T) -> R + 'static,
229 {
230 BoxMapperOnce {
231 function: Box::new(f),
232 }
233 }
234
235 /// Creates an identity mapper
236 ///
237 /// # Examples
238 ///
239 /// ```rust
240 /// use prism3_function::{BoxMapperOnce, MapperOnce};
241 ///
242 /// let identity = BoxMapperOnce::<i32, i32>::identity();
243 /// assert_eq!(identity.apply_once(42), 42);
244 /// ```
245 pub fn identity() -> BoxMapperOnce<T, T> {
246 BoxMapperOnce::new(|x| x)
247 }
248
249 /// Chain composition - applies self first, then after
250 ///
251 /// # Type Parameters
252 ///
253 /// * `S` - The output type of the after mapper
254 /// * `G` - The type of the after mapper (must implement MapperOnce<R, S>)
255 ///
256 /// # Parameters
257 ///
258 /// * `after` - The mapper to apply after self. **Note: This parameter
259 /// is passed by value and will transfer ownership.** Since
260 /// `BoxMapperOnce` cannot be cloned, the parameter will be consumed.
261 /// Can be:
262 /// - A closure: `|x: R| -> S`
263 /// - A function pointer: `fn(R) -> S`
264 /// - A `BoxMapperOnce<R, S>`
265 /// - Any type implementing `MapperOnce<R, S>`
266 ///
267 /// # Returns
268 ///
269 /// A new BoxMapperOnce representing the composition
270 ///
271 /// # Examples
272 ///
273 /// ```rust
274 /// use prism3_function::{BoxMapperOnce, MapperOnce};
275 ///
276 /// let add_one = BoxMapperOnce::new(|x: i32| x + 1);
277 /// let double = BoxMapperOnce::new(|x: i32| x * 2);
278 ///
279 /// // Both add_one and double are moved and consumed
280 /// let composed = add_one.and_then(double);
281 /// assert_eq!(composed.apply_once(5), 12); // (5 + 1) * 2
282 /// // add_one.apply_once(3); // Would not compile - moved
283 /// // double.apply_once(4); // Would not compile - moved
284 /// ```
285 pub fn and_then<S, G>(self, after: G) -> BoxMapperOnce<T, S>
286 where
287 S: 'static,
288 G: MapperOnce<R, S> + 'static,
289 {
290 BoxMapperOnce::new(move |x| {
291 let intermediate = (self.function)(x);
292 after.apply_once(intermediate)
293 })
294 }
295
296 /// Reverse composition - applies before first, then self
297 ///
298 /// # Type Parameters
299 ///
300 /// * `S` - The input type of the before mapper
301 /// * `G` - The type of the before mapper (must implement MapperOnce<S, T>)
302 ///
303 /// # Parameters
304 ///
305 /// * `before` - The mapper to apply before self. **Note: This parameter
306 /// is passed by value and will transfer ownership.** Since
307 /// `BoxMapperOnce` cannot be cloned, the parameter will be consumed.
308 /// Can be:
309 /// - A closure: `|x: S| -> T`
310 /// - A function pointer: `fn(S) -> T`
311 /// - A `BoxMapperOnce<S, T>`
312 /// - Any type implementing `MapperOnce<S, T>`
313 ///
314 /// # Returns
315 ///
316 /// A new BoxMapperOnce representing the composition
317 ///
318 /// # Examples
319 ///
320 /// ```rust
321 /// use prism3_function::{BoxMapperOnce, MapperOnce};
322 ///
323 /// let double = BoxMapperOnce::new(|x: i32| x * 2);
324 /// let add_one = BoxMapperOnce::new(|x: i32| x + 1);
325 ///
326 /// // Both double and add_one are moved and consumed
327 /// let composed = double.compose(add_one);
328 /// assert_eq!(composed.apply_once(5), 12); // (5 + 1) * 2
329 /// // double.apply_once(3); // Would not compile - moved
330 /// // add_one.apply_once(4); // Would not compile - moved
331 /// ```
332 pub fn compose<S, G>(self, before: G) -> BoxMapperOnce<S, R>
333 where
334 S: 'static,
335 G: MapperOnce<S, T> + 'static,
336 {
337 BoxMapperOnce::new(move |x| {
338 let intermediate = before.apply_once(x);
339 (self.function)(intermediate)
340 })
341 }
342
343 /// Creates a conditional mapper
344 ///
345 /// Returns a mapper that only executes when a predicate is satisfied.
346 /// You must call `or_else()` to provide an alternative mapper.
347 ///
348 /// # Parameters
349 ///
350 /// * `predicate` - The condition to check. **Note: This parameter is passed
351 /// by value and will transfer ownership.** If you need to preserve the
352 /// original predicate, clone it first (if it implements `Clone`). Can be:
353 /// - A closure: `|x: &T| -> bool`
354 /// - A function pointer: `fn(&T) -> bool`
355 /// - A `BoxPredicate<T>`
356 /// - An `RcPredicate<T>`
357 /// - An `ArcPredicate<T>`
358 /// - Any type implementing `Predicate<T>`
359 ///
360 /// # Returns
361 ///
362 /// Returns `BoxConditionalMapperOnce<T, R>`
363 ///
364 /// # Examples
365 ///
366 /// ## Basic usage with or_else
367 ///
368 /// ```rust
369 /// use prism3_function::{MapperOnce, BoxMapperOnce};
370 ///
371 /// let double = BoxMapperOnce::new(|x: i32| x * 2);
372 /// let identity = BoxMapperOnce::<i32, i32>::identity();
373 /// let conditional = double.when(|x: &i32| *x > 0).or_else(identity);
374 /// assert_eq!(conditional.apply_once(5), 10);
375 ///
376 /// let double2 = BoxMapperOnce::new(|x: i32| x * 2);
377 /// let identity2 = BoxMapperOnce::<i32, i32>::identity();
378 /// let conditional2 = double2.when(|x: &i32| *x > 0).or_else(identity2);
379 /// assert_eq!(conditional2.apply_once(-5), -5);
380 /// ```
381 ///
382 /// ## Preserving predicate with clone
383 ///
384 /// ```rust
385 /// use prism3_function::{MapperOnce, BoxMapperOnce, RcPredicate, Predicate};
386 ///
387 /// let double = BoxMapperOnce::new(|x: i32| x * 2);
388 /// let is_positive = RcPredicate::new(|x: &i32| *x > 0);
389 ///
390 /// // Clone to preserve original predicate
391 /// let conditional = double.when(is_positive.clone())
392 /// .or_else(BoxMapperOnce::<i32, i32>::identity());
393 ///
394 /// assert_eq!(conditional.apply_once(5), 10);
395 ///
396 /// // Original predicate still usable
397 /// assert!(is_positive.test(&3));
398 /// ```
399 pub fn when<P>(self, predicate: P) -> BoxConditionalMapperOnce<T, R>
400 where
401 P: Predicate<T> + 'static,
402 {
403 BoxConditionalMapperOnce {
404 mapper: self,
405 predicate: predicate.into_box(),
406 }
407 }
408}
409
410impl<T, R> BoxMapperOnce<T, R>
411where
412 T: 'static,
413 R: Clone + 'static,
414{
415 /// Creates a constant mapper
416 ///
417 /// # Examples
418 ///
419 /// ```rust
420 /// use prism3_function::{BoxMapperOnce, MapperOnce};
421 ///
422 /// let constant = BoxMapperOnce::constant("hello");
423 /// assert_eq!(constant.apply_once(123), "hello");
424 /// ```
425 pub fn constant(value: R) -> BoxMapperOnce<T, R> {
426 BoxMapperOnce::new(move |_| value.clone())
427 }
428}
429
430impl<T, R> MapperOnce<T, R> for BoxMapperOnce<T, R> {
431 fn apply_once(self, input: T) -> R {
432 (self.function)(input)
433 }
434
435 fn into_box_once(self) -> BoxMapperOnce<T, R>
436 where
437 T: 'static,
438 R: 'static,
439 {
440 // Zero-cost: directly return itself
441 self
442 }
443
444 fn into_fn_once(self) -> impl FnOnce(T) -> R
445 where
446 T: 'static,
447 R: 'static,
448 {
449 // Zero-cost: directly return the inner function
450 self.function
451 }
452
453 // do NOT override BoxMapperOnce::to_box_once() and BoxMapperOnce::to_fn_once()
454 // because BoxMapperOnce is not Clone and calling BoxMapperOnce::to_box_once()
455 // or BoxMapperOnce::to_fn_once() will cause a compile error
456}
457
458// ============================================================================
459// BoxConditionalMapperOnce - Box-based Conditional Mapper
460// ============================================================================
461
462/// BoxConditionalMapperOnce struct
463///
464/// A conditional consuming mapper that only executes when a predicate is
465/// satisfied. Uses `BoxMapperOnce` and `BoxPredicate` for single
466/// ownership semantics.
467///
468/// This type is typically created by calling `BoxMapperOnce::when()` and
469/// is designed to work with the `or_else()` method to create if-then-else
470/// logic.
471///
472/// # Features
473///
474/// - **Single Ownership**: Not cloneable, consumes `self` on use
475/// - **One-time Use**: Can only be called once
476/// - **Conditional Execution**: Only maps when predicate returns `true`
477/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
478///
479/// # Examples
480///
481/// ## With or_else Branch
482///
483/// ```rust
484/// use prism3_function::{MapperOnce, BoxMapperOnce};
485///
486/// let double = BoxMapperOnce::new(|x: i32| x * 2);
487/// let negate = BoxMapperOnce::new(|x: i32| -x);
488/// let conditional = double.when(|x: &i32| *x > 0).or_else(negate);
489/// assert_eq!(conditional.apply_once(5), 10); // when branch executed
490///
491/// let double2 = BoxMapperOnce::new(|x: i32| x * 2);
492/// let negate2 = BoxMapperOnce::new(|x: i32| -x);
493/// let conditional2 = double2.when(|x: &i32| *x > 0).or_else(negate2);
494/// assert_eq!(conditional2.apply_once(-5), 5); // or_else branch executed
495/// ```
496///
497/// # Author
498///
499/// 胡海星
500pub struct BoxConditionalMapperOnce<T, R> {
501 mapper: BoxMapperOnce<T, R>,
502 predicate: BoxPredicate<T>,
503}
504
505impl<T, R> BoxConditionalMapperOnce<T, R>
506where
507 T: 'static,
508 R: 'static,
509{
510 /// Adds an else branch
511 ///
512 /// Executes the original mapper when the condition is satisfied,
513 /// otherwise executes else_mapper.
514 ///
515 /// # Parameters
516 ///
517 /// * `else_mapper` - The mapper for the else branch, can be:
518 /// - Closure: `|x: T| -> R`
519 /// - `BoxMapperOnce<T, R>`
520 /// - Any type implementing `MapperOnce<T, R>`
521 ///
522 /// # Returns
523 ///
524 /// Returns the composed `BoxMapperOnce<T, R>`
525 ///
526 /// # Examples
527 ///
528 /// ## Using a closure (recommended)
529 ///
530 /// ```rust
531 /// use prism3_function::{MapperOnce, BoxMapperOnce};
532 ///
533 /// let double = BoxMapperOnce::new(|x: i32| x * 2);
534 /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
535 /// assert_eq!(conditional.apply_once(5), 10); // Condition satisfied, execute double
536 ///
537 /// let double2 = BoxMapperOnce::new(|x: i32| x * 2);
538 /// let conditional2 = double2.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
539 /// assert_eq!(conditional2.apply_once(-5), 5); // Condition not satisfied, execute negate
540 /// ```
541 pub fn or_else<F>(self, else_mapper: F) -> BoxMapperOnce<T, R>
542 where
543 F: MapperOnce<T, R> + 'static,
544 {
545 let pred = self.predicate;
546 let then_mapper = self.mapper;
547 BoxMapperOnce::new(move |t| {
548 if pred.test(&t) {
549 then_mapper.apply_once(t)
550 } else {
551 else_mapper.apply_once(t)
552 }
553 })
554 }
555}
556
557// ============================================================================
558// Blanket implementation for standard FnOnce trait
559// ============================================================================
560
561/// Implement MapperOnce<T, R> for any type that implements FnOnce(T) -> R
562///
563/// This allows once-callable closures and function pointers to be used
564/// directly with our MapperOnce trait without wrapping.
565///
566/// # Examples
567///
568/// ```rust
569/// use prism3_function::MapperOnce;
570///
571/// fn parse(s: String) -> i32 {
572/// s.parse().unwrap_or(0)
573/// }
574///
575/// assert_eq!(parse.apply_once("42".to_string()), 42);
576///
577/// let owned_value = String::from("hello");
578/// let consume = |s: String| {
579/// format!("{} world", s)
580/// };
581/// assert_eq!(consume.apply_once(owned_value), "hello world");
582/// ```
583///
584/// # Author
585///
586/// 胡海星
587impl<F, T, R> MapperOnce<T, R> for F
588where
589 F: FnOnce(T) -> R,
590 T: 'static,
591 R: 'static,
592{
593 fn apply_once(self, input: T) -> R {
594 self(input)
595 }
596
597 fn into_box_once(self) -> BoxMapperOnce<T, R>
598 where
599 Self: Sized + 'static,
600 {
601 BoxMapperOnce::new(self)
602 }
603
604 fn into_fn_once(self) -> impl FnOnce(T) -> R
605 where
606 Self: Sized + 'static,
607 {
608 // Zero-cost: directly return self since F is already FnOnce(T) -> R
609 self
610 }
611
612 fn to_box_once(&self) -> BoxMapperOnce<T, R>
613 where
614 Self: Clone + Sized + 'static,
615 {
616 self.clone().into_box_once()
617 }
618
619 fn to_fn_once(&self) -> impl FnOnce(T) -> R
620 where
621 Self: Clone + Sized + 'static,
622 {
623 self.clone()
624 }
625}
626
627// ============================================================================
628// FnMapperOnceOps - Extension trait for FnOnce mappers
629// ============================================================================
630
631/// Extension trait for closures implementing `FnOnce(T) -> R`
632///
633/// Provides composition methods (`and_then`, `compose`, `when`) for one-time
634/// use closures and function pointers without requiring explicit wrapping in
635/// `BoxMapperOnce`.
636///
637/// This trait is automatically implemented for all closures and function
638/// pointers that implement `FnOnce(T) -> R`.
639///
640/// # Design Rationale
641///
642/// While closures automatically implement `MapperOnce<T, R>` through
643/// blanket implementation, they don't have access to instance methods like
644/// `and_then`, `compose`, and `when`. This extension trait provides those
645/// methods, returning `BoxMapperOnce` for maximum flexibility.
646///
647/// # Examples
648///
649/// ## Chain composition with and_then
650///
651/// ```rust
652/// use prism3_function::{MapperOnce, FnMapperOnceOps};
653///
654/// let parse = |s: String| s.parse::<i32>().unwrap_or(0);
655/// let double = |x: i32| x * 2;
656///
657/// let composed = parse.and_then(double);
658/// assert_eq!(composed.apply_once("21".to_string()), 42);
659/// ```
660///
661/// ## Reverse composition with compose
662///
663/// ```rust
664/// use prism3_function::{MapperOnce, FnMapperOnceOps};
665///
666/// let double = |x: i32| x * 2;
667/// let to_string = |x: i32| x.to_string();
668///
669/// let composed = to_string.compose(double);
670/// assert_eq!(composed.apply_once(21), "42");
671/// ```
672///
673/// ## Conditional mapping with when
674///
675/// ```rust
676/// use prism3_function::{MapperOnce, FnMapperOnceOps};
677///
678/// let double = |x: i32| x * 2;
679/// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
680///
681/// assert_eq!(conditional.apply_once(5), 10);
682/// ```
683///
684/// # Author
685///
686/// 胡海星
687pub trait FnMapperOnceOps<T, R>: FnOnce(T) -> R + Sized + 'static {
688 /// Chain composition - applies self first, then after
689 ///
690 /// Creates a new mapper that applies this mapper first, then
691 /// applies the after mapper to the result. Consumes self and returns
692 /// a `BoxMapperOnce`.
693 ///
694 /// # Type Parameters
695 ///
696 /// * `S` - The output type of the after mapper
697 /// * `G` - The type of the after mapper (must implement MapperOnce<R, S>)
698 ///
699 /// # Parameters
700 ///
701 /// * `after` - The mapper to apply after self. **Note: This parameter
702 /// is passed by value and will transfer ownership.** Since this is a
703 /// `FnOnce` mapper, the parameter will be consumed. Can be:
704 /// - A closure: `|x: R| -> S`
705 /// - A function pointer: `fn(R) -> S`
706 /// - A `BoxMapperOnce<R, S>`
707 /// - Any type implementing `MapperOnce<R, S>`
708 ///
709 /// # Returns
710 ///
711 /// A new `BoxMapperOnce<T, S>` representing the composition
712 ///
713 /// # Examples
714 ///
715 /// ```rust
716 /// use prism3_function::{MapperOnce, FnMapperOnceOps, BoxMapperOnce};
717 ///
718 /// let parse = |s: String| s.parse::<i32>().unwrap_or(0);
719 /// let double = BoxMapperOnce::new(|x: i32| x * 2);
720 ///
721 /// // double is moved and consumed
722 /// let composed = parse.and_then(double);
723 /// assert_eq!(composed.apply_once("21".to_string()), 42);
724 /// // double.apply_once(5); // Would not compile - moved
725 /// ```
726 fn and_then<S, G>(self, after: G) -> BoxMapperOnce<T, S>
727 where
728 S: 'static,
729 G: MapperOnce<R, S> + 'static,
730 T: 'static,
731 R: 'static,
732 {
733 BoxMapperOnce::new(move |x: T| {
734 let intermediate = self(x);
735 after.apply_once(intermediate)
736 })
737 }
738
739 /// Reverse composition - applies before first, then self
740 ///
741 /// Creates a new mapper that applies the before mapper first,
742 /// then applies this mapper to the result. Consumes self and returns
743 /// a `BoxMapperOnce`.
744 ///
745 /// # Type Parameters
746 ///
747 /// * `S` - The input type of the before mapper
748 /// * `G` - The type of the before mapper (must implement MapperOnce<S, T>)
749 ///
750 /// # Parameters
751 ///
752 /// * `before` - The mapper to apply before self. **Note: This parameter
753 /// is passed by value and will transfer ownership.** Since this is a
754 /// `FnOnce` mapper, the parameter will be consumed. Can be:
755 /// - A closure: `|x: S| -> T`
756 /// - A function pointer: `fn(S) -> T`
757 /// - A `BoxMapperOnce<S, T>`
758 /// - Any type implementing `MapperOnce<S, T>`
759 ///
760 /// # Returns
761 ///
762 /// A new `BoxMapperOnce<S, R>` representing the composition
763 ///
764 /// # Examples
765 ///
766 /// ```rust
767 /// use prism3_function::{MapperOnce, FnMapperOnceOps, BoxMapperOnce};
768 ///
769 /// let double = BoxMapperOnce::new(|x: i32| x * 2);
770 /// let to_string = |x: i32| x.to_string();
771 ///
772 /// // double is moved and consumed
773 /// let composed = to_string.compose(double);
774 /// assert_eq!(composed.apply_once(21), "42");
775 /// // double.apply_once(5); // Would not compile - moved
776 /// ```
777 fn compose<S, G>(self, before: G) -> BoxMapperOnce<S, R>
778 where
779 S: 'static,
780 G: MapperOnce<S, T> + 'static,
781 T: 'static,
782 R: 'static,
783 {
784 BoxMapperOnce::new(move |x: S| {
785 let intermediate = before.apply_once(x);
786 self(intermediate)
787 })
788 }
789
790 /// Creates a conditional mapper
791 ///
792 /// Returns a mapper that only executes when a predicate is satisfied.
793 /// You must call `or_else()` to provide an alternative mapper for when
794 /// the condition is not satisfied.
795 ///
796 /// # Parameters
797 ///
798 /// * `predicate` - The condition to check. **Note: This parameter is passed
799 /// by value and will transfer ownership.** If you need to preserve the
800 /// original predicate, clone it first (if it implements `Clone`). Can be:
801 /// - A closure: `|x: &T| -> bool`
802 /// - A function pointer: `fn(&T) -> bool`
803 /// - A `BoxPredicate<T>`
804 /// - An `RcPredicate<T>`
805 /// - An `ArcPredicate<T>`
806 /// - Any type implementing `Predicate<T>`
807 ///
808 /// # Returns
809 ///
810 /// Returns `BoxConditionalMapperOnce<T, R>`
811 ///
812 /// # Examples
813 ///
814 /// ## Basic usage with or_else
815 ///
816 /// ```rust
817 /// use prism3_function::{MapperOnce, FnMapperOnceOps};
818 ///
819 /// let double = |x: i32| x * 2;
820 /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
821 ///
822 /// assert_eq!(conditional.apply_once(5), 10);
823 /// ```
824 ///
825 /// ## Preserving predicate with clone
826 ///
827 /// ```rust
828 /// use prism3_function::{MapperOnce, FnMapperOnceOps, RcPredicate, Predicate};
829 ///
830 /// let double = |x: i32| x * 2;
831 /// let is_positive = RcPredicate::new(|x: &i32| *x > 0);
832 ///
833 /// // Clone to preserve original predicate
834 /// let conditional = double.when(is_positive.clone())
835 /// .or_else(|x: i32| -x);
836 ///
837 /// assert_eq!(conditional.apply_once(5), 10);
838 ///
839 /// // Original predicate still usable
840 /// assert!(is_positive.test(&3));
841 /// ```
842 fn when<P>(self, predicate: P) -> BoxConditionalMapperOnce<T, R>
843 where
844 P: Predicate<T> + 'static,
845 T: 'static,
846 R: 'static,
847 {
848 BoxMapperOnce::new(self).when(predicate)
849 }
850}
851
852/// Blanket implementation of FnMapperOnceOps for all FnOnce closures
853///
854/// Automatically implements `FnMapperOnceOps<T, R>` for any type that
855/// implements `FnOnce(T) -> R`.
856///
857/// # Author
858///
859/// 胡海星
860impl<T, R, F> FnMapperOnceOps<T, R> for F where F: FnOnce(T) -> R + 'static {}