Skip to main content

xgx_intern/
from_ref.rs

1extern crate alloc;
2
3use alloc::{
4    borrow::ToOwned as _,
5    boxed::Box,
6    ffi::CString,
7    rc::Rc,
8    string::{String, ToString as _},
9    sync::Arc,
10    vec::Vec,
11};
12use core::ffi::CStr;
13
14/// Construct an owned type from a reference.
15///
16/// Similar to [`ToOwned`] or [`Clone`], but it can be implemented on any
17/// combination of base type and `Borrowed` type.
18pub trait FromRef<Borrowed: ?Sized> {
19    /// Construct an owned type from a reference.
20    fn from_ref(val: &Borrowed) -> Self;
21}
22
23// str
24impl FromRef<str> for Box<str> {
25    fn from_ref(val: &str) -> Self {
26        Self::from(val)
27    }
28}
29impl FromRef<str> for Rc<str> {
30    fn from_ref(val: &str) -> Self {
31        Self::from(val)
32    }
33}
34impl FromRef<str> for Arc<str> {
35    fn from_ref(val: &str) -> Self {
36        Self::from(val)
37    }
38}
39impl FromRef<str> for String {
40    fn from_ref(val: &str) -> Self {
41        val.to_string()
42    }
43}
44
45// CStr
46impl FromRef<CStr> for Box<CStr> {
47    fn from_ref(val: &CStr) -> Self {
48        Self::from(val)
49    }
50}
51impl FromRef<CStr> for Rc<CStr> {
52    fn from_ref(val: &CStr) -> Self {
53        Self::from(val)
54    }
55}
56impl FromRef<CStr> for Arc<CStr> {
57    fn from_ref(val: &CStr) -> Self {
58        Self::from(val)
59    }
60}
61impl FromRef<CStr> for CString {
62    fn from_ref(val: &CStr) -> Self {
63        val.to_owned()
64    }
65}
66
67// T
68impl<T: Clone> FromRef<T> for T {
69    fn from_ref(val: &T) -> Self {
70        val.clone()
71    }
72}
73
74// [T]
75impl<T: Clone> FromRef<[T]> for Box<[T]> {
76    fn from_ref(val: &[T]) -> Self {
77        Self::from(val)
78    }
79}
80impl<T: Clone> FromRef<[T]> for Rc<[T]> {
81    fn from_ref(val: &[T]) -> Self {
82        Self::from(val)
83    }
84}
85impl<T: Clone> FromRef<[T]> for Arc<[T]> {
86    fn from_ref(val: &[T]) -> Self {
87        Self::from(val)
88    }
89}
90impl<T: Clone> FromRef<[T]> for Vec<T> {
91    fn from_ref(val: &[T]) -> Self {
92        val.to_vec()
93    }
94}
95
96// Gate the OS-specific ones
97#[cfg(feature = "std")]
98mod os_impls {
99    extern crate std;
100
101    use alloc::{boxed::Box, rc::Rc, sync::Arc};
102    use std::{
103        ffi::{OsStr, OsString},
104        path::{Path, PathBuf},
105    };
106
107    use super::FromRef;
108
109    // OsStr
110    impl FromRef<OsStr> for Box<OsStr> {
111        fn from_ref(val: &OsStr) -> Self {
112            Self::from(val)
113        }
114    }
115    impl FromRef<OsStr> for Rc<OsStr> {
116        fn from_ref(val: &OsStr) -> Self {
117            Self::from(val)
118        }
119    }
120    impl FromRef<OsStr> for Arc<OsStr> {
121        fn from_ref(val: &OsStr) -> Self {
122            Self::from(val)
123        }
124    }
125    impl FromRef<OsStr> for OsString {
126        fn from_ref(val: &OsStr) -> Self {
127            val.to_os_string()
128        }
129    }
130
131    // Path
132    impl FromRef<Path> for Box<Path> {
133        fn from_ref(val: &Path) -> Self {
134            Self::from(val)
135        }
136    }
137    impl FromRef<Path> for Rc<Path> {
138        fn from_ref(val: &Path) -> Self {
139            Self::from(val)
140        }
141    }
142    impl FromRef<Path> for Arc<Path> {
143        fn from_ref(val: &Path) -> Self {
144            Self::from(val)
145        }
146    }
147    impl FromRef<Path> for PathBuf {
148        fn from_ref(val: &Path) -> Self {
149            val.to_path_buf()
150        }
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use alloc::{boxed::Box, ffi::CString, rc::Rc, string::String, sync::Arc, vec::Vec};
157    use core::ffi::CStr;
158
159    use ahash::RandomState;
160
161    use crate::{FromRef, Interner};
162
163    #[cfg(feature = "std")]
164    #[test]
165    fn test_from_ref_system_types() {
166        extern crate std;
167        use std::{
168            ffi::{CString, OsStr, OsString},
169            path::{Path, PathBuf},
170        };
171
172        let mut interner = Interner::<PathBuf, RandomState>::new(RandomState::new());
173        let p = Path::new("/tmp/test");
174        let h = interner.intern_ref(p).unwrap();
175        assert_eq!(interner.resolve(h).unwrap(), p);
176
177        let mut os_interner = Interner::<OsString, RandomState>::new(RandomState::new());
178        let o = OsStr::new("test_os_str");
179        let h_os = os_interner.intern_ref(o).unwrap();
180        assert_eq!(os_interner.resolve(h_os).unwrap(), o);
181
182        // Test CStr
183        let mut c_interner = Interner::<CString, RandomState>::new(RandomState::new());
184        let c = c"hello";
185        let h_c = c_interner.intern_ref(c).unwrap();
186        assert_eq!(c_interner.resolve(h_c).unwrap().as_c_str(), c);
187
188        // Test Box<Path> specifically (different FromRef impl than PathBuf)
189        let mut box_path_interner = Interner::<Box<Path>, RandomState>::new(RandomState::new());
190        let h_bp = box_path_interner.intern_ref(p).unwrap();
191        assert_eq!(&**box_path_interner.resolve(h_bp).unwrap(), p);
192    }
193
194    #[test]
195    fn test_from_ref_identity() {
196        // Test the `impl<T: Clone> FromRef<T> for T` block
197        // We use u32, which is Copy/Clone
198        let mut interner = Interner::<u32, RandomState>::new(RandomState::new());
199        let val = 42u32;
200        // intern_ref takes &Q. Here Q is u32. T is u32.
201        // It should clone the integer.
202        let h = interner.intern_ref(&val).unwrap();
203        assert_eq!(*interner.resolve(h).unwrap(), 42);
204    }
205
206    #[test]
207    fn test_from_ref_slices_generic() {
208        // Test [T] -> Box<[T]>
209        let mut interner = Interner::<Box<[u32]>, RandomState>::new(RandomState::new());
210        let slice: &[u32] = &[1, 2, 3];
211        let h = interner.intern_ref(slice).unwrap();
212        assert_eq!(&**interner.resolve(h).unwrap(), slice);
213
214        // Test [T] -> Rc<[T]>
215        let mut rc_interner = Interner::<Rc<[u32]>, RandomState>::new(RandomState::new());
216        let h_rc = rc_interner.intern_ref(slice).unwrap();
217        assert_eq!(&**rc_interner.resolve(h_rc).unwrap(), slice);
218    }
219
220    // Helper to verify FromRef works for a specific type combo
221    fn assert_from_ref<
222        B: ?Sized + PartialEq + core::fmt::Debug,
223        O: FromRef<B> + core::borrow::Borrow<B> + core::fmt::Debug + PartialEq,
224    >(
225        borrowed: &B,
226        expected: &O,
227    ) {
228        let converted = O::from_ref(borrowed);
229        assert_eq!(&converted, expected);
230        assert_eq!(converted.borrow(), borrowed);
231    }
232
233    #[test]
234    fn test_str_permutations() {
235        let input = "hello";
236
237        // Test String
238        assert_from_ref::<str, String>(input, &String::from("hello"));
239
240        // Test Box<str>
241        let b: Box<str> = Box::from("hello");
242        assert_from_ref::<str, Box<str>>(input, &b);
243
244        // Test Rc<str>
245        let r: Rc<str> = Rc::from("hello");
246        assert_from_ref::<str, Rc<str>>(input, &r);
247
248        // Test Arc<str>
249        let a: Arc<str> = Arc::from("hello");
250        assert_from_ref::<str, Arc<str>>(input, &a);
251    }
252
253    #[test]
254    fn test_cstr_permutations() {
255        let input = c"hello";
256
257        // Test CString
258        assert_from_ref::<CStr, CString>(input, &CString::new("hello").unwrap());
259
260        // Test Box<CStr>
261        let b: Box<CStr> = Box::from(input);
262        assert_from_ref::<CStr, Box<CStr>>(input, &b);
263
264        // Test Rc<CStr>
265        let r: Rc<CStr> = Rc::from(input);
266        assert_from_ref::<CStr, Rc<CStr>>(input, &r);
267
268        // Test Arc<CStr>
269        let a: Arc<CStr> = Arc::from(input);
270        assert_from_ref::<CStr, Arc<CStr>>(input, &a);
271    }
272
273    #[test]
274    fn test_slice_permutations() {
275        let input: &[u8] = &[1, 2, 3];
276
277        // Test Vec<T>
278        assert_from_ref::<[u8], Vec<u8>>(input, &Vec::from(input));
279
280        // Test Box<[T]>
281        let b: Box<[u8]> = Box::from(input);
282        assert_from_ref::<[u8], Box<[u8]>>(input, &b);
283
284        // Test Rc<[T]>
285        let r: Rc<[u8]> = Rc::from(input);
286        assert_from_ref::<[u8], Rc<[u8]>>(input, &r);
287
288        // Test Arc<[T]>
289        let a: Arc<[u8]> = Arc::from(input);
290        assert_from_ref::<[u8], Arc<[u8]>>(input, &a);
291    }
292
293    #[test]
294    fn test_identity_t() {
295        // Test T -> T (Clone)
296        let input = 42;
297        assert_from_ref::<i32, i32>(&input, &42);
298    }
299
300    #[cfg(feature = "std")]
301    #[test]
302    fn test_os_str_permutations() {
303        extern crate std;
304        use std::ffi::{OsStr, OsString};
305
306        let input = OsStr::new("hello");
307
308        // Test OsString
309        assert_from_ref::<OsStr, OsString>(input, &OsString::from("hello"));
310
311        // Test Box<OsStr>
312        let b: Box<OsStr> = Box::from(input);
313        assert_from_ref::<OsStr, Box<OsStr>>(input, &b);
314
315        // Test Rc<OsStr>
316        let r: Rc<OsStr> = Rc::from(input);
317        assert_from_ref::<OsStr, Rc<OsStr>>(input, &r);
318
319        // Test Arc<OsStr>
320        let a: Arc<OsStr> = Arc::from(input);
321        assert_from_ref::<OsStr, Arc<OsStr>>(input, &a);
322    }
323
324    #[cfg(feature = "std")]
325    #[test]
326    fn test_path_permutations() {
327        extern crate std;
328        use std::path::{Path, PathBuf};
329
330        let input = Path::new("/tmp/hello");
331
332        // Test PathBuf
333        assert_from_ref::<Path, PathBuf>(input, &PathBuf::from("/tmp/hello"));
334
335        // Test Box<Path>
336        let b: Box<Path> = Box::from(input);
337        assert_from_ref::<Path, Box<Path>>(input, &b);
338
339        // Test Rc<Path>
340        let r: Rc<Path> = Rc::from(input);
341        assert_from_ref::<Path, Rc<Path>>(input, &r);
342
343        // Test Arc<Path>
344        let a: Arc<Path> = Arc::from(input);
345        assert_from_ref::<Path, Arc<Path>>(input, &a);
346    }
347}