From feef26e4932d4115a94a792ba146d24874711c5d Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 8 Nov 2024 08:40:50 -0800 Subject: [PATCH] Deps: Update `arbitrary` to 1.4.1. Includes implementing the new recommended `try_size_hint()` for recursive types. --- Cargo.lock | 8 ++-- Cargo.toml | 2 +- all-is-cubes-base/src/math/vol.rs | 15 ++++-- all-is-cubes/src/block/attributes.rs | 23 +++++---- all-is-cubes/src/block/block_def.rs | 1 + all-is-cubes/src/block/eval/evaluated.rs | 19 +++++++- all-is-cubes/src/block/text.rs | 17 +++++-- all-is-cubes/src/inv/tool.rs | 15 ++++-- all-is-cubes/src/universe.rs | 60 +++++++++++++++--------- all-is-cubes/src/universe/handle.rs | 18 +++++-- fuzz/Cargo.toml | 2 +- 11 files changed, 126 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed37e561c..935ed11d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -454,9 +454,9 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] @@ -1719,9 +1719,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7b7faee67..3779b35fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ allocation-counter = { version = "0.8.1", default-features = false } # Only used in std-using packages, so default features enabled anyhow = "1.0.70" # Each use should be { optional = true }. -arbitrary = { version = "1.3.2", features = ["derive"] } +arbitrary = { version = "1.4.1", features = ["derive"] } arrayvec = { version = "0.7.4", default-features = false } async_fn_traits = { version = "0.1.1", default-features = false } base64 = { version = "0.22.1", default-features = false } diff --git a/all-is-cubes-base/src/math/vol.rs b/all-is-cubes-base/src/math/vol.rs index bfcb78ed6..c7c432de0 100644 --- a/all-is-cubes-base/src/math/vol.rs +++ b/all-is-cubes-base/src/math/vol.rs @@ -741,15 +741,22 @@ pub(crate) mod vol_arb { } fn size_hint(depth: usize) -> (usize, Option) { - arbitrary::size_hint::recursion_guard(depth, |depth| { - let (lower, upper) = V::size_hint(depth); - arbitrary::size_hint::and( + // recommended impl from trait documentation + Self::try_size_hint(depth).unwrap_or_default() + } + + fn try_size_hint( + depth: usize, + ) -> Result<(usize, Option), arbitrary::MaxRecursionReached> { + arbitrary::size_hint::try_recursion_guard(depth, |depth| { + let (lower, upper) = V::try_size_hint(depth)?; + Ok(arbitrary::size_hint::and( ARBITRARY_BOUNDS_SIZE_HINT, ( lower.saturating_mul(MAX_VOLUME), upper.map(|u| u.saturating_mul(MAX_VOLUME)), ), - ) + )) }) } } diff --git a/all-is-cubes/src/block/attributes.rs b/all-is-cubes/src/block/attributes.rs index 665e0526f..8a74887b6 100644 --- a/all-is-cubes/src/block/attributes.rs +++ b/all-is-cubes/src/block/attributes.rs @@ -214,14 +214,21 @@ impl<'a> arbitrary::Arbitrary<'a> for BlockAttributes { } fn size_hint(depth: usize) -> (usize, Option) { - arbitrary::size_hint::and_all(&[ - alloc::string::String::size_hint(depth), - bool::size_hint(depth), - InvInBlock::size_hint(depth), - RotationPlacementRule::size_hint(depth), - TickAction::size_hint(depth), - AnimationHint::size_hint(depth), - ]) + Self::try_size_hint(depth).unwrap_or_default() + } + fn try_size_hint( + depth: usize, + ) -> Result<(usize, Option), arbitrary::MaxRecursionReached> { + arbitrary::size_hint::try_recursion_guard(depth, |depth| { + Ok(arbitrary::size_hint::and_all(&[ + alloc::string::String::try_size_hint(depth)?, + bool::try_size_hint(depth)?, + InvInBlock::try_size_hint(depth)?, + RotationPlacementRule::try_size_hint(depth)?, + TickAction::try_size_hint(depth)?, + AnimationHint::try_size_hint(depth)?, + ])) + }) } } diff --git a/all-is-cubes/src/block/block_def.rs b/all-is-cubes/src/block/block_def.rs index b3a98911c..6f8447af5 100644 --- a/all-is-cubes/src/block/block_def.rs +++ b/all-is-cubes/src/block/block_def.rs @@ -277,6 +277,7 @@ impl<'a> arbitrary::Arbitrary<'a> for BlockDef { } fn size_hint(depth: usize) -> (usize, Option) { + // We don't need to bother with try_size_hint() because Block short-circuits recursion Block::size_hint(depth) } } diff --git a/all-is-cubes/src/block/eval/evaluated.rs b/all-is-cubes/src/block/eval/evaluated.rs index 47ba3fff3..3bca8bbbb 100644 --- a/all-is-cubes/src/block/eval/evaluated.rs +++ b/all-is-cubes/src/block/eval/evaluated.rs @@ -327,6 +327,12 @@ impl<'a> arbitrary::Arbitrary<'a> for EvaluatedBlock { fn size_hint(depth: usize) -> (usize, Option) { MinEval::size_hint(depth) } + + fn try_size_hint( + depth: usize, + ) -> Result<(usize, Option), arbitrary::MaxRecursionReached> { + MinEval::try_size_hint(depth) + } } /// The result of [AIR].[evaluate()](Block::evaluate), as a constant. @@ -500,7 +506,18 @@ impl<'a> arbitrary::Arbitrary<'a> for MinEval { } fn size_hint(depth: usize) -> (usize, Option) { - arbitrary::size_hint::and(BlockAttributes::size_hint(depth), Evoxels::size_hint(depth)) + Self::try_size_hint(depth).unwrap_or_default() + } + + fn try_size_hint( + depth: usize, + ) -> Result<(usize, Option), arbitrary::MaxRecursionReached> { + arbitrary::size_hint::try_recursion_guard(depth, |depth| { + Ok(arbitrary::size_hint::and( + BlockAttributes::try_size_hint(depth)?, + Evoxels::try_size_hint(depth)?, + )) + }) } } diff --git a/all-is-cubes/src/block/text.rs b/all-is-cubes/src/block/text.rs index 3f501957c..916c21012 100644 --- a/all-is-cubes/src/block/text.rs +++ b/all-is-cubes/src/block/text.rs @@ -418,8 +418,19 @@ impl<'a> arbitrary::Arbitrary<'a> for Text { } fn size_hint(depth: usize) -> (usize, Option) { - arbitrary::size_hint::recursion_guard(depth, |depth| { - arbitrary::size_hint::and_all(&[ + // recommended impl from trait documentation + Self::try_size_hint(depth).unwrap_or_default() + } + + fn try_size_hint( + depth: usize, + ) -> Result<(usize, Option), arbitrary::MaxRecursionReached> { + // Note that `Text` is recursive because `Text` contains `Block` and `Block` contains + // `Text`. However, this will still produce a useful, cheap result because + // `Block::size_hint()` has an explicitly set bound. + + arbitrary::size_hint::try_recursion_guard(depth, |depth| { + Ok(arbitrary::size_hint::and_all(&[ alloc::string::String::size_hint(depth), Font::size_hint(depth), Block::size_hint(depth), @@ -427,7 +438,7 @@ impl<'a> arbitrary::Arbitrary<'a> for Text { Resolution::size_hint(depth), GridAab::size_hint(depth), bool::size_hint(depth), - ]) + ])) }) } } diff --git a/all-is-cubes/src/inv/tool.rs b/all-is-cubes/src/inv/tool.rs index 2f0b38293..ec41e34ca 100644 --- a/all-is-cubes/src/inv/tool.rs +++ b/all-is-cubes/src/inv/tool.rs @@ -596,12 +596,17 @@ impl<'a, T: arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for EphemeralOpaq } fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + fn try_size_hint( + depth: usize, + ) -> Result<(usize, Option), arbitrary::MaxRecursionReached> { use arbitrary::{size_hint, Arbitrary}; - size_hint::recursion_guard(depth, |depth| { - size_hint::and( - ::size_hint(depth), - ::size_hint(depth), - ) + size_hint::try_recursion_guard(depth, |depth| { + Ok(size_hint::and( + ::size_hint(depth), + ::try_size_hint(depth)?, + )) }) } } diff --git a/all-is-cubes/src/universe.rs b/all-is-cubes/src/universe.rs index 6f3ce168f..9d6f5af4a 100644 --- a/all-is-cubes/src/universe.rs +++ b/all-is-cubes/src/universe.rs @@ -117,28 +117,44 @@ impl fmt::Display for Name { // Manual impl because `ArcStr` doesn't impl Arbitrary. #[cfg(feature = "arbitrary")] -impl<'a> arbitrary::Arbitrary<'a> for Name { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - Ok(match u.int_in_range::(0..=2)? { - 0 => Name::Specific(u.arbitrary::()?.into()), - 1 => Name::Anonym(u.arbitrary()?), - 2 => Name::Pending, - _ => unreachable!(), - }) - } - - fn size_hint(depth: usize) -> (usize, Option) { - use arbitrary::size_hint; - size_hint::recursion_guard(depth, |depth| { - size_hint::and( - u8::size_hint(depth), - size_hint::or_all(&[ - String::size_hint(depth), - usize::size_hint(depth), - <()>::size_hint(depth), - ]), - ) - }) +mod impl_arbitrary { + use super::*; + #[derive(arbitrary::Arbitrary)] + enum ArbName { + Specific(String), + Anonym(usize), + Pending, + } + + impl<'a> arbitrary::Arbitrary<'a> for Name { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + let input = ArbName::arbitrary(u)?; + let value = match input { + ArbName::Specific(name) => Name::Specific(name.into()), + ArbName::Anonym(index) => Name::Anonym(index), + ArbName::Pending => Name::Pending, + }; + if false { + // This non-executed code proves ArbName has as many variants as Name + let _ = match value { + Name::Specific(name) => ArbName::Specific(name.to_string()), + Name::Anonym(index) => ArbName::Anonym(index), + Name::Pending => ArbName::Pending, + }; + unreachable!() + } else { + Ok(value) + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + ArbName::size_hint(depth) + } + fn try_size_hint( + depth: usize, + ) -> arbitrary::Result<(usize, Option), arbitrary::MaxRecursionReached> { + ArbName::try_size_hint(depth) + } } } diff --git a/all-is-cubes/src/universe/handle.rs b/all-is-cubes/src/universe/handle.rs index 6cc0686ad..d6531e9b3 100644 --- a/all-is-cubes/src/universe/handle.rs +++ b/all-is-cubes/src/universe/handle.rs @@ -483,14 +483,22 @@ impl<'a, T: arbitrary::Arbitrary<'a> + 'static> arbitrary::Arbitrary<'a> for Han } fn size_hint(depth: usize) -> (usize, Option) { - arbitrary::size_hint::recursion_guard(depth, |depth| { - arbitrary::size_hint::and( + Self::try_size_hint(depth).unwrap_or_default() + } + fn try_size_hint( + depth: usize, + ) -> Result<(usize, Option), arbitrary::MaxRecursionReached> { + arbitrary::size_hint::try_recursion_guard(depth, |depth| { + Ok(arbitrary::size_hint::and( bool::size_hint(depth), arbitrary::size_hint::or( - Name::size_hint(depth), - arbitrary::size_hint::and(Name::size_hint(depth), T::size_hint(depth)), + Name::try_size_hint(depth)?, + arbitrary::size_hint::and( + Name::try_size_hint(depth)?, + T::try_size_hint(depth)?, + ), ), - ) + )) }) } } diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 41075de74..bca3ae010 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -14,7 +14,7 @@ cargo-fuzz = true all-is-cubes = { path = "../all-is-cubes", features = ["arbitrary"] } all-is-cubes-gpu = { path = "../all-is-cubes-gpu" } all-is-cubes-mesh = { path = "../all-is-cubes-mesh", features = ["arbitrary"] } -arbitrary = { version = "1.3.2", features = ["derive"] } +arbitrary = { version = "1.4.1", features = ["derive"] } libfuzzer-sys = "0.4" [patch.crates-io]