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