1use 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
115impl<'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}