length_delimited/
string.rs

1use dbutils::{
2  error::{IncompleteBuffer, InsufficientBuffer},
3  leb128::*,
4};
5
6macro_rules! string_impl {
7  ($($ty:ty:$converter:ident),+$(,)?) => {
8    string_impl!(@encoder $($ty),+);
9    string_impl!(@decoder $($ty:$converter),+);
10  };
11  (@encoder $($ty:ty),+$(,)?) => {
12    $(
13      impl crate::LengthDelimitedEncoder for $ty {
14        type Error = InsufficientBuffer;
15
16        fn encoded_len(&self) -> usize {
17          <&[u8] as crate::LengthDelimitedEncoder>::encoded_len(&self.as_bytes())
18        }
19
20        fn encoded_length_delimited_len(&self) -> usize {
21          <&[u8] as crate::LengthDelimitedEncoder>::encoded_length_delimited_len(&self.as_bytes())
22        }
23
24        fn encode_length_delimited(&self, buf: &mut [u8]) -> Result<usize, Self::Error> {
25          <&[u8] as crate::LengthDelimitedEncoder>::encode_length_delimited(&self.as_bytes(), buf)
26        }
27
28        fn encode(&self, buf: &mut [u8]) -> Result<usize, Self::Error> {
29          <&[u8] as crate::LengthDelimitedEncoder>::encode(&self.as_bytes(), buf)
30        }
31      }
32    )*
33  };
34  (@decoder $($ty:ty:$converter:ident),+$(,)?) => {
35    $(
36      impl crate::LengthDelimitedDecoder for $ty {
37        type Error = DecodeUtf8BytesError;
38
39        fn decode(src: &[u8]) -> Result<(usize, Self), Self::Error>
40        where
41          Self: Sized,
42        {
43          core::str::from_utf8(&src).map_err(Into::into).map(|s| (src.len(), Self::$converter(s)))
44        }
45
46        fn decode_length_delimited(src: &[u8]) -> Result<(usize, Self), Self::Error>
47        where
48          Self: Sized,
49        {
50          let (read, bytes) = decode_u64_varint(src)?;
51          let len = bytes as usize;
52          let required = read + len;
53          if required > src.len() {
54            return Err(IncompleteBuffer::with_information(required as u64, src.len() as u64).into());
55          }
56
57          Self::decode(&src[read..required])
58            .map(|(bytes, this)| (read + bytes, this))
59            .map_err(|e| match e {
60              Self::Error::IncompleteBuffer(_) => IncompleteBuffer::with_information(
61                required as u64,
62                src.len() as u64,
63              ).into(),
64              e => e,
65            })
66        }
67      }
68    )*
69  };
70}
71
72/// The error that can be returned when decoding utf8 bytes.
73#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
74pub enum DecodeUtf8BytesError {
75  /// Returned when there is not enough data to decode the full type.
76  #[error(transparent)]
77  IncompleteBuffer(#[from] IncompleteBuffer),
78  /// Returned when the length delimited overflows.
79  #[error("length delimited overflow")]
80  Overflow,
81  /// Returned when the string is not valid UTF-8.
82  #[error(transparent)]
83  Utf8(#[from] core::str::Utf8Error),
84}
85
86impl From<DecodeVarintError> for DecodeUtf8BytesError {
87  fn from(e: DecodeVarintError) -> Self {
88    match e {
89      DecodeVarintError::Underflow => Self::IncompleteBuffer(IncompleteBuffer::new()),
90      DecodeVarintError::Overflow => Self::Overflow,
91    }
92  }
93}
94
95impl From<crate::DecodeBytesError> for DecodeUtf8BytesError {
96  fn from(e: crate::DecodeBytesError) -> Self {
97    match e {
98      crate::DecodeBytesError::IncompleteBuffer(e) => Self::IncompleteBuffer(e),
99      crate::DecodeBytesError::Overflow => Self::Overflow,
100    }
101  }
102}
103
104string_impl!(@encoder &str);
105
106#[cfg(any(feature = "std", feature = "alloc"))]
107string_impl!(std::string::String:from, std::sync::Arc<str>:from, std::boxed::Box<str>:from, std::rc::Rc<str>:from);
108
109#[cfg(all(feature = "triomphe01", any(feature = "std", feature = "alloc")))]
110string_impl!(triomphe01::Arc<str>:from,);
111
112#[cfg(all(feature = "smol_str03", any(feature = "std", feature = "alloc")))]
113string_impl!(smol_str03::SmolStr:new,);
114
115#[cfg(all(feature = "faststr02", any(feature = "std", feature = "alloc")))]
116string_impl!(faststr02::FastStr:new,);