qubit_function/suppliers/supplier/rc_supplier.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10// qubit-style: allow explicit-imports
11//! Defines the `RcSupplier` public type.
12
13use super::{
14 ArcSupplier,
15 BoxSupplier,
16 BoxSupplierOnce,
17 Predicate,
18 Rc,
19 Supplier,
20 Transformer,
21 impl_closure_trait,
22 impl_rc_conversions,
23 impl_shared_supplier_methods,
24 impl_supplier_clone,
25 impl_supplier_common_methods,
26 impl_supplier_debug_display,
27};
28
29// ======================================================================
30// RcSupplier - Single-threaded Shared Ownership
31// ======================================================================
32
33/// Single-threaded shared ownership stateless supplier.
34///
35/// Uses `Rc<dyn Fn() -> T>` for single-threaded shared ownership.
36/// Can be cloned but not sent across threads.
37///
38/// # Ownership Model
39///
40/// Like `ArcSupplier`, methods borrow `&self` instead of
41/// consuming `self`:
42///
43/// ```rust
44/// use qubit_function::{RcSupplier, Supplier};
45///
46/// let source = RcSupplier::new(|| 10);
47/// let mapped = source.map(|x| x * 2);
48/// // source is still usable here!
49/// ```
50///
51/// # Examples
52///
53/// ## Shared Factory
54///
55/// ```rust
56/// use qubit_function::{RcSupplier, Supplier};
57///
58/// let factory = RcSupplier::new(|| {
59/// String::from("Hello")
60/// });
61///
62/// let f1 = factory.clone();
63/// let f2 = factory.clone();
64/// assert_eq!(f1.get(), "Hello");
65/// assert_eq!(f2.get(), "Hello");
66/// ```
67///
68/// ## Reusable Transformations
69///
70/// ```rust
71/// use qubit_function::{RcSupplier, Supplier};
72///
73/// let base = RcSupplier::new(|| 10);
74/// let doubled = base.map(|x| x * 2);
75/// let tripled = base.map(|x| x * 3);
76///
77/// assert_eq!(base.get(), 10);
78/// assert_eq!(doubled.get(), 20);
79/// assert_eq!(tripled.get(), 30);
80/// ```
81///
82pub struct RcSupplier<T> {
83 pub(super) function: Rc<dyn Fn() -> T>,
84 pub(super) name: Option<String>,
85}
86
87impl<T> RcSupplier<T> {
88 // Generates: new(), new_with_name(), name(), set_name(), constant()
89 impl_supplier_common_methods!(RcSupplier<T>, (Fn() -> T + 'static), |f| Rc::new(f));
90
91 // Generates: map(), filter(), zip()
92 impl_shared_supplier_methods!(
93 RcSupplier<T>,
94 Supplier,
95 ('static)
96 );
97}
98
99// Generates: Debug and Display implementations for RcSupplier<T>
100impl_supplier_debug_display!(RcSupplier<T>);
101
102// Generates: Clone implementation for RcSupplier<T>
103impl_supplier_clone!(RcSupplier<T>);
104
105impl<T> Supplier<T> for RcSupplier<T> {
106 fn get(&self) -> T {
107 (self.function)()
108 }
109
110 // Generate all conversion methods using the unified macro
111 impl_rc_conversions!(
112 RcSupplier<T>,
113 BoxSupplier,
114 BoxSupplierOnce,
115 Fn() -> T
116 );
117}
118
119// ======================================================================
120// Implement Supplier for Closures
121// ======================================================================
122
123// Implement Supplier<T> for any type that implements Fn() -> T
124impl_closure_trait!(
125 Supplier<T>,
126 get,
127 BoxSupplierOnce,
128 Fn() -> T
129);
130
131// ======================================================================
132// Note on Extension Traits for Closures
133// ======================================================================
134//
135// We don't provide `FnSupplierOps` trait for `Fn() -> T` closures
136// because:
137//
138// 1. All `Fn` closures also implement `FnMut`, so they can use `FnSupplierOps`
139// from the `supplier` module
140// 2. Providing both would cause ambiguity errors due to overlapping trait impls
141// 3. Rust doesn't support negative trait bounds to exclude `FnMut`
142//
143// Users of `Fn` closures should use `FnSupplierOps` from `supplier` module,
144// or explicitly convert to `BoxSupplier` using `.into_box()` first.