Skip to main content

turtle_build/
path_pool.rs

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