arbitrary icon indicating copy to clipboard operation
arbitrary copied to clipboard

Allow custom arbitrary methods for fields in the custom derive

Open fitzgen opened this issue 4 years ago • 5 comments

Sometimes a field of a struct doesn't implement arbitrary and it is either impossible to do (because it is from another crate, for example) or undesired.

We should support some kind of attribute to either use the Default::default implementation for the type, when we "don't care" about that field, or supply an arbitrary function that has the same signature as Arbitrary::arbitrary to be used instead.

This is all possible to do when implementing Arbitrary by hand, in the sense that you can always stuff whatever code inside the impl. But this seems common enough and simple enough that we may want to support it in the custom derive.

Straw person syntax:

#[derive(Arbitrary)]
struct MyThing {
    // This doesn't actually matter, just a diagnostic message, so don't
    // waste input bytes on it.
    #[arbitrary(default)]
    diagnostic: String,

    // This is a type defined by a foreign crate and doesn't implement
    // Arbitrary. Because of orphan rules, we can't implement Arbitrary
    // for it, so instead we have a one-off function.
    #[arbitrary(arbitrary = arbitrary_foreign_type)]
    foreign: foreign_crate::ForeignType,
}

fn arbitrary_foreign_type(u: &mut Unstructured)
    -> Result<foreign_crate::ForeignType>
{
    // ...
}

The open question in my mind is how to deal with the other, optional Arbtirary methods? e.g. arbitrary_take_rest, shrink, and size_hint. Should we assume the default implementations in this case? Should we also allow providing custom implementations for them?

Any thoughts @Manishearth?

+cc @bnjbvr

fitzgen avatar Feb 21 '20 19:02 fitzgen

No strong thoughts, we can allow multiple methods for overriding it perhaps.

Manishearth avatar Feb 21 '20 19:02 Manishearth

Is this still in the pipeline? Would significantly simplify my use case testing reasonably complex serde structures.

h4l7 avatar Mar 30 '22 15:03 h4l7

AFAIK, no one has ever started implementing this. It seems like it is generally wanted/useful, so if you want to take a shot at implementing it, I would be happy to review/give feedback/etc.

fitzgen avatar Mar 30 '22 15:03 fitzgen

in cases where it's only the orphan rules prevent deriving Arbitrary, we could do a remote derive like serde does. I also like the idea of a function override as described before, and there's not full overlap

evanrichter avatar Jun 15 '22 13:06 evanrichter

I would love to have this. Otherwise it's almost impossible to apply Arbitrary in a big project, because there is always 2-3% of fields, that are not like others.

greyblake avatar Aug 13 '22 19:08 greyblake

FYI: I created ArbitraryExt crate which provides a temporal workaround for this problem.

greyblake avatar Oct 18 '22 15:10 greyblake

Would you like to turn that into a pull request for this crate?

fitzgen avatar Oct 18 '22 19:10 fitzgen

@fitzgen Sure.

For now, ArbitraryExt is a quick and dirty prototype. E.g. I just applied it to my code base, it I quickly found that a few things are missing. Once I implement everything I need and test it against a large code base, I will port it to Arbitrary and open a PR. I'll keep you updated.

greyblake avatar Oct 18 '22 19:10 greyblake

@fitzgen Ok, I've opened a PR: https://github.com/rust-fuzz/arbitrary/pull/129

greyblake avatar Oct 19 '22 10:10 greyblake

This can be marked as resolved (since https://github.com/rust-fuzz/arbitrary/pull/129 is merged)

greyblake avatar Oct 20 '22 20:10 greyblake