1#[derive(Clone, Default, Debug, Eq)]
16pub struct Argv {
17 buf: Vec<u8>,
18 ends: Vec<u32>,
19}
20
21impl Argv {
22 pub fn with_capacity(argc: usize, bytes: usize) -> Self {
24 Argv {
25 buf: Vec::with_capacity(bytes),
26 ends: Vec::with_capacity(argc),
27 }
28 }
29
30 #[inline]
34 pub fn clear(&mut self) {
35 self.buf.clear();
36 self.ends.clear();
37 }
38
39 #[inline]
42 pub fn reserve_for(&mut self, argc: usize, bytes: usize) {
43 self.buf.reserve(bytes);
44 self.ends.reserve(argc);
45 }
46
47 pub(crate) fn buf_capacity(&self) -> usize {
50 self.buf.capacity()
51 }
52
53 pub fn push(&mut self, arg: &[u8]) {
55 self.buf.extend_from_slice(arg);
56 self.ends.push(self.buf.len() as u32);
57 }
58
59 pub fn len(&self) -> usize {
61 self.ends.len()
62 }
63
64 pub fn is_empty(&self) -> bool {
66 self.ends.is_empty()
67 }
68
69 pub fn get(&self, i: usize) -> Option<&[u8]> {
71 let end = *self.ends.get(i)? as usize;
72 let start = if i == 0 { 0 } else { self.ends[i - 1] as usize };
73 Some(&self.buf[start..end])
74 }
75
76 pub fn first(&self) -> Option<&[u8]> {
78 self.get(0)
79 }
80
81 #[allow(clippy::missing_panics_doc)]
85 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
86 (0..self.len()).map(move |i| self.get(i).expect("in range"))
87 }
88}
89
90impl core::ops::Index<usize> for Argv {
91 type Output = [u8];
92 fn index(&self, i: usize) -> &[u8] {
93 self.get(i).expect("argv index out of bounds")
94 }
95}
96
97impl PartialEq<Vec<Vec<u8>>> for Argv {
100 fn eq(&self, other: &Vec<Vec<u8>>) -> bool {
101 self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b.as_slice())
102 }
103}
104
105impl PartialEq for Argv {
106 fn eq(&self, other: &Argv) -> bool {
107 self.buf == other.buf && self.ends == other.ends
108 }
109}
110
111impl From<Vec<Vec<u8>>> for Argv {
115 fn from(v: Vec<Vec<u8>>) -> Self {
116 let mut a = Argv::with_capacity(v.len(), v.iter().map(Vec::len).sum());
117 for arg in &v {
118 a.push(arg);
119 }
120 a
121 }
122}
123
124pub type Command = Argv;
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn with_capacity_preallocates_both_buffers() {
133 let a: Argv = Argv::with_capacity(4, 32);
134 assert_eq!(a.len(), 0);
135 assert!(a.is_empty());
136 assert!(a.buf.capacity() >= 32);
138 assert!(a.ends.capacity() >= 4);
139 }
140
141 #[test]
142 fn clear_keeps_capacity_resets_len() {
143 let mut a = Argv::default();
144 a.push(b"foo");
145 a.push(b"barbaz");
146 assert_eq!(a.len(), 2);
147 let cap_buf = a.buf.capacity();
148 let cap_ends = a.ends.capacity();
149 a.clear();
150 assert_eq!(a.len(), 0);
151 assert!(a.is_empty());
152 assert_eq!(a.buf.capacity(), cap_buf);
154 assert_eq!(a.ends.capacity(), cap_ends);
155 }
156
157 #[test]
158 fn reserve_for_grows_to_at_least_requested() {
159 let mut a = Argv::with_capacity(1, 4);
160 a.reserve_for(8, 64);
161 assert!(a.buf.capacity() >= 64);
162 assert!(a.ends.capacity() >= 8);
163 a.reserve_for(0, 0);
165 assert!(a.buf.capacity() >= 64);
166 assert!(a.ends.capacity() >= 8);
167 }
168
169 #[test]
170 fn push_get_iter_first_round_trip() {
171 let mut a = Argv::default();
172 a.push(b"SET");
173 a.push(b"key");
174 a.push(b"value");
175 assert_eq!(a.len(), 3);
176 assert_eq!(a.first(), Some(b"SET" as &[u8]));
177 assert_eq!(a.get(0), Some(b"SET" as &[u8]));
178 assert_eq!(a.get(1), Some(b"key" as &[u8]));
179 assert_eq!(a.get(2), Some(b"value" as &[u8]));
180 assert_eq!(a.get(3), None);
181 let collected: Vec<&[u8]> = a.iter().collect();
182 assert_eq!(collected, vec![b"SET" as &[u8], b"key", b"value"]);
183 }
184
185 #[test]
186 fn first_on_empty_returns_none() {
187 let a = Argv::default();
188 assert_eq!(a.first(), None);
189 assert_eq!(a.get(0), None);
190 }
191
192 #[test]
193 fn index_returns_correct_slice() {
194 let mut a = Argv::default();
195 a.push(b"hi");
196 a.push(b"there");
197 assert_eq!(&a[0], b"hi" as &[u8]);
198 assert_eq!(&a[1], b"there" as &[u8]);
199 }
200
201 #[test]
202 #[should_panic(expected = "argv index out of bounds")]
203 fn index_out_of_bounds_panics() {
204 let a = Argv::default();
205 let _ = &a[0];
206 }
207
208 #[test]
209 fn eq_against_vec_of_vec() {
210 let mut a = Argv::default();
211 a.push(b"PING");
212 a.push(b"hello");
213 assert_eq!(a, vec![b"PING".to_vec(), b"hello".to_vec()]);
214 assert_ne!(a, vec![b"PING".to_vec()]);
215 assert_ne!(a, vec![b"PING".to_vec(), b"world".to_vec()]);
216 }
217
218 #[test]
219 fn eq_argv_vs_argv() {
220 let mut a = Argv::default();
221 a.push(b"A");
222 a.push(b"B");
223 let mut b = Argv::default();
224 b.push(b"A");
225 b.push(b"B");
226 let mut c = Argv::default();
227 c.push(b"A");
228 c.push(b"C");
229 assert_eq!(a, b);
230 assert_ne!(a, c);
231 }
232
233 #[test]
234 fn from_vec_of_vec_preserves_args() {
235 let v = vec![b"GET".to_vec(), b"my-key".to_vec()];
236 let a: Argv = Argv::from(v.clone());
237 assert_eq!(a.len(), 2);
238 assert_eq!(a, v);
239 assert_eq!(a.buf.len(), 3 + 6);
241 }
242
243 #[test]
244 fn clone_makes_independent_argv() {
245 let mut a = Argv::default();
246 a.push(b"X");
247 let b = a.clone();
248 assert_eq!(a, b);
249 a.push(b"Y");
251 assert_ne!(a, b);
252 assert_eq!(b.len(), 1);
253 }
254}