interning/
lib.rs

1pub use crate::hash::InternedStringHash;
2use crate::lookup::{local_intern, local_lookup};
3use crate::serde_util::BorrowedStrVisitor;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt::{Debug, Display};
6use std::ops::Deref;
7use std::str::FromStr;
8use std::sync::Arc;
9pub mod hash;
10pub mod lookup;
11mod serde_util;
12mod utils;
13
14#[derive(Clone, PartialEq, Eq, Hash, Copy)]
15pub struct InternedString {
16    hash: InternedStringHash,
17}
18
19impl InternedString {
20    pub fn new(s: impl Into<String>) -> InternedString {
21        let string = s.into();
22        let hash = InternedStringHash::from_str(&string);
23        if !hash.is_inlined() {
24            local_intern(hash, string);
25        }
26        InternedString { hash }
27    }
28    pub fn from_str(s: &str) -> InternedString {
29        let hash = InternedStringHash::from_str(s);
30        if !hash.is_inlined() {
31            let looked_up = local_lookup(hash);
32            if looked_up.is_none() {
33                let string = s.to_string();
34                local_intern(hash, string);
35            }
36        }
37        InternedString { hash }
38    }
39
40    /// Build a InternedString from a hash. Use with caution as the hash may not be valid.
41    pub unsafe fn from_hash(hash: InternedStringHash) -> InternedString {
42        InternedString { hash }
43    }
44    pub fn as_str(&self) -> &str {
45        if self.hash.is_inlined() {
46            self.hash.get_inlined_str()
47        } else {
48            local_lookup(self.hash).unwrap()
49        }
50    }
51    pub fn hash(&self) -> InternedStringHash {
52        self.hash
53    }
54}
55impl<'a> From<&'a str> for InternedString {
56    fn from(s: &'a str) -> Self {
57        InternedString::from_str(s)
58    }
59}
60impl From<String> for InternedString {
61    fn from(s: String) -> Self {
62        InternedString::new(s)
63    }
64}
65impl From<Box<str>> for InternedString {
66    fn from(s: Box<str>) -> Self {
67        let s = String::from(s);
68        InternedString::new(s)
69    }
70}
71impl From<Arc<str>> for InternedString {
72    fn from(s: Arc<str>) -> Self {
73        let s = String::from(s.as_ref());
74        InternedString::new(s)
75    }
76}
77impl Into<String> for InternedString {
78    fn into(self) -> String {
79        self.as_str().to_string()
80    }
81}
82impl Into<Box<str>> for InternedString {
83    fn into(self) -> Box<str> {
84        self.as_str().into()
85    }
86}
87impl Into<Arc<str>> for InternedString {
88    fn into(self) -> Arc<str> {
89        self.as_str().into()
90    }
91}
92impl FromStr for InternedString {
93    type Err = std::convert::Infallible;
94    fn from_str(s: &str) -> Result<Self, Self::Err> {
95        Ok(InternedString::from_str(s))
96    }
97}
98impl AsRef<str> for InternedString {
99    fn as_ref(&self) -> &str {
100        self.as_str()
101    }
102}
103impl Deref for InternedString {
104    type Target = str;
105
106    fn deref(&self) -> &Self::Target {
107        self.as_str()
108    }
109}
110impl Display for InternedString {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        Display::fmt(self.as_str(), f)
113    }
114}
115impl Debug for InternedString {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        Debug::fmt(self.as_str(), f)
118    }
119}
120impl Serialize for InternedString {
121    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
122    where
123        S: Serializer,
124    {
125        self.as_str().serialize(serializer)
126    }
127}
128
129impl<'de> Deserialize<'de> for InternedString {
130    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
131    where
132        D: Deserializer<'de>,
133    {
134        let val = deserializer.deserialize_str(BorrowedStrVisitor)?;
135        Ok(InternedString::from_str(val))
136    }
137}
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn test_small_strings() {
144        let s = "hello";
145        let interned = InternedString::from_str(s);
146        assert_eq!(interned.as_str(), s);
147        let interned = InternedString::from_str(s);
148        assert_eq!(interned.as_str(), s);
149    }
150}