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