strmap/
pathmap.rs

1use std::convert::AsRef;
2use std::fmt;
3use std::path::{Path, PathBuf};
4
5use crate::{StrMap, StrMapConfig};
6
7type Result<T, E = fst::Error> = std::result::Result<T, E>;
8type InsertResult<R> = std::result::Result<R, InsertDuplicateError>;
9
10#[cfg(unix)]
11pub fn path_to_bytes<F, T>(path: &Path, func: F) -> T
12where
13    F: FnOnce(&[u8]) -> T,
14{
15    use std::os::unix::ffi::OsStrExt;
16
17    func(path.as_os_str().as_bytes())
18}
19
20#[cfg(unix)]
21pub fn bytes_to_path(path: &[u8]) -> PathBuf {
22    use std::ffi::OsStr;
23    use std::os::unix::ffi::OsStrExt;
24
25    Path::new(OsStr::from_bytes(path)).to_path_buf()
26}
27
28#[cfg(windows)]
29pub fn path_to_bytes<F, T>(path: &Path, func: F) -> T
30where
31    F: FnOnce(&[u8]) -> T,
32{
33    use std::char::decode_utf16;
34    use std::os::windows::ffi::OsStrExt;
35
36    let iter = decode_utf16(path.as_os_str().encode_wide());
37
38    let mut byte_repr = Vec::new();
39    let mut buf = [0; 4];
40    for item in iter {
41        match item {
42            Ok(c) => {
43                let slice = c.encode_utf8(&mut buf).as_bytes();
44                if slice == b"\\" {
45                    byte_repr.push(b'/');
46                } else {
47                    byte_repr.extend_from_slice(slice);
48                }
49            }
50            Err(err) => {
51                byte_repr.push(0xff);
52                byte_repr.extend_from_slice(&u16::to_le_bytes(err.unpaired_surrogate()));
53            }
54        }
55    }
56
57    func(&byte_repr)
58}
59
60#[cfg(windows)]
61pub fn bytes_to_path(mut path: &[u8]) -> PathBuf {
62    use std::ffi::OsString;
63    use std::os::windows::ffi::OsStringExt;
64
65    let mut wide: Vec<u16> = Vec::with_capacity(path.len());
66    while path.len() > 0 {
67        let stop = path.iter().position(|i| *i == 0xff).unwrap_or(path.len());
68
69        if stop > 0 {
70            let (chunk, next_path) = path.split_at(stop);
71            path = next_path;
72
73            let chunk = std::str::from_utf8(chunk).unwrap();
74            wide.extend(chunk.encode_utf16());
75        } else {
76            wide.push(u16::from_le_bytes([path[1], path[2]]));
77            path = &path[3..];
78        }
79    }
80
81    OsString::from_wide(&wide).into()
82}
83
84/// A map from path to T.
85pub struct PathMap<T> {
86    inner: StrMap<T>,
87}
88
89impl<T> PathMap<T> {
90    pub fn empty() -> Self {
91        Self {
92            inner: StrMap::empty(),
93        }
94    }
95
96    pub fn len(&self) -> usize {
97        self.inner.len()
98    }
99
100    pub fn insert(&mut self, key: &Path, value: T) -> InsertResult<()> {
101        path_to_bytes(key, |key| self.inner.insert(key, value))
102            .map_err(|_| InsertDuplicateError::new(key))
103    }
104
105    pub fn insert_many<P: AsRef<Path>>(
106        &mut self,
107        keys: &[P],
108        vals: Vec<T>,
109        opts: &StrMapConfig,
110    ) -> Result<()> {
111        let len = keys.len();
112        assert_eq!(vals.len(), len);
113        let mut keys_data = Vec::new();
114        let mut keys_idx = Vec::with_capacity(len + 1);
115        keys_idx.push(0);
116
117        for key in keys {
118            let key = key.as_ref();
119            let start = keys_data.len();
120            path_to_bytes(key, |key| keys_data.extend_from_slice(key));
121            keys_idx.push(keys_data.len());
122
123            if self.inner.has_key(&keys_data[start..]) {
124                return Err(InsertDuplicateError::new(key).into_fst());
125            }
126        }
127
128        let mut keys_dupe = std::collections::HashSet::new();
129        let mut key_args = Vec::with_capacity(len);
130        for i in 0..len {
131            let key = &keys_data[keys_idx[i]..keys_idx[i + 1]];
132            if !keys_dupe.insert(key) {
133                return Err(InsertDuplicateError::new(keys[i].as_ref()).into_fst());
134            }
135            key_args.push(key);
136        }
137        drop(keys_dupe);
138        drop(keys_idx);
139
140        self.inner.insert_many_unchecked(&key_args, vals, opts)
141    }
142
143    pub fn first(&self) -> Option<(PathBuf, &T)> {
144        self.inner
145            .first()
146            .map(|(path, item)| (bytes_to_path(&path), item))
147    }
148
149    pub fn next(&self, curr: &Path) -> Option<(PathBuf, &T)> {
150        path_to_bytes(curr, |curr| self.inner.next(curr))
151            .map(|(path, item)| (bytes_to_path(&path), item))
152    }
153
154    pub fn should_rebalance(&self) -> bool {
155        self.inner.should_rebalance()
156    }
157
158    pub fn rebalance(&mut self, opts: &StrMapConfig) -> Result<()> {
159        self.inner.rebalance(opts)
160    }
161
162    pub fn has_key(&self, key: &Path) -> bool {
163        path_to_bytes(key, |key| self.inner.has_key(key))
164    }
165
166    pub fn get(&self, key: &Path) -> Option<&T> {
167        path_to_bytes(key, |key| self.inner.get(key))
168    }
169
170    pub fn get_mut(&mut self, key: &Path) -> Option<&mut T> {
171        path_to_bytes(key, |key| self.inner.get_mut(key))
172    }
173
174    pub fn delete(&mut self, key: &Path) -> bool {
175        path_to_bytes(key, |key| self.inner.delete(key))
176    }
177}
178
179#[derive(Debug)]
180pub struct InsertDuplicateError {
181    key: PathBuf,
182}
183
184impl InsertDuplicateError {
185    fn new(key: &Path) -> Self {
186        Self {
187            key: key.to_path_buf(),
188        }
189    }
190
191    pub fn key(&self) -> &Path {
192        &self.key
193    }
194
195    fn into_io(self) -> std::io::Error {
196        std::io::Error::new(std::io::ErrorKind::AlreadyExists, self)
197    }
198
199    fn into_fst(self) -> fst::Error {
200        self.into_io().into()
201    }
202}
203
204impl std::error::Error for InsertDuplicateError {}
205
206impl fmt::Display for InsertDuplicateError {
207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        write!(
209            f,
210            "trying to insert at existing key \"{}\"",
211            self.key.display()
212        )
213    }
214}