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
Conversation
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()) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 implementarbitrary_take_rest
with this implementation that takes all the bytes.
the default implementation for arbitrary_take_rest
defers to arbitrary
:
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?
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
#[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); | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect! Thanks @frewsxcv :)
#62 (comment)