Browse Source

Improved performance when constructing StoredStrings from owned containers.

Kestrel 2 months ago
parent
commit
fe1d3e9c4a
2 changed files with 76 additions and 12 deletions
  1. 1 1
      Cargo.toml
  2. 75 11
      src/lib.rs

+ 1 - 1
Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "stringstore"
-version = "0.1.4"
+version = "0.1.5"
 edition = "2021"
 author = "kestrel <kestrel@flying-kestrel.ca>"
 repository = "https://git.flying-kestrel.ca/kestrel/stringstore"

+ 75 - 11
src/lib.rs

@@ -135,10 +135,22 @@ impl<Tag> StoredString<Tag> {
             None => {
                 let s = Box::leak(from.to_owned().into_boxed_str());
                 mg.insert(s);
-                Self {
-                    stored: mg.get(from).unwrap(),
-                    _ghost: Default::default(),
-                }
+                Self { stored: s, _ghost: Default::default() }
+            }
+        }
+    }
+
+    pub fn new_from_string(from: String) -> Self {
+        let mut mg = STR_STORE.lock().expect("couldn't lock STR_STORE?");
+        match mg.get(from.as_str()) {
+            Some(name) => Self {
+                stored: name,
+                _ghost: Default::default(),
+            },
+            None => {
+                let s = Box::leak(from.into_boxed_str());
+                mg.insert(s);
+                Self { stored: s, _ghost: Default::default() }
             }
         }
     }
@@ -168,8 +180,8 @@ impl<'de, Tag: 'static> serde::de::Visitor<'de> for StoredStringVisitor<Tag> {
         write!(formatter, "stored string")
     }
 
-    fn visit_borrowed_str<E: serde::de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
-        Ok(StoredString::new(v))
+    fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
+        Ok(v.into())
     }
 
     fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
@@ -199,7 +211,7 @@ impl<Tag> serde::ser::Serialize for StoredString<Tag> {
 
 impl<Tag: 'static> From<String> for StoredString<Tag> {
     fn from(value: String) -> Self {
-        Self::new(value.as_str())
+        Self::new_from_string(value)
     }
 }
 
@@ -296,7 +308,7 @@ static OS_STR_STORE: std::sync::LazyLock<
     std::sync::Mutex<std::collections::HashSet<&'static OsStr>>,
 > = std::sync::LazyLock::new(Default::default);
 
-/// See crate documentation for general description.
+/// Variant of [`StoredString`] that stores an [`OsStr`] instead of a `str`
 pub struct StoredOsString<Tag: 'static> {
     stored: &'static OsStr,
     _ghost: std::marker::PhantomData<Tag>,
@@ -364,7 +376,7 @@ impl<Tag: 'static> Ord for StoredOsString<Tag> {
 
 impl<Tag> StoredOsString<Tag> {
     pub fn new(from: &OsStr) -> Self {
-        let mut mg = OS_STR_STORE.lock().expect("couldn't lock STR_STORE?");
+        let mut mg = OS_STR_STORE.lock().expect("couldn't lock OS_STR_STORE?");
         match mg.get(from) {
             Some(name) => Self {
                 stored: name,
@@ -374,7 +386,48 @@ impl<Tag> StoredOsString<Tag> {
                 let s = Box::leak(from.to_owned().into_boxed_os_str());
                 mg.insert(s);
                 Self {
-                    stored: mg.get(from).unwrap(),
+                    stored: s,
+                    _ghost: Default::default(),
+                }
+            }
+        }
+    }
+
+    pub fn new_from_string(from: OsString) -> Self {
+        let mut mg = OS_STR_STORE.lock().expect("couldn't lock OS_STR_STORE?");
+        match mg.get(from.as_os_str()) {
+            Some(name) => Self {
+                stored: name,
+                _ghost: Default::default(),
+            },
+            None => {
+                let s = Box::leak(from.into_boxed_os_str());
+                mg.insert(s);
+                Self {
+                    stored: s,
+                    _ghost: Default::default(),
+                }
+            }
+        }
+    }
+
+    #[cfg(target_os = "linux")]
+    pub fn new_from_vec(from: Vec<u8>) -> Self {
+        use std::os::unix::ffi::OsStrExt;
+
+        let mut mg = OS_STR_STORE.lock().expect("couldn't lock OS_STR_STORE?");
+        let from_str = OsStr::from_bytes(from.as_slice());
+
+        match mg.get(from_str) {
+            Some(name) => Self {
+                stored: name,
+                _ghost: Default::default(),
+            },
+            None => {
+                let s = OsStr::from_bytes(Box::leak(from.into_boxed_slice()));
+                mg.insert(s);
+                Self {
+                    stored: s,
                     _ghost: Default::default(),
                 }
             }
@@ -407,7 +460,11 @@ impl<'de, Tag: 'static> serde::de::Visitor<'de> for StoredOsStringVisitor<Tag> {
     }
 
     fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
-        Ok(StoredOsString::from(v))
+        Ok(v.into())
+    }
+
+    fn visit_byte_buf<E: serde::de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
+        Ok(v.into())
     }
 }
 
@@ -456,3 +513,10 @@ impl<'l, Tag: 'static> From<&'l [u8]> for StoredOsString<Tag> {
         OsStr::from_bytes(value).into()
     }
 }
+
+#[cfg(target_os = "linux")]
+impl<'l, Tag: 'static> From<Vec<u8>> for StoredOsString<Tag> {
+    fn from(value: Vec<u8>) -> Self {
+        Self::new_from_vec(value)
+    }
+}