1use bytes::{Buf, BufMut};
12
13use crate::{
14 Decode, Encode, ProtocolError, ProtocolRequest, UnknownTaggedFields,
15 krabka::common::{
16 I16_LEN, I32_LEN, I64_LEN, array_len, check_version, decode_array, encode_array,
17 read_unknown_tagged_fields, unknown_tagged_fields_len, write_unknown_tagged_fields,
18 },
19 primitives::{
20 fixed::{get_i16, get_i32, get_i64, put_i16, put_i32, put_i64},
21 string_bytes::{compact_string_len, get_compact_string_owned, put_compact_string},
22 },
23};
24
25pub const API_KEY: i16 = 1014;
27pub const MIN_VERSION: i16 = 0;
29pub const MAX_VERSION: i16 = 0;
31pub const FLEXIBLE_MIN: i16 = 0;
33
34#[inline]
39#[must_use]
40pub fn is_flexible(version: i16) -> bool {
41 version >= FLEXIBLE_MIN
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct WritableBarrierPartition {
47 pub partition: i32,
49 pub expected_leader_epoch: i32,
55 pub unknown_tagged_fields: UnknownTaggedFields,
57}
58
59impl Default for WritableBarrierPartition {
60 fn default() -> Self {
61 Self {
62 partition: 0,
63 expected_leader_epoch: -1,
64 unknown_tagged_fields: UnknownTaggedFields::default(),
65 }
66 }
67}
68
69impl Encode for WritableBarrierPartition {
70 fn encode<B: BufMut>(&self, buf: &mut B, _version: i16) -> Result<(), ProtocolError> {
71 put_i32(buf, self.partition);
72 put_i32(buf, self.expected_leader_epoch);
73 write_unknown_tagged_fields(buf, &self.unknown_tagged_fields);
74 Ok(())
75 }
76
77 fn encoded_len(&self, _version: i16) -> usize {
78 I32_LEN + I32_LEN + unknown_tagged_fields_len(&self.unknown_tagged_fields)
79 }
80}
81
82impl Decode<'_> for WritableBarrierPartition {
83 fn decode<B: Buf>(buf: &mut B, _version: i16) -> Result<Self, ProtocolError> {
84 Ok(Self {
85 partition: get_i32(buf)?,
86 expected_leader_epoch: get_i32(buf)?,
87 unknown_tagged_fields: read_unknown_tagged_fields(buf)?,
88 })
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Default)]
94pub struct WritableBarrierTopic {
95 pub topic: String,
97 pub partitions: Vec<WritableBarrierPartition>,
99 pub unknown_tagged_fields: UnknownTaggedFields,
101}
102
103impl Encode for WritableBarrierTopic {
104 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
105 put_compact_string(buf, &self.topic);
106 encode_array(buf, &self.partitions, version)?;
107 write_unknown_tagged_fields(buf, &self.unknown_tagged_fields);
108 Ok(())
109 }
110
111 fn encoded_len(&self, version: i16) -> usize {
112 compact_string_len(&self.topic)
113 + array_len(&self.partitions, version)
114 + unknown_tagged_fields_len(&self.unknown_tagged_fields)
115 }
116}
117
118impl Decode<'_> for WritableBarrierTopic {
119 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
120 Ok(Self {
121 topic: get_compact_string_owned(buf)?,
122 partitions: decode_array(buf, version)?,
123 unknown_tagged_fields: read_unknown_tagged_fields(buf)?,
124 })
125 }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Default)]
130pub struct WriteBarrierMarkersRequest {
131 pub group: String,
133 pub epoch: i64,
135 pub triggered_at: i64,
138 pub topics: Vec<WritableBarrierTopic>,
140 pub unknown_tagged_fields: UnknownTaggedFields,
142}
143
144impl Encode for WriteBarrierMarkersRequest {
145 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
146 check_version(API_KEY, version, MIN_VERSION, MAX_VERSION)?;
147 put_compact_string(buf, &self.group);
148 put_i64(buf, self.epoch);
149 put_i64(buf, self.triggered_at);
150 encode_array(buf, &self.topics, version)?;
151 write_unknown_tagged_fields(buf, &self.unknown_tagged_fields);
152 Ok(())
153 }
154
155 fn encoded_len(&self, version: i16) -> usize {
156 compact_string_len(&self.group)
157 + I64_LEN
158 + I64_LEN
159 + array_len(&self.topics, version)
160 + unknown_tagged_fields_len(&self.unknown_tagged_fields)
161 }
162}
163
164impl Decode<'_> for WriteBarrierMarkersRequest {
165 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
166 check_version(API_KEY, version, MIN_VERSION, MAX_VERSION)?;
167 Ok(Self {
168 group: get_compact_string_owned(buf)?,
169 epoch: get_i64(buf)?,
170 triggered_at: get_i64(buf)?,
171 topics: decode_array(buf, version)?,
172 unknown_tagged_fields: read_unknown_tagged_fields(buf)?,
173 })
174 }
175}
176
177impl ProtocolRequest for WriteBarrierMarkersRequest {
178 const API_KEY: i16 = API_KEY;
179 const MIN_VERSION: i16 = MIN_VERSION;
180 const MAX_VERSION: i16 = MAX_VERSION;
181 const LATEST_STABLE_VERSION: i16 = MAX_VERSION;
182 const FLEXIBLE_MIN: i16 = FLEXIBLE_MIN;
183
184 type Response = WriteBarrierMarkersResponse;
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Default)]
189pub struct WrittenBarrierPartition {
190 pub partition: i32,
192 pub error_code: i16,
195 pub offset: i64,
198 pub unknown_tagged_fields: UnknownTaggedFields,
200}
201
202impl Encode for WrittenBarrierPartition {
203 fn encode<B: BufMut>(&self, buf: &mut B, _version: i16) -> Result<(), ProtocolError> {
204 put_i32(buf, self.partition);
205 put_i16(buf, self.error_code);
206 put_i64(buf, self.offset);
207 write_unknown_tagged_fields(buf, &self.unknown_tagged_fields);
208 Ok(())
209 }
210
211 fn encoded_len(&self, _version: i16) -> usize {
212 I32_LEN + I16_LEN + I64_LEN + unknown_tagged_fields_len(&self.unknown_tagged_fields)
213 }
214}
215
216impl Decode<'_> for WrittenBarrierPartition {
217 fn decode<B: Buf>(buf: &mut B, _version: i16) -> Result<Self, ProtocolError> {
218 Ok(Self {
219 partition: get_i32(buf)?,
220 error_code: get_i16(buf)?,
221 offset: get_i64(buf)?,
222 unknown_tagged_fields: read_unknown_tagged_fields(buf)?,
223 })
224 }
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Default)]
229pub struct WrittenBarrierTopic {
230 pub topic: String,
232 pub partitions: Vec<WrittenBarrierPartition>,
234 pub unknown_tagged_fields: UnknownTaggedFields,
236}
237
238impl Encode for WrittenBarrierTopic {
239 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
240 put_compact_string(buf, &self.topic);
241 encode_array(buf, &self.partitions, version)?;
242 write_unknown_tagged_fields(buf, &self.unknown_tagged_fields);
243 Ok(())
244 }
245
246 fn encoded_len(&self, version: i16) -> usize {
247 compact_string_len(&self.topic)
248 + array_len(&self.partitions, version)
249 + unknown_tagged_fields_len(&self.unknown_tagged_fields)
250 }
251}
252
253impl Decode<'_> for WrittenBarrierTopic {
254 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
255 Ok(Self {
256 topic: get_compact_string_owned(buf)?,
257 partitions: decode_array(buf, version)?,
258 unknown_tagged_fields: read_unknown_tagged_fields(buf)?,
259 })
260 }
261}
262
263#[derive(Debug, Clone, PartialEq, Eq, Default)]
268pub struct WriteBarrierMarkersResponse {
269 pub topics: Vec<WrittenBarrierTopic>,
271 pub unknown_tagged_fields: UnknownTaggedFields,
273}
274
275impl Encode for WriteBarrierMarkersResponse {
276 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
277 check_version(API_KEY, version, MIN_VERSION, MAX_VERSION)?;
278 encode_array(buf, &self.topics, version)?;
279 write_unknown_tagged_fields(buf, &self.unknown_tagged_fields);
280 Ok(())
281 }
282
283 fn encoded_len(&self, version: i16) -> usize {
284 array_len(&self.topics, version) + unknown_tagged_fields_len(&self.unknown_tagged_fields)
285 }
286}
287
288impl Decode<'_> for WriteBarrierMarkersResponse {
289 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
290 check_version(API_KEY, version, MIN_VERSION, MAX_VERSION)?;
291 Ok(Self {
292 topics: decode_array(buf, version)?,
293 unknown_tagged_fields: read_unknown_tagged_fields(buf)?,
294 })
295 }
296}
297
298#[cfg(test)]
299impl WriteBarrierMarkersRequest {
300 fn populated() -> Self {
302 Self {
303 group: "orders".to_string(),
304 epoch: 41,
305 triggered_at: 1_724_500_000_000,
306 topics: vec![
307 WritableBarrierTopic {
308 topic: "orders".to_string(),
309 partitions: vec![
310 WritableBarrierPartition {
311 partition: 0,
312 expected_leader_epoch: 4,
313 unknown_tagged_fields: UnknownTaggedFields::default(),
314 },
315 WritableBarrierPartition {
316 partition: 3,
317 expected_leader_epoch: -1,
318 unknown_tagged_fields:
319 crate::krabka::test_support::sample_tagged_fields(),
320 },
321 WritableBarrierPartition {
322 partition: 7,
323 expected_leader_epoch: 17,
324 unknown_tagged_fields: UnknownTaggedFields::default(),
325 },
326 ],
327 unknown_tagged_fields: crate::krabka::test_support::sample_tagged_fields(),
328 },
329 WritableBarrierTopic {
330 topic: "payments".to_string(),
331 partitions: Vec::new(),
332 unknown_tagged_fields: UnknownTaggedFields::default(),
333 },
334 ],
335 unknown_tagged_fields: crate::krabka::test_support::sample_tagged_fields(),
336 }
337 }
338}
339
340#[cfg(test)]
341impl WriteBarrierMarkersResponse {
342 fn populated() -> Self {
344 Self {
345 topics: vec![WrittenBarrierTopic {
346 topic: "orders".to_string(),
347 partitions: vec![
348 WrittenBarrierPartition {
349 partition: 0,
350 error_code: 0,
351 offset: 9_412,
352 unknown_tagged_fields: UnknownTaggedFields::default(),
353 },
354 WrittenBarrierPartition {
355 partition: 3,
356 error_code: 6,
357 offset: -1,
358 unknown_tagged_fields: crate::krabka::test_support::sample_tagged_fields(),
359 },
360 ],
361 unknown_tagged_fields: UnknownTaggedFields::default(),
362 }],
363 unknown_tagged_fields: crate::krabka::test_support::sample_tagged_fields(),
364 }
365 }
366}
367
368#[cfg(test)]
369mod tests {
370 use assert2::assert;
371
372 use super::*;
373 use crate::krabka::test_support::{reject_truncated, roundtrip, unsupported_versions};
374
375 #[test]
376 fn default_roundtrips_all_versions() {
377 for version in MIN_VERSION..=MAX_VERSION {
378 roundtrip(&WriteBarrierMarkersRequest::default(), version);
379 roundtrip(&WriteBarrierMarkersResponse::default(), version);
380 }
381 }
382
383 #[test]
384 fn populated_roundtrips_all_versions() {
385 for version in MIN_VERSION..=MAX_VERSION {
386 roundtrip(&WriteBarrierMarkersRequest::populated(), version);
387 roundtrip(&WriteBarrierMarkersResponse::populated(), version);
388 }
389 }
390
391 #[test]
392 fn no_expected_leader_epoch_is_the_partition_default() {
393 assert!(
394 WritableBarrierPartition::default()
395 == WritableBarrierPartition {
396 partition: 0,
397 expected_leader_epoch: -1,
398 unknown_tagged_fields: UnknownTaggedFields::default(),
399 }
400 );
401 }
402
403 #[test]
404 fn truncated_input_is_rejected() {
405 reject_truncated(&WriteBarrierMarkersRequest::populated(), MIN_VERSION);
406 reject_truncated(&WriteBarrierMarkersResponse::populated(), MIN_VERSION);
407 }
408
409 #[test]
410 fn rejects_unsupported_versions() {
411 for version in unsupported_versions(MIN_VERSION, MAX_VERSION) {
412 let request = WriteBarrierMarkersRequest::populated();
413 assert!(matches!(
414 request.encode(&mut Vec::<u8>::new(), version),
415 Err(ProtocolError::UnsupportedVersion {
416 api_key: API_KEY,
417 ..
418 })
419 ));
420 }
421 }
422}