kevy_resp/
argv_borrowed.rs1use crate::argv::Argv;
11use crate::inline_ranges::InlineRanges;
12
13#[derive(Clone, Debug)]
29pub struct ArgvBorrowed<'a> {
30 input: &'a [u8],
31 ranges: InlineRanges,
32}
33
34impl<'a> ArgvBorrowed<'a> {
35 pub fn new(input: &'a [u8]) -> Self {
37 Self {
38 input,
39 ranges: InlineRanges::new(),
40 }
41 }
42
43 pub fn with_capacity(input: &'a [u8], argc: usize) -> Self {
45 Self {
46 input,
47 ranges: InlineRanges::with_capacity(argc),
48 }
49 }
50
51 pub(crate) fn push_range(&mut self, start: usize, end: usize) {
53 debug_assert!(end <= self.input.len() && start <= end);
54 self.ranges.push((start as u32, end as u32));
55 }
56
57 pub fn len(&self) -> usize {
59 self.ranges.len()
60 }
61
62 pub fn is_empty(&self) -> bool {
64 self.ranges.is_empty()
65 }
66
67 pub fn get(&self, i: usize) -> Option<&[u8]> {
69 let (s, e) = self.ranges.get(i)?;
70 Some(&self.input[s as usize..e as usize])
71 }
72
73 pub fn first(&self) -> Option<&[u8]> {
75 self.get(0)
76 }
77
78 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
80 (0..self.len()).map(move |i| self.get(i).expect("in range"))
81 }
82
83 pub fn into_owned(self) -> Argv {
87 let mut total: usize = 0;
88 for i in 0..self.ranges.len() {
89 let (s, e) = self.ranges.get(i).expect("in range");
90 total += (e - s) as usize;
91 }
92 let mut a = Argv::with_capacity(self.ranges.len(), total);
93 for i in 0..self.ranges.len() {
94 let (s, e) = self.ranges.get(i).expect("in range");
95 a.push(&self.input[s as usize..e as usize]);
96 }
97 a
98 }
99}
100
101impl core::ops::Index<usize> for ArgvBorrowed<'_> {
102 type Output = [u8];
103 fn index(&self, i: usize) -> &[u8] {
104 self.get(i).expect("argv-borrowed index out of bounds")
105 }
106}
107
108impl PartialEq<Vec<Vec<u8>>> for ArgvBorrowed<'_> {
109 fn eq(&self, other: &Vec<Vec<u8>>) -> bool {
110 self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b.as_slice())
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn new_and_with_capacity_start_empty() {
120 let buf = b"hello";
121 let a = ArgvBorrowed::new(buf);
122 assert!(a.is_empty());
123 assert_eq!(a.len(), 0);
124 let b = ArgvBorrowed::with_capacity(buf, 8);
125 assert!(b.is_empty());
126 }
127
128 #[test]
129 fn push_range_and_get_round_trip() {
130 let buf: &[u8] = b"*2\r\n$3\r\nGET\r\n$5\r\nmykey\r\n";
132 let mut a = ArgvBorrowed::with_capacity(buf, 2);
133 a.push_range(8, 11);
135 a.push_range(17, 22);
136 assert_eq!(a.len(), 2);
137 assert_eq!(a.first(), Some(b"GET" as &[u8]));
138 assert_eq!(a.get(0), Some(b"GET" as &[u8]));
139 assert_eq!(a.get(1), Some(b"mykey" as &[u8]));
140 assert_eq!(a.get(2), None);
141 }
142
143 #[test]
144 fn iter_yields_args_in_order() {
145 let buf: &[u8] = b"abcXYZdef";
146 let mut a = ArgvBorrowed::new(buf);
147 a.push_range(0, 3);
148 a.push_range(3, 6);
149 a.push_range(6, 9);
150 let collected: Vec<&[u8]> = a.iter().collect();
151 assert_eq!(collected, vec![b"abc" as &[u8], b"XYZ", b"def"]);
152 }
153
154 #[test]
155 fn first_empty_returns_none() {
156 let a = ArgvBorrowed::new(b"" as &[u8]);
157 assert_eq!(a.first(), None);
158 assert_eq!(a.get(0), None);
159 }
160
161 #[test]
162 fn index_returns_correct_slice() {
163 let buf: &[u8] = b"hithere";
164 let mut a = ArgvBorrowed::new(buf);
165 a.push_range(0, 2);
166 a.push_range(2, 7);
167 assert_eq!(&a[0], b"hi" as &[u8]);
168 assert_eq!(&a[1], b"there" as &[u8]);
169 }
170
171 #[test]
172 #[should_panic(expected = "argv-borrowed index out of bounds")]
173 fn index_out_of_bounds_panics() {
174 let a = ArgvBorrowed::new(b"" as &[u8]);
175 let _ = &a[0];
176 }
177
178 #[test]
179 fn eq_against_vec_of_vec() {
180 let buf: &[u8] = b"PINGhello";
181 let mut a = ArgvBorrowed::new(buf);
182 a.push_range(0, 4);
183 a.push_range(4, 9);
184 assert_eq!(a, vec![b"PING".to_vec(), b"hello".to_vec()]);
185 assert_ne!(a, vec![b"PING".to_vec()]);
186 assert_ne!(a, vec![b"PING".to_vec(), b"world".to_vec()]);
187 }
188
189 #[test]
190 fn into_owned_copies_args_into_argv() {
191 let buf: &[u8] = b"*2\r\n$3\r\nSET\r\n$1\r\nk\r\n";
193 let mut a = ArgvBorrowed::with_capacity(buf, 2);
194 a.push_range(8, 11); a.push_range(17, 18); let owned: Argv = a.into_owned();
197 assert_eq!(owned.len(), 2);
198 assert_eq!(owned.get(0), Some(b"SET" as &[u8]));
199 assert_eq!(owned.get(1), Some(b"k" as &[u8]));
200 assert_eq!(owned, vec![b"SET".to_vec(), b"k".to_vec()]);
202 }
203
204 #[test]
205 fn into_owned_on_empty_argv_returns_empty_argv() {
206 let a = ArgvBorrowed::new(b"" as &[u8]);
207 let owned = a.into_owned();
208 assert!(owned.is_empty());
209 assert_eq!(owned.len(), 0);
210 }
211
212 #[test]
213 fn clone_shares_input_slice_independent_ranges() {
214 let buf: &[u8] = b"abcdef";
215 let mut a = ArgvBorrowed::new(buf);
216 a.push_range(0, 3); let b = a.clone();
218 assert_eq!(b.len(), 1);
219 assert_eq!(b.get(0), Some(b"abc" as &[u8]));
220 a.push_range(3, 6); assert_eq!(a.len(), 2);
223 assert_eq!(b.len(), 1);
224 }
225}