1use std::fmt;
12
13use crate::buffer::Buffer;
14
15#[derive(Clone)]
17pub struct StrBuffer {
18 offsets: Buffer<i64>,
20 data: Buffer<u8>,
22}
23
24impl StrBuffer {
25 #[inline]
27 pub fn from_vec(v: Vec<String>) -> Self {
28 v.into_iter().collect()
29 }
30
31 #[inline]
33 pub fn from_buffers(offsets: Buffer<i64>, data: Buffer<u8>) -> Self {
34 StrBuffer { offsets, data }
35 }
36
37 #[inline]
39 pub fn buffers(&self) -> (&Buffer<i64>, &Buffer<u8>) {
40 (&self.offsets, &self.data)
41 }
42
43 #[inline]
44 pub fn len(&self) -> usize {
45 self.offsets.len().saturating_sub(1)
46 }
47
48 #[inline]
49 pub fn is_empty(&self) -> bool {
50 self.len() == 0
51 }
52
53 #[inline]
55 pub fn get(&self, i: usize) -> &str {
56 let off = self.offsets.as_slice();
57 let (s, e) = (off[i] as usize, off[i + 1] as usize);
58 unsafe { std::str::from_utf8_unchecked(&self.data.as_slice()[s..e]) }
61 }
62
63 #[inline]
72 pub unsafe fn get_unchecked(&self, i: usize) -> &str {
73 let off = self.offsets.as_slice();
74 let (s, e) = (*off.get_unchecked(i) as usize, *off.get_unchecked(i + 1) as usize);
75 std::str::from_utf8_unchecked(self.data.as_slice().get_unchecked(s..e))
76 }
77
78 #[inline]
83 pub fn iter(&self) -> impl Iterator<Item = &str> + '_ {
84 let off = self.offsets.as_slice();
85 let data = self.data.as_slice();
86 (0..self.len()).map(move |i| {
87 unsafe {
90 let s = *off.get_unchecked(i) as usize;
91 let e = *off.get_unchecked(i + 1) as usize;
92 std::str::from_utf8_unchecked(data.get_unchecked(s..e))
93 }
94 })
95 }
96
97 pub fn to_vec(&self) -> Vec<String> {
99 self.iter().map(String::from).collect()
100 }
101
102 pub fn slice(&self, start: usize, end: usize) -> StrBuffer {
105 (start..end).map(|i| self.get(i)).collect()
106 }
107
108 pub fn extend<S: AsRef<str>>(&mut self, items: impl IntoIterator<Item = S>) {
113 let data = self.data.make_mut();
114 let offsets = self.offsets.make_mut();
115 for s in items {
116 data.extend_from_slice(s.as_ref().as_bytes());
117 offsets.push(data.len() as i64);
118 }
119 }
120}
121
122#[derive(Default)]
124pub struct StrBufferBuilder {
125 offsets: Vec<i64>,
126 data: Vec<u8>,
127}
128
129impl StrBufferBuilder {
130 pub fn with_capacity(n: usize) -> Self {
131 let mut offsets = Vec::with_capacity(n + 1);
132 offsets.push(0);
133 StrBufferBuilder { offsets, data: Vec::new() }
134 }
135 #[inline]
136 pub fn push(&mut self, s: &str) {
137 self.data.extend_from_slice(s.as_bytes());
138 self.offsets.push(self.data.len() as i64);
139 }
140 pub fn finish(mut self) -> StrBuffer {
141 if self.offsets.is_empty() {
142 self.offsets.push(0);
143 }
144 StrBuffer {
145 offsets: Buffer::from_vec(self.offsets),
146 data: Buffer::from_vec(self.data),
147 }
148 }
149}
150
151impl PartialEq for StrBuffer {
152 fn eq(&self, other: &Self) -> bool {
153 self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
154 }
155}
156
157impl fmt::Debug for StrBuffer {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 f.debug_list().entries(self.iter()).finish()
160 }
161}
162
163impl<S: AsRef<str>> FromIterator<S> for StrBuffer {
164 fn from_iter<I: IntoIterator<Item = S>>(it: I) -> Self {
167 let mut offsets = vec![0i64];
168 let mut data = Vec::new();
169 for s in it {
170 data.extend_from_slice(s.as_ref().as_bytes());
171 offsets.push(data.len() as i64);
172 }
173 StrBuffer {
174 offsets: Buffer::from_vec(offsets),
175 data: Buffer::from_vec(data),
176 }
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn build_access_and_emptiness() {
186 let sb = StrBuffer::from_vec(vec!["a".into(), "".into(), "cd".into()]);
187 assert_eq!(sb.len(), 3);
188 assert!(!sb.is_empty());
189 assert_eq!(sb.get(2), "cd");
190 assert_eq!(unsafe { sb.get_unchecked(1) }, "");
192 assert_eq!(sb.iter().collect::<Vec<_>>(), ["a", "", "cd"]);
193 assert_eq!(sb.to_vec(), vec!["a".to_string(), "".into(), "cd".into()]);
194 assert!(StrBuffer::from_vec(vec![]).is_empty());
195 }
196
197 #[test]
198 fn buffers_round_trip_zero_copy() {
199 let sb = StrBuffer::from_vec(vec!["xy".into(), "z".into()]);
201 let (offsets, data) = sb.buffers();
202 let rebuilt = StrBuffer::from_buffers(offsets.clone(), data.clone());
203 assert_eq!(rebuilt, sb);
204 assert_eq!(rebuilt.slice(1, 2), StrBuffer::from_vec(vec!["z".into()]));
205 }
206
207 #[test]
208 fn builder_default_finishes_empty() {
209 let empty = StrBufferBuilder::default().finish();
211 assert!(empty.is_empty());
212 let mut b = StrBufferBuilder::with_capacity(2);
213 b.push("p");
214 b.push("qr");
215 assert_eq!(b.finish(), StrBuffer::from_vec(vec!["p".into(), "qr".into()]));
216 }
217
218 #[test]
219 fn debug_lists_cells() {
220 let sb = StrBuffer::from_vec(vec!["a".into(), "b".into()]);
221 assert_eq!(format!("{sb:?}"), r#"["a", "b"]"#);
222 }
223}