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}