Skip to main content

qubit_batch/process/
batch_processor.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 ******************************************************************************/
10use super::BatchProcessResult;
11
12/// Processes a batch of data items.
13///
14/// This trait models processors that receive data items directly. A processor
15/// may insert records into a database, send them to a remote service, or apply
16/// any other batch-level operation chosen by the implementation.
17///
18/// ```rust
19/// use std::time::Duration;
20///
21/// use qubit_batch::{
22///     BatchProcessResult,
23///     BatchProcessResultBuilder,
24///     BatchProcessor,
25/// };
26///
27/// struct CountItems;
28///
29/// impl BatchProcessor<i32> for CountItems {
30///     type Error = &'static str;
31///
32///     fn process_with_count<I>(
33///         &mut self,
34///         items: I,
35///         count: usize,
36///     ) -> Result<BatchProcessResult, Self::Error>
37///     where
38///         I: IntoIterator<Item = i32>,
39///     {
40///         let processed = items.into_iter().count();
41///         BatchProcessResultBuilder::builder(count)
42///             .completed_count(processed)
43///             .processed_count(processed)
44///             .chunk_count(1)
45///             .elapsed(Duration::ZERO)
46///             .build()
47///             .map_err(|_| "invalid process result")
48///     }
49/// }
50///
51/// let result = CountItems
52///     .process([1, 2, 3])
53///     .expect("array length should be exact");
54///
55/// assert!(result.is_success());
56/// ```
57///
58/// # Type Parameters
59///
60/// * `Item` - The data item type consumed by this processor.
61///
62pub trait BatchProcessor<Item> {
63    /// Error returned by this processor.
64    type Error;
65
66    /// Processes `items` as one batch using its exact iterator length.
67    ///
68    /// # Parameters
69    ///
70    /// * `items` - Data source for this batch. Its iterator must report the
71    ///   remaining item count exactly.
72    ///
73    /// # Returns
74    ///
75    /// The result returned by [`Self::process_with_count`] after deriving the
76    /// declared count from the iterator length.
77    ///
78    /// # Errors
79    ///
80    /// Returns [`Self::Error`] if the processor rejects the batch or if the
81    /// iterator violates its exact length contract while being consumed.
82    fn process<I>(&mut self, items: I) -> Result<BatchProcessResult, Self::Error>
83    where
84        I: IntoIterator<Item = Item>,
85        I::IntoIter: ExactSizeIterator,
86    {
87        let items = items.into_iter();
88        let count = items.len();
89        self.process_with_count(items, count)
90    }
91
92    /// Processes `items` as one batch with an explicit declared count.
93    ///
94    /// # Parameters
95    ///
96    /// * `items` - Data source for this batch.
97    /// * `count` - Declared number of items expected from `items`.
98    ///
99    /// # Returns
100    ///
101    /// Returns a [`BatchProcessResult`] describing the processed batch when the
102    /// processor accepts the input.
103    ///
104    /// # Errors
105    ///
106    /// Returns [`Self::Error`] when this processor cannot process the batch.
107    fn process_with_count<I>(
108        &mut self,
109        items: I,
110        count: usize,
111    ) -> Result<BatchProcessResult, Self::Error>
112    where
113        I: IntoIterator<Item = Item>;
114}