1use std::cmp::Ordering;
2use std::convert::TryInto;
3use std::fmt::Debug;
4
5#[derive(Eq, PartialEq, Clone, Debug)]
6enum TypeClassification {
7 Internal,
8 UserDefined,
9}
10
11impl TypeClassification {
12 fn to_byte(&self) -> u8 {
13 match self {
14 TypeClassification::Internal => 1,
15 TypeClassification::UserDefined => 2,
16 }
17 }
18
19 fn from_byte(value: u8) -> Self {
20 match value {
21 1 => TypeClassification::Internal,
22 2 => TypeClassification::UserDefined,
23 _ => unreachable!(),
24 }
25 }
26}
27
28#[derive(Eq, PartialEq, Debug, Clone)]
29pub struct TypeName {
30 classification: TypeClassification,
31 name: String,
32}
33
34impl TypeName {
35 pub fn new(name: &str) -> Self {
38 Self {
39 classification: TypeClassification::UserDefined,
40 name: name.to_string(),
41 }
42 }
43
44 pub(crate) fn internal(name: &str) -> Self {
45 Self {
46 classification: TypeClassification::Internal,
47 name: name.to_string(),
48 }
49 }
50
51 pub(crate) fn to_bytes(&self) -> Vec<u8> {
52 let mut result = Vec::with_capacity(self.name.as_bytes().len() + 1);
53 result.push(self.classification.to_byte());
54 result.extend_from_slice(self.name.as_bytes());
55 result
56 }
57
58 pub(crate) fn from_bytes(bytes: &[u8]) -> Self {
59 let classification = TypeClassification::from_byte(bytes[0]);
60 let name = std::str::from_utf8(&bytes[1..]).unwrap().to_string();
61
62 Self {
63 classification,
64 name,
65 }
66 }
67
68 pub(crate) fn name(&self) -> &str {
69 &self.name
70 }
71}
72
73pub trait RedbValue: Debug {
74 type SelfType<'a>: Debug + 'a
76 where
77 Self: 'a;
78
79 type AsBytes<'a>: AsRef<[u8]> + 'a
80 where
81 Self: 'a;
82
83 fn fixed_width() -> Option<usize>;
85
86 fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
89 where
90 Self: 'a;
91
92 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
94 where
95 Self: 'a,
96 Self: 'b;
97
98 fn type_name() -> TypeName;
100}
101
102pub trait MutInPlaceValue: RedbValue {
105 type BaseRefType: Debug + ?Sized;
107
108 fn initialize(data: &mut [u8]);
111
112 fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType;
113}
114
115impl MutInPlaceValue for &[u8] {
116 type BaseRefType = [u8];
117
118 fn initialize(_data: &mut [u8]) {
119 }
121
122 fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType {
123 data
124 }
125}
126
127pub trait RedbKey: RedbValue {
128 fn compare(data1: &[u8], data2: &[u8]) -> Ordering;
130}
131
132impl RedbValue for () {
133 type SelfType<'a> = ()
134 where
135 Self: 'a;
136 type AsBytes<'a> = &'a [u8]
137 where
138 Self: 'a;
139
140 fn fixed_width() -> Option<usize> {
141 Some(0)
142 }
143
144 #[allow(clippy::unused_unit)]
145 fn from_bytes<'a>(_data: &'a [u8]) -> ()
146 where
147 Self: 'a,
148 {
149 ()
150 }
151
152 fn as_bytes<'a, 'b: 'a>(_: &'a Self::SelfType<'b>) -> &'a [u8]
153 where
154 Self: 'a,
155 Self: 'b,
156 {
157 &[]
158 }
159
160 fn type_name() -> TypeName {
161 TypeName::internal("()")
162 }
163}
164
165impl RedbKey for () {
166 fn compare(_data1: &[u8], _data2: &[u8]) -> Ordering {
167 Ordering::Equal
168 }
169}
170
171impl RedbValue for bool {
172 type SelfType<'a> = bool
173 where
174 Self: 'a;
175 type AsBytes<'a> = &'a [u8]
176 where
177 Self: 'a;
178
179 fn fixed_width() -> Option<usize> {
180 Some(1)
181 }
182
183 fn from_bytes<'a>(data: &'a [u8]) -> bool
184 where
185 Self: 'a,
186 {
187 match data[0] {
188 0 => false,
189 1 => true,
190 _ => unreachable!(),
191 }
192 }
193
194 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8]
195 where
196 Self: 'a,
197 Self: 'b,
198 {
199 match value {
200 true => &[1],
201 false => &[0],
202 }
203 }
204
205 fn type_name() -> TypeName {
206 TypeName::internal("bool")
207 }
208}
209
210impl RedbKey for bool {
211 fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
212 let value1 = Self::from_bytes(data1);
213 let value2 = Self::from_bytes(data2);
214 value1.cmp(&value2)
215 }
216}
217
218impl<T: RedbValue> RedbValue for Option<T> {
219 type SelfType<'a> = Option<T::SelfType<'a>>
220 where
221 Self: 'a;
222 type AsBytes<'a> = Vec<u8>
223 where
224 Self: 'a;
225
226 fn fixed_width() -> Option<usize> {
227 T::fixed_width().map(|x| x + 1)
228 }
229
230 fn from_bytes<'a>(data: &'a [u8]) -> Option<T::SelfType<'a>>
231 where
232 Self: 'a,
233 {
234 match data[0] {
235 0 => None,
236 1 => Some(T::from_bytes(&data[1..])),
237 _ => unreachable!(),
238 }
239 }
240
241 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Vec<u8>
242 where
243 Self: 'a,
244 Self: 'b,
245 {
246 let mut result = vec![0];
247 if let Some(x) = value {
248 result[0] = 1;
249 result.extend_from_slice(T::as_bytes(x).as_ref());
250 } else if let Some(fixed_width) = T::fixed_width() {
251 result.extend_from_slice(&vec![0; fixed_width]);
252 }
253 result
254 }
255
256 fn type_name() -> TypeName {
257 TypeName::internal(&format!("Option<{}>", T::type_name().name()))
258 }
259}
260
261impl<T: RedbKey> RedbKey for Option<T> {
262 #[allow(clippy::collapsible_else_if)]
263 fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
264 if data1[0] == 0 {
265 if data2[0] == 0 {
266 Ordering::Equal
267 } else {
268 Ordering::Less
269 }
270 } else {
271 if data2[0] == 0 {
272 Ordering::Greater
273 } else {
274 T::compare(&data1[1..], &data2[1..])
275 }
276 }
277 }
278}
279
280impl RedbValue for &[u8] {
281 type SelfType<'a> = &'a [u8]
282 where
283 Self: 'a;
284 type AsBytes<'a> = &'a [u8]
285 where
286 Self: 'a;
287
288 fn fixed_width() -> Option<usize> {
289 None
290 }
291
292 fn from_bytes<'a>(data: &'a [u8]) -> &'a [u8]
293 where
294 Self: 'a,
295 {
296 data
297 }
298
299 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8]
300 where
301 Self: 'a,
302 Self: 'b,
303 {
304 value
305 }
306
307 fn type_name() -> TypeName {
308 TypeName::internal("&[u8]")
309 }
310}
311
312impl RedbKey for &[u8] {
313 fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
314 data1.cmp(data2)
315 }
316}
317
318impl<const N: usize> RedbValue for &[u8; N] {
319 type SelfType<'a> = &'a [u8; N]
320 where
321 Self: 'a;
322 type AsBytes<'a> = &'a [u8; N]
323 where
324 Self: 'a;
325
326 fn fixed_width() -> Option<usize> {
327 Some(N)
328 }
329
330 fn from_bytes<'a>(data: &'a [u8]) -> &'a [u8; N]
331 where
332 Self: 'a,
333 {
334 data.try_into().unwrap()
335 }
336
337 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8; N]
338 where
339 Self: 'a,
340 Self: 'b,
341 {
342 value
343 }
344
345 fn type_name() -> TypeName {
346 TypeName::internal(&format!("[u8;{N}]"))
347 }
348}
349
350impl<const N: usize> RedbKey for &[u8; N] {
351 fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
352 data1.cmp(data2)
353 }
354}
355
356impl RedbValue for &str {
357 type SelfType<'a> = &'a str
358 where
359 Self: 'a;
360 type AsBytes<'a> = &'a str
361 where
362 Self: 'a;
363
364 fn fixed_width() -> Option<usize> {
365 None
366 }
367
368 fn from_bytes<'a>(data: &'a [u8]) -> &'a str
369 where
370 Self: 'a,
371 {
372 std::str::from_utf8(data).unwrap()
373 }
374
375 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a str
376 where
377 Self: 'a,
378 Self: 'b,
379 {
380 value
381 }
382
383 fn type_name() -> TypeName {
384 TypeName::internal("&str")
385 }
386}
387
388impl RedbKey for &str {
389 fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
390 let str1 = Self::from_bytes(data1);
391 let str2 = Self::from_bytes(data2);
392 str1.cmp(str2)
393 }
394}
395
396impl RedbValue for char {
397 type SelfType<'a> = char;
398 type AsBytes<'a> = [u8; 3] where Self: 'a;
399
400 fn fixed_width() -> Option<usize> {
401 Some(3)
402 }
403
404 fn from_bytes<'a>(data: &'a [u8]) -> char
405 where
406 Self: 'a,
407 {
408 char::from_u32(u32::from_le_bytes([data[0], data[1], data[2], 0])).unwrap()
409 }
410
411 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> [u8; 3]
412 where
413 Self: 'a,
414 Self: 'b,
415 {
416 let bytes = u32::from(*value).to_le_bytes();
417 [bytes[0], bytes[1], bytes[2]]
418 }
419
420 fn type_name() -> TypeName {
421 TypeName::internal(stringify!(char))
422 }
423}
424
425impl RedbKey for char {
426 fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
427 Self::from_bytes(data1).cmp(&Self::from_bytes(data2))
428 }
429}
430
431macro_rules! le_value {
432 ($t:ty) => {
433 impl RedbValue for $t {
434 type SelfType<'a> = $t;
435 type AsBytes<'a> = [u8; std::mem::size_of::<$t>()] where Self: 'a;
436
437 fn fixed_width() -> Option<usize> {
438 Some(std::mem::size_of::<$t>())
439 }
440
441 fn from_bytes<'a>(data: &'a [u8]) -> $t
442 where
443 Self: 'a,
444 {
445 <$t>::from_le_bytes(data.try_into().unwrap())
446 }
447
448 fn as_bytes<'a, 'b: 'a>(
449 value: &'a Self::SelfType<'b>,
450 ) -> [u8; std::mem::size_of::<$t>()]
451 where
452 Self: 'a,
453 Self: 'b,
454 {
455 value.to_le_bytes()
456 }
457
458 fn type_name() -> TypeName {
459 TypeName::internal(stringify!($t))
460 }
461 }
462 };
463}
464
465macro_rules! le_impl {
466 ($t:ty) => {
467 le_value!($t);
468
469 impl RedbKey for $t {
470 fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
471 Self::from_bytes(data1).cmp(&Self::from_bytes(data2))
472 }
473 }
474 };
475}
476
477le_impl!(u8);
478le_impl!(u16);
479le_impl!(u32);
480le_impl!(u64);
481le_impl!(u128);
482le_impl!(i8);
483le_impl!(i16);
484le_impl!(i32);
485le_impl!(i64);
486le_impl!(i128);
487le_value!(f32);
488le_value!(f64);