-
Notifications
You must be signed in to change notification settings - Fork 76
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
Improving support for generating recursive types #78
Comments
I find that the best approach in this kind of situation is to use a helper function: impl<'a> Arbitrary<'a> for Expression {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
arbitrary_expr(u, 0)
}
}
fn arbitrary_expr(u: &mut Unstructured, depth: u32) -> arbitrary::Result<Expression> {
if depth >= MAX_DEPTH {
// non-recursive version here...
} else {
match u.int_in_range(0..=4) {
0 => Ok(Expression::Constant(u.arbitrary()?)),
1 => Ok(Expression::X),
2 => Ok(Expression::Y),
// recursive calls increment depth
3 => Ok(Expression::Add(
Box::new(arbitrary_expr(u, depth + 1)?),
Box::new(arbitrary_expr(u, depth + 1)?),
),
_ => unreachable!(),
}
}
} This approach also doesn't require changes in the |
For a real world example, check out |
Thanks for the suggestion, this should work for me; I'm happy to close this issue out. Should we put this recommendation in the docs anywhere, to help the next person that might run into this? |
If you'd like to make a pull request, that would be much appreciated! I think a subsection in the crate-level docs or the Thanks! |
I know this issue's closed but I didn't want to open a dupe. Thanks for your work on the lib! I'll throw out there that although the technique of just writing helpers does work, it leaves a lot to be desired in terms of integrating with all the nice exiting implementations arbitrary provides. If you scale up this example a bit to "I want to pass around some context object through all of my arbitrary impls" you can see how that starts to fall down where, if I use helpers for this everywhere, the moment I want to use one of the built-in arbitrary implementations (for an fn arbitrary_thing(u: &mut Unstructured, context: &mut MyContext) -> arbitrary::Result<MyThing> {
MyField { optional_field: ??? }
} If the type of This to me indicates that there'd still be a lot of value in being able to attach a custom context type to the call chain |
Hi!
Would it be possible to update the API to allow implementors of
Arbitrary
to plumb some context through which would be useful when manually implementingArbitrary
?I most often need this to implement a recursion limit when handling arbitrary recursive types, e.g. a tree. There is a workaround involving globals (using
lazy_static
) but it would be much easier to do if the trait supported a method likeArbitrary::with_context()
which took a struct of a user-defined type so I could pass along the depth limit.Here's some abstracted code for what I currently have (with a wrapper struct for making the depth tracking less verbose), if it helps:
This would be simpler if the
Expression::arbitrary()
method could take an argument that it could pass down to the recursive calls.If extending the API in this way isn't possible, do you have suggestions for how best to encode this pattern?
The text was updated successfully, but these errors were encountered: