1#![doc(html_logo_url = "https://raw.githubusercontent.com/al8n/memberlist/main/art/logo_72x72.png")]
3#![forbid(unsafe_code)]
4#![deny(warnings)]
5#![allow(clippy::type_complexity, clippy::double_parens, unexpected_cfgs)]
6#![cfg_attr(docsrs, feature(doc_cfg))]
7#![cfg_attr(docsrs, allow(unused_attributes))]
8
9#[cfg(feature = "metrics")]
10#[cfg_attr(docsrs, doc(cfg(feature = "metrics")))]
11pub use metrics_label::MetricLabels;
12#[cfg(any(feature = "std", feature = "alloc"))]
13#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
14pub use nodecraft::{CheapClone, Node, NodeId, ParseNodeIdError};
15
16#[cfg(all(any(feature = "std", feature = "alloc"), feature = "hostaddr"))]
17#[cfg_attr(
18 docsrs,
19 doc(cfg(all(any(feature = "std", feature = "alloc"), feature = "hostaddr")))
20)]
21pub use nodecraft::{
22 Domain, DomainBuffer, HostAddr, HostAddrBuffer,
23 hostaddr::{ParseDomainError, ParseHostAddrError},
24};
25
26#[cfg(any(feature = "arbitrary", test))]
27mod arbitrary_impl;
28
29#[cfg(any(
31 feature = "zstd",
32 feature = "lz4",
33 feature = "brotli",
34 feature = "snappy",
35))]
36pub mod compression;
37
38#[cfg(any(
40 feature = "crc32",
41 feature = "xxhash32",
42 feature = "xxhash64",
43 feature = "xxhash3",
44 feature = "murmur3",
45))]
46pub mod checksum;
47
48#[cfg(feature = "encryption")]
50#[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
51pub mod encryption;
52
53#[cfg(feature = "metrics")]
54mod metrics_label;
55#[cfg(any(feature = "quickcheck", test))]
56mod quickcheck_impl;
57#[cfg(feature = "serde")]
58mod serde_impl;
59
60#[cfg(any(
61 feature = "crc32",
62 feature = "xxhash32",
63 feature = "xxhash64",
64 feature = "xxhash3",
65 feature = "murmur3",
66))]
67pub use checksum::*;
68#[cfg(any(
69 feature = "zstd",
70 feature = "lz4",
71 feature = "brotli",
72 feature = "snappy",
73))]
74pub use compression::*;
75#[cfg(feature = "encryption")]
76#[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
77pub use encryption::*;
78
79pub use ack::*;
80pub use address::*;
81pub use alive::*;
82pub use bad_state::*;
83pub use bytes;
84pub use cidr_policy::*;
85pub use data::*;
86pub use err::*;
87pub use label::*;
88pub use meta::*;
89pub use payload::*;
90pub use ping::*;
91pub use proto::*;
92pub use push_pull::*;
93pub use server::*;
94pub use smallvec_wrapper::*;
95pub use version::*;
96
97mod ack;
98mod address;
99mod alive;
100mod bad_state;
101mod cidr_policy;
102mod data;
103mod err;
104mod label;
105mod meta;
106mod payload;
107mod ping;
108mod proto;
109mod push_pull;
110mod server;
111mod version;
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115#[repr(u8)]
116#[non_exhaustive]
117pub enum WireType {
118 Byte = 0,
120 Varint = 1,
122 LengthDelimited = 2,
124 Fixed32 = 3,
126 Fixed64 = 4,
128}
129
130impl WireType {
131 #[inline]
133 pub const fn as_str(&self) -> &'static str {
134 match self {
135 Self::Byte => "byte",
136 Self::Varint => "varint",
137 Self::LengthDelimited => "length-delimited",
138 Self::Fixed32 => "fixed32",
139 Self::Fixed64 => "fixed64",
140 }
141 }
142}
143
144impl core::fmt::Display for WireType {
145 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
146 write!(f, "{}", self.as_str())
147 }
148}
149
150impl TryFrom<u8> for WireType {
151 type Error = u8;
152
153 fn try_from(value: u8) -> Result<Self, Self::Error> {
154 Ok(match value {
155 0 => Self::Byte,
156 1 => Self::Varint,
157 2 => Self::LengthDelimited,
158 3 => Self::Fixed32,
159 4 => Self::Fixed64,
160 _ => return Err(value),
161 })
162 }
163}
164
165use utils::*;
166
167pub mod utils {
169 use super::{DecodeError, WireType};
170
171 #[inline]
173 pub const fn merge(ty: WireType, tag: u8) -> u8 {
174 (ty as u8) << 3 | tag
175 }
176
177 #[inline]
179 pub const fn split(val: u8) -> (u8, u8) {
180 let wire_type = val >> 3; let tag = val & 0b111; (wire_type, tag)
183 }
184
185 pub fn skip(ty: &'static str, src: &[u8]) -> Result<usize, DecodeError> {
187 let buf_len = src.len();
188 if buf_len == 0 {
189 return Ok(0);
190 }
191
192 let mut offset = 0;
193 let (wire_type, tag) = split(src[offset]);
194
195 let wire_type =
196 WireType::try_from(wire_type).map_err(|v| DecodeError::unknown_wire_type(ty, v, tag))?;
197 offset += 1;
198 let src = &src[offset..];
199 match wire_type {
200 WireType::Varint => match varing::decode_u64_varint(src) {
201 Ok((bytes_read, _)) => Ok((offset + bytes_read.get()).min(buf_len)),
202 Err(e) => Err(e.into()),
203 },
204 WireType::LengthDelimited => {
205 if src.is_empty() {
207 return Err(DecodeError::buffer_underflow());
208 }
209
210 match varing::decode_u32_varint(src) {
211 Ok((bytes_read, length)) => {
212 Ok((offset + bytes_read.get() + length as usize).min(buf_len))
213 }
214 Err(e) => Err(e.into()),
215 }
216 }
217 WireType::Byte => Ok((offset + 1).min(buf_len)),
218 WireType::Fixed32 => Ok((offset + 4).min(buf_len)),
219 WireType::Fixed64 => Ok((offset + 8).min(buf_len)),
220 }
221 }
222}
223
224#[cfg(debug_assertions)]
225#[inline]
226fn debug_assert_write_eq<T: ?Sized>(actual: usize, expected: usize) {
227 debug_assert_eq!(
228 actual,
229 expected,
230 "{}: expect writting {expected} bytes, but actual write {actual} bytes",
231 core::any::type_name::<T>()
232 );
233}
234
235#[cfg(debug_assertions)]
236#[inline]
237fn debug_assert_read_eq<T: ?Sized>(actual: usize, expected: usize) {
238 debug_assert_eq!(
239 actual,
240 expected,
241 "{}: expect reading {expected} bytes, but actual read {actual} bytes",
242 core::any::type_name::<T>()
243 );
244}
245
246#[inline]
247fn check_encoded_message_size(required: usize) -> Result<(), EncodeError> {
248 if required > u32::MAX as usize {
249 return Err(EncodeError::TooLarge);
250 }
251
252 Ok(())
253}