1use std::borrow::Cow;
2
3#[derive(Debug, Clone, Copy)]
6#[repr(u8)]
7pub enum ValueKind {
8 U8 = 0,
9 I8 = 1,
10 U16 = 2,
11 I16 = 3,
12 U32 = 4,
13 I32 = 5,
14 U64 = 6,
15 I64 = 7,
16 F32 = 8,
17 STR = 0xa,
18 BLOB = 0xb,
19}
20
21pub(crate) mod sealed {
22 use std::{borrow::Cow, collections::HashMap};
23
24 #[doc(hidden)]
25 pub trait Primitive: ToOwned {
26 type Buffer: AsRef<[u8]> + AsMut<[u8]> + Default;
27
28 const SIZE_IN_UTF: usize = std::mem::size_of::<Self::Buffer>();
29 const TYPE_FLAG: super::ValueKind;
30
31 fn parse<'a>(
32 data: Self::Buffer,
33 strings: &'a HashMap<u32, String>,
34 blobs: &Vec<u8>,
35 ) -> Option<Self::Owned>;
36
37 fn write<'a>(
38 value: Cow<'a, Self>,
39 strings: &mut HashMap<Cow<'a, str>, u32>,
40 string_buffer: &mut Vec<u8>,
41 blobs: &mut Vec<u8>,
42 ) -> Self::Buffer;
43 }
44
45 macro_rules! impl_primitive_number {
46 ($($name:ident $flag:ident),+) => {
47 $(
48 impl Primitive for $name {
49 type Buffer = [u8; std::mem::size_of::<$name>()];
50
51 const TYPE_FLAG: super::ValueKind = super::ValueKind::$flag;
52
53 #[inline]
54 fn parse<'a>(
55 data: Self::Buffer,
56 _: &HashMap<u32, String>,
57 _: &Vec<u8>,
58 ) -> Option<Self> {
59 Some($name::from_be_bytes(data))
60 }
61 #[inline]
62 fn write<'a>(
63 value: Cow<'a, Self>,
64 _: &mut HashMap<Cow<'a, str>, u32>,
65 _: &mut Vec<u8>,
66 _: &mut Vec<u8>,
67 ) -> Self::Buffer {
68 value.to_be_bytes()
69 }
70 }
71 )*
72 };
73 }
74
75 impl_primitive_number!(u8 U8, i8 I8, u16 U16, i16 I16, u32 U32, i32 I32, u64 U64, i64 I64, f32 F32);
76
77 impl Primitive for str {
78 type Buffer = [u8; 4];
79
80 const TYPE_FLAG: super::ValueKind = super::ValueKind::STR;
81
82 fn parse<'a>(
83 data: Self::Buffer,
84 strings: &HashMap<u32, String>,
85 _: &Vec<u8>,
86 ) -> Option<Self::Owned> {
87 strings
88 .get(&u32::from_be_bytes(data))
89 .map(|v| v.to_string())
90 }
91 fn write<'a>(
92 value: Cow<'a, Self>,
93 strings: &mut HashMap<Cow<'a, str>, u32>,
94 string_buffer: &mut Vec<u8>,
95 _: &mut Vec<u8>,
96 ) -> Self::Buffer {
97 match strings.get(&value) {
98 Some(idx) => (*idx).to_be_bytes(),
99 None => {
100 let position = string_buffer.len() as u32;
101 string_buffer.extend_from_slice(&value.as_bytes());
102 string_buffer.push(0u8);
103 strings.insert(value, position);
104 position.to_be_bytes()
105 }
106 }
107 }
108 }
109
110 impl Primitive for [u8] {
111 type Buffer = [u8; 8];
112
113 const TYPE_FLAG: super::ValueKind = super::ValueKind::BLOB;
114
115 fn parse<'a>(
116 data: Self::Buffer,
117 _: &HashMap<u32, String>,
118 blobs: &Vec<u8>,
119 ) -> Option<Self::Owned> {
120 let idx = u32::from_be_bytes(data[0..4].try_into().unwrap()) as usize;
121 let len = u32::from_be_bytes(data[4..8].try_into().unwrap()) as usize;
122 let end = idx + len;
123 if end > blobs.len() {
124 None
125 } else {
126 Some(blobs[idx..end].into())
127 }
128 }
129 fn write<'a>(
130 value: Cow<'a, Self>,
131 _: &mut HashMap<Cow<'a, str>, u32>,
132 _: &mut Vec<u8>,
133 blobs: &mut Vec<u8>,
134 ) -> Self::Buffer {
135 let data = ((blobs.len() << 32) | value.len()) as u64;
136 blobs.extend(value.iter());
137 data.to_be_bytes()
138 }
139 }
140}
141
142macro_rules! blanket_impl {
143 ($trait:ident for $($name:ty),+) => {
144 $(
145 impl $trait for $name {}
146 )*
147 };
148}
149
150pub trait Primitive: sealed::Primitive + ToOwned {}
153
154blanket_impl!(Primitive for u8, u16, u32, u64, i8, i16, i32, i64, f32, str, [u8]);
155
156pub trait Value: Sized {
182 type Primitive: Primitive + ?Sized;
189
190 fn from_primitive(
193 value: <Self::Primitive as ToOwned>::Owned,
194 ) -> Result<Self, Box<dyn std::error::Error>>;
195
196 fn to_primitive<'a>(&'a self) -> Result<Cow<'a, Self::Primitive>, Box<dyn std::error::Error>>;
199}
200
201type BoxRes<T> = Result<T, Box<dyn std::error::Error>>;
202
203macro_rules! impl_value_number {
204 ($($type:ty),*) => {
205 $(
206 impl Value for $type {
207 type Primitive = $type;
208 #[inline]
209 fn from_primitive(value: Self) -> BoxRes<Self> {
210 Ok(value)
211 }
212 #[inline]
213 fn to_primitive<'a>(&'a self) -> BoxRes<Cow<'a, Self::Primitive>> {
214 Ok(Cow::Owned(*self))
215 }
216 }
217 )*
218 };
219}
220
221impl_value_number!(u8, u16, u32, u64, i8, i16, i32, i64, f32);
222
223impl Value for String {
224 type Primitive = str;
225
226 #[inline]
227 fn from_primitive(value: String) -> Result<Self, Box<dyn std::error::Error>> {
228 Ok(value)
229 }
230 #[inline]
231 fn to_primitive<'a>(&'a self) -> Result<Cow<'a, Self::Primitive>, Box<dyn std::error::Error>> {
232 Ok(Cow::Borrowed(self.as_str()))
233 }
234}
235
236impl Value for Vec<u8> {
237 type Primitive = [u8];
238
239 #[inline]
240 fn from_primitive(value: Vec<u8>) -> Result<Self, Box<dyn std::error::Error>> {
241 Ok(value)
242 }
243 #[inline]
244 fn to_primitive<'a>(&'a self) -> Result<Cow<'a, Self::Primitive>, Box<dyn std::error::Error>> {
245 Ok(Cow::Borrowed(self.as_slice()))
246 }
247}
248
249impl Value for Box<[u8]> {
250 type Primitive = [u8];
251
252 #[inline]
253 fn from_primitive(value: Vec<u8>) -> Result<Self, Box<dyn std::error::Error>> {
254 Ok(value.into_boxed_slice())
255 }
256 #[inline]
257 fn to_primitive<'a>(&'a self) -> Result<Cow<'a, Self::Primitive>, Box<dyn std::error::Error>> {
258 Ok(Cow::Borrowed(&self))
259 }
260}
261
262impl<const N: usize> Value for [u8; N] {
263 type Primitive = [u8];
264
265 fn from_primitive(value: Vec<u8>) -> Result<Self, Box<dyn std::error::Error>> {
266 match value.try_into() {
267 Ok(value) => Ok(value),
268 Err(_) => Err(crate::Error::BlobWrongSize.into()),
269 }
270 }
271 #[inline]
272 fn to_primitive<'a>(&'a self) -> Result<Cow<'a, Self::Primitive>, Box<dyn std::error::Error>> {
273 Ok(Cow::Borrowed(self))
274 }
275}
276
277pub const fn utf_size_of<T: Value>() -> usize {
312 <T::Primitive as sealed::Primitive>::SIZE_IN_UTF
313}