string_hash_interner/
intern.rs

1use core::{ffi::CStr, fmt::Debug, hash::Hash};
2
3/// Trait implemented by different types of strings that can be interned.
4///
5/// # Safety
6///
7/// It should be alwas valid to reinterpret bytes of `Self` as `&[Self::Primitive]`
8/// using [`Intern::as_bytes`].
9///
10/// It should be valid to reinterpret bytes copied from [`Intern::as_bytes`].
11/// as `&Self` using [`Intern::from_bytes`]. Even if they were moved in memory.
12pub unsafe trait Intern: Hash + PartialEq + Eq {
13    /// A primitive type that has the same alignment as `Self`.
14    type Primitive: Sized + Copy + Debug;
15
16    fn as_bytes(&self) -> &[Self::Primitive];
17
18    /// # Safety
19    ///
20    /// See [Safety section](Intern#safety) in the trait doc.
21    unsafe fn from_bytes(bytes: &[Self::Primitive]) -> &Self;
22}
23
24unsafe impl Intern for str {
25    type Primitive = u8;
26
27    fn as_bytes(&self) -> &[u8] {
28        str::as_bytes(self)
29    }
30
31    unsafe fn from_bytes(bytes: &[u8]) -> &Self {
32        // SAFETY: Calling this function is only valid with bytes obtained from `Self::as_bytes`.
33        unsafe { core::str::from_utf8_unchecked(bytes) }
34    }
35}
36
37unsafe impl Intern for CStr {
38    type Primitive = u8;
39
40    fn as_bytes(&self) -> &[u8] {
41        CStr::to_bytes_with_nul(self)
42    }
43
44    unsafe fn from_bytes(bytes: &[u8]) -> &Self {
45        // SAFETY: Calling this function is only valid with bytes obtained from `Self::as_bytes`.
46        unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }
47    }
48}
49
50unsafe impl Intern for [u8] {
51    type Primitive = u8;
52
53    fn as_bytes(&self) -> &[u8] {
54        self
55    }
56
57    unsafe fn from_bytes(bytes: &[u8]) -> &Self {
58        bytes
59    }
60}
61
62unsafe impl Intern for [char] {
63    type Primitive = char;
64
65    fn as_bytes(&self) -> &[char] {
66        self
67    }
68
69    unsafe fn from_bytes(bytes: &[char]) -> &Self {
70        bytes
71    }
72}
73
74#[cfg(feature = "std")]
75mod std_impls {
76    use super::Intern;
77    use std::ffi::OsStr;
78
79    unsafe impl Intern for OsStr {
80        type Primitive = u8;
81
82        fn as_bytes(&self) -> &[u8] {
83            OsStr::as_encoded_bytes(self)
84        }
85
86        unsafe fn from_bytes(bytes: &[u8]) -> &Self {
87            // SAFETY: Calling this function is only valid with bytes obtained from `Self::as_bytes`.
88            unsafe { OsStr::from_encoded_bytes_unchecked(bytes) }
89        }
90    }
91}
92
93// TODO: add impl for `[std::ascii::Char]` when stable.