Skip to main content

arbitrary/foreign/core/
str.rs

1use {
2    crate::{Arbitrary, Result, Unstructured},
3    core::str,
4};
5
6fn arbitrary_str<'a>(u: &mut Unstructured<'a>, size: usize) -> Result<&'a str> {
7    match str::from_utf8(u.peek_bytes(size).unwrap()) {
8        Ok(s) => {
9            u.bytes(size).unwrap();
10            Ok(s)
11        }
12        Err(e) => {
13            let i = e.valid_up_to();
14            let valid = u.bytes(i).unwrap();
15            // SAFETY:
16            // Contract from `str::from_utf8_unchecked`: the bytes must be valid UTF-8.
17            // Evidence:
18            // - `str::from_utf8` was called on the next `size` peeked bytes from `u`.
19            // - The call failed, returning a `Utf8Error` `e`.
20            // - `e.valid_up_to()` returns the length of the prefix of the peeked bytes
21            //   which is guaranteed to be valid UTF-8.
22            // - `u.bytes(i)` consumes and returns exactly this valid prefix (since `u`
23            //   was not mutated or consumed between peeking and calling `bytes`).
24            // - Therefore, `valid` is guaranteed to contain valid UTF-8.
25            let s = unsafe {
26                debug_assert!(str::from_utf8(valid).is_ok());
27                str::from_utf8_unchecked(valid)
28            };
29            Ok(s)
30        }
31    }
32}
33
34impl<'a> Arbitrary<'a> for &'a str {
35    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
36        let size = u.arbitrary_len::<u8>()?;
37        arbitrary_str(u, size)
38    }
39
40    fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
41        let size = u.len();
42        arbitrary_str(&mut u, size)
43    }
44
45    #[inline]
46    fn size_hint(_depth: usize) -> (usize, Option<usize>) {
47        (0, None)
48    }
49}