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