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