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