prism3_function/supplier_once.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025.
4 * 3-Prism Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # SupplierOnce Types
10//!
11//! Provides one-time supplier implementations that generate and
12//! return values without taking any input parameters, consuming
13//! themselves in the process.
14//!
15//! # Overview
16//!
17//! A **SupplierOnce** is a functional abstraction similar to
18//! `Supplier`, but can only be called once. The `get()` method
19//! consumes `self`, ensuring the supplier cannot be reused.
20//!
21//! # Key Characteristics
22//!
23//! - **Single use**: Can only call `get()` once
24//! - **Consumes self**: The method takes ownership of `self`
25//! - **Holds `FnOnce`**: Can capture and move non-cloneable values
26//! - **Type-system guaranteed**: Prevents multiple calls at compile
27//! time
28//!
29//! # Use Cases
30//!
31//! 1. **Lazy initialization**: Delay expensive computation until
32//! needed
33//! 2. **One-time resource consumption**: Generate value by consuming
34//! a resource
35//! 3. **Move-only closures**: Hold closures that capture moved
36//! values
37//!
38//! # Examples
39//!
40//! ## Lazy Initialization
41//!
42//! ```rust
43//! use prism3_function::{BoxSupplierOnce, SupplierOnce};
44//!
45//! let once = BoxSupplierOnce::new(|| {
46//! println!("Expensive initialization");
47//! 42
48//! });
49//!
50//! let value = once.get(); // Only initializes once
51//! assert_eq!(value, 42);
52//! ```
53//!
54//! ## Moving Captured Values
55//!
56//! ```rust
57//! use prism3_function::{BoxSupplierOnce, SupplierOnce};
58//!
59//! let resource = String::from("data");
60//! let once = BoxSupplierOnce::new(move || resource);
61//!
62//! let value = once.get();
63//! assert_eq!(value, "data");
64//! ```
65//!
66//! # Author
67//!
68//! Haixing Hu
69
70// ==========================================================================
71// SupplierOnce Trait
72// ==========================================================================
73
74/// One-time supplier trait: generates a value consuming self.
75///
76/// Similar to `Supplier`, but can only be called once. The `get()`
77/// method consumes `self`, ensuring the supplier cannot be reused.
78///
79/// # Key Characteristics
80///
81/// - **Single use**: Can only call `get()` once
82/// - **Consumes self**: The method takes ownership of `self`
83/// - **Holds `FnOnce`**: Can capture and move non-cloneable values
84/// - **Type-system guaranteed**: Prevents multiple calls at compile
85/// time
86///
87/// # Use Cases
88///
89/// 1. **Lazy initialization**: Delay expensive computation until
90/// needed
91/// 2. **One-time resource consumption**: Generate value by consuming
92/// a resource
93/// 3. **Move-only closures**: Hold closures that capture moved
94/// values
95///
96/// # Examples
97///
98/// ## Lazy Initialization
99///
100/// ```rust
101/// use prism3_function::{BoxSupplierOnce, SupplierOnce};
102///
103/// let once = BoxSupplierOnce::new(|| {
104/// println!("Expensive computation");
105/// 42
106/// });
107///
108/// let value = once.get(); // Prints: Expensive computation
109/// assert_eq!(value, 42);
110/// // once is now consumed and cannot be used again
111/// ```
112///
113/// ## Resource Consumption
114///
115/// ```rust
116/// use prism3_function::{BoxSupplierOnce, SupplierOnce};
117///
118/// let resource = String::from("data");
119/// let once = BoxSupplierOnce::new(move || {
120/// resource // Move the resource
121/// });
122///
123/// let value = once.get();
124/// assert_eq!(value, "data");
125/// ```
126///
127/// # Author
128///
129/// Haixing Hu
130pub trait SupplierOnce<T> {
131 /// Generates and returns the value, consuming self.
132 ///
133 /// This method can only be called once because it consumes
134 /// `self`. This ensures type-system level guarantee that the
135 /// supplier won't be called multiple times.
136 ///
137 /// # Returns
138 ///
139 /// The generated value of type `T`
140 ///
141 /// # Examples
142 ///
143 /// ```rust
144 /// use prism3_function::{BoxSupplierOnce, SupplierOnce};
145 ///
146 /// let once = BoxSupplierOnce::new(|| 42);
147 /// assert_eq!(once.get(), 42);
148 /// // once is consumed here
149 /// ```
150 fn get(self) -> T;
151
152 /// Converts to `BoxSupplierOnce`.
153 ///
154 /// # Returns
155 ///
156 /// A new `BoxSupplierOnce<T>` instance
157 ///
158 /// # Examples
159 ///
160 /// ```rust
161 /// use prism3_function::SupplierOnce;
162 ///
163 /// let closure = || 42;
164 /// let boxed = closure.into_box_once();
165 /// assert_eq!(boxed.get(), 42);
166 /// ```
167 fn into_box(self) -> BoxSupplierOnce<T>
168 where
169 Self: Sized + 'static,
170 T: 'static,
171 {
172 BoxSupplierOnce::new(move || self.get())
173 }
174
175 /// Converts the supplier to a `Box<dyn FnOnce() -> T>`.
176 ///
177 /// This method consumes the current supplier and wraps it in a `Box` as a
178 /// trait object, allowing it to be used where a dynamically dispatched
179 /// `FnOnce` is needed.
180 ///
181 /// # Returns
182 ///
183 /// A `Box<dyn FnOnce() -> T>` that executes the supplier when called.
184 ///
185 /// # Examples
186 ///
187 /// ```rust
188 /// use prism3_function::SupplierOnce;
189 ///
190 /// let closure = || 42;
191 /// let fn_once = closure.into_fn();
192 /// assert_eq!(fn_once(), 42);
193 /// ```
194 fn into_fn(self) -> impl FnOnce() -> T
195 where
196 Self: Sized + 'static,
197 T: 'static,
198 {
199 move || self.get()
200 }
201
202 /// Converts the supplier to a `BoxSupplierOnce`.
203 ///
204 /// This is a convenience method that clones the current supplier and
205 /// wraps it in a `BoxSupplierOnce`. This is useful for type erasure and
206 /// creating homogenous collections of suppliers.
207 ///
208 /// # Returns
209 ///
210 /// A new `BoxSupplierOnce<T>` instance.
211 ///
212 /// # Note
213 ///
214 /// This requires the `SupplierOnce` to be `Clone` because it only
215 /// borrows `&self` but must create a new owned `BoxSupplierOnce`. The
216 /// clone provides the owned value needed for the new instance.
217 fn to_box(&self) -> BoxSupplierOnce<T>
218 where
219 Self: Clone + Sized + 'static,
220 T: 'static,
221 {
222 self.clone().into_box()
223 }
224
225 /// Converts the supplier to a `Box<dyn FnOnce() -> T>`.
226 ///
227 /// This method clones the current supplier and wraps it in a `Box` as a
228 /// trait object, allowing it to be used where a dynamically dispatched
229 /// `FnOnce` is needed.
230 ///
231 /// # Returns
232 ///
233 /// A `Box<dyn FnOnce() -> T>` that executes the supplier when called.
234 ///
235 /// # Note
236 ///
237 /// This requires the `SupplierOnce` to be `Clone` since `to_fn` only
238 /// borrows `&self` but needs to produce a `FnOnce` which will be
239 /// consumed. The underlying supplier is cloned to provide an owned value
240 /// that the returned closure can consume.
241 fn to_fn(&self) -> impl FnOnce() -> T
242 where
243 Self: Clone + Sized + 'static,
244 T: 'static,
245 {
246 self.clone().into_fn()
247 }
248}
249
250// ==========================================================================
251// BoxSupplierOnce - One-time Supplier Implementation
252// ==========================================================================
253
254/// Box-based one-time supplier.
255///
256/// Uses `Box<dyn FnOnce() -> T>` for one-time value generation.
257/// Can only call `get()` once, consuming the supplier.
258///
259/// # Examples
260///
261/// ## Lazy Initialization
262///
263/// ```rust
264/// use prism3_function::{BoxSupplierOnce, SupplierOnce};
265///
266/// let once = BoxSupplierOnce::new(|| {
267/// println!("Expensive initialization");
268/// 42
269/// });
270///
271/// let value = once.get(); // Prints: Expensive initialization
272/// assert_eq!(value, 42);
273/// ```
274///
275/// ## Moving Captured Values
276///
277/// ```rust
278/// use prism3_function::{BoxSupplierOnce, SupplierOnce};
279///
280/// let resource = String::from("data");
281/// let once = BoxSupplierOnce::new(move || resource);
282///
283/// let value = once.get();
284/// assert_eq!(value, "data");
285/// ```
286///
287/// # Author
288///
289/// Haixing Hu
290pub struct BoxSupplierOnce<T> {
291 function: Box<dyn FnOnce() -> T>,
292}
293
294impl<T> BoxSupplierOnce<T> {
295 /// Creates a new `BoxSupplierOnce`.
296 ///
297 /// # Parameters
298 ///
299 /// * `f` - The closure to wrap
300 ///
301 /// # Returns
302 ///
303 /// A new `BoxSupplierOnce<T>` instance
304 ///
305 /// # Examples
306 ///
307 /// ```rust
308 /// use prism3_function::{BoxSupplierOnce, SupplierOnce};
309 ///
310 /// let once = BoxSupplierOnce::new(|| 42);
311 /// assert_eq!(once.get(), 42);
312 /// ```
313 pub fn new<F>(f: F) -> Self
314 where
315 F: FnOnce() -> T + 'static,
316 {
317 BoxSupplierOnce {
318 function: Box::new(f),
319 }
320 }
321}
322
323// ==========================================================================
324// Implementations for BoxSupplierOnce
325// ==========================================================================
326
327impl<T> SupplierOnce<T> for BoxSupplierOnce<T> {
328 fn get(self) -> T {
329 (self.function)()
330 }
331
332 fn into_box(self) -> BoxSupplierOnce<T>
333 where
334 Self: Sized + 'static,
335 T: 'static,
336 {
337 self
338 }
339
340 fn into_fn(self) -> impl FnOnce() -> T
341 where
342 Self: Sized + 'static,
343 T: 'static,
344 {
345 self.function
346 }
347
348 // The `to_box` method cannot be implemented for `BoxSupplierOnce`.
349 // The default implementation of `to_box` requires `Self: Clone`, but
350 // `BoxSupplierOnce` cannot be cloned because it contains a
351 // `Box<dyn FnOnce() -> T>`, which is not cloneable. Calling `to_box()` on a
352 // `BoxSupplierOnce` instance will result in a compile-time error, as it
353 // does not satisfy the `Clone` trait bound.
354
355 // The `to_fn` method cannot be implemented for `BoxSupplierOnce` for the
356 // same reason. It also requires `Self: Clone`, which `BoxSupplierOnce`
357 // does not implement. This limitation is inherent to any `FnOnce`-based
358 // supplier that takes ownership of a non-cloneable resource.
359}
360
361// ==========================================================================
362// Implement SupplierOnce for Closures
363// ==========================================================================
364
365impl<T, F> SupplierOnce<T> for F
366where
367 F: FnOnce() -> T,
368{
369 fn get(self) -> T {
370 self()
371 }
372
373 fn into_box(self) -> BoxSupplierOnce<T>
374 where
375 Self: Sized + 'static,
376 T: 'static,
377 {
378 BoxSupplierOnce::new(self)
379 }
380
381 fn into_fn(self) -> impl FnOnce() -> T
382 where
383 Self: Sized + 'static,
384 T: 'static,
385 {
386 self
387 }
388
389 fn to_box(&self) -> BoxSupplierOnce<T>
390 where
391 Self: Clone + Sized + 'static,
392 T: 'static,
393 {
394 BoxSupplierOnce::new(self.clone())
395 }
396
397 fn to_fn(&self) -> impl FnOnce() -> T
398 where
399 Self: Clone + Sized + 'static,
400 T: 'static,
401 {
402 self.clone()
403 }
404}