kafka_protocol/protocol/
mod.rs1use std::cmp;
5use std::collections::BTreeMap;
6use std::ops::RangeBounds;
7use std::{borrow::Borrow, fmt::Display};
8
9use anyhow::{bail, Result};
10use buf::{ByteBuf, ByteBufMut};
11use bytes::Bytes;
12
13pub mod buf;
14pub mod types;
15
16mod str_bytes {
17 use bytes::Bytes;
18 use std::borrow::Borrow;
19 use std::convert::TryFrom;
20 use std::fmt::{Debug, Display, Formatter};
21 use std::ops::Deref;
22 use std::str::Utf8Error;
23
24 #[derive(Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Default)]
26 pub struct StrBytes(Bytes);
27
28 impl StrBytes {
29 pub const fn new() -> Self {
33 Self(Bytes::new())
34 }
35
36 pub fn from_utf8(bytes: Bytes) -> Result<Self, Utf8Error> {
39 let _: &str = std::str::from_utf8(&bytes)?;
40 Ok(Self(bytes))
41 }
42
43 pub const fn from_static_str(s: &'static str) -> Self {
45 Self(Bytes::from_static(s.as_bytes()))
46 }
47
48 pub fn from_string(s: String) -> Self {
50 Self(Bytes::from(s.into_bytes()))
51 }
52
53 pub fn as_str(&self) -> &str {
55 unsafe { std::str::from_utf8_unchecked(&self.0) }
59 }
60
61 pub fn into_bytes(self) -> Bytes {
63 self.0
64 }
65 }
66
67 impl TryFrom<Bytes> for StrBytes {
68 type Error = Utf8Error;
69
70 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
71 StrBytes::from_utf8(value)
72 }
73 }
74
75 impl From<StrBytes> for Bytes {
76 fn from(value: StrBytes) -> Bytes {
77 value.0
78 }
79 }
80
81 impl From<String> for StrBytes {
82 fn from(value: String) -> Self {
83 Self::from_string(value)
84 }
85 }
86
87 impl From<&'static str> for StrBytes {
88 fn from(value: &'static str) -> Self {
89 Self::from_static_str(value)
90 }
91 }
92
93 impl Deref for StrBytes {
94 type Target = str;
95
96 fn deref(&self) -> &Self::Target {
97 self.as_str()
98 }
99 }
100
101 impl Debug for StrBytes {
102 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
103 Debug::fmt(self.as_str(), f)
104 }
105 }
106
107 impl Display for StrBytes {
108 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
109 std::fmt::Display::fmt(&**self, f)
110 }
111 }
112
113 impl PartialEq<str> for StrBytes {
114 fn eq(&self, other: &str) -> bool {
115 self.as_str().eq(other)
116 }
117 }
118
119 impl Borrow<[u8]> for StrBytes {
120 fn borrow(&self) -> &[u8] {
121 self.as_bytes()
125 }
126 }
127}
128
129pub use str_bytes::StrBytes;
130
131use crate::messages::{ApiKey, RequestHeader};
132
133pub(crate) trait NewType<Inner>: From<Inner> + Into<Inner> + Borrow<Inner> {}
134
135impl<T> NewType<T> for T {}
136
137pub(crate) trait Encoder<Value> {
138 fn encode<B: ByteBufMut>(&self, buf: &mut B, value: Value) -> Result<()>;
139 fn compute_size(&self, value: Value) -> Result<usize>;
140 fn fixed_size(&self) -> Option<usize> {
141 None
142 }
143}
144
145pub(crate) trait Decoder<Value> {
146 fn decode<B: ByteBuf>(&self, buf: &mut B) -> Result<Value>;
147}
148
149#[derive(Debug, Copy, Clone, PartialEq)]
151pub struct VersionRange {
152 pub min: i16,
154 pub max: i16,
156}
157
158impl VersionRange {
159 pub fn is_empty(&self) -> bool {
161 self.min > self.max
162 }
163
164 pub fn intersect(&self, other: &VersionRange) -> VersionRange {
166 VersionRange {
167 min: cmp::max(self.min, other.min),
168 max: cmp::min(self.max, other.max),
169 }
170 }
171}
172
173impl Display for VersionRange {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 write!(f, "{}..{}", self.min, self.max)
176 }
177}
178
179pub trait Message: Sized {
183 const VERSIONS: VersionRange;
185 const DEPRECATED_VERSIONS: Option<VersionRange>;
187}
188
189pub trait Encodable: Sized {
191 fn encode<B: ByteBufMut>(&self, buf: &mut B, version: i16) -> Result<()>;
193 fn compute_size(&self, version: i16) -> Result<usize>;
195}
196
197pub trait Decodable: Sized {
199 fn decode<B: ByteBuf>(buf: &mut B, version: i16) -> Result<Self>;
201}
202
203pub trait HeaderVersion {
205 fn header_version(version: i16) -> i16;
207}
208
209pub trait Request: Message + Encodable + Decodable + HeaderVersion {
215 const KEY: i16;
217 type Response: Message + Encodable + Decodable + HeaderVersion;
219}
220
221pub fn decode_request_header_from_buffer<B: ByteBuf>(buf: &mut B) -> Result<RequestHeader> {
223 let api_key = ApiKey::try_from(bytes::Buf::get_i16(&mut buf.peek_bytes(0..2)))
224 .map_err(|_| anyhow::Error::msg("Unknown API key"))?;
225 let api_version = bytes::Buf::get_i16(&mut buf.peek_bytes(2..4));
226 let header_version = api_key.request_header_version(api_version);
227 RequestHeader::decode(buf, header_version)
228}
229
230pub fn encode_request_header_into_buffer<B: ByteBufMut>(
232 buf: &mut B,
233 header: &RequestHeader,
234) -> Result<()> {
235 let api_key = ApiKey::try_from(header.request_api_key)
236 .map_err(|_| anyhow::Error::msg("Unknown API key"))?;
237 let version = api_key.request_header_version(header.request_api_version);
238 header.encode(buf, version)
239}
240
241pub(crate) fn write_unknown_tagged_fields<B: ByteBufMut, R: RangeBounds<i32>>(
242 buf: &mut B,
243 range: R,
244 unknown_tagged_fields: &BTreeMap<i32, Bytes>,
245) -> Result<()> {
246 for (&k, v) in unknown_tagged_fields.range(range) {
247 if v.len() > u32::MAX as usize {
248 bail!("Tagged field is too long to encode ({} bytes)", v.len());
249 }
250 types::UnsignedVarInt.encode(buf, k as u32)?;
251 types::UnsignedVarInt.encode(buf, v.len() as u32)?;
252 buf.put_slice(v);
253 }
254 Ok(())
255}
256
257pub(crate) fn compute_unknown_tagged_fields_size(
258 unknown_tagged_fields: &BTreeMap<i32, Bytes>,
259) -> Result<usize> {
260 let mut total_size = 0;
261 for (&k, v) in unknown_tagged_fields {
262 if v.len() > u32::MAX as usize {
263 bail!("Tagged field is too long to encode ({} bytes)", v.len());
264 }
265 total_size += types::UnsignedVarInt.compute_size(k as u32)?;
266 total_size += types::UnsignedVarInt.compute_size(v.len() as u32)?;
267 total_size += v.len();
268 }
269 Ok(total_size)
270}