Skip to main content

uv_small_str/
lib.rs

1use std::borrow::Cow;
2use std::cmp::PartialEq;
3use std::ops::Deref;
4use std::str::Utf8Error;
5
6use arcstr::ArcStr;
7
8/// An optimized type for immutable identifiers. Represented as an [`ArcStr`] internally.
9#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct SmallString(ArcStr);
11
12impl SmallString {
13    /// Allocate a string of `length` bytes and initialize its zeroed buffer.
14    ///
15    /// Returns an error if the initialized bytes are not valid UTF-8.
16    #[inline]
17    pub fn init_with(
18        length: usize,
19        initializer: impl FnOnce(&mut [u8]),
20    ) -> Result<Self, Utf8Error> {
21        ArcStr::init_with(length, initializer).map(Self)
22    }
23}
24
25impl From<ArcStr> for SmallString {
26    #[inline]
27    fn from(s: ArcStr) -> Self {
28        Self(s)
29    }
30}
31
32impl From<&str> for SmallString {
33    #[inline]
34    fn from(s: &str) -> Self {
35        Self(s.into())
36    }
37}
38
39impl From<String> for SmallString {
40    #[inline]
41    fn from(s: String) -> Self {
42        Self(s.into())
43    }
44}
45
46impl From<Cow<'_, str>> for SmallString {
47    fn from(s: Cow<'_, str>) -> Self {
48        match s {
49            Cow::Borrowed(s) => Self::from(s),
50            Cow::Owned(s) => Self::from(s),
51        }
52    }
53}
54
55impl AsRef<str> for SmallString {
56    #[inline]
57    fn as_ref(&self) -> &str {
58        &self.0
59    }
60}
61
62impl core::borrow::Borrow<str> for SmallString {
63    #[inline]
64    fn borrow(&self) -> &str {
65        self
66    }
67}
68
69impl Deref for SmallString {
70    type Target = str;
71
72    #[inline]
73    fn deref(&self) -> &Self::Target {
74        &self.0
75    }
76}
77
78impl core::fmt::Debug for SmallString {
79    #[inline]
80    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81        core::fmt::Debug::fmt(&self.0, f)
82    }
83}
84
85impl core::fmt::Display for SmallString {
86    #[inline]
87    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
88        core::fmt::Display::fmt(&self.0, f)
89    }
90}
91
92/// A [`serde::Serialize`] implementation for [`SmallString`].
93impl serde::Serialize for SmallString {
94    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
95    where
96        S: serde::Serializer,
97    {
98        self.0.serialize(serializer)
99    }
100}
101
102impl<'de> serde::Deserialize<'de> for SmallString {
103    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
104        struct Visitor;
105
106        impl serde::de::Visitor<'_> for Visitor {
107            type Value = SmallString;
108
109            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
110                f.write_str("a string")
111            }
112
113            fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
114                Ok(v.into())
115            }
116        }
117
118        deserializer.deserialize_str(Visitor)
119    }
120}
121
122/// An [`rkyv`] implementation for [`SmallString`].
123impl rkyv::Archive for SmallString {
124    type Archived = rkyv::string::ArchivedString;
125    type Resolver = rkyv::string::StringResolver;
126
127    #[inline]
128    fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
129        rkyv::string::ArchivedString::resolve_from_str(&self.0, resolver, out);
130    }
131}
132
133impl<S> rkyv::Serialize<S> for SmallString
134where
135    S: rkyv::rancor::Fallible + rkyv::ser::Allocator + rkyv::ser::Writer + ?Sized,
136    S::Error: rkyv::rancor::Source,
137{
138    fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
139        rkyv::string::ArchivedString::serialize_from_str(&self.0, serializer)
140    }
141}
142
143impl<D: rkyv::rancor::Fallible + ?Sized> rkyv::Deserialize<SmallString, D>
144    for rkyv::string::ArchivedString
145{
146    fn deserialize(&self, _deserializer: &mut D) -> Result<SmallString, D::Error> {
147        Ok(SmallString::from(self.as_str()))
148    }
149}
150
151impl PartialEq<SmallString> for rkyv::string::ArchivedString {
152    fn eq(&self, other: &SmallString) -> bool {
153        **other == **self
154    }
155}
156
157impl PartialOrd<SmallString> for rkyv::string::ArchivedString {
158    fn partial_cmp(&self, other: &SmallString) -> Option<::core::cmp::Ordering> {
159        Some(self.as_str().cmp(other))
160    }
161}
162
163/// An [`schemars::JsonSchema`] implementation for [`SmallString`].
164#[cfg(feature = "schemars")]
165impl schemars::JsonSchema for SmallString {
166    fn inline_schema() -> bool {
167        true
168    }
169
170    fn schema_name() -> Cow<'static, str> {
171        String::schema_name()
172    }
173
174    fn json_schema(generator: &mut schemars::generate::SchemaGenerator) -> schemars::Schema {
175        String::json_schema(generator)
176    }
177}