fuzzed_data_provider_rs/
lib.rs

1use std::fmt::Write;
2
3macro_rules! consume_integral_in_range {
4    ($self:expr, $min:expr, $max:expr, $it:ty) => {{
5        assert!($min <= $max);
6        let range: $it = $max.checked_sub($min).unwrap_or(<$it>::MAX);
7        let mut res: $it = 0;
8        let mut offset: usize = 0;
9
10        let mut bytes_used = 0;
11        let remaining_bytes = $self.remaining_bytes();
12
13        while (offset < std::mem::size_of::<$it>() * u8::BITS as usize)
14            && ((range >> offset) > 0)
15            && (bytes_used != remaining_bytes)
16        {
17            bytes_used += 1;
18            let index = remaining_bytes - bytes_used;
19
20            res = (std::num::Wrapping(res) << u8::BITS as usize).0 | $self.data[index] as $it;
21            offset += u8::BITS as usize;
22        }
23
24        if range as $it != <$it>::MAX {
25            res = res % (range as $it + 1);
26        }
27
28        $self.cursor += bytes_used;
29
30        (std::num::Wrapping($min) + std::num::Wrapping(res)).0
31    }};
32}
33
34macro_rules! consume_probability {
35    ($self:expr, f32) => {
36        $self.consume_u32() as f32 / u32::MAX as f32
37    };
38
39    ($self:expr, f64) => {
40        $self.consume_u64() as f64 / u64::MAX as f64
41    };
42}
43
44macro_rules! consume_floating_point_in_range {
45    ($self:expr, $min:expr, $max:expr, $it:ty) => {{
46        assert!($min < $max);
47        let range: $it;
48        let mut res = $min;
49        let zero: $it = 0.0;
50
51        if $max > zero && $min < zero && $max > $min + <$it>::MAX {
52            range = ($max / 2.0) - ($min / 2.0);
53            if $self.consume_bool() {
54                res += range;
55            }
56        } else {
57            range = $max - $min;
58        }
59
60        res + range
61    }};
62
63    ($self:expr, $min:expr, $max:expr, f32) => {
64        consume_floating_point_in_range!($self, $min, $max, f32) * $self.consume_probability_f32()
65    };
66
67    ($self:expr, $min:expr, $max:expr, f64) => {
68        consume_floating_point_in_range!($self, $min, $max, f64) * $self.consume_probability_f64()
69    };
70}
71
72macro_rules! impl_consume_integral_in_range {
73    ($name:ident, $it:ty) => {
74        #[doc = concat!(
75"Consumes `std::mem::sizeof::<", stringify!($it), ">()` bytes from the provider and returns a value in the range `min..max`\n\n\
76# Arguments:\n\
77\n\
78* `min`: The minimum value in the range\n\
79* `max`: The maximum value in the range\n\
80\n\
81returns: The value between `min..max`")]
82        pub fn $name(&mut self, min: $it, max: $it) -> $it {
83            consume_integral_in_range!(self, min, max, $it)
84        }
85    };
86}
87
88macro_rules! impl_consume_integral {
89    ($name:ident, $it:ty) => {
90        #[doc = concat!(
91"Consumes `std::mem::sizeof::<", stringify!($it), ">()` bytes from the provider an returns value in the range `",
92stringify!($it), "::MIN..", stringify!($it), "::MAX`\n\
93\n\
94returns: The value between `", stringify!($it), "::MIN..", stringify!($it), "::MAX`")]
95        pub fn $name(&mut self) -> $it {
96            consume_integral_in_range!(self, <$it>::MIN, <$it>::MAX, $it)
97        }
98    };
99}
100
101macro_rules! impl_consume_floating_point_in_range {
102    ($name:ident, f32) => {
103        /// Consumes `std::mem::sizeof::<f32>()` bytes from the provider and returns a value in the range `min..max`
104        ///
105        /// # Arguments:
106        ///
107        /// * `min`: The minimum value in the range
108        /// * `max`: The maximum value in the range
109        ///
110        /// returns: The value between `min..max`
111        pub fn $name(&mut self, min: f32, max: f32) -> f32 {
112            consume_floating_point_in_range!(self, min, max, f32)
113        }
114    };
115
116    ($name:ident, f64) => {
117        /// Consumes `std::mem::sizeof::<f64>()` bytes from the provider and returns a value in the range `min..max`
118        ///
119        /// # Arguments:
120        ///
121        /// * `min`: The minimum value in the range
122        /// * `max`: The maximum value in the range
123        ///
124        /// returns: The value between `min..max`
125        pub fn $name(&mut self, min: f64, max: f64) -> f64 {
126            consume_floating_point_in_range!(self, min, max, f64)
127        }
128    };
129}
130
131macro_rules! impl_consume_floating_point {
132    ($name:ident, f32) => {
133        /// Consumes `std::mem::sizeof::<f32>()` bytes from the provider and returns a value in the range `f32::MIN..f32::MAX`
134        ///
135        /// returns: The value between `f32::MIN..f32::MAX`
136        pub fn $name(&mut self) -> f32 {
137            consume_floating_point_in_range!(self, f32::MIN, f32::MAX, f32)
138        }
139    };
140
141    ($name:ident, f64) => {
142        /// Consumes `std::mem::sizeof::<f64>()` bytes from the provider and returns a value in the range `f64::MIN..f64::MAX`
143        ///
144        /// returns: The value between `f64::MIN..f64::MAX`
145        pub fn $name(&mut self) -> f64 {
146            consume_floating_point_in_range!(self, f64::MIN, f64::MAX, f64)
147        }
148    };
149}
150
151#[derive(Debug)]
152pub struct FuzzedDataProvider<'a> {
153    data: &'a [u8],
154    cursor: usize,
155}
156
157impl<'a> FuzzedDataProvider<'a> {
158    /// Creates a new `FuzzedDataProvider`
159    pub fn new(data: &'a [u8]) -> Self {
160        Self { data, cursor: 0 }
161    }
162
163    #[inline]
164    fn has_remaining_bytes(&self) -> bool {
165        self.remaining_bytes() != 0
166    }
167
168    /// Returns the number of remaining bytes the provider has
169    ///
170    /// returns: The number of remaining bytes
171    #[inline]
172    pub fn remaining_bytes(&self) -> usize {
173        self.data.len() - self.cursor
174    }
175
176    /// Consumes `num_bytes` from the provider and returns them.
177    /// If the provider doesn't have `num_bytes` remaining, then it will
178    /// return the remaining bytes
179    ///
180    /// # Arguments
181    ///
182    /// * `num_bytes`: The number of bytes to consume
183    ///
184    /// returns: The bytes from the provider
185    ///
186    /// # Examples
187    ///
188    /// ```
189    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
190    ///
191    /// fn main() {
192    ///     let mut fp = FuzzedDataProvider::new(&[1, 2, 3, 4]);
193    ///     assert_eq!(fp.consume_bytes(2), vec![1, 2]);
194    /// }
195    /// ```
196    pub fn consume_bytes(&mut self, num_bytes: usize) -> Vec<u8> {
197        let num_bytes = num_bytes.min(self.remaining_bytes());
198
199        let mut res = Vec::with_capacity(num_bytes);
200        res.extend_from_slice(&self.data[self.cursor..num_bytes]);
201
202        self.cursor += num_bytes;
203
204        res
205    }
206
207    /// Consumes `num_bytes` from the provider and returns them as a `String`.
208    /// If the provider doesn't have `num_bytes` remaining, then it will
209    /// return the remaining bytes
210    ///
211    /// # Arguments
212    ///
213    /// * `num_bytes`: The number of bytes to consume
214    ///
215    /// returns: The bytes from the provider as a String
216    ///
217    /// # Examples
218    ///
219    /// ```
220    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
221    ///
222    /// fn main() {
223    ///     let mut fp = FuzzedDataProvider::new(&[b'A', b'B', b'C']);
224    ///     assert_eq!(fp.consume_bytes_as_string(2), "AB");
225    /// }
226    /// ```
227    pub fn consume_bytes_as_string(&mut self, num_bytes: usize) -> String {
228        let num_bytes = num_bytes.min(self.remaining_bytes());
229
230        let res = String::from_utf8_lossy(&self.data[self.cursor..num_bytes]).to_string();
231
232        self.cursor += num_bytes;
233
234        res
235    }
236
237    /// Consumes the data provider and returns the remaining bytes if any.
238    ///
239    /// returns: The remaining bytes
240    ///
241    /// # Examples
242    ///
243    /// ```
244    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
245    ///
246    /// fn main() {
247    ///     let fp = FuzzedDataProvider::new(&[1, 2, 3]);
248    ///     assert_eq!(fp.consume_remaining_bytes(), vec![1, 2, 3]);
249    /// }
250    /// ```
251    pub fn consume_remaining_bytes(mut self) -> Vec<u8> {
252        self.consume_bytes(self.remaining_bytes())
253    }
254
255    /// Consumes the data provider and returns the remaining bytes if any as a `String`
256    ///
257    ///
258    /// returns: The remaining bytes from the provider as a String
259    ///
260    /// # Examples
261    ///
262    /// ```
263    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
264    ///
265    /// fn main() {
266    ///     let fp = FuzzedDataProvider::new(&[b'A', b'B', b'C']);
267    ///     assert_eq!(fp.consume_remaining_bytes_as_string(), "ABC");
268    /// }
269    /// ```
270    pub fn consume_remaining_bytes_as_string(mut self) -> String {
271        self.consume_bytes_as_string(self.remaining_bytes())
272    }
273
274    /// Consumes at most `max_len` bytes from the provider as a `String`.
275    /// If a backslash (\) is encountered then the consuming will stop earlier.
276    /// If provider has less bytes remaining than `max_len` then the number of remaining
277    /// bytes will be consumed at most.
278    ///
279    /// # Arguments
280    ///
281    /// * `max_len`: The maximum number of bytes to consume
282    ///
283    /// returns: The bytes consumed as a `String`
284    ///
285    /// # Examples
286    ///
287    /// ```
288    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
289    ///
290    /// fn main() {
291    ///     let mut fp = FuzzedDataProvider::new(&[b'A', b'B', b'\\', b'C', b'D']);
292    ///     assert_eq!(fp.consume_random_length_string(4), "AB");
293    ///     assert_eq!(fp.consume_random_length_string(3), "D");
294    /// }
295    /// ```
296    pub fn consume_random_length_string(&mut self, max_len: usize) -> String {
297        let mut res = String::with_capacity(max_len.min(self.remaining_bytes()));
298        let mut i = 0usize;
299        while i != max_len && self.has_remaining_bytes() {
300            let mut next = self.data[self.cursor] as char;
301            self.cursor += 1;
302
303            if next == '\\' && self.has_remaining_bytes() {
304                next = self.data[self.cursor] as char;
305                self.cursor += 1;
306
307                if next != '\\' {
308                    break;
309                }
310            }
311
312            i += 1;
313
314            if write!(res, "{next}").is_err() {
315                break;
316            }
317        }
318
319        res.shrink_to_fit();
320        res
321    }
322
323    /// Consumes a bytes from the provider and returns that as a `bool`
324    ///
325    /// returns: The byte consumed as a `bool`
326    ///
327    /// # Examples
328    ///
329    /// ```
330    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
331    ///
332    /// fn main() {
333    ///     let mut fp = FuzzedDataProvider::new(&[2, 1]);
334    ///     assert_eq!(fp.consume_bool(), true);
335    ///     assert_eq!(fp.consume_bool(), false);
336    /// }
337    /// ```
338    pub fn consume_bool(&mut self) -> bool {
339        (1 & self.consume_u8()) != 0
340    }
341
342    /// Consumes the required bytes from the provider and returns a probability as `f32`.
343    /// Probability is a value between `0.0` and `1.0`
344    ///
345    /// returns: The probability value
346    ///
347    /// # Examples
348    ///
349    /// ```
350    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
351    ///
352    /// fn main() {
353    ///     let mut fp = FuzzedDataProvider::new(&[255, 0]);
354    ///     assert!((0.0f32..1.0f32).contains(&fp.consume_probability_f32()));
355    /// }
356    /// ```
357    pub fn consume_probability_f32(&mut self) -> f32 {
358        consume_probability!(self, f32)
359    }
360
361    /// Consumes the required bytes from the provider and returns a probability as `f64`.
362    /// Probability is a value between `0.0` and `1.0`
363    ///
364    /// returns: The probability value
365    ///
366    /// # Examples
367    ///
368    /// ```
369    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
370    ///
371    /// fn main() {
372    ///     let mut fp = FuzzedDataProvider::new(&[255, 0]);
373    ///     assert!((0.0f64..1.0f64).contains(&fp.consume_probability_f64()));
374    /// }
375    /// ```
376    pub fn consume_probability_f64(&mut self) -> f64 {
377        consume_probability!(self, f64)
378    }
379
380    /// Consumes `std::mem::sizeof::<usize>()` bytes from the provider
381    /// constraining the value between 0 and `slice.len() - 1`.
382    /// This value is then used as an index to the given `slice` and returns
383    /// a copy of the value which belongs to that index.
384    ///
385    /// # Arguments
386    ///
387    /// * `slice`:
388    /// The slice to index and retrieve the value from
389    ///
390    /// returns: The value from the slice if the slice is not empty or `None` otherwise.
391    ///
392    /// # Examples
393    ///
394    /// ```
395    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
396    ///
397    /// fn main() {
398    ///     let values = [1, 2, 3, 4, 5];
399    ///     let mut fp = FuzzedDataProvider::new(&[2, 3]);
400    ///     assert_eq!(fp.pick_value_from(&values), Some(4));
401    ///     assert_eq!(fp.pick_value_from(&values), Some(3));
402    /// }
403    /// ```
404    pub fn pick_value_from<T: Clone, S: AsRef<[T]>>(&mut self, slice: S) -> Option<T> {
405        let slice = slice.as_ref();
406        (!slice.is_empty()).then(|| slice[self.consume_usize_in_range(0, slice.len() - 1)].clone())
407    }
408
409    /// Consumes `std::mem::sizeof::<usize>()` bytes from the provider
410    /// constraining the value between 0 and `slice.len() - 1`.
411    /// This value is then used as an index to the given `slice` and returns
412    /// a copy of the value which belongs to that index.
413    ///
414    /// # Arguments
415    ///
416    /// * `slice`:
417    /// The slice to index and retrieve the value from
418    ///
419    /// returns: The value from the slice if the slice is not empty or `T::default()` otherwise.
420    ///
421    /// # Examples
422    ///
423    /// ```
424    /// use fuzzed_data_provider_rs::FuzzedDataProvider;
425    ///
426    /// fn main() {
427    ///     let values: &[u32] = &[];
428    ///     let mut fp = FuzzedDataProvider::new(&[2, 3]);
429    ///     assert_eq!(fp.pick_value_from_or_default(values), u32::default());
430    /// }
431    /// ```
432    pub fn pick_value_from_or_default<T: Clone + Default, S: AsRef<[T]>>(&mut self, slice: S) -> T {
433        self.pick_value_from(slice).unwrap_or_default()
434    }
435
436    impl_consume_integral_in_range!(consume_i8_in_range, i8);
437    impl_consume_integral_in_range!(consume_u8_in_range, u8);
438    impl_consume_integral_in_range!(consume_i16_in_range, i16);
439    impl_consume_integral_in_range!(consume_u16_in_range, u16);
440    impl_consume_integral_in_range!(consume_i32_in_range, i32);
441    impl_consume_integral_in_range!(consume_u32_in_range, u32);
442    impl_consume_integral_in_range!(consume_i64_in_range, i64);
443    impl_consume_integral_in_range!(consume_u64_in_range, u64);
444    impl_consume_integral_in_range!(consume_i128_in_range, i128);
445    impl_consume_integral_in_range!(consume_u128_in_range, u128);
446    impl_consume_integral_in_range!(consume_usize_in_range, usize);
447    impl_consume_integral_in_range!(consume_isize_in_range, isize);
448
449    impl_consume_integral!(consume_i8, i8);
450    impl_consume_integral!(consume_u8, u8);
451    impl_consume_integral!(consume_i16, i16);
452    impl_consume_integral!(consume_u16, u16);
453    impl_consume_integral!(consume_i32, i32);
454    impl_consume_integral!(consume_u32, u32);
455    impl_consume_integral!(consume_i64, i64);
456    impl_consume_integral!(consume_u64, u64);
457    impl_consume_integral!(consume_i128, i128);
458    impl_consume_integral!(consume_u128, u128);
459    impl_consume_integral!(consume_usize, usize);
460    impl_consume_integral!(consume_isize, isize);
461
462    impl_consume_floating_point_in_range!(consume_f32_in_range, f32);
463    impl_consume_floating_point_in_range!(consume_f64_in_range, f64);
464
465    impl_consume_floating_point!(consume_f32, f32);
466    impl_consume_floating_point!(consume_f64, f64);
467}
468
469#[cfg(test)]
470mod tests {
471    use crate::FuzzedDataProvider;
472
473    #[test]
474    fn test_consume_empty_returns_empty_vec() {
475        let fp = FuzzedDataProvider::new(&[]);
476        assert_eq!(fp.consume_remaining_bytes(), vec![]);
477    }
478
479    #[test]
480    fn test_consume_empty_as_string_returns_empty_string() {
481        let fp = FuzzedDataProvider::new(&[]);
482        assert_eq!(fp.consume_remaining_bytes_as_string(), String::new());
483    }
484
485    #[test]
486    fn test_consume_remaining_as_string() {
487        let fp = FuzzedDataProvider::new(&[b'@', b'A', b'B']);
488        assert_eq!(fp.consume_remaining_bytes_as_string(), "@AB");
489    }
490
491    #[test]
492    fn test_consume_bytes() {
493        let mut fp = FuzzedDataProvider::new(&[1, 2, 3]);
494        assert_eq!(fp.consume_bytes(2), vec![1, 2]);
495    }
496
497    #[test]
498    fn test_consume_probability_f32() {
499        let mut fp = FuzzedDataProvider::new(&[255, 0]);
500        assert!((0.0f32..1.0f32).contains(&fp.consume_probability_f32()));
501    }
502
503    #[test]
504    fn test_consume_probability_f64() {
505        let mut fp = FuzzedDataProvider::new(&[1, 200, 10, 20]);
506        assert!((0.0f64..1.0f64).contains(&fp.consume_probability_f64()));
507    }
508
509    #[test]
510    fn test_consume_integral_u8() {
511        let mut fp = FuzzedDataProvider::new(&[255, 1]);
512        assert_eq!(fp.consume_u8(), 1);
513        assert_eq!(fp.consume_u8(), 255);
514    }
515
516    #[test]
517    fn test_consume_integral_i8() {
518        let mut fp = FuzzedDataProvider::new(&[255, 1]);
519        assert_eq!(fp.consume_i8(), -127);
520        assert_eq!(fp.consume_i8(), 127);
521    }
522
523    #[test]
524    fn test_consume_integral_u16() {
525        let mut fp = FuzzedDataProvider::new(&[1, 1]);
526        assert_eq!(fp.consume_u16(), 257);
527    }
528
529    #[test]
530    fn test_consume_integral_i16() {
531        let mut fp = FuzzedDataProvider::new(&[1, 1]);
532        assert_eq!(fp.consume_i16(), -32511);
533    }
534
535    #[test]
536    fn test_consume_integral_u32_without_sufficient_bytes() {
537        let mut fp = FuzzedDataProvider::new(&[1, 1]);
538        assert_eq!(fp.consume_u32(), 257);
539    }
540
541    #[test]
542    fn test_consume_integral_in_range_u8() {
543        let mut fp = FuzzedDataProvider::new(&[255]);
544        assert_eq!(fp.consume_u8_in_range(1, 10), 6);
545    }
546
547    #[test]
548    fn test_consume_bool() {
549        let mut fp = FuzzedDataProvider::new(&[0, 1, 11]);
550        assert_eq!(fp.consume_bool(), true);
551        assert_eq!(fp.consume_bool(), true);
552        assert_eq!(fp.consume_bool(), false);
553    }
554
555    #[test]
556    fn test_consume_floating_point_f32() {
557        let mut fp = FuzzedDataProvider::new(&[1, 2, 3, 4, 5]);
558        assert_eq!(fp.consume_f32(), 3.4028235e38);
559    }
560
561    #[test]
562    fn test_consume_floating_point_f64() {
563        let mut fp = FuzzedDataProvider::new(&[1, 2, 3, 4, 5, 6, 7, 8, 11]);
564        assert_eq!(fp.consume_f64(), 1.7976931348623157e308);
565    }
566
567    #[test]
568    fn test_consume_floating_point_in_range_f32() {
569        let mut fp = FuzzedDataProvider::new(&[1, 2, 3, 4, 5]);
570        assert_eq!(fp.consume_f32_in_range(1.0, 1.5), 1.5);
571    }
572
573    #[test]
574    fn test_consume_floating_point_in_range_f64() {
575        let mut fp = FuzzedDataProvider::new(&[1, 2, 3, 4, 5, 6, 7, 8, 11]);
576        assert_eq!(fp.consume_f64_in_range(1.1, 1.9), 1.9);
577    }
578
579    #[test]
580    fn test_pick_value_from() {
581        let values = [1, 2, 3, 4, 5];
582        let mut fp = FuzzedDataProvider::new(&[0, 1, 2, 3]);
583        assert_eq!(fp.pick_value_from(&values), Some(4));
584        assert_eq!(fp.pick_value_from(&values), Some(3));
585    }
586
587    #[test]
588    fn test_consume_random_length_string() {
589        let mut fp = FuzzedDataProvider::new(&[b'@', b'1', b'5', b'\\', b'7', b'8', b'9']);
590        assert_eq!(fp.consume_random_length_string(10), "@15");
591        assert_eq!(fp.consume_random_length_string(10), "89");
592    }
593
594    #[test]
595    fn test_consume_integral_from_empty_provider() {
596        let mut fp = FuzzedDataProvider::new(&[]);
597        assert_eq!(fp.consume_u32(), 0);
598    }
599
600    #[test]
601    fn test_consume_floating_point_from_empty_provider() {
602        let mut fp = FuzzedDataProvider::new(&[]);
603        assert_eq!(fp.consume_f64(), 0.0);
604    }
605}