├── .github └── workflows │ └── rust.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── derive ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ ├── container_attributes.rs │ ├── field_attributes.rs │ ├── lib.rs │ └── variant_attributes.rs ├── examples └── derive_enum.rs ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzz_targets │ └── int_in_range.rs ├── publish.sh ├── src ├── error.rs ├── foreign │ ├── alloc │ │ ├── borrow.rs │ │ ├── boxed.rs │ │ ├── collections │ │ │ ├── binary_heap.rs │ │ │ ├── btree_map.rs │ │ │ ├── btree_set.rs │ │ │ ├── linked_list.rs │ │ │ ├── mod.rs │ │ │ └── vec_deque.rs │ │ ├── ffi │ │ │ ├── c_str.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── rc.rs │ │ ├── string.rs │ │ ├── sync.rs │ │ └── vec.rs │ ├── core │ │ ├── array.rs │ │ ├── bool.rs │ │ ├── cell.rs │ │ ├── char.rs │ │ ├── cmp.rs │ │ ├── iter.rs │ │ ├── marker.rs │ │ ├── mod.rs │ │ ├── num.rs │ │ ├── ops.rs │ │ ├── option.rs │ │ ├── result.rs │ │ ├── slice.rs │ │ ├── str.rs │ │ ├── sync │ │ │ ├── atomic.rs │ │ │ └── mod.rs │ │ ├── time.rs │ │ ├── tuple.rs │ │ └── unit.rs │ ├── mod.rs │ └── std │ │ ├── collections │ │ ├── hash_map.rs │ │ ├── hash_set.rs │ │ └── mod.rs │ │ ├── ffi │ │ ├── c_str.rs │ │ ├── mod.rs │ │ └── os_str.rs │ │ ├── mod.rs │ │ ├── net.rs │ │ ├── path.rs │ │ └── sync.rs ├── lib.rs ├── size_hint.rs ├── tests.rs └── unstructured.rs └── tests ├── bound.rs ├── derive.rs └── path.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | vanilla_build: 7 | name: Vanilla Build 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - run: rustup update 12 | - name: Build 13 | run: cargo build --verbose --all 14 | - name: Run tests 15 | run: cargo test --verbose --all 16 | all_features_build: 17 | name: All Features Enabled Build 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | - run: rustup update 22 | - name: Build 23 | run: cargo build --verbose --all-features --all 24 | - name: Run tests 25 | run: cargo test --verbose --all-features --all 26 | - name: Build Examples 27 | run: cargo build --examples --all-features --all 28 | msrv: 29 | name: Minimum Supported Rust Version 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v3 33 | - run: rustup toolchain add 1.63 34 | - name: Build 35 | run: cargo +1.63 check --lib --all-features 36 | clippy: 37 | name: Clippy 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v3 41 | - run: rustup update 42 | - run: rustup component add clippy 43 | - run: cargo clippy --all-features --workspace -- -Dclippy::all 44 | rustfmt: 45 | name: Check rustfmt 46 | runs-on: ubuntu-latest 47 | steps: 48 | - uses: actions/checkout@v3 49 | - run: rustup update 50 | - run: rustup component add rustfmt --toolchain stable 51 | - run: cargo +stable fmt --all -- --check 52 | fuzz: 53 | name: Run `int_in_range` fuzz target 54 | runs-on: ubuntu-latest 55 | steps: 56 | - uses: actions/checkout@v3 57 | - run: rustup update 58 | - name: "Install nightly" 59 | run: rustup toolchain install nightly && rustup default nightly 60 | - name: "Install `cargo-fuzz`" 61 | run: cargo install cargo-fuzz 62 | - name: "Fuzz for 3 minutes" 63 | run: cargo fuzz run int_in_range -- -max_total_time=$((3 * 60)) 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Unreleased 2 | 3 | Released YYYY-MM-DD. 4 | 5 | ### Added 6 | 7 | * TODO (or remove section if none) 8 | 9 | ### Changed 10 | 11 | * TODO (or remove section if none) 12 | 13 | ### Deprecated 14 | 15 | * TODO (or remove section if none) 16 | 17 | ### Removed 18 | 19 | * TODO (or remove section if none) 20 | 21 | ### Fixed 22 | 23 | * TODO (or remove section if none) 24 | 25 | ### Security 26 | 27 | * TODO (or remove section if none) 28 | 29 | -------------------------------------------------------------------------------- 30 | 31 | ## 1.4.0 32 | 33 | Released 2024-10-30. 34 | 35 | ### Added 36 | 37 | * Added an `Arbitrary` implementation for `PhantomPinned`. 38 | * Added the `Unstructured::choose_iter` helper method. 39 | * Added `#[arbitrary(skip)]` for `enum` variants in the derive macro. 40 | * Added the `Arbitrary::try_size_hint` trait method. 41 | 42 | ### Changed 43 | 44 | * Implement `Arbitrary` for `PhantomData` even when `A` does not implement 45 | `Arbitrary` and when `A` is `?Sized`. 46 | * Make `usize`'s underlying encoding independent of machine word size so that 47 | corpora are more portable. 48 | 49 | ### Fixed 50 | 51 | * Make `derive(Arbitrary)` work for local definitions of `struct Option`. 52 | 53 | -------------------------------------------------------------------------------- 54 | 55 | ## 1.3.2 56 | 57 | Released 2023-10-30. 58 | 59 | ### Added 60 | 61 | * Added `Arbitrary` implementations for `Arc<[T]>` and 62 | `Rc<[T]>`. [#160](https://github.com/rust-fuzz/arbitrary/pull/160) 63 | 64 | -------------------------------------------------------------------------------- 65 | 66 | ## 1.3.1 67 | 68 | Released 2023-10-11. 69 | 70 | ### Fixed 71 | 72 | * Fixed an issue with generating collections of collections in 73 | `arbitrary_take_rest` where `>>::arbitrary_take_rest` would never 74 | generate `vec![vec![]]` for example. See 75 | [#159](https://github.com/rust-fuzz/arbitrary/pull/159) for details. 76 | 77 | -------------------------------------------------------------------------------- 78 | 79 | ## 1.3.0 80 | 81 | Released 2023-03-13. 82 | 83 | ### Added 84 | 85 | * Added the ability to manually specify derived trait bounds for 86 | `Arbitrary`. See [#138](https://github.com/rust-fuzz/arbitrary/pull/138) for 87 | details. 88 | 89 | ### Fixed 90 | 91 | * Fixed minimal versions correctness for `syn`. 92 | 93 | -------------------------------------------------------------------------------- 94 | 95 | ## 1.2.3 96 | 97 | Released 2023-01-20. 98 | 99 | ### Fixed 100 | 101 | * The `derive(Arbitrary)` will now annotate the generated `impl`s with a `#[automatically_derived]` 102 | attribute to indicate to e.g. clippy that lints should not fire for the code within the derived 103 | implementation. 104 | 105 | ## 1.2.2 106 | 107 | Released 2023-01-03. 108 | 109 | ### Fixed 110 | 111 | * Ensured that `arbitrary` and `derive_arbitrary` versions are synced up so that 112 | they don't, e.g., emit generated code that depends on newer versions of 113 | `arbitrary` than the one currently in 114 | use. [#134](https://github.com/rust-fuzz/arbitrary/issues/134) 115 | 116 | ## 1.2.1 117 | 118 | ### Fixed 119 | 120 | * Fixed an issue where `std::thread_local!` macro invocations in derive code 121 | were not fully prefixed, causing confusing build errors in certain situations. 122 | 123 | ## 1.2.0 124 | 125 | Released 2022-10-20. 126 | 127 | ### Added 128 | 129 | * Support custom arbitrary implementation for fields on 130 | derive. [#129](https://github.com/rust-fuzz/arbitrary/pull/129) 131 | 132 | -------------------------------------------------------------------------------- 133 | 134 | ## 1.1.6 135 | 136 | Released 2022-09-20. 137 | 138 | ### Fixed 139 | 140 | * Fixed a potential panic due to an off-by-one error in the `Arbitrary` 141 | implementation for `std::ops::Bound`. 142 | 143 | -------------------------------------------------------------------------------- 144 | 145 | ## 1.1.5 146 | 147 | Released 2022-09-08. 148 | 149 | ### Added 150 | 151 | * Implemented `Arbitrary` for `std::ops::Bound`. 152 | 153 | ### Fixed 154 | 155 | * Fixed a bug where `Unstructured::int_in_range` could return out-of-range 156 | integers when generating arbitrary signed integers. 157 | 158 | -------------------------------------------------------------------------------- 159 | 160 | ## 1.1.4 161 | 162 | Released 2022-08-29. 163 | 164 | ### Added 165 | 166 | * Implemented `Arbitrary` for `Rc` and `Arc` 167 | 168 | ### Changed 169 | 170 | * Allow overriding the error type in `arbitrary::Result` 171 | * The `Unstructured::arbitrary_loop` method will consume fewer bytes of input 172 | now. 173 | 174 | ### Fixed 175 | 176 | * Fixed a bug where `Unstructured::int_in_range` could return out-of-range 177 | integers. 178 | 179 | -------------------------------------------------------------------------------- 180 | 181 | ## 1.1.3 182 | 183 | Released 2022-06-23. 184 | 185 | ### Fixed 186 | 187 | * Fixed some potential (but highly unlikely) name-clashes inside 188 | `derive(Arbitrary)`'s generated 189 | code. [#111](https://github.com/rust-fuzz/arbitrary/pull/111) 190 | * Fixed an edge case where `derive(Arbitrary)` for recursive types that detected 191 | an overflow would not reset the overflow 192 | detection. [#111](https://github.com/rust-fuzz/arbitrary/pull/111) 193 | 194 | -------------------------------------------------------------------------------- 195 | 196 | ## 1.1.2 197 | 198 | Released 2022-06-16. 199 | 200 | ### Fixed 201 | 202 | * Fixed a warning inside `derive(Arbitrary)`-generated 203 | code. [#110](https://github.com/rust-fuzz/arbitrary/pull/110) 204 | 205 | -------------------------------------------------------------------------------- 206 | 207 | ## 1.1.1 208 | 209 | Released 2022-06-14. 210 | 211 | ### Fixed 212 | 213 | * Fixed a stack overflow when using `derive(Arbitrary)` with recursive types and 214 | empty inputs. [#109](https://github.com/rust-fuzz/arbitrary/pull/109) 215 | 216 | -------------------------------------------------------------------------------- 217 | 218 | ## 1.1.0 219 | 220 | Released 2022-02-09. 221 | 222 | ### Added 223 | 224 | * Added the `Unstructured::ratio` method to generate a boolean that is `true` at 225 | the given rate. 226 | 227 | * Added the `Unstructured::arbitrary_loop` method to call a function an 228 | arbitrary number of times. 229 | 230 | -------------------------------------------------------------------------------- 231 | 232 | ## 1.0.3 233 | 234 | Released 2021-11-20. 235 | 236 | ### Fixed 237 | 238 | * Fixed documentation for `Unstructured::fill_bytes`. We forgot to update this 239 | way back in [#53](https://github.com/rust-fuzz/arbitrary/pull/53) when the 240 | behavior changed. 241 | 242 | -------------------------------------------------------------------------------- 243 | 244 | ## 1.0.2 245 | 246 | Released 2021-08-25. 247 | 248 | ### Added 249 | 250 | * `Arbitrary` impls for `HashMap`s and `HashSet`s with custom `Hasher`s 251 | [#87](https://github.com/rust-fuzz/arbitrary/pull/87) 252 | 253 | -------------------------------------------------------------------------------- 254 | 255 | ## 1.0.1 256 | 257 | Released 2021-05-20. 258 | 259 | ### Added 260 | 261 | * `Arbitrary` impls for `NonZeroX` types [#79](https://github.com/rust-fuzz/arbitrary/pull/79) 262 | * `Arbitrary` impls for all arrays using const generics [#55](https://github.com/rust-fuzz/arbitrary/pull/55) 263 | * `Arbitrary` impls for `Ipv4Addr` and `Ipv6Addr` [#84](https://github.com/rust-fuzz/arbitrary/pull/84) 264 | 265 | ### Fixed 266 | 267 | * Use fewer bytes for `Unstructured::int_in_range()` [#80](https://github.com/rust-fuzz/arbitrary/pull/80) 268 | * Use correct range for `char` generation [#83](https://github.com/rust-fuzz/arbitrary/pull/83) 269 | 270 | -------------------------------------------------------------------------------- 271 | 272 | ## 1.0.0 273 | 274 | Released 2020-02-24. 275 | 276 | See 1.0.0-rc1 and 1.0.0-rc2 for changes since 0.4.7, which was the last main 277 | line release. 278 | 279 | -------------------------------------------------------------------------------- 280 | 281 | ## 1.0.0-rc2 282 | 283 | Released 2021-02-09. 284 | 285 | ### Added 286 | 287 | * The `Arbitrary` trait is now implemented for `&[u8]`. [#67](https://github.com/rust-fuzz/arbitrary/pull/67) 288 | 289 | ### Changed 290 | 291 | * Rename `Unstructured#get_bytes` to `Unstructured#bytes`. [#70](https://github.com/rust-fuzz/arbitrary/pull/70) 292 | * Passing an empty slice of choices to `Unstructured#choose` returns an error. Previously it would panic. [71](https://github.com/rust-fuzz/arbitrary/pull/71) 293 | 294 | -------------------------------------------------------------------------------- 295 | 296 | ## 1.0.0-rc1 297 | 298 | Released 2020-11-25. 299 | 300 | ### Added 301 | 302 | * The `Arbitrary` trait is now implemented for `&str`. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) 303 | 304 | ### Changed 305 | 306 | * The `Arbitrary` trait now has a lifetime parameter, allowing `Arbitrary` implementations that borrow from the raw input (e.g. the new `&str` implementaton). The `derive(Arbitrary)` macro also supports deriving `Arbitrary` on types with lifetimes now. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) 307 | 308 | ### Removed 309 | 310 | * The `shrink` method on the `Arbitrary` trait has been removed. 311 | 312 | We have found that, in practice, using [internal reduction](https://drmaciver.github.io/papers/reduction-via-generation-preview.pdf) via approaches like `cargo fuzz tmin`, where the raw input bytes are reduced rather than the `T: Arbitrary` type constructed from those raw bytes, has the best efficiency-to-maintenance ratio. To the best of our knowledge, no one is relying on or using the `Arbitrary::shrink` method. If you *are* using and relying on the `Arbitrary::shrink` method, please reach out by [dropping a comment here](https://github.com/rust-fuzz/arbitrary/issues/62) and explaining how you're using it and what your use case is. We'll figure out what the best solution is, including potentially adding shrinking functionality back to the `arbitrary` crate. 313 | 314 | -------------------------------------------------------------------------------- 315 | 316 | ## 0.4.7 317 | 318 | Released 2020-10-14. 319 | 320 | ### Added 321 | 322 | * Added an optimization to avoid unnecessarily consuming bytes from the 323 | underlying data when there is only one possible choice in 324 | `Unstructured::{int_in_range, choose, etc..}`. 325 | 326 | * Added license files to the derive crate. 327 | 328 | ### Changed 329 | 330 | * The `Arbitrary` implementation for `std::time::Duration` should now be faster 331 | and produce durations with a more-uniform distribution of nanoseconds. 332 | 333 | -------------------------------------------------------------------------------- 334 | 335 | ## 0.4.6 336 | 337 | Released 2020-08-22. 338 | 339 | ### Added 340 | 341 | * Added the `Unstructured::peek_bytes` method. 342 | 343 | ### Changed 344 | 345 | * Test case reduction via `cargo fuzz tmin` should be much more effective at 346 | reducing the sizes of collections now. (See 347 | [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit messages 348 | for details.) 349 | 350 | * Fuzzing with mutation-based fuzzers (like libFuzzer) should be more efficient 351 | now. (See [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit 352 | messages for details) 353 | 354 | -------------------------------------------------------------------------------- 355 | 356 | ## 0.4.5 357 | 358 | Released 2020-06-18. 359 | 360 | ### Added 361 | 362 | * Implement `Arbitrary` for zero length arrays. 363 | * Implement `Arbitrary` for `Range` and `RangeInclusive`. 364 | 365 | -------------------------------------------------------------------------------- 366 | 367 | ## 0.4.4 368 | 369 | Released 2020-04-29. 370 | 371 | ### Fixed 372 | 373 | * Fixed the custom derive for enums when used via its full path (like 374 | `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`). 375 | 376 | 377 | ## 0.4.3 378 | 379 | Released 2020-04-28. 380 | 381 | ### Fixed 382 | 383 | * Fixed the custom derive when used via its full path (like 384 | `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`). 385 | 386 | -------------------------------------------------------------------------------- 387 | 388 | ## 0.4.2 389 | 390 | Released 2020-04-17. 391 | 392 | ### Changed 393 | 394 | * We forgot to release a new version of the `derive_arbitrary` crate last 395 | release. This release fixes that and so the `synstructure` dependency is 396 | finally actually removed in the cargo releases. 397 | 398 | -------------------------------------------------------------------------------- 399 | 400 | ## 0.4.1 401 | 402 | Released 2020-03-18. 403 | 404 | ### Removed 405 | 406 | * Removed an internal dependency on the `synstructure` crate when the `derive` 407 | feature is enabled. This should not have any visible downstream effects other 408 | than faster build times! 409 | 410 | -------------------------------------------------------------------------------- 411 | 412 | ## 0.4.0 413 | 414 | Released 2020-01-22. 415 | 416 | This is technically a breaking change, but we expect that nearly everyone should 417 | be able to upgrade without any compilation errors. The only exception is if you 418 | were implementing the `Arbitrary::size_hint` method by hand. If so, see the 419 | "changed" section below and the [API docs for 420 | `Arbitrary::shrink`](https://docs.rs/arbitrary/0.4.0/arbitrary/trait.Arbitrary.html#method.size_hint) 421 | for details. 422 | 423 | ### Added 424 | 425 | * Added [the `arbitary::size_hint::recursion_guard` helper 426 | function][recursion_guard] for guarding against infinite recursion in 427 | `size_hint` implementations for recursive types. 428 | 429 | ### Changed 430 | 431 | * The `Arbitrary::size_hint` signature now takes a `depth: usize` 432 | parameter. This should be passed along unmodified to any nested calls of other 433 | `size_hint` methods. If you're implementing `size_hint` for a recursive type 434 | (like a linked list or tree) or a generic type with type parameters, you 435 | should use [the new `arbitrary::size_hint::recursion_guard` helper 436 | function][recursion_guard]. 437 | 438 | ### Fixed 439 | 440 | * Fixed infinite recursion in generated `size_hint` implementations 441 | from `#[derive(Arbitrary)]` for recursive types. 442 | 443 | [recursion_guard]: https://docs.rs/arbitrary/0.4.0/arbitrary/size_hint/fn.recursion_guard.html 444 | 445 | -------------------------------------------------------------------------------- 446 | 447 | ## 0.3.2 448 | 449 | Released 2020-01-16. 450 | 451 | ### Changed 452 | 453 | * Updated the custom derive's dependencies. 454 | 455 | -------------------------------------------------------------------------------- 456 | 457 | ## 0.3.2 458 | 459 | Released 2020-01-15. 460 | 461 | ### Fixed 462 | 463 | * Fixed an over-eager assertion condition in `Unstructured::int_in_range` that 464 | would incorrectly trigger when given valid ranges of length one. 465 | 466 | -------------------------------------------------------------------------------- 467 | 468 | ## 0.3.1 469 | 470 | Released 2020-01-14. 471 | 472 | ### Fixed 473 | 474 | * Fixed some links and version numbers in README. 475 | 476 | -------------------------------------------------------------------------------- 477 | 478 | ## 0.3.0 479 | 480 | Released 2020-01-14. 481 | 482 | ### Added 483 | 484 | * Added the `"derive"` cargo feature, to enable `#[derive(Arbitrary)]` for 485 | custom types. Enabling this feature re-exports functionality from the 486 | `derive_arbitrary` crate. 487 | * The custom derive for `Arbitrary` implements the shrink method for you now. 488 | * All implementations of `Arbitrary` for `std` types implement shrinking now. 489 | * Added the `Arbitrary::arbitrary_take_rest` method allows an `Arbitrary` 490 | implementation to consume all of the rest of the remaining raw input. It has a 491 | default implementation that forwards to `Arbitrary::arbitrary` and the custom 492 | derive creates a smart implementation for your custom types. 493 | * Added the `Arbitrary::size_hint` method for hinting how many raw bytes an 494 | implementation needs to construct itself. This has a default implementation, 495 | but the custom derive creates a smart implementation for your custom types. 496 | * Added the `Unstructured::choose` method to choose one thing among a set of 497 | choices. 498 | * Added the `Unstructured::arbitrary_len` method to get an arbitrary length for 499 | a collection of some arbitrary type. 500 | * Added the `Unstructured::arbitrary_iter` method to create an iterator of 501 | arbitrary instance of some type. 502 | 503 | ### Changed 504 | 505 | * The `Arbitrary` trait was simplified a bit. 506 | * `Unstructured` is a concrete type now, not a trait. 507 | * Switched to Rust 2018 edition. 508 | 509 | ### Removed 510 | 511 | * `RingBuffer` and `FiniteBuffer` are removed. Use `Unstructured` instead. 512 | 513 | ### Fixed 514 | 515 | * Better `Arbitrary` implementation for `char`. 516 | * Better `Arbitrary` implementation for `String`. 517 | 518 | -------------------------------------------------------------------------------- 519 | 520 | ## 0.2.0 521 | 522 | -------------------------------------------------------------------------------- 523 | 524 | ## 0.1.0 525 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arbitrary" 3 | version = "1.4.1" # Make sure this matches the derive crate version (not including the patch version) 4 | authors = [ 5 | "The Rust-Fuzz Project Developers", 6 | "Nick Fitzgerald ", 7 | "Manish Goregaokar ", 8 | "Simonas Kazlauskas ", 9 | "Brian L. Troutwine ", 10 | "Corey Farwell ", 11 | ] 12 | categories = ["development-tools::testing"] 13 | edition = "2021" 14 | keywords = ["arbitrary", "testing"] 15 | readme = "README.md" 16 | description = "The trait for generating structured data from unstructured data" 17 | license = "MIT OR Apache-2.0" 18 | repository = "https://github.com/rust-fuzz/arbitrary/" 19 | documentation = "https://docs.rs/arbitrary/" 20 | rust-version = "1.63.0" # Keep in sync with version documented in the README.md 21 | 22 | [dependencies] 23 | derive_arbitrary = { version = "~1.4.0", path = "./derive", optional = true } 24 | 25 | [features] 26 | # Turn this feature on to enable support for `#[derive(Arbitrary)]`. 27 | derive = ["derive_arbitrary"] 28 | 29 | [[example]] 30 | name = "derive_enum" 31 | required-features = ["derive"] 32 | 33 | [[test]] 34 | name = "derive" 35 | path = "./tests/derive.rs" 36 | required-features = ["derive"] 37 | 38 | [workspace] 39 | members = ["./fuzz"] 40 | 41 | [dev-dependencies] 42 | exhaustigen = "0.1.0" 43 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Manish Goregaokar 4 | 5 | Permission is hereby granted, free of charge, to any 6 | person obtaining a copy of this software and associated 7 | documentation files (the "Software"), to deal in the 8 | Software without restriction, including without 9 | limitation the rights to use, copy, modify, merge, 10 | publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software 12 | is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions 17 | of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 20 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 21 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 22 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 23 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 26 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | DEALINGS IN THE SOFTWARE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Arbitrary

4 | 5 |

The trait for generating structured data from arbitrary, unstructured input.

6 | 7 | GitHub Actions Status 8 | 9 |
10 | 11 | ## About 12 | 13 | The `Arbitrary` crate lets you construct arbitrary instances of a type. 14 | 15 | This crate is primarily intended to be combined with a fuzzer like [libFuzzer 16 | and `cargo-fuzz`](https://github.com/rust-fuzz/cargo-fuzz) or 17 | [AFL](https://github.com/rust-fuzz/afl.rs), and to help you turn the raw, 18 | untyped byte buffers that they produce into well-typed, valid, structured 19 | values. This allows you to combine structure-aware test case generation with 20 | coverage-guided, mutation-based fuzzers. 21 | 22 | ## Documentation 23 | 24 | [**Read the API documentation on `docs.rs`!**](https://docs.rs/arbitrary) 25 | 26 | ## Example 27 | 28 | Say you're writing a color conversion library, and you have an `Rgb` struct to 29 | represent RGB colors. You might want to implement `Arbitrary` for `Rgb` so that 30 | you could take arbitrary `Rgb` instances in a test function that asserts some 31 | property (for example, asserting that RGB converted to HSL and converted back to 32 | RGB always ends up exactly where we started). 33 | 34 | ### Automatically Deriving `Arbitrary` 35 | 36 | Automatically deriving the `Arbitrary` trait is the recommended way to implement 37 | `Arbitrary` for your types. 38 | 39 | Automatically deriving `Arbitrary` requires you to enable the `"derive"` cargo 40 | feature: 41 | 42 | ```toml 43 | # Cargo.toml 44 | 45 | [dependencies] 46 | arbitrary = { version = "1", features = ["derive"] } 47 | ``` 48 | 49 | And then you can simply add `#[derive(Arbitrary)]` annotations to your types: 50 | 51 | ```rust 52 | // rgb.rs 53 | 54 | use arbitrary::Arbitrary; 55 | 56 | #[derive(Arbitrary)] 57 | pub struct Rgb { 58 | pub r: u8, 59 | pub g: u8, 60 | pub b: u8, 61 | } 62 | ``` 63 | 64 | #### Customizing single fields 65 | 66 | This can be particular handy if your structure uses a type that does not implement `Arbitrary` or you want to have more customization for particular fields. 67 | 68 | ```rust 69 | #[derive(Arbitrary)] 70 | pub struct Rgba { 71 | // set `r` to Default::default() 72 | #[arbitrary(default)] 73 | pub r: u8, 74 | 75 | // set `g` to 255 76 | #[arbitrary(value = 255)] 77 | pub g: u8, 78 | 79 | // Generate `b` with a custom function of type 80 | // 81 | // fn(&mut Unstructured) -> arbitrary::Result 82 | // 83 | // where `T` is the field's type. 84 | #[arbitrary(with = arbitrary_b)] 85 | pub b: u8, 86 | 87 | // Generate `a` with a custom closure (shortcut to avoid a custom function) 88 | #[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=64))] 89 | pub a: u8, 90 | } 91 | 92 | fn arbitrary_b(u: &mut Unstructured) -> arbitrary::Result { 93 | u.int_in_range(64..=128) 94 | } 95 | ``` 96 | 97 | ### Implementing `Arbitrary` By Hand 98 | 99 | Alternatively, you can write an `Arbitrary` implementation by hand: 100 | 101 | ```rust 102 | // rgb.rs 103 | 104 | use arbitrary::{Arbitrary, Result, Unstructured}; 105 | 106 | #[derive(Copy, Clone, Debug)] 107 | pub struct Rgb { 108 | pub r: u8, 109 | pub g: u8, 110 | pub b: u8, 111 | } 112 | 113 | impl<'a> Arbitrary<'a> for Rgb { 114 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 115 | let r = u8::arbitrary(u)?; 116 | let g = u8::arbitrary(u)?; 117 | let b = u8::arbitrary(u)?; 118 | Ok(Rgb { r, g, b }) 119 | } 120 | } 121 | ``` 122 | 123 | ## Minimum Supported Rust Version (MSRV) 124 | 125 | 126 | 127 | This crate is guaranteed to compile on stable Rust **1.63.0** and up. It might 128 | compile with older versions but that may change in any new patch release. 129 | 130 | We reserve the right to increment the MSRV on minor releases, however we will 131 | strive to only do it deliberately and for good reasons. 132 | 133 | ## License 134 | 135 | Licensed under dual MIT or Apache-2.0 at your choice. 136 | 137 | Unless you explicitly state otherwise, any contribution intentionally submitted 138 | for inclusion in this project by you, as defined in the Apache-2.0 license, 139 | shall be dual licensed as above, without any additional terms or conditions. 140 | -------------------------------------------------------------------------------- /derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "derive_arbitrary" 3 | version = "1.4.1" # Make sure it matches the version of the arbitrary crate itself (not including the patch version) 4 | authors = [ 5 | "The Rust-Fuzz Project Developers", 6 | "Nick Fitzgerald ", 7 | "Manish Goregaokar ", 8 | "Andre Bogus ", 9 | "Corey Farwell ", 10 | ] 11 | categories = ["development-tools::testing"] 12 | edition = "2021" 13 | keywords = ["arbitrary", "testing", "derive", "macro"] 14 | readme = "README.md" 15 | description = "Derives arbitrary traits" 16 | license = "MIT OR Apache-2.0" 17 | repository = "https://github.com/rust-fuzz/arbitrary" 18 | documentation = "https://docs.rs/arbitrary/" 19 | rust-version = "1.63.0" 20 | 21 | [dependencies] 22 | proc-macro2 = "1.0" 23 | quote = "1.0" 24 | syn = { version = "2", features = ['derive', 'parsing', 'extra-traits'] } 25 | 26 | [lib] 27 | proc-macro = true 28 | -------------------------------------------------------------------------------- /derive/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /derive/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Manish Goregaokar 4 | 5 | Permission is hereby granted, free of charge, to any 6 | person obtaining a copy of this software and associated 7 | documentation files (the "Software"), to deal in the 8 | Software without restriction, including without 9 | limitation the rights to use, copy, modify, merge, 10 | publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software 12 | is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions 17 | of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 20 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 21 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 22 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 23 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 26 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | DEALINGS IN THE SOFTWARE. 28 | -------------------------------------------------------------------------------- /derive/README.md: -------------------------------------------------------------------------------- 1 | # `#[derive(Arbitrary)]` 2 | 3 | This crate implements support for automatically deriving [the `Arbitrary` 4 | trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html). 5 | 6 | Don't depend on this crate directly, though. Instead, enable the `"derive"` 7 | feature of the `arbitrary` crate. 8 | -------------------------------------------------------------------------------- /derive/src/container_attributes.rs: -------------------------------------------------------------------------------- 1 | use crate::ARBITRARY_ATTRIBUTE_NAME; 2 | use syn::{ 3 | parse::Error, punctuated::Punctuated, DeriveInput, Expr, ExprLit, Lit, Meta, MetaNameValue, 4 | Token, TypeParam, 5 | }; 6 | 7 | pub struct ContainerAttributes { 8 | /// Specify type bounds to be applied to the derived `Arbitrary` implementation instead of the 9 | /// default inferred bounds. 10 | /// 11 | /// ```ignore 12 | /// #[arbitrary(bound = "T: Default, U: Debug")] 13 | /// ``` 14 | /// 15 | /// Multiple attributes will be combined as long as they don't conflict, e.g. 16 | /// 17 | /// ```ignore 18 | /// #[arbitrary(bound = "T: Default")] 19 | /// #[arbitrary(bound = "U: Default")] 20 | /// ``` 21 | pub bounds: Option>>, 22 | } 23 | 24 | impl ContainerAttributes { 25 | pub fn from_derive_input(derive_input: &DeriveInput) -> Result { 26 | let mut bounds = None; 27 | 28 | for attr in &derive_input.attrs { 29 | if !attr.path().is_ident(ARBITRARY_ATTRIBUTE_NAME) { 30 | continue; 31 | } 32 | 33 | let meta_list = match attr.meta { 34 | Meta::List(ref l) => l, 35 | _ => { 36 | return Err(Error::new_spanned( 37 | attr, 38 | format!( 39 | "invalid `{}` attribute. expected list", 40 | ARBITRARY_ATTRIBUTE_NAME 41 | ), 42 | )) 43 | } 44 | }; 45 | 46 | for nested_meta in 47 | meta_list.parse_args_with(Punctuated::::parse_terminated)? 48 | { 49 | match nested_meta { 50 | Meta::NameValue(MetaNameValue { 51 | path, 52 | value: 53 | Expr::Lit(ExprLit { 54 | lit: Lit::Str(bound_str_lit), 55 | .. 56 | }), 57 | .. 58 | }) if path.is_ident("bound") => { 59 | bounds 60 | .get_or_insert_with(Vec::new) 61 | .push(bound_str_lit.parse_with(Punctuated::parse_terminated)?); 62 | } 63 | _ => { 64 | return Err(Error::new_spanned( 65 | attr, 66 | format!( 67 | "invalid `{}` attribute. expected `bound = \"..\"`", 68 | ARBITRARY_ATTRIBUTE_NAME, 69 | ), 70 | )) 71 | } 72 | } 73 | } 74 | } 75 | 76 | Ok(Self { bounds }) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /derive/src/field_attributes.rs: -------------------------------------------------------------------------------- 1 | use crate::ARBITRARY_ATTRIBUTE_NAME; 2 | use proc_macro2::{Span, TokenStream, TokenTree}; 3 | use quote::quote; 4 | use syn::{spanned::Spanned, *}; 5 | 6 | /// Determines how a value for a field should be constructed. 7 | #[cfg_attr(test, derive(Debug))] 8 | pub enum FieldConstructor { 9 | /// Assume that Arbitrary is defined for the type of this field and use it (default) 10 | Arbitrary, 11 | 12 | /// Places `Default::default()` as a field value. 13 | Default, 14 | 15 | /// Use custom function or closure to generate a value for a field. 16 | With(TokenStream), 17 | 18 | /// Set a field always to the given value. 19 | Value(TokenStream), 20 | } 21 | 22 | pub fn determine_field_constructor(field: &Field) -> Result { 23 | let opt_attr = fetch_attr_from_field(field)?; 24 | let ctor = match opt_attr { 25 | Some(attr) => parse_attribute(attr)?, 26 | None => FieldConstructor::Arbitrary, 27 | }; 28 | Ok(ctor) 29 | } 30 | 31 | fn fetch_attr_from_field(field: &Field) -> Result> { 32 | let found_attributes: Vec<_> = field 33 | .attrs 34 | .iter() 35 | .filter(|a| { 36 | let path = a.path(); 37 | let name = quote!(#path).to_string(); 38 | name == ARBITRARY_ATTRIBUTE_NAME 39 | }) 40 | .collect(); 41 | if found_attributes.len() > 1 { 42 | let name = field.ident.as_ref().unwrap(); 43 | let msg = format!( 44 | "Multiple conflicting #[{ARBITRARY_ATTRIBUTE_NAME}] attributes found on field `{name}`" 45 | ); 46 | return Err(syn::Error::new(field.span(), msg)); 47 | } 48 | Ok(found_attributes.into_iter().next()) 49 | } 50 | 51 | fn parse_attribute(attr: &Attribute) -> Result { 52 | if let Meta::List(ref meta_list) = attr.meta { 53 | parse_attribute_internals(meta_list) 54 | } else { 55 | let msg = format!("#[{ARBITRARY_ATTRIBUTE_NAME}] must contain a group"); 56 | Err(syn::Error::new(attr.span(), msg)) 57 | } 58 | } 59 | 60 | fn parse_attribute_internals(meta_list: &MetaList) -> Result { 61 | let mut tokens_iter = meta_list.tokens.clone().into_iter(); 62 | let token = tokens_iter.next().ok_or_else(|| { 63 | let msg = format!("#[{ARBITRARY_ATTRIBUTE_NAME}] cannot be empty."); 64 | syn::Error::new(meta_list.span(), msg) 65 | })?; 66 | match token.to_string().as_ref() { 67 | "default" => Ok(FieldConstructor::Default), 68 | "with" => { 69 | let func_path = parse_assigned_value("with", tokens_iter, meta_list.span())?; 70 | Ok(FieldConstructor::With(func_path)) 71 | } 72 | "value" => { 73 | let value = parse_assigned_value("value", tokens_iter, meta_list.span())?; 74 | Ok(FieldConstructor::Value(value)) 75 | } 76 | _ => { 77 | let msg = format!("Unknown option for #[{ARBITRARY_ATTRIBUTE_NAME}]: `{token}`"); 78 | Err(syn::Error::new(token.span(), msg)) 79 | } 80 | } 81 | } 82 | 83 | // Input: 84 | // = 2 + 2 85 | // Output: 86 | // 2 + 2 87 | fn parse_assigned_value( 88 | opt_name: &str, 89 | mut tokens_iter: impl Iterator, 90 | default_span: Span, 91 | ) -> Result { 92 | let eq_sign = tokens_iter.next().ok_or_else(|| { 93 | let msg = format!( 94 | "Invalid syntax for #[{ARBITRARY_ATTRIBUTE_NAME}], `{opt_name}` is missing assignment." 95 | ); 96 | syn::Error::new(default_span, msg) 97 | })?; 98 | 99 | if eq_sign.to_string() == "=" { 100 | Ok(tokens_iter.collect()) 101 | } else { 102 | let msg = format!("Invalid syntax for #[{ARBITRARY_ATTRIBUTE_NAME}], expected `=` after `{opt_name}`, got: `{eq_sign}`"); 103 | Err(syn::Error::new(eq_sign.span(), msg)) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | 3 | use proc_macro2::{Span, TokenStream}; 4 | use quote::quote; 5 | use syn::*; 6 | 7 | mod container_attributes; 8 | mod field_attributes; 9 | mod variant_attributes; 10 | 11 | use container_attributes::ContainerAttributes; 12 | use field_attributes::{determine_field_constructor, FieldConstructor}; 13 | use variant_attributes::not_skipped; 14 | 15 | const ARBITRARY_ATTRIBUTE_NAME: &str = "arbitrary"; 16 | const ARBITRARY_LIFETIME_NAME: &str = "'arbitrary"; 17 | 18 | #[proc_macro_derive(Arbitrary, attributes(arbitrary))] 19 | pub fn derive_arbitrary(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { 20 | let input = syn::parse_macro_input!(tokens as syn::DeriveInput); 21 | expand_derive_arbitrary(input) 22 | .unwrap_or_else(syn::Error::into_compile_error) 23 | .into() 24 | } 25 | 26 | fn expand_derive_arbitrary(input: syn::DeriveInput) -> Result { 27 | let container_attrs = ContainerAttributes::from_derive_input(&input)?; 28 | 29 | let (lifetime_without_bounds, lifetime_with_bounds) = 30 | build_arbitrary_lifetime(input.generics.clone()); 31 | 32 | let recursive_count = syn::Ident::new( 33 | &format!("RECURSIVE_COUNT_{}", input.ident), 34 | Span::call_site(), 35 | ); 36 | 37 | let arbitrary_method = 38 | gen_arbitrary_method(&input, lifetime_without_bounds.clone(), &recursive_count)?; 39 | let size_hint_method = gen_size_hint_method(&input)?; 40 | let name = input.ident; 41 | 42 | // Apply user-supplied bounds or automatic `T: ArbitraryBounds`. 43 | let generics = apply_trait_bounds( 44 | input.generics, 45 | lifetime_without_bounds.clone(), 46 | &container_attrs, 47 | )?; 48 | 49 | // Build ImplGeneric with a lifetime (https://github.com/dtolnay/syn/issues/90) 50 | let mut generics_with_lifetime = generics.clone(); 51 | generics_with_lifetime 52 | .params 53 | .push(GenericParam::Lifetime(lifetime_with_bounds)); 54 | let (impl_generics, _, _) = generics_with_lifetime.split_for_impl(); 55 | 56 | // Build TypeGenerics and WhereClause without a lifetime 57 | let (_, ty_generics, where_clause) = generics.split_for_impl(); 58 | 59 | Ok(quote! { 60 | const _: () = { 61 | ::std::thread_local! { 62 | #[allow(non_upper_case_globals)] 63 | static #recursive_count: ::core::cell::Cell = ::core::cell::Cell::new(0); 64 | } 65 | 66 | #[automatically_derived] 67 | impl #impl_generics arbitrary::Arbitrary<#lifetime_without_bounds> for #name #ty_generics #where_clause { 68 | #arbitrary_method 69 | #size_hint_method 70 | } 71 | }; 72 | }) 73 | } 74 | 75 | // Returns: (lifetime without bounds, lifetime with bounds) 76 | // Example: ("'arbitrary", "'arbitrary: 'a + 'b") 77 | fn build_arbitrary_lifetime(generics: Generics) -> (LifetimeParam, LifetimeParam) { 78 | let lifetime_without_bounds = 79 | LifetimeParam::new(Lifetime::new(ARBITRARY_LIFETIME_NAME, Span::call_site())); 80 | let mut lifetime_with_bounds = lifetime_without_bounds.clone(); 81 | 82 | for param in generics.params.iter() { 83 | if let GenericParam::Lifetime(lifetime_def) = param { 84 | lifetime_with_bounds 85 | .bounds 86 | .push(lifetime_def.lifetime.clone()); 87 | } 88 | } 89 | 90 | (lifetime_without_bounds, lifetime_with_bounds) 91 | } 92 | 93 | fn apply_trait_bounds( 94 | mut generics: Generics, 95 | lifetime: LifetimeParam, 96 | container_attrs: &ContainerAttributes, 97 | ) -> Result { 98 | // If user-supplied bounds exist, apply them to their matching type parameters. 99 | if let Some(config_bounds) = &container_attrs.bounds { 100 | let mut config_bounds_applied = 0; 101 | for param in generics.params.iter_mut() { 102 | if let GenericParam::Type(type_param) = param { 103 | if let Some(replacement) = config_bounds 104 | .iter() 105 | .flatten() 106 | .find(|p| p.ident == type_param.ident) 107 | { 108 | *type_param = replacement.clone(); 109 | config_bounds_applied += 1; 110 | } else { 111 | // If no user-supplied bounds exist for this type, delete the original bounds. 112 | // This mimics serde. 113 | type_param.bounds = Default::default(); 114 | type_param.default = None; 115 | } 116 | } 117 | } 118 | let config_bounds_supplied = config_bounds 119 | .iter() 120 | .map(|bounds| bounds.len()) 121 | .sum::(); 122 | if config_bounds_applied != config_bounds_supplied { 123 | return Err(Error::new( 124 | Span::call_site(), 125 | format!( 126 | "invalid `{}` attribute. too many bounds, only {} out of {} are applicable", 127 | ARBITRARY_ATTRIBUTE_NAME, config_bounds_applied, config_bounds_supplied, 128 | ), 129 | )); 130 | } 131 | Ok(generics) 132 | } else { 133 | // Otherwise, inject a `T: Arbitrary` bound for every parameter. 134 | Ok(add_trait_bounds(generics, lifetime)) 135 | } 136 | } 137 | 138 | // Add a bound `T: Arbitrary` to every type parameter T. 139 | fn add_trait_bounds(mut generics: Generics, lifetime: LifetimeParam) -> Generics { 140 | for param in generics.params.iter_mut() { 141 | if let GenericParam::Type(type_param) = param { 142 | type_param 143 | .bounds 144 | .push(parse_quote!(arbitrary::Arbitrary<#lifetime>)); 145 | } 146 | } 147 | generics 148 | } 149 | 150 | fn with_recursive_count_guard( 151 | recursive_count: &syn::Ident, 152 | expr: impl quote::ToTokens, 153 | ) -> impl quote::ToTokens { 154 | quote! { 155 | let guard_against_recursion = u.is_empty(); 156 | if guard_against_recursion { 157 | #recursive_count.with(|count| { 158 | if count.get() > 0 { 159 | return Err(arbitrary::Error::NotEnoughData); 160 | } 161 | count.set(count.get() + 1); 162 | Ok(()) 163 | })?; 164 | } 165 | 166 | let result = (|| { #expr })(); 167 | 168 | if guard_against_recursion { 169 | #recursive_count.with(|count| { 170 | count.set(count.get() - 1); 171 | }); 172 | } 173 | 174 | result 175 | } 176 | } 177 | 178 | fn gen_arbitrary_method( 179 | input: &DeriveInput, 180 | lifetime: LifetimeParam, 181 | recursive_count: &syn::Ident, 182 | ) -> Result { 183 | fn arbitrary_structlike( 184 | fields: &Fields, 185 | ident: &syn::Ident, 186 | lifetime: LifetimeParam, 187 | recursive_count: &syn::Ident, 188 | ) -> Result { 189 | let arbitrary = construct(fields, |_idx, field| gen_constructor_for_field(field))?; 190 | let body = with_recursive_count_guard(recursive_count, quote! { Ok(#ident #arbitrary) }); 191 | 192 | let arbitrary_take_rest = construct_take_rest(fields)?; 193 | let take_rest_body = 194 | with_recursive_count_guard(recursive_count, quote! { Ok(#ident #arbitrary_take_rest) }); 195 | 196 | Ok(quote! { 197 | fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { 198 | #body 199 | } 200 | 201 | fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { 202 | #take_rest_body 203 | } 204 | }) 205 | } 206 | 207 | fn arbitrary_variant( 208 | index: u64, 209 | enum_name: &Ident, 210 | variant_name: &Ident, 211 | ctor: TokenStream, 212 | ) -> TokenStream { 213 | quote! { #index => #enum_name::#variant_name #ctor } 214 | } 215 | 216 | fn arbitrary_enum_method( 217 | recursive_count: &syn::Ident, 218 | unstructured: TokenStream, 219 | variants: &[TokenStream], 220 | ) -> impl quote::ToTokens { 221 | let count = variants.len() as u64; 222 | with_recursive_count_guard( 223 | recursive_count, 224 | quote! { 225 | // Use a multiply + shift to generate a ranged random number 226 | // with slight bias. For details, see: 227 | // https://lemire.me/blog/2016/06/30/fast-random-shuffling 228 | Ok(match (u64::from(::arbitrary(#unstructured)?) * #count) >> 32 { 229 | #(#variants,)* 230 | _ => unreachable!() 231 | }) 232 | }, 233 | ) 234 | } 235 | 236 | fn arbitrary_enum( 237 | DataEnum { variants, .. }: &DataEnum, 238 | enum_name: &Ident, 239 | lifetime: LifetimeParam, 240 | recursive_count: &syn::Ident, 241 | ) -> Result { 242 | let filtered_variants = variants.iter().filter(not_skipped); 243 | 244 | // Check attributes of all variants: 245 | filtered_variants 246 | .clone() 247 | .try_for_each(check_variant_attrs)?; 248 | 249 | // From here on, we can assume that the attributes of all variants were checked. 250 | let enumerated_variants = filtered_variants 251 | .enumerate() 252 | .map(|(index, variant)| (index as u64, variant)); 253 | 254 | // Construct `match`-arms for the `arbitrary` method. 255 | let variants = enumerated_variants 256 | .clone() 257 | .map(|(index, Variant { fields, ident, .. })| { 258 | construct(fields, |_, field| gen_constructor_for_field(field)) 259 | .map(|ctor| arbitrary_variant(index, enum_name, ident, ctor)) 260 | }) 261 | .collect::>>()?; 262 | 263 | // Construct `match`-arms for the `arbitrary_take_rest` method. 264 | let variants_take_rest = enumerated_variants 265 | .map(|(index, Variant { fields, ident, .. })| { 266 | construct_take_rest(fields) 267 | .map(|ctor| arbitrary_variant(index, enum_name, ident, ctor)) 268 | }) 269 | .collect::>>()?; 270 | 271 | // Most of the time, `variants` is not empty (the happy path), 272 | // thus `variants_take_rest` will be used, 273 | // so no need to move this check before constructing `variants_take_rest`. 274 | // If `variants` is empty, this will emit a compiler-error. 275 | (!variants.is_empty()) 276 | .then(|| { 277 | // TODO: Improve dealing with `u` vs. `&mut u`. 278 | let arbitrary = arbitrary_enum_method(recursive_count, quote! { u }, &variants); 279 | let arbitrary_take_rest = arbitrary_enum_method(recursive_count, quote! { &mut u }, &variants_take_rest); 280 | 281 | quote! { 282 | fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { 283 | #arbitrary 284 | } 285 | 286 | fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { 287 | #arbitrary_take_rest 288 | } 289 | } 290 | }) 291 | .ok_or_else(|| Error::new_spanned( 292 | enum_name, 293 | "Enum must have at least one variant, that is not skipped" 294 | )) 295 | } 296 | 297 | let ident = &input.ident; 298 | match &input.data { 299 | Data::Struct(data) => arbitrary_structlike(&data.fields, ident, lifetime, recursive_count), 300 | Data::Union(data) => arbitrary_structlike( 301 | &Fields::Named(data.fields.clone()), 302 | ident, 303 | lifetime, 304 | recursive_count, 305 | ), 306 | Data::Enum(data) => arbitrary_enum(data, ident, lifetime, recursive_count), 307 | } 308 | } 309 | 310 | fn construct( 311 | fields: &Fields, 312 | ctor: impl Fn(usize, &Field) -> Result, 313 | ) -> Result { 314 | let output = match fields { 315 | Fields::Named(names) => { 316 | let names: Vec = names 317 | .named 318 | .iter() 319 | .enumerate() 320 | .map(|(i, f)| { 321 | let name = f.ident.as_ref().unwrap(); 322 | ctor(i, f).map(|ctor| quote! { #name: #ctor }) 323 | }) 324 | .collect::>()?; 325 | quote! { { #(#names,)* } } 326 | } 327 | Fields::Unnamed(names) => { 328 | let names: Vec = names 329 | .unnamed 330 | .iter() 331 | .enumerate() 332 | .map(|(i, f)| ctor(i, f).map(|ctor| quote! { #ctor })) 333 | .collect::>()?; 334 | quote! { ( #(#names),* ) } 335 | } 336 | Fields::Unit => quote!(), 337 | }; 338 | Ok(output) 339 | } 340 | 341 | fn construct_take_rest(fields: &Fields) -> Result { 342 | construct(fields, |idx, field| { 343 | determine_field_constructor(field).map(|field_constructor| match field_constructor { 344 | FieldConstructor::Default => quote!(::core::default::Default::default()), 345 | FieldConstructor::Arbitrary => { 346 | if idx + 1 == fields.len() { 347 | quote! { arbitrary::Arbitrary::arbitrary_take_rest(u)? } 348 | } else { 349 | quote! { arbitrary::Arbitrary::arbitrary(&mut u)? } 350 | } 351 | } 352 | FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(&mut u)?), 353 | FieldConstructor::Value(value) => quote!(#value), 354 | }) 355 | }) 356 | } 357 | 358 | fn gen_size_hint_method(input: &DeriveInput) -> Result { 359 | let size_hint_fields = |fields: &Fields| { 360 | fields 361 | .iter() 362 | .map(|f| { 363 | let ty = &f.ty; 364 | determine_field_constructor(f).map(|field_constructor| { 365 | match field_constructor { 366 | FieldConstructor::Default | FieldConstructor::Value(_) => { 367 | quote!(Ok((0, Some(0)))) 368 | } 369 | FieldConstructor::Arbitrary => { 370 | quote! { <#ty as arbitrary::Arbitrary>::try_size_hint(depth) } 371 | } 372 | 373 | // Note that in this case it's hard to determine what size_hint must be, so size_of::() is 374 | // just an educated guess, although it's gonna be inaccurate for dynamically 375 | // allocated types (Vec, HashMap, etc.). 376 | FieldConstructor::With(_) => { 377 | quote! { Ok((::core::mem::size_of::<#ty>(), None)) } 378 | } 379 | } 380 | }) 381 | }) 382 | .collect::>>() 383 | .map(|hints| { 384 | quote! { 385 | Ok(arbitrary::size_hint::and_all(&[ 386 | #( #hints? ),* 387 | ])) 388 | } 389 | }) 390 | }; 391 | let size_hint_structlike = |fields: &Fields| { 392 | size_hint_fields(fields).map(|hint| { 393 | quote! { 394 | #[inline] 395 | fn size_hint(depth: usize) -> (usize, ::core::option::Option) { 396 | Self::try_size_hint(depth).unwrap_or_default() 397 | } 398 | 399 | #[inline] 400 | fn try_size_hint(depth: usize) -> ::core::result::Result<(usize, ::core::option::Option), arbitrary::MaxRecursionReached> { 401 | arbitrary::size_hint::try_recursion_guard(depth, |depth| #hint) 402 | } 403 | } 404 | }) 405 | }; 406 | match &input.data { 407 | Data::Struct(data) => size_hint_structlike(&data.fields), 408 | Data::Union(data) => size_hint_structlike(&Fields::Named(data.fields.clone())), 409 | Data::Enum(data) => data 410 | .variants 411 | .iter() 412 | .filter(not_skipped) 413 | .map(|Variant { fields, .. }| { 414 | // The attributes of all variants are checked in `gen_arbitrary_method` above 415 | // and can therefore assume that they are valid. 416 | size_hint_fields(fields) 417 | }) 418 | .collect::>>() 419 | .map(|variants| { 420 | quote! { 421 | fn size_hint(depth: usize) -> (usize, ::core::option::Option) { 422 | Self::try_size_hint(depth).unwrap_or_default() 423 | } 424 | #[inline] 425 | fn try_size_hint(depth: usize) -> ::core::result::Result<(usize, ::core::option::Option), arbitrary::MaxRecursionReached> { 426 | Ok(arbitrary::size_hint::and( 427 | ::try_size_hint(depth)?, 428 | arbitrary::size_hint::try_recursion_guard(depth, |depth| { 429 | Ok(arbitrary::size_hint::or_all(&[ #( #variants? ),* ])) 430 | })?, 431 | )) 432 | } 433 | } 434 | }), 435 | } 436 | } 437 | 438 | fn gen_constructor_for_field(field: &Field) -> Result { 439 | let ctor = match determine_field_constructor(field)? { 440 | FieldConstructor::Default => quote!(::core::default::Default::default()), 441 | FieldConstructor::Arbitrary => quote!(arbitrary::Arbitrary::arbitrary(u)?), 442 | FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(u)?), 443 | FieldConstructor::Value(value) => quote!(#value), 444 | }; 445 | Ok(ctor) 446 | } 447 | 448 | fn check_variant_attrs(variant: &Variant) -> Result<()> { 449 | for attr in &variant.attrs { 450 | if attr.path().is_ident(ARBITRARY_ATTRIBUTE_NAME) { 451 | return Err(Error::new_spanned( 452 | attr, 453 | format!( 454 | "invalid `{}` attribute. it is unsupported on enum variants. try applying it to a field of the variant instead", 455 | ARBITRARY_ATTRIBUTE_NAME 456 | ), 457 | )); 458 | } 459 | } 460 | Ok(()) 461 | } 462 | -------------------------------------------------------------------------------- /derive/src/variant_attributes.rs: -------------------------------------------------------------------------------- 1 | use crate::ARBITRARY_ATTRIBUTE_NAME; 2 | use syn::*; 3 | 4 | pub fn not_skipped(variant: &&Variant) -> bool { 5 | !should_skip(variant) 6 | } 7 | 8 | fn should_skip(Variant { attrs, .. }: &Variant) -> bool { 9 | attrs 10 | .iter() 11 | .filter_map(|attr| { 12 | attr.path() 13 | .is_ident(ARBITRARY_ATTRIBUTE_NAME) 14 | .then(|| attr.parse_args::()) 15 | .and_then(Result::ok) 16 | }) 17 | .any(|meta| match meta { 18 | Meta::Path(path) => path.is_ident("skip"), 19 | _ => false, 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /examples/derive_enum.rs: -------------------------------------------------------------------------------- 1 | //! A simple example of deriving the `Arbitrary` trait for an `enum`. 2 | //! 3 | //! Note that this requires enabling the "derive" cargo feature. 4 | 5 | // Various enums/fields that we are deriving `Arbitrary` for aren't actually 6 | // used except to show off the derive. 7 | #![allow(dead_code)] 8 | 9 | use arbitrary::{Arbitrary, Unstructured}; 10 | 11 | #[derive(Arbitrary, Debug)] 12 | enum MyEnum { 13 | Unit, 14 | Tuple(bool, u32), 15 | Struct { 16 | x: i8, 17 | y: (u8, i32), 18 | }, 19 | 20 | #[arbitrary(skip)] 21 | Skipped(usize), 22 | } 23 | 24 | fn main() { 25 | let raw = b"This is some raw, unstructured data!"; 26 | 27 | let mut unstructured = Unstructured::new(raw); 28 | 29 | let instance = MyEnum::arbitrary(&mut unstructured) 30 | .expect("`unstructured` has enough underlying data to create all variants of `MyEnum`"); 31 | 32 | println!("Here is an arbitrary enum: {:?}", instance); 33 | } 34 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arbitrary-fuzz" 3 | version = "0.0.0" 4 | authors = ["Automatically generated"] 5 | publish = false 6 | edition = "2021" 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies] 12 | libfuzzer-sys = "0.4" 13 | 14 | [dependencies.arbitrary] 15 | path = ".." 16 | 17 | [[bin]] 18 | name = "int_in_range" 19 | path = "fuzz_targets/int_in_range.rs" 20 | test = false 21 | doc = false 22 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/int_in_range.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use arbitrary::{unstructured::Int, Arbitrary, Result, Unstructured}; 4 | use libfuzzer_sys::fuzz_target; 5 | use std::{fmt::Display, ops::RangeInclusive}; 6 | 7 | fuzz_target!(|data: &[u8]| { 8 | fuzz(data).expect("`int_in_range` should never return an error"); 9 | }); 10 | 11 | fn fuzz(data: &[u8]) -> Result<()> { 12 | let mut u = Unstructured::new(data); 13 | 14 | let choices = [ 15 | assert_in_range::, 16 | assert_in_range::, 17 | assert_in_range::, 18 | assert_in_range::, 19 | assert_in_range::, 20 | assert_in_range::, 21 | assert_in_range::, 22 | assert_in_range::, 23 | assert_in_range::, 24 | assert_in_range::, 25 | assert_in_range::, 26 | assert_in_range::, 27 | ]; 28 | 29 | let f = u.choose(&choices[..])?; 30 | f(&mut u) 31 | } 32 | 33 | fn assert_in_range<'a, 'b, T>(u: &'a mut Unstructured<'b>) -> Result<()> 34 | where 35 | T: Arbitrary<'b> + Int + Display, 36 | { 37 | let range = RangeInclusive::::arbitrary(u)?; 38 | let start = *range.start(); 39 | let end = *range.end(); 40 | 41 | let x = u.int_in_range(range)?; 42 | 43 | if start <= x && x <= end { 44 | return Ok(()); 45 | } 46 | 47 | let ty = std::any::type_name::(); 48 | panic!("{ty}: {x} is not within {start}..={end}",); 49 | } 50 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | cd $(dirname $0)/derive 6 | 7 | cargo publish 8 | 9 | cd .. 10 | 11 | # Let the crates.io index figure out we've published `derive_arbitrary` already. 12 | sleep 5 13 | 14 | cargo publish 15 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{error, fmt}; 2 | 3 | /// An enumeration of buffer creation errors 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 5 | #[non_exhaustive] 6 | pub enum Error { 7 | /// No choices were provided to the Unstructured::choose call 8 | EmptyChoose, 9 | /// There was not enough underlying data to fulfill some request for raw 10 | /// bytes. 11 | /// 12 | /// Note that outside of [`Unstructured::bytes`][crate::Unstructured::bytes], 13 | /// most APIs do *not* return this error when running out of underlying arbitrary bytes 14 | /// but silently return some default value instead. 15 | NotEnoughData, 16 | /// The input bytes were not of the right format 17 | IncorrectFormat, 18 | } 19 | 20 | impl fmt::Display for Error { 21 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 22 | match self { 23 | Error::EmptyChoose => write!( 24 | f, 25 | "`arbitrary::Unstructured::choose` must be given a non-empty set of choices" 26 | ), 27 | Error::NotEnoughData => write!( 28 | f, 29 | "There is not enough underlying raw data to construct an `Arbitrary` instance" 30 | ), 31 | Error::IncorrectFormat => write!( 32 | f, 33 | "The raw data is not of the correct format to construct this type" 34 | ), 35 | } 36 | } 37 | } 38 | 39 | impl error::Error for Error {} 40 | 41 | /// A `Result` with the error type fixed as `arbitrary::Error`. 42 | /// 43 | /// Either an `Ok(T)` or `Err(arbitrary::Error)`. 44 | pub type Result = std::result::Result; 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | // Often people will import our custom `Result` type because 99.9% of 49 | // results in a file will be `arbitrary::Result` but then have that one last 50 | // 0.1% that want to have a custom error type. Don't make them prefix that 51 | // 0.1% as `std::result::Result`; instead, let `arbitrary::Result` have an 52 | // overridable error type. 53 | #[test] 54 | fn can_use_custom_error_types_with_result() -> super::Result<(), String> { 55 | Ok(()) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/foreign/alloc/borrow.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::borrow::{Cow, ToOwned}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Cow<'a, A> 7 | where 8 | A: ToOwned + ?Sized + 'a, 9 |
::Owned: Arbitrary<'a>, 10 | { 11 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 12 | Arbitrary::arbitrary(u).map(Cow::Owned) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | Self::try_size_hint(depth).unwrap_or_default() 18 | } 19 | 20 | #[inline] 21 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 22 | size_hint::try_recursion_guard(depth, |depth| { 23 | <::Owned as Arbitrary>::try_size_hint(depth) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/foreign/alloc/boxed.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::boxed::Box, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Box 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for Box<[A]> 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | u.arbitrary_iter()?.collect() 31 | } 32 | 33 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 34 | u.arbitrary_take_rest_iter()?.collect() 35 | } 36 | 37 | #[inline] 38 | fn size_hint(_depth: usize) -> (usize, Option) { 39 | (0, None) 40 | } 41 | } 42 | 43 | impl<'a> Arbitrary<'a> for Box { 44 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 45 | ::arbitrary(u).map(|x| x.into_boxed_str()) 46 | } 47 | 48 | #[inline] 49 | fn size_hint(depth: usize) -> (usize, Option) { 50 | ::size_hint(depth) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/binary_heap.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::binary_heap::BinaryHeap, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for BinaryHeap 7 | where 8 | A: Arbitrary<'a> + Ord, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/btree_map.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::btree_map::BTreeMap, 4 | }; 5 | 6 | impl<'a, K, V> Arbitrary<'a> for BTreeMap 7 | where 8 | K: Arbitrary<'a> + Ord, 9 | V: Arbitrary<'a>, 10 | { 11 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 12 | u.arbitrary_iter()?.collect() 13 | } 14 | 15 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 16 | u.arbitrary_take_rest_iter()?.collect() 17 | } 18 | 19 | #[inline] 20 | fn size_hint(_depth: usize) -> (usize, Option) { 21 | (0, None) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/btree_set.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::btree_set::BTreeSet, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for BTreeSet 7 | where 8 | A: Arbitrary<'a> + Ord, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/linked_list.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::linked_list::LinkedList, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for LinkedList 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/mod.rs: -------------------------------------------------------------------------------- 1 | mod binary_heap; 2 | mod btree_map; 3 | mod btree_set; 4 | mod linked_list; 5 | mod vec_deque; 6 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/vec_deque.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::vec_deque::VecDeque, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for VecDeque 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/ffi/c_str.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::ffi::CString, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for CString { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | as Arbitrary>::arbitrary(u).map(|mut x| { 9 | x.retain(|&c| c != 0); 10 | // SAFETY: all zero bytes have been removed 11 | unsafe { Self::from_vec_unchecked(x) } 12 | }) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | as Arbitrary>::size_hint(depth) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/foreign/alloc/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | mod c_str; 2 | -------------------------------------------------------------------------------- /src/foreign/alloc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for [`alloc`] types, 2 | //! excluding those in [`core`]. 3 | //! 4 | //! [`Arbitrary`]: crate::Arbitrary 5 | 6 | mod borrow; 7 | mod boxed; 8 | mod collections; 9 | mod ffi; 10 | mod rc; 11 | mod string; 12 | mod sync; 13 | mod vec; 14 | -------------------------------------------------------------------------------- /src/foreign/alloc/rc.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::rc::Rc, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Rc 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for Rc<[A]> 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | u.arbitrary_iter()?.collect() 31 | } 32 | 33 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 34 | u.arbitrary_take_rest_iter()?.collect() 35 | } 36 | 37 | #[inline] 38 | fn size_hint(_depth: usize) -> (usize, Option) { 39 | (0, None) 40 | } 41 | } 42 | 43 | impl<'a> Arbitrary<'a> for Rc { 44 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 45 | <&str as Arbitrary>::arbitrary(u).map(Into::into) 46 | } 47 | 48 | #[inline] 49 | fn size_hint(depth: usize) -> (usize, Option) { 50 | <&str as Arbitrary>::size_hint(depth) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/foreign/alloc/string.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::string::String, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for String { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | <&str as Arbitrary>::arbitrary(u).map(Into::into) 9 | } 10 | 11 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 12 | <&str as Arbitrary>::arbitrary_take_rest(u).map(Into::into) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | <&str as Arbitrary>::size_hint(depth) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/foreign/alloc/sync.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::sync::Arc, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Arc 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for Arc<[A]> 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | u.arbitrary_iter()?.collect() 31 | } 32 | 33 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 34 | u.arbitrary_take_rest_iter()?.collect() 35 | } 36 | 37 | #[inline] 38 | fn size_hint(_depth: usize) -> (usize, Option) { 39 | (0, None) 40 | } 41 | } 42 | 43 | impl<'a> Arbitrary<'a> for Arc { 44 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 45 | <&str as Arbitrary>::arbitrary(u).map(Into::into) 46 | } 47 | 48 | #[inline] 49 | fn size_hint(depth: usize) -> (usize, Option) { 50 | <&str as Arbitrary>::size_hint(depth) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/foreign/alloc/vec.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::vec::Vec, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Vec 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/core/array.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | core::{ 4 | array, 5 | mem::{self, MaybeUninit}, 6 | ptr, 7 | }, 8 | }; 9 | 10 | /// Helper to safely create arrays since the standard library doesn't 11 | /// provide one yet. Shouldn't be necessary in the future. 12 | struct ArrayGuard { 13 | dst: *mut T, 14 | initialized: usize, 15 | } 16 | 17 | impl Drop for ArrayGuard { 18 | fn drop(&mut self) { 19 | debug_assert!(self.initialized <= N); 20 | let initialized_part = ptr::slice_from_raw_parts_mut(self.dst, self.initialized); 21 | unsafe { 22 | ptr::drop_in_place(initialized_part); 23 | } 24 | } 25 | } 26 | 27 | fn try_create_array(mut cb: F) -> Result<[T; N]> 28 | where 29 | F: FnMut(usize) -> Result, 30 | { 31 | let mut array: MaybeUninit<[T; N]> = MaybeUninit::uninit(); 32 | let array_ptr = array.as_mut_ptr(); 33 | let dst = array_ptr as _; 34 | let mut guard: ArrayGuard = ArrayGuard { 35 | dst, 36 | initialized: 0, 37 | }; 38 | unsafe { 39 | for (idx, value_ptr) in (*array.as_mut_ptr()).iter_mut().enumerate() { 40 | ptr::write(value_ptr, cb(idx)?); 41 | guard.initialized += 1; 42 | } 43 | mem::forget(guard); 44 | Ok(array.assume_init()) 45 | } 46 | } 47 | 48 | impl<'a, T, const N: usize> Arbitrary<'a> for [T; N] 49 | where 50 | T: Arbitrary<'a>, 51 | { 52 | #[inline] 53 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 54 | try_create_array(|_| >::arbitrary(u)) 55 | } 56 | 57 | #[inline] 58 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 59 | let mut array = Self::arbitrary(&mut u)?; 60 | if let Some(last) = array.last_mut() { 61 | *last = Arbitrary::arbitrary_take_rest(u)?; 62 | } 63 | Ok(array) 64 | } 65 | 66 | #[inline] 67 | fn size_hint(depth: usize) -> (usize, Option) { 68 | Self::try_size_hint(depth).unwrap_or_default() 69 | } 70 | 71 | #[inline] 72 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 73 | let hint = ::try_size_hint(depth)?; 74 | Ok(size_hint::and_all(&array::from_fn::<_, N, _>(|_| hint))) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/foreign/core/bool.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | /// Returns false, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 4 | impl<'a> Arbitrary<'a> for bool { 5 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 6 | Ok(>::arbitrary(u)? & 1 == 1) 7 | } 8 | 9 | #[inline] 10 | fn size_hint(depth: usize) -> (usize, Option) { 11 | >::size_hint(depth) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/foreign/core/cell.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, MaxRecursionReached, Result, Unstructured}, 3 | core::cell::{Cell, RefCell, UnsafeCell}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Cell 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 21 | >::try_size_hint(depth) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for RefCell 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | Arbitrary::arbitrary(u).map(Self::new) 31 | } 32 | 33 | #[inline] 34 | fn size_hint(depth: usize) -> (usize, Option) { 35 | Self::try_size_hint(depth).unwrap_or_default() 36 | } 37 | 38 | #[inline] 39 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 40 | >::try_size_hint(depth) 41 | } 42 | } 43 | 44 | impl<'a, A> Arbitrary<'a> for UnsafeCell 45 | where 46 | A: Arbitrary<'a>, 47 | { 48 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 49 | Arbitrary::arbitrary(u).map(Self::new) 50 | } 51 | 52 | #[inline] 53 | fn size_hint(depth: usize) -> (usize, Option) { 54 | Self::try_size_hint(depth).unwrap_or_default() 55 | } 56 | 57 | #[inline] 58 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 59 | >::try_size_hint(depth) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/foreign/core/char.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | /// Returns '\0', not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 4 | impl<'a> Arbitrary<'a> for char { 5 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 6 | // The highest unicode code point is 0x11_FFFF 7 | const CHAR_END: u32 = 0x11_0000; 8 | // The size of the surrogate blocks 9 | const SURROGATES_START: u32 = 0xD800; 10 | let mut c = >::arbitrary(u)? % CHAR_END; 11 | if let Some(c) = char::from_u32(c) { 12 | Ok(c) 13 | } else { 14 | // We found a surrogate, wrap and try again 15 | c -= SURROGATES_START; 16 | Ok(char::from_u32(c) 17 | .expect("Generated character should be valid! This is a bug in arbitrary-rs")) 18 | } 19 | } 20 | 21 | #[inline] 22 | fn size_hint(depth: usize) -> (usize, Option) { 23 | >::size_hint(depth) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/foreign/core/cmp.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | core::cmp::Reverse, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Reverse 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/foreign/core/iter.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::iter::{empty, Empty}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Empty 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 11 | Ok(empty()) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(_depth: usize) -> (usize, Option) { 16 | (0, Some(0)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/foreign/core/marker.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::marker::{PhantomData, PhantomPinned}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for PhantomData 7 | where 8 | A: ?Sized, 9 | { 10 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 11 | Ok(PhantomData) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(_depth: usize) -> (usize, Option) { 16 | (0, Some(0)) 17 | } 18 | } 19 | 20 | impl<'a> Arbitrary<'a> for PhantomPinned { 21 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 22 | Ok(PhantomPinned) 23 | } 24 | 25 | #[inline] 26 | fn size_hint(_depth: usize) -> (usize, Option) { 27 | (0, Some(0)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/foreign/core/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for [`core`] types. 2 | //! 3 | //! [`Arbitrary`]: crate::Arbitrary 4 | 5 | mod array; 6 | mod bool; 7 | mod cell; 8 | mod char; 9 | mod cmp; 10 | mod iter; 11 | mod marker; 12 | mod num; 13 | mod ops; 14 | mod option; 15 | mod result; 16 | mod slice; 17 | mod str; 18 | mod sync; 19 | mod time; 20 | mod tuple; 21 | mod unit; 22 | -------------------------------------------------------------------------------- /src/foreign/core/num.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Error, MaxRecursionReached, Result, Unstructured}, 3 | core::{ 4 | mem, 5 | num::{ 6 | NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, 7 | NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, 8 | }, 9 | }, 10 | }; 11 | 12 | macro_rules! impl_arbitrary_for_integers { 13 | ( $( $ty:ty; )* ) => { 14 | $( 15 | impl<'a> Arbitrary<'a> for $ty { 16 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 17 | let mut buf = [0; mem::size_of::<$ty>()]; 18 | u.fill_buffer(&mut buf)?; 19 | Ok(Self::from_le_bytes(buf)) 20 | } 21 | 22 | #[inline] 23 | fn size_hint(_depth: usize) -> (usize, Option) { 24 | let n = mem::size_of::<$ty>(); 25 | (n, Some(n)) 26 | } 27 | 28 | } 29 | )* 30 | } 31 | } 32 | 33 | impl_arbitrary_for_integers! { 34 | u8; 35 | u16; 36 | u32; 37 | u64; 38 | u128; 39 | i8; 40 | i16; 41 | i32; 42 | i64; 43 | i128; 44 | } 45 | 46 | // Note: We forward Arbitrary for i/usize to i/u64 in order to simplify corpus 47 | // compatibility between 32-bit and 64-bit builds. This introduces dead space in 48 | // 32-bit builds but keeps the input layout independent of the build platform. 49 | impl<'a> Arbitrary<'a> for usize { 50 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 51 | u.arbitrary::().map(|x| x as usize) 52 | } 53 | 54 | #[inline] 55 | fn size_hint(depth: usize) -> (usize, Option) { 56 | ::size_hint(depth) 57 | } 58 | } 59 | 60 | impl<'a> Arbitrary<'a> for isize { 61 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 62 | u.arbitrary::().map(|x| x as isize) 63 | } 64 | 65 | #[inline] 66 | fn size_hint(depth: usize) -> (usize, Option) { 67 | ::size_hint(depth) 68 | } 69 | } 70 | 71 | macro_rules! impl_arbitrary_for_floats { 72 | ( $( $ty:ident : $unsigned:ty; )* ) => { 73 | $( 74 | impl<'a> Arbitrary<'a> for $ty { 75 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 76 | Ok(Self::from_bits(<$unsigned as Arbitrary<'a>>::arbitrary(u)?)) 77 | } 78 | 79 | #[inline] 80 | fn size_hint(depth: usize) -> (usize, Option) { 81 | <$unsigned as Arbitrary<'a>>::size_hint(depth) 82 | } 83 | } 84 | )* 85 | } 86 | } 87 | 88 | impl_arbitrary_for_floats! { 89 | f32: u32; 90 | f64: u64; 91 | } 92 | 93 | macro_rules! implement_nonzero_int { 94 | ($nonzero:ty, $int:ty) => { 95 | impl<'a> Arbitrary<'a> for $nonzero { 96 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 97 | match Self::new(<$int as Arbitrary<'a>>::arbitrary(u)?) { 98 | Some(n) => Ok(n), 99 | None => Err(Error::IncorrectFormat), 100 | } 101 | } 102 | 103 | #[inline] 104 | fn size_hint(depth: usize) -> (usize, Option) { 105 | <$int as Arbitrary<'a>>::size_hint(depth) 106 | } 107 | } 108 | }; 109 | } 110 | 111 | implement_nonzero_int! { NonZeroI8, i8 } 112 | implement_nonzero_int! { NonZeroI16, i16 } 113 | implement_nonzero_int! { NonZeroI32, i32 } 114 | implement_nonzero_int! { NonZeroI64, i64 } 115 | implement_nonzero_int! { NonZeroI128, i128 } 116 | implement_nonzero_int! { NonZeroIsize, isize } 117 | implement_nonzero_int! { NonZeroU8, u8 } 118 | implement_nonzero_int! { NonZeroU16, u16 } 119 | implement_nonzero_int! { NonZeroU32, u32 } 120 | implement_nonzero_int! { NonZeroU64, u64 } 121 | implement_nonzero_int! { NonZeroU128, u128 } 122 | implement_nonzero_int! { NonZeroUsize, usize } 123 | 124 | impl<'a, A> Arbitrary<'a> for Wrapping 125 | where 126 | A: Arbitrary<'a>, 127 | { 128 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 129 | Arbitrary::arbitrary(u).map(Wrapping) 130 | } 131 | 132 | #[inline] 133 | fn size_hint(depth: usize) -> (usize, Option) { 134 | Self::try_size_hint(depth).unwrap_or_default() 135 | } 136 | 137 | #[inline] 138 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 139 | >::try_size_hint(depth) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/foreign/core/ops.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}, 3 | core::{ 4 | mem, 5 | ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}, 6 | }, 7 | }; 8 | 9 | macro_rules! impl_range { 10 | ( 11 | $range:ty, 12 | $value_closure:expr, 13 | $value_ty:ty, 14 | $fun:ident($fun_closure:expr), 15 | $size_hint_closure:expr 16 | ) => { 17 | impl<'a, A> Arbitrary<'a> for $range 18 | where 19 | A: Arbitrary<'a> + Clone + PartialOrd, 20 | { 21 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 22 | let value: $value_ty = Arbitrary::arbitrary(u)?; 23 | Ok($fun(value, $fun_closure)) 24 | } 25 | 26 | #[inline] 27 | fn size_hint(depth: usize) -> (usize, Option) { 28 | Self::try_size_hint(depth).unwrap_or_default() 29 | } 30 | 31 | #[inline] 32 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 33 | #[allow(clippy::redundant_closure_call)] 34 | $size_hint_closure(depth) 35 | } 36 | } 37 | }; 38 | } 39 | impl_range!( 40 | Range, 41 | |r: &Range| (r.start.clone(), r.end.clone()), 42 | (A, A), 43 | bounded_range(|(a, b)| a..b), 44 | |depth| Ok(crate::size_hint::and( 45 | ::try_size_hint(depth)?, 46 | ::try_size_hint(depth)?, 47 | )) 48 | ); 49 | impl_range!( 50 | RangeFrom, 51 | |r: &RangeFrom| r.start.clone(), 52 | A, 53 | unbounded_range(|a| a..), 54 | |depth| ::try_size_hint(depth) 55 | ); 56 | impl_range!( 57 | RangeInclusive, 58 | |r: &RangeInclusive| (r.start().clone(), r.end().clone()), 59 | (A, A), 60 | bounded_range(|(a, b)| a..=b), 61 | |depth| Ok(crate::size_hint::and( 62 | ::try_size_hint(depth)?, 63 | ::try_size_hint(depth)?, 64 | )) 65 | ); 66 | impl_range!( 67 | RangeTo, 68 | |r: &RangeTo| r.end.clone(), 69 | A, 70 | unbounded_range(|b| ..b), 71 | |depth| ::try_size_hint(depth) 72 | ); 73 | impl_range!( 74 | RangeToInclusive, 75 | |r: &RangeToInclusive| r.end.clone(), 76 | A, 77 | unbounded_range(|b| ..=b), 78 | |depth| ::try_size_hint(depth) 79 | ); 80 | 81 | pub(crate) fn bounded_range(bounds: (I, I), cb: CB) -> R 82 | where 83 | CB: Fn((I, I)) -> R, 84 | I: PartialOrd, 85 | R: RangeBounds, 86 | { 87 | let (mut start, mut end) = bounds; 88 | if start > end { 89 | mem::swap(&mut start, &mut end); 90 | } 91 | cb((start, end)) 92 | } 93 | 94 | pub(crate) fn unbounded_range(bound: I, cb: CB) -> R 95 | where 96 | CB: Fn(I) -> R, 97 | R: RangeBounds, 98 | { 99 | cb(bound) 100 | } 101 | 102 | impl<'a, A> Arbitrary<'a> for Bound 103 | where 104 | A: Arbitrary<'a>, 105 | { 106 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 107 | match u.int_in_range::(0..=2)? { 108 | 0 => Ok(Bound::Included(A::arbitrary(u)?)), 109 | 1 => Ok(Bound::Excluded(A::arbitrary(u)?)), 110 | 2 => Ok(Bound::Unbounded), 111 | _ => unreachable!(), 112 | } 113 | } 114 | 115 | #[inline] 116 | fn size_hint(depth: usize) -> (usize, Option) { 117 | Self::try_size_hint(depth).unwrap_or_default() 118 | } 119 | 120 | #[inline] 121 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 122 | Ok(size_hint::or( 123 | size_hint::and((1, Some(1)), A::try_size_hint(depth)?), 124 | (1, Some(1)), 125 | )) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/foreign/core/option.rs: -------------------------------------------------------------------------------- 1 | use crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; 2 | 3 | /// Returns `None`, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 4 | impl<'a, A> Arbitrary<'a> for Option 5 | where 6 | A: Arbitrary<'a>, 7 | { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Ok(if >::arbitrary(u)? { 10 | Some(Arbitrary::arbitrary(u)?) 11 | } else { 12 | None 13 | }) 14 | } 15 | 16 | #[inline] 17 | fn size_hint(depth: usize) -> (usize, Option) { 18 | Self::try_size_hint(depth).unwrap_or_default() 19 | } 20 | 21 | #[inline] 22 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 23 | Ok(size_hint::and( 24 | ::try_size_hint(depth)?, 25 | size_hint::or((0, Some(0)), ::try_size_hint(depth)?), 26 | )) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/foreign/core/result.rs: -------------------------------------------------------------------------------- 1 | use crate::{size_hint, Arbitrary, Error, MaxRecursionReached, Unstructured}; 2 | 3 | impl<'a, T, E> Arbitrary<'a> for Result 4 | where 5 | T: Arbitrary<'a>, 6 | E: Arbitrary<'a>, 7 | { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Ok(if >::arbitrary(u)? { 10 | Ok(::arbitrary(u)?) 11 | } else { 12 | Err(::arbitrary(u)?) 13 | }) 14 | } 15 | 16 | #[inline] 17 | fn size_hint(depth: usize) -> (usize, Option) { 18 | Self::try_size_hint(depth).unwrap_or_default() 19 | } 20 | 21 | #[inline] 22 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 23 | Ok(size_hint::and( 24 | ::size_hint(depth), 25 | size_hint::or( 26 | ::try_size_hint(depth)?, 27 | ::try_size_hint(depth)?, 28 | ), 29 | )) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/foreign/core/slice.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | impl<'a> Arbitrary<'a> for &'a [u8] { 4 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 5 | let len = u.arbitrary_len::()?; 6 | u.bytes(len) 7 | } 8 | 9 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 10 | Ok(u.take_rest()) 11 | } 12 | 13 | #[inline] 14 | fn size_hint(_depth: usize) -> (usize, Option) { 15 | (0, None) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/foreign/core/str.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::str, 4 | }; 5 | 6 | fn arbitrary_str<'a>(u: &mut Unstructured<'a>, size: usize) -> Result<&'a str> { 7 | match str::from_utf8(u.peek_bytes(size).unwrap()) { 8 | Ok(s) => { 9 | u.bytes(size).unwrap(); 10 | Ok(s) 11 | } 12 | Err(e) => { 13 | let i = e.valid_up_to(); 14 | let valid = u.bytes(i).unwrap(); 15 | let s = unsafe { 16 | debug_assert!(str::from_utf8(valid).is_ok()); 17 | str::from_utf8_unchecked(valid) 18 | }; 19 | Ok(s) 20 | } 21 | } 22 | } 23 | 24 | impl<'a> Arbitrary<'a> for &'a str { 25 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 26 | let size = u.arbitrary_len::()?; 27 | arbitrary_str(u, size) 28 | } 29 | 30 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 31 | let size = u.len(); 32 | arbitrary_str(&mut u, size) 33 | } 34 | 35 | #[inline] 36 | fn size_hint(_depth: usize) -> (usize, Option) { 37 | (0, None) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/foreign/core/sync/atomic.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}, 4 | }; 5 | 6 | /// Returns false, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 7 | impl<'a> Arbitrary<'a> for AtomicBool { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Arbitrary::arbitrary(u).map(Self::new) 10 | } 11 | 12 | #[inline] 13 | fn size_hint(depth: usize) -> (usize, Option) { 14 | >::size_hint(depth) 15 | } 16 | } 17 | 18 | /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 19 | impl<'a> Arbitrary<'a> for AtomicIsize { 20 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 21 | Arbitrary::arbitrary(u).map(Self::new) 22 | } 23 | 24 | #[inline] 25 | fn size_hint(depth: usize) -> (usize, Option) { 26 | >::size_hint(depth) 27 | } 28 | } 29 | 30 | /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 31 | impl<'a> Arbitrary<'a> for AtomicUsize { 32 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 33 | Arbitrary::arbitrary(u).map(Self::new) 34 | } 35 | 36 | #[inline] 37 | fn size_hint(depth: usize) -> (usize, Option) { 38 | >::size_hint(depth) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/foreign/core/sync/mod.rs: -------------------------------------------------------------------------------- 1 | mod atomic; 2 | -------------------------------------------------------------------------------- /src/foreign/core/time.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | core::time::Duration, 4 | }; 5 | 6 | /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 7 | impl<'a> Arbitrary<'a> for Duration { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Ok(Self::new( 10 | ::arbitrary(u)?, 11 | u.int_in_range(0..=999_999_999)?, 12 | )) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | size_hint::and( 18 | ::size_hint(depth), 19 | ::size_hint(depth), 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/core/tuple.rs: -------------------------------------------------------------------------------- 1 | use crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; 2 | 3 | macro_rules! arbitrary_tuple { 4 | () => {}; 5 | ($last: ident $($xs: ident)*) => { 6 | arbitrary_tuple!($($xs)*); 7 | 8 | impl<'a, $($xs,)* $last> Arbitrary<'a> for ($($xs,)* $last,) 9 | where 10 | $($xs: Arbitrary<'a>,)* 11 | $last: Arbitrary<'a>, 12 | { 13 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 14 | Ok(($($xs::arbitrary(u)?,)* Arbitrary::arbitrary(u)?,)) 15 | } 16 | 17 | #[allow(unused_mut, non_snake_case)] 18 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 19 | $(let $xs = $xs::arbitrary(&mut u)?;)* 20 | let $last = $last::arbitrary_take_rest(u)?; 21 | Ok(($($xs,)* $last,)) 22 | } 23 | 24 | #[inline] 25 | fn size_hint(depth: usize) -> (usize, Option) { 26 | Self::try_size_hint(depth).unwrap_or_default() 27 | } 28 | #[inline] 29 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 30 | Ok(size_hint::and_all(&[ 31 | <$last as Arbitrary>::try_size_hint(depth)?, 32 | $( <$xs as Arbitrary>::try_size_hint(depth)?),* 33 | ])) 34 | } 35 | } 36 | }; 37 | } 38 | arbitrary_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z); 39 | -------------------------------------------------------------------------------- /src/foreign/core/unit.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | impl<'a> Arbitrary<'a> for () { 4 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 5 | Ok(()) 6 | } 7 | 8 | #[inline] 9 | fn size_hint(_depth: usize) -> (usize, Option) { 10 | (0, Some(0)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/foreign/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for foreign types. 2 | //! 3 | //! [`Arbitrary`]: crate::Arbitrary 4 | 5 | mod alloc; 6 | mod core; 7 | mod std; 8 | -------------------------------------------------------------------------------- /src/foreign/std/collections/hash_map.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::{ 4 | collections::hash_map::HashMap, 5 | hash::{BuildHasher, Hash}, 6 | }, 7 | }; 8 | 9 | impl<'a, K, V, S> Arbitrary<'a> for HashMap 10 | where 11 | K: Arbitrary<'a> + Eq + Hash, 12 | V: Arbitrary<'a>, 13 | S: BuildHasher + Default, 14 | { 15 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 16 | u.arbitrary_iter()?.collect() 17 | } 18 | 19 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 20 | u.arbitrary_take_rest_iter()?.collect() 21 | } 22 | 23 | #[inline] 24 | fn size_hint(_depth: usize) -> (usize, Option) { 25 | (0, None) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/foreign/std/collections/hash_set.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::{ 4 | collections::hash_set::HashSet, 5 | hash::{BuildHasher, Hash}, 6 | }, 7 | }; 8 | 9 | impl<'a, A, S> Arbitrary<'a> for HashSet 10 | where 11 | A: Arbitrary<'a> + Eq + Hash, 12 | S: BuildHasher + Default, 13 | { 14 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 15 | u.arbitrary_iter()?.collect() 16 | } 17 | 18 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 19 | u.arbitrary_take_rest_iter()?.collect() 20 | } 21 | 22 | #[inline] 23 | fn size_hint(_depth: usize) -> (usize, Option) { 24 | (0, None) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/foreign/std/collections/mod.rs: -------------------------------------------------------------------------------- 1 | mod hash_map; 2 | mod hash_set; 3 | -------------------------------------------------------------------------------- /src/foreign/std/ffi/c_str.rs: -------------------------------------------------------------------------------- 1 | // impl Arbitrary for Box { 2 | // fn arbitrary(u: &mut Unstructured<'_>) -> Result { 3 | // ::arbitrary(u).map(|x| x.into_boxed_c_str()) 4 | // } 5 | // } 6 | -------------------------------------------------------------------------------- /src/foreign/std/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | mod c_str; 2 | mod os_str; 3 | -------------------------------------------------------------------------------- /src/foreign/std/ffi/os_str.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::ffi::OsString, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for OsString { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | ::arbitrary(u).map(From::from) 9 | } 10 | 11 | #[inline] 12 | fn size_hint(depth: usize) -> (usize, Option) { 13 | ::size_hint(depth) 14 | } 15 | } 16 | 17 | // impl Arbitrary for Box { 18 | // fn arbitrary(u: &mut Unstructured<'_>) -> Result { 19 | // ::arbitrary(u).map(|x| x.into_boxed_osstr()) 20 | // 21 | // } 22 | // } 23 | -------------------------------------------------------------------------------- /src/foreign/std/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for [`std`] types, 2 | //! excluding those in [`core`] and [`alloc`]. 3 | //! 4 | //! [`Arbitrary`]: crate::Arbitrary 5 | 6 | mod collections; 7 | mod ffi; 8 | mod net; 9 | mod path; 10 | mod sync; 11 | -------------------------------------------------------------------------------- /src/foreign/std/net.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for Ipv4Addr { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | Ok(Ipv4Addr::from(u32::arbitrary(u)?)) 9 | } 10 | 11 | #[inline] 12 | fn size_hint(_depth: usize) -> (usize, Option) { 13 | (4, Some(4)) 14 | } 15 | } 16 | 17 | impl<'a> Arbitrary<'a> for Ipv6Addr { 18 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 19 | Ok(Ipv6Addr::from(u128::arbitrary(u)?)) 20 | } 21 | 22 | #[inline] 23 | fn size_hint(_depth: usize) -> (usize, Option) { 24 | (16, Some(16)) 25 | } 26 | } 27 | 28 | impl<'a> Arbitrary<'a> for IpAddr { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | if u.arbitrary()? { 31 | Ok(IpAddr::V4(u.arbitrary()?)) 32 | } else { 33 | Ok(IpAddr::V6(u.arbitrary()?)) 34 | } 35 | } 36 | 37 | fn size_hint(depth: usize) -> (usize, Option) { 38 | size_hint::and( 39 | bool::size_hint(depth), 40 | size_hint::or(Ipv4Addr::size_hint(depth), Ipv6Addr::size_hint(depth)), 41 | ) 42 | } 43 | } 44 | 45 | impl<'a> Arbitrary<'a> for SocketAddrV4 { 46 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 47 | Ok(SocketAddrV4::new(u.arbitrary()?, u.arbitrary()?)) 48 | } 49 | 50 | #[inline] 51 | fn size_hint(depth: usize) -> (usize, Option) { 52 | size_hint::and(Ipv4Addr::size_hint(depth), u16::size_hint(depth)) 53 | } 54 | } 55 | 56 | impl<'a> Arbitrary<'a> for SocketAddrV6 { 57 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 58 | Ok(SocketAddrV6::new( 59 | u.arbitrary()?, 60 | u.arbitrary()?, 61 | u.arbitrary()?, 62 | u.arbitrary()?, 63 | )) 64 | } 65 | 66 | #[inline] 67 | fn size_hint(depth: usize) -> (usize, Option) { 68 | size_hint::and( 69 | Ipv6Addr::size_hint(depth), 70 | size_hint::and( 71 | u16::size_hint(depth), 72 | size_hint::and(u32::size_hint(depth), u32::size_hint(depth)), 73 | ), 74 | ) 75 | } 76 | } 77 | 78 | impl<'a> Arbitrary<'a> for SocketAddr { 79 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 80 | if u.arbitrary()? { 81 | Ok(SocketAddr::V4(u.arbitrary()?)) 82 | } else { 83 | Ok(SocketAddr::V6(u.arbitrary()?)) 84 | } 85 | } 86 | 87 | fn size_hint(depth: usize) -> (usize, Option) { 88 | size_hint::and( 89 | bool::size_hint(depth), 90 | size_hint::or( 91 | SocketAddrV4::size_hint(depth), 92 | SocketAddrV6::size_hint(depth), 93 | ), 94 | ) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/foreign/std/path.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::{ffi::OsString, path::PathBuf}, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for PathBuf { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | ::arbitrary(u).map(From::from) 9 | } 10 | 11 | #[inline] 12 | fn size_hint(depth: usize) -> (usize, Option) { 13 | ::size_hint(depth) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/foreign/std/sync.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, MaxRecursionReached, Result, Unstructured}, 3 | std::sync::Mutex, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Mutex 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 21 | A::try_size_hint(depth) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 The Rust Fuzz Project Developers. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! The `Arbitrary` trait crate. 10 | //! 11 | //! This trait provides an [`Arbitrary`] trait to 12 | //! produce well-typed, structured values, from raw, byte buffers. It is 13 | //! generally intended to be used with fuzzers like AFL or libFuzzer. See the 14 | //! [`Arbitrary`] trait's documentation for details on 15 | //! automatically deriving, implementing, and/or using the trait. 16 | 17 | #![deny(bad_style)] 18 | #![deny(missing_docs)] 19 | #![deny(future_incompatible)] 20 | #![deny(nonstandard_style)] 21 | #![deny(rust_2018_compatibility)] 22 | #![deny(rust_2018_idioms)] 23 | #![deny(unused)] 24 | 25 | mod error; 26 | mod foreign; 27 | pub mod size_hint; 28 | pub mod unstructured; 29 | 30 | #[cfg(test)] 31 | mod tests; 32 | 33 | pub use error::*; 34 | 35 | #[cfg(feature = "derive_arbitrary")] 36 | pub use derive_arbitrary::*; 37 | 38 | #[doc(inline)] 39 | pub use unstructured::Unstructured; 40 | 41 | /// Error indicating that the maximum recursion depth has been reached while calculating [`Arbitrary::size_hint`]() 42 | #[derive(Debug, Clone)] 43 | #[non_exhaustive] 44 | pub struct MaxRecursionReached {} 45 | 46 | impl core::fmt::Display for MaxRecursionReached { 47 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 48 | f.write_str("Maximum recursion depth has been reached") 49 | } 50 | } 51 | 52 | impl std::error::Error for MaxRecursionReached {} 53 | 54 | /// Generate arbitrary structured values from raw, unstructured data. 55 | /// 56 | /// The `Arbitrary` trait allows you to generate valid structured values, like 57 | /// `HashMap`s, or ASTs, or `MyTomlConfig`, or any other data structure from 58 | /// raw, unstructured bytes provided by a fuzzer. 59 | /// 60 | /// # Deriving `Arbitrary` 61 | /// 62 | /// Automatically deriving the `Arbitrary` trait is the recommended way to 63 | /// implement `Arbitrary` for your types. 64 | /// 65 | /// Using the custom derive requires that you enable the `"derive"` cargo 66 | /// feature in your `Cargo.toml`: 67 | /// 68 | /// ```toml 69 | /// [dependencies] 70 | /// arbitrary = { version = "1", features = ["derive"] } 71 | /// ``` 72 | /// 73 | /// Then, you add the `#[derive(Arbitrary)]` annotation to your `struct` or 74 | /// `enum` type definition: 75 | /// 76 | /// ``` 77 | /// # #[cfg(feature = "derive")] mod foo { 78 | /// use arbitrary::Arbitrary; 79 | /// use std::collections::HashSet; 80 | /// 81 | /// #[derive(Arbitrary)] 82 | /// pub struct AddressBook { 83 | /// friends: HashSet, 84 | /// } 85 | /// 86 | /// #[derive(Arbitrary, Hash, Eq, PartialEq)] 87 | /// pub enum Friend { 88 | /// Buddy { name: String }, 89 | /// Pal { age: usize }, 90 | /// } 91 | /// # } 92 | /// ``` 93 | /// 94 | /// Every member of the `struct` or `enum` must also implement `Arbitrary`. 95 | /// 96 | /// It is also possible to change the default bounds added by the derive: 97 | /// 98 | /// ``` 99 | /// # #[cfg(feature = "derive")] mod foo { 100 | /// use arbitrary::Arbitrary; 101 | /// 102 | /// trait Trait { 103 | /// type Assoc: for<'a> Arbitrary<'a>; 104 | /// } 105 | /// 106 | /// #[derive(Arbitrary)] 107 | /// // The bounds are used verbatim, so any existing trait bounds will need to be repeated. 108 | /// #[arbitrary(bound = "T: Trait")] 109 | /// struct Point { 110 | /// x: T::Assoc, 111 | /// } 112 | /// # } 113 | /// ``` 114 | /// 115 | /// # Implementing `Arbitrary` By Hand 116 | /// 117 | /// Implementing `Arbitrary` mostly involves nested calls to other `Arbitrary` 118 | /// arbitrary implementations for each of your `struct` or `enum`'s members. But 119 | /// sometimes you need some amount of raw data, or you need to generate a 120 | /// variably-sized collection type, or something of that sort. The 121 | /// [`Unstructured`] type helps you with these tasks. 122 | /// 123 | /// ``` 124 | /// # #[cfg(feature = "derive")] mod foo { 125 | /// # pub struct MyCollection { _t: std::marker::PhantomData } 126 | /// # impl MyCollection { 127 | /// # pub fn new() -> Self { MyCollection { _t: std::marker::PhantomData } } 128 | /// # pub fn insert(&mut self, element: T) {} 129 | /// # } 130 | /// use arbitrary::{Arbitrary, Result, Unstructured}; 131 | /// 132 | /// impl<'a, T> Arbitrary<'a> for MyCollection 133 | /// where 134 | /// T: Arbitrary<'a>, 135 | /// { 136 | /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { 137 | /// // Get an iterator of arbitrary `T`s. 138 | /// let iter = u.arbitrary_iter::()?; 139 | /// 140 | /// // And then create a collection! 141 | /// let mut my_collection = MyCollection::new(); 142 | /// for elem_result in iter { 143 | /// let elem = elem_result?; 144 | /// my_collection.insert(elem); 145 | /// } 146 | /// 147 | /// Ok(my_collection) 148 | /// } 149 | /// } 150 | /// # } 151 | /// ``` 152 | /// 153 | /// # A Note On Output Distributions 154 | /// 155 | /// There is no requirement for a particular distribution of the values. For 156 | /// example, it is not required that every value appears with the same 157 | /// probability. That being said, the main use for `Arbitrary` is for fuzzing, 158 | /// so in many cases a uniform distribution will make the most sense in order to 159 | /// provide the best coverage of the domain. In other cases this is not 160 | /// desirable or even possible, for example when sampling from a uniform 161 | /// distribution is computationally expensive or in the case of collections that 162 | /// may grow indefinitely. 163 | pub trait Arbitrary<'a>: Sized { 164 | /// Generate an arbitrary value of `Self` from the given unstructured data. 165 | /// 166 | /// Calling `Arbitrary::arbitrary` requires that you have some raw data, 167 | /// perhaps given to you by a fuzzer like AFL or libFuzzer. You wrap this 168 | /// raw data in an `Unstructured`, and then you can call `::arbitrary` to construct an arbitrary instance of `MyType` 170 | /// from that unstructured data. 171 | /// 172 | /// Implementations may return an error if there is not enough data to 173 | /// construct a full instance of `Self`, or they may fill out the rest of 174 | /// `Self` with dummy values. Using dummy values when the underlying data is 175 | /// exhausted can help avoid accidentally "defeating" some of the fuzzer's 176 | /// mutations to the underlying byte stream that might otherwise lead to 177 | /// interesting runtime behavior or new code coverage if only we had just a 178 | /// few more bytes. However, it also requires that implementations for 179 | /// recursive types (e.g. `struct Foo(Option>)`) avoid infinite 180 | /// recursion when the underlying data is exhausted. 181 | /// 182 | /// ``` 183 | /// # #[cfg(feature = "derive")] fn foo() { 184 | /// use arbitrary::{Arbitrary, Unstructured}; 185 | /// 186 | /// #[derive(Arbitrary)] 187 | /// pub struct MyType { 188 | /// // ... 189 | /// } 190 | /// 191 | /// // Get the raw data from the fuzzer or wherever else. 192 | /// # let get_raw_data_from_fuzzer = || &[]; 193 | /// let raw_data: &[u8] = get_raw_data_from_fuzzer(); 194 | /// 195 | /// // Wrap that raw data in an `Unstructured`. 196 | /// let mut unstructured = Unstructured::new(raw_data); 197 | /// 198 | /// // Generate an arbitrary instance of `MyType` and do stuff with it. 199 | /// if let Ok(value) = MyType::arbitrary(&mut unstructured) { 200 | /// # let do_stuff = |_| {}; 201 | /// do_stuff(value); 202 | /// } 203 | /// # } 204 | /// ``` 205 | /// 206 | /// See also the documentation for [`Unstructured`]. 207 | fn arbitrary(u: &mut Unstructured<'a>) -> Result; 208 | 209 | /// Generate an arbitrary value of `Self` from the entirety of the given 210 | /// unstructured data. 211 | /// 212 | /// This is similar to Arbitrary::arbitrary, however it assumes that it is 213 | /// the last consumer of the given data, and is thus able to consume it all 214 | /// if it needs. See also the documentation for 215 | /// [`Unstructured`]. 216 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 217 | Self::arbitrary(&mut u) 218 | } 219 | 220 | /// Get a size hint for how many bytes out of an `Unstructured` this type 221 | /// needs to construct itself. 222 | /// 223 | /// This is useful for determining how many elements we should insert when 224 | /// creating an arbitrary collection. 225 | /// 226 | /// The return value is similar to [`Iterator::size_hint`]: it returns a 227 | /// tuple where the first element is a lower bound on the number of bytes 228 | /// required, and the second element is an optional upper bound. 229 | /// 230 | /// The default implementation return `(0, None)` which is correct for any 231 | /// type, but not ultimately that useful. Using `#[derive(Arbitrary)]` will 232 | /// create a better implementation. If you are writing an `Arbitrary` 233 | /// implementation by hand, and your type can be part of a dynamically sized 234 | /// collection (such as `Vec`), you are strongly encouraged to override this 235 | /// default with a better implementation, and also override 236 | /// [`try_size_hint`]. 237 | /// 238 | /// ## How to implement this 239 | /// 240 | /// If the size hint calculation is a trivial constant and does not recurse 241 | /// into any other `size_hint` call, you should implement it in `size_hint`: 242 | /// 243 | /// ``` 244 | /// use arbitrary::{size_hint, Arbitrary, Result, Unstructured}; 245 | /// 246 | /// struct SomeStruct(u8); 247 | /// 248 | /// impl<'a> Arbitrary<'a> for SomeStruct { 249 | /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { 250 | /// let buf = &mut [0]; 251 | /// u.fill_buffer(buf)?; 252 | /// Ok(SomeStruct(buf[0])) 253 | /// } 254 | /// 255 | /// #[inline] 256 | /// fn size_hint(depth: usize) -> (usize, Option) { 257 | /// let _ = depth; 258 | /// (1, Some(1)) 259 | /// } 260 | /// } 261 | /// ``` 262 | /// 263 | /// Otherwise, it should instead be implemented in [`try_size_hint`], 264 | /// and the `size_hint` implementation should forward to it: 265 | /// 266 | /// ``` 267 | /// use arbitrary::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; 268 | /// 269 | /// struct SomeStruct { 270 | /// a: A, 271 | /// b: B, 272 | /// } 273 | /// 274 | /// impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for SomeStruct { 275 | /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { 276 | /// // ... 277 | /// # todo!() 278 | /// } 279 | /// 280 | /// fn size_hint(depth: usize) -> (usize, Option) { 281 | /// // Return the value of try_size_hint 282 | /// // 283 | /// // If the recursion fails, return the default, always valid `(0, None)` 284 | /// Self::try_size_hint(depth).unwrap_or_default() 285 | /// } 286 | /// 287 | /// fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 288 | /// // Protect against potential infinite recursion with 289 | /// // `try_recursion_guard`. 290 | /// size_hint::try_recursion_guard(depth, |depth| { 291 | /// // If we aren't too deep, then `recursion_guard` calls 292 | /// // this closure, which implements the natural size hint. 293 | /// // Don't forget to use the new `depth` in all nested 294 | /// // `try_size_hint` calls! We recommend shadowing the 295 | /// // parameter, like what is done here, so that you can't 296 | /// // accidentally use the wrong depth. 297 | /// Ok(size_hint::and( 298 | /// ::try_size_hint(depth)?, 299 | /// ::try_size_hint(depth)?, 300 | /// )) 301 | /// }) 302 | /// } 303 | /// } 304 | /// ``` 305 | /// 306 | /// ## Invariant 307 | /// 308 | /// It must be possible to construct every possible output using only inputs 309 | /// of lengths bounded by these parameters. This applies to both 310 | /// [`Arbitrary::arbitrary`] and [`Arbitrary::arbitrary_take_rest`]. 311 | /// 312 | /// This is trivially true for `(0, None)`. To restrict this further, it 313 | /// must be proven that all inputs that are now excluded produced redundant 314 | /// outputs which are still possible to produce using the reduced input 315 | /// space. 316 | /// 317 | /// [iterator-size-hint]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.size_hint 318 | /// [`try_size_hint`]: Arbitrary::try_size_hint 319 | #[inline] 320 | fn size_hint(depth: usize) -> (usize, Option) { 321 | let _ = depth; 322 | (0, None) 323 | } 324 | 325 | /// Get a size hint for how many bytes out of an `Unstructured` this type 326 | /// needs to construct itself. 327 | /// 328 | /// Unlike [`size_hint`], this function keeps the information that the 329 | /// recursion limit was reached. This is required to "short circuit" the 330 | /// calculation and avoid exponential blowup with recursive structures. 331 | /// 332 | /// If you are implementing [`size_hint`] for a struct that could be 333 | /// recursive, you should implement `try_size_hint` and call the 334 | /// `try_size_hint` when recursing 335 | /// 336 | /// 337 | /// The return value is similar to [`core::iter::Iterator::size_hint`]: it 338 | /// returns a tuple where the first element is a lower bound on the number 339 | /// of bytes required, and the second element is an optional upper bound. 340 | /// 341 | /// The default implementation returns the value of [`size_hint`] which is 342 | /// correct for any type, but might lead to exponential blowup when dealing 343 | /// with recursive types. 344 | /// 345 | /// ## Invariant 346 | /// 347 | /// It must be possible to construct every possible output using only inputs 348 | /// of lengths bounded by these parameters. This applies to both 349 | /// [`Arbitrary::arbitrary`] and [`Arbitrary::arbitrary_take_rest`]. 350 | /// 351 | /// This is trivially true for `(0, None)`. To restrict this further, it 352 | /// must be proven that all inputs that are now excluded produced redundant 353 | /// outputs which are still possible to produce using the reduced input 354 | /// space. 355 | /// 356 | /// ## When to implement `try_size_hint` 357 | /// 358 | /// If you 100% know that the type you are implementing `Arbitrary` for is 359 | /// not a recursive type, or your implementation is not transitively calling 360 | /// any other `size_hint` methods, you may implement [`size_hint`], and the 361 | /// default `try_size_hint` implementation will use it. 362 | /// 363 | /// Note that if you are implementing `Arbitrary` for a generic type, you 364 | /// cannot guarantee the lack of type recursion! 365 | /// 366 | /// Otherwise, when there is possible type recursion, you should implement 367 | /// `try_size_hint` instead. 368 | /// 369 | /// ## The `depth` parameter 370 | /// 371 | /// When implementing `try_size_hint`, you need to use 372 | /// [`arbitrary::size_hint::try_recursion_guard(depth)`][crate::size_hint::try_recursion_guard] 373 | /// to prevent potential infinite recursion when calculating size hints for 374 | /// potentially recursive types: 375 | /// 376 | /// ``` 377 | /// use arbitrary::{size_hint, Arbitrary, MaxRecursionReached, Unstructured}; 378 | /// 379 | /// // This can potentially be a recursive type if `L` or `R` contain 380 | /// // something like `Box>>`! 381 | /// enum MyEither { 382 | /// Left(L), 383 | /// Right(R), 384 | /// } 385 | /// 386 | /// impl<'a, L, R> Arbitrary<'a> for MyEither 387 | /// where 388 | /// L: Arbitrary<'a>, 389 | /// R: Arbitrary<'a>, 390 | /// { 391 | /// fn arbitrary(u: &mut Unstructured) -> arbitrary::Result { 392 | /// // ... 393 | /// # unimplemented!() 394 | /// } 395 | /// 396 | /// fn size_hint(depth: usize) -> (usize, Option) { 397 | /// // Return the value of `try_size_hint` 398 | /// // 399 | /// // If the recursion fails, return the default `(0, None)` range, 400 | /// // which is always valid. 401 | /// Self::try_size_hint(depth).unwrap_or_default() 402 | /// } 403 | /// 404 | /// fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 405 | /// // Protect against potential infinite recursion with 406 | /// // `try_recursion_guard`. 407 | /// size_hint::try_recursion_guard(depth, |depth| { 408 | /// // If we aren't too deep, then `recursion_guard` calls 409 | /// // this closure, which implements the natural size hint. 410 | /// // Don't forget to use the new `depth` in all nested 411 | /// // `try_size_hint` calls! We recommend shadowing the 412 | /// // parameter, like what is done here, so that you can't 413 | /// // accidentally use the wrong depth. 414 | /// Ok(size_hint::or( 415 | /// ::try_size_hint(depth)?, 416 | /// ::try_size_hint(depth)?, 417 | /// )) 418 | /// }) 419 | /// } 420 | /// } 421 | /// ``` 422 | #[inline] 423 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 424 | Ok(Self::size_hint(depth)) 425 | } 426 | } 427 | 428 | #[cfg(test)] 429 | mod test { 430 | use super::*; 431 | 432 | #[test] 433 | fn exhausted_entropy() { 434 | let mut u = Unstructured::new(&[]); 435 | assert_eq!(u.arbitrary::().unwrap(), false); 436 | assert_eq!(u.arbitrary::().unwrap(), 0); 437 | assert_eq!(u.arbitrary::().unwrap(), 0); 438 | assert_eq!(u.arbitrary::().unwrap(), 0.0); 439 | assert_eq!(u.arbitrary::().unwrap(), 0.0); 440 | assert_eq!(u.arbitrary::>().unwrap(), None); 441 | assert_eq!(u.int_in_range(4..=100).unwrap(), 4); 442 | assert_eq!(u.choose_index(10).unwrap(), 0); 443 | assert_eq!(u.ratio(5, 7).unwrap(), true); 444 | } 445 | } 446 | 447 | /// Multiple conflicting arbitrary attributes are used on the same field: 448 | /// ```compile_fail 449 | /// #[derive(::arbitrary::Arbitrary)] 450 | /// struct Point { 451 | /// #[arbitrary(value = 2)] 452 | /// #[arbitrary(value = 2)] 453 | /// x: i32, 454 | /// } 455 | /// ``` 456 | /// 457 | /// An unknown attribute: 458 | /// ```compile_fail 459 | /// #[derive(::arbitrary::Arbitrary)] 460 | /// struct Point { 461 | /// #[arbitrary(unknown_attr)] 462 | /// x: i32, 463 | /// } 464 | /// ``` 465 | /// 466 | /// An unknown attribute with a value: 467 | /// ```compile_fail 468 | /// #[derive(::arbitrary::Arbitrary)] 469 | /// struct Point { 470 | /// #[arbitrary(unknown_attr = 13)] 471 | /// x: i32, 472 | /// } 473 | /// ``` 474 | /// 475 | /// `value` without RHS: 476 | /// ```compile_fail 477 | /// #[derive(::arbitrary::Arbitrary)] 478 | /// struct Point { 479 | /// #[arbitrary(value)] 480 | /// x: i32, 481 | /// } 482 | /// ``` 483 | /// 484 | /// `with` without RHS: 485 | /// ```compile_fail 486 | /// #[derive(::arbitrary::Arbitrary)] 487 | /// struct Point { 488 | /// #[arbitrary(with)] 489 | /// x: i32, 490 | /// } 491 | /// ``` 492 | /// 493 | /// Multiple conflicting bounds at the container-level: 494 | /// ```compile_fail 495 | /// #[derive(::arbitrary::Arbitrary)] 496 | /// #[arbitrary(bound = "T: Default")] 497 | /// #[arbitrary(bound = "T: Default")] 498 | /// struct Point { 499 | /// #[arbitrary(default)] 500 | /// x: T, 501 | /// } 502 | /// ``` 503 | /// 504 | /// Multiple conflicting bounds in a single bound attribute: 505 | /// ```compile_fail 506 | /// #[derive(::arbitrary::Arbitrary)] 507 | /// #[arbitrary(bound = "T: Default, T: Default")] 508 | /// struct Point { 509 | /// #[arbitrary(default)] 510 | /// x: T, 511 | /// } 512 | /// ``` 513 | /// 514 | /// Multiple conflicting bounds in multiple bound attributes: 515 | /// ```compile_fail 516 | /// #[derive(::arbitrary::Arbitrary)] 517 | /// #[arbitrary(bound = "T: Default", bound = "T: Default")] 518 | /// struct Point { 519 | /// #[arbitrary(default)] 520 | /// x: T, 521 | /// } 522 | /// ``` 523 | /// 524 | /// Too many bounds supplied: 525 | /// ```compile_fail 526 | /// #[derive(::arbitrary::Arbitrary)] 527 | /// #[arbitrary(bound = "T: Default")] 528 | /// struct Point { 529 | /// x: i32, 530 | /// } 531 | /// ``` 532 | /// 533 | /// Too many bounds supplied across multiple attributes: 534 | /// ```compile_fail 535 | /// #[derive(::arbitrary::Arbitrary)] 536 | /// #[arbitrary(bound = "T: Default")] 537 | /// #[arbitrary(bound = "U: Default")] 538 | /// struct Point { 539 | /// #[arbitrary(default)] 540 | /// x: T, 541 | /// } 542 | /// ``` 543 | /// 544 | /// Attempt to use the derive attribute on an enum variant: 545 | /// ```compile_fail 546 | /// #[derive(::arbitrary::Arbitrary)] 547 | /// enum Enum { 548 | /// #[arbitrary(default)] 549 | /// Variant(T), 550 | /// } 551 | /// ``` 552 | #[cfg(all(doctest, feature = "derive"))] 553 | pub struct CompileFailTests; 554 | -------------------------------------------------------------------------------- /src/size_hint.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for working with and combining the results of 2 | //! [`Arbitrary::size_hint`][crate::Arbitrary::size_hint]. 3 | 4 | pub(crate) const MAX_DEPTH: usize = 20; 5 | 6 | /// Protects against potential infinite recursion when calculating size hints 7 | /// due to indirect type recursion. 8 | /// 9 | /// When the depth is not too deep, calls `f` with `depth + 1` to calculate the 10 | /// size hint. 11 | /// 12 | /// Otherwise, returns the default size hint: `(0, None)`. 13 | /// 14 | /// 15 | #[inline] 16 | #[deprecated(note = "use `try_recursion_guard` instead")] 17 | pub fn recursion_guard( 18 | depth: usize, 19 | f: impl FnOnce(usize) -> (usize, Option), 20 | ) -> (usize, Option) { 21 | if depth > MAX_DEPTH { 22 | (0, None) 23 | } else { 24 | f(depth + 1) 25 | } 26 | } 27 | 28 | /// Protects against potential infinite recursion when calculating size hints 29 | /// due to indirect type recursion. 30 | /// 31 | /// When the depth is not too deep, calls `f` with `depth + 1` to calculate the 32 | /// size hint. 33 | /// 34 | /// Otherwise, returns an error. 35 | /// 36 | /// This should be used when implementing [`try_size_hint`](crate::Arbitrary::try_size_hint) 37 | #[inline] 38 | pub fn try_recursion_guard( 39 | depth: usize, 40 | f: impl FnOnce(usize) -> Result<(usize, Option), crate::MaxRecursionReached>, 41 | ) -> Result<(usize, Option), crate::MaxRecursionReached> { 42 | if depth > MAX_DEPTH { 43 | Err(crate::MaxRecursionReached {}) 44 | } else { 45 | f(depth + 1) 46 | } 47 | } 48 | 49 | /// Take the sum of the `lhs` and `rhs` size hints. 50 | #[inline] 51 | pub fn and(lhs: (usize, Option), rhs: (usize, Option)) -> (usize, Option) { 52 | let lower = lhs.0 + rhs.0; 53 | let upper = lhs.1.and_then(|lhs| rhs.1.map(|rhs| lhs + rhs)); 54 | (lower, upper) 55 | } 56 | 57 | /// Take the sum of all of the given size hints. 58 | /// 59 | /// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming 60 | /// nothing. 61 | #[inline] 62 | pub fn and_all(hints: &[(usize, Option)]) -> (usize, Option) { 63 | hints.iter().copied().fold((0, Some(0)), and) 64 | } 65 | 66 | /// Take the minimum of the lower bounds and maximum of the upper bounds in the 67 | /// `lhs` and `rhs` size hints. 68 | #[inline] 69 | pub fn or(lhs: (usize, Option), rhs: (usize, Option)) -> (usize, Option) { 70 | let lower = std::cmp::min(lhs.0, rhs.0); 71 | let upper = lhs 72 | .1 73 | .and_then(|lhs| rhs.1.map(|rhs| std::cmp::max(lhs, rhs))); 74 | (lower, upper) 75 | } 76 | 77 | /// Take the maximum of the `lhs` and `rhs` size hints. 78 | /// 79 | /// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming 80 | /// nothing. 81 | #[inline] 82 | pub fn or_all(hints: &[(usize, Option)]) -> (usize, Option) { 83 | if let Some(head) = hints.first().copied() { 84 | hints[1..].iter().copied().fold(head, or) 85 | } else { 86 | (0, Some(0)) 87 | } 88 | } 89 | 90 | #[cfg(test)] 91 | mod tests { 92 | #[test] 93 | fn and() { 94 | assert_eq!((5, Some(5)), super::and((2, Some(2)), (3, Some(3)))); 95 | assert_eq!((5, None), super::and((2, Some(2)), (3, None))); 96 | assert_eq!((5, None), super::and((2, None), (3, Some(3)))); 97 | assert_eq!((5, None), super::and((2, None), (3, None))); 98 | } 99 | 100 | #[test] 101 | fn or() { 102 | assert_eq!((2, Some(3)), super::or((2, Some(2)), (3, Some(3)))); 103 | assert_eq!((2, None), super::or((2, Some(2)), (3, None))); 104 | assert_eq!((2, None), super::or((2, None), (3, Some(3)))); 105 | assert_eq!((2, None), super::or((2, None), (3, None))); 106 | } 107 | 108 | #[test] 109 | fn and_all() { 110 | assert_eq!((0, Some(0)), super::and_all(&[])); 111 | assert_eq!( 112 | (7, Some(7)), 113 | super::and_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))]) 114 | ); 115 | assert_eq!( 116 | (7, None), 117 | super::and_all(&[(1, Some(1)), (2, Some(2)), (4, None)]) 118 | ); 119 | assert_eq!( 120 | (7, None), 121 | super::and_all(&[(1, Some(1)), (2, None), (4, Some(4))]) 122 | ); 123 | assert_eq!( 124 | (7, None), 125 | super::and_all(&[(1, None), (2, Some(2)), (4, Some(4))]) 126 | ); 127 | } 128 | 129 | #[test] 130 | fn or_all() { 131 | assert_eq!((0, Some(0)), super::or_all(&[])); 132 | assert_eq!( 133 | (1, Some(4)), 134 | super::or_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))]) 135 | ); 136 | assert_eq!( 137 | (1, None), 138 | super::or_all(&[(1, Some(1)), (2, Some(2)), (4, None)]) 139 | ); 140 | assert_eq!( 141 | (1, None), 142 | super::or_all(&[(1, Some(1)), (2, None), (4, Some(4))]) 143 | ); 144 | assert_eq!( 145 | (1, None), 146 | super::or_all(&[(1, None), (2, Some(2)), (4, Some(4))]) 147 | ); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::{Arbitrary, Result, Unstructured}, 3 | std::{collections::HashSet, fmt::Debug, hash::Hash, rc::Rc, sync::Arc}, 4 | }; 5 | 6 | /// Assert that the given expected values are all generated. 7 | /// 8 | /// Exhaustively enumerates all buffers up to length 10 containing the 9 | /// following bytes: `0x00`, `0x01`, `0x61` (aka ASCII 'a'), and `0xff` 10 | fn assert_generates(expected_values: impl IntoIterator) 11 | where 12 | T: Clone + Debug + Hash + Eq + for<'a> Arbitrary<'a>, 13 | { 14 | let expected_values: HashSet<_> = expected_values.into_iter().collect(); 15 | let mut arbitrary_expected = expected_values.clone(); 16 | let mut arbitrary_take_rest_expected = expected_values; 17 | 18 | let bytes = [0, 1, b'a', 0xff]; 19 | let max_len = 10; 20 | 21 | let mut buf = Vec::with_capacity(max_len); 22 | 23 | let mut g = exhaustigen::Gen::new(); 24 | while !g.done() { 25 | let len = g.gen(max_len); 26 | 27 | buf.clear(); 28 | buf.extend( 29 | std::iter::repeat_with(|| { 30 | let index = g.gen(bytes.len() - 1); 31 | bytes[index] 32 | }) 33 | .take(len), 34 | ); 35 | 36 | let mut u = Unstructured::new(&buf); 37 | let val = T::arbitrary(&mut u).unwrap(); 38 | arbitrary_expected.remove(&val); 39 | 40 | let u = Unstructured::new(&buf); 41 | let val = T::arbitrary_take_rest(u).unwrap(); 42 | arbitrary_take_rest_expected.remove(&val); 43 | 44 | if arbitrary_expected.is_empty() && arbitrary_take_rest_expected.is_empty() { 45 | return; 46 | } 47 | } 48 | 49 | panic!( 50 | "failed to generate all expected values!\n\n\ 51 | T::arbitrary did not generate: {arbitrary_expected:#?}\n\n\ 52 | T::arbitrary_take_rest did not generate {arbitrary_take_rest_expected:#?}" 53 | ) 54 | } 55 | 56 | /// Generates an arbitrary `T`, and checks that the result is consistent with the 57 | /// `size_hint()` reported by `T`. 58 | fn checked_arbitrary<'a, T: Arbitrary<'a>>(u: &mut Unstructured<'a>) -> Result { 59 | let (min, max) = T::size_hint(0); 60 | 61 | let len_before = u.len(); 62 | let result = T::arbitrary(u); 63 | 64 | let consumed = len_before - u.len(); 65 | 66 | if let Some(max) = max { 67 | assert!( 68 | consumed <= max, 69 | "incorrect maximum size: indicated {}, actually consumed {}", 70 | max, 71 | consumed 72 | ); 73 | } 74 | 75 | if result.is_ok() { 76 | assert!( 77 | consumed >= min, 78 | "incorrect minimum size: indicated {}, actually consumed {}", 79 | min, 80 | consumed 81 | ); 82 | } 83 | 84 | result 85 | } 86 | 87 | /// Like `checked_arbitrary()`, but calls `arbitrary_take_rest()` instead of `arbitrary()`. 88 | fn checked_arbitrary_take_rest<'a, T: Arbitrary<'a>>(u: Unstructured<'a>) -> Result { 89 | let (min, _) = T::size_hint(0); 90 | 91 | let len_before = u.len(); 92 | let result = T::arbitrary_take_rest(u); 93 | 94 | if result.is_ok() { 95 | assert!( 96 | len_before >= min, 97 | "incorrect minimum size: indicated {}, worked with {}", 98 | min, 99 | len_before 100 | ); 101 | } 102 | 103 | result 104 | } 105 | 106 | #[test] 107 | fn finite_buffer_fill_buffer() { 108 | let x = [1, 2, 3, 4]; 109 | let mut rb = Unstructured::new(&x); 110 | let mut z = [0; 2]; 111 | rb.fill_buffer(&mut z).unwrap(); 112 | assert_eq!(z, [1, 2]); 113 | rb.fill_buffer(&mut z).unwrap(); 114 | assert_eq!(z, [3, 4]); 115 | rb.fill_buffer(&mut z).unwrap(); 116 | assert_eq!(z, [0, 0]); 117 | } 118 | 119 | #[test] 120 | fn arbitrary_for_integers() { 121 | let x = [1, 2, 3, 4]; 122 | let mut buf = Unstructured::new(&x); 123 | let expected = 1 | (2 << 8) | (3 << 16) | (4 << 24); 124 | let actual = checked_arbitrary::(&mut buf).unwrap(); 125 | assert_eq!(expected, actual); 126 | 127 | assert_generates([ 128 | i32::from_ne_bytes([0, 0, 0, 0]), 129 | i32::from_ne_bytes([0, 0, 0, 1]), 130 | i32::from_ne_bytes([0, 0, 1, 0]), 131 | i32::from_ne_bytes([0, 1, 0, 0]), 132 | i32::from_ne_bytes([1, 0, 0, 0]), 133 | i32::from_ne_bytes([1, 1, 1, 1]), 134 | i32::from_ne_bytes([0xff, 0xff, 0xff, 0xff]), 135 | ]); 136 | } 137 | 138 | #[test] 139 | fn arbitrary_for_bytes() { 140 | let x = [1, 2, 3, 4, 4]; 141 | let mut buf = Unstructured::new(&x); 142 | let expected = &[1, 2, 3, 4]; 143 | let actual = checked_arbitrary::<&[u8]>(&mut buf).unwrap(); 144 | assert_eq!(expected, actual); 145 | } 146 | 147 | #[test] 148 | fn arbitrary_take_rest_for_bytes() { 149 | let x = [1, 2, 3, 4]; 150 | let buf = Unstructured::new(&x); 151 | let expected = &[1, 2, 3, 4]; 152 | let actual = checked_arbitrary_take_rest::<&[u8]>(buf).unwrap(); 153 | assert_eq!(expected, actual); 154 | } 155 | 156 | #[test] 157 | fn arbitrary_for_vec_u8() { 158 | assert_generates::>([ 159 | vec![], 160 | vec![0], 161 | vec![1], 162 | vec![0, 0], 163 | vec![0, 1], 164 | vec![1, 0], 165 | vec![1, 1], 166 | vec![0, 0, 0], 167 | vec![0, 0, 1], 168 | vec![0, 1, 0], 169 | vec![0, 1, 1], 170 | vec![1, 0, 0], 171 | vec![1, 0, 1], 172 | vec![1, 1, 0], 173 | vec![1, 1, 1], 174 | ]); 175 | } 176 | 177 | #[test] 178 | fn arbitrary_for_vec_vec_u8() { 179 | assert_generates::>>([ 180 | vec![], 181 | vec![vec![]], 182 | vec![vec![0]], 183 | vec![vec![1]], 184 | vec![vec![0, 1]], 185 | vec![vec![], vec![]], 186 | vec![vec![0], vec![]], 187 | vec![vec![], vec![1]], 188 | vec![vec![0], vec![1]], 189 | vec![vec![0, 1], vec![]], 190 | vec![vec![], vec![1, 0]], 191 | vec![vec![], vec![], vec![]], 192 | ]); 193 | } 194 | 195 | #[test] 196 | fn arbitrary_for_vec_vec_vec_u8() { 197 | assert_generates::>>>([ 198 | vec![], 199 | vec![vec![]], 200 | vec![vec![vec![0]]], 201 | vec![vec![vec![1]]], 202 | vec![vec![vec![0, 1]]], 203 | vec![vec![], vec![]], 204 | vec![vec![], vec![vec![]]], 205 | vec![vec![vec![]], vec![]], 206 | vec![vec![vec![]], vec![vec![]]], 207 | vec![vec![vec![0]], vec![]], 208 | vec![vec![], vec![vec![1]]], 209 | vec![vec![vec![0]], vec![vec![1]]], 210 | vec![vec![vec![0, 1]], vec![]], 211 | vec![vec![], vec![vec![0, 1]]], 212 | vec![vec![], vec![], vec![]], 213 | vec![vec![vec![]], vec![], vec![]], 214 | vec![vec![], vec![vec![]], vec![]], 215 | vec![vec![], vec![], vec![vec![]]], 216 | ]); 217 | } 218 | 219 | #[test] 220 | fn arbitrary_for_string() { 221 | assert_generates::(["".into(), "a".into(), "aa".into(), "aaa".into()]); 222 | } 223 | 224 | #[test] 225 | fn arbitrary_collection() { 226 | let x = [ 227 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 12, 228 | ]; 229 | assert_eq!( 230 | checked_arbitrary::<&[u8]>(&mut Unstructured::new(&x)).unwrap(), 231 | &[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3] 232 | ); 233 | assert_eq!( 234 | checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 235 | &[2, 4, 6, 8, 1] 236 | ); 237 | assert_eq!( 238 | &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 239 | &[2, 4, 6, 8, 1] 240 | ); 241 | assert_eq!( 242 | &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 243 | &[2, 4, 6, 8, 1] 244 | ); 245 | assert_eq!( 246 | &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 247 | &[2, 4, 6, 8, 1] 248 | ); 249 | assert_eq!( 250 | checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 251 | &[84148994] 252 | ); 253 | assert_eq!( 254 | checked_arbitrary::(&mut Unstructured::new(&x)).unwrap(), 255 | "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03" 256 | ); 257 | } 258 | 259 | #[test] 260 | fn arbitrary_take_rest() { 261 | // Basic examples 262 | let x = [1, 2, 3, 4]; 263 | assert_eq!( 264 | checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&x)).unwrap(), 265 | &[1, 2, 3, 4] 266 | ); 267 | assert_eq!( 268 | checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 269 | &[2, 4] 270 | ); 271 | assert_eq!( 272 | &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 273 | &[2, 4] 274 | ); 275 | assert_eq!( 276 | &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 277 | &[2, 4] 278 | ); 279 | assert_eq!( 280 | &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 281 | &[2, 4] 282 | ); 283 | assert_eq!( 284 | checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 285 | &[0x040302] 286 | ); 287 | assert_eq!( 288 | checked_arbitrary_take_rest::(Unstructured::new(&x)).unwrap(), 289 | "\x01\x02\x03\x04" 290 | ); 291 | 292 | // Empty remainder 293 | assert_eq!( 294 | checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&[])).unwrap(), 295 | &[] 296 | ); 297 | assert_eq!( 298 | checked_arbitrary_take_rest::>(Unstructured::new(&[])).unwrap(), 299 | &[] 300 | ); 301 | 302 | // Cannot consume all but can consume part of the input 303 | assert_eq!( 304 | checked_arbitrary_take_rest::(Unstructured::new(&[1, 0xFF, 2])).unwrap(), 305 | "\x01" 306 | ); 307 | } 308 | 309 | #[test] 310 | fn size_hint_for_tuples() { 311 | assert_eq!( 312 | (7, Some(7)), 313 | <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0) 314 | ); 315 | assert_eq!((1, None), <(u8, Vec) as Arbitrary>::size_hint(0)); 316 | } 317 | -------------------------------------------------------------------------------- /src/unstructured.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 The Rust Fuzz Project Developers. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Wrappers around raw, unstructured bytes. 10 | 11 | use crate::{Arbitrary, Error, Result}; 12 | use std::marker::PhantomData; 13 | use std::ops::ControlFlow; 14 | use std::{mem, ops}; 15 | 16 | /// A source of unstructured data. 17 | /// 18 | /// An `Unstructured` helps `Arbitrary` implementations interpret raw data 19 | /// (typically provided by a fuzzer) as a "DNA string" that describes how to 20 | /// construct the `Arbitrary` type. The goal is that a small change to the "DNA 21 | /// string" (the raw data wrapped by an `Unstructured`) results in a small 22 | /// change to the generated `Arbitrary` instance. This helps a fuzzer 23 | /// efficiently explore the `Arbitrary`'s input space. 24 | /// 25 | /// `Unstructured` is deterministic: given the same raw data, the same series of 26 | /// API calls will return the same results (modulo system resource constraints, 27 | /// like running out of memory). However, `Unstructured` does not guarantee 28 | /// anything beyond that: it makes not guarantee that it will yield bytes from 29 | /// the underlying data in any particular order. 30 | /// 31 | /// You shouldn't generally need to use an `Unstructured` unless you are writing 32 | /// a custom `Arbitrary` implementation by hand, instead of deriving it. Mostly, 33 | /// you should just be passing it through to nested `Arbitrary::arbitrary` 34 | /// calls. 35 | /// 36 | /// # Example 37 | /// 38 | /// Imagine you were writing a color conversion crate. You might want to write 39 | /// fuzz tests that take a random RGB color and assert various properties, run 40 | /// functions and make sure nothing panics, etc. 41 | /// 42 | /// Below is what translating the fuzzer's raw input into an `Unstructured` and 43 | /// using that to generate an arbitrary RGB color might look like: 44 | /// 45 | /// ``` 46 | /// # #[cfg(feature = "derive")] fn foo() { 47 | /// use arbitrary::{Arbitrary, Unstructured}; 48 | /// 49 | /// /// An RGB color. 50 | /// #[derive(Arbitrary)] 51 | /// pub struct Rgb { 52 | /// r: u8, 53 | /// g: u8, 54 | /// b: u8, 55 | /// } 56 | /// 57 | /// // Get the raw bytes from the fuzzer. 58 | /// # let get_input_from_fuzzer = || &[]; 59 | /// let raw_data: &[u8] = get_input_from_fuzzer(); 60 | /// 61 | /// // Wrap it in an `Unstructured`. 62 | /// let mut unstructured = Unstructured::new(raw_data); 63 | /// 64 | /// // Generate an `Rgb` color and run our checks. 65 | /// if let Ok(rgb) = Rgb::arbitrary(&mut unstructured) { 66 | /// # let run_my_color_conversion_checks = |_| {}; 67 | /// run_my_color_conversion_checks(rgb); 68 | /// } 69 | /// # } 70 | /// ``` 71 | #[derive(Debug)] 72 | pub struct Unstructured<'a> { 73 | data: &'a [u8], 74 | } 75 | 76 | impl<'a> Unstructured<'a> { 77 | /// Create a new `Unstructured` from the given raw data. 78 | /// 79 | /// # Example 80 | /// 81 | /// ``` 82 | /// use arbitrary::Unstructured; 83 | /// 84 | /// let u = Unstructured::new(&[1, 2, 3, 4]); 85 | /// ``` 86 | pub fn new(data: &'a [u8]) -> Self { 87 | Unstructured { data } 88 | } 89 | 90 | /// Get the number of remaining bytes of underlying data that are still 91 | /// available. 92 | /// 93 | /// # Example 94 | /// 95 | /// ``` 96 | /// use arbitrary::{Arbitrary, Unstructured}; 97 | /// 98 | /// let mut u = Unstructured::new(&[1, 2, 3]); 99 | /// 100 | /// // Initially have three bytes of data. 101 | /// assert_eq!(u.len(), 3); 102 | /// 103 | /// // Generating a `bool` consumes one byte from the underlying data, so 104 | /// // we are left with two bytes afterwards. 105 | /// let _ = bool::arbitrary(&mut u); 106 | /// assert_eq!(u.len(), 2); 107 | /// ``` 108 | #[inline] 109 | pub fn len(&self) -> usize { 110 | self.data.len() 111 | } 112 | 113 | /// Is the underlying unstructured data exhausted? 114 | /// 115 | /// `unstructured.is_empty()` is the same as `unstructured.len() == 0`. 116 | /// 117 | /// # Example 118 | /// 119 | /// ``` 120 | /// use arbitrary::{Arbitrary, Unstructured}; 121 | /// 122 | /// let mut u = Unstructured::new(&[1, 2, 3, 4]); 123 | /// 124 | /// // Initially, we are not empty. 125 | /// assert!(!u.is_empty()); 126 | /// 127 | /// // Generating a `u32` consumes all four bytes of the underlying data, so 128 | /// // we become empty afterwards. 129 | /// let _ = u32::arbitrary(&mut u); 130 | /// assert!(u.is_empty()); 131 | /// ``` 132 | #[inline] 133 | pub fn is_empty(&self) -> bool { 134 | self.len() == 0 135 | } 136 | 137 | /// Generate an arbitrary instance of `A`. 138 | /// 139 | /// This is simply a helper method that is equivalent to `::arbitrary(self)`. This helper is a little bit more concise, 141 | /// and can be used in situations where Rust's type inference will figure 142 | /// out what `A` should be. 143 | /// 144 | /// # Example 145 | /// 146 | /// ``` 147 | /// # #[cfg(feature="derive")] fn foo() -> arbitrary::Result<()> { 148 | /// use arbitrary::{Arbitrary, Unstructured}; 149 | /// 150 | /// #[derive(Arbitrary)] 151 | /// struct MyType { 152 | /// // ... 153 | /// } 154 | /// 155 | /// fn do_stuff(value: MyType) { 156 | /// # let _ = value; 157 | /// // ... 158 | /// } 159 | /// 160 | /// let mut u = Unstructured::new(&[1, 2, 3, 4]); 161 | /// 162 | /// // Rust's type inference can figure out that `value` should be of type 163 | /// // `MyType` here: 164 | /// let value = u.arbitrary()?; 165 | /// do_stuff(value); 166 | /// # Ok(()) } 167 | /// ``` 168 | pub fn arbitrary(&mut self) -> Result 169 | where 170 | A: Arbitrary<'a>, 171 | { 172 | >::arbitrary(self) 173 | } 174 | 175 | /// Get the number of elements to insert when building up a collection of 176 | /// arbitrary `ElementType`s. 177 | /// 178 | /// This uses the [`::size_hint`][crate::Arbitrary::size_hint] method to smartly 180 | /// choose a length such that we most likely have enough underlying bytes to 181 | /// construct that many arbitrary `ElementType`s. 182 | /// 183 | /// This should only be called within an `Arbitrary` implementation. 184 | /// 185 | /// # Example 186 | /// 187 | /// ``` 188 | /// use arbitrary::{Arbitrary, Result, Unstructured}; 189 | /// # pub struct MyCollection { _t: std::marker::PhantomData } 190 | /// # impl MyCollection { 191 | /// # pub fn with_capacity(capacity: usize) -> Self { MyCollection { _t: std::marker::PhantomData } } 192 | /// # pub fn insert(&mut self, element: T) {} 193 | /// # } 194 | /// 195 | /// impl<'a, T> Arbitrary<'a> for MyCollection 196 | /// where 197 | /// T: Arbitrary<'a>, 198 | /// { 199 | /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { 200 | /// // Get the number of `T`s we should insert into our collection. 201 | /// let len = u.arbitrary_len::()?; 202 | /// 203 | /// // And then create a collection of that length! 204 | /// let mut my_collection = MyCollection::with_capacity(len); 205 | /// for _ in 0..len { 206 | /// let element = T::arbitrary(u)?; 207 | /// my_collection.insert(element); 208 | /// } 209 | /// 210 | /// Ok(my_collection) 211 | /// } 212 | /// } 213 | /// ``` 214 | pub fn arbitrary_len(&mut self) -> Result 215 | where 216 | ElementType: Arbitrary<'a>, 217 | { 218 | let byte_size = self.arbitrary_byte_size()?; 219 | let (lower, upper) = ::size_hint(0); 220 | let elem_size = upper.unwrap_or(lower * 2); 221 | let elem_size = std::cmp::max(1, elem_size); 222 | Ok(byte_size / elem_size) 223 | } 224 | 225 | fn arbitrary_byte_size(&mut self) -> Result { 226 | if self.data.is_empty() { 227 | Ok(0) 228 | } else if self.data.len() == 1 { 229 | self.data = &[]; 230 | Ok(0) 231 | } else { 232 | // Take lengths from the end of the data, since the `libFuzzer` folks 233 | // found that this lets fuzzers more efficiently explore the input 234 | // space. 235 | // 236 | // https://github.com/rust-fuzz/libfuzzer-sys/blob/0c450753/libfuzzer/utils/FuzzedDataProvider.h#L92-L97 237 | 238 | // We only consume as many bytes as necessary to cover the entire 239 | // range of the byte string. 240 | // Note: We cast to u64 so we don't overflow when checking u32::MAX + 4 on 32-bit archs 241 | let len = if self.data.len() as u64 <= u8::MAX as u64 + 1 { 242 | let bytes = 1; 243 | let max_size = self.data.len() - bytes; 244 | let (rest, for_size) = self.data.split_at(max_size); 245 | self.data = rest; 246 | Self::int_in_range_impl(0..=max_size as u8, for_size.iter().copied())?.0 as usize 247 | } else if self.data.len() as u64 <= u16::MAX as u64 + 2 { 248 | let bytes = 2; 249 | let max_size = self.data.len() - bytes; 250 | let (rest, for_size) = self.data.split_at(max_size); 251 | self.data = rest; 252 | Self::int_in_range_impl(0..=max_size as u16, for_size.iter().copied())?.0 as usize 253 | } else if self.data.len() as u64 <= u32::MAX as u64 + 4 { 254 | let bytes = 4; 255 | let max_size = self.data.len() - bytes; 256 | let (rest, for_size) = self.data.split_at(max_size); 257 | self.data = rest; 258 | Self::int_in_range_impl(0..=max_size as u32, for_size.iter().copied())?.0 as usize 259 | } else { 260 | let bytes = 8; 261 | let max_size = self.data.len() - bytes; 262 | let (rest, for_size) = self.data.split_at(max_size); 263 | self.data = rest; 264 | Self::int_in_range_impl(0..=max_size as u64, for_size.iter().copied())?.0 as usize 265 | }; 266 | 267 | Ok(len) 268 | } 269 | } 270 | 271 | /// Generate an integer within the given range. 272 | /// 273 | /// Do not use this to generate the size of a collection. Use 274 | /// `arbitrary_len` instead. 275 | /// 276 | /// The probability distribution of the return value is not necessarily uniform. 277 | /// 278 | /// Returns `range.start()`, not an error, 279 | /// if this `Unstructured` [is empty][Unstructured::is_empty]. 280 | /// 281 | /// # Panics 282 | /// 283 | /// Panics if `range.start > range.end`. That is, the given range must be 284 | /// non-empty. 285 | /// 286 | /// # Example 287 | /// 288 | /// ``` 289 | /// # fn foo() -> arbitrary::Result<()> { 290 | /// use arbitrary::{Arbitrary, Unstructured}; 291 | /// 292 | /// let mut u = Unstructured::new(&[1, 2, 3, 4]); 293 | /// 294 | /// let x: i32 = u.int_in_range(-5_000..=-1_000)?; 295 | /// 296 | /// assert!(-5_000 <= x); 297 | /// assert!(x <= -1_000); 298 | /// # Ok(()) } 299 | /// ``` 300 | pub fn int_in_range(&mut self, range: ops::RangeInclusive) -> Result 301 | where 302 | T: Int, 303 | { 304 | let (result, bytes_consumed) = Self::int_in_range_impl(range, self.data.iter().cloned())?; 305 | self.data = &self.data[bytes_consumed..]; 306 | Ok(result) 307 | } 308 | 309 | fn int_in_range_impl( 310 | range: ops::RangeInclusive, 311 | mut bytes: impl Iterator, 312 | ) -> Result<(T, usize)> 313 | where 314 | T: Int, 315 | { 316 | let start = *range.start(); 317 | let end = *range.end(); 318 | assert!( 319 | start <= end, 320 | "`arbitrary::Unstructured::int_in_range` requires a non-empty range" 321 | ); 322 | 323 | // When there is only one possible choice, don't waste any entropy from 324 | // the underlying data. 325 | if start == end { 326 | return Ok((start, 0)); 327 | } 328 | 329 | // From here on out we work with the unsigned representation. All of the 330 | // operations performed below work out just as well whether or not `T` 331 | // is a signed or unsigned integer. 332 | let start = start.to_unsigned(); 333 | let end = end.to_unsigned(); 334 | 335 | let delta = end.wrapping_sub(start); 336 | debug_assert_ne!(delta, T::Unsigned::ZERO); 337 | 338 | // Compute an arbitrary integer offset from the start of the range. We 339 | // do this by consuming `size_of(T)` bytes from the input to create an 340 | // arbitrary integer and then clamping that int into our range bounds 341 | // with a modulo operation. 342 | let mut arbitrary_int = T::Unsigned::ZERO; 343 | let mut bytes_consumed: usize = 0; 344 | 345 | while (bytes_consumed < mem::size_of::()) 346 | && (delta >> T::Unsigned::from_usize(bytes_consumed * 8)) > T::Unsigned::ZERO 347 | { 348 | let byte = match bytes.next() { 349 | None => break, 350 | Some(b) => b, 351 | }; 352 | bytes_consumed += 1; 353 | 354 | // Combine this byte into our arbitrary integer, but avoid 355 | // overflowing the shift for `u8` and `i8`. 356 | arbitrary_int = if mem::size_of::() == 1 { 357 | T::Unsigned::from_u8(byte) 358 | } else { 359 | (arbitrary_int << 8) | T::Unsigned::from_u8(byte) 360 | }; 361 | } 362 | 363 | let offset = if delta == T::Unsigned::MAX { 364 | arbitrary_int 365 | } else { 366 | arbitrary_int % (delta.checked_add(T::Unsigned::ONE).unwrap()) 367 | }; 368 | 369 | // Finally, we add `start` to our offset from `start` to get the result 370 | // actual value within the range. 371 | let result = start.wrapping_add(offset); 372 | 373 | // And convert back to our maybe-signed representation. 374 | let result = T::from_unsigned(result); 375 | debug_assert!(*range.start() <= result); 376 | debug_assert!(result <= *range.end()); 377 | 378 | Ok((result, bytes_consumed)) 379 | } 380 | 381 | /// Choose one of the given choices. 382 | /// 383 | /// This should only be used inside of `Arbitrary` implementations. 384 | /// 385 | /// The probability distribution of choices is not necessarily uniform. 386 | /// 387 | /// Returns the first choice, not an error, 388 | /// if this `Unstructured` [is empty][Unstructured::is_empty]. 389 | /// 390 | /// Returns an error if no choices are provided. 391 | /// 392 | /// # Examples 393 | /// 394 | /// Selecting from an array of choices: 395 | /// 396 | /// ``` 397 | /// use arbitrary::Unstructured; 398 | /// 399 | /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); 400 | /// let choices = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; 401 | /// 402 | /// let choice = u.choose(&choices).unwrap(); 403 | /// 404 | /// println!("chose {}", choice); 405 | /// ``` 406 | /// 407 | /// An error is returned if no choices are provided: 408 | /// 409 | /// ``` 410 | /// use arbitrary::Unstructured; 411 | /// 412 | /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); 413 | /// let choices: [char; 0] = []; 414 | /// 415 | /// let result = u.choose(&choices); 416 | /// 417 | /// assert!(result.is_err()); 418 | /// ``` 419 | pub fn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T> { 420 | let idx = self.choose_index(choices.len())?; 421 | Ok(&choices[idx]) 422 | } 423 | 424 | /// Choose one of the given iterator choices. 425 | /// 426 | /// This should only be used inside of `Arbitrary` implementations. 427 | /// 428 | /// The probability distribution of choices is not necessarily uniform. 429 | /// 430 | /// Returns the first choice, not an error, 431 | /// if this `Unstructured` [is empty][Unstructured::is_empty]. 432 | /// 433 | /// Returns an error if no choices are provided. 434 | /// 435 | /// # Examples 436 | /// 437 | /// Selecting a random item from a set: 438 | /// 439 | /// ``` 440 | /// use std::collections::BTreeSet; 441 | /// use arbitrary::Unstructured; 442 | /// 443 | /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); 444 | /// let set = BTreeSet::from(['a', 'b', 'c']); 445 | /// 446 | /// let choice = u.choose_iter(set.iter()).unwrap(); 447 | /// 448 | /// println!("chose {}", choice); 449 | /// ``` 450 | pub fn choose_iter(&mut self, choices: I) -> Result 451 | where 452 | I: IntoIterator, 453 | I::IntoIter: ExactSizeIterator, 454 | { 455 | let mut choices = choices.into_iter(); 456 | let idx = self.choose_index(choices.len())?; 457 | let choice = choices 458 | .nth(idx) 459 | .expect("ExactSizeIterator should have correct len"); 460 | Ok(choice) 461 | } 462 | 463 | /// Choose a value in `0..len`. 464 | /// 465 | /// The probability distribution of return values is not necessarily uniform. 466 | /// 467 | /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 468 | /// 469 | /// Returns an error if the `len` is zero. 470 | /// 471 | /// # Examples 472 | /// 473 | /// Using Fisher–Yates shuffle shuffle to gerate an arbitrary permutation. 474 | /// 475 | /// [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle 476 | /// 477 | /// ``` 478 | /// use arbitrary::Unstructured; 479 | /// 480 | /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); 481 | /// let mut permutation = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; 482 | /// let mut to_permute = &mut permutation[..]; 483 | /// while to_permute.len() > 1 { 484 | /// let idx = u.choose_index(to_permute.len()).unwrap(); 485 | /// to_permute.swap(0, idx); 486 | /// to_permute = &mut to_permute[1..]; 487 | /// } 488 | /// 489 | /// println!("permutation: {:?}", permutation); 490 | /// ``` 491 | /// 492 | /// An error is returned if the length is zero: 493 | /// 494 | /// ``` 495 | /// use arbitrary::Unstructured; 496 | /// 497 | /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); 498 | /// let array: [i32; 0] = []; 499 | /// 500 | /// let result = u.choose_index(array.len()); 501 | /// 502 | /// assert!(result.is_err()); 503 | /// ``` 504 | pub fn choose_index(&mut self, len: usize) -> Result { 505 | if len == 0 { 506 | return Err(Error::EmptyChoose); 507 | } 508 | let idx = self.int_in_range(0..=len - 1)?; 509 | Ok(idx) 510 | } 511 | 512 | /// Generate a boolean which is true with probability approximately the given ratio. 513 | /// 514 | /// Returns true, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 515 | /// 516 | /// # Panics 517 | /// 518 | /// Panics when the numerator and denominator do not meet these constraints: 519 | /// 520 | /// * `0 < numerator <= denominator` 521 | /// 522 | /// # Example 523 | /// 524 | /// Generate a boolean that is `true` five sevenths of the time: 525 | /// 526 | /// ``` 527 | /// # fn foo() -> arbitrary::Result<()> { 528 | /// use arbitrary::Unstructured; 529 | /// 530 | /// # let my_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; 531 | /// let mut u = Unstructured::new(&my_data); 532 | /// 533 | /// if u.ratio(5, 7)? { 534 | /// // Take this branch approximately 5/7 of the time. 535 | /// } 536 | /// # Ok(()) 537 | /// # } 538 | /// ``` 539 | pub fn ratio(&mut self, numerator: T, denominator: T) -> Result 540 | where 541 | T: Int, 542 | { 543 | assert!(T::ZERO < numerator); 544 | assert!(numerator <= denominator); 545 | let x = self.int_in_range(T::ONE..=denominator)?; 546 | Ok(x <= numerator) 547 | } 548 | 549 | /// Fill a `buffer` with bytes from the underlying raw data. 550 | /// 551 | /// This should only be called within an `Arbitrary` implementation. This is 552 | /// a very low-level operation. You should generally prefer calling nested 553 | /// `Arbitrary` implementations like `>::arbitrary` and 554 | /// `String::arbitrary` over using this method directly. 555 | /// 556 | /// If this `Unstructured` does not have enough underlying data to fill the 557 | /// whole `buffer`, it pads the buffer out with zeros. 558 | /// 559 | /// # Example 560 | /// 561 | /// ``` 562 | /// use arbitrary::Unstructured; 563 | /// 564 | /// let mut u = Unstructured::new(&[1, 2, 3, 4]); 565 | /// 566 | /// let mut buf = [0; 2]; 567 | /// 568 | /// assert!(u.fill_buffer(&mut buf).is_ok()); 569 | /// assert_eq!(buf, [1, 2]); 570 | /// 571 | /// assert!(u.fill_buffer(&mut buf).is_ok()); 572 | /// assert_eq!(buf, [3, 4]); 573 | /// 574 | /// assert!(u.fill_buffer(&mut buf).is_ok()); 575 | /// assert_eq!(buf, [0, 0]); 576 | /// ``` 577 | pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()> { 578 | let n = std::cmp::min(buffer.len(), self.data.len()); 579 | buffer[..n].copy_from_slice(&self.data[..n]); 580 | for byte in buffer[n..].iter_mut() { 581 | *byte = 0; 582 | } 583 | self.data = &self.data[n..]; 584 | Ok(()) 585 | } 586 | 587 | /// Provide `size` bytes from the underlying raw data. 588 | /// 589 | /// This should only be called within an `Arbitrary` implementation. This is 590 | /// a very low-level operation. You should generally prefer calling nested 591 | /// `Arbitrary` implementations like `>::arbitrary` and 592 | /// `String::arbitrary` over using this method directly. 593 | /// 594 | /// # Example 595 | /// 596 | /// ``` 597 | /// use arbitrary::Unstructured; 598 | /// 599 | /// let mut u = Unstructured::new(&[1, 2, 3, 4]); 600 | /// 601 | /// assert!(u.bytes(2).unwrap() == &[1, 2]); 602 | /// assert!(u.bytes(2).unwrap() == &[3, 4]); 603 | /// ``` 604 | pub fn bytes(&mut self, size: usize) -> Result<&'a [u8]> { 605 | if self.data.len() < size { 606 | return Err(Error::NotEnoughData); 607 | } 608 | 609 | let (for_buf, rest) = self.data.split_at(size); 610 | self.data = rest; 611 | Ok(for_buf) 612 | } 613 | 614 | /// Peek at `size` number of bytes of the underlying raw input. 615 | /// 616 | /// Does not consume the bytes, only peeks at them. 617 | /// 618 | /// Returns `None` if there are not `size` bytes left in the underlying raw 619 | /// input. 620 | /// 621 | /// # Example 622 | /// 623 | /// ``` 624 | /// use arbitrary::Unstructured; 625 | /// 626 | /// let u = Unstructured::new(&[1, 2, 3]); 627 | /// 628 | /// assert_eq!(u.peek_bytes(0).unwrap(), []); 629 | /// assert_eq!(u.peek_bytes(1).unwrap(), [1]); 630 | /// assert_eq!(u.peek_bytes(2).unwrap(), [1, 2]); 631 | /// assert_eq!(u.peek_bytes(3).unwrap(), [1, 2, 3]); 632 | /// 633 | /// assert!(u.peek_bytes(4).is_none()); 634 | /// ``` 635 | pub fn peek_bytes(&self, size: usize) -> Option<&'a [u8]> { 636 | self.data.get(..size) 637 | } 638 | 639 | /// Consume all of the rest of the remaining underlying bytes. 640 | /// 641 | /// Returns a slice of all the remaining, unconsumed bytes. 642 | /// 643 | /// # Example 644 | /// 645 | /// ``` 646 | /// use arbitrary::Unstructured; 647 | /// 648 | /// let mut u = Unstructured::new(&[1, 2, 3]); 649 | /// 650 | /// let mut remaining = u.take_rest(); 651 | /// 652 | /// assert_eq!(remaining, [1, 2, 3]); 653 | /// ``` 654 | pub fn take_rest(mut self) -> &'a [u8] { 655 | mem::take(&mut self.data) 656 | } 657 | 658 | /// Provide an iterator over elements for constructing a collection 659 | /// 660 | /// This is useful for implementing [`Arbitrary::arbitrary`] on collections 661 | /// since the implementation is simply `u.arbitrary_iter()?.collect()` 662 | pub fn arbitrary_iter<'b, ElementType: Arbitrary<'a>>( 663 | &'b mut self, 664 | ) -> Result> { 665 | Ok(ArbitraryIter { 666 | u: &mut *self, 667 | _marker: PhantomData, 668 | }) 669 | } 670 | 671 | /// Provide an iterator over elements for constructing a collection from 672 | /// all the remaining bytes. 673 | /// 674 | /// This is useful for implementing [`Arbitrary::arbitrary_take_rest`] on collections 675 | /// since the implementation is simply `u.arbitrary_take_rest_iter()?.collect()` 676 | pub fn arbitrary_take_rest_iter>( 677 | self, 678 | ) -> Result> { 679 | Ok(ArbitraryTakeRestIter { 680 | u: self, 681 | _marker: PhantomData, 682 | }) 683 | } 684 | 685 | /// Call the given function an arbitrary number of times. 686 | /// 687 | /// The function is given this `Unstructured` so that it can continue to 688 | /// generate arbitrary data and structures. 689 | /// 690 | /// You may optionaly specify minimum and maximum bounds on the number of 691 | /// times the function is called. 692 | /// 693 | /// You may break out of the loop early by returning 694 | /// `Ok(std::ops::ControlFlow::Break)`. To continue the loop, return 695 | /// `Ok(std::ops::ControlFlow::Continue)`. 696 | /// 697 | /// # Panics 698 | /// 699 | /// Panics if `min > max`. 700 | /// 701 | /// # Example 702 | /// 703 | /// Call a closure that generates an arbitrary type inside a context an 704 | /// arbitrary number of times: 705 | /// 706 | /// ``` 707 | /// use arbitrary::{Result, Unstructured}; 708 | /// use std::ops::ControlFlow; 709 | /// 710 | /// enum Type { 711 | /// /// A boolean type. 712 | /// Bool, 713 | /// 714 | /// /// An integer type. 715 | /// Int, 716 | /// 717 | /// /// A list of the `i`th type in this type's context. 718 | /// List(usize), 719 | /// } 720 | /// 721 | /// fn arbitrary_types_context(u: &mut Unstructured) -> Result> { 722 | /// let mut context = vec![]; 723 | /// 724 | /// u.arbitrary_loop(Some(10), Some(20), |u| { 725 | /// let num_choices = if context.is_empty() { 726 | /// 2 727 | /// } else { 728 | /// 3 729 | /// }; 730 | /// let ty = match u.int_in_range::(1..=num_choices)? { 731 | /// 1 => Type::Bool, 732 | /// 2 => Type::Int, 733 | /// 3 => Type::List(u.int_in_range(0..=context.len() - 1)?), 734 | /// _ => unreachable!(), 735 | /// }; 736 | /// context.push(ty); 737 | /// Ok(ControlFlow::Continue(())) 738 | /// })?; 739 | /// 740 | /// // The number of loop iterations are constrained by the min/max 741 | /// // bounds that we provided. 742 | /// assert!(context.len() >= 10); 743 | /// assert!(context.len() <= 20); 744 | /// 745 | /// Ok(context) 746 | /// } 747 | /// ``` 748 | pub fn arbitrary_loop( 749 | &mut self, 750 | min: Option, 751 | max: Option, 752 | mut f: impl FnMut(&mut Self) -> Result>, 753 | ) -> Result<()> { 754 | let min = min.unwrap_or(0); 755 | let max = max.unwrap_or(u32::MAX); 756 | 757 | for _ in 0..self.int_in_range(min..=max)? { 758 | match f(self)? { 759 | ControlFlow::Continue(_) => continue, 760 | ControlFlow::Break(_) => break, 761 | } 762 | } 763 | 764 | Ok(()) 765 | } 766 | } 767 | 768 | /// Utility iterator produced by [`Unstructured::arbitrary_iter`] 769 | pub struct ArbitraryIter<'a, 'b, ElementType> { 770 | u: &'b mut Unstructured<'a>, 771 | _marker: PhantomData, 772 | } 773 | 774 | impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryIter<'a, '_, ElementType> { 775 | type Item = Result; 776 | fn next(&mut self) -> Option> { 777 | let keep_going = self.u.arbitrary().unwrap_or(false); 778 | if keep_going { 779 | Some(Arbitrary::arbitrary(self.u)) 780 | } else { 781 | None 782 | } 783 | } 784 | } 785 | 786 | /// Utility iterator produced by [`Unstructured::arbitrary_take_rest_iter`] 787 | pub struct ArbitraryTakeRestIter<'a, ElementType> { 788 | u: Unstructured<'a>, 789 | _marker: PhantomData, 790 | } 791 | 792 | impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryTakeRestIter<'a, ElementType> { 793 | type Item = Result; 794 | fn next(&mut self) -> Option> { 795 | let keep_going = self.u.arbitrary().unwrap_or(false); 796 | if keep_going { 797 | Some(Arbitrary::arbitrary(&mut self.u)) 798 | } else { 799 | None 800 | } 801 | } 802 | } 803 | 804 | /// A trait that is implemented for all of the primitive integers: 805 | /// 806 | /// * `u8` 807 | /// * `u16` 808 | /// * `u32` 809 | /// * `u64` 810 | /// * `u128` 811 | /// * `usize` 812 | /// * `i8` 813 | /// * `i16` 814 | /// * `i32` 815 | /// * `i64` 816 | /// * `i128` 817 | /// * `isize` 818 | /// 819 | /// Don't implement this trait yourself. 820 | pub trait Int: 821 | Copy 822 | + std::fmt::Debug 823 | + PartialOrd 824 | + Ord 825 | + ops::Sub 826 | + ops::Rem 827 | + ops::Shr 828 | + ops::Shl 829 | + ops::BitOr 830 | { 831 | #[doc(hidden)] 832 | type Unsigned: Int; 833 | 834 | #[doc(hidden)] 835 | const ZERO: Self; 836 | 837 | #[doc(hidden)] 838 | const ONE: Self; 839 | 840 | #[doc(hidden)] 841 | const MAX: Self; 842 | 843 | #[doc(hidden)] 844 | fn from_u8(b: u8) -> Self; 845 | 846 | #[doc(hidden)] 847 | fn from_usize(u: usize) -> Self; 848 | 849 | #[doc(hidden)] 850 | fn checked_add(self, rhs: Self) -> Option; 851 | 852 | #[doc(hidden)] 853 | fn wrapping_add(self, rhs: Self) -> Self; 854 | 855 | #[doc(hidden)] 856 | fn wrapping_sub(self, rhs: Self) -> Self; 857 | 858 | #[doc(hidden)] 859 | fn to_unsigned(self) -> Self::Unsigned; 860 | 861 | #[doc(hidden)] 862 | fn from_unsigned(unsigned: Self::Unsigned) -> Self; 863 | } 864 | 865 | macro_rules! impl_int { 866 | ( $( $ty:ty : $unsigned_ty: ty ; )* ) => { 867 | $( 868 | impl Int for $ty { 869 | type Unsigned = $unsigned_ty; 870 | 871 | const ZERO: Self = 0; 872 | 873 | const ONE: Self = 1; 874 | 875 | const MAX: Self = Self::MAX; 876 | 877 | fn from_u8(b: u8) -> Self { 878 | b as Self 879 | } 880 | 881 | fn from_usize(u: usize) -> Self { 882 | u as Self 883 | } 884 | 885 | fn checked_add(self, rhs: Self) -> Option { 886 | <$ty>::checked_add(self, rhs) 887 | } 888 | 889 | fn wrapping_add(self, rhs: Self) -> Self { 890 | <$ty>::wrapping_add(self, rhs) 891 | } 892 | 893 | fn wrapping_sub(self, rhs: Self) -> Self { 894 | <$ty>::wrapping_sub(self, rhs) 895 | } 896 | 897 | fn to_unsigned(self) -> Self::Unsigned { 898 | self as $unsigned_ty 899 | } 900 | 901 | fn from_unsigned(unsigned: $unsigned_ty) -> Self { 902 | unsigned as Self 903 | } 904 | } 905 | )* 906 | } 907 | } 908 | 909 | impl_int! { 910 | u8: u8; 911 | u16: u16; 912 | u32: u32; 913 | u64: u64; 914 | u128: u128; 915 | usize: usize; 916 | i8: u8; 917 | i16: u16; 918 | i32: u32; 919 | i64: u64; 920 | i128: u128; 921 | isize: usize; 922 | } 923 | 924 | #[cfg(test)] 925 | mod tests { 926 | use super::*; 927 | 928 | #[test] 929 | fn test_byte_size() { 930 | let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]); 931 | // Should take one byte off the end 932 | assert_eq!(u.arbitrary_byte_size().unwrap(), 6); 933 | assert_eq!(u.len(), 9); 934 | let mut v = vec![0; 260]; 935 | v.push(1); 936 | v.push(4); 937 | let mut u = Unstructured::new(&v); 938 | // Should read two bytes off the end 939 | assert_eq!(u.arbitrary_byte_size().unwrap(), 0x104); 940 | assert_eq!(u.len(), 260); 941 | } 942 | 943 | #[test] 944 | fn int_in_range_of_one() { 945 | let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]); 946 | let x = u.int_in_range(0..=0).unwrap(); 947 | assert_eq!(x, 0); 948 | let choice = *u.choose(&[42]).unwrap(); 949 | assert_eq!(choice, 42) 950 | } 951 | 952 | #[test] 953 | fn int_in_range_uses_minimal_amount_of_bytes() { 954 | let mut u = Unstructured::new(&[1, 2]); 955 | assert_eq!(1, u.int_in_range::(0..=u8::MAX).unwrap()); 956 | assert_eq!(u.len(), 1); 957 | 958 | let mut u = Unstructured::new(&[1, 2]); 959 | assert_eq!(1, u.int_in_range::(0..=u8::MAX as u32).unwrap()); 960 | assert_eq!(u.len(), 1); 961 | 962 | let mut u = Unstructured::new(&[1]); 963 | assert_eq!(1, u.int_in_range::(0..=u8::MAX as u32 + 1).unwrap()); 964 | assert!(u.is_empty()); 965 | } 966 | 967 | #[test] 968 | fn int_in_range_in_bounds() { 969 | for input in u8::MIN..=u8::MAX { 970 | let input = [input]; 971 | 972 | let mut u = Unstructured::new(&input); 973 | let x = u.int_in_range(1..=u8::MAX).unwrap(); 974 | assert_ne!(x, 0); 975 | 976 | let mut u = Unstructured::new(&input); 977 | let x = u.int_in_range(0..=u8::MAX - 1).unwrap(); 978 | assert_ne!(x, u8::MAX); 979 | } 980 | } 981 | 982 | #[test] 983 | fn int_in_range_covers_unsigned_range() { 984 | // Test that we generate all values within the range given to 985 | // `int_in_range`. 986 | 987 | let mut full = [false; u8::MAX as usize + 1]; 988 | let mut no_zero = [false; u8::MAX as usize]; 989 | let mut no_max = [false; u8::MAX as usize]; 990 | let mut narrow = [false; 10]; 991 | 992 | for input in u8::MIN..=u8::MAX { 993 | let input = [input]; 994 | 995 | let mut u = Unstructured::new(&input); 996 | let x = u.int_in_range(0..=u8::MAX).unwrap(); 997 | full[x as usize] = true; 998 | 999 | let mut u = Unstructured::new(&input); 1000 | let x = u.int_in_range(1..=u8::MAX).unwrap(); 1001 | no_zero[x as usize - 1] = true; 1002 | 1003 | let mut u = Unstructured::new(&input); 1004 | let x = u.int_in_range(0..=u8::MAX - 1).unwrap(); 1005 | no_max[x as usize] = true; 1006 | 1007 | let mut u = Unstructured::new(&input); 1008 | let x = u.int_in_range(100..=109).unwrap(); 1009 | narrow[x as usize - 100] = true; 1010 | } 1011 | 1012 | for (i, covered) in full.iter().enumerate() { 1013 | assert!(covered, "full[{}] should have been generated", i); 1014 | } 1015 | for (i, covered) in no_zero.iter().enumerate() { 1016 | assert!(covered, "no_zero[{}] should have been generated", i); 1017 | } 1018 | for (i, covered) in no_max.iter().enumerate() { 1019 | assert!(covered, "no_max[{}] should have been generated", i); 1020 | } 1021 | for (i, covered) in narrow.iter().enumerate() { 1022 | assert!(covered, "narrow[{}] should have been generated", i); 1023 | } 1024 | } 1025 | 1026 | #[test] 1027 | fn int_in_range_covers_signed_range() { 1028 | // Test that we generate all values within the range given to 1029 | // `int_in_range`. 1030 | 1031 | let mut full = [false; u8::MAX as usize + 1]; 1032 | let mut no_min = [false; u8::MAX as usize]; 1033 | let mut no_max = [false; u8::MAX as usize]; 1034 | let mut narrow = [false; 21]; 1035 | 1036 | let abs_i8_min: isize = 128; 1037 | 1038 | for input in 0..=u8::MAX { 1039 | let input = [input]; 1040 | 1041 | let mut u = Unstructured::new(&input); 1042 | let x = u.int_in_range(i8::MIN..=i8::MAX).unwrap(); 1043 | full[(x as isize + abs_i8_min) as usize] = true; 1044 | 1045 | let mut u = Unstructured::new(&input); 1046 | let x = u.int_in_range(i8::MIN + 1..=i8::MAX).unwrap(); 1047 | no_min[(x as isize + abs_i8_min - 1) as usize] = true; 1048 | 1049 | let mut u = Unstructured::new(&input); 1050 | let x = u.int_in_range(i8::MIN..=i8::MAX - 1).unwrap(); 1051 | no_max[(x as isize + abs_i8_min) as usize] = true; 1052 | 1053 | let mut u = Unstructured::new(&input); 1054 | let x = u.int_in_range(-10..=10).unwrap(); 1055 | narrow[(x as isize + 10) as usize] = true; 1056 | } 1057 | 1058 | for (i, covered) in full.iter().enumerate() { 1059 | assert!(covered, "full[{}] should have been generated", i); 1060 | } 1061 | for (i, covered) in no_min.iter().enumerate() { 1062 | assert!(covered, "no_min[{}] should have been generated", i); 1063 | } 1064 | for (i, covered) in no_max.iter().enumerate() { 1065 | assert!(covered, "no_max[{}] should have been generated", i); 1066 | } 1067 | for (i, covered) in narrow.iter().enumerate() { 1068 | assert!(covered, "narrow[{}] should have been generated", i); 1069 | } 1070 | } 1071 | } 1072 | -------------------------------------------------------------------------------- /tests/bound.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "derive")] 2 | 3 | use arbitrary::{Arbitrary, Unstructured}; 4 | 5 | fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T { 6 | let mut buf = Unstructured::new(input); 7 | T::arbitrary(&mut buf).expect("can create arbitrary instance OK") 8 | } 9 | 10 | /// This wrapper trait *implies* `Arbitrary`, but the compiler isn't smart enough to work that out 11 | /// so when using this wrapper we *must* opt-out of the auto-generated `T: Arbitrary` bounds. 12 | pub trait WrapperTrait: for<'a> Arbitrary<'a> {} 13 | 14 | impl WrapperTrait for u32 {} 15 | 16 | #[derive(Arbitrary)] 17 | #[arbitrary(bound = "T: WrapperTrait")] 18 | struct GenericSingleBound { 19 | t: T, 20 | } 21 | 22 | #[test] 23 | fn single_bound() { 24 | let v: GenericSingleBound = arbitrary_from(&[0, 0, 0, 0]); 25 | assert_eq!(v.t, 0); 26 | } 27 | 28 | #[derive(Arbitrary)] 29 | #[arbitrary(bound = "T: WrapperTrait, U: WrapperTrait")] 30 | struct GenericMultipleBoundsSingleAttribute { 31 | t: T, 32 | u: U, 33 | } 34 | 35 | #[test] 36 | fn multiple_bounds_single_attribute() { 37 | let v: GenericMultipleBoundsSingleAttribute = 38 | arbitrary_from(&[1, 0, 0, 0, 2, 0, 0, 0]); 39 | assert_eq!(v.t, 1); 40 | assert_eq!(v.u, 2); 41 | } 42 | 43 | #[derive(Arbitrary)] 44 | #[arbitrary(bound = "T: WrapperTrait")] 45 | #[arbitrary(bound = "U: Default")] 46 | struct GenericMultipleArbitraryAttributes { 47 | t: T, 48 | #[arbitrary(default)] 49 | u: U, 50 | } 51 | 52 | #[test] 53 | fn multiple_arbitrary_attributes() { 54 | let v: GenericMultipleArbitraryAttributes = arbitrary_from(&[1, 0, 0, 0]); 55 | assert_eq!(v.t, 1); 56 | assert_eq!(v.u, 0); 57 | } 58 | 59 | #[derive(Arbitrary)] 60 | #[arbitrary(bound = "T: WrapperTrait", bound = "U: Default")] 61 | struct GenericMultipleBoundAttributes { 62 | t: T, 63 | #[arbitrary(default)] 64 | u: U, 65 | } 66 | 67 | #[test] 68 | fn multiple_bound_attributes() { 69 | let v: GenericMultipleBoundAttributes = arbitrary_from(&[1, 0, 0, 0]); 70 | assert_eq!(v.t, 1); 71 | assert_eq!(v.u, 0); 72 | } 73 | 74 | #[derive(Arbitrary)] 75 | #[arbitrary(bound = "T: WrapperTrait", bound = "U: Default")] 76 | #[arbitrary(bound = "V: WrapperTrait, W: Default")] 77 | struct GenericMultipleArbitraryAndBoundAttributes< 78 | T: WrapperTrait, 79 | U: Default, 80 | V: WrapperTrait, 81 | W: Default, 82 | > { 83 | t: T, 84 | #[arbitrary(default)] 85 | u: U, 86 | v: V, 87 | #[arbitrary(default)] 88 | w: W, 89 | } 90 | 91 | #[test] 92 | fn multiple_arbitrary_and_bound_attributes() { 93 | let v: GenericMultipleArbitraryAndBoundAttributes = 94 | arbitrary_from(&[1, 0, 0, 0, 2, 0, 0, 0]); 95 | assert_eq!(v.t, 1); 96 | assert_eq!(v.u, 0); 97 | assert_eq!(v.v, 2); 98 | assert_eq!(v.w, 0); 99 | } 100 | 101 | #[derive(Arbitrary)] 102 | #[arbitrary(bound = "T: Default")] 103 | struct GenericDefault { 104 | #[arbitrary(default)] 105 | x: T, 106 | } 107 | 108 | #[test] 109 | fn default_bound() { 110 | // We can write a generic func without any `Arbitrary` bound. 111 | fn generic_default() -> GenericDefault { 112 | arbitrary_from(&[]) 113 | } 114 | 115 | assert_eq!(generic_default::().x, 0); 116 | assert_eq!(generic_default::().x, String::new()); 117 | assert_eq!(generic_default::>().x, Vec::new()); 118 | } 119 | 120 | #[derive(Arbitrary)] 121 | #[arbitrary()] 122 | struct EmptyArbitraryAttribute { 123 | t: u32, 124 | } 125 | 126 | #[test] 127 | fn empty_arbitrary_attribute() { 128 | let v: EmptyArbitraryAttribute = arbitrary_from(&[1, 0, 0, 0]); 129 | assert_eq!(v.t, 1); 130 | } 131 | 132 | #[derive(Arbitrary)] 133 | #[arbitrary(bound = "")] 134 | struct EmptyBoundAttribute { 135 | t: u32, 136 | } 137 | 138 | #[test] 139 | fn empty_bound_attribute() { 140 | let v: EmptyBoundAttribute = arbitrary_from(&[1, 0, 0, 0]); 141 | assert_eq!(v.t, 1); 142 | } 143 | -------------------------------------------------------------------------------- /tests/derive.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "derive")] 2 | // Various structs/fields that we are deriving `Arbitrary` for aren't actually 3 | // used except to exercise the derive. 4 | #![allow(dead_code)] 5 | // Various assert_eq! are used to compare result of bool amongst other data types 6 | // In this case, using assert! is less explicit and readable 7 | #![allow(clippy::bool_assert_comparison)] 8 | 9 | use arbitrary::*; 10 | 11 | fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T { 12 | let mut buf = Unstructured::new(input); 13 | T::arbitrary(&mut buf).expect("can create arbitrary instance OK") 14 | } 15 | 16 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Arbitrary)] 17 | pub struct Rgb { 18 | pub r: u8, 19 | pub g: u8, 20 | pub b: u8, 21 | } 22 | 23 | #[test] 24 | fn struct_with_named_fields() { 25 | let rgb: Rgb = arbitrary_from(&[4, 5, 6]); 26 | assert_eq!(rgb.r, 4); 27 | assert_eq!(rgb.g, 5); 28 | assert_eq!(rgb.b, 6); 29 | 30 | assert_eq!((3, Some(3)), ::size_hint(0)); 31 | } 32 | 33 | #[derive(Copy, Clone, Debug, Arbitrary)] 34 | struct MyTupleStruct(u8, bool); 35 | 36 | #[test] 37 | fn tuple_struct() { 38 | let s: MyTupleStruct = arbitrary_from(&[43, 42]); 39 | assert_eq!(s.0, 43); 40 | assert_eq!(s.1, false); 41 | 42 | let s: MyTupleStruct = arbitrary_from(&[42, 43]); 43 | assert_eq!(s.0, 42); 44 | assert_eq!(s.1, true); 45 | 46 | assert_eq!((2, Some(2)), ::size_hint(0)); 47 | } 48 | 49 | #[derive(Clone, Debug, Arbitrary)] 50 | struct EndingInVec(u8, bool, u32, Vec); 51 | #[derive(Clone, Debug, Arbitrary)] 52 | struct EndingInString(u8, bool, u32, String); 53 | 54 | #[test] 55 | fn test_take_rest() { 56 | let bytes = [1, 1, 1, 2, 3, 4, 5, 6, 7, 8]; 57 | let s1 = EndingInVec::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap(); 58 | let s2 = EndingInString::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap(); 59 | assert_eq!(s1.0, 1); 60 | assert_eq!(s2.0, 1); 61 | assert_eq!(s1.1, true); 62 | assert_eq!(s2.1, true); 63 | assert_eq!(s1.2, 0x4030201); 64 | assert_eq!(s2.2, 0x4030201); 65 | assert_eq!(s1.3, vec![0x0706]); 66 | assert_eq!(s2.3, "\x05\x06\x07\x08"); 67 | } 68 | 69 | #[derive(Copy, Clone, Debug, Arbitrary)] 70 | enum MyEnum { 71 | Unit, 72 | Tuple(u8, u16), 73 | Struct { a: u32, b: (bool, u64) }, 74 | } 75 | 76 | #[test] 77 | fn derive_enum() { 78 | let mut raw = vec![ 79 | // The choice of which enum variant takes 4 bytes. 80 | 1, 2, 3, 4, 81 | // And then we need up to 13 bytes for creating `MyEnum::Struct`, the 82 | // largest variant. 83 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 84 | ]; 85 | 86 | let mut saw_unit = false; 87 | let mut saw_tuple = false; 88 | let mut saw_struct = false; 89 | 90 | for i in 0..=255 { 91 | // Choose different variants each iteration. 92 | for el in &mut raw[..4] { 93 | *el = i; 94 | } 95 | 96 | let e: MyEnum = arbitrary_from(&raw); 97 | 98 | match e { 99 | MyEnum::Unit => { 100 | saw_unit = true; 101 | } 102 | MyEnum::Tuple(a, b) => { 103 | saw_tuple = true; 104 | assert_eq!(a, arbitrary_from(&raw[4..5])); 105 | assert_eq!(b, arbitrary_from(&raw[5..])); 106 | } 107 | MyEnum::Struct { a, b } => { 108 | saw_struct = true; 109 | assert_eq!(a, arbitrary_from(&raw[4..8])); 110 | assert_eq!(b, arbitrary_from(&raw[8..])); 111 | } 112 | } 113 | } 114 | 115 | assert!(saw_unit); 116 | assert!(saw_tuple); 117 | assert!(saw_struct); 118 | 119 | assert_eq!((4, Some(17)), ::size_hint(0)); 120 | } 121 | 122 | // This should result in a compiler-error: 123 | // #[derive(Arbitrary, Debug)] 124 | // enum Never { 125 | // #[arbitrary(skip)] 126 | // Nope, 127 | // } 128 | 129 | #[derive(Arbitrary, Debug)] 130 | enum SkipVariant { 131 | Always, 132 | #[arbitrary(skip)] 133 | Never, 134 | } 135 | 136 | #[test] 137 | fn test_skip_variant() { 138 | (0..=u8::MAX).for_each(|byte| { 139 | let buffer = [byte]; 140 | let unstructured = Unstructured::new(&buffer); 141 | let skip_variant = SkipVariant::arbitrary_take_rest(unstructured).unwrap(); 142 | assert!(!matches!(skip_variant, SkipVariant::Never)); 143 | }) 144 | } 145 | 146 | #[derive(Arbitrary, Debug)] 147 | enum RecursiveTree { 148 | Leaf, 149 | Node { 150 | left: Box, 151 | right: Box, 152 | }, 153 | } 154 | 155 | #[derive(Arbitrary, Debug)] 156 | struct WideRecursiveStruct { 157 | a: Option>, 158 | b: Option>, 159 | c: Option>, 160 | d: Option>, 161 | e: Option>, 162 | f: Option>, 163 | g: Option>, 164 | h: Option>, 165 | i: Option>, 166 | k: Option>, 167 | } 168 | 169 | #[derive(Arbitrary, Debug)] 170 | enum WideRecursiveEnum { 171 | None, 172 | A(Box), 173 | B(Box), 174 | C(Box), 175 | D(Box), 176 | E(Box), 177 | F(Box), 178 | G(Box), 179 | H(Box), 180 | I(Box), 181 | K(Box), 182 | } 183 | 184 | #[derive(Arbitrary, Debug)] 185 | enum WideRecursiveMixedEnum { 186 | None, 187 | A(Box), 188 | B(Box), 189 | C(Box), 190 | D(Box), 191 | E(Box), 192 | F(Box), 193 | G(Box), 194 | H(Box), 195 | I(Box), 196 | K(Box), 197 | } 198 | 199 | #[derive(Arbitrary, Debug)] 200 | struct WideRecursiveMixedStruct { 201 | a: Option>, 202 | b: Option>, 203 | c: Option>, 204 | d: Option>, 205 | e: Option>, 206 | f: Option>, 207 | g: Option>, 208 | h: Option>, 209 | i: Option>, 210 | k: Option>, 211 | } 212 | 213 | #[test] 214 | fn recursive() { 215 | let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; 216 | let _rec: RecursiveTree = arbitrary_from(&raw); 217 | let _rec: WideRecursiveStruct = arbitrary_from(&raw); 218 | let _rec: WideRecursiveEnum = arbitrary_from(&raw); 219 | let _rec: WideRecursiveMixedStruct = arbitrary_from(&raw); 220 | let _rec: WideRecursiveMixedEnum = arbitrary_from(&raw); 221 | 222 | assert_eq!((0, None), ::size_hint(0)); 223 | assert_eq!((0, None), ::size_hint(0)); 224 | assert_eq!( 225 | (0, None), 226 | ::size_hint(0) 227 | ); 228 | assert_eq!( 229 | (0, None), 230 | ::size_hint(0) 231 | ); 232 | 233 | let (lower, upper) = ::size_hint(0); 234 | assert_eq!(lower, 0, "Cannot compute size hint of recursive structure"); 235 | assert!( 236 | upper.is_none(), 237 | "potentially infinitely recursive, so no upper bound" 238 | ); 239 | } 240 | 241 | #[derive(Arbitrary, Debug)] 242 | struct Generic { 243 | inner: T, 244 | } 245 | 246 | #[test] 247 | fn generics() { 248 | let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; 249 | let gen: Generic = arbitrary_from(&raw); 250 | assert!(gen.inner); 251 | 252 | let (lower, upper) = as Arbitrary>::size_hint(0); 253 | assert_eq!(lower, 4); 254 | assert_eq!(upper, Some(4)); 255 | } 256 | 257 | #[derive(Arbitrary, Debug)] 258 | struct OneLifetime<'a> { 259 | alpha: &'a str, 260 | } 261 | 262 | #[test] 263 | fn one_lifetime() { 264 | // Last byte is used for length 265 | let raw: Vec = vec![97, 98, 99, 100, 3]; 266 | let lifetime: OneLifetime = arbitrary_from(&raw); 267 | assert_eq!("abc", lifetime.alpha); 268 | 269 | let (lower, upper) = ::size_hint(0); 270 | assert_eq!(lower, 0); 271 | assert_eq!(upper, None); 272 | } 273 | 274 | #[derive(Arbitrary, Debug)] 275 | struct TwoLifetimes<'a, 'b> { 276 | alpha: &'a str, 277 | beta: &'b str, 278 | } 279 | 280 | #[test] 281 | fn two_lifetimes() { 282 | // Last byte is used for length 283 | let raw: Vec = vec![97, 98, 99, 100, 101, 102, 103, 3]; 284 | let lifetime: TwoLifetimes = arbitrary_from(&raw); 285 | assert_eq!("abc", lifetime.alpha); 286 | assert_eq!("def", lifetime.beta); 287 | 288 | let (lower, upper) = ::size_hint(0); 289 | assert_eq!(lower, 0); 290 | assert_eq!(upper, None); 291 | } 292 | 293 | #[test] 294 | fn recursive_and_empty_input() { 295 | // None of the following derives should result in a stack overflow. See 296 | // https://github.com/rust-fuzz/arbitrary/issues/107 for details. 297 | 298 | #[derive(Debug, Arbitrary)] 299 | enum Nat { 300 | Succ(Box), 301 | Zero, 302 | } 303 | 304 | let _ = Nat::arbitrary(&mut Unstructured::new(&[])); 305 | 306 | #[derive(Debug, Arbitrary)] 307 | enum Nat2 { 308 | Zero, 309 | Succ(Box), 310 | } 311 | 312 | let _ = Nat2::arbitrary(&mut Unstructured::new(&[])); 313 | 314 | #[derive(Debug, Arbitrary)] 315 | struct Nat3 { 316 | f: Option>, 317 | } 318 | 319 | let _ = Nat3::arbitrary(&mut Unstructured::new(&[])); 320 | 321 | #[derive(Debug, Arbitrary)] 322 | struct Nat4(Option>); 323 | 324 | let _ = Nat4::arbitrary(&mut Unstructured::new(&[])); 325 | 326 | #[derive(Debug, Arbitrary)] 327 | enum Nat5 { 328 | Zero, 329 | Succ { f: Box }, 330 | } 331 | 332 | let _ = Nat5::arbitrary(&mut Unstructured::new(&[])); 333 | } 334 | 335 | #[test] 336 | fn test_field_attributes() { 337 | // A type that DOES NOT implement Arbitrary 338 | #[derive(Debug)] 339 | struct Weight(u8); 340 | 341 | #[derive(Debug, Arbitrary)] 342 | struct Parcel { 343 | #[arbitrary(with = arbitrary_weight)] 344 | weight: Weight, 345 | 346 | #[arbitrary(default)] 347 | width: u8, 348 | 349 | #[arbitrary(value = 2 + 2)] 350 | length: u8, 351 | 352 | height: u8, 353 | 354 | #[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=100))] 355 | price: u8, 356 | } 357 | 358 | fn arbitrary_weight(u: &mut Unstructured) -> arbitrary::Result { 359 | u.int_in_range(45..=56).map(Weight) 360 | } 361 | 362 | let parcel: Parcel = arbitrary_from(&[6, 199, 17]); 363 | 364 | // 45 + 6 = 51 365 | assert_eq!(parcel.weight.0, 51); 366 | 367 | // u8::default() 368 | assert_eq!(parcel.width, 0); 369 | 370 | // 2 + 2 = 4 371 | assert_eq!(parcel.length, 4); 372 | 373 | // 199 is the 2nd byte used by arbitrary 374 | assert_eq!(parcel.height, 199); 375 | 376 | // 17 is the 3rd byte used by arbitrary 377 | assert_eq!(parcel.price, 17); 378 | } 379 | 380 | #[test] 381 | fn derive_structs_named_same_as_core() { 382 | #[derive(Debug, Arbitrary)] 383 | struct Option { 384 | f: core::option::Option, 385 | } 386 | 387 | let _ = Option::arbitrary(&mut Unstructured::new(&[])); 388 | 389 | #[derive(Debug, Default, Arbitrary)] 390 | struct Default { 391 | f: u32, 392 | } 393 | 394 | let _ = Default::arbitrary(&mut Unstructured::new(&[])); 395 | 396 | #[derive(Debug, Arbitrary)] 397 | struct Result { 398 | f: core::result::Result, 399 | } 400 | 401 | let _ = Result::arbitrary(&mut Unstructured::new(&[])); 402 | } 403 | -------------------------------------------------------------------------------- /tests/path.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "derive")] 2 | // Various structs/fields that we are deriving `Arbitrary` for aren't actually 3 | // used except to show off the derive. 4 | #![allow(dead_code)] 5 | 6 | // Regression test for ensuring the derives work without Arbitrary being imported 7 | 8 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 9 | pub struct Struct { 10 | x: u8, 11 | y: u8, 12 | } 13 | 14 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 15 | pub struct Tuple(u8); 16 | 17 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 18 | pub struct Unit(u8); 19 | 20 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 21 | pub enum Enum { 22 | X(u8), 23 | Y(u8), 24 | } 25 | 26 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 27 | struct EndingInVec(u8, bool, u32, Vec); 28 | 29 | #[derive(arbitrary::Arbitrary, Debug)] 30 | struct Generic { 31 | inner: T, 32 | } 33 | --------------------------------------------------------------------------------