Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Arbitrary for &[u8]. #67

Merged
merged 1 commit into from Jan 25, 2021
Merged

Implement Arbitrary for &[u8]. #67

merged 1 commit into from Jan 25, 2021

Conversation

frewsxcv
Copy link
Member

src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated
@@ -626,6 +626,17 @@ arbitrary_array! { 32, (T, a) (T, b) (T, c) (T, d) (T, e) (T, f) (T, g) (T, h)
(T, z) (T, aa) (T, ab) (T, ac) (T, ad) (T, ae) (T, af)
(T, ag) }

impl<'a> Arbitrary<'a> for &'a [u8] {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
u.get_bytes(u.len())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consuming the entire unstructured buffer every time would mean that e.g.

#[derive(Arbitrary)]
struct Foo<'a> {
    bytes: &'a [u8],
    other_bytes: &'a [u9],
}

would always generate an empty slice for the 2nd field. You may want to do the arbitrary_len thing still here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye @nagisa. Yes, we should still do the arbitrary_len thing, but also implement arbitrary_take_rest with this implementation that takes all the bytes.

Copy link
Member Author

@frewsxcv frewsxcv Jan 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consuming the entire unstructured buffer every time would mean that e.g.

#[derive(Arbitrary)]
struct Foo<'a> {
    bytes: &'a [u8],
    other_bytes: &'a [u9],
}

would always generate an empty slice for the 2nd field. You may want to do the arbitrary_len thing still here.

great catch! fixed in f44a7e0

Good eye @nagisa. Yes, we should still do the arbitrary_len thing, but also implement arbitrary_take_rest with this implementation that takes all the bytes.

the default implementation for arbitrary_take_rest defers to arbitrary:

arbitrary/src/lib.rs

Lines 173 to 180 in f951b5a

/// Generate an arbitrary value of `Self` from the entirety of the given unstructured data.
///
/// This is similar to Arbitrary::arbitrary, however it assumes that it is the
/// last consumer of the given data, and is thus able to consume it all if it needs.
/// See also the documentation for [`Unstructured`][crate::Unstructured].
fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
Self::arbitrary(&mut u)
}

so seems like it'll already use this code. is that what you were thinking?

Copy link
Member

@fitzgen fitzgen Jan 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite. It should be this:

impl<'a> Arbitrary<'a> for &'a [u8] {
    // ...
    fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
        Ok(u.take_rest())
    }
}

This will always consume the rest of the Unstructured's input (which is what we want in the _take_rest method) without getting any kind of length prefix (we only want the length prefix in regular arbitrary, not in arbitrary_take_rest).

Does that clear things up? Sorry this required so many back and forths to spell out.

@frewsxcv
Copy link
Member Author

@nagisa @fitzgen Thanks for your patience, this is ready for another review. Just added a couple more commits

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo the arbitrary_take_rest stuff upthread and a question about the test below.

Comment on lines +1035 to +1046
#[test]
fn arbitrary_for_bytes() {
let x = [1, 2, 3, 4, 4];
let mut buf = Unstructured::new(&x);
let expected = &[1, 2, 3, 4];
let actual = <&[u8] as Arbitrary>::arbitrary(&mut buf).unwrap();
assert_eq!(expected, actual);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this test still pass with the length prefix stuff? I expect it to pass when using arbitrary_take_rest but not with regular arbitrary, where I instead I would expect that we read a length (which is read from the end of the data) and then get some prefix of [1, 2, 3] depending on how arbitrary_len maps 4 into the 0..3 range.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the latest commit– does that match what's in your head?

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect! Thanks @frewsxcv :)

@fitzgen fitzgen merged commit 393edc3 into staging-1.0 Jan 25, 2021
@fitzgen fitzgen deleted the 1.0-bytes branch January 25, 2021 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants