1use crate::codec::{DecodeLimits, Decoder, Encoder};
2use crate::error::{Error, Result};
3use crate::header::RequestHeader;
4use crate::record_batch::{decompress_record_batch_records_with_limit, RecordBatchCompression};
5
6pub const API_KEY: i16 = 1;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct FetchRequestV2 {
10 pub correlation_id: i32,
11 pub client_id: Option<String>,
12 pub replica_id: i32,
13 pub max_wait_ms: i32,
14 pub min_bytes: i32,
15 pub topics: Vec<FetchTopicV2>,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct FetchRequestV4 {
20 pub correlation_id: i32,
21 pub client_id: Option<String>,
22 pub replica_id: i32,
23 pub max_wait_ms: i32,
24 pub min_bytes: i32,
25 pub max_bytes: i32,
26 pub isolation_level: i8,
27 pub topics: Vec<FetchTopicV2>,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct FetchRequestV11 {
36 pub correlation_id: i32,
37 pub client_id: Option<String>,
38 pub replica_id: i32,
39 pub max_wait_ms: i32,
40 pub min_bytes: i32,
41 pub max_bytes: i32,
42 pub isolation_level: i8,
43 pub session_id: i32,
44 pub session_epoch: i32,
45 pub topics: Vec<FetchTopicV11>,
46 pub forgotten_topics: Vec<FetchForgottenTopicV11>,
47 pub rack_id: String,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct FetchRequestV12 {
53 pub correlation_id: i32,
54 pub client_id: Option<String>,
55 pub replica_id: i32,
56 pub max_wait_ms: i32,
57 pub min_bytes: i32,
58 pub max_bytes: i32,
59 pub isolation_level: i8,
60 pub session_id: i32,
61 pub session_epoch: i32,
62 pub topics: Vec<FetchTopicV12>,
63 pub forgotten_topics: Vec<FetchForgottenTopicV12>,
64 pub rack_id: String,
65}
66
67impl FetchRequestV12 {
68 pub fn encode(&self) -> Result<Vec<u8>> {
69 let mut encoder = Encoder::new();
70 RequestHeader {
71 api_key: API_KEY,
72 api_version: 12,
73 correlation_id: self.correlation_id,
74 client_id: self.client_id.clone(),
75 }
76 .encode_v2(&mut encoder)?;
77 encoder.write_i32(self.replica_id);
78 encoder.write_i32(self.max_wait_ms);
79 encoder.write_i32(self.min_bytes);
80 encoder.write_i32(self.max_bytes);
81 encoder.write_i8(self.isolation_level);
82 encoder.write_i32(self.session_id);
83 encoder.write_i32(self.session_epoch);
84 encoder.write_compact_array(Some(self.topics.as_slice()), |encoder, topic| {
85 topic.encode(encoder)
86 })?;
87 encoder.write_compact_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
88 topic.encode(encoder)
89 })?;
90 encoder.write_compact_string(&self.rack_id)?;
91 encoder.write_empty_tagged_fields();
92 Ok(encoder.into_bytes())
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct FetchTopicV12 {
98 pub name: String,
99 pub partitions: Vec<FetchPartitionV12>,
100}
101
102impl FetchTopicV12 {
103 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
104 encoder.write_compact_string(&self.name)?;
105 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
106 partition.encode(encoder)
107 })?;
108 encoder.write_empty_tagged_fields();
109 Ok(())
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct FetchPartitionV12 {
115 pub partition_index: i32,
116 pub current_leader_epoch: i32,
117 pub fetch_offset: i64,
118 pub last_fetched_epoch: i32,
119 pub log_start_offset: i64,
120 pub max_bytes: i32,
121}
122
123impl FetchPartitionV12 {
124 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
125 encoder.write_i32(self.partition_index);
126 encoder.write_i32(self.current_leader_epoch);
127 encoder.write_i64(self.fetch_offset);
128 encoder.write_i32(self.last_fetched_epoch);
129 encoder.write_i64(self.log_start_offset);
130 encoder.write_i32(self.max_bytes);
131 encoder.write_empty_tagged_fields();
132 Ok(())
133 }
134}
135
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct FetchForgottenTopicV12 {
138 pub name: String,
139 pub partitions: Vec<i32>,
140}
141
142impl FetchForgottenTopicV12 {
143 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
144 encoder.write_compact_string(&self.name)?;
145 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
146 encoder.write_i32(*partition);
147 Ok(())
148 })?;
149 encoder.write_empty_tagged_fields();
150 Ok(())
151 }
152}
153
154impl FetchRequestV11 {
155 pub fn encode(&self) -> Result<Vec<u8>> {
156 let mut encoder = Encoder::new();
157 RequestHeader {
158 api_key: API_KEY,
159 api_version: 11,
160 correlation_id: self.correlation_id,
161 client_id: self.client_id.clone(),
162 }
163 .encode_v1(&mut encoder)?;
164 encoder.write_i32(self.replica_id);
165 encoder.write_i32(self.max_wait_ms);
166 encoder.write_i32(self.min_bytes);
167 encoder.write_i32(self.max_bytes);
168 encoder.write_i8(self.isolation_level);
169 encoder.write_i32(self.session_id);
170 encoder.write_i32(self.session_epoch);
171 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
172 topic.encode(encoder)
173 })?;
174 encoder.write_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
175 topic.encode(encoder)
176 })?;
177 encoder.write_string(&self.rack_id)?;
178 Ok(encoder.into_bytes())
179 }
180}
181
182#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct FetchTopicV11 {
184 pub name: String,
185 pub partitions: Vec<FetchPartitionV11>,
186}
187
188impl FetchTopicV11 {
189 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
190 encoder.write_string(&self.name)?;
191 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
192 partition.encode(encoder)
193 })
194 }
195}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
198pub struct FetchPartitionV11 {
199 pub partition_index: i32,
200 pub current_leader_epoch: i32,
201 pub fetch_offset: i64,
202 pub log_start_offset: i64,
203 pub max_bytes: i32,
204}
205
206impl FetchPartitionV11 {
207 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
208 encoder.write_i32(self.partition_index);
209 encoder.write_i32(self.current_leader_epoch);
210 encoder.write_i64(self.fetch_offset);
211 encoder.write_i64(self.log_start_offset);
212 encoder.write_i32(self.max_bytes);
213 Ok(())
214 }
215}
216
217#[derive(Debug, Clone, PartialEq, Eq)]
218pub struct FetchForgottenTopicV11 {
219 pub name: String,
220 pub partitions: Vec<i32>,
221}
222
223impl FetchForgottenTopicV11 {
224 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
225 encoder.write_string(&self.name)?;
226 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
227 encoder.write_i32(*partition);
228 Ok(())
229 })
230 }
231}
232
233impl FetchRequestV4 {
234 pub fn encode(&self) -> Result<Vec<u8>> {
235 let mut encoder = Encoder::new();
236 RequestHeader {
237 api_key: API_KEY,
238 api_version: 4,
239 correlation_id: self.correlation_id,
240 client_id: self.client_id.clone(),
241 }
242 .encode_v1(&mut encoder)?;
243 encoder.write_i32(self.replica_id);
244 encoder.write_i32(self.max_wait_ms);
245 encoder.write_i32(self.min_bytes);
246 encoder.write_i32(self.max_bytes);
247 encoder.write_i8(self.isolation_level);
248 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
249 topic.encode(encoder)
250 })?;
251 Ok(encoder.into_bytes())
252 }
253}
254
255impl FetchRequestV2 {
256 pub fn encode(&self) -> Result<Vec<u8>> {
257 let mut encoder = Encoder::new();
258 RequestHeader {
259 api_key: API_KEY,
260 api_version: 2,
261 correlation_id: self.correlation_id,
262 client_id: self.client_id.clone(),
263 }
264 .encode_v1(&mut encoder)?;
265 encoder.write_i32(self.replica_id);
266 encoder.write_i32(self.max_wait_ms);
267 encoder.write_i32(self.min_bytes);
268 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
269 topic.encode(encoder)
270 })?;
271 Ok(encoder.into_bytes())
272 }
273}
274
275#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct FetchTopicV2 {
277 pub name: String,
278 pub partitions: Vec<FetchPartitionV2>,
279}
280
281impl FetchTopicV2 {
282 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
283 encoder.write_string(&self.name)?;
284 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
285 partition.encode(encoder)
286 })
287 }
288}
289
290#[derive(Debug, Clone, PartialEq, Eq)]
291pub struct FetchPartitionV2 {
292 pub partition_index: i32,
293 pub fetch_offset: i64,
294 pub max_bytes: i32,
295}
296
297impl FetchPartitionV2 {
298 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
299 encoder.write_i32(self.partition_index);
300 encoder.write_i64(self.fetch_offset);
301 encoder.write_i32(self.max_bytes);
302 Ok(())
303 }
304}
305
306#[derive(Debug, Clone, PartialEq, Eq)]
307pub struct FetchResponseV2 {
308 pub throttle_time_ms: i32,
309 pub responses: Vec<FetchTopicResponseV2>,
310}
311
312#[derive(Debug, Clone, PartialEq, Eq)]
313pub struct FetchResponseV4 {
314 pub throttle_time_ms: i32,
315 pub responses: Vec<FetchTopicResponseV4>,
316}
317
318#[derive(Debug, Clone, PartialEq, Eq)]
320pub struct FetchResponseV11 {
321 pub throttle_time_ms: i32,
322 pub error_code: i16,
323 pub session_id: i32,
324 pub responses: Vec<FetchTopicResponseV11>,
325}
326
327#[derive(Debug, Clone, PartialEq, Eq)]
329pub struct FetchResponseV12 {
330 pub throttle_time_ms: i32,
331 pub error_code: i16,
332 pub session_id: i32,
333 pub responses: Vec<FetchTopicResponseV12>,
334}
335
336impl FetchResponseV12 {
337 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
338 Ok(Self {
339 throttle_time_ms: decoder.read_i32()?,
340 error_code: decoder.read_i16()?,
341 session_id: decoder.read_i32()?,
342 responses: decoder
343 .read_compact_array("fetch responses", FetchTopicResponseV12::decode)?
344 .unwrap_or_default(),
345 })
346 .and_then(|response| {
347 decoder.read_tagged_fields()?;
348 Ok(response)
349 })
350 }
351}
352
353#[derive(Debug, Clone, PartialEq, Eq)]
354pub struct FetchTopicResponseV12 {
355 pub name: String,
356 pub partitions: Vec<FetchPartitionResponseV12>,
357}
358
359impl FetchTopicResponseV12 {
360 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
361 let name = decoder.read_compact_string()?;
362 let partitions = decoder
363 .read_compact_array(
364 "fetch partition responses",
365 FetchPartitionResponseV12::decode,
366 )?
367 .unwrap_or_default();
368 decoder.read_tagged_fields()?;
369 Ok(Self { name, partitions })
370 }
371}
372
373#[derive(Debug, Clone, PartialEq, Eq)]
374pub struct FetchPartitionResponseV12 {
375 pub partition_index: i32,
376 pub error_code: i16,
377 pub high_watermark: i64,
378 pub last_stable_offset: i64,
379 pub log_start_offset: i64,
380 pub aborted_transactions: Vec<AbortedTransactionV12>,
381 pub preferred_read_replica: i32,
382 pub records: Vec<MessageSetRecord>,
383}
384
385impl FetchPartitionResponseV12 {
386 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
387 let limits = decoder.limits();
388 let partition_index = decoder.read_i32()?;
389 let error_code = decoder.read_i16()?;
390 let high_watermark = decoder.read_i64()?;
391 let last_stable_offset = decoder.read_i64()?;
392 let log_start_offset = decoder.read_i64()?;
393 let aborted_transactions = decoder
394 .read_compact_array("aborted transactions", AbortedTransactionV12::decode)?
395 .unwrap_or_default();
396 let preferred_read_replica = decoder.read_i32()?;
397 let records = decoder
398 .read_compact_nullable_bytes()?
399 .map(|bytes| decode_message_set(&bytes, limits))
400 .transpose()?
401 .unwrap_or_default();
402 decoder.read_tagged_fields()?;
403 Ok(Self {
404 partition_index,
405 error_code,
406 high_watermark,
407 last_stable_offset,
408 log_start_offset,
409 aborted_transactions,
410 preferred_read_replica,
411 records,
412 })
413 }
414}
415
416#[derive(Debug, Clone, PartialEq, Eq)]
417pub struct AbortedTransactionV12 {
418 pub producer_id: i64,
419 pub first_offset: i64,
420}
421
422impl AbortedTransactionV12 {
423 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
424 let producer_id = decoder.read_i64()?;
425 let first_offset = decoder.read_i64()?;
426 decoder.read_tagged_fields()?;
427 Ok(Self {
428 producer_id,
429 first_offset,
430 })
431 }
432}
433
434impl FetchResponseV11 {
435 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
436 Ok(Self {
437 throttle_time_ms: decoder.read_i32()?,
438 error_code: decoder.read_i16()?,
439 session_id: decoder.read_i32()?,
440 responses: decoder
441 .read_array("fetch responses", FetchTopicResponseV11::decode)?
442 .unwrap_or_default(),
443 })
444 }
445}
446
447#[derive(Debug, Clone, PartialEq, Eq)]
448pub struct FetchTopicResponseV11 {
449 pub name: String,
450 pub partitions: Vec<FetchPartitionResponseV11>,
451}
452
453impl FetchTopicResponseV11 {
454 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
455 Ok(Self {
456 name: decoder.read_string()?,
457 partitions: decoder
458 .read_array(
459 "fetch partition responses",
460 FetchPartitionResponseV11::decode,
461 )?
462 .unwrap_or_default(),
463 })
464 }
465}
466
467#[derive(Debug, Clone, PartialEq, Eq)]
468pub struct FetchPartitionResponseV11 {
469 pub partition_index: i32,
470 pub error_code: i16,
471 pub high_watermark: i64,
472 pub last_stable_offset: i64,
473 pub log_start_offset: i64,
474 pub aborted_transactions: Vec<AbortedTransactionV4>,
475 pub preferred_read_replica: i32,
476 pub records: Vec<MessageSetRecord>,
477}
478
479impl FetchPartitionResponseV11 {
480 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
481 let limits = decoder.limits();
482 Ok(Self {
483 partition_index: decoder.read_i32()?,
484 error_code: decoder.read_i16()?,
485 high_watermark: decoder.read_i64()?,
486 last_stable_offset: decoder.read_i64()?,
487 log_start_offset: decoder.read_i64()?,
488 aborted_transactions: decoder
489 .read_array("aborted transactions", AbortedTransactionV4::decode)?
490 .unwrap_or_default(),
491 preferred_read_replica: decoder.read_i32()?,
492 records: decode_message_set(&decoder.read_bytes()?, limits)?,
493 })
494 }
495}
496
497impl FetchResponseV4 {
498 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
499 Ok(Self {
500 throttle_time_ms: decoder.read_i32()?,
501 responses: decoder
502 .read_array("fetch responses", FetchTopicResponseV4::decode)?
503 .unwrap_or_default(),
504 })
505 }
506}
507
508#[derive(Debug, Clone, PartialEq, Eq)]
509pub struct FetchTopicResponseV4 {
510 pub name: String,
511 pub partitions: Vec<FetchPartitionResponseV4>,
512}
513
514impl FetchTopicResponseV4 {
515 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
516 Ok(Self {
517 name: decoder.read_string()?,
518 partitions: decoder
519 .read_array(
520 "fetch partition responses",
521 FetchPartitionResponseV4::decode,
522 )?
523 .unwrap_or_default(),
524 })
525 }
526}
527
528#[derive(Debug, Clone, PartialEq, Eq)]
529pub struct FetchPartitionResponseV4 {
530 pub partition_index: i32,
531 pub error_code: i16,
532 pub high_watermark: i64,
533 pub last_stable_offset: i64,
534 pub aborted_transactions: Vec<AbortedTransactionV4>,
535 pub records: Vec<MessageSetRecord>,
536}
537
538impl FetchPartitionResponseV4 {
539 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
540 let limits = decoder.limits();
541 Ok(Self {
542 partition_index: decoder.read_i32()?,
543 error_code: decoder.read_i16()?,
544 high_watermark: decoder.read_i64()?,
545 last_stable_offset: decoder.read_i64()?,
546 aborted_transactions: decoder
547 .read_array("aborted transactions", AbortedTransactionV4::decode)?
548 .unwrap_or_default(),
549 records: decode_message_set(&decoder.read_bytes()?, limits)?,
550 })
551 }
552}
553
554#[derive(Debug, Clone, PartialEq, Eq)]
555pub struct AbortedTransactionV4 {
556 pub producer_id: i64,
557 pub first_offset: i64,
558}
559
560impl AbortedTransactionV4 {
561 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
562 Ok(Self {
563 producer_id: decoder.read_i64()?,
564 first_offset: decoder.read_i64()?,
565 })
566 }
567}
568
569impl FetchResponseV2 {
570 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
571 Ok(Self {
572 throttle_time_ms: decoder.read_i32()?,
573 responses: decoder
574 .read_array("fetch responses", FetchTopicResponseV2::decode)?
575 .unwrap_or_default(),
576 })
577 }
578}
579
580#[derive(Debug, Clone, PartialEq, Eq)]
581pub struct FetchTopicResponseV2 {
582 pub name: String,
583 pub partitions: Vec<FetchPartitionResponseV2>,
584}
585
586impl FetchTopicResponseV2 {
587 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
588 Ok(Self {
589 name: decoder.read_string()?,
590 partitions: decoder
591 .read_array(
592 "fetch partition responses",
593 FetchPartitionResponseV2::decode,
594 )?
595 .unwrap_or_default(),
596 })
597 }
598}
599
600#[derive(Debug, Clone, PartialEq, Eq)]
601pub struct FetchPartitionResponseV2 {
602 pub partition_index: i32,
603 pub error_code: i16,
604 pub high_watermark: i64,
605 pub records: Vec<MessageSetRecord>,
606}
607
608impl FetchPartitionResponseV2 {
609 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
610 let limits = decoder.limits();
611 Ok(Self {
612 partition_index: decoder.read_i32()?,
613 error_code: decoder.read_i16()?,
614 high_watermark: decoder.read_i64()?,
615 records: decode_message_set(&decoder.read_bytes()?, limits)?,
616 })
617 }
618}
619
620#[derive(Debug, Clone, PartialEq, Eq)]
621pub struct MessageSetRecord {
622 pub offset: i64,
623 pub timestamp_ms: i64,
624 pub key: Option<Vec<u8>>,
625 pub value: Option<Vec<u8>>,
626 pub producer_id: Option<i64>,
627 pub transactional: bool,
628 pub control: bool,
629}
630
631fn decode_message_set(bytes: &[u8], limits: DecodeLimits) -> Result<Vec<MessageSetRecord>> {
632 let mut decoder = Decoder::with_limits(bytes, limits);
633 let mut records = Vec::new();
634
635 while decoder.remaining() >= 12 {
636 let offset = decoder.read_i64()?;
637 let message_size = decoder.read_i32()?;
638 if message_size < 0 {
639 return Err(Error::NegativeLength {
640 kind: "message",
641 length: message_size,
642 });
643 }
644 let message_size =
645 usize::try_from(message_size).map_err(|_| Error::LengthOverflow("message"))?;
646 if decoder.remaining() < message_size {
648 break;
649 }
650 let message = decoder.read_exact(message_size)?;
651 let decoded = decode_message_or_batch(offset, message, limits)?;
652 let total = records
653 .len()
654 .checked_add(decoded.len())
655 .ok_or(Error::LengthOverflow("fetch records"))?;
656 decoder.ensure_collection_length("fetch records", total)?;
657 records.extend(decoded);
658 }
659
660 Ok(records)
661}
662
663fn decode_message_or_batch(
664 offset: i64,
665 bytes: &[u8],
666 limits: DecodeLimits,
667) -> Result<Vec<MessageSetRecord>> {
668 match bytes.get(4).copied() {
669 Some(2) => decode_record_batch(offset, bytes, limits),
670 _ => Ok(vec![decode_message(offset, bytes, limits)?]),
671 }
672}
673
674fn decode_message(offset: i64, bytes: &[u8], limits: DecodeLimits) -> Result<MessageSetRecord> {
675 let mut decoder = Decoder::with_limits(bytes, limits);
676 let _crc = decoder.read_i32()?;
677 let magic = decoder.read_i8()?;
678 let _attributes = decoder.read_i8()?;
679 let timestamp_ms = match magic {
680 0 => -1,
681 1 => decoder.read_i64()?,
682 _ => {
683 return Err(Error::UnsupportedVersion {
684 kind: "message magic",
685 version: i16::from(magic),
686 })
687 }
688 };
689 let key = decoder.read_nullable_bytes()?;
690 let value = decoder.read_nullable_bytes()?;
691
692 Ok(MessageSetRecord {
693 offset,
694 timestamp_ms,
695 key,
696 value,
697 producer_id: None,
698 transactional: false,
699 control: false,
700 })
701}
702
703fn decode_record_batch(
704 base_offset: i64,
705 bytes: &[u8],
706 limits: DecodeLimits,
707) -> Result<Vec<MessageSetRecord>> {
708 let mut decoder = Decoder::with_limits(bytes, limits);
709 let _partition_leader_epoch = decoder.read_i32()?;
710 let magic = decoder.read_i8()?;
711 if magic != 2 {
712 return Err(Error::UnsupportedVersion {
713 kind: "record batch magic",
714 version: i16::from(magic),
715 });
716 }
717 let _crc = decoder.read_i32()?;
718 let attributes = decoder.read_i16()?;
719 let compression = RecordBatchCompression::from_attributes(attributes)?;
720 let _last_offset_delta = decoder.read_i32()?;
721 let base_timestamp = decoder.read_i64()?;
722 let _max_timestamp = decoder.read_i64()?;
723 let producer_id = decoder.read_i64()?;
724 let _producer_epoch = decoder.read_i16()?;
725 let _base_sequence = decoder.read_i32()?;
726 let record_count = decoder.read_i32()?;
727 if record_count < 0 {
728 return Err(Error::NegativeLength {
729 kind: "record batch records",
730 length: record_count,
731 });
732 }
733
734 let record_count =
735 usize::try_from(record_count).map_err(|_| Error::LengthOverflow("record batch records"))?;
736 decoder.ensure_collection_length("record batch records", record_count)?;
737 let record_bytes = if compression.is_compressed() {
738 let compressed = decoder.read_exact(decoder.remaining())?;
739 decompress_record_batch_records_with_limit(
740 compression,
741 compressed,
742 limits.max_decompressed_record_bytes(),
743 )?
744 } else {
745 if decoder.remaining() > limits.max_decompressed_record_bytes() {
746 return Err(Error::LimitExceeded {
747 kind: "decompressed record batch bytes",
748 actual: decoder.remaining(),
749 max: limits.max_decompressed_record_bytes(),
750 });
751 }
752 decoder.read_exact(decoder.remaining())?.to_vec()
753 };
754 let mut record_decoder = Decoder::with_limits(&record_bytes, limits);
755 let mut records = Vec::with_capacity(record_count);
756 for _ in 0..record_count {
757 let record_length = record_decoder.read_varint()?;
758 if record_length < 0 {
759 return Err(Error::NegativeLength {
760 kind: "record",
761 length: record_length,
762 });
763 }
764 let record_length =
765 usize::try_from(record_length).map_err(|_| Error::LengthOverflow("record"))?;
766 let record_bytes = record_decoder.read_exact(record_length)?;
767 records.push(decode_record(
768 base_offset,
769 base_timestamp,
770 producer_id,
771 attributes,
772 record_bytes,
773 limits,
774 )?);
775 }
776
777 Ok(records)
778}
779
780fn decode_record(
781 base_offset: i64,
782 base_timestamp: i64,
783 producer_id: i64,
784 batch_attributes: i16,
785 bytes: &[u8],
786 limits: DecodeLimits,
787) -> Result<MessageSetRecord> {
788 let mut decoder = Decoder::with_limits(bytes, limits);
789 let _attributes = decoder.read_i8()?;
790 let timestamp_delta = decoder.read_varlong()?;
791 let offset_delta = decoder.read_varint()?;
792 let key = decoder.read_varint_nullable_bytes()?;
793 let value = decoder.read_varint_nullable_bytes()?;
794 let header_count = decoder.read_varint()?;
795 if header_count < 0 {
796 return Err(Error::NegativeLength {
797 kind: "record headers",
798 length: header_count,
799 });
800 }
801 let header_count =
802 usize::try_from(header_count).map_err(|_| Error::LengthOverflow("record headers"))?;
803 decoder.ensure_collection_length("record headers", header_count)?;
804 for _ in 0..header_count {
805 let _header_key = decoder.read_varint_bytes()?;
806 let _header_value = decoder.read_varint_nullable_bytes()?;
807 }
808
809 Ok(MessageSetRecord {
810 offset: base_offset.saturating_add(i64::from(offset_delta)),
811 timestamp_ms: base_timestamp.saturating_add(timestamp_delta),
812 key,
813 value,
814 producer_id: (producer_id >= 0).then_some(producer_id),
815 transactional: batch_attributes & 0x10 != 0,
816 control: batch_attributes & 0x20 != 0,
817 })
818}
819
820#[cfg(test)]
821#[allow(clippy::unwrap_used)]
822mod tests {
823 use super::{
824 FetchPartitionV11, FetchPartitionV12, FetchPartitionV2, FetchRequestV11, FetchRequestV12,
825 FetchRequestV2, FetchRequestV4, FetchResponseV11, FetchResponseV12, FetchResponseV2,
826 FetchResponseV4, FetchTopicV11, FetchTopicV12, FetchTopicV2, MessageSetRecord,
827 };
828 use crate::codec::{Decoder, Encoder};
829
830 #[test]
831 fn encodes_fetch_request_v2() {
832 let request = FetchRequestV2 {
833 correlation_id: 7,
834 client_id: Some("kafrust".to_owned()),
835 replica_id: -1,
836 max_wait_ms: 500,
837 min_bytes: 1,
838 topics: vec![FetchTopicV2 {
839 name: "orders".to_owned(),
840 partitions: vec![FetchPartitionV2 {
841 partition_index: 0,
842 fetch_offset: 42,
843 max_bytes: 1_048_576,
844 }],
845 }],
846 };
847
848 let bytes = request.encode().unwrap();
849 assert_eq!(&bytes[0..4], &[0, 1, 0, 2]);
850 assert!(bytes.len() > 40);
851 }
852
853 #[test]
854 fn encodes_fetch_request_v4() {
855 let request = FetchRequestV4 {
856 correlation_id: 8,
857 client_id: Some("kafrust".to_owned()),
858 replica_id: -1,
859 max_wait_ms: 500,
860 min_bytes: 1,
861 max_bytes: 1_048_576,
862 isolation_level: 0,
863 topics: vec![FetchTopicV2 {
864 name: "orders".to_owned(),
865 partitions: vec![FetchPartitionV2 {
866 partition_index: 0,
867 fetch_offset: 42,
868 max_bytes: 1_048_576,
869 }],
870 }],
871 };
872
873 let bytes = request.encode().unwrap();
874 assert_eq!(&bytes[0..4], &[0, 1, 0, 4]);
875 assert_eq!(&bytes[4..8], &[0, 0, 0, 8]);
876 assert!(bytes.len() > 45);
877 }
878
879 #[test]
880 fn encodes_fetch_request_v11_with_rack_and_fetch_session_fields() {
881 let request = FetchRequestV11 {
882 correlation_id: 9,
883 client_id: Some("kafrust".to_owned()),
884 replica_id: -1,
885 max_wait_ms: 500,
886 min_bytes: 1,
887 max_bytes: 1_048_576,
888 isolation_level: 1,
889 session_id: 0,
890 session_epoch: 0,
891 topics: vec![FetchTopicV11 {
892 name: "orders".to_owned(),
893 partitions: vec![FetchPartitionV11 {
894 partition_index: 0,
895 current_leader_epoch: -1,
896 fetch_offset: 42,
897 log_start_offset: -1,
898 max_bytes: 1_048_576,
899 }],
900 }],
901 forgotten_topics: Vec::new(),
902 rack_id: "rack-a".to_owned(),
903 };
904
905 let bytes = request.encode().unwrap();
906 let mut decoder = Decoder::new(&bytes);
907 assert_eq!(decoder.read_i16().unwrap(), 1);
908 assert_eq!(decoder.read_i16().unwrap(), 11);
909 assert_eq!(decoder.read_i32().unwrap(), 9);
910 assert_eq!(
911 decoder.read_nullable_string().unwrap().as_deref(),
912 Some("kafrust")
913 );
914 assert_eq!(decoder.read_i32().unwrap(), -1);
915 assert_eq!(decoder.read_i32().unwrap(), 500);
916 assert_eq!(decoder.read_i32().unwrap(), 1);
917 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
918 assert_eq!(decoder.read_i8().unwrap(), 1);
919 assert_eq!(decoder.read_i32().unwrap(), 0);
920 assert_eq!(decoder.read_i32().unwrap(), 0);
921 assert_eq!(decoder.read_i32().unwrap(), 1);
922 assert_eq!(decoder.read_string().unwrap(), "orders");
923 assert_eq!(decoder.read_i32().unwrap(), 1);
924 assert_eq!(decoder.read_i32().unwrap(), 0);
925 assert_eq!(decoder.read_i32().unwrap(), -1);
926 assert_eq!(decoder.read_i64().unwrap(), 42);
927 assert_eq!(decoder.read_i64().unwrap(), -1);
928 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
929 assert_eq!(decoder.read_i32().unwrap(), 0);
930 assert_eq!(decoder.read_string().unwrap(), "rack-a");
931 assert!(decoder.is_empty());
932 }
933
934 #[test]
935 fn decodes_fetch_response_v11_with_preferred_read_replica() {
936 let mut bytes = Encoder::new();
937 bytes.write_i32(3);
938 bytes.write_i16(0);
939 bytes.write_i32(17);
940 bytes.write_i32(1);
941 bytes.write_string("orders").unwrap();
942 bytes.write_i32(1);
943 bytes.write_i32(0);
944 bytes.write_i16(0);
945 bytes.write_i64(43);
946 bytes.write_i64(42);
947 bytes.write_i64(40);
948 bytes.write_i32(0);
949 bytes.write_i32(2);
950 bytes.write_bytes(&[]).unwrap();
951
952 let bytes = bytes.into_bytes();
953 let mut decoder = Decoder::new(&bytes);
954 let response = FetchResponseV11::decode_body(&mut decoder).unwrap();
955 let partition = &response.responses[0].partitions[0];
956
957 assert_eq!(response.throttle_time_ms, 3);
958 assert_eq!(response.session_id, 17);
959 assert_eq!(partition.log_start_offset, 40);
960 assert_eq!(partition.preferred_read_replica, 2);
961 assert!(partition.records.is_empty());
962 assert!(decoder.is_empty());
963 }
964
965 #[test]
966 fn encodes_fetch_request_v12_with_flexible_rack_fields() {
967 let request = FetchRequestV12 {
968 correlation_id: 10,
969 client_id: Some("kafrust".to_owned()),
970 replica_id: -1,
971 max_wait_ms: 500,
972 min_bytes: 1,
973 max_bytes: 1_048_576,
974 isolation_level: 1,
975 session_id: 0,
976 session_epoch: 0,
977 topics: vec![FetchTopicV12 {
978 name: "orders".to_owned(),
979 partitions: vec![FetchPartitionV12 {
980 partition_index: 0,
981 current_leader_epoch: -1,
982 fetch_offset: 42,
983 last_fetched_epoch: -1,
984 log_start_offset: -1,
985 max_bytes: 1_048_576,
986 }],
987 }],
988 forgotten_topics: Vec::new(),
989 rack_id: "rack-a".to_owned(),
990 };
991
992 let bytes = request.encode().unwrap();
993 let mut decoder = Decoder::new(&bytes);
994 assert_eq!(decoder.read_i16().unwrap(), 1);
995 assert_eq!(decoder.read_i16().unwrap(), 12);
996 assert_eq!(decoder.read_i32().unwrap(), 10);
997 assert_eq!(
998 decoder.read_nullable_string().unwrap().as_deref(),
999 Some("kafrust")
1000 );
1001 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1002 assert_eq!(decoder.read_i32().unwrap(), -1);
1003 assert_eq!(decoder.read_i32().unwrap(), 500);
1004 assert_eq!(decoder.read_i32().unwrap(), 1);
1005 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1006 assert_eq!(decoder.read_i8().unwrap(), 1);
1007 assert_eq!(decoder.read_i32().unwrap(), 0);
1008 assert_eq!(decoder.read_i32().unwrap(), 0);
1009 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1010 assert_eq!(decoder.read_compact_string().unwrap(), "orders");
1011 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1012 assert_eq!(decoder.read_i32().unwrap(), 0);
1013 assert_eq!(decoder.read_i32().unwrap(), -1);
1014 assert_eq!(decoder.read_i64().unwrap(), 42);
1015 assert_eq!(decoder.read_i32().unwrap(), -1);
1016 assert_eq!(decoder.read_i64().unwrap(), -1);
1017 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1018 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1019 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1020 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1021 assert_eq!(decoder.read_compact_string().unwrap(), "rack-a");
1022 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1023 assert!(decoder.is_empty());
1024 }
1025
1026 #[test]
1027 fn decodes_fetch_response_v12_with_preferred_read_replica() {
1028 let mut bytes = Encoder::new();
1029 bytes.write_i32(3);
1030 bytes.write_i16(0);
1031 bytes.write_i32(17);
1032 bytes.write_unsigned_varint(2);
1033 bytes.write_compact_string("orders").unwrap();
1034 bytes.write_unsigned_varint(2);
1035 bytes.write_i32(0);
1036 bytes.write_i16(0);
1037 bytes.write_i64(43);
1038 bytes.write_i64(42);
1039 bytes.write_i64(40);
1040 bytes.write_unsigned_varint(2);
1041 bytes.write_i64(7);
1042 bytes.write_i64(40);
1043 bytes.write_unsigned_varint(0);
1044 bytes.write_i32(2);
1045 bytes.write_compact_nullable_bytes(Some(&[])).unwrap();
1046 bytes.write_unsigned_varint(0);
1047 bytes.write_unsigned_varint(0);
1048 bytes.write_unsigned_varint(0);
1049
1050 let bytes = bytes.into_bytes();
1051 let mut decoder = Decoder::new(&bytes);
1052 let response = FetchResponseV12::decode_body(&mut decoder).unwrap();
1053 let partition = &response.responses[0].partitions[0];
1054
1055 assert_eq!(response.throttle_time_ms, 3);
1056 assert_eq!(response.session_id, 17);
1057 assert_eq!(partition.log_start_offset, 40);
1058 assert_eq!(partition.preferred_read_replica, 2);
1059 assert_eq!(partition.aborted_transactions[0].producer_id, 7);
1060 assert!(partition.records.is_empty());
1061 assert!(decoder.is_empty());
1062 }
1063
1064 #[test]
1065 fn decodes_fetch_response_v4_with_aborted_transaction() {
1066 let mut bytes = Encoder::new();
1067 bytes.write_i32(0);
1068 bytes.write_i32(1);
1069 bytes.write_string("orders").unwrap();
1070 bytes.write_i32(1);
1071 bytes.write_i32(0);
1072 bytes.write_i16(0);
1073 bytes.write_i64(43);
1074 bytes.write_i64(42);
1075 bytes.write_i32(1);
1076 bytes.write_i64(7);
1077 bytes.write_i64(40);
1078 bytes.write_bytes(&[]).unwrap();
1079 let bytes = bytes.into_bytes();
1080
1081 let mut decoder = Decoder::new(&bytes);
1082 let response = FetchResponseV4::decode_body(&mut decoder).unwrap();
1083 let partition = &response.responses[0].partitions[0];
1084
1085 assert_eq!(partition.high_watermark, 43);
1086 assert_eq!(partition.last_stable_offset, 42);
1087 assert_eq!(partition.aborted_transactions[0].producer_id, 7);
1088 assert_eq!(partition.aborted_transactions[0].first_offset, 40);
1089 assert!(partition.records.is_empty());
1090 assert!(decoder.is_empty());
1091 }
1092
1093 #[test]
1094 fn decodes_fetch_response_v2_with_message_set() {
1095 let mut message = Encoder::new();
1096 message.write_i32(0);
1097 message.write_i8(1);
1098 message.write_i8(0);
1099 message.write_i64(123);
1100 message.write_nullable_bytes(Some(b"order-1")).unwrap();
1101 message.write_nullable_bytes(Some(b"created")).unwrap();
1102 let message = message.into_bytes();
1103
1104 let mut set = Encoder::new();
1105 set.write_i64(42);
1106 set.write_i32(i32::try_from(message.len()).unwrap());
1107 set.write_raw(&message);
1108 let set = set.into_bytes();
1109
1110 let mut bytes = Encoder::new();
1111 bytes.write_i32(0);
1112 bytes.write_i32(1);
1113 bytes.write_string("orders").unwrap();
1114 bytes.write_i32(1);
1115 bytes.write_i32(0);
1116 bytes.write_i16(0);
1117 bytes.write_i64(43);
1118 bytes.write_bytes(&set).unwrap();
1119 let bytes = bytes.into_bytes();
1120
1121 let mut decoder = Decoder::new(&bytes);
1122 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
1123 let record = MessageSetRecord {
1124 offset: 42,
1125 timestamp_ms: 123,
1126 key: Some(b"order-1".to_vec()),
1127 value: Some(b"created".to_vec()),
1128 producer_id: None,
1129 transactional: false,
1130 control: false,
1131 };
1132
1133 assert_eq!(response.throttle_time_ms, 0);
1134 assert_eq!(response.responses[0].partitions[0].high_watermark, 43);
1135 assert_eq!(response.responses[0].partitions[0].records, vec![record]);
1136 assert!(decoder.is_empty());
1137 }
1138
1139 #[test]
1140 fn decodes_fetch_response_v2_ignores_partial_trailing_message_set_entry() {
1141 let mut message = Encoder::new();
1142 message.write_i32(0);
1143 message.write_i8(1);
1144 message.write_i8(0);
1145 message.write_i64(123);
1146 message.write_nullable_bytes(Some(b"order-1")).unwrap();
1147 message.write_nullable_bytes(Some(b"created")).unwrap();
1148 let message = message.into_bytes();
1149
1150 let mut set = Encoder::new();
1151 set.write_i64(42);
1152 set.write_i32(i32::try_from(message.len()).unwrap());
1153 set.write_raw(&message);
1154 set.write_i64(-1);
1155 set.write_i32(61);
1156 set.write_raw(&[0; 22]);
1157 let set = set.into_bytes();
1158
1159 let mut bytes = Encoder::new();
1160 bytes.write_i32(0);
1161 bytes.write_i32(1);
1162 bytes.write_string("orders").unwrap();
1163 bytes.write_i32(1);
1164 bytes.write_i32(0);
1165 bytes.write_i16(0);
1166 bytes.write_i64(43);
1167 bytes.write_bytes(&set).unwrap();
1168 let bytes = bytes.into_bytes();
1169
1170 let mut decoder = Decoder::new(&bytes);
1171 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
1172
1173 assert_eq!(response.responses[0].partitions[0].records.len(), 1);
1174 assert_eq!(response.responses[0].partitions[0].records[0].offset, 42);
1175 assert!(decoder.is_empty());
1176 }
1177
1178 #[test]
1179 fn decodes_fetch_response_v2_with_record_batch() {
1180 let mut record = Vec::new();
1181 record.push(0);
1182 write_varlong(&mut record, 5);
1183 write_varint(&mut record, 0);
1184 write_varint(&mut record, 7);
1185 record.extend_from_slice(b"order-1");
1186 write_varint(&mut record, 7);
1187 record.extend_from_slice(b"created");
1188 write_varint(&mut record, 0);
1189
1190 let mut batch = Encoder::new();
1191 batch.write_i32(0);
1192 batch.write_i8(2);
1193 batch.write_i32(0);
1194 batch.write_i16(0x10);
1195 batch.write_i32(0);
1196 batch.write_i64(1_000);
1197 batch.write_i64(1_005);
1198 batch.write_i64(7);
1199 batch.write_i16(-1);
1200 batch.write_i32(-1);
1201 batch.write_i32(1);
1202 let mut encoded_record = Vec::new();
1203 write_varint(&mut encoded_record, i32::try_from(record.len()).unwrap());
1204 encoded_record.extend_from_slice(&record);
1205 batch.write_raw(&encoded_record);
1206 let batch = batch.into_bytes();
1207
1208 let mut set = Encoder::new();
1209 set.write_i64(42);
1210 set.write_i32(i32::try_from(batch.len()).unwrap());
1211 set.write_raw(&batch);
1212 let set = set.into_bytes();
1213
1214 let mut bytes = Encoder::new();
1215 bytes.write_i32(0);
1216 bytes.write_i32(1);
1217 bytes.write_string("orders").unwrap();
1218 bytes.write_i32(1);
1219 bytes.write_i32(0);
1220 bytes.write_i16(0);
1221 bytes.write_i64(43);
1222 bytes.write_bytes(&set).unwrap();
1223 let bytes = bytes.into_bytes();
1224
1225 let mut decoder = Decoder::new(&bytes);
1226 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
1227 let record = MessageSetRecord {
1228 offset: 42,
1229 timestamp_ms: 1_005,
1230 key: Some(b"order-1".to_vec()),
1231 value: Some(b"created".to_vec()),
1232 producer_id: Some(7),
1233 transactional: true,
1234 control: false,
1235 };
1236
1237 assert_eq!(response.responses[0].partitions[0].records, vec![record]);
1238 assert!(decoder.is_empty());
1239 }
1240
1241 fn write_varint(output: &mut Vec<u8>, value: i32) {
1242 write_unsigned_varint(output, u64::from(((value << 1) ^ (value >> 31)) as u32));
1243 }
1244
1245 fn write_varlong(output: &mut Vec<u8>, value: i64) {
1246 write_unsigned_varint(output, ((value << 1) ^ (value >> 63)) as u64);
1247 }
1248
1249 fn write_unsigned_varint(output: &mut Vec<u8>, mut value: u64) {
1250 loop {
1251 let mut byte = (value & 0x7f) as u8;
1252 value >>= 7;
1253 if value != 0 {
1254 byte |= 0x80;
1255 }
1256 output.push(byte);
1257 if value == 0 {
1258 break;
1259 }
1260 }
1261 }
1262}