vec_strings/
strings_no_index.rs1use std::convert::TryInto;
2use std::iter::{ExactSizeIterator, IntoIterator, Iterator};
3use std::str;
4
5use thin_vec::ThinVec;
6
7#[derive(Debug, Default, Eq, PartialEq, Clone, Hash)]
12pub struct StringsNoIndex {
13 strs: ThinVec<u8>,
14}
15
16impl StringsNoIndex {
17 pub fn new() -> Self {
18 Self::default()
19 }
20
21 pub fn with_capacity(_len: u32) -> Self {
26 Self::new()
27 }
28
29 fn set_len(&mut self, new_len: u32) {
30 self.strs[..4].copy_from_slice(&new_len.to_ne_bytes());
31 }
32
33 pub fn len(&self) -> u32 {
34 if self.is_empty() {
35 0
36 } else {
37 u32::from_ne_bytes(self.strs[..4].try_into().unwrap())
38 }
39 }
40
41 pub fn is_empty(&self) -> bool {
42 self.strs.is_empty()
43 }
44
45 pub fn push(&mut self, s: &str) {
47 if self.is_empty() {
48 let len: u32 = 1;
49 self.strs.extend_from_slice(&len.to_ne_bytes());
50 } else {
51 let len = self.len();
52
53 if len == u32::MAX {
54 panic!(
55 "StringsNoIndex cannot contain more than u32::MAX {} elements",
56 u32::MAX
57 );
58 }
59
60 self.set_len(len + 1);
61 }
62
63 self.strs
64 .extend(s.as_bytes().iter().copied().filter(|byte| *byte != b'\0'));
65 self.strs.push(0);
66 }
67
68 #[inline(always)]
70 pub fn strs_len(&self) -> usize {
71 self.strs.len()
72 }
73
74 #[inline(always)]
75 pub fn reserve_strs(&mut self, cnt: usize) {
76 self.strs.reserve(cnt);
77 }
78
79 pub fn shrink_to_fit(&mut self) {
80 self.strs.shrink_to_fit();
81 }
82
83 #[inline(always)]
84 pub fn iter(&self) -> StringsNoIndexIter<'_> {
85 let slice = if self.is_empty() {
86 &[]
87 } else {
88 &self.strs[4..]
89 };
90 StringsNoIndexIter::new(slice, self.len())
91 }
92}
93impl<'a> IntoIterator for &'a StringsNoIndex {
94 type Item = &'a str;
95 type IntoIter = StringsNoIndexIter<'a>;
96
97 #[inline(always)]
98 fn into_iter(self) -> Self::IntoIter {
99 self.iter()
100 }
101}
102
103#[derive(Clone, Debug)]
104pub struct StringsNoIndexIter<'a>(&'a [u8], u32);
105
106impl<'a> StringsNoIndexIter<'a> {
107 fn new(strs: &'a [u8], len: u32) -> Self {
108 Self(strs, len)
109 }
110}
111
112impl<'a> Iterator for StringsNoIndexIter<'a> {
113 type Item = &'a str;
114
115 fn next(&mut self) -> Option<Self::Item> {
116 if self.0.is_empty() {
117 return None;
118 }
119
120 self.1 -= 1;
121
122 let pos = self.0.iter().position(|byte| *byte == 0).unwrap();
123 let slice = &self.0[..pos];
124 self.0 = &self.0[(pos + 1)..];
125 Some(unsafe { str::from_utf8_unchecked(slice) })
126 }
127
128 fn size_hint(&self) -> (usize, Option<usize>) {
129 let len = self.1 as usize;
130 (len, Some(len))
131 }
132}
133
134impl ExactSizeIterator for StringsNoIndexIter<'_> {}
135
136#[cfg(test)]
137mod tests {
138 use super::StringsNoIndex;
139
140 fn assert_strs_in(strs: &StringsNoIndex, input_strs: &Vec<String>) {
141 for (string, input_str) in strs.iter().zip(input_strs) {
142 assert_eq!(string, input_str);
143 }
144 }
145
146 #[test]
147 fn test() {
148 let mut strs = StringsNoIndex::new();
149 let input_strs: Vec<String> = (0..256).map(|n| n.to_string()).collect();
150
151 assert!(strs.is_empty());
152
153 for (i, input_str) in input_strs.iter().enumerate() {
154 strs.push(input_str);
155 assert_eq!(strs.len() as usize, i + 1);
156
157 assert_strs_in(&strs, &input_strs);
158 }
159
160 assert!(!strs.is_empty());
161
162 assert!(input_strs.iter().eq(strs.iter()));
163 }
164
165 #[test]
166 fn test_adding_empty_strs() {
167 let mut strs = StringsNoIndex::new();
168
169 assert!(strs.is_empty());
170
171 for i in 0..10 {
172 strs.push("");
173 assert_eq!(strs.len() as usize, i + 1);
174 }
175
176 assert!(!strs.is_empty());
177
178 strs.push("12345");
179
180 for (i, string) in strs.iter().enumerate() {
181 if i < 10 {
182 assert_eq!(string, "");
183 } else {
184 assert_eq!(string, "12345");
185 }
186 }
187 }
188}