arbitrary icon indicating copy to clipboard operation
arbitrary copied to clipboard

Support arbitrary 🥁 collections

Open jyn514 opened this issue 2 years ago • 3 comments

I would like to be able to derive(Arbitrary) on a custom struct that happens to contain various collections that aren't in std (e.g. DashMap, SmallVec). I could add optional dependencies on dashmap and smallvec directly to the arbitrary crate, but I'd prefer to do this more generically so that it works for any collection.

I tried to do that as follows:

impl<'a, T: Arbitrary<'a>, C: FromIterator<T>> Arbitrary<'a> for C {
    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
        u.arbitrary_iter().collect()
    }
}

which didn't work:

 1  error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
     --> /Users/jyn/src/arbitrary/src/lib.rs:1158:10
      |
 1158 | impl<'a, T: Arbitrary<'a>, C: FromIterator<T>> Arbitrary<'a> for C {
      |          ^ unconstrained type parameter

I have two questions:

  1. Before I spent more time on it, is this a feature you're interested in?
  2. Do you have suggestions for how to get it working?

jyn514 avatar Jun 23 '23 20:06 jyn514

ok, I think this idea cannot work.

impl<'a, T: Arbitrary<'a>, C: std::iter::FromIterator<T> + std::iter::IntoIterator<Item = T>> Arbitrary<'a> for C {
    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
        u.arbitrary_iter().collect()
    }
}
 1  error[E0119]: conflicting implementations of trait `Arbitrary<'_>` for type `()`
     --> /Users/jyn/src/arbitrary/src/lib.rs:1157:1
      |
 283  | impl<'a> Arbitrary<'a> for () {
      | ----------------------------- first implementation here
 ...
 1157 | impl<'a, T: Arbitrary<'a>, C: std::iter::FromIterator<T> + std::iter::IntoIterator<Item = T>> Arbitrary<'a> for C {
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflict
      |
      = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions

jyn514 avatar Jun 23 '23 20:06 jyn514

You can only commit to a single blanket impl per trait, and it severely restricts downstream impls, so I'm opposed to introducing any new blanket impl.

However, this may be possible by instead introducing a #[from_iterator] field attribute (perhaps with a T parameter though I suspect inference will usually work) that tweaks the methods used to construct the type.

Manishearth avatar Jun 24 '23 03:06 Manishearth

i ended up not needing this (turns out smallvec already supports arbitrary and i needed custom logic for my dashmap struct anyway) but i don't mind keeping the issue open if you're interested in #[from_iterator].

jyn514 avatar Jun 30 '23 15:06 jyn514