byte_chunk/
lib.rs

1use bytes::Bytes;
2
3pub struct ByteChunks<'a, T: 'a> {
4    v: &'a [T],
5    chunk_byte_size: usize,
6}
7
8pub trait SizeInBytes {
9    fn bytes_size(&self) -> usize;
10}
11
12impl SizeInBytes for String {
13    fn bytes_size(&self) -> usize {
14        let bytes: Bytes = self.to_owned().into();
15        bytes.len()
16    }
17}
18
19impl<'a> SizeInBytes for &'a str {
20    fn bytes_size(&self) -> usize {
21        let bytes: Bytes = self.to_string().into();
22        bytes.len()
23    }
24}
25
26impl<'a, T: 'a> ByteChunks<'a, T>
27where
28    T: SizeInBytes,
29{
30    pub fn new(slice: &'a [T], size: usize) -> Self {
31        Self {
32            v: slice,
33            chunk_byte_size: size,
34        }
35    }
36
37    fn next_split_index(&mut self) -> usize {
38        let mut byte_count = 0;
39        let mut index = 0;
40        loop {
41            let next = self.v.get(index);
42            match next {
43                Some(d) => {
44                    let size_of_next = d.bytes_size();
45                    if size_of_next > self.chunk_byte_size {
46                        panic!("Chunk is larger than {} bytes", self.chunk_byte_size);
47                    } else if byte_count + size_of_next > self.chunk_byte_size {
48                        break;
49                    } else {
50                        byte_count += size_of_next;
51                        index += 1;
52                    }
53                }
54                None => break,
55            }
56        }
57        index
58    }
59}
60
61impl<'a, T> Iterator for ByteChunks<'a, T>
62where
63    T: SizeInBytes,
64{
65    type Item = &'a [T];
66
67    fn next(&mut self) -> Option<&'a [T]> {
68        if self.v.is_empty() {
69            None
70        } else {
71            let chunksz = self.next_split_index();
72            let (fst, snd) = self.v.split_at(chunksz);
73            self.v = snd;
74            Some(fst)
75        }
76    }
77}
78
79pub trait ByteChunked<'a, T> {
80    fn byte_chunks(&self, chunk_byte_size: usize) -> ByteChunks<'_, T>;
81}
82
83pub trait SafeByteChunkedMut<'a, T> {
84    fn byte_chunks_safe_mut(&mut self, chunk_byte_size: usize) -> ByteChunks<'_, T>;
85}
86
87pub trait SafeByteChunked<'a, T> {
88    fn byte_chunks_safe(&mut self, chunk_byte_size: usize) -> ByteChunks<'_, T>;
89}
90
91impl<T> ByteChunked<'_, T> for [T]
92where
93    T: SizeInBytes,
94{
95    fn byte_chunks(&self, chunk_byte_size: usize) -> ByteChunks<'_, T> {
96        ByteChunks::new(self, chunk_byte_size)
97    }
98}
99
100impl<T> ByteChunked<'_, T> for Vec<T>
101where
102    T: SizeInBytes,
103{
104    fn byte_chunks(&self, chunk_byte_size: usize) -> ByteChunks<'_, T> {
105        ByteChunks::new(self.as_slice(), chunk_byte_size)
106    }
107}
108
109impl<T> SafeByteChunkedMut<'_, T> for Vec<T>
110where
111    T: SizeInBytes,
112{
113    fn byte_chunks_safe_mut(&mut self, chunk_byte_size: usize) -> ByteChunks<'_, T> {
114        self.retain(|x| x.bytes_size() <= chunk_byte_size);
115        ByteChunks::new(self.as_slice(), chunk_byte_size)
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::{ByteChunked, SafeByteChunkedMut};
122    use std::mem::size_of_val;
123
124    #[test]
125    fn test_next_split_index() {
126        let data: Vec<&str> = vec!["Hello", "There", "Best", "Worl", "D", "A"];
127        let mut chunked = data.as_slice().byte_chunks(10);
128        let next_index = chunked.next_split_index();
129
130        assert_eq!(2, next_index);
131    }
132
133    #[test]
134    fn size_of_tests() {
135        let string_ref = "test";
136        assert_eq!(size_of_val(string_ref), 4);
137    }
138
139    #[test]
140    fn creates_chunks_static_str() {
141        let data: Vec<&str> = vec!["Hello", "There", "Best", "Worl", "D", "A"];
142        let mut chunk_iter = data.byte_chunks(10);
143        if let Some(next) = chunk_iter.next() {
144            println!("{:?}", next);
145            assert_eq!(2, next.len());
146        }
147
148        if let Some(next) = chunk_iter.next() {
149            println!("{:?}", next);
150            assert_eq!(4, next.len());
151        }
152
153        let next = chunk_iter.next();
154        assert_eq!(None, next);
155    }
156
157    #[test]
158    fn creates_chunks_string() {
159        let data: Vec<String> = (vec!["Hello", "There", "Best", "Worl", "D", "A"])
160            .iter()
161            .map(|&x| String::from(x))
162            .collect();
163
164        let mut chunk_iter = data.byte_chunks(10);
165
166        if let Some(next) = chunk_iter.next() {
167            println!("{:?}", next);
168            assert_eq!(2, next.len());
169        }
170
171        if let Some(next) = chunk_iter.next() {
172            println!("{:?}", next);
173            assert_eq!(4, next.len());
174        }
175        let next = chunk_iter.next();
176        assert_eq!(None, next);
177    }
178
179    #[test]
180    fn empty_vec_returns_none() {
181        let data: Vec<String> = Vec::new();
182
183        let mut chunk_iter = data.byte_chunks(10);
184
185        let next = chunk_iter.next();
186        assert_eq!(None, next);
187    }
188
189    //"ラウトは難しいです!" == 30 bytes
190    #[test]
191    fn special_chars_are_sized_with_string() {
192        let data: Vec<String> = vec!["ラウ", "トは", "難し", "いで", "す!"]
193            .iter()
194            .map(|&x| String::from(x))
195            .collect();
196
197        let mut chunk_iter = data.byte_chunks(12);
198
199        if let Some(next) = chunk_iter.next() {
200            println!("{:?}", next);
201            assert_eq!(2, next.len());
202        }
203
204        if let Some(next) = chunk_iter.next() {
205            println!("{:?}", next);
206            assert_eq!(2, next.len());
207        }
208
209        if let Some(next) = chunk_iter.next() {
210            println!("{:?}", next);
211            assert_eq!(1, next.len());
212        }
213        let next = chunk_iter.next();
214        assert_eq!(None, next);
215    }
216
217    #[test]
218    fn special_chars_are_sized_with_static_string() {
219        let data = vec!["ラウ", "トは", "難し", "いで", "す!"];
220
221        let mut chunk_iter = data.byte_chunks(12);
222
223        if let Some(next) = chunk_iter.next() {
224            println!("{:?}", next);
225            assert_eq!(2, next.len());
226        }
227
228        if let Some(next) = chunk_iter.next() {
229            println!("{:?}", next);
230            assert_eq!(2, next.len());
231        }
232
233        if let Some(next) = chunk_iter.next() {
234            println!("{:?}", next);
235            assert_eq!(1, next.len());
236        }
237        let next = chunk_iter.next();
238        assert_eq!(None, next);
239    }
240
241    #[test]
242    fn strings_that_are_too_large_are_skipped() {
243        let mut data: Vec<String> = vec!["Hello", "There"]
244            .iter()
245            .map(|&x| String::from(x))
246            .collect();
247        let mut chunk_iter = data.byte_chunks_safe_mut(3);
248
249        let next = chunk_iter.next();
250        assert_eq!(None, next);
251    }
252}