1use bytes::{Buf, BufMut};
4
5use crate::{
6 Decode, Encode, ProtocolError, UnknownTaggedFields,
7 primitives::{
8 fixed::{get_i16, get_i32, get_i64, put_i16, put_i32, put_i64},
9 string_bytes::{
10 compact_nullable_string_len, compact_string_len, get_compact_nullable_string_owned,
11 get_compact_string_owned, get_nullable_string_owned, get_string_owned,
12 nullable_string_len, put_compact_nullable_string, put_compact_string,
13 put_nullable_string, put_string, string_len,
14 },
15 },
16 tagged_fields::{WriteTaggedFields, read_tagged_fields, tagged_fields_len},
17};
18pub const API_KEY: i16 = 28;
19pub const MIN_VERSION: i16 = 0;
20pub const MAX_VERSION: i16 = 6;
21pub const LATEST_STABLE_VERSION: i16 = 6;
22pub const FLEXIBLE_MIN: i16 = 3;
23#[inline]
24#[must_use]
25pub fn is_flexible(version: i16) -> bool {
26 version >= FLEXIBLE_MIN
27}
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct TxnOffsetCommitRequest {
30 pub transactional_id: String,
31 pub group_id: String,
32 pub producer_id: i64,
33 pub producer_epoch: i16,
34 pub generation_id_or_member_epoch: i32,
35 pub member_id: String,
36 pub group_instance_id: Option<String>,
37 pub topics: Vec<TxnOffsetCommitRequestTopic>,
38 pub unknown_tagged_fields: UnknownTaggedFields,
39}
40impl Default for TxnOffsetCommitRequest {
41 fn default() -> Self {
42 Self {
43 transactional_id: String::new(),
44 group_id: String::new(),
45 producer_id: 0i64,
46 producer_epoch: 0i16,
47 generation_id_or_member_epoch: -1i32,
48 member_id: String::new(),
49 group_instance_id: None,
50 topics: Vec::new(),
51 unknown_tagged_fields: UnknownTaggedFields::default(),
52 }
53 }
54}
55impl TxnOffsetCommitRequest {
56 fn encode_field_0<B: BufMut>(&self, buf: &mut B, version: i16, flex: bool) {
57 if version >= 0 {
58 if flex {
59 let () = put_compact_string(buf, &self.transactional_id);
60 } else {
61 let () = put_string(buf, &self.transactional_id);
62 }
63 }
64 }
65 fn encode_field_1<B: BufMut>(&self, buf: &mut B, version: i16, flex: bool) {
66 if version >= 0 {
67 if flex {
68 let () = put_compact_string(buf, &self.group_id);
69 } else {
70 let () = put_string(buf, &self.group_id);
71 }
72 }
73 }
74 fn encode_field_2<B: BufMut>(&self, buf: &mut B, version: i16, _flex: bool) {
75 if version >= 0 {
76 put_i64(buf, self.producer_id);
77 }
78 }
79 fn encode_field_3<B: BufMut>(&self, buf: &mut B, version: i16, _flex: bool) {
80 if version >= 0 {
81 put_i16(buf, self.producer_epoch);
82 }
83 }
84 fn encode_field_4<B: BufMut>(&self, buf: &mut B, version: i16, _flex: bool) {
85 if version >= 3 {
86 put_i32(buf, self.generation_id_or_member_epoch);
87 }
88 }
89 fn encode_field_5<B: BufMut>(&self, buf: &mut B, version: i16, flex: bool) {
90 if version >= 3 {
91 if flex {
92 let () = put_compact_string(buf, &self.member_id);
93 } else {
94 let () = put_string(buf, &self.member_id);
95 }
96 }
97 }
98 fn encode_field_6<B: BufMut>(&self, buf: &mut B, version: i16, flex: bool) {
99 if version >= 3 {
100 if flex {
101 let () = put_compact_nullable_string(buf, self.group_instance_id.as_deref());
102 } else {
103 let () = put_nullable_string(buf, self.group_instance_id.as_deref());
104 }
105 }
106 }
107 fn encode_field_7<B: BufMut>(
108 &self,
109 buf: &mut B,
110 version: i16,
111 flex: bool,
112 ) -> Result<(), ProtocolError> {
113 if version >= 0 {
114 {
115 crate::primitives::array::put_array_len(buf, (self.topics).len(), flex);
116 for it in &self.topics {
117 it.encode(buf, version)?;
118 }
119 };
120 }
121 Ok(())
122 }
123 fn encode_tagged_fields<B: BufMut>(&self, buf: &mut B, _version: i16, flex: bool) {
124 if flex {
125 let tagged = WriteTaggedFields::new();
126 tagged.write(buf, &self.unknown_tagged_fields);
127 }
128 }
129 fn decode_field_0<B: Buf>(
130 out: &mut Self,
131 buf: &mut B,
132 version: i16,
133 flex: bool,
134 ) -> Result<(), ProtocolError> {
135 if version >= 0 {
136 out.transactional_id = if flex {
137 get_compact_string_owned(buf)?
138 } else {
139 get_string_owned(buf)?
140 };
141 }
142 Ok(())
143 }
144 fn decode_field_1<B: Buf>(
145 out: &mut Self,
146 buf: &mut B,
147 version: i16,
148 flex: bool,
149 ) -> Result<(), ProtocolError> {
150 if version >= 0 {
151 out.group_id = if flex {
152 get_compact_string_owned(buf)?
153 } else {
154 get_string_owned(buf)?
155 };
156 }
157 Ok(())
158 }
159 fn decode_field_2<B: Buf>(
160 out: &mut Self,
161 buf: &mut B,
162 version: i16,
163 _flex: bool,
164 ) -> Result<(), ProtocolError> {
165 if version >= 0 {
166 out.producer_id = get_i64(buf)?;
167 }
168 Ok(())
169 }
170 fn decode_field_3<B: Buf>(
171 out: &mut Self,
172 buf: &mut B,
173 version: i16,
174 _flex: bool,
175 ) -> Result<(), ProtocolError> {
176 if version >= 0 {
177 out.producer_epoch = get_i16(buf)?;
178 }
179 Ok(())
180 }
181 fn decode_field_4<B: Buf>(
182 out: &mut Self,
183 buf: &mut B,
184 version: i16,
185 _flex: bool,
186 ) -> Result<(), ProtocolError> {
187 if version >= 3 {
188 out.generation_id_or_member_epoch = get_i32(buf)?;
189 }
190 Ok(())
191 }
192 fn decode_field_5<B: Buf>(
193 out: &mut Self,
194 buf: &mut B,
195 version: i16,
196 flex: bool,
197 ) -> Result<(), ProtocolError> {
198 if version >= 3 {
199 out.member_id = if flex {
200 get_compact_string_owned(buf)?
201 } else {
202 get_string_owned(buf)?
203 };
204 }
205 Ok(())
206 }
207 fn decode_field_6<B: Buf>(
208 out: &mut Self,
209 buf: &mut B,
210 version: i16,
211 flex: bool,
212 ) -> Result<(), ProtocolError> {
213 if version >= 3 {
214 out.group_instance_id = if flex {
215 get_compact_nullable_string_owned(buf)?
216 } else {
217 get_nullable_string_owned(buf)?
218 };
219 }
220 Ok(())
221 }
222 fn decode_field_7<B: Buf>(
223 out: &mut Self,
224 buf: &mut B,
225 version: i16,
226 flex: bool,
227 ) -> Result<(), ProtocolError> {
228 if version >= 0 {
229 out.topics = {
230 let n = crate::primitives::array::get_array_len(buf, flex)?;
231 let mut v = Vec::with_capacity(n);
232 for _ in 0..n {
233 v.push(TxnOffsetCommitRequestTopic::decode(buf, version)?);
234 }
235 v
236 };
237 }
238 Ok(())
239 }
240 fn decode_tagged_fields<B: Buf>(
241 out: &mut Self,
242 buf: &mut B,
243 _version: i16,
244 flex: bool,
245 ) -> Result<(), ProtocolError> {
246 if flex {
247 out.unknown_tagged_fields = read_tagged_fields(buf, |_tag, _payload| Ok(false))?;
248 }
249 Ok(())
250 }
251}
252impl Encode for TxnOffsetCommitRequest {
253 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
254 if !(MIN_VERSION..=MAX_VERSION).contains(&version) {
255 return Err(ProtocolError::UnsupportedVersion {
256 api_key: API_KEY,
257 version,
258 });
259 }
260 let flex = is_flexible(version);
261 self.encode_field_0(buf, version, flex);
262 self.encode_field_1(buf, version, flex);
263 self.encode_field_2(buf, version, flex);
264 self.encode_field_3(buf, version, flex);
265 self.encode_field_4(buf, version, flex);
266 self.encode_field_5(buf, version, flex);
267 self.encode_field_6(buf, version, flex);
268 self.encode_field_7(buf, version, flex)?;
269 self.encode_tagged_fields(buf, version, flex);
270 Ok(())
271 }
272 fn encoded_len(&self, version: i16) -> usize {
273 let flex = is_flexible(version);
274 let mut n: usize = 0;
275 if version >= 0 {
276 n += if flex {
277 compact_string_len(&self.transactional_id)
278 } else {
279 string_len(&self.transactional_id)
280 };
281 }
282 if version >= 0 {
283 n += if flex {
284 compact_string_len(&self.group_id)
285 } else {
286 string_len(&self.group_id)
287 };
288 }
289 if version >= 0 {
290 n += 8;
291 }
292 if version >= 0 {
293 n += 2;
294 }
295 if version >= 3 {
296 n += 4;
297 }
298 if version >= 3 {
299 n += if flex {
300 compact_string_len(&self.member_id)
301 } else {
302 string_len(&self.member_id)
303 };
304 }
305 if version >= 3 {
306 n += if flex {
307 compact_nullable_string_len(self.group_instance_id.as_deref())
308 } else {
309 nullable_string_len(self.group_instance_id.as_deref())
310 };
311 }
312 if version >= 0 {
313 n += {
314 let prefix =
315 crate::primitives::array::array_len_prefix_len((self.topics).len(), flex);
316 let body: usize = (self.topics).iter().map(|it| it.encoded_len(version)).sum();
317 prefix + body
318 };
319 }
320 if flex {
321 let known_pairs: Vec<(u32, usize)> = Vec::new();
322 n += tagged_fields_len(&known_pairs, &self.unknown_tagged_fields);
323 }
324 n
325 }
326}
327impl Decode<'_> for TxnOffsetCommitRequest {
328 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
329 if !(MIN_VERSION..=MAX_VERSION).contains(&version) {
330 return Err(ProtocolError::UnsupportedVersion {
331 api_key: API_KEY,
332 version,
333 });
334 }
335 let flex = is_flexible(version);
336 let mut out = Self::default();
337 Self::decode_field_0(&mut out, buf, version, flex)?;
338 Self::decode_field_1(&mut out, buf, version, flex)?;
339 Self::decode_field_2(&mut out, buf, version, flex)?;
340 Self::decode_field_3(&mut out, buf, version, flex)?;
341 Self::decode_field_4(&mut out, buf, version, flex)?;
342 Self::decode_field_5(&mut out, buf, version, flex)?;
343 Self::decode_field_6(&mut out, buf, version, flex)?;
344 Self::decode_field_7(&mut out, buf, version, flex)?;
345 Self::decode_tagged_fields(&mut out, buf, version, flex)?;
346 Ok(out)
347 }
348}
349#[cfg(test)]
350impl TxnOffsetCommitRequest {
351 #[must_use]
352 pub fn populated(version: i16) -> Self {
353 let mut m = Self::default();
354 if version >= 0 {
355 m.transactional_id = "x".to_string();
356 }
357 if version >= 0 {
358 m.group_id = "x".to_string();
359 }
360 if version >= 0 {
361 m.producer_id = 1i64;
362 }
363 if version >= 0 {
364 m.producer_epoch = 1i16;
365 }
366 if version >= 3 {
367 m.generation_id_or_member_epoch = 1i32;
368 }
369 if version >= 3 {
370 m.member_id = "x".to_string();
371 }
372 if version >= 3 {
373 m.group_instance_id = Some("x".to_string());
374 }
375 if version >= 0 {
376 m.topics = vec![TxnOffsetCommitRequestTopic::populated(version)];
377 }
378 m
379 }
380}
381#[derive(Debug, Clone, PartialEq, Eq, Default)]
382pub struct TxnOffsetCommitRequestTopic {
383 pub name: String,
384 pub topic_id: crate::primitives::uuid::Uuid,
385 pub partitions: Vec<TxnOffsetCommitRequestPartition>,
386 pub unknown_tagged_fields: UnknownTaggedFields,
387}
388impl Encode for TxnOffsetCommitRequestTopic {
389 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
390 let flex = version >= 3;
391 if (0..=5).contains(&version) {
392 if flex {
393 let () = put_compact_string(buf, &self.name);
394 } else {
395 let () = put_string(buf, &self.name);
396 }
397 }
398 if version >= 6 {
399 crate::primitives::uuid::put_uuid(buf, self.topic_id);
400 }
401 if version >= 0 {
402 {
403 crate::primitives::array::put_array_len(buf, (self.partitions).len(), flex);
404 for it in &self.partitions {
405 it.encode(buf, version)?;
406 }
407 };
408 }
409 if flex {
410 let tagged = WriteTaggedFields::new();
411 tagged.write(buf, &self.unknown_tagged_fields);
412 }
413 Ok(())
414 }
415 fn encoded_len(&self, version: i16) -> usize {
416 let flex = version >= 3;
417 let mut n: usize = 0;
418 if (0..=5).contains(&version) {
419 n += if flex {
420 compact_string_len(&self.name)
421 } else {
422 string_len(&self.name)
423 };
424 }
425 if version >= 6 {
426 n += 16;
427 }
428 if version >= 0 {
429 n += {
430 let prefix =
431 crate::primitives::array::array_len_prefix_len((self.partitions).len(), flex);
432 let body: usize = (self.partitions)
433 .iter()
434 .map(|it| it.encoded_len(version))
435 .sum();
436 prefix + body
437 };
438 }
439 if flex {
440 let known_pairs: Vec<(u32, usize)> = Vec::new();
441 n += tagged_fields_len(&known_pairs, &self.unknown_tagged_fields);
442 }
443 n
444 }
445}
446impl Decode<'_> for TxnOffsetCommitRequestTopic {
447 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
448 let flex = version >= 3;
449 let mut out = Self::default();
450 if (0..=5).contains(&version) {
451 out.name = if flex {
452 get_compact_string_owned(buf)?
453 } else {
454 get_string_owned(buf)?
455 };
456 }
457 if version >= 6 {
458 out.topic_id = crate::primitives::uuid::get_uuid(buf)?;
459 }
460 if version >= 0 {
461 out.partitions = {
462 let n = crate::primitives::array::get_array_len(buf, flex)?;
463 let mut v = Vec::with_capacity(n);
464 for _ in 0..n {
465 v.push(TxnOffsetCommitRequestPartition::decode(buf, version)?);
466 }
467 v
468 };
469 }
470 if flex {
471 out.unknown_tagged_fields = read_tagged_fields(buf, |_tag, _payload| Ok(false))?;
472 }
473 Ok(out)
474 }
475}
476#[cfg(test)]
477impl TxnOffsetCommitRequestTopic {
478 #[must_use]
479 pub fn populated(version: i16) -> Self {
480 let mut m = Self::default();
481 if (0..=5).contains(&version) {
482 m.name = "x".to_string();
483 }
484 if version >= 6 {
485 m.topic_id = crate::primitives::uuid::Uuid([1u8; 16]);
486 }
487 if version >= 0 {
488 m.partitions = vec![TxnOffsetCommitRequestPartition::populated(version)];
489 }
490 m
491 }
492}
493#[derive(Debug, Clone, PartialEq, Eq)]
494pub struct TxnOffsetCommitRequestPartition {
495 pub partition_index: i32,
496 pub committed_offset: i64,
497 pub committed_leader_epoch: i32,
498 pub committed_metadata: Option<String>,
499 pub unknown_tagged_fields: UnknownTaggedFields,
500}
501impl Default for TxnOffsetCommitRequestPartition {
502 fn default() -> Self {
503 Self {
504 partition_index: 0i32,
505 committed_offset: 0i64,
506 committed_leader_epoch: -1i32,
507 committed_metadata: Some(String::new()),
508 unknown_tagged_fields: UnknownTaggedFields::default(),
509 }
510 }
511}
512impl Encode for TxnOffsetCommitRequestPartition {
513 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
514 let flex = version >= 3;
515 if version >= 0 {
516 put_i32(buf, self.partition_index);
517 }
518 if version >= 0 {
519 put_i64(buf, self.committed_offset);
520 }
521 if version >= 2 {
522 put_i32(buf, self.committed_leader_epoch);
523 }
524 if version >= 0 {
525 if flex {
526 let () = put_compact_nullable_string(buf, self.committed_metadata.as_deref());
527 } else {
528 let () = put_nullable_string(buf, self.committed_metadata.as_deref());
529 }
530 }
531 if flex {
532 let tagged = WriteTaggedFields::new();
533 tagged.write(buf, &self.unknown_tagged_fields);
534 }
535 Ok(())
536 }
537 fn encoded_len(&self, version: i16) -> usize {
538 let flex = version >= 3;
539 let mut n: usize = 0;
540 if version >= 0 {
541 n += 4;
542 }
543 if version >= 0 {
544 n += 8;
545 }
546 if version >= 2 {
547 n += 4;
548 }
549 if version >= 0 {
550 n += if flex {
551 compact_nullable_string_len(self.committed_metadata.as_deref())
552 } else {
553 nullable_string_len(self.committed_metadata.as_deref())
554 };
555 }
556 if flex {
557 let known_pairs: Vec<(u32, usize)> = Vec::new();
558 n += tagged_fields_len(&known_pairs, &self.unknown_tagged_fields);
559 }
560 n
561 }
562}
563impl Decode<'_> for TxnOffsetCommitRequestPartition {
564 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
565 let flex = version >= 3;
566 let mut out = Self::default();
567 if version >= 0 {
568 out.partition_index = get_i32(buf)?;
569 }
570 if version >= 0 {
571 out.committed_offset = get_i64(buf)?;
572 }
573 if version >= 2 {
574 out.committed_leader_epoch = get_i32(buf)?;
575 }
576 if version >= 0 {
577 out.committed_metadata = if flex {
578 get_compact_nullable_string_owned(buf)?
579 } else {
580 get_nullable_string_owned(buf)?
581 };
582 }
583 if flex {
584 out.unknown_tagged_fields = read_tagged_fields(buf, |_tag, _payload| Ok(false))?;
585 }
586 Ok(out)
587 }
588}
589#[cfg(test)]
590impl TxnOffsetCommitRequestPartition {
591 #[must_use]
592 pub fn populated(version: i16) -> Self {
593 let mut m = Self::default();
594 if version >= 0 {
595 m.partition_index = 1i32;
596 }
597 if version >= 0 {
598 m.committed_offset = 1i64;
599 }
600 if version >= 2 {
601 m.committed_leader_epoch = 1i32;
602 }
603 if version >= 0 {
604 m.committed_metadata = Some("x".to_string());
605 }
606 m
607 }
608}
609#[must_use]
612#[allow(unused_comparisons)]
613pub fn default_json(version: i16) -> ::serde_json::Value {
614 let mut obj = ::serde_json::Map::new();
615 obj.insert(
616 "transactionalId".to_string(),
617 ::serde_json::Value::String(String::new()),
618 );
619 obj.insert(
620 "groupId".to_string(),
621 ::serde_json::Value::String(String::new()),
622 );
623 obj.insert("producerId".to_string(), ::serde_json::json!(0));
624 obj.insert("producerEpoch".to_string(), ::serde_json::json!(0));
625 if version >= 3 {
626 obj.insert(
627 "generationIdOrMemberEpoch".to_string(),
628 ::serde_json::json!(-1),
629 );
630 }
631 if version >= 3 {
632 obj.insert(
633 "memberId".to_string(),
634 ::serde_json::Value::String(String::new()),
635 );
636 }
637 if version >= 3 {
638 obj.insert("groupInstanceId".to_string(), ::serde_json::Value::Null);
639 }
640 obj.insert("topics".to_string(), ::serde_json::Value::Array(vec![]));
641 ::serde_json::Value::Object(obj)
642}
643impl crate::ProtocolRequest for TxnOffsetCommitRequest {
644 const API_KEY: i16 = API_KEY;
645 const MIN_VERSION: i16 = MIN_VERSION;
646 const MAX_VERSION: i16 = MAX_VERSION;
647 const LATEST_STABLE_VERSION: i16 = LATEST_STABLE_VERSION;
648 const FLEXIBLE_MIN: i16 = FLEXIBLE_MIN;
649 type Response = super::txn_offset_commit_response::TxnOffsetCommitResponse;
650}