anathema_strings/
lib.rs

1// NOTE: On a second go-around we can consider removing the buffer and pre-compute the required
2//       space with some exceptions
3
4use region::Region;
5use storage::Storage;
6pub use storage::Transaction;
7
8mod region;
9mod storage;
10
11static BUCKET_SIZE: usize = 128;
12
13#[derive(Debug, Copy, Clone, PartialEq)]
14pub struct StrIndex {
15    index: u32,
16    len: u32,
17}
18
19impl StrIndex {
20    fn new(index: usize, len: usize) -> Self {
21        Self {
22            index: index as u32,
23            len: len as u32,
24        }
25    }
26
27    fn to_region(self) -> Region {
28        let padding = self.len % BUCKET_SIZE as u32;
29        Region {
30            start: self.index,
31            len: self.len + padding,
32        }
33    }
34}
35
36impl From<(u32, u32)> for StrIndex {
37    fn from((index, len): (u32, u32)) -> Self {
38        Self { index, len }
39    }
40}
41
42pub struct HStrings<'slice> {
43    inner: Storage<'slice>,
44}
45
46impl<'slice> HStrings<'slice> {
47    pub fn empty() -> Self {
48        Self {
49            inner: Storage::empty(),
50        }
51    }
52
53    pub fn insert_with<F>(&mut self, f: F) -> StrIndex
54    where
55        F: FnOnce(&mut Transaction<'_, 'slice>),
56    {
57        let mut tx = self.inner.begin_insert();
58        f(&mut tx);
59        tx.commit()
60    }
61
62    pub fn get(&self, hstr: StrIndex) -> HString<impl Iterator<Item = &str> + Clone> {
63        let iter = self.inner.get(hstr);
64        HString { inner: iter }
65    }
66
67    pub fn remove(&mut self, hstr: StrIndex) {
68        self.inner.remove(hstr);
69    }
70}
71
72pub struct HString<I> {
73    inner: I,
74}
75
76impl<'hstr, I> Iterator for HString<I>
77where
78    I: Iterator<Item = &'hstr str>,
79{
80    type Item = &'hstr str;
81
82    fn next(&mut self) -> Option<Self::Item> {
83        self.inner.next()
84    }
85}
86
87impl<'hstr, I> std::fmt::Debug for HString<I>
88where
89    I: Iterator<Item = &'hstr str>,
90    I: Clone,
91{
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        let iter = self.inner.clone();
94        for s in iter {
95            s.fmt(f)?;
96        }
97        Ok(())
98    }
99}
100
101impl<'hstr, I> std::fmt::Display for HString<I>
102where
103    I: Iterator<Item = &'hstr str>,
104    I: Clone,
105{
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        let iter = self.inner.clone();
108        for s in iter {
109            s.fmt(f)?;
110        }
111        Ok(())
112    }
113}
114
115// -----------------------------------------------------------------------------
116//   - Equality -
117// -----------------------------------------------------------------------------
118
119impl<'hstr, A, B> PartialEq<HString<B>> for HString<A>
120where
121    A: Iterator<Item = &'hstr str>,
122    A: Clone,
123    B: Iterator<Item = &'hstr str>,
124    B: Clone,
125{
126    fn eq(&self, other: &HString<B>) -> bool {
127        let mut lhs = self.inner.clone();
128        let mut rhs = other.inner.clone();
129
130        loop {
131            let a = lhs.next();
132            let b = rhs.next();
133            if a != b {
134                return false;
135            }
136
137            if a.is_none() && b.is_none() {
138                break true;
139            }
140        }
141    }
142}
143
144impl<'hstr, I> PartialEq<str> for HString<I>
145where
146    I: Iterator<Item = &'hstr str>,
147    I: Clone,
148{
149    fn eq(&self, mut other: &str) -> bool {
150        let iter = self.inner.clone();
151
152        for s in iter {
153            if s != &other[..s.len()] {
154                return false;
155            }
156            other = &other[s.len()..];
157        }
158        other.is_empty()
159    }
160}
161
162impl<'hstr, I> PartialEq<&str> for HString<I>
163where
164    I: Iterator<Item = &'hstr str>,
165    I: Clone,
166{
167    fn eq(&self, other: &&str) -> bool {
168        self == *other
169    }
170}
171
172impl<'hstr, I> PartialEq<HString<I>> for &str
173where
174    I: Iterator<Item = &'hstr str>,
175    I: Clone,
176{
177    fn eq(&self, other: &HString<I>) -> bool {
178        other.eq(self)
179    }
180}
181
182#[cfg(test)]
183mod test {
184    use std::fmt::Write;
185
186    use super::*;
187
188    #[test]
189    fn basic() {
190        let mut strings = HStrings::empty();
191        let hstr = strings.insert_with(|tx| {
192            tx.add_slice("hello");
193            tx.add_slice(" ");
194            tx.add_slice("world");
195        });
196        let s = strings.get(hstr);
197
198        assert_eq!("hello world", s);
199    }
200
201    #[test]
202    fn write_borrowed_and_owned() {
203        let mut strings = HStrings::empty();
204        let hstr = strings.insert_with(|tx| {
205            tx.add_slice("hello");
206            write!(tx, " ").unwrap();
207            tx.add_slice("world");
208        });
209        let s = strings.get(hstr);
210
211        assert_eq!(s, "hello world");
212        assert_eq!("hello world", s);
213    }
214
215    #[test]
216    fn empty_str() {
217        let mut strings = HStrings::empty();
218        let hstr = strings.insert_with(|_| {});
219        let s = strings.get(hstr);
220        assert!("hello world" != s);
221    }
222}