Skip to main content

turtle_build/
path_pool.rs

1use alloc::sync::Arc;
2use rapidhash::fast::RandomState;
3use scc::HashSet;
4
5/// A path pool.
6#[derive(Debug, Default)]
7pub struct PathPool {
8    paths: HashSet<Arc<str>, RandomState>,
9}
10
11impl PathPool {
12    /// Creates a path pool.
13    pub fn new() -> Self {
14        Self::default()
15    }
16
17    /// Interns a path.
18    pub fn intern(&self, path: &str) -> Arc<str> {
19        self.paths.read_sync(path, Clone::clone).unwrap_or_else(|| {
20            // Another thread might intern the same path at the same time.
21            let _ = self.paths.insert_sync(path.into());
22
23            self.intern(path)
24        })
25    }
26}
27
28#[cfg(test)]
29mod tests {
30    use super::*;
31    use pretty_assertions::assert_eq;
32
33    #[test]
34    fn intern_path() {
35        assert_eq!(PathPool::new().intern("foo"), "foo".into());
36    }
37
38    #[test]
39    fn intern_same_path_twice() {
40        let pool = PathPool::new();
41
42        assert!(Arc::ptr_eq(&pool.intern("foo"), &pool.intern("foo")));
43    }
44
45    #[test]
46    fn intern_different_paths() {
47        let pool = PathPool::new();
48
49        assert_eq!(pool.intern("foo"), "foo".into());
50        assert_eq!(pool.intern("bar"), "bar".into());
51    }
52
53    #[test]
54    fn intern_same_path_after_different_path() {
55        let pool = PathPool::new();
56        let path = pool.intern("foo");
57
58        pool.intern("bar");
59
60        assert!(Arc::ptr_eq(&path, &pool.intern("foo")));
61    }
62}