Skip to main content

krabka_client_consumer/share/
types.rs

1//! Public value types for the share-group consumer.
2
3use bytes::Bytes;
4
5use crate::consumer::TimestampType;
6
7/// One record delivered by [`ShareConsumer::poll`](super::ShareConsumer).
8///
9/// Unlike a classic `ConsumerRecord`, a share record carries a
10/// `delivery_count`. The broker increments it each time it re-acquires the
11/// record after a prior delivery was released or after its acquisition lock
12/// expired, per KIP-932. A first delivery has `delivery_count == 1`.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct ShareConsumerRecord {
15    pub topic: String,
16    pub partition: i32,
17    pub offset: i64,
18    /// The create time, or for a `LogAppendTime` batch the broker append
19    /// time (the batch `max_timestamp`).
20    pub timestamp: i64,
21    /// The timestamp type from the attributes of the record batch.
22    pub timestamp_type: TimestampType,
23    pub key: Option<Bytes>,
24    pub value: Option<Bytes>,
25    /// Kafka record headers, kept lossless and in wire order.
26    pub headers: Vec<(String, Option<Bytes>)>,
27    pub delivery_count: i16,
28}
29
30/// How acquired records are acknowledged.
31///
32/// In [`Implicit`](ShareAckMode::Implicit) mode the next `poll()`, and
33/// `close()`, implicitly `Accept` every record that the previous `poll()`
34/// returned. In [`Explicit`](ShareAckMode::Explicit) mode the application must
35/// call `acknowledge()` for each record. The broker releases un-acknowledged
36/// records back to the queue.
37#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
38pub enum ShareAckMode {
39    /// Auto-accept the previous batch on the next poll. The default, matching
40    /// the JVM `share.acknowledgement.mode=implicit`.
41    #[default]
42    Implicit,
43    /// The application acknowledges each record explicitly.
44    Explicit,
45}
46
47/// How a `ShareFetch` applies its maximum-record limit.
48#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
49pub enum ShareAcquireMode {
50    /// Acquire complete record batches, which can exceed the requested record
51    /// limit. This keeps the existing Kafka-compatible behavior.
52    #[default]
53    BatchOptimized,
54    /// Stop acquiring when the requested record limit is reached.
55    RecordLimit,
56}
57
58impl ShareAcquireMode {
59    /// The `i8` wire value carried in `ShareFetch` version 2 and later.
60    pub(crate) fn wire(self) -> i8 {
61        match self {
62            Self::BatchOptimized => 0,
63            Self::RecordLimit => 1,
64        }
65    }
66}
67
68/// The disposition of an acknowledged record, with the KIP-932 wire codes.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum ShareAckType {
71    /// Successfully processed. Advance the share-partition start offset past it.
72    Accept,
73    /// Return to the queue for re-delivery. This increments `delivery_count`.
74    Release,
75    /// Permanently skip. Do not re-deliver.
76    Reject,
77}
78
79impl ShareAckType {
80    /// The `i8` wire value carried in `ShareFetch` / `ShareAcknowledge`
81    /// acknowledgement batches.
82    pub(crate) fn wire(self) -> i8 {
83        match self {
84            Self::Accept => 1,
85            Self::Release => 2,
86            Self::Reject => 3,
87        }
88    }
89}
90
91#[cfg(test)]
92mod tests {
93
94    use super::*;
95
96    #[test]
97    fn ack_wire_codes() {
98        for (_name, ack, expected) in [
99            ("accept", ShareAckType::Accept, 1),
100            ("release", ShareAckType::Release, 2),
101            ("reject", ShareAckType::Reject, 3),
102        ] {
103            assert2::assert!(ack.wire() == expected);
104        }
105    }
106
107    #[test]
108    fn ack_mode_default_is_implicit() {
109        assert2::assert!(ShareAckMode::default() == ShareAckMode::Implicit);
110    }
111
112    #[test]
113    fn acquire_mode_default_is_batch_optimized() {
114        assert2::assert!(ShareAcquireMode::default() == ShareAcquireMode::BatchOptimized);
115    }
116
117    #[test]
118    fn acquire_mode_wire_codes_match_kafka() {
119        for (mode, expected) in [
120            (ShareAcquireMode::BatchOptimized, 0),
121            (ShareAcquireMode::RecordLimit, 1),
122        ] {
123            assert2::assert!(mode.wire() == expected);
124        }
125    }
126}