1use crate::api::produce::RecordBatchHeader;
2use crate::codec::{DecodeLimits, Decoder, Encoder};
3use crate::error::{Error, Result};
4use crate::header::RequestHeader;
5use crate::record_batch::{decompress_record_batch_records_with_limit, RecordBatchCompression};
6
7pub const API_KEY: i16 = 1;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct FetchRequestV2 {
11 pub correlation_id: i32,
12 pub client_id: Option<String>,
13 pub replica_id: i32,
14 pub max_wait_ms: i32,
15 pub min_bytes: i32,
16 pub topics: Vec<FetchTopicV2>,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct FetchRequestV4 {
21 pub correlation_id: i32,
22 pub client_id: Option<String>,
23 pub replica_id: i32,
24 pub max_wait_ms: i32,
25 pub min_bytes: i32,
26 pub max_bytes: i32,
27 pub isolation_level: i8,
28 pub topics: Vec<FetchTopicV2>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct FetchRequestV11 {
37 pub correlation_id: i32,
38 pub client_id: Option<String>,
39 pub replica_id: i32,
40 pub max_wait_ms: i32,
41 pub min_bytes: i32,
42 pub max_bytes: i32,
43 pub isolation_level: i8,
44 pub session_id: i32,
45 pub session_epoch: i32,
46 pub topics: Vec<FetchTopicV11>,
47 pub forgotten_topics: Vec<FetchForgottenTopicV11>,
48 pub rack_id: String,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct FetchRequestV12 {
54 pub correlation_id: i32,
55 pub client_id: Option<String>,
56 pub replica_id: i32,
57 pub max_wait_ms: i32,
58 pub min_bytes: i32,
59 pub max_bytes: i32,
60 pub isolation_level: i8,
61 pub session_id: i32,
62 pub session_epoch: i32,
63 pub topics: Vec<FetchTopicV12>,
64 pub forgotten_topics: Vec<FetchForgottenTopicV12>,
65 pub rack_id: String,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct FetchRequestV13 {
76 pub correlation_id: i32,
77 pub client_id: Option<String>,
78 pub cluster_id: Option<String>,
79 pub replica_id: i32,
80 pub max_wait_ms: i32,
81 pub min_bytes: i32,
82 pub max_bytes: i32,
83 pub isolation_level: i8,
84 pub session_id: i32,
85 pub session_epoch: i32,
86 pub topics: Vec<FetchTopicV13>,
87 pub forgotten_topics: Vec<FetchForgottenTopicV13>,
88 pub rack_id: String,
89}
90
91impl FetchRequestV12 {
92 pub fn encode(&self) -> Result<Vec<u8>> {
93 let mut encoder = Encoder::new();
94 RequestHeader {
95 api_key: API_KEY,
96 api_version: 12,
97 correlation_id: self.correlation_id,
98 client_id: self.client_id.clone(),
99 }
100 .encode_v2(&mut encoder)?;
101 encoder.write_i32(self.replica_id);
102 encoder.write_i32(self.max_wait_ms);
103 encoder.write_i32(self.min_bytes);
104 encoder.write_i32(self.max_bytes);
105 encoder.write_i8(self.isolation_level);
106 encoder.write_i32(self.session_id);
107 encoder.write_i32(self.session_epoch);
108 encoder.write_compact_array(Some(self.topics.as_slice()), |encoder, topic| {
109 topic.encode(encoder)
110 })?;
111 encoder.write_compact_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
112 topic.encode(encoder)
113 })?;
114 encoder.write_compact_string(&self.rack_id)?;
115 encoder.write_empty_tagged_fields();
116 Ok(encoder.into_bytes())
117 }
118}
119
120impl FetchRequestV13 {
121 pub fn encode(&self) -> Result<Vec<u8>> {
122 self.encode_version(13)
123 }
124
125 fn encode_version(&self, api_version: i16) -> Result<Vec<u8>> {
126 let mut encoder = Encoder::new();
127 RequestHeader {
128 api_key: API_KEY,
129 api_version,
130 correlation_id: self.correlation_id,
131 client_id: self.client_id.clone(),
132 }
133 .encode_v2(&mut encoder)?;
134 encoder.write_i32(self.replica_id);
135 encoder.write_i32(self.max_wait_ms);
136 encoder.write_i32(self.min_bytes);
137 encoder.write_i32(self.max_bytes);
138 encoder.write_i8(self.isolation_level);
139 encoder.write_i32(self.session_id);
140 encoder.write_i32(self.session_epoch);
141 encoder.write_compact_array(Some(self.topics.as_slice()), |encoder, topic| {
142 topic.encode(encoder)
143 })?;
144 encoder.write_compact_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
145 topic.encode(encoder)
146 })?;
147 encoder.write_compact_string(&self.rack_id)?;
148 write_cluster_id_tag(&mut encoder, self.cluster_id.as_deref())?;
149 Ok(encoder.into_bytes())
150 }
151}
152
153#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct FetchRequestV14 {
157 pub correlation_id: i32,
158 pub client_id: Option<String>,
159 pub cluster_id: Option<String>,
160 pub replica_id: i32,
161 pub max_wait_ms: i32,
162 pub min_bytes: i32,
163 pub max_bytes: i32,
164 pub isolation_level: i8,
165 pub session_id: i32,
166 pub session_epoch: i32,
167 pub topics: Vec<FetchTopicV14>,
168 pub forgotten_topics: Vec<FetchForgottenTopicV14>,
169 pub rack_id: String,
170}
171
172impl FetchRequestV14 {
173 pub fn encode(&self) -> Result<Vec<u8>> {
174 FetchRequestV13 {
175 correlation_id: self.correlation_id,
176 client_id: self.client_id.clone(),
177 cluster_id: self.cluster_id.clone(),
178 replica_id: self.replica_id,
179 max_wait_ms: self.max_wait_ms,
180 min_bytes: self.min_bytes,
181 max_bytes: self.max_bytes,
182 isolation_level: self.isolation_level,
183 session_id: self.session_id,
184 session_epoch: self.session_epoch,
185 topics: self.topics.clone(),
186 forgotten_topics: self.forgotten_topics.clone(),
187 rack_id: self.rack_id.clone(),
188 }
189 .encode_version(14)
190 }
191}
192
193#[derive(Debug, Clone, PartialEq, Eq)]
195pub struct FetchReplicaStateV15 {
196 pub replica_id: i32,
197 pub replica_epoch: i64,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq)]
202pub struct FetchRequestV15 {
203 pub correlation_id: i32,
204 pub client_id: Option<String>,
205 pub cluster_id: Option<String>,
206 pub replica_state: Option<FetchReplicaStateV15>,
207 pub max_wait_ms: i32,
208 pub min_bytes: i32,
209 pub max_bytes: i32,
210 pub isolation_level: i8,
211 pub session_id: i32,
212 pub session_epoch: i32,
213 pub topics: Vec<FetchTopicV15>,
214 pub forgotten_topics: Vec<FetchForgottenTopicV15>,
215 pub rack_id: String,
216}
217
218impl FetchRequestV15 {
219 pub fn encode(&self) -> Result<Vec<u8>> {
220 self.encode_version(15)
221 }
222
223 fn encode_version(&self, api_version: i16) -> Result<Vec<u8>> {
224 let mut encoder = Encoder::new();
225 RequestHeader {
226 api_key: API_KEY,
227 api_version,
228 correlation_id: self.correlation_id,
229 client_id: self.client_id.clone(),
230 }
231 .encode_v2(&mut encoder)?;
232 encoder.write_i32(self.max_wait_ms);
233 encoder.write_i32(self.min_bytes);
234 encoder.write_i32(self.max_bytes);
235 encoder.write_i8(self.isolation_level);
236 encoder.write_i32(self.session_id);
237 encoder.write_i32(self.session_epoch);
238 encoder.write_compact_array(Some(self.topics.as_slice()), |encoder, topic| {
239 topic.encode(encoder)
240 })?;
241 encoder.write_compact_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
242 topic.encode(encoder)
243 })?;
244 encoder.write_compact_string(&self.rack_id)?;
245 write_fetch_request_tags(
246 &mut encoder,
247 self.cluster_id.as_deref(),
248 self.replica_state.as_ref(),
249 )?;
250 Ok(encoder.into_bytes())
251 }
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
256pub struct FetchRequestV16 {
257 pub correlation_id: i32,
258 pub client_id: Option<String>,
259 pub cluster_id: Option<String>,
260 pub replica_state: Option<FetchReplicaStateV15>,
261 pub max_wait_ms: i32,
262 pub min_bytes: i32,
263 pub max_bytes: i32,
264 pub isolation_level: i8,
265 pub session_id: i32,
266 pub session_epoch: i32,
267 pub topics: Vec<FetchTopicV16>,
268 pub forgotten_topics: Vec<FetchForgottenTopicV16>,
269 pub rack_id: String,
270}
271
272impl FetchRequestV16 {
273 pub fn encode(&self) -> Result<Vec<u8>> {
274 FetchRequestV15 {
275 correlation_id: self.correlation_id,
276 client_id: self.client_id.clone(),
277 cluster_id: self.cluster_id.clone(),
278 replica_state: self.replica_state.clone(),
279 max_wait_ms: self.max_wait_ms,
280 min_bytes: self.min_bytes,
281 max_bytes: self.max_bytes,
282 isolation_level: self.isolation_level,
283 session_id: self.session_id,
284 session_epoch: self.session_epoch,
285 topics: self.topics.clone(),
286 forgotten_topics: self.forgotten_topics.clone(),
287 rack_id: self.rack_id.clone(),
288 }
289 .encode_version(16)
290 }
291}
292
293#[derive(Debug, Clone, PartialEq, Eq)]
295pub struct FetchRequestV17 {
296 pub correlation_id: i32,
297 pub client_id: Option<String>,
298 pub cluster_id: Option<String>,
299 pub replica_state: Option<FetchReplicaStateV15>,
300 pub max_wait_ms: i32,
301 pub min_bytes: i32,
302 pub max_bytes: i32,
303 pub isolation_level: i8,
304 pub session_id: i32,
305 pub session_epoch: i32,
306 pub topics: Vec<FetchTopicV17>,
307 pub forgotten_topics: Vec<FetchForgottenTopicV17>,
308 pub rack_id: String,
309}
310
311impl FetchRequestV17 {
312 pub fn encode(&self) -> Result<Vec<u8>> {
313 encode_fetch_v17_plus_request(
314 17,
315 self.correlation_id,
316 self.client_id.clone(),
317 self.cluster_id.as_deref(),
318 self.replica_state.as_ref(),
319 self.max_wait_ms,
320 self.min_bytes,
321 self.max_bytes,
322 self.isolation_level,
323 self.session_id,
324 self.session_epoch,
325 &self.topics,
326 |encoder, topic| topic.encode(encoder),
327 &self.forgotten_topics,
328 self.rack_id.as_str(),
329 )
330 }
331}
332
333#[derive(Debug, Clone, PartialEq, Eq)]
335pub struct FetchRequestV18 {
336 pub correlation_id: i32,
337 pub client_id: Option<String>,
338 pub cluster_id: Option<String>,
339 pub replica_state: Option<FetchReplicaStateV15>,
340 pub max_wait_ms: i32,
341 pub min_bytes: i32,
342 pub max_bytes: i32,
343 pub isolation_level: i8,
344 pub session_id: i32,
345 pub session_epoch: i32,
346 pub topics: Vec<FetchTopicV18>,
347 pub forgotten_topics: Vec<FetchForgottenTopicV18>,
348 pub rack_id: String,
349}
350
351impl FetchRequestV18 {
352 pub fn encode(&self) -> Result<Vec<u8>> {
353 encode_fetch_v17_plus_request(
354 18,
355 self.correlation_id,
356 self.client_id.clone(),
357 self.cluster_id.as_deref(),
358 self.replica_state.as_ref(),
359 self.max_wait_ms,
360 self.min_bytes,
361 self.max_bytes,
362 self.isolation_level,
363 self.session_id,
364 self.session_epoch,
365 &self.topics,
366 |encoder, topic| topic.encode(encoder),
367 &self.forgotten_topics,
368 self.rack_id.as_str(),
369 )
370 }
371}
372
373#[allow(clippy::too_many_arguments)]
375fn encode_fetch_v17_plus_request<T, F>(
376 api_version: i16,
377 correlation_id: i32,
378 client_id: Option<String>,
379 cluster_id: Option<&str>,
380 replica_state: Option<&FetchReplicaStateV15>,
381 max_wait_ms: i32,
382 min_bytes: i32,
383 max_bytes: i32,
384 isolation_level: i8,
385 session_id: i32,
386 session_epoch: i32,
387 topics: &[T],
388 mut encode_topic: F,
389 forgotten_topics: &[FetchForgottenTopicV13],
390 rack_id: &str,
391) -> Result<Vec<u8>>
392where
393 F: FnMut(&mut Encoder, &T) -> Result<()>,
394{
395 let mut encoder = Encoder::new();
396 RequestHeader {
397 api_key: API_KEY,
398 api_version,
399 correlation_id,
400 client_id,
401 }
402 .encode_v2(&mut encoder)?;
403 encoder.write_i32(max_wait_ms);
404 encoder.write_i32(min_bytes);
405 encoder.write_i32(max_bytes);
406 encoder.write_i8(isolation_level);
407 encoder.write_i32(session_id);
408 encoder.write_i32(session_epoch);
409 encoder.write_compact_array(Some(topics), |encoder, topic| encode_topic(encoder, topic))?;
410 encoder.write_compact_array(Some(forgotten_topics), |encoder, topic| {
411 topic.encode(encoder)
412 })?;
413 encoder.write_compact_string(rack_id)?;
414 write_fetch_request_tags(&mut encoder, cluster_id, replica_state)?;
415 Ok(encoder.into_bytes())
416}
417
418fn write_cluster_id_tag(encoder: &mut Encoder, cluster_id: Option<&str>) -> Result<()> {
419 write_fetch_request_tags(encoder, cluster_id, None)
420}
421
422fn write_fetch_request_tags(
423 encoder: &mut Encoder,
424 cluster_id: Option<&str>,
425 replica_state: Option<&FetchReplicaStateV15>,
426) -> Result<()> {
427 let mut fields = Vec::new();
428 if let Some(cluster_id) = cluster_id {
429 let mut value = Encoder::new();
430 value.write_compact_string(cluster_id)?;
431 fields.push((0, value.into_bytes()));
432 }
433 if let Some(replica_state) = replica_state {
434 let mut value = Encoder::new();
435 value.write_i32(replica_state.replica_id);
436 value.write_i64(replica_state.replica_epoch);
437 fields.push((1, value.into_bytes()));
438 }
439 let field_count =
440 u32::try_from(fields.len()).map_err(|_| Error::LengthOverflow("tagged fields"))?;
441 encoder.write_unsigned_varint(field_count);
442 for (tag, value) in fields {
443 encoder.write_unsigned_varint(tag);
444 let value_len =
445 u32::try_from(value.len()).map_err(|_| Error::LengthOverflow("tagged field"))?;
446 encoder.write_unsigned_varint(value_len);
447 encoder.write_raw(&value);
448 }
449 Ok(())
450}
451
452fn write_fetch_partition_v17_tags(
453 encoder: &mut Encoder,
454 replica_directory_id: Option<&[u8; 16]>,
455 high_watermark: Option<i64>,
456) {
457 let tag_count = u32::from(replica_directory_id.is_some()) + u32::from(high_watermark.is_some());
458 encoder.write_unsigned_varint(tag_count);
459 if let Some(replica_directory_id) = replica_directory_id {
460 encoder.write_unsigned_varint(0);
461 encoder.write_unsigned_varint(16);
462 encoder.write_uuid(replica_directory_id);
463 }
464 if let Some(high_watermark) = high_watermark {
465 encoder.write_unsigned_varint(1);
466 encoder.write_unsigned_varint(8);
467 encoder.write_i64(high_watermark);
468 }
469}
470
471#[derive(Debug, Clone, PartialEq, Eq)]
472pub struct FetchTopicV12 {
473 pub name: String,
474 pub partitions: Vec<FetchPartitionV12>,
475}
476
477impl FetchTopicV12 {
478 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
479 encoder.write_compact_string(&self.name)?;
480 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
481 partition.encode(encoder)
482 })?;
483 encoder.write_empty_tagged_fields();
484 Ok(())
485 }
486}
487
488#[derive(Debug, Clone, PartialEq, Eq)]
489pub struct FetchPartitionV12 {
490 pub partition_index: i32,
491 pub current_leader_epoch: i32,
492 pub fetch_offset: i64,
493 pub last_fetched_epoch: i32,
494 pub log_start_offset: i64,
495 pub max_bytes: i32,
496}
497
498impl FetchPartitionV12 {
499 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
500 encoder.write_i32(self.partition_index);
501 encoder.write_i32(self.current_leader_epoch);
502 encoder.write_i64(self.fetch_offset);
503 encoder.write_i32(self.last_fetched_epoch);
504 encoder.write_i64(self.log_start_offset);
505 encoder.write_i32(self.max_bytes);
506 encoder.write_empty_tagged_fields();
507 Ok(())
508 }
509}
510
511#[derive(Debug, Clone, PartialEq, Eq)]
512pub struct FetchForgottenTopicV12 {
513 pub name: String,
514 pub partitions: Vec<i32>,
515}
516
517#[derive(Debug, Clone, PartialEq, Eq)]
518pub struct FetchTopicV13 {
519 pub topic_id: [u8; 16],
520 pub partitions: Vec<FetchPartitionV13>,
521}
522
523impl FetchTopicV13 {
524 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
525 encoder.write_uuid(&self.topic_id);
526 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
527 partition.encode(encoder)
528 })?;
529 encoder.write_empty_tagged_fields();
530 Ok(())
531 }
532}
533
534pub type FetchPartitionV13 = FetchPartitionV12;
535pub type FetchTopicV14 = FetchTopicV13;
536pub type FetchPartitionV14 = FetchPartitionV13;
537pub type FetchTopicV16 = FetchTopicV13;
538pub type FetchPartitionV16 = FetchPartitionV13;
539pub type FetchTopicV15 = FetchTopicV13;
540pub type FetchPartitionV15 = FetchPartitionV13;
541
542#[derive(Debug, Clone, PartialEq, Eq)]
543pub struct FetchTopicV17 {
544 pub topic_id: [u8; 16],
545 pub partitions: Vec<FetchPartitionV17>,
546}
547
548impl FetchTopicV17 {
549 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
550 encoder.write_uuid(&self.topic_id);
551 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
552 partition.encode(encoder)
553 })?;
554 encoder.write_empty_tagged_fields();
555 Ok(())
556 }
557}
558
559#[derive(Debug, Clone, PartialEq, Eq)]
560pub struct FetchPartitionV17 {
561 pub partition_index: i32,
562 pub current_leader_epoch: i32,
563 pub fetch_offset: i64,
564 pub last_fetched_epoch: i32,
565 pub log_start_offset: i64,
566 pub max_bytes: i32,
567 pub replica_directory_id: Option<[u8; 16]>,
568}
569
570impl FetchPartitionV17 {
571 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
572 encoder.write_i32(self.partition_index);
573 encoder.write_i32(self.current_leader_epoch);
574 encoder.write_i64(self.fetch_offset);
575 encoder.write_i32(self.last_fetched_epoch);
576 encoder.write_i64(self.log_start_offset);
577 encoder.write_i32(self.max_bytes);
578 write_fetch_partition_v17_tags(encoder, self.replica_directory_id.as_ref(), None);
579 Ok(())
580 }
581}
582
583pub type FetchForgottenTopicV16 = FetchForgottenTopicV13;
584pub type FetchForgottenTopicV17 = FetchForgottenTopicV13;
585
586#[derive(Debug, Clone, PartialEq, Eq)]
587pub struct FetchTopicV18 {
588 pub topic_id: [u8; 16],
589 pub partitions: Vec<FetchPartitionV18>,
590}
591
592impl FetchTopicV18 {
593 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
594 encoder.write_uuid(&self.topic_id);
595 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
596 partition.encode(encoder)
597 })?;
598 encoder.write_empty_tagged_fields();
599 Ok(())
600 }
601}
602
603#[derive(Debug, Clone, PartialEq, Eq)]
604pub struct FetchPartitionV18 {
605 pub partition_index: i32,
606 pub current_leader_epoch: i32,
607 pub fetch_offset: i64,
608 pub last_fetched_epoch: i32,
609 pub log_start_offset: i64,
610 pub max_bytes: i32,
611 pub replica_directory_id: Option<[u8; 16]>,
612 pub high_watermark: Option<i64>,
613}
614
615impl FetchPartitionV18 {
616 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
617 encoder.write_i32(self.partition_index);
618 encoder.write_i32(self.current_leader_epoch);
619 encoder.write_i64(self.fetch_offset);
620 encoder.write_i32(self.last_fetched_epoch);
621 encoder.write_i64(self.log_start_offset);
622 encoder.write_i32(self.max_bytes);
623 write_fetch_partition_v17_tags(
624 encoder,
625 self.replica_directory_id.as_ref(),
626 self.high_watermark,
627 );
628 Ok(())
629 }
630}
631
632pub type FetchForgottenTopicV18 = FetchForgottenTopicV13;
633
634#[derive(Debug, Clone, PartialEq, Eq)]
635pub struct FetchForgottenTopicV13 {
636 pub topic_id: [u8; 16],
637 pub partitions: Vec<i32>,
638}
639
640impl FetchForgottenTopicV13 {
641 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
642 encoder.write_uuid(&self.topic_id);
643 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
644 encoder.write_i32(*partition);
645 Ok(())
646 })?;
647 encoder.write_empty_tagged_fields();
648 Ok(())
649 }
650}
651
652impl FetchForgottenTopicV12 {
653 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
654 encoder.write_compact_string(&self.name)?;
655 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
656 encoder.write_i32(*partition);
657 Ok(())
658 })?;
659 encoder.write_empty_tagged_fields();
660 Ok(())
661 }
662}
663
664impl FetchRequestV11 {
665 pub fn encode(&self) -> Result<Vec<u8>> {
666 let mut encoder = Encoder::new();
667 RequestHeader {
668 api_key: API_KEY,
669 api_version: 11,
670 correlation_id: self.correlation_id,
671 client_id: self.client_id.clone(),
672 }
673 .encode_v1(&mut encoder)?;
674 encoder.write_i32(self.replica_id);
675 encoder.write_i32(self.max_wait_ms);
676 encoder.write_i32(self.min_bytes);
677 encoder.write_i32(self.max_bytes);
678 encoder.write_i8(self.isolation_level);
679 encoder.write_i32(self.session_id);
680 encoder.write_i32(self.session_epoch);
681 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
682 topic.encode(encoder)
683 })?;
684 encoder.write_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
685 topic.encode(encoder)
686 })?;
687 encoder.write_string(&self.rack_id)?;
688 Ok(encoder.into_bytes())
689 }
690}
691
692#[derive(Debug, Clone, PartialEq, Eq)]
693pub struct FetchTopicV11 {
694 pub name: String,
695 pub partitions: Vec<FetchPartitionV11>,
696}
697
698impl FetchTopicV11 {
699 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
700 encoder.write_string(&self.name)?;
701 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
702 partition.encode(encoder)
703 })
704 }
705}
706
707#[derive(Debug, Clone, PartialEq, Eq)]
708pub struct FetchPartitionV11 {
709 pub partition_index: i32,
710 pub current_leader_epoch: i32,
711 pub fetch_offset: i64,
712 pub log_start_offset: i64,
713 pub max_bytes: i32,
714}
715
716impl FetchPartitionV11 {
717 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
718 encoder.write_i32(self.partition_index);
719 encoder.write_i32(self.current_leader_epoch);
720 encoder.write_i64(self.fetch_offset);
721 encoder.write_i64(self.log_start_offset);
722 encoder.write_i32(self.max_bytes);
723 Ok(())
724 }
725}
726
727#[derive(Debug, Clone, PartialEq, Eq)]
728pub struct FetchForgottenTopicV11 {
729 pub name: String,
730 pub partitions: Vec<i32>,
731}
732
733impl FetchForgottenTopicV11 {
734 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
735 encoder.write_string(&self.name)?;
736 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
737 encoder.write_i32(*partition);
738 Ok(())
739 })
740 }
741}
742
743impl FetchRequestV4 {
744 pub fn encode(&self) -> Result<Vec<u8>> {
745 let mut encoder = Encoder::new();
746 RequestHeader {
747 api_key: API_KEY,
748 api_version: 4,
749 correlation_id: self.correlation_id,
750 client_id: self.client_id.clone(),
751 }
752 .encode_v1(&mut encoder)?;
753 encoder.write_i32(self.replica_id);
754 encoder.write_i32(self.max_wait_ms);
755 encoder.write_i32(self.min_bytes);
756 encoder.write_i32(self.max_bytes);
757 encoder.write_i8(self.isolation_level);
758 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
759 topic.encode(encoder)
760 })?;
761 Ok(encoder.into_bytes())
762 }
763}
764
765impl FetchRequestV2 {
766 pub fn encode(&self) -> Result<Vec<u8>> {
767 let mut encoder = Encoder::new();
768 RequestHeader {
769 api_key: API_KEY,
770 api_version: 2,
771 correlation_id: self.correlation_id,
772 client_id: self.client_id.clone(),
773 }
774 .encode_v1(&mut encoder)?;
775 encoder.write_i32(self.replica_id);
776 encoder.write_i32(self.max_wait_ms);
777 encoder.write_i32(self.min_bytes);
778 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
779 topic.encode(encoder)
780 })?;
781 Ok(encoder.into_bytes())
782 }
783}
784
785#[derive(Debug, Clone, PartialEq, Eq)]
786pub struct FetchTopicV2 {
787 pub name: String,
788 pub partitions: Vec<FetchPartitionV2>,
789}
790
791impl FetchTopicV2 {
792 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
793 encoder.write_string(&self.name)?;
794 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
795 partition.encode(encoder)
796 })
797 }
798}
799
800#[derive(Debug, Clone, PartialEq, Eq)]
801pub struct FetchPartitionV2 {
802 pub partition_index: i32,
803 pub fetch_offset: i64,
804 pub max_bytes: i32,
805}
806
807impl FetchPartitionV2 {
808 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
809 encoder.write_i32(self.partition_index);
810 encoder.write_i64(self.fetch_offset);
811 encoder.write_i32(self.max_bytes);
812 Ok(())
813 }
814}
815
816#[derive(Debug, Clone, PartialEq, Eq)]
817pub struct FetchResponseV2 {
818 pub throttle_time_ms: i32,
819 pub responses: Vec<FetchTopicResponseV2>,
820}
821
822#[derive(Debug, Clone, PartialEq, Eq)]
823pub struct FetchResponseV4 {
824 pub throttle_time_ms: i32,
825 pub responses: Vec<FetchTopicResponseV4>,
826}
827
828#[derive(Debug, Clone, PartialEq, Eq)]
830pub struct FetchResponseV11 {
831 pub throttle_time_ms: i32,
832 pub error_code: i16,
833 pub session_id: i32,
834 pub responses: Vec<FetchTopicResponseV11>,
835}
836
837#[derive(Debug, Clone, PartialEq, Eq)]
839pub struct FetchResponseV12 {
840 pub throttle_time_ms: i32,
841 pub error_code: i16,
842 pub session_id: i32,
843 pub responses: Vec<FetchTopicResponseV12>,
844}
845
846#[derive(Debug, Clone, PartialEq, Eq)]
848pub struct FetchResponseV13 {
849 pub throttle_time_ms: i32,
850 pub error_code: i16,
851 pub session_id: i32,
852 pub responses: Vec<FetchTopicResponseV13>,
853}
854
855impl FetchResponseV12 {
856 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
857 Ok(Self {
858 throttle_time_ms: decoder.read_i32()?,
859 error_code: decoder.read_i16()?,
860 session_id: decoder.read_i32()?,
861 responses: decoder
862 .read_compact_array("fetch responses", FetchTopicResponseV12::decode)?
863 .unwrap_or_default(),
864 })
865 .and_then(|response| {
866 decoder.read_tagged_fields()?;
867 Ok(response)
868 })
869 }
870}
871
872impl FetchResponseV13 {
873 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
874 let response = Self {
875 throttle_time_ms: decoder.read_i32()?,
876 error_code: decoder.read_i16()?,
877 session_id: decoder.read_i32()?,
878 responses: decoder
879 .read_compact_array("fetch responses", FetchTopicResponseV13::decode)?
880 .unwrap_or_default(),
881 };
882 decoder.read_tagged_fields()?;
883 Ok(response)
884 }
885}
886
887#[derive(Debug, Clone, PartialEq, Eq)]
888pub struct FetchTopicResponseV13 {
889 pub topic_id: [u8; 16],
890 pub partitions: Vec<FetchPartitionResponseV13>,
891}
892
893impl FetchTopicResponseV13 {
894 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
895 let topic_id = decoder.read_uuid()?;
896 let partitions = decoder
897 .read_compact_array(
898 "fetch partition responses",
899 FetchPartitionResponseV13::decode,
900 )?
901 .unwrap_or_default();
902 decoder.read_tagged_fields()?;
903 Ok(Self {
904 topic_id,
905 partitions,
906 })
907 }
908}
909
910pub type FetchPartitionResponseV13 = FetchPartitionResponseV12;
911pub type FetchResponseV14 = FetchResponseV13;
912pub type FetchTopicResponseV14 = FetchTopicResponseV13;
913pub type FetchPartitionResponseV14 = FetchPartitionResponseV13;
914pub type FetchForgottenTopicV14 = FetchForgottenTopicV13;
915pub type FetchPartitionResponseV16 = FetchPartitionResponseV13;
916pub type FetchTopicResponseV16 = FetchTopicResponseV13;
917pub type FetchResponseV15 = FetchResponseV13;
918pub type FetchTopicResponseV15 = FetchTopicResponseV13;
919pub type FetchPartitionResponseV15 = FetchPartitionResponseV13;
920pub type FetchForgottenTopicV15 = FetchForgottenTopicV13;
921
922#[derive(Debug, Clone, PartialEq, Eq)]
924pub struct FetchNodeEndpointV16 {
925 pub node_id: i32,
926 pub host: String,
927 pub port: i32,
928 pub rack: Option<String>,
929}
930
931#[derive(Debug, Clone, PartialEq, Eq)]
933pub struct FetchResponseV16 {
934 pub throttle_time_ms: i32,
935 pub error_code: i16,
936 pub session_id: i32,
937 pub responses: Vec<FetchTopicResponseV16>,
938 pub node_endpoints: Vec<FetchNodeEndpointV16>,
939}
940
941impl FetchResponseV16 {
942 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
943 let response = Self {
944 throttle_time_ms: decoder.read_i32()?,
945 error_code: decoder.read_i16()?,
946 session_id: decoder.read_i32()?,
947 responses: decoder
948 .read_compact_array("fetch responses", FetchTopicResponseV16::decode)?
949 .unwrap_or_default(),
950 node_endpoints: Vec::new(),
951 };
952 let tagged_fields = decoder.read_tagged_fields()?;
953 let node_endpoints = tagged_fields
954 .into_iter()
955 .find(|field| field.tag == 0)
956 .map(|field| decode_fetch_node_endpoints(&field.data, decoder.limits()))
957 .transpose()?
958 .unwrap_or_default();
959 Ok(Self {
960 node_endpoints,
961 ..response
962 })
963 }
964}
965
966fn decode_fetch_node_endpoints(
967 data: &[u8],
968 limits: DecodeLimits,
969) -> Result<Vec<FetchNodeEndpointV16>> {
970 let mut decoder = Decoder::with_limits(data, limits);
971 Ok(decoder
972 .read_compact_array("fetch node endpoints", |decoder| {
973 let endpoint = FetchNodeEndpointV16 {
974 node_id: decoder.read_i32()?,
975 host: decoder.read_compact_string()?,
976 port: decoder.read_i32()?,
977 rack: decoder.read_compact_nullable_string()?,
978 };
979 decoder.read_tagged_fields()?;
980 Ok(endpoint)
981 })?
982 .unwrap_or_default())
983}
984
985pub type FetchResponseV17 = FetchResponseV16;
986pub type FetchTopicResponseV17 = FetchTopicResponseV16;
987pub type FetchPartitionResponseV17 = FetchPartitionResponseV16;
988pub type FetchResponseV18 = FetchResponseV17;
989pub type FetchTopicResponseV18 = FetchTopicResponseV17;
990pub type FetchPartitionResponseV18 = FetchPartitionResponseV17;
991
992#[derive(Debug, Clone, PartialEq, Eq)]
993pub struct FetchTopicResponseV12 {
994 pub name: String,
995 pub partitions: Vec<FetchPartitionResponseV12>,
996}
997
998impl FetchTopicResponseV12 {
999 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1000 let name = decoder.read_compact_string()?;
1001 let partitions = decoder
1002 .read_compact_array(
1003 "fetch partition responses",
1004 FetchPartitionResponseV12::decode,
1005 )?
1006 .unwrap_or_default();
1007 decoder.read_tagged_fields()?;
1008 Ok(Self { name, partitions })
1009 }
1010}
1011
1012#[derive(Debug, Clone, PartialEq, Eq)]
1013pub struct FetchPartitionResponseV12 {
1014 pub partition_index: i32,
1015 pub error_code: i16,
1016 pub high_watermark: i64,
1017 pub last_stable_offset: i64,
1018 pub log_start_offset: i64,
1019 pub aborted_transactions: Vec<AbortedTransactionV12>,
1020 pub preferred_read_replica: i32,
1021 pub records: Vec<MessageSetRecord>,
1022}
1023
1024impl FetchPartitionResponseV12 {
1025 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1026 let limits = decoder.limits();
1027 let partition_index = decoder.read_i32()?;
1028 let error_code = decoder.read_i16()?;
1029 let high_watermark = decoder.read_i64()?;
1030 let last_stable_offset = decoder.read_i64()?;
1031 let log_start_offset = decoder.read_i64()?;
1032 let aborted_transactions = decoder
1033 .read_compact_array("aborted transactions", AbortedTransactionV12::decode)?
1034 .unwrap_or_default();
1035 let preferred_read_replica = decoder.read_i32()?;
1036 let records = decoder
1037 .read_compact_nullable_bytes()?
1038 .map(|bytes| decode_message_set(&bytes, limits))
1039 .transpose()?
1040 .unwrap_or_default();
1041 decoder.read_tagged_fields()?;
1042 Ok(Self {
1043 partition_index,
1044 error_code,
1045 high_watermark,
1046 last_stable_offset,
1047 log_start_offset,
1048 aborted_transactions,
1049 preferred_read_replica,
1050 records,
1051 })
1052 }
1053}
1054
1055#[derive(Debug, Clone, PartialEq, Eq)]
1056pub struct AbortedTransactionV12 {
1057 pub producer_id: i64,
1058 pub first_offset: i64,
1059}
1060
1061impl AbortedTransactionV12 {
1062 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1063 let producer_id = decoder.read_i64()?;
1064 let first_offset = decoder.read_i64()?;
1065 decoder.read_tagged_fields()?;
1066 Ok(Self {
1067 producer_id,
1068 first_offset,
1069 })
1070 }
1071}
1072
1073impl FetchResponseV11 {
1074 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
1075 Ok(Self {
1076 throttle_time_ms: decoder.read_i32()?,
1077 error_code: decoder.read_i16()?,
1078 session_id: decoder.read_i32()?,
1079 responses: decoder
1080 .read_array("fetch responses", FetchTopicResponseV11::decode)?
1081 .unwrap_or_default(),
1082 })
1083 }
1084}
1085
1086#[derive(Debug, Clone, PartialEq, Eq)]
1087pub struct FetchTopicResponseV11 {
1088 pub name: String,
1089 pub partitions: Vec<FetchPartitionResponseV11>,
1090}
1091
1092impl FetchTopicResponseV11 {
1093 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1094 Ok(Self {
1095 name: decoder.read_string()?,
1096 partitions: decoder
1097 .read_array(
1098 "fetch partition responses",
1099 FetchPartitionResponseV11::decode,
1100 )?
1101 .unwrap_or_default(),
1102 })
1103 }
1104}
1105
1106#[derive(Debug, Clone, PartialEq, Eq)]
1107pub struct FetchPartitionResponseV11 {
1108 pub partition_index: i32,
1109 pub error_code: i16,
1110 pub high_watermark: i64,
1111 pub last_stable_offset: i64,
1112 pub log_start_offset: i64,
1113 pub aborted_transactions: Vec<AbortedTransactionV4>,
1114 pub preferred_read_replica: i32,
1115 pub records: Vec<MessageSetRecord>,
1116}
1117
1118impl FetchPartitionResponseV11 {
1119 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1120 let limits = decoder.limits();
1121 Ok(Self {
1122 partition_index: decoder.read_i32()?,
1123 error_code: decoder.read_i16()?,
1124 high_watermark: decoder.read_i64()?,
1125 last_stable_offset: decoder.read_i64()?,
1126 log_start_offset: decoder.read_i64()?,
1127 aborted_transactions: decoder
1128 .read_array("aborted transactions", AbortedTransactionV4::decode)?
1129 .unwrap_or_default(),
1130 preferred_read_replica: decoder.read_i32()?,
1131 records: decode_message_set(&decoder.read_bytes()?, limits)?,
1132 })
1133 }
1134}
1135
1136impl FetchResponseV4 {
1137 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
1138 Ok(Self {
1139 throttle_time_ms: decoder.read_i32()?,
1140 responses: decoder
1141 .read_array("fetch responses", FetchTopicResponseV4::decode)?
1142 .unwrap_or_default(),
1143 })
1144 }
1145}
1146
1147#[derive(Debug, Clone, PartialEq, Eq)]
1148pub struct FetchTopicResponseV4 {
1149 pub name: String,
1150 pub partitions: Vec<FetchPartitionResponseV4>,
1151}
1152
1153impl FetchTopicResponseV4 {
1154 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1155 Ok(Self {
1156 name: decoder.read_string()?,
1157 partitions: decoder
1158 .read_array(
1159 "fetch partition responses",
1160 FetchPartitionResponseV4::decode,
1161 )?
1162 .unwrap_or_default(),
1163 })
1164 }
1165}
1166
1167#[derive(Debug, Clone, PartialEq, Eq)]
1168pub struct FetchPartitionResponseV4 {
1169 pub partition_index: i32,
1170 pub error_code: i16,
1171 pub high_watermark: i64,
1172 pub last_stable_offset: i64,
1173 pub aborted_transactions: Vec<AbortedTransactionV4>,
1174 pub records: Vec<MessageSetRecord>,
1175}
1176
1177impl FetchPartitionResponseV4 {
1178 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1179 let limits = decoder.limits();
1180 Ok(Self {
1181 partition_index: decoder.read_i32()?,
1182 error_code: decoder.read_i16()?,
1183 high_watermark: decoder.read_i64()?,
1184 last_stable_offset: decoder.read_i64()?,
1185 aborted_transactions: decoder
1186 .read_array("aborted transactions", AbortedTransactionV4::decode)?
1187 .unwrap_or_default(),
1188 records: decode_message_set(&decoder.read_bytes()?, limits)?,
1189 })
1190 }
1191}
1192
1193#[derive(Debug, Clone, PartialEq, Eq)]
1194pub struct AbortedTransactionV4 {
1195 pub producer_id: i64,
1196 pub first_offset: i64,
1197}
1198
1199impl AbortedTransactionV4 {
1200 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1201 Ok(Self {
1202 producer_id: decoder.read_i64()?,
1203 first_offset: decoder.read_i64()?,
1204 })
1205 }
1206}
1207
1208impl FetchResponseV2 {
1209 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
1210 Ok(Self {
1211 throttle_time_ms: decoder.read_i32()?,
1212 responses: decoder
1213 .read_array("fetch responses", FetchTopicResponseV2::decode)?
1214 .unwrap_or_default(),
1215 })
1216 }
1217}
1218
1219#[derive(Debug, Clone, PartialEq, Eq)]
1220pub struct FetchTopicResponseV2 {
1221 pub name: String,
1222 pub partitions: Vec<FetchPartitionResponseV2>,
1223}
1224
1225impl FetchTopicResponseV2 {
1226 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1227 Ok(Self {
1228 name: decoder.read_string()?,
1229 partitions: decoder
1230 .read_array(
1231 "fetch partition responses",
1232 FetchPartitionResponseV2::decode,
1233 )?
1234 .unwrap_or_default(),
1235 })
1236 }
1237}
1238
1239#[derive(Debug, Clone, PartialEq, Eq)]
1240pub struct FetchPartitionResponseV2 {
1241 pub partition_index: i32,
1242 pub error_code: i16,
1243 pub high_watermark: i64,
1244 pub records: Vec<MessageSetRecord>,
1245}
1246
1247impl FetchPartitionResponseV2 {
1248 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
1249 let limits = decoder.limits();
1250 Ok(Self {
1251 partition_index: decoder.read_i32()?,
1252 error_code: decoder.read_i16()?,
1253 high_watermark: decoder.read_i64()?,
1254 records: decode_message_set(&decoder.read_bytes()?, limits)?,
1255 })
1256 }
1257}
1258
1259#[derive(Debug, Clone, PartialEq, Eq)]
1260pub struct MessageSetRecord {
1261 pub offset: i64,
1262 pub leader_epoch: i32,
1265 pub timestamp_ms: i64,
1266 pub key: Option<Vec<u8>>,
1267 pub value: Option<Vec<u8>>,
1268 pub headers: Vec<RecordBatchHeader>,
1269 pub producer_id: Option<i64>,
1270 pub transactional: bool,
1271 pub control: bool,
1272}
1273
1274pub fn decode_message_set(bytes: &[u8], limits: DecodeLimits) -> Result<Vec<MessageSetRecord>> {
1281 let mut decoder = Decoder::with_limits(bytes, limits);
1282 let mut records = Vec::new();
1283
1284 while decoder.remaining() >= 12 {
1285 let offset = decoder.read_i64()?;
1286 let message_size = decoder.read_i32()?;
1287 if message_size < 0 {
1288 return Err(Error::NegativeLength {
1289 kind: "message",
1290 length: message_size,
1291 });
1292 }
1293 let message_size =
1294 usize::try_from(message_size).map_err(|_| Error::LengthOverflow("message"))?;
1295 if decoder.remaining() < message_size {
1297 break;
1298 }
1299 let message = decoder.read_exact(message_size)?;
1300 let decoded = decode_message_or_batch(offset, message, limits)?;
1301 let total = records
1302 .len()
1303 .checked_add(decoded.len())
1304 .ok_or(Error::LengthOverflow("fetch records"))?;
1305 decoder.ensure_collection_length("fetch records", total)?;
1306 records.extend(decoded);
1307 }
1308
1309 Ok(records)
1310}
1311
1312fn decode_message_or_batch(
1313 offset: i64,
1314 bytes: &[u8],
1315 limits: DecodeLimits,
1316) -> Result<Vec<MessageSetRecord>> {
1317 match bytes.get(4).copied() {
1318 Some(2) => decode_record_batch(offset, bytes, limits),
1319 _ => Ok(vec![decode_message(offset, bytes, limits)?]),
1320 }
1321}
1322
1323fn decode_message(offset: i64, bytes: &[u8], limits: DecodeLimits) -> Result<MessageSetRecord> {
1324 let mut decoder = Decoder::with_limits(bytes, limits);
1325 let _crc = decoder.read_i32()?;
1326 let magic = decoder.read_i8()?;
1327 let _attributes = decoder.read_i8()?;
1328 let timestamp_ms = match magic {
1329 0 => -1,
1330 1 => decoder.read_i64()?,
1331 _ => {
1332 return Err(Error::UnsupportedVersion {
1333 kind: "message magic",
1334 version: i16::from(magic),
1335 })
1336 }
1337 };
1338 let key = decoder.read_nullable_bytes()?;
1339 let value = decoder.read_nullable_bytes()?;
1340
1341 Ok(MessageSetRecord {
1342 offset,
1343 leader_epoch: -1,
1344 timestamp_ms,
1345 key,
1346 value,
1347 headers: Vec::new(),
1348 producer_id: None,
1349 transactional: false,
1350 control: false,
1351 })
1352}
1353
1354fn decode_record_batch(
1355 base_offset: i64,
1356 bytes: &[u8],
1357 limits: DecodeLimits,
1358) -> Result<Vec<MessageSetRecord>> {
1359 let mut decoder = Decoder::with_limits(bytes, limits);
1360 let partition_leader_epoch = decoder.read_i32()?;
1361 let magic = decoder.read_i8()?;
1362 if magic != 2 {
1363 return Err(Error::UnsupportedVersion {
1364 kind: "record batch magic",
1365 version: i16::from(magic),
1366 });
1367 }
1368 let _crc = decoder.read_i32()?;
1369 let attributes = decoder.read_i16()?;
1370 let compression = RecordBatchCompression::from_attributes(attributes)?;
1371 let _last_offset_delta = decoder.read_i32()?;
1372 let base_timestamp = decoder.read_i64()?;
1373 let _max_timestamp = decoder.read_i64()?;
1374 let producer_id = decoder.read_i64()?;
1375 let _producer_epoch = decoder.read_i16()?;
1376 let _base_sequence = decoder.read_i32()?;
1377 let record_count = decoder.read_i32()?;
1378 if record_count < 0 {
1379 return Err(Error::NegativeLength {
1380 kind: "record batch records",
1381 length: record_count,
1382 });
1383 }
1384
1385 let record_count =
1386 usize::try_from(record_count).map_err(|_| Error::LengthOverflow("record batch records"))?;
1387 decoder.ensure_collection_length("record batch records", record_count)?;
1388 let record_bytes = if compression.is_compressed() {
1389 let compressed = decoder.read_exact(decoder.remaining())?;
1390 decompress_record_batch_records_with_limit(
1391 compression,
1392 compressed,
1393 limits.max_decompressed_record_bytes(),
1394 )?
1395 } else {
1396 if decoder.remaining() > limits.max_decompressed_record_bytes() {
1397 return Err(Error::LimitExceeded {
1398 kind: "decompressed record batch bytes",
1399 actual: decoder.remaining(),
1400 max: limits.max_decompressed_record_bytes(),
1401 });
1402 }
1403 decoder.read_exact(decoder.remaining())?.to_vec()
1404 };
1405 let mut record_decoder = Decoder::with_limits(&record_bytes, limits);
1406 let mut records = Vec::with_capacity(record_count);
1407 for _ in 0..record_count {
1408 let record_length = record_decoder.read_varint()?;
1409 if record_length < 0 {
1410 return Err(Error::NegativeLength {
1411 kind: "record",
1412 length: record_length,
1413 });
1414 }
1415 let record_length =
1416 usize::try_from(record_length).map_err(|_| Error::LengthOverflow("record"))?;
1417 let record_bytes = record_decoder.read_exact(record_length)?;
1418 records.push(decode_record(
1419 base_offset,
1420 partition_leader_epoch,
1421 base_timestamp,
1422 producer_id,
1423 attributes,
1424 record_bytes,
1425 limits,
1426 )?);
1427 }
1428
1429 Ok(records)
1430}
1431
1432fn decode_record(
1433 base_offset: i64,
1434 partition_leader_epoch: i32,
1435 base_timestamp: i64,
1436 producer_id: i64,
1437 batch_attributes: i16,
1438 bytes: &[u8],
1439 limits: DecodeLimits,
1440) -> Result<MessageSetRecord> {
1441 let mut decoder = Decoder::with_limits(bytes, limits);
1442 let _attributes = decoder.read_i8()?;
1443 let timestamp_delta = decoder.read_varlong()?;
1444 let offset_delta = decoder.read_varint()?;
1445 let key = decoder.read_varint_nullable_bytes()?;
1446 let value = decoder.read_varint_nullable_bytes()?;
1447 let header_count = decoder.read_varint()?;
1448 if header_count < 0 {
1449 return Err(Error::NegativeLength {
1450 kind: "record headers",
1451 length: header_count,
1452 });
1453 }
1454 let header_count =
1455 usize::try_from(header_count).map_err(|_| Error::LengthOverflow("record headers"))?;
1456 decoder.ensure_collection_length("record headers", header_count)?;
1457 let mut headers = Vec::with_capacity(header_count);
1458 for _ in 0..header_count {
1459 let header_key =
1460 String::from_utf8(decoder.read_varint_bytes()?).map_err(|_| Error::InvalidUtf8)?;
1461 let header_value = decoder.read_varint_nullable_bytes()?;
1462 headers.push(RecordBatchHeader::new(header_key, header_value));
1463 }
1464
1465 Ok(MessageSetRecord {
1466 offset: base_offset.saturating_add(i64::from(offset_delta)),
1467 leader_epoch: partition_leader_epoch,
1468 timestamp_ms: base_timestamp.saturating_add(timestamp_delta),
1469 key,
1470 value,
1471 headers,
1472 producer_id: (producer_id >= 0).then_some(producer_id),
1473 transactional: batch_attributes & 0x10 != 0,
1474 control: batch_attributes & 0x20 != 0,
1475 })
1476}
1477
1478#[cfg(test)]
1479#[allow(clippy::unwrap_used)]
1480mod tests {
1481 use super::{
1482 FetchPartitionV11, FetchPartitionV12, FetchPartitionV17, FetchPartitionV18,
1483 FetchPartitionV2, FetchReplicaStateV15, FetchRequestV11, FetchRequestV12, FetchRequestV13,
1484 FetchRequestV14, FetchRequestV15, FetchRequestV16, FetchRequestV17, FetchRequestV18,
1485 FetchRequestV2, FetchRequestV4, FetchResponseV11, FetchResponseV12, FetchResponseV13,
1486 FetchResponseV16, FetchResponseV2, FetchResponseV4, FetchTopicV11, FetchTopicV12,
1487 FetchTopicV13, FetchTopicV17, FetchTopicV18, FetchTopicV2, MessageSetRecord,
1488 RecordBatchHeader,
1489 };
1490 use crate::codec::{Decoder, Encoder};
1491
1492 #[test]
1493 fn encodes_fetch_request_v2() {
1494 let request = FetchRequestV2 {
1495 correlation_id: 7,
1496 client_id: Some("kafrust".to_owned()),
1497 replica_id: -1,
1498 max_wait_ms: 500,
1499 min_bytes: 1,
1500 topics: vec![FetchTopicV2 {
1501 name: "orders".to_owned(),
1502 partitions: vec![FetchPartitionV2 {
1503 partition_index: 0,
1504 fetch_offset: 42,
1505 max_bytes: 1_048_576,
1506 }],
1507 }],
1508 };
1509
1510 let bytes = request.encode().unwrap();
1511 assert_eq!(&bytes[0..4], &[0, 1, 0, 2]);
1512 assert!(bytes.len() > 40);
1513 }
1514
1515 #[test]
1516 fn encodes_fetch_request_v4() {
1517 let request = FetchRequestV4 {
1518 correlation_id: 8,
1519 client_id: Some("kafrust".to_owned()),
1520 replica_id: -1,
1521 max_wait_ms: 500,
1522 min_bytes: 1,
1523 max_bytes: 1_048_576,
1524 isolation_level: 0,
1525 topics: vec![FetchTopicV2 {
1526 name: "orders".to_owned(),
1527 partitions: vec![FetchPartitionV2 {
1528 partition_index: 0,
1529 fetch_offset: 42,
1530 max_bytes: 1_048_576,
1531 }],
1532 }],
1533 };
1534
1535 let bytes = request.encode().unwrap();
1536 assert_eq!(&bytes[0..4], &[0, 1, 0, 4]);
1537 assert_eq!(&bytes[4..8], &[0, 0, 0, 8]);
1538 assert!(bytes.len() > 45);
1539 }
1540
1541 #[test]
1542 fn encodes_fetch_request_v11_with_rack_and_fetch_session_fields() {
1543 let request = FetchRequestV11 {
1544 correlation_id: 9,
1545 client_id: Some("kafrust".to_owned()),
1546 replica_id: -1,
1547 max_wait_ms: 500,
1548 min_bytes: 1,
1549 max_bytes: 1_048_576,
1550 isolation_level: 1,
1551 session_id: 0,
1552 session_epoch: 0,
1553 topics: vec![FetchTopicV11 {
1554 name: "orders".to_owned(),
1555 partitions: vec![FetchPartitionV11 {
1556 partition_index: 0,
1557 current_leader_epoch: -1,
1558 fetch_offset: 42,
1559 log_start_offset: -1,
1560 max_bytes: 1_048_576,
1561 }],
1562 }],
1563 forgotten_topics: Vec::new(),
1564 rack_id: "rack-a".to_owned(),
1565 };
1566
1567 let bytes = request.encode().unwrap();
1568 let mut decoder = Decoder::new(&bytes);
1569 assert_eq!(decoder.read_i16().unwrap(), 1);
1570 assert_eq!(decoder.read_i16().unwrap(), 11);
1571 assert_eq!(decoder.read_i32().unwrap(), 9);
1572 assert_eq!(
1573 decoder.read_nullable_string().unwrap().as_deref(),
1574 Some("kafrust")
1575 );
1576 assert_eq!(decoder.read_i32().unwrap(), -1);
1577 assert_eq!(decoder.read_i32().unwrap(), 500);
1578 assert_eq!(decoder.read_i32().unwrap(), 1);
1579 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1580 assert_eq!(decoder.read_i8().unwrap(), 1);
1581 assert_eq!(decoder.read_i32().unwrap(), 0);
1582 assert_eq!(decoder.read_i32().unwrap(), 0);
1583 assert_eq!(decoder.read_i32().unwrap(), 1);
1584 assert_eq!(decoder.read_string().unwrap(), "orders");
1585 assert_eq!(decoder.read_i32().unwrap(), 1);
1586 assert_eq!(decoder.read_i32().unwrap(), 0);
1587 assert_eq!(decoder.read_i32().unwrap(), -1);
1588 assert_eq!(decoder.read_i64().unwrap(), 42);
1589 assert_eq!(decoder.read_i64().unwrap(), -1);
1590 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1591 assert_eq!(decoder.read_i32().unwrap(), 0);
1592 assert_eq!(decoder.read_string().unwrap(), "rack-a");
1593 assert!(decoder.is_empty());
1594 }
1595
1596 #[test]
1597 fn decodes_fetch_response_v11_with_preferred_read_replica() {
1598 let mut bytes = Encoder::new();
1599 bytes.write_i32(3);
1600 bytes.write_i16(0);
1601 bytes.write_i32(17);
1602 bytes.write_i32(1);
1603 bytes.write_string("orders").unwrap();
1604 bytes.write_i32(1);
1605 bytes.write_i32(0);
1606 bytes.write_i16(0);
1607 bytes.write_i64(43);
1608 bytes.write_i64(42);
1609 bytes.write_i64(40);
1610 bytes.write_i32(0);
1611 bytes.write_i32(2);
1612 bytes.write_bytes(&[]).unwrap();
1613
1614 let bytes = bytes.into_bytes();
1615 let mut decoder = Decoder::new(&bytes);
1616 let response = FetchResponseV11::decode_body(&mut decoder).unwrap();
1617 let partition = &response.responses[0].partitions[0];
1618
1619 assert_eq!(response.throttle_time_ms, 3);
1620 assert_eq!(response.session_id, 17);
1621 assert_eq!(partition.log_start_offset, 40);
1622 assert_eq!(partition.preferred_read_replica, 2);
1623 assert!(partition.records.is_empty());
1624 assert!(decoder.is_empty());
1625 }
1626
1627 #[test]
1628 fn encodes_fetch_request_v12_with_flexible_rack_fields() {
1629 let request = FetchRequestV12 {
1630 correlation_id: 10,
1631 client_id: Some("kafrust".to_owned()),
1632 replica_id: -1,
1633 max_wait_ms: 500,
1634 min_bytes: 1,
1635 max_bytes: 1_048_576,
1636 isolation_level: 1,
1637 session_id: 0,
1638 session_epoch: 0,
1639 topics: vec![FetchTopicV12 {
1640 name: "orders".to_owned(),
1641 partitions: vec![FetchPartitionV12 {
1642 partition_index: 0,
1643 current_leader_epoch: -1,
1644 fetch_offset: 42,
1645 last_fetched_epoch: -1,
1646 log_start_offset: -1,
1647 max_bytes: 1_048_576,
1648 }],
1649 }],
1650 forgotten_topics: Vec::new(),
1651 rack_id: "rack-a".to_owned(),
1652 };
1653
1654 let bytes = request.encode().unwrap();
1655 let mut decoder = Decoder::new(&bytes);
1656 assert_eq!(decoder.read_i16().unwrap(), 1);
1657 assert_eq!(decoder.read_i16().unwrap(), 12);
1658 assert_eq!(decoder.read_i32().unwrap(), 10);
1659 assert_eq!(
1660 decoder.read_nullable_string().unwrap().as_deref(),
1661 Some("kafrust")
1662 );
1663 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1664 assert_eq!(decoder.read_i32().unwrap(), -1);
1665 assert_eq!(decoder.read_i32().unwrap(), 500);
1666 assert_eq!(decoder.read_i32().unwrap(), 1);
1667 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1668 assert_eq!(decoder.read_i8().unwrap(), 1);
1669 assert_eq!(decoder.read_i32().unwrap(), 0);
1670 assert_eq!(decoder.read_i32().unwrap(), 0);
1671 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1672 assert_eq!(decoder.read_compact_string().unwrap(), "orders");
1673 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1674 assert_eq!(decoder.read_i32().unwrap(), 0);
1675 assert_eq!(decoder.read_i32().unwrap(), -1);
1676 assert_eq!(decoder.read_i64().unwrap(), 42);
1677 assert_eq!(decoder.read_i32().unwrap(), -1);
1678 assert_eq!(decoder.read_i64().unwrap(), -1);
1679 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1680 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1681 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1682 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1683 assert_eq!(decoder.read_compact_string().unwrap(), "rack-a");
1684 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1685 assert!(decoder.is_empty());
1686 }
1687
1688 #[test]
1689 fn decodes_fetch_response_v12_with_preferred_read_replica() {
1690 let mut bytes = Encoder::new();
1691 bytes.write_i32(3);
1692 bytes.write_i16(0);
1693 bytes.write_i32(17);
1694 bytes.write_unsigned_varint(2);
1695 bytes.write_compact_string("orders").unwrap();
1696 bytes.write_unsigned_varint(2);
1697 bytes.write_i32(0);
1698 bytes.write_i16(0);
1699 bytes.write_i64(43);
1700 bytes.write_i64(42);
1701 bytes.write_i64(40);
1702 bytes.write_unsigned_varint(2);
1703 bytes.write_i64(7);
1704 bytes.write_i64(40);
1705 bytes.write_unsigned_varint(0);
1706 bytes.write_i32(2);
1707 bytes.write_compact_nullable_bytes(Some(&[])).unwrap();
1708 bytes.write_unsigned_varint(0);
1709 bytes.write_unsigned_varint(0);
1710 bytes.write_unsigned_varint(0);
1711
1712 let bytes = bytes.into_bytes();
1713 let mut decoder = Decoder::new(&bytes);
1714 let response = FetchResponseV12::decode_body(&mut decoder).unwrap();
1715 let partition = &response.responses[0].partitions[0];
1716
1717 assert_eq!(response.throttle_time_ms, 3);
1718 assert_eq!(response.session_id, 17);
1719 assert_eq!(partition.log_start_offset, 40);
1720 assert_eq!(partition.preferred_read_replica, 2);
1721 assert_eq!(partition.aborted_transactions[0].producer_id, 7);
1722 assert!(partition.records.is_empty());
1723 assert!(decoder.is_empty());
1724 }
1725
1726 #[test]
1727 fn encodes_fetch_request_v13_with_topic_uuid_and_cluster_tag() {
1728 let request = FetchRequestV13 {
1729 correlation_id: 11,
1730 client_id: Some("kafrust".to_owned()),
1731 cluster_id: Some("cluster-a".to_owned()),
1732 replica_id: -1,
1733 max_wait_ms: 500,
1734 min_bytes: 1,
1735 max_bytes: 1_048_576,
1736 isolation_level: 1,
1737 session_id: 17,
1738 session_epoch: 2,
1739 topics: vec![FetchTopicV13 {
1740 topic_id: [3; 16],
1741 partitions: vec![FetchPartitionV12 {
1742 partition_index: 0,
1743 current_leader_epoch: 4,
1744 fetch_offset: 42,
1745 last_fetched_epoch: 3,
1746 log_start_offset: -1,
1747 max_bytes: 1_048_576,
1748 }],
1749 }],
1750 forgotten_topics: Vec::new(),
1751 rack_id: "rack-a".to_owned(),
1752 };
1753
1754 let bytes = request.encode().unwrap();
1755 let mut decoder = Decoder::new(&bytes);
1756 assert_eq!(decoder.read_i16().unwrap(), 1);
1757 assert_eq!(decoder.read_i16().unwrap(), 13);
1758 assert_eq!(decoder.read_i32().unwrap(), 11);
1759 assert_eq!(
1760 decoder.read_nullable_string().unwrap().as_deref(),
1761 Some("kafrust")
1762 );
1763 assert!(decoder.read_tagged_fields().unwrap().is_empty());
1764 assert_eq!(decoder.read_i32().unwrap(), -1);
1765 assert_eq!(decoder.read_i32().unwrap(), 500);
1766 assert_eq!(decoder.read_i32().unwrap(), 1);
1767 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1768 assert_eq!(decoder.read_i8().unwrap(), 1);
1769 assert_eq!(decoder.read_i32().unwrap(), 17);
1770 assert_eq!(decoder.read_i32().unwrap(), 2);
1771 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1772 assert_eq!(decoder.read_uuid().unwrap(), [3; 16]);
1773 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1774 assert_eq!(decoder.read_i32().unwrap(), 0);
1775 assert_eq!(decoder.read_i32().unwrap(), 4);
1776 assert_eq!(decoder.read_i64().unwrap(), 42);
1777 assert_eq!(decoder.read_i32().unwrap(), 3);
1778 assert_eq!(decoder.read_i64().unwrap(), -1);
1779 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1780 assert!(decoder.read_tagged_fields().unwrap().is_empty());
1781 assert!(decoder.read_tagged_fields().unwrap().is_empty());
1782 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1783 assert_eq!(decoder.read_compact_string().unwrap(), "rack-a");
1784 let fields = decoder.read_tagged_fields().unwrap();
1785 assert_eq!(fields.len(), 1);
1786 let mut cluster_decoder = Decoder::new(&fields[0].data);
1787 assert_eq!(fields[0].tag, 0);
1788 assert_eq!(cluster_decoder.read_compact_string().unwrap(), "cluster-a");
1789 assert!(cluster_decoder.is_empty());
1790 assert!(decoder.is_empty());
1791 }
1792
1793 #[test]
1794 fn decodes_fetch_response_v13_with_topic_uuid() {
1795 let mut bytes = Encoder::new();
1796 bytes.write_i32(3);
1797 bytes.write_i16(0);
1798 bytes.write_i32(17);
1799 bytes.write_unsigned_varint(2);
1800 bytes.write_uuid(&[4; 16]);
1801 bytes.write_unsigned_varint(2);
1802 bytes.write_i32(0);
1803 bytes.write_i16(0);
1804 bytes.write_i64(43);
1805 bytes.write_i64(42);
1806 bytes.write_i64(40);
1807 bytes.write_unsigned_varint(1);
1808 bytes.write_i32(2);
1809 bytes.write_compact_nullable_bytes(Some(&[])).unwrap();
1810 bytes.write_empty_tagged_fields();
1811 bytes.write_empty_tagged_fields();
1812 bytes.write_empty_tagged_fields();
1813
1814 let bytes = bytes.into_bytes();
1815 let mut decoder = Decoder::new(&bytes);
1816 let response = FetchResponseV13::decode_body(&mut decoder).unwrap();
1817 let partition = &response.responses[0].partitions[0];
1818
1819 assert_eq!(response.session_id, 17);
1820 assert_eq!(response.responses[0].topic_id, [4; 16]);
1821 assert_eq!(partition.high_watermark, 43);
1822 assert_eq!(partition.preferred_read_replica, 2);
1823 assert!(partition.records.is_empty());
1824 assert!(decoder.is_empty());
1825 }
1826
1827 #[test]
1828 fn decodes_fetch_response_v16_node_endpoints_tag() {
1829 let mut endpoint = Encoder::new();
1830 endpoint.write_unsigned_varint(2);
1831 endpoint.write_i32(3);
1832 endpoint.write_compact_string("broker-a").unwrap();
1833 endpoint.write_i32(9092);
1834 endpoint
1835 .write_compact_nullable_string(Some("rack-a"))
1836 .unwrap();
1837 endpoint.write_empty_tagged_fields();
1838 let endpoint = endpoint.into_bytes();
1839
1840 let mut bytes = Encoder::new();
1841 bytes.write_i32(3);
1842 bytes.write_i16(0);
1843 bytes.write_i32(17);
1844 bytes.write_unsigned_varint(1);
1845 bytes.write_unsigned_varint(1);
1846 bytes.write_unsigned_varint(0);
1847 bytes.write_unsigned_varint(endpoint.len() as u32);
1848 bytes.write_raw(&endpoint);
1849
1850 let bytes = bytes.into_bytes();
1851 let mut decoder = Decoder::new(&bytes);
1852 let response = FetchResponseV16::decode_body(&mut decoder).unwrap();
1853 assert_eq!(response.node_endpoints.len(), 1);
1854 assert_eq!(response.node_endpoints[0].node_id, 3);
1855 assert_eq!(response.node_endpoints[0].host, "broker-a");
1856 assert_eq!(response.node_endpoints[0].port, 9092);
1857 assert_eq!(response.node_endpoints[0].rack.as_deref(), Some("rack-a"));
1858 assert!(decoder.is_empty());
1859 }
1860
1861 #[test]
1862 fn encodes_fetch_request_v14_with_the_v14_header_version() {
1863 let request = FetchRequestV14 {
1864 correlation_id: 12,
1865 client_id: None,
1866 cluster_id: None,
1867 replica_id: -1,
1868 max_wait_ms: 500,
1869 min_bytes: 1,
1870 max_bytes: 1_048_576,
1871 isolation_level: 0,
1872 session_id: 0,
1873 session_epoch: -1,
1874 topics: Vec::new(),
1875 forgotten_topics: Vec::new(),
1876 rack_id: String::new(),
1877 };
1878
1879 let bytes = request.encode().unwrap();
1880 assert_eq!(&bytes[0..4], &[0, 1, 0, 14]);
1881 let mut decoder = Decoder::new(&bytes);
1882 decoder.read_i16().unwrap();
1883 decoder.read_i16().unwrap();
1884 decoder.read_i32().unwrap();
1885 decoder.read_nullable_string().unwrap();
1886 assert!(decoder.read_tagged_fields().unwrap().is_empty());
1887 assert_eq!(decoder.read_i32().unwrap(), -1);
1888 assert_eq!(decoder.read_i32().unwrap(), 500);
1889 assert_eq!(decoder.read_i32().unwrap(), 1);
1890 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1891 assert_eq!(decoder.read_i8().unwrap(), 0);
1892 assert_eq!(decoder.read_i32().unwrap(), 0);
1893 assert_eq!(decoder.read_i32().unwrap(), -1);
1894 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1895 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1896 assert!(decoder.read_compact_string().unwrap().is_empty());
1897 assert!(decoder.read_tagged_fields().unwrap().is_empty());
1898 assert!(decoder.is_empty());
1899 }
1900
1901 #[test]
1902 fn encodes_fetch_request_v15_replica_state_as_tagged_struct() {
1903 let request = FetchRequestV15 {
1904 correlation_id: 13,
1905 client_id: Some("kafrust".to_owned()),
1906 cluster_id: Some("cluster-a".to_owned()),
1907 replica_state: Some(FetchReplicaStateV15 {
1908 replica_id: 4,
1909 replica_epoch: 9,
1910 }),
1911 max_wait_ms: 500,
1912 min_bytes: 1,
1913 max_bytes: 1_048_576,
1914 isolation_level: 0,
1915 session_id: 0,
1916 session_epoch: -1,
1917 topics: Vec::new(),
1918 forgotten_topics: Vec::new(),
1919 rack_id: String::new(),
1920 };
1921
1922 let bytes = request.encode().unwrap();
1923 let mut decoder = Decoder::new(&bytes);
1924 assert_eq!(decoder.read_i16().unwrap(), 1);
1925 assert_eq!(decoder.read_i16().unwrap(), 15);
1926 assert_eq!(decoder.read_i32().unwrap(), 13);
1927 assert_eq!(
1928 decoder.read_nullable_string().unwrap().as_deref(),
1929 Some("kafrust")
1930 );
1931 assert!(decoder.read_tagged_fields().unwrap().is_empty());
1932 assert_eq!(decoder.read_i32().unwrap(), 500);
1933 assert_eq!(decoder.read_i32().unwrap(), 1);
1934 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1935 assert_eq!(decoder.read_i8().unwrap(), 0);
1936 assert_eq!(decoder.read_i32().unwrap(), 0);
1937 assert_eq!(decoder.read_i32().unwrap(), -1);
1938 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1939 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1940 assert!(decoder.read_compact_string().unwrap().is_empty());
1941 let fields = decoder.read_tagged_fields().unwrap();
1942 assert_eq!(fields.len(), 2);
1943 assert_eq!(fields[0].tag, 0);
1944 assert_eq!(fields[1].tag, 1);
1945 let mut cluster_decoder = Decoder::new(&fields[0].data);
1946 assert_eq!(cluster_decoder.read_compact_string().unwrap(), "cluster-a");
1947 let mut replica_decoder = Decoder::new(&fields[1].data);
1948 assert_eq!(replica_decoder.read_i32().unwrap(), 4);
1949 assert_eq!(replica_decoder.read_i64().unwrap(), 9);
1950 assert!(decoder.is_empty());
1951 }
1952
1953 #[test]
1954 fn encodes_fetch_request_v16_with_the_v16_header_version() {
1955 let request = FetchRequestV16 {
1956 correlation_id: 14,
1957 client_id: None,
1958 cluster_id: None,
1959 replica_state: None,
1960 max_wait_ms: 500,
1961 min_bytes: 1,
1962 max_bytes: 1_048_576,
1963 isolation_level: 0,
1964 session_id: 0,
1965 session_epoch: -1,
1966 topics: Vec::new(),
1967 forgotten_topics: Vec::new(),
1968 rack_id: String::new(),
1969 };
1970
1971 let bytes = request.encode().unwrap();
1972 assert_eq!(&bytes[0..4], &[0, 1, 0, 16]);
1973 }
1974
1975 #[test]
1976 fn encodes_fetch_request_v17_directory_id_as_partition_tag() {
1977 let request = FetchRequestV17 {
1978 correlation_id: 15,
1979 client_id: None,
1980 cluster_id: None,
1981 replica_state: None,
1982 max_wait_ms: 500,
1983 min_bytes: 1,
1984 max_bytes: 1_048_576,
1985 isolation_level: 0,
1986 session_id: 0,
1987 session_epoch: -1,
1988 topics: vec![FetchTopicV17 {
1989 topic_id: [7; 16],
1990 partitions: vec![FetchPartitionV17 {
1991 partition_index: 0,
1992 current_leader_epoch: -1,
1993 fetch_offset: 42,
1994 last_fetched_epoch: -1,
1995 log_start_offset: -1,
1996 max_bytes: 1_048_576,
1997 replica_directory_id: Some([8; 16]),
1998 }],
1999 }],
2000 forgotten_topics: Vec::new(),
2001 rack_id: String::new(),
2002 };
2003
2004 let bytes = request.encode().unwrap();
2005 let mut decoder = Decoder::new(&bytes);
2006 assert_eq!(decoder.read_i16().unwrap(), 1);
2007 assert_eq!(decoder.read_i16().unwrap(), 17);
2008 decoder.read_i32().unwrap();
2009 decoder.read_nullable_string().unwrap();
2010 assert!(decoder.read_tagged_fields().unwrap().is_empty());
2011 for _ in 0..3 {
2012 decoder.read_i32().unwrap();
2013 }
2014 decoder.read_i8().unwrap();
2015 decoder.read_i32().unwrap();
2016 decoder.read_i32().unwrap();
2017 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
2018 assert_eq!(decoder.read_uuid().unwrap(), [7; 16]);
2019 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
2020 decoder.read_i32().unwrap();
2021 decoder.read_i32().unwrap();
2022 decoder.read_i64().unwrap();
2023 decoder.read_i32().unwrap();
2024 decoder.read_i64().unwrap();
2025 decoder.read_i32().unwrap();
2026 let fields = decoder.read_tagged_fields().unwrap();
2027 assert_eq!(fields.len(), 1);
2028 assert_eq!(fields[0].tag, 0);
2029 assert_eq!(fields[0].data, vec![8; 16]);
2030 assert!(decoder.read_tagged_fields().unwrap().is_empty());
2031 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
2032 assert!(decoder.read_compact_string().unwrap().is_empty());
2033 assert!(decoder.read_tagged_fields().unwrap().is_empty());
2034 assert!(decoder.is_empty());
2035 }
2036
2037 #[test]
2038 fn encodes_fetch_request_v18_high_watermark_after_directory_id() {
2039 let request = FetchRequestV18 {
2040 correlation_id: 16,
2041 client_id: None,
2042 cluster_id: None,
2043 replica_state: None,
2044 max_wait_ms: 500,
2045 min_bytes: 1,
2046 max_bytes: 1_048_576,
2047 isolation_level: 0,
2048 session_id: 0,
2049 session_epoch: -1,
2050 topics: vec![FetchTopicV18 {
2051 topic_id: [9; 16],
2052 partitions: vec![FetchPartitionV18 {
2053 partition_index: 0,
2054 current_leader_epoch: -1,
2055 fetch_offset: 42,
2056 last_fetched_epoch: -1,
2057 log_start_offset: -1,
2058 max_bytes: 1_048_576,
2059 replica_directory_id: Some([10; 16]),
2060 high_watermark: Some(100),
2061 }],
2062 }],
2063 forgotten_topics: Vec::new(),
2064 rack_id: String::new(),
2065 };
2066
2067 let bytes = request.encode().unwrap();
2068 let mut decoder = Decoder::new(&bytes);
2069 decoder.read_i16().unwrap();
2070 decoder.read_i16().unwrap();
2071 decoder.read_i32().unwrap();
2072 decoder.read_nullable_string().unwrap();
2073 decoder.read_tagged_fields().unwrap();
2074 for _ in 0..3 {
2075 decoder.read_i32().unwrap();
2076 }
2077 decoder.read_i8().unwrap();
2078 decoder.read_i32().unwrap();
2079 decoder.read_i32().unwrap();
2080 decoder.read_unsigned_varint().unwrap();
2081 decoder.read_uuid().unwrap();
2082 decoder.read_unsigned_varint().unwrap();
2083 decoder.read_i32().unwrap();
2084 decoder.read_i32().unwrap();
2085 decoder.read_i64().unwrap();
2086 decoder.read_i32().unwrap();
2087 decoder.read_i64().unwrap();
2088 decoder.read_i32().unwrap();
2089 let fields = decoder.read_tagged_fields().unwrap();
2090 assert_eq!(fields.len(), 2);
2091 assert_eq!(fields[0].tag, 0);
2092 assert_eq!(fields[0].data, vec![10; 16]);
2093 assert_eq!(fields[1].tag, 1);
2094 assert_eq!(fields[1].data, 100_i64.to_be_bytes());
2095 assert!(decoder.read_tagged_fields().unwrap().is_empty());
2096 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
2097 assert!(decoder.read_compact_string().unwrap().is_empty());
2098 assert!(decoder.read_tagged_fields().unwrap().is_empty());
2099 assert!(decoder.is_empty());
2100 }
2101
2102 #[test]
2103 fn decodes_fetch_response_v4_with_aborted_transaction() {
2104 let mut bytes = Encoder::new();
2105 bytes.write_i32(0);
2106 bytes.write_i32(1);
2107 bytes.write_string("orders").unwrap();
2108 bytes.write_i32(1);
2109 bytes.write_i32(0);
2110 bytes.write_i16(0);
2111 bytes.write_i64(43);
2112 bytes.write_i64(42);
2113 bytes.write_i32(1);
2114 bytes.write_i64(7);
2115 bytes.write_i64(40);
2116 bytes.write_bytes(&[]).unwrap();
2117 let bytes = bytes.into_bytes();
2118
2119 let mut decoder = Decoder::new(&bytes);
2120 let response = FetchResponseV4::decode_body(&mut decoder).unwrap();
2121 let partition = &response.responses[0].partitions[0];
2122
2123 assert_eq!(partition.high_watermark, 43);
2124 assert_eq!(partition.last_stable_offset, 42);
2125 assert_eq!(partition.aborted_transactions[0].producer_id, 7);
2126 assert_eq!(partition.aborted_transactions[0].first_offset, 40);
2127 assert!(partition.records.is_empty());
2128 assert!(decoder.is_empty());
2129 }
2130
2131 #[test]
2132 fn decodes_fetch_response_v2_with_message_set() {
2133 let mut message = Encoder::new();
2134 message.write_i32(0);
2135 message.write_i8(1);
2136 message.write_i8(0);
2137 message.write_i64(123);
2138 message.write_nullable_bytes(Some(b"order-1")).unwrap();
2139 message.write_nullable_bytes(Some(b"created")).unwrap();
2140 let message = message.into_bytes();
2141
2142 let mut set = Encoder::new();
2143 set.write_i64(42);
2144 set.write_i32(i32::try_from(message.len()).unwrap());
2145 set.write_raw(&message);
2146 let set = set.into_bytes();
2147
2148 let mut bytes = Encoder::new();
2149 bytes.write_i32(0);
2150 bytes.write_i32(1);
2151 bytes.write_string("orders").unwrap();
2152 bytes.write_i32(1);
2153 bytes.write_i32(0);
2154 bytes.write_i16(0);
2155 bytes.write_i64(43);
2156 bytes.write_bytes(&set).unwrap();
2157 let bytes = bytes.into_bytes();
2158
2159 let mut decoder = Decoder::new(&bytes);
2160 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
2161 let record = MessageSetRecord {
2162 offset: 42,
2163 leader_epoch: -1,
2164 timestamp_ms: 123,
2165 key: Some(b"order-1".to_vec()),
2166 value: Some(b"created".to_vec()),
2167 headers: Vec::new(),
2168 producer_id: None,
2169 transactional: false,
2170 control: false,
2171 };
2172
2173 assert_eq!(response.throttle_time_ms, 0);
2174 assert_eq!(response.responses[0].partitions[0].high_watermark, 43);
2175 assert_eq!(response.responses[0].partitions[0].records, vec![record]);
2176 assert!(decoder.is_empty());
2177 }
2178
2179 #[test]
2180 fn decodes_fetch_response_v2_ignores_partial_trailing_message_set_entry() {
2181 let mut message = Encoder::new();
2182 message.write_i32(0);
2183 message.write_i8(1);
2184 message.write_i8(0);
2185 message.write_i64(123);
2186 message.write_nullable_bytes(Some(b"order-1")).unwrap();
2187 message.write_nullable_bytes(Some(b"created")).unwrap();
2188 let message = message.into_bytes();
2189
2190 let mut set = Encoder::new();
2191 set.write_i64(42);
2192 set.write_i32(i32::try_from(message.len()).unwrap());
2193 set.write_raw(&message);
2194 set.write_i64(-1);
2195 set.write_i32(61);
2196 set.write_raw(&[0; 22]);
2197 let set = set.into_bytes();
2198
2199 let mut bytes = Encoder::new();
2200 bytes.write_i32(0);
2201 bytes.write_i32(1);
2202 bytes.write_string("orders").unwrap();
2203 bytes.write_i32(1);
2204 bytes.write_i32(0);
2205 bytes.write_i16(0);
2206 bytes.write_i64(43);
2207 bytes.write_bytes(&set).unwrap();
2208 let bytes = bytes.into_bytes();
2209
2210 let mut decoder = Decoder::new(&bytes);
2211 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
2212
2213 assert_eq!(response.responses[0].partitions[0].records.len(), 1);
2214 assert_eq!(response.responses[0].partitions[0].records[0].offset, 42);
2215 assert!(decoder.is_empty());
2216 }
2217
2218 #[test]
2219 fn decodes_fetch_response_v2_with_record_batch() {
2220 let mut record = Vec::new();
2221 record.push(0);
2222 write_varlong(&mut record, 5);
2223 write_varint(&mut record, 0);
2224 write_varint(&mut record, 7);
2225 record.extend_from_slice(b"order-1");
2226 write_varint(&mut record, 7);
2227 record.extend_from_slice(b"created");
2228 write_varint(&mut record, 2);
2229 write_varint(&mut record, 6);
2230 record.extend_from_slice(b"source");
2231 write_varint(&mut record, 8);
2232 record.extend_from_slice(b"checkout");
2233 write_varint(&mut record, 9);
2234 record.extend_from_slice(b"tombstone");
2235 write_varint(&mut record, -1);
2236
2237 let mut batch = Encoder::new();
2238 batch.write_i32(0);
2239 batch.write_i8(2);
2240 batch.write_i32(0);
2241 batch.write_i16(0x10);
2242 batch.write_i32(0);
2243 batch.write_i64(1_000);
2244 batch.write_i64(1_005);
2245 batch.write_i64(7);
2246 batch.write_i16(-1);
2247 batch.write_i32(-1);
2248 batch.write_i32(1);
2249 let mut encoded_record = Vec::new();
2250 write_varint(&mut encoded_record, i32::try_from(record.len()).unwrap());
2251 encoded_record.extend_from_slice(&record);
2252 batch.write_raw(&encoded_record);
2253 let batch = batch.into_bytes();
2254
2255 let mut set = Encoder::new();
2256 set.write_i64(42);
2257 set.write_i32(i32::try_from(batch.len()).unwrap());
2258 set.write_raw(&batch);
2259 let set = set.into_bytes();
2260
2261 let mut bytes = Encoder::new();
2262 bytes.write_i32(0);
2263 bytes.write_i32(1);
2264 bytes.write_string("orders").unwrap();
2265 bytes.write_i32(1);
2266 bytes.write_i32(0);
2267 bytes.write_i16(0);
2268 bytes.write_i64(43);
2269 bytes.write_bytes(&set).unwrap();
2270 let bytes = bytes.into_bytes();
2271
2272 let mut decoder = Decoder::new(&bytes);
2273 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
2274 let record = MessageSetRecord {
2275 offset: 42,
2276 leader_epoch: 0,
2277 timestamp_ms: 1_005,
2278 key: Some(b"order-1".to_vec()),
2279 value: Some(b"created".to_vec()),
2280 headers: vec![
2281 RecordBatchHeader::new("source", Some(b"checkout".to_vec())),
2282 RecordBatchHeader::new("tombstone", None),
2283 ],
2284 producer_id: Some(7),
2285 transactional: true,
2286 control: false,
2287 };
2288
2289 assert_eq!(response.responses[0].partitions[0].records, vec![record]);
2290 assert!(decoder.is_empty());
2291 }
2292
2293 fn write_varint(output: &mut Vec<u8>, value: i32) {
2294 write_unsigned_varint(output, u64::from(((value << 1) ^ (value >> 31)) as u32));
2295 }
2296
2297 fn write_varlong(output: &mut Vec<u8>, value: i64) {
2298 write_unsigned_varint(output, ((value << 1) ^ (value >> 63)) as u64);
2299 }
2300
2301 fn write_unsigned_varint(output: &mut Vec<u8>, mut value: u64) {
2302 loop {
2303 let mut byte = (value & 0x7f) as u8;
2304 value >>= 7;
2305 if value != 0 {
2306 byte |= 0x80;
2307 }
2308 output.push(byte);
2309 if value == 0 {
2310 break;
2311 }
2312 }
2313 }
2314}