jzon/
short.rs

1use std::mem::MaybeUninit;
2use std::{ ptr, str, slice, fmt };
3use std::ops::Deref;
4
5pub const MAX_LEN: usize = 30;
6
7#[derive(Clone, Copy)]
8pub struct Short {
9    len: u8,
10    value: [MaybeUninit<u8>; MAX_LEN],
11}
12
13/// A `Short` is a small string, up to `MAX_LEN` bytes, that can be managed without
14/// the expensive heap allocation performed for the regular `String` type.
15impl Short {
16    /// Creates a `Short` from a `&str` slice. This method can cause buffer
17    /// overflow if the length of the slice is larger than `MAX_LEN`, which is why
18    /// it is marked as `unsafe`.
19    ///
20    ///
21    /// Typically you should avoid creating your own `Short`s, instead create a
22    /// `JsonValue` (either using `"foo".into()` or `JsonValue::from("foo")`) out
23    /// of a slice. This will automatically decide on `String` or `Short` for you.
24    #[inline(always)]
25    pub unsafe fn from_slice(slice: &str) -> Self {
26        let mut short = Short {
27            value: MaybeUninit::uninit().assume_init(),
28            len: slice.len() as u8,
29        };
30
31        ptr::copy_nonoverlapping(slice.as_ptr(), short.value.as_mut_ptr() as _, slice.len());
32
33        short
34    }
35
36    /// Cheaply obtain a `&str` slice out of the `Short`.
37    #[inline]
38    pub fn as_str(&self) -> &str {
39        unsafe {
40            str::from_utf8_unchecked(
41                slice::from_raw_parts(self.value.as_ptr() as _, self.len as usize)
42            )
43        }
44    }
45}
46
47impl PartialEq for Short {
48    #[inline]
49    fn eq(&self, other: &Short) -> bool {
50        self.as_str() == other.as_str()
51    }
52}
53
54impl fmt::Debug for Short {
55    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56        fmt::Debug::fmt(self.as_str(), f)
57    }
58}
59
60impl fmt::Display for Short {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        fmt::Display::fmt(self.as_str(), f)
63    }
64}
65
66/// Implements `Deref` for `Short` means that, just like `String`, you can
67/// pass `&Short` to functions that expect `&str` and have the conversion happen
68/// automagically. On top of that, all methods present on `&str` can be called on
69/// an instance of `Short`.
70impl Deref for Short {
71    type Target = str;
72
73    #[inline(always)]
74    fn deref(&self) -> &str {
75        self.as_str()
76    }
77}
78
79impl From<Short> for String {
80    fn from(short: Short) -> String {
81        String::from(short.as_str())
82    }
83}
84
85impl PartialEq<str> for Short {
86    fn eq(&self, other: &str) -> bool {
87        self.as_str().eq(other)
88    }
89}
90
91impl PartialEq<Short> for str {
92    fn eq(&self, other: &Short) -> bool {
93        other.as_str().eq(self)
94    }
95}
96
97impl PartialEq<String> for Short {
98    fn eq(&self, other: &String) -> bool {
99        self.as_str().eq(other)
100    }
101}
102
103impl PartialEq<Short> for String {
104    fn eq(&self, other: &Short) -> bool {
105        other.as_str().eq(self)
106    }
107}