1use bytes::{Buf, BufMut};
4
5use crate::{
6 Decode, Encode, ProtocolError, UnknownTaggedFields,
7 primitives::{
8 fixed::{get_i32, get_i64, put_i32, put_i64},
9 string_bytes::{
10 compact_nullable_string_len, compact_string_len, get_compact_nullable_string_owned,
11 get_compact_string_owned, get_nullable_string_owned, get_string_owned,
12 nullable_string_len, put_compact_nullable_string, put_compact_string,
13 put_nullable_string, put_string, string_len,
14 },
15 },
16 tagged_fields::{WriteTaggedFields, encode_to_bytes, read_tagged_fields, tagged_fields_len},
17};
18pub const API_KEY: i16 = 59;
19pub const MIN_VERSION: i16 = 0;
20pub const MAX_VERSION: i16 = 1;
21pub const LATEST_STABLE_VERSION: i16 = 1;
22pub const FLEXIBLE_MIN: i16 = 0;
23#[inline]
24#[must_use]
25pub fn is_flexible(version: i16) -> bool {
26 version >= FLEXIBLE_MIN
27}
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct FetchSnapshotRequest {
30 pub replica_id: i32,
31 pub max_bytes: i32,
32 pub topics: Vec<TopicSnapshot>,
33 pub cluster_id: Option<String>,
34 pub unknown_tagged_fields: UnknownTaggedFields,
35}
36impl Default for FetchSnapshotRequest {
37 fn default() -> Self {
38 Self {
39 replica_id: -1i32,
40 max_bytes: 2_147_483_647i32,
41 topics: Vec::new(),
42 cluster_id: None,
43 unknown_tagged_fields: UnknownTaggedFields::default(),
44 }
45 }
46}
47impl Encode for FetchSnapshotRequest {
48 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
49 if !(MIN_VERSION..=MAX_VERSION).contains(&version) {
50 return Err(ProtocolError::UnsupportedVersion {
51 api_key: API_KEY,
52 version,
53 });
54 }
55 let flex = is_flexible(version);
56 if version >= 0 {
57 put_i32(buf, self.replica_id);
58 }
59 if version >= 0 {
60 put_i32(buf, self.max_bytes);
61 }
62 if version >= 0 {
63 {
64 crate::primitives::array::put_array_len(buf, (self.topics).len(), flex);
65 for it in &self.topics {
66 it.encode(buf, version)?;
67 }
68 };
69 }
70 if flex {
71 let mut tagged = WriteTaggedFields::new();
72 if self.cluster_id.is_some() {
73 let payload = encode_to_bytes(
74 if flex {
75 compact_nullable_string_len(self.cluster_id.as_deref())
76 } else {
77 nullable_string_len(self.cluster_id.as_deref())
78 },
79 |b| {
80 if flex {
81 let () = put_compact_nullable_string(b, self.cluster_id.as_deref());
82 } else {
83 let () = put_nullable_string(b, self.cluster_id.as_deref());
84 }
85 Ok(())
86 },
87 );
88 tagged.add(0, payload);
89 }
90 tagged.write(buf, &self.unknown_tagged_fields);
91 }
92 Ok(())
93 }
94 fn encoded_len(&self, version: i16) -> usize {
95 let flex = is_flexible(version);
96 let mut n: usize = 0;
97 if version >= 0 {
98 n += 4;
99 }
100 if version >= 0 {
101 n += 4;
102 }
103 if version >= 0 {
104 n += {
105 let prefix =
106 crate::primitives::array::array_len_prefix_len((self.topics).len(), flex);
107 let body: usize = (self.topics).iter().map(|it| it.encoded_len(version)).sum();
108 prefix + body
109 };
110 }
111 if flex {
112 let mut known_pairs: Vec<(u32, usize)> = Vec::new();
113 if self.cluster_id.is_some() {
114 known_pairs.push((
115 0,
116 if flex {
117 compact_nullable_string_len(self.cluster_id.as_deref())
118 } else {
119 nullable_string_len(self.cluster_id.as_deref())
120 },
121 ));
122 }
123 n += tagged_fields_len(&known_pairs, &self.unknown_tagged_fields);
124 }
125 n
126 }
127}
128impl Decode<'_> for FetchSnapshotRequest {
129 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
130 if !(MIN_VERSION..=MAX_VERSION).contains(&version) {
131 return Err(ProtocolError::UnsupportedVersion {
132 api_key: API_KEY,
133 version,
134 });
135 }
136 let flex = is_flexible(version);
137 let mut out = Self::default();
138 if version >= 0 {
139 out.replica_id = get_i32(buf)?;
140 }
141 if version >= 0 {
142 out.max_bytes = get_i32(buf)?;
143 }
144 if version >= 0 {
145 out.topics = {
146 let n = crate::primitives::array::get_array_len(buf, flex)?;
147 let mut v = Vec::with_capacity(n);
148 for _ in 0..n {
149 v.push(TopicSnapshot::decode(buf, version)?);
150 }
151 v
152 };
153 }
154 if flex {
155 let mut tag_cluster_id = None;
156 out.unknown_tagged_fields = read_tagged_fields(buf, |tag, payload| match tag {
157 0 => {
158 tag_cluster_id = Some({
159 let b: &mut &[u8] = payload;
160 if flex {
161 get_compact_nullable_string_owned(b)?
162 } else {
163 get_nullable_string_owned(b)?
164 }
165 });
166 Ok(true)
167 }
168 _ => Ok(false),
169 })?;
170 if let Some(v) = tag_cluster_id {
171 out.cluster_id = v;
172 }
173 }
174 Ok(out)
175 }
176}
177#[cfg(test)]
178impl FetchSnapshotRequest {
179 #[must_use]
180 pub fn populated(version: i16) -> Self {
181 let mut m = Self::default();
182 if version >= 0 {
183 m.replica_id = 1i32;
184 }
185 if version >= 0 {
186 m.max_bytes = 1i32;
187 }
188 if version >= 0 {
189 m.topics = vec![TopicSnapshot::populated(version)];
190 }
191 if version >= 0 {
192 m.cluster_id = Some("x".to_string());
193 }
194 m
195 }
196}
197#[derive(Debug, Clone, PartialEq, Eq, Default)]
198pub struct TopicSnapshot {
199 pub name: String,
200 pub partitions: Vec<PartitionSnapshot>,
201 pub unknown_tagged_fields: UnknownTaggedFields,
202}
203impl Encode for TopicSnapshot {
204 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
205 let flex = version >= 0;
206 if version >= 0 {
207 if flex {
208 let () = put_compact_string(buf, &self.name);
209 } else {
210 let () = put_string(buf, &self.name);
211 }
212 }
213 if version >= 0 {
214 {
215 crate::primitives::array::put_array_len(buf, (self.partitions).len(), flex);
216 for it in &self.partitions {
217 it.encode(buf, version)?;
218 }
219 };
220 }
221 if flex {
222 let tagged = WriteTaggedFields::new();
223 tagged.write(buf, &self.unknown_tagged_fields);
224 }
225 Ok(())
226 }
227 fn encoded_len(&self, version: i16) -> usize {
228 let flex = version >= 0;
229 let mut n: usize = 0;
230 if version >= 0 {
231 n += if flex {
232 compact_string_len(&self.name)
233 } else {
234 string_len(&self.name)
235 };
236 }
237 if version >= 0 {
238 n += {
239 let prefix =
240 crate::primitives::array::array_len_prefix_len((self.partitions).len(), flex);
241 let body: usize = (self.partitions)
242 .iter()
243 .map(|it| it.encoded_len(version))
244 .sum();
245 prefix + body
246 };
247 }
248 if flex {
249 let known_pairs: Vec<(u32, usize)> = Vec::new();
250 n += tagged_fields_len(&known_pairs, &self.unknown_tagged_fields);
251 }
252 n
253 }
254}
255impl Decode<'_> for TopicSnapshot {
256 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
257 let flex = version >= 0;
258 let mut out = Self::default();
259 if version >= 0 {
260 out.name = if flex {
261 get_compact_string_owned(buf)?
262 } else {
263 get_string_owned(buf)?
264 };
265 }
266 if version >= 0 {
267 out.partitions = {
268 let n = crate::primitives::array::get_array_len(buf, flex)?;
269 let mut v = Vec::with_capacity(n);
270 for _ in 0..n {
271 v.push(PartitionSnapshot::decode(buf, version)?);
272 }
273 v
274 };
275 }
276 if flex {
277 out.unknown_tagged_fields = read_tagged_fields(buf, |_tag, _payload| Ok(false))?;
278 }
279 Ok(out)
280 }
281}
282#[cfg(test)]
283impl TopicSnapshot {
284 #[must_use]
285 pub fn populated(version: i16) -> Self {
286 let mut m = Self::default();
287 if version >= 0 {
288 m.name = "x".to_string();
289 }
290 if version >= 0 {
291 m.partitions = vec![PartitionSnapshot::populated(version)];
292 }
293 m
294 }
295}
296#[derive(Debug, Clone, PartialEq, Eq, Default)]
297pub struct PartitionSnapshot {
298 pub partition: i32,
299 pub current_leader_epoch: i32,
300 pub snapshot_id: SnapshotId,
301 pub position: i64,
302 pub replica_directory_id: crate::primitives::uuid::Uuid,
303 pub unknown_tagged_fields: UnknownTaggedFields,
304}
305impl Encode for PartitionSnapshot {
306 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
307 let flex = version >= 0;
308 if version >= 0 {
309 put_i32(buf, self.partition);
310 }
311 if version >= 0 {
312 put_i32(buf, self.current_leader_epoch);
313 }
314 if version >= 0 {
315 self.snapshot_id.encode(buf, version)?;
316 }
317 if version >= 0 {
318 put_i64(buf, self.position);
319 }
320 if flex {
321 let mut tagged = WriteTaggedFields::new();
322 if version >= 1 && !(crate::codegen_helpers::is_default(&self.replica_directory_id)) {
323 let payload = encode_to_bytes(16, |b| {
324 crate::primitives::uuid::put_uuid(b, self.replica_directory_id);
325 Ok(())
326 });
327 tagged.add(0, payload);
328 }
329 tagged.write(buf, &self.unknown_tagged_fields);
330 }
331 Ok(())
332 }
333 fn encoded_len(&self, version: i16) -> usize {
334 let flex = version >= 0;
335 let mut n: usize = 0;
336 if version >= 0 {
337 n += 4;
338 }
339 if version >= 0 {
340 n += 4;
341 }
342 if version >= 0 {
343 n += self.snapshot_id.encoded_len(version);
344 }
345 if version >= 0 {
346 n += 8;
347 }
348 if flex {
349 let mut known_pairs: Vec<(u32, usize)> = Vec::new();
350 if version >= 1 && !(crate::codegen_helpers::is_default(&self.replica_directory_id)) {
351 known_pairs.push((0, 16));
352 }
353 n += tagged_fields_len(&known_pairs, &self.unknown_tagged_fields);
354 }
355 n
356 }
357}
358impl Decode<'_> for PartitionSnapshot {
359 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
360 let flex = version >= 0;
361 let mut out = Self::default();
362 if version >= 0 {
363 out.partition = get_i32(buf)?;
364 }
365 if version >= 0 {
366 out.current_leader_epoch = get_i32(buf)?;
367 }
368 if version >= 0 {
369 out.snapshot_id = SnapshotId::decode(buf, version)?;
370 }
371 if version >= 0 {
372 out.position = get_i64(buf)?;
373 }
374 if flex {
375 let mut tag_replica_directory_id = None;
376 out.unknown_tagged_fields = read_tagged_fields(buf, |tag, payload| match tag {
377 0 if version >= 1 => {
378 tag_replica_directory_id = Some({
379 let b: &mut &[u8] = payload;
380 crate::primitives::uuid::get_uuid(b)?
381 });
382 Ok(true)
383 }
384 0 => Err(ProtocolError::TagNotValidForVersion { tag: 0, version }),
385 _ => Ok(false),
386 })?;
387 if let Some(v) = tag_replica_directory_id {
388 out.replica_directory_id = v;
389 }
390 }
391 Ok(out)
392 }
393}
394#[cfg(test)]
395impl PartitionSnapshot {
396 #[must_use]
397 pub fn populated(version: i16) -> Self {
398 let mut m = Self::default();
399 if version >= 0 {
400 m.partition = 1i32;
401 }
402 if version >= 0 {
403 m.current_leader_epoch = 1i32;
404 }
405 if version >= 0 {
406 m.snapshot_id = SnapshotId::populated(version);
407 }
408 if version >= 0 {
409 m.position = 1i64;
410 }
411 if version >= 1 {
412 m.replica_directory_id = crate::primitives::uuid::Uuid([1u8; 16]);
413 }
414 m
415 }
416}
417#[derive(Debug, Clone, PartialEq, Eq, Default)]
418pub struct SnapshotId {
419 pub end_offset: i64,
420 pub epoch: i32,
421 pub unknown_tagged_fields: UnknownTaggedFields,
422}
423impl Encode for SnapshotId {
424 fn encode<B: BufMut>(&self, buf: &mut B, version: i16) -> Result<(), ProtocolError> {
425 let flex = version >= 0;
426 if version >= 0 {
427 put_i64(buf, self.end_offset);
428 }
429 if version >= 0 {
430 put_i32(buf, self.epoch);
431 }
432 if flex {
433 let tagged = WriteTaggedFields::new();
434 tagged.write(buf, &self.unknown_tagged_fields);
435 }
436 Ok(())
437 }
438 fn encoded_len(&self, version: i16) -> usize {
439 let flex = version >= 0;
440 let mut n: usize = 0;
441 if version >= 0 {
442 n += 8;
443 }
444 if version >= 0 {
445 n += 4;
446 }
447 if flex {
448 let known_pairs: Vec<(u32, usize)> = Vec::new();
449 n += tagged_fields_len(&known_pairs, &self.unknown_tagged_fields);
450 }
451 n
452 }
453}
454impl Decode<'_> for SnapshotId {
455 fn decode<B: Buf>(buf: &mut B, version: i16) -> Result<Self, ProtocolError> {
456 let flex = version >= 0;
457 let mut out = Self::default();
458 if version >= 0 {
459 out.end_offset = get_i64(buf)?;
460 }
461 if version >= 0 {
462 out.epoch = get_i32(buf)?;
463 }
464 if flex {
465 out.unknown_tagged_fields = read_tagged_fields(buf, |_tag, _payload| Ok(false))?;
466 }
467 Ok(out)
468 }
469}
470#[cfg(test)]
471impl SnapshotId {
472 #[must_use]
473 pub fn populated(version: i16) -> Self {
474 let mut m = Self::default();
475 if version >= 0 {
476 m.end_offset = 1i64;
477 }
478 if version >= 0 {
479 m.epoch = 1i32;
480 }
481 m
482 }
483}
484#[must_use]
487#[allow(unused_comparisons)]
488pub fn default_json(_version: i16) -> ::serde_json::Value {
489 let mut obj = ::serde_json::Map::new();
490 obj.insert("clusterId".to_string(), ::serde_json::Value::Null);
491 obj.insert("replicaId".to_string(), ::serde_json::json!(-1));
492 obj.insert("maxBytes".to_string(), ::serde_json::json!(2_147_483_647));
493 obj.insert("topics".to_string(), ::serde_json::Value::Array(vec![]));
494 ::serde_json::Value::Object(obj)
495}
496#[must_use]
499pub fn tagged_fixture() -> FetchSnapshotRequest {
500 FetchSnapshotRequest {
501 cluster_id: Some("x".to_string()),
502 topics: vec![TopicSnapshot {
503 partitions: vec![PartitionSnapshot {
504 replica_directory_id: crate::primitives::uuid::Uuid([1u8; 16]),
505 ..PartitionSnapshot::default()
506 }],
507 ..TopicSnapshot::default()
508 }],
509 ..FetchSnapshotRequest::default()
510 }
511}
512#[must_use]
515pub fn tagged_fixture_json(version: i16) -> ::serde_json::Value {
516 let mut m = ::serde_json::Map::new();
517 m.insert(
518 "clusterId".to_string(),
519 ::serde_json::Value::String("x".to_string()),
520 );
521 m.insert("replicaId".to_string(), ::serde_json::json!(-1));
522 m.insert("maxBytes".to_string(), ::serde_json::json!(2_147_483_647));
523 m.insert(
524 "topics".to_string(),
525 ::serde_json::Value::Array(vec![{
526 let mut m = ::serde_json::Map::new();
527 m.insert(
528 "name".to_string(),
529 ::serde_json::Value::String(String::new()),
530 );
531 m.insert(
532 "partitions".to_string(),
533 ::serde_json::Value::Array(vec![{
534 let mut m = ::serde_json::Map::new();
535 m.insert("partition".to_string(), ::serde_json::json!(0));
536 m.insert("currentLeaderEpoch".to_string(), ::serde_json::json!(0));
537 m.insert("snapshotId".to_string(), {
538 let mut m = ::serde_json::Map::new();
539 m.insert("endOffset".to_string(), ::serde_json::json!(0));
540 m.insert("epoch".to_string(), ::serde_json::json!(0));
541 ::serde_json::Value::Object(m)
542 });
543 m.insert("position".to_string(), ::serde_json::json!(0));
544 if version == 1 {
545 m.insert(
546 "replicaDirectoryId".to_string(),
547 ::serde_json::Value::String("AQEBAQEBAQEBAQEBAQEBAQ".to_string()),
548 );
549 }
550 ::serde_json::Value::Object(m)
551 }]),
552 );
553 ::serde_json::Value::Object(m)
554 }]),
555 );
556 ::serde_json::Value::Object(m)
557}
558impl crate::ProtocolRequest for FetchSnapshotRequest {
559 const API_KEY: i16 = API_KEY;
560 const MIN_VERSION: i16 = MIN_VERSION;
561 const MAX_VERSION: i16 = MAX_VERSION;
562 const LATEST_STABLE_VERSION: i16 = LATEST_STABLE_VERSION;
563 const FLEXIBLE_MIN: i16 = FLEXIBLE_MIN;
564 type Response = super::fetch_snapshot_response::FetchSnapshotResponse;
565}