qubit_function/consumers/stateful_bi_consumer.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//! # BiConsumer Types
11//!
12//! Provides bi-consumer interface implementations for operations accepting
13//! two input parameters without returning a result.
14//!
15//! It is similar to the `FnMut(&T, &U)` trait in the standard library.
16//!
17//! This module provides a unified `BiConsumer` trait and three concrete
18//! implementations based on different ownership models:
19//!
20//! - **`BoxStatefulBiConsumer<T, U>`**: Box-based single ownership for one-time use
21//! - **`ArcStatefulBiConsumer<T, U>`**: Arc<Mutex<>>-based thread-safe shared
22//! ownership
23//! - **`RcStatefulBiConsumer<T, U>`**: Rc<RefCell<>>-based single-threaded shared
24//! ownership
25//!
26//! # Design Philosophy
27//!
28//! BiConsumer uses `FnMut(&T, &U)` semantics: can modify its own state but
29//! does NOT modify input values.
30//!
31//! Suitable for statistics, accumulation, and event processing scenarios
32//! involving two parameters.
33//!
34use std::cell::RefCell;
35use std::rc::Rc;
36use std::sync::Arc;
37
38use parking_lot::Mutex;
39
40use crate::consumers::{
41 bi_consumer_once::BoxBiConsumerOnce,
42 macros::{
43 impl_box_conditional_consumer,
44 impl_box_consumer_methods,
45 impl_conditional_consumer_clone,
46 impl_conditional_consumer_conversions,
47 impl_conditional_consumer_debug_display,
48 impl_consumer_clone,
49 impl_consumer_common_methods,
50 impl_consumer_debug_display,
51 impl_shared_conditional_consumer,
52 impl_shared_consumer_methods,
53 },
54};
55use crate::macros::{
56 impl_arc_conversions,
57 impl_box_conversions,
58 impl_closure_trait,
59 impl_rc_conversions,
60};
61use crate::predicates::bi_predicate::{
62 ArcBiPredicate,
63 BiPredicate,
64 BoxBiPredicate,
65 RcBiPredicate,
66};
67
68mod box_stateful_bi_consumer;
69pub use box_stateful_bi_consumer::BoxStatefulBiConsumer;
70mod rc_stateful_bi_consumer;
71pub use rc_stateful_bi_consumer::RcStatefulBiConsumer;
72mod arc_stateful_bi_consumer;
73pub use arc_stateful_bi_consumer::ArcStatefulBiConsumer;
74mod fn_stateful_bi_consumer_ops;
75pub use fn_stateful_bi_consumer_ops::FnStatefulBiConsumerOps;
76mod box_conditional_stateful_bi_consumer;
77pub use box_conditional_stateful_bi_consumer::BoxConditionalStatefulBiConsumer;
78mod arc_conditional_stateful_bi_consumer;
79pub use arc_conditional_stateful_bi_consumer::ArcConditionalStatefulBiConsumer;
80mod rc_conditional_stateful_bi_consumer;
81pub use rc_conditional_stateful_bi_consumer::RcConditionalStatefulBiConsumer;
82
83// =======================================================================
84// 1. BiConsumer Trait - Unified BiConsumer Interface
85// =======================================================================
86
87/// BiConsumer trait - Unified bi-consumer interface
88///
89/// Defines core behavior for all bi-consumer types. Similar to Java's
90/// `BiConsumer<T, U>` interface, performs operations accepting two values
91/// but returning no result (side effects only).
92///
93/// It is similar to the `FnMut(&T, &U)` trait in the standard library.
94///
95/// BiConsumer can modify its own state (e.g., accumulate, count) but
96/// should NOT modify the consumed values themselves.
97///
98/// # Automatic Implementations
99///
100/// - All closures implementing `FnMut(&T, &U)`
101/// - `BoxStatefulBiConsumer<T, U>`, `ArcStatefulBiConsumer<T, U>`, `RcStatefulBiConsumer<T, U>`
102///
103/// # Features
104///
105/// - **Unified Interface**: All bi-consumer types share the same `accept`
106/// method signature
107/// - **Automatic Implementation**: Closures automatically implement this
108/// trait with zero overhead
109/// - **Type Conversions**: Easy conversion between ownership models
110/// - **Generic Programming**: Write functions accepting any bi-consumer
111/// type
112///
113/// # Examples
114///
115/// ```rust
116/// use qubit_function::{BiConsumer, BoxStatefulBiConsumer, StatefulBiConsumer};
117/// use std::cell::RefCell;
118/// use std::rc::Rc;
119///
120/// fn apply_bi_consumer<C: StatefulBiConsumer<i32, i32>>(
121/// consumer: &mut C,
122/// a: &i32,
123/// b: &i32
124/// ) {
125/// consumer.accept(a, b);
126/// }
127///
128/// // Works with any bi-consumer type
129/// let log = Rc::new(RefCell::new(Vec::new()));
130/// let l = log.clone();
131/// let mut box_con = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
132/// l.borrow_mut().push(*x + *y);
133/// });
134/// apply_bi_consumer(&mut box_con, &5, &3);
135/// assert_eq!(*log.borrow(), vec![8]);
136/// ```
137///
138pub trait StatefulBiConsumer<T, U> {
139 /// Performs the consumption operation
140 ///
141 /// Executes an operation on the given two references. The operation
142 /// typically reads input values or produces side effects, but does not
143 /// modify the input values themselves. Can modify the consumer's own
144 /// state.
145 ///
146 /// # Parameters
147 ///
148 /// * `first` - Reference to the first value to consume
149 /// * `second` - Reference to the second value to consume
150 ///
151 /// # Examples
152 ///
153 /// ```rust
154 /// use qubit_function::{BiConsumer, BoxStatefulBiConsumer, StatefulBiConsumer};
155 /// use std::sync::{Arc, Mutex};
156 ///
157 /// let log = Arc::new(Mutex::new(Vec::new()));
158 /// let l = log.clone();
159 /// let mut consumer = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
160 /// l.lock().unwrap().push(*x + *y);
161 /// });
162 /// consumer.accept(&5, &3);
163 /// assert_eq!(*log.lock().unwrap(), vec![8]);
164 /// ```
165 fn accept(&mut self, first: &T, second: &U);
166
167 /// Converts to BoxStatefulBiConsumer
168 ///
169 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
170 /// calling this method.
171 ///
172 /// Converts the current bi-consumer to `BoxStatefulBiConsumer<T, U>`.
173 ///
174 /// # Ownership
175 ///
176 /// This method **consumes** the consumer (takes ownership of `self`).
177 /// After calling, the original consumer is no longer available.
178 ///
179 /// **Tip**: For cloneable consumers ([`ArcStatefulBiConsumer`],
180 /// [`RcStatefulBiConsumer`]), call `.clone()` first if you need to keep the
181 /// original.
182 ///
183 /// # Returns
184 ///
185 /// Returns the wrapped `BoxStatefulBiConsumer<T, U>`
186 ///
187 /// # Examples
188 ///
189 /// ```rust
190 /// use qubit_function::{BiConsumer, StatefulBiConsumer};
191 /// use std::sync::{Arc, Mutex};
192 ///
193 /// let log = Arc::new(Mutex::new(Vec::new()));
194 /// let l = log.clone();
195 /// let closure = move |x: &i32, y: &i32| {
196 /// l.lock().unwrap().push(*x + *y);
197 /// };
198 /// let mut box_consumer = StatefulBiConsumer::into_box(closure);
199 /// box_consumer.accept(&5, &3);
200 /// assert_eq!(*log.lock().unwrap(), vec![8]);
201 /// ```
202 fn into_box(self) -> BoxStatefulBiConsumer<T, U>
203 where
204 Self: Sized + 'static,
205 {
206 let mut consumer = self;
207 BoxStatefulBiConsumer::new(move |t, u| consumer.accept(t, u))
208 }
209
210 /// Converts to RcStatefulBiConsumer
211 ///
212 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
213 /// calling this method.
214 ///
215 /// # Returns
216 ///
217 /// Returns the wrapped `RcStatefulBiConsumer<T, U>`
218 fn into_rc(self) -> RcStatefulBiConsumer<T, U>
219 where
220 Self: Sized + 'static,
221 {
222 let mut consumer = self;
223 RcStatefulBiConsumer::new(move |t, u| consumer.accept(t, u))
224 }
225
226 /// Converts to ArcStatefulBiConsumer
227 ///
228 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
229 /// calling this method.
230 ///
231 /// # Returns
232 ///
233 /// Returns the wrapped `ArcStatefulBiConsumer<T, U>`
234 fn into_arc(self) -> ArcStatefulBiConsumer<T, U>
235 where
236 Self: Sized + Send + 'static,
237 {
238 let mut consumer = self;
239 ArcStatefulBiConsumer::new(move |t, u| consumer.accept(t, u))
240 }
241
242 /// Converts bi-consumer to a closure
243 ///
244 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
245 /// calling this method.
246 ///
247 /// Converts the bi-consumer to a closure usable with standard library
248 /// methods requiring `FnMut`.
249 ///
250 /// # Returns
251 ///
252 /// Returns a closure implementing `FnMut(&T, &U)`
253 ///
254 /// # Examples
255 ///
256 /// ```rust
257 /// use qubit_function::{BiConsumer, ArcStatefulBiConsumer, StatefulBiConsumer};
258 /// use std::sync::{Arc, Mutex};
259 ///
260 /// let log = Arc::new(Mutex::new(Vec::new()));
261 /// let l = log.clone();
262 /// let mut consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
263 /// l.lock().unwrap().push(*x + *y);
264 /// });
265 /// let mut func = consumer.into_fn();
266 /// func(&5, &3);
267 /// assert_eq!(*log.lock().unwrap(), vec![8]);
268 /// ```
269 fn into_fn(self) -> impl FnMut(&T, &U)
270 where
271 Self: Sized + 'static,
272 {
273 let mut consumer = self;
274 move |t, u| consumer.accept(t, u)
275 }
276
277 /// Convert to BiConsumerOnce
278 ///
279 /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
280 ///
281 /// Converts a reusable stateful bi-consumer to a one-time consumer that consumes itself on use.
282 /// This enables passing `StatefulBiConsumer` to functions that require `BiConsumerOnce`.
283 ///
284 /// # Returns
285 ///
286 /// Returns a `BoxBiConsumerOnce<T, U>`
287 fn into_once(self) -> BoxBiConsumerOnce<T, U>
288 where
289 Self: Sized + 'static,
290 {
291 BoxBiConsumerOnce::new(move |t, u| {
292 let mut consumer = self;
293 consumer.accept(t, u);
294 })
295 }
296
297 /// Converts to BoxStatefulBiConsumer (non-consuming)
298 ///
299 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
300 ///
301 /// Converts the current bi-consumer to `BoxStatefulBiConsumer<T, U>` by cloning
302 /// it first.
303 ///
304 /// # Ownership
305 ///
306 /// This method does **not consume** the consumer. It clones the consumer
307 /// and then converts the clone to `BoxStatefulBiConsumer<T, U>`. The original
308 /// consumer remains available after calling this method.
309 ///
310 /// # Returns
311 ///
312 /// Returns the wrapped `BoxStatefulBiConsumer<T, U>` from the clone
313 ///
314 /// # Examples
315 ///
316 /// ```rust
317 /// use qubit_function::{BiConsumer, ArcStatefulBiConsumer, StatefulBiConsumer};
318 /// use std::sync::{Arc, Mutex};
319 ///
320 /// let log = Arc::new(Mutex::new(Vec::new()));
321 /// let l = log.clone();
322 /// let mut consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
323 /// l.lock().unwrap().push(*x + *y);
324 /// });
325 /// let mut box_consumer = consumer.to_box();
326 /// box_consumer.accept(&5, &3);
327 /// assert_eq!(*log.lock().unwrap(), vec![8]);
328 /// // Original consumer still usable
329 /// consumer.accept(&2, &1);
330 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
331 /// ```
332 fn to_box(&self) -> BoxStatefulBiConsumer<T, U>
333 where
334 Self: Sized + Clone + 'static,
335 {
336 self.clone().into_box()
337 }
338
339 /// Converts to RcStatefulBiConsumer (non-consuming)
340 ///
341 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
342 ///
343 /// Converts the current bi-consumer to `RcStatefulBiConsumer<T, U>` by cloning
344 /// it first.
345 ///
346 /// # Ownership
347 ///
348 /// This method does **not consume** the consumer. It clones the consumer
349 /// and then converts the clone to `RcStatefulBiConsumer<T, U>`. The original
350 /// consumer remains available after calling this method.
351 ///
352 /// # Returns
353 ///
354 /// Returns the wrapped `RcStatefulBiConsumer<T, U>` from the clone
355 ///
356 /// # Examples
357 ///
358 /// ```rust
359 /// use qubit_function::{BiConsumer, ArcStatefulBiConsumer, StatefulBiConsumer};
360 /// use std::sync::{Arc, Mutex};
361 ///
362 /// let log = Arc::new(Mutex::new(Vec::new()));
363 /// let l = log.clone();
364 /// let mut consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
365 /// l.lock().unwrap().push(*x + *y);
366 /// });
367 /// let mut rc_consumer = consumer.to_rc();
368 /// rc_consumer.accept(&5, &3);
369 /// assert_eq!(*log.lock().unwrap(), vec![8]);
370 /// // Original consumer still usable
371 /// consumer.accept(&2, &1);
372 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
373 /// ```
374 fn to_rc(&self) -> RcStatefulBiConsumer<T, U>
375 where
376 Self: Sized + Clone + 'static,
377 {
378 self.clone().into_rc()
379 }
380
381 /// Converts to ArcStatefulBiConsumer (non-consuming)
382 ///
383 /// **⚠️ Requires Clone + Send**: Original consumer must implement Clone +
384 /// Send.
385 ///
386 /// Converts the current bi-consumer to `ArcStatefulBiConsumer<T, U>` by cloning
387 /// it first.
388 ///
389 /// # Ownership
390 ///
391 /// This method does **not consume** the consumer. It clones the consumer
392 /// and then converts the clone to `ArcStatefulBiConsumer<T, U>`. The original
393 /// consumer remains available after calling this method.
394 ///
395 /// # Returns
396 ///
397 /// Returns the wrapped `ArcStatefulBiConsumer<T, U>` from the clone
398 ///
399 /// # Examples
400 ///
401 /// ```rust
402 /// use qubit_function::{BiConsumer, ArcStatefulBiConsumer, StatefulBiConsumer};
403 /// use std::sync::{Arc, Mutex};
404 ///
405 /// let log = Arc::new(Mutex::new(Vec::new()));
406 /// let l = log.clone();
407 /// let mut consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
408 /// l.lock().unwrap().push(*x + *y);
409 /// });
410 /// let mut arc_consumer = consumer.to_arc();
411 /// arc_consumer.accept(&5, &3);
412 /// assert_eq!(*log.lock().unwrap(), vec![8]);
413 /// // Original consumer still usable
414 /// consumer.accept(&2, &1);
415 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
416 /// ```
417 fn to_arc(&self) -> ArcStatefulBiConsumer<T, U>
418 where
419 Self: Sized + Clone + Send + 'static,
420 {
421 self.clone().into_arc()
422 }
423
424 /// Converts to closure (non-consuming)
425 ///
426 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
427 ///
428 /// Converts the consumer to a closure that can be used directly in
429 /// standard library functions requiring `FnMut`.
430 ///
431 /// # Ownership
432 ///
433 /// This method does **not consume** the consumer. It clones the consumer
434 /// and then converts the clone to a closure. The original consumer
435 /// remains available after calling this method.
436 ///
437 /// # Returns
438 ///
439 /// Returns a closure implementing `FnMut(&T, &U)` from the clone
440 ///
441 /// # Examples
442 ///
443 /// ```rust
444 /// use qubit_function::{BiConsumer, ArcStatefulBiConsumer, StatefulBiConsumer};
445 /// use std::sync::{Arc, Mutex};
446 ///
447 /// let log = Arc::new(Mutex::new(Vec::new()));
448 /// let l = log.clone();
449 /// let mut consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
450 /// l.lock().unwrap().push(*x + *y);
451 /// });
452 /// {
453 /// let mut func = consumer.to_fn();
454 /// func(&5, &3);
455 /// assert_eq!(*log.lock().unwrap(), vec![8]);
456 /// }
457 /// // Original consumer still usable
458 /// consumer.accept(&2, &1);
459 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
460 /// ```
461 fn to_fn(&self) -> impl FnMut(&T, &U)
462 where
463 Self: Sized + Clone + 'static,
464 {
465 self.clone().into_fn()
466 }
467
468 /// Convert to BiConsumerOnce without consuming self
469 ///
470 /// **⚠️ Requires Clone**: This method requires `Self` to implement `Clone`.
471 /// Clones the current consumer and converts the clone to a one-time consumer.
472 ///
473 /// # Returns
474 ///
475 /// Returns a `BoxBiConsumerOnce<T, U>`
476 fn to_once(&self) -> BoxBiConsumerOnce<T, U>
477 where
478 Self: Clone + 'static,
479 {
480 self.clone().into_once()
481 }
482}