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