krabka_protocol/legacy_compat/
fetch.rs1use crate::{
2 kafka_3_6_2,
3 owned::{
4 fetch_request::{self, FetchRequest},
5 fetch_response::{self, FetchResponse},
6 },
7};
8
9impl From<kafka_3_6_2::owned::fetch_request::FetchRequest> for FetchRequest {
12 fn from(l: kafka_3_6_2::owned::fetch_request::FetchRequest) -> Self {
13 Self {
14 replica_id: l.replica_id,
15 max_wait_ms: l.max_wait_ms,
16 min_bytes: l.min_bytes,
17 max_bytes: l.max_bytes,
18 isolation_level: l.isolation_level,
19 session_id: l.session_id,
20 session_epoch: l.session_epoch,
21 topics: l.topics.into_iter().map(Into::into).collect(),
22 forgotten_topics_data: l
23 .forgotten_topics_data
24 .into_iter()
25 .map(Into::into)
26 .collect(),
27 rack_id: l.rack_id,
28 cluster_id: l.cluster_id,
29 replica_state: l.replica_state.into(),
30 ..Default::default()
31 }
32 }
33}
34
35impl From<kafka_3_6_2::owned::fetch_request::ReplicaState> for fetch_request::ReplicaState {
36 fn from(l: kafka_3_6_2::owned::fetch_request::ReplicaState) -> Self {
37 Self {
38 replica_id: l.replica_id,
39 replica_epoch: l.replica_epoch,
40 ..Default::default()
41 }
42 }
43}
44
45impl From<kafka_3_6_2::owned::fetch_request::FetchTopic> for fetch_request::FetchTopic {
46 fn from(l: kafka_3_6_2::owned::fetch_request::FetchTopic) -> Self {
47 Self {
48 topic: l.topic,
49 partitions: l.partitions.into_iter().map(Into::into).collect(),
51 ..Default::default()
52 }
53 }
54}
55
56impl From<kafka_3_6_2::owned::fetch_request::FetchPartition> for fetch_request::FetchPartition {
57 fn from(l: kafka_3_6_2::owned::fetch_request::FetchPartition) -> Self {
58 Self {
59 partition: l.partition,
60 current_leader_epoch: l.current_leader_epoch,
61 fetch_offset: l.fetch_offset,
62 last_fetched_epoch: l.last_fetched_epoch,
63 log_start_offset: l.log_start_offset,
64 partition_max_bytes: l.partition_max_bytes,
65 ..Default::default()
67 }
68 }
69}
70
71impl From<kafka_3_6_2::owned::fetch_request::ForgottenTopic> for fetch_request::ForgottenTopic {
72 fn from(l: kafka_3_6_2::owned::fetch_request::ForgottenTopic) -> Self {
73 Self {
74 topic: l.topic,
75 partitions: l.partitions,
77 ..Default::default()
78 }
79 }
80}
81
82impl From<FetchResponse> for kafka_3_6_2::owned::fetch_response::FetchResponse {
85 fn from(c: FetchResponse) -> Self {
86 Self {
87 throttle_time_ms: c.throttle_time_ms,
88 error_code: c.error_code,
89 session_id: c.session_id,
90 responses: c.responses.into_iter().map(Into::into).collect(),
91 ..Default::default()
93 }
94 }
95}
96
97impl From<fetch_response::FetchableTopicResponse>
98 for kafka_3_6_2::owned::fetch_response::FetchableTopicResponse
99{
100 fn from(c: fetch_response::FetchableTopicResponse) -> Self {
101 Self {
102 topic: c.topic,
103 topic_id: c.topic_id,
104 partitions: c.partitions.into_iter().map(Into::into).collect(),
105 ..Default::default()
106 }
107 }
108}
109
110impl From<fetch_response::PartitionData> for kafka_3_6_2::owned::fetch_response::PartitionData {
111 fn from(c: fetch_response::PartitionData) -> Self {
112 Self {
113 partition_index: c.partition_index,
114 error_code: c.error_code,
115 high_watermark: c.high_watermark,
116 last_stable_offset: c.last_stable_offset,
117 log_start_offset: c.log_start_offset,
118 aborted_transactions: c
119 .aborted_transactions
120 .map(|v| v.into_iter().map(Into::into).collect()),
121 preferred_read_replica: c.preferred_read_replica,
122 records: c.records,
123 diverging_epoch: c.diverging_epoch.into(),
124 current_leader: c.current_leader.into(),
125 snapshot_id: c.snapshot_id.into(),
126 ..Default::default()
127 }
128 }
129}
130
131impl From<fetch_response::AbortedTransaction>
132 for kafka_3_6_2::owned::fetch_response::AbortedTransaction
133{
134 fn from(c: fetch_response::AbortedTransaction) -> Self {
135 Self {
136 producer_id: c.producer_id,
137 first_offset: c.first_offset,
138 ..Default::default()
139 }
140 }
141}
142
143impl From<fetch_response::EpochEndOffset> for kafka_3_6_2::owned::fetch_response::EpochEndOffset {
144 fn from(c: fetch_response::EpochEndOffset) -> Self {
145 Self {
146 epoch: c.epoch,
147 end_offset: c.end_offset,
148 ..Default::default()
149 }
150 }
151}
152
153impl From<fetch_response::LeaderIdAndEpoch>
154 for kafka_3_6_2::owned::fetch_response::LeaderIdAndEpoch
155{
156 fn from(c: fetch_response::LeaderIdAndEpoch) -> Self {
157 Self {
158 leader_id: c.leader_id,
159 leader_epoch: c.leader_epoch,
160 ..Default::default()
161 }
162 }
163}
164
165impl From<fetch_response::SnapshotId> for kafka_3_6_2::owned::fetch_response::SnapshotId {
166 fn from(c: fetch_response::SnapshotId) -> Self {
167 Self {
168 end_offset: c.end_offset,
169 epoch: c.epoch,
170 ..Default::default()
171 }
172 }
173}
174
175#[cfg(test)]
176mod tests {
177
178 use bytes::Bytes;
179
180 use super::*;
181 use crate::{UnknownTaggedFields, primitives::uuid::Uuid, records::RecordsPayload};
182
183 #[test]
184 fn legacy_fetch_request_conversion_preserves_mapped_fields() {
185 let mut legacy = kafka_3_6_2::owned::fetch_request::FetchRequest::populated(15);
186 legacy.replica_id = 42;
187 legacy.max_wait_ms = 43;
188 legacy.min_bytes = 44;
189 legacy.max_bytes = 45;
190 legacy.isolation_level = 1;
191 legacy.session_id = 46;
192 legacy.session_epoch = 47;
193 legacy.rack_id = "rack-a".into();
194 legacy.cluster_id = Some("cluster-a".into());
195 legacy.replica_state.replica_id = 48;
196 legacy.replica_state.replica_epoch = 49;
197 legacy.topics[0].topic = "fetch-topic".into();
198 legacy.topics[0].partitions[0].partition = 3;
199 legacy.topics[0].partitions[0].current_leader_epoch = 4;
200 legacy.topics[0].partitions[0].fetch_offset = 5;
201 legacy.topics[0].partitions[0].last_fetched_epoch = 6;
202 legacy.topics[0].partitions[0].log_start_offset = 7;
203 legacy.topics[0].partitions[0].partition_max_bytes = 8;
204 legacy.forgotten_topics_data[0].topic = "forgotten-topic".into();
205 legacy.forgotten_topics_data[0].partitions = vec![9, 10];
206 let converted = FetchRequest::from(legacy);
207
208 let expected = FetchRequest {
209 replica_id: 42,
210 max_wait_ms: 43,
211 min_bytes: 44,
212 max_bytes: 45,
213 isolation_level: 1,
214 session_id: 46,
215 session_epoch: 47,
216 topics: vec![fetch_request::FetchTopic {
217 topic: "fetch-topic".to_owned(),
218 topic_id: Uuid::ZERO,
219 partitions: vec![fetch_request::FetchPartition {
220 partition: 3,
221 current_leader_epoch: 4,
222 fetch_offset: 5,
223 last_fetched_epoch: 6,
224 log_start_offset: 7,
225 partition_max_bytes: 8,
226 replica_directory_id: Uuid::ZERO,
227 high_watermark: 9_223_372_036_854_775_807,
228 unknown_tagged_fields: UnknownTaggedFields(vec![]),
229 }],
230 unknown_tagged_fields: UnknownTaggedFields(vec![]),
231 }],
232 forgotten_topics_data: vec![fetch_request::ForgottenTopic {
233 topic: "forgotten-topic".to_owned(),
234 topic_id: Uuid::ZERO,
235 partitions: vec![9, 10],
236 unknown_tagged_fields: UnknownTaggedFields(vec![]),
237 }],
238 rack_id: "rack-a".to_owned(),
239 cluster_id: Some("cluster-a".to_owned()),
240 replica_state: fetch_request::ReplicaState {
241 replica_id: 48,
242 replica_epoch: 49,
243 unknown_tagged_fields: UnknownTaggedFields(vec![]),
244 },
245 unknown_tagged_fields: UnknownTaggedFields(vec![]),
246 };
247 assert2::assert!(converted == expected);
248 }
249
250 #[test]
251 fn fetch_response_conversion_preserves_mapped_fields() {
252 let mut canonical = FetchResponse::populated(18);
253 canonical.throttle_time_ms = 51;
254 canonical.error_code = 52;
255 canonical.session_id = 53;
256 canonical.responses[0].topic = "fetch-response-topic".into();
257 canonical.responses[0].topic_id = Uuid([0x12; 16]);
258 canonical.responses[0].partitions[0].partition_index = 54;
259 canonical.responses[0].partitions[0].error_code = 55;
260 canonical.responses[0].partitions[0].high_watermark = 56;
261 canonical.responses[0].partitions[0].last_stable_offset = 57;
262 canonical.responses[0].partitions[0].log_start_offset = 58;
263 canonical.responses[0].partitions[0].preferred_read_replica = 59;
264 canonical.responses[0].partitions[0].records =
265 Some(RecordsPayload::Legacy(Bytes::from_static(&[1, 2, 3])));
266 canonical.responses[0].partitions[0].diverging_epoch.epoch = 60;
267 canonical.responses[0].partitions[0]
268 .diverging_epoch
269 .end_offset = 61;
270 canonical.responses[0].partitions[0]
271 .current_leader
272 .leader_id = 62;
273 canonical.responses[0].partitions[0]
274 .current_leader
275 .leader_epoch = 63;
276 canonical.responses[0].partitions[0].snapshot_id.end_offset = 64;
277 canonical.responses[0].partitions[0].snapshot_id.epoch = 65;
278 canonical.responses[0].partitions[0]
279 .aborted_transactions
280 .as_mut()
281 .expect("aborted transactions")[0]
282 .producer_id = 66;
283 canonical.responses[0].partitions[0]
284 .aborted_transactions
285 .as_mut()
286 .expect("aborted transactions")[0]
287 .first_offset = 67;
288 let converted = kafka_3_6_2::owned::fetch_response::FetchResponse::from(canonical);
289
290 let expected = kafka_3_6_2::owned::fetch_response::FetchResponse {
291 throttle_time_ms: 51,
292 error_code: 52,
293 session_id: 53,
294 responses: vec![kafka_3_6_2::owned::fetch_response::FetchableTopicResponse {
295 topic: "fetch-response-topic".to_owned(),
296 topic_id: Uuid([0x12; 16]),
297 partitions: vec![kafka_3_6_2::owned::fetch_response::PartitionData {
298 partition_index: 54,
299 error_code: 55,
300 high_watermark: 56,
301 last_stable_offset: 57,
302 log_start_offset: 58,
303 aborted_transactions: Some(vec![
304 kafka_3_6_2::owned::fetch_response::AbortedTransaction {
305 producer_id: 66,
306 first_offset: 67,
307 unknown_tagged_fields: UnknownTaggedFields(vec![]),
308 },
309 ]),
310 preferred_read_replica: 59,
311 records: Some(RecordsPayload::Legacy(Bytes::from_static(&[1, 2, 3]))),
312 diverging_epoch: kafka_3_6_2::owned::fetch_response::EpochEndOffset {
313 epoch: 60,
314 end_offset: 61,
315 unknown_tagged_fields: UnknownTaggedFields(vec![]),
316 },
317 current_leader: kafka_3_6_2::owned::fetch_response::LeaderIdAndEpoch {
318 leader_id: 62,
319 leader_epoch: 63,
320 unknown_tagged_fields: UnknownTaggedFields(vec![]),
321 },
322 snapshot_id: kafka_3_6_2::owned::fetch_response::SnapshotId {
323 end_offset: 64,
324 epoch: 65,
325 unknown_tagged_fields: UnknownTaggedFields(vec![]),
326 },
327 unknown_tagged_fields: UnknownTaggedFields(vec![]),
328 }],
329 unknown_tagged_fields: UnknownTaggedFields(vec![]),
330 }],
331 unknown_tagged_fields: UnknownTaggedFields(vec![]),
332 };
333 assert2::assert!(converted == expected);
334 }
335}