From a90a5cba08fdf6c0ceb95101c275108a152a3aed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:35:37 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- third_party/rust/ahash/.cargo-checksum.json | 2 +- third_party/rust/ahash/Cargo.toml | 74 +- third_party/rust/ahash/LICENSE-MIT | 2 +- third_party/rust/ahash/README.md | 19 +- third_party/rust/ahash/build.rs | 31 +- third_party/rust/ahash/src/aes_hash.rs | 65 +- third_party/rust/ahash/src/convert.rs | 11 +- third_party/rust/ahash/src/fallback_hash.rs | 51 +- third_party/rust/ahash/src/hash_map.rs | 150 +- third_party/rust/ahash/src/hash_quality_test.rs | 95 +- third_party/rust/ahash/src/hash_set.rs | 65 +- third_party/rust/ahash/src/lib.rs | 243 +- third_party/rust/ahash/src/operations.rs | 98 +- third_party/rust/ahash/src/random_state.rs | 511 +- third_party/rust/ahash/src/specialize.rs | 23 +- third_party/rust/ahash/tests/bench.rs | 205 +- third_party/rust/ahash/tests/map_tests.rs | 115 +- third_party/rust/ahash/tests/nopanic.rs | 35 +- .../rust/any_all_workaround/.cargo-checksum.json | 1 + third_party/rust/any_all_workaround/Cargo.toml | 28 + third_party/rust/any_all_workaround/LICENSE-APACHE | 201 + third_party/rust/any_all_workaround/LICENSE-MIT | 25 + .../rust/any_all_workaround/LICENSE-MIT-QCMS | 21 + third_party/rust/any_all_workaround/README.md | 13 + third_party/rust/any_all_workaround/build.rs | 7 + third_party/rust/any_all_workaround/src/lib.rs | 110 + third_party/rust/audio-mixer/.cargo-checksum.json | 2 +- third_party/rust/audio-mixer/Cargo.lock | 207 +- third_party/rust/audio-mixer/Cargo.toml | 2 +- third_party/rust/audio-mixer/src/channel.rs | 4 +- third_party/rust/audio-mixer/src/coefficient.rs | 239 +- third_party/rust/bindgen/clang.rs | 2 +- third_party/rust/bitflags/.cargo-checksum.json | 2 +- third_party/rust/bitflags/CHANGELOG.md | 26 + third_party/rust/bitflags/Cargo.lock | 165 +- third_party/rust/bitflags/Cargo.toml | 6 +- third_party/rust/bitflags/README.md | 2 +- third_party/rust/bitflags/src/external.rs | 24 +- third_party/rust/bitflags/src/internal.rs | 10 +- third_party/rust/bitflags/src/lib.rs | 46 +- third_party/rust/bitflags/src/parser.rs | 85 + third_party/rust/bitflags/src/public.rs | 42 +- third_party/rust/bitflags/src/tests/all.rs | 23 + third_party/rust/bitflags/src/tests/bits.rs | 36 + third_party/rust/bitflags/src/tests/complement.rs | 53 + third_party/rust/bitflags/src/tests/contains.rs | 108 + third_party/rust/bitflags/src/tests/difference.rs | 92 + third_party/rust/bitflags/src/tests/empty.rs | 23 + third_party/rust/bitflags/src/tests/eq.rs | 10 + third_party/rust/bitflags/src/tests/extend.rs | 42 + third_party/rust/bitflags/src/tests/flags.rs | 46 + third_party/rust/bitflags/src/tests/fmt.rs | 97 + third_party/rust/bitflags/src/tests/from_bits.rs | 45 + .../rust/bitflags/src/tests/from_bits_retain.rs | 38 + .../rust/bitflags/src/tests/from_bits_truncate.rs | 42 + third_party/rust/bitflags/src/tests/from_name.rs | 42 + third_party/rust/bitflags/src/tests/insert.rs | 91 + .../rust/bitflags/src/tests/intersection.rs | 79 + third_party/rust/bitflags/src/tests/intersects.rs | 91 + third_party/rust/bitflags/src/tests/is_all.rs | 32 + third_party/rust/bitflags/src/tests/is_empty.rs | 31 + third_party/rust/bitflags/src/tests/iter.rs | 209 + third_party/rust/bitflags/src/tests/parser.rs | 332 + third_party/rust/bitflags/src/tests/remove.rs | 100 + .../bitflags/src/tests/symmetric_difference.rs | 110 + third_party/rust/bitflags/src/tests/union.rs | 71 + third_party/rust/bitflags/src/traits.rs | 1 + third_party/rust/byteorder/.cargo-checksum.json | 2 +- third_party/rust/byteorder/CHANGELOG.md | 4 + third_party/rust/byteorder/Cargo.toml | 31 +- third_party/rust/byteorder/README.md | 16 +- third_party/rust/byteorder/benches/bench.rs | 2 + third_party/rust/byteorder/src/lib.rs | 231 +- .../rust/core-foundation-sys/.cargo-checksum.json | 2 +- third_party/rust/core-foundation-sys/Cargo.toml | 19 +- third_party/rust/core-foundation-sys/build.rs | 14 - third_party/rust/core-foundation-sys/src/array.rs | 119 +- .../core-foundation-sys/src/attributed_string.rs | 99 +- third_party/rust/core-foundation-sys/src/bag.rs | 101 + third_party/rust/core-foundation-sys/src/base.rs | 88 +- .../rust/core-foundation-sys/src/binary_heap.rs | 83 + .../rust/core-foundation-sys/src/bit_vector.rs | 74 + third_party/rust/core-foundation-sys/src/bundle.rs | 215 +- .../rust/core-foundation-sys/src/calendar.rs | 128 + .../rust/core-foundation-sys/src/characterset.rs | 102 +- third_party/rust/core-foundation-sys/src/data.rs | 59 +- third_party/rust/core-foundation-sys/src/date.rs | 10 +- .../rust/core-foundation-sys/src/date_formatter.rs | 147 + .../rust/core-foundation-sys/src/dictionary.rs | 124 +- third_party/rust/core-foundation-sys/src/error.rs | 38 +- .../rust/core-foundation-sys/src/file_security.rs | 71 + .../rust/core-foundation-sys/src/filedescriptor.rs | 56 +- third_party/rust/core-foundation-sys/src/lib.rs | 48 +- third_party/rust/core-foundation-sys/src/locale.rs | 146 + .../rust/core-foundation-sys/src/mach_port.rs | 63 +- .../rust/core-foundation-sys/src/messageport.rs | 123 +- .../core-foundation-sys/src/notification_center.rs | 89 + third_party/rust/core-foundation-sys/src/number.rs | 74 +- .../core-foundation-sys/src/number_formatter.rs | 163 + third_party/rust/core-foundation-sys/src/plugin.rs | 99 + .../rust/core-foundation-sys/src/preferences.rs | 103 + .../rust/core-foundation-sys/src/propertylist.rs | 102 +- .../rust/core-foundation-sys/src/runloop.rs | 220 +- third_party/rust/core-foundation-sys/src/set.rs | 64 +- third_party/rust/core-foundation-sys/src/socket.rs | 188 + third_party/rust/core-foundation-sys/src/stream.rs | 281 + third_party/rust/core-foundation-sys/src/string.rs | 757 +- .../core-foundation-sys/src/string_tokenizer.rs | 91 + .../rust/core-foundation-sys/src/timezone.rs | 76 +- third_party/rust/core-foundation-sys/src/tree.rs | 74 + third_party/rust/core-foundation-sys/src/url.rs | 468 +- .../rust/core-foundation-sys/src/url_enumerator.rs | 62 + .../core-foundation-sys/src/user_notification.rs | 138 + third_party/rust/core-foundation-sys/src/uuid.rs | 74 +- .../rust/core-foundation-sys/src/xml_node.rs | 147 + .../rust/core-foundation-sys/src/xml_parser.rs | 174 + .../rust/core-foundation/.cargo-checksum.json | 2 +- third_party/rust/core-foundation/Cargo.toml | 19 +- third_party/rust/core-foundation/src/array.rs | 97 +- .../rust/core-foundation/src/attributed_string.rs | 51 +- third_party/rust/core-foundation/src/base.rs | 84 +- third_party/rust/core-foundation/src/boolean.rs | 17 +- third_party/rust/core-foundation/src/bundle.rs | 65 +- .../rust/core-foundation/src/characterset.rs | 4 +- third_party/rust/core-foundation/src/data.rs | 53 +- third_party/rust/core-foundation/src/date.rs | 25 +- third_party/rust/core-foundation/src/dictionary.rs | 204 +- third_party/rust/core-foundation/src/error.rs | 15 +- .../rust/core-foundation/src/filedescriptor.rs | 90 +- third_party/rust/core-foundation/src/lib.rs | 24 +- third_party/rust/core-foundation/src/mach_port.rs | 13 +- third_party/rust/core-foundation/src/number.rs | 54 +- .../rust/core-foundation/src/propertylist.rs | 109 +- third_party/rust/core-foundation/src/runloop.rs | 128 +- third_party/rust/core-foundation/src/set.rs | 32 +- third_party/rust/core-foundation/src/string.rs | 100 +- third_party/rust/core-foundation/src/timezone.rs | 25 +- third_party/rust/core-foundation/src/url.rs | 75 +- third_party/rust/core-foundation/src/uuid.rs | 32 +- .../rust/core-graphics-types/.cargo-checksum.json | 2 +- third_party/rust/core-graphics-types/Cargo.toml | 10 +- .../rust/core-graphics-types/LICENSE-APACHE | 201 + third_party/rust/core-graphics-types/LICENSE-MIT | 25 + third_party/rust/core-graphics-types/src/base.rs | 4 +- .../rust/core-graphics-types/src/geometry.rs | 67 +- third_party/rust/core-graphics-types/src/lib.rs | 2 +- .../rust/cssparser-macros/.cargo-checksum.json | 2 +- third_party/rust/cssparser-macros/Cargo.toml | 4 +- third_party/rust/cssparser/.cargo-checksum.json | 2 +- .../rust/cssparser/.github/workflows/main.yml | 78 - third_party/rust/cssparser/Cargo.toml | 41 +- third_party/rust/cssparser/README.md | 4 +- third_party/rust/cssparser/docs/.nojekyll | 0 third_party/rust/cssparser/src/color.rs | 63 +- third_party/rust/cssparser/src/cow_rc_str.rs | 6 +- third_party/rust/cssparser/src/macros.rs | 4 +- third_party/rust/cssparser/src/nth.rs | 18 +- third_party/rust/cssparser/src/parser.rs | 56 +- .../rust/cssparser/src/rules_and_declarations.rs | 87 +- third_party/rust/cssparser/src/serializer.rs | 36 +- third_party/rust/cssparser/src/tests.rs | 74 +- third_party/rust/cssparser/src/tokenizer.rs | 86 +- third_party/rust/cssparser/src/unicode_range.rs | 20 +- .../rust/cubeb-coreaudio/.cargo-checksum.json | 2 +- third_party/rust/cubeb-coreaudio/Cargo.toml | 5 +- .../rust/cubeb-coreaudio/src/backend/mixer.rs | 53 +- .../rust/cubeb-coreaudio/src/backend/mod.rs | 172 +- .../rust/cubeb-coreaudio/src/backend/tests/api.rs | 3 +- third_party/rust/d3d12/.cargo-checksum.json | 2 +- third_party/rust/d3d12/Cargo.toml | 2 +- third_party/rust/encoding_rs/.cargo-checksum.json | 2 +- third_party/rust/encoding_rs/Cargo.toml | 19 +- third_party/rust/encoding_rs/README.md | 34 +- third_party/rust/encoding_rs/src/ascii.rs | 388 +- third_party/rust/encoding_rs/src/handles.rs | 36 +- third_party/rust/encoding_rs/src/lib.rs | 13 +- third_party/rust/encoding_rs/src/mem.rs | 18 +- third_party/rust/encoding_rs/src/simd_funcs.rs | 146 +- third_party/rust/encoding_rs/src/single_byte.rs | 64 +- third_party/rust/encoding_rs/src/x_user_defined.rs | 10 +- third_party/rust/equivalent/.cargo-checksum.json | 1 + third_party/rust/equivalent/Cargo.toml | 27 + third_party/rust/equivalent/LICENSE-APACHE | 201 + third_party/rust/equivalent/LICENSE-MIT | 25 + third_party/rust/equivalent/README.md | 25 + third_party/rust/equivalent/src/lib.rs | 113 + .../rust/fallible_collections/.cargo-checksum.json | 2 +- third_party/rust/fallible_collections/Cargo.toml | 7 +- third_party/rust/fallible_collections/README.md | 3 +- third_party/rust/fallible_collections/src/arc.rs | 35 +- third_party/rust/fallible_collections/src/boxed.rs | 15 +- .../rust/fallible_collections/src/btree/node.rs | 29 +- third_party/rust/fallible_collections/src/lib.rs | 24 +- .../fallible_collections/src/try_reserve_error.rs | 19 + third_party/rust/fallible_collections/src/vec.rs | 4 +- third_party/rust/getrandom/.cargo-checksum.json | 2 +- third_party/rust/getrandom/CHANGELOG.md | 39 + third_party/rust/getrandom/Cargo.toml | 3 +- third_party/rust/getrandom/LICENSE-MIT | 2 +- third_party/rust/getrandom/README.md | 23 +- third_party/rust/getrandom/src/3ds.rs | 8 - third_party/rust/getrandom/src/apple-other.rs | 27 +- third_party/rust/getrandom/src/bsd_arandom.rs | 8 - third_party/rust/getrandom/src/custom.rs | 9 - third_party/rust/getrandom/src/dragonfly.rs | 8 - third_party/rust/getrandom/src/error.rs | 14 +- third_party/rust/getrandom/src/error_impls.rs | 9 - third_party/rust/getrandom/src/espidf.rs | 8 - third_party/rust/getrandom/src/fuchsia.rs | 8 - third_party/rust/getrandom/src/hermit.rs | 24 +- third_party/rust/getrandom/src/hurd.rs | 8 - third_party/rust/getrandom/src/js.rs | 8 +- third_party/rust/getrandom/src/lazy.rs | 56 + third_party/rust/getrandom/src/lib.rs | 96 +- third_party/rust/getrandom/src/linux_android.rs | 47 +- .../getrandom/src/linux_android_with_fallback.rs | 33 + third_party/rust/getrandom/src/macos.rs | 40 +- third_party/rust/getrandom/src/openbsd.rs | 8 - third_party/rust/getrandom/src/rdrand.rs | 13 +- third_party/rust/getrandom/src/solaris_illumos.rs | 8 - third_party/rust/getrandom/src/solid.rs | 8 - third_party/rust/getrandom/src/use_file.rs | 21 +- third_party/rust/getrandom/src/util.rs | 68 +- third_party/rust/getrandom/src/util_libc.rs | 41 +- third_party/rust/getrandom/src/vita.rs | 8 - third_party/rust/getrandom/src/vxworks.rs | 8 - third_party/rust/getrandom/src/wasi.rs | 8 - third_party/rust/getrandom/src/windows.rs | 9 +- third_party/rust/getrandom/tests/rdrand.rs | 2 + third_party/rust/glean-core/.cargo-checksum.json | 2 +- third_party/rust/glean-core/Cargo.toml | 4 +- .../rust/glean-core/src/common_metric_data.rs | 5 +- third_party/rust/glean-core/src/core/mod.rs | 29 +- third_party/rust/glean-core/src/database/mod.rs | 65 + third_party/rust/glean-core/src/glean.udl | 22 +- third_party/rust/glean-core/src/internal_pings.rs | 17 +- third_party/rust/glean-core/src/lib.rs | 42 +- third_party/rust/glean-core/src/lib_unit_tests.rs | 118 +- .../src/metrics/metrics_enabled_config.rs | 46 - third_party/rust/glean-core/src/metrics/mod.rs | 21 +- third_party/rust/glean-core/src/metrics/object.rs | 29 + third_party/rust/glean-core/src/metrics/ping.rs | 74 +- .../src/metrics/remote_settings_config.rs | 52 + third_party/rust/glean-core/src/ping/mod.rs | 3 + .../rust/glean-core/src/upload/directory.rs | 6 +- third_party/rust/glean-core/src/upload/mod.rs | 24 + third_party/rust/glean-core/tests/event.rs | 4 + third_party/rust/glean-core/tests/ping.rs | 46 +- third_party/rust/glean-core/tests/ping_maker.rs | 23 +- third_party/rust/glean/.cargo-checksum.json | 2 +- third_party/rust/glean/Cargo.toml | 4 +- third_party/rust/glean/src/lib.rs | 10 +- third_party/rust/glean/src/private/ping.rs | 11 + third_party/rust/glean/src/test.rs | 29 +- third_party/rust/glean/tests/init_fails.rs | 5 +- third_party/rust/glean/tests/never_init.rs | 5 +- third_party/rust/glean/tests/no_time_to_init.rs | 5 +- third_party/rust/glean/tests/schema.rs | 3 +- third_party/rust/glean/tests/simple.rs | 5 +- .../rust/glean/tests/test-shutdown-blocking.sh | 2 +- .../rust/glean/tests/test-thread-crashing.sh | 2 +- third_party/rust/glean/tests/upload_timing.rs | 5 +- .../rust/gpu-descriptor-types/.cargo-checksum.json | 2 +- third_party/rust/gpu-descriptor-types/Cargo.toml | 23 +- .../rust/gpu-descriptor-types/src/device.rs | 128 +- third_party/rust/gpu-descriptor-types/src/lib.rs | 12 +- third_party/rust/gpu-descriptor-types/src/types.rs | 86 +- .../rust/gpu-descriptor/.cargo-checksum.json | 2 +- third_party/rust/gpu-descriptor/Cargo.toml | 14 +- third_party/rust/gpu-descriptor/src/allocator.rs | 38 +- third_party/rust/hashbrown/.cargo-checksum.json | 2 +- third_party/rust/hashbrown/CHANGELOG.md | 166 +- third_party/rust/hashbrown/Cargo.toml | 40 +- third_party/rust/hashbrown/README.md | 77 +- third_party/rust/hashbrown/benches/bench.rs | 2 +- .../rust/hashbrown/src/external_trait_impls/mod.rs | 2 + .../src/external_trait_impls/rayon/map.rs | 47 +- .../src/external_trait_impls/rayon/mod.rs | 1 + .../src/external_trait_impls/rayon/raw.rs | 23 +- .../src/external_trait_impls/rayon/set.rs | 34 +- .../src/external_trait_impls/rayon/table.rs | 252 + .../src/external_trait_impls/rkyv/hash_map.rs | 125 + .../src/external_trait_impls/rkyv/hash_set.rs | 123 + .../hashbrown/src/external_trait_impls/rkyv/mod.rs | 2 + .../hashbrown/src/external_trait_impls/serde.rs | 63 +- third_party/rust/hashbrown/src/lib.rs | 78 +- third_party/rust/hashbrown/src/macros.rs | 2 +- third_party/rust/hashbrown/src/map.rs | 1324 +++- third_party/rust/hashbrown/src/raw/alloc.rs | 57 +- third_party/rust/hashbrown/src/raw/bitmask.rs | 99 +- third_party/rust/hashbrown/src/raw/generic.rs | 59 +- third_party/rust/hashbrown/src/raw/mod.rs | 3319 ++++++-- third_party/rust/hashbrown/src/raw/neon.rs | 124 + third_party/rust/hashbrown/src/raw/sse2.rs | 31 +- third_party/rust/hashbrown/src/rustc_entry.rs | 32 +- third_party/rust/hashbrown/src/scopeguard.rs | 14 +- third_party/rust/hashbrown/src/set.rs | 516 +- third_party/rust/hashbrown/src/table.rs | 2070 +++++ .../rust/hashbrown/tests/equivalent_trait.rs | 53 + third_party/rust/hashbrown/tests/raw.rs | 11 + third_party/rust/hashbrown/tests/rayon.rs | 4 +- third_party/rust/hashbrown/tests/set.rs | 2 +- third_party/rust/hashlink/.cargo-checksum.json | 2 +- third_party/rust/hashlink/CHANGELOG.md | 3 + third_party/rust/hashlink/Cargo.toml | 8 +- third_party/rust/hashlink/tests/serde.rs | 10 +- third_party/rust/indexmap/.cargo-checksum.json | 2 +- third_party/rust/indexmap/Cargo.toml | 47 +- third_party/rust/indexmap/README.md | 10 +- third_party/rust/indexmap/RELEASES.md | 618 +- third_party/rust/indexmap/build.rs | 8 - third_party/rust/indexmap/src/arbitrary.rs | 2 + third_party/rust/indexmap/src/borsh.rs | 122 + third_party/rust/indexmap/src/equivalent.rs | 27 - third_party/rust/indexmap/src/lib.rs | 132 +- third_party/rust/indexmap/src/macros.rs | 36 +- third_party/rust/indexmap/src/map.rs | 1410 ++-- third_party/rust/indexmap/src/map/core.rs | 460 +- third_party/rust/indexmap/src/map/core/entry.rs | 481 ++ third_party/rust/indexmap/src/map/core/raw.rs | 174 +- .../rust/indexmap/src/map/core/raw_entry_v1.rs | 652 ++ third_party/rust/indexmap/src/map/iter.rs | 713 ++ third_party/rust/indexmap/src/map/mutable.rs | 87 + third_party/rust/indexmap/src/map/serde_seq.rs | 138 + third_party/rust/indexmap/src/map/slice.rs | 539 ++ third_party/rust/indexmap/src/map/tests.rs | 727 ++ third_party/rust/indexmap/src/mutable_keys.rs | 75 - third_party/rust/indexmap/src/rayon/map.rs | 184 +- third_party/rust/indexmap/src/rayon/mod.rs | 2 + third_party/rust/indexmap/src/rayon/set.rs | 111 +- third_party/rust/indexmap/src/serde.rs | 43 +- third_party/rust/indexmap/src/serde_seq.rs | 112 - third_party/rust/indexmap/src/set.rs | 1465 +--- third_party/rust/indexmap/src/set/iter.rs | 626 ++ third_party/rust/indexmap/src/set/mutable.rs | 86 + third_party/rust/indexmap/src/set/slice.rs | 340 + third_party/rust/indexmap/src/set/tests.rs | 723 ++ third_party/rust/indexmap/src/util.rs | 22 + third_party/rust/indexmap/tests/quick.rs | 198 +- .../rust/interrupt-support/.cargo-checksum.json | 2 +- third_party/rust/interrupt-support/Cargo.toml | 5 + third_party/rust/interrupt-support/build.rs | 8 + .../interrupt-support/src/interrupt_support.udl | 5 + third_party/rust/interrupt-support/src/shutdown.rs | 5 +- third_party/rust/interrupt-support/src/sql.rs | 7 + third_party/rust/libc/.cargo-checksum.json | 2 +- third_party/rust/libc/Cargo.toml | 2 +- .../rust/libc/src/unix/linux_like/android/mod.rs | 33 + .../src/unix/linux_like/linux/arch/generic/mod.rs | 6 +- .../rust/libc/src/unix/linux_like/linux/mod.rs | 2 + third_party/rust/libc/src/unix/newlib/vita/mod.rs | 2 + third_party/rust/libloading/.cargo-checksum.json | 2 +- third_party/rust/libloading/Cargo.toml | 16 +- third_party/rust/libloading/README.mkd | 7 +- third_party/rust/libloading/src/changelog.rs | 45 + third_party/rust/libloading/src/error.rs | 8 +- third_party/rust/libloading/src/lib.rs | 8 +- third_party/rust/libloading/src/os/unix/consts.rs | 12 +- third_party/rust/libloading/src/os/unix/mod.rs | 186 +- third_party/rust/libloading/src/os/windows/mod.rs | 154 +- third_party/rust/libloading/tests/functions.rs | 20 +- third_party/rust/metal/.cargo-checksum.json | 2 +- third_party/rust/metal/Cargo.lock | 273 +- third_party/rust/metal/Cargo.toml | 7 +- third_party/rust/metal/README.md | 7 - third_party/rust/metal/src/device.rs | 3 +- third_party/rust/metal/src/lib.rs | 8 +- third_party/rust/metal/src/library.rs | 9 +- third_party/rust/metal/src/mps.rs | 7 +- third_party/rust/metal/src/sync.rs | 4 +- .../rust/minidump-common/.cargo-checksum.json | 2 +- third_party/rust/minidump-common/Cargo.toml | 4 +- .../rust/minidump-common/src/errors/macos.rs | 25 +- third_party/rust/minidump-common/src/format.rs | 24 + .../rust/minidump-writer/.cargo-checksum.json | 2 +- third_party/rust/minidump-writer/CHANGELOG.md | 40 +- third_party/rust/minidump-writer/Cargo.lock | 1763 ++++- third_party/rust/minidump-writer/Cargo.toml | 27 +- third_party/rust/minidump-writer/README.md | 26 +- third_party/rust/minidump-writer/deny.toml | 6 +- third_party/rust/minidump-writer/src/bin/test.rs | 26 +- .../rust/minidump-writer/src/linux/dso_debug.rs | 5 - .../rust/minidump-writer/src/linux/maps_reader.rs | 147 +- .../minidump-writer/src/linux/minidump_writer.rs | 38 +- .../minidump-writer/src/linux/ptrace_dumper.rs | 81 +- .../minidump-writer/src/linux/sections/mappings.rs | 21 +- .../rust/minidump-writer/src/linux/thread_info.rs | 22 +- third_party/rust/minidump-writer/src/mac/mach.rs | 3 +- .../minidump-writer/src/mac/streams/exception.rs | 8 +- .../minidump-writer/src/mac/streams/module_list.rs | 8 + .../src/mac/streams/thread_names.rs | 4 +- .../minidump-writer/src/windows/minidump_writer.rs | 14 +- .../rust/minidump-writer/tests/common/mod.rs | 67 +- .../minidump-writer/tests/linux_minidump_writer.rs | 106 +- .../rust/minidump-writer/tests/ptrace_dumper.rs | 21 +- third_party/rust/naga/.cargo-checksum.json | 2 +- third_party/rust/naga/Cargo.toml | 9 +- third_party/rust/naga/src/arena.rs | 17 +- third_party/rust/naga/src/back/dot/mod.rs | 91 + third_party/rust/naga/src/back/glsl/features.rs | 23 + third_party/rust/naga/src/back/glsl/mod.rs | 148 +- third_party/rust/naga/src/back/hlsl/conv.rs | 5 + third_party/rust/naga/src/back/hlsl/help.rs | 94 +- third_party/rust/naga/src/back/hlsl/mod.rs | 17 + third_party/rust/naga/src/back/hlsl/writer.rs | 315 +- third_party/rust/naga/src/back/mod.rs | 17 + third_party/rust/naga/src/back/msl/mod.rs | 27 +- third_party/rust/naga/src/back/msl/writer.rs | 192 +- .../rust/naga/src/back/pipeline_constants.rs | 957 +++ third_party/rust/naga/src/back/spv/block.rs | 32 +- third_party/rust/naga/src/back/spv/helpers.rs | 53 +- third_party/rust/naga/src/back/spv/instructions.rs | 103 + third_party/rust/naga/src/back/spv/mod.rs | 47 +- third_party/rust/naga/src/back/spv/subgroup.rs | 207 + third_party/rust/naga/src/back/spv/writer.rs | 68 +- third_party/rust/naga/src/back/wgsl/writer.rs | 131 +- third_party/rust/naga/src/block.rs | 6 + third_party/rust/naga/src/compact/expressions.rs | 27 +- third_party/rust/naga/src/compact/functions.rs | 6 +- third_party/rust/naga/src/compact/mod.rs | 49 +- third_party/rust/naga/src/compact/statements.rs | 67 + third_party/rust/naga/src/error.rs | 74 + third_party/rust/naga/src/front/glsl/context.rs | 48 +- third_party/rust/naga/src/front/glsl/error.rs | 18 +- third_party/rust/naga/src/front/glsl/functions.rs | 10 + third_party/rust/naga/src/front/glsl/mod.rs | 4 +- third_party/rust/naga/src/front/glsl/parser.rs | 17 +- .../naga/src/front/glsl/parser/declarations.rs | 9 +- .../rust/naga/src/front/glsl/parser/functions.rs | 9 +- .../rust/naga/src/front/glsl/parser_tests.rs | 22 +- third_party/rust/naga/src/front/glsl/types.rs | 17 +- third_party/rust/naga/src/front/glsl/variables.rs | 1 - third_party/rust/naga/src/front/spv/convert.rs | 5 + third_party/rust/naga/src/front/spv/error.rs | 10 +- third_party/rust/naga/src/front/spv/function.rs | 13 +- third_party/rust/naga/src/front/spv/image.rs | 13 +- third_party/rust/naga/src/front/spv/mod.rs | 455 +- third_party/rust/naga/src/front/spv/null.rs | 8 +- third_party/rust/naga/src/front/wgsl/error.rs | 29 +- third_party/rust/naga/src/front/wgsl/index.rs | 1 + third_party/rust/naga/src/front/wgsl/lower/mod.rs | 414 +- third_party/rust/naga/src/front/wgsl/mod.rs | 11 + third_party/rust/naga/src/front/wgsl/parse/ast.rs | 9 + third_party/rust/naga/src/front/wgsl/parse/conv.rs | 28 + third_party/rust/naga/src/front/wgsl/parse/mod.rs | 106 +- third_party/rust/naga/src/front/wgsl/to_wgsl.rs | 3 +- third_party/rust/naga/src/lib.rs | 174 +- .../rust/naga/src/proc/constant_evaluator.rs | 589 +- third_party/rust/naga/src/proc/index.rs | 4 +- third_party/rust/naga/src/proc/mod.rs | 105 +- third_party/rust/naga/src/proc/terminator.rs | 3 + third_party/rust/naga/src/proc/typifier.rs | 8 + third_party/rust/naga/src/span.rs | 12 +- third_party/rust/naga/src/valid/analyzer.rs | 53 +- third_party/rust/naga/src/valid/expression.rs | 39 +- third_party/rust/naga/src/valid/function.rs | 268 +- third_party/rust/naga/src/valid/handles.rs | 91 +- third_party/rust/naga/src/valid/interface.rs | 48 +- third_party/rust/naga/src/valid/mod.rs | 228 +- third_party/rust/naga/src/valid/type.rs | 3 +- third_party/rust/neqo-common/.cargo-checksum.json | 2 +- third_party/rust/neqo-common/Cargo.toml | 13 +- third_party/rust/neqo-common/src/datagram.rs | 2 +- third_party/rust/neqo-common/src/fuzz.rs | 43 + third_party/rust/neqo-common/src/lib.rs | 4 + third_party/rust/neqo-common/src/tos.rs | 27 + third_party/rust/neqo-crypto/.cargo-checksum.json | 2 +- third_party/rust/neqo-crypto/Cargo.toml | 5 +- third_party/rust/neqo-crypto/src/aead_null.rs | 2 - third_party/rust/neqo-crypto/src/agentio.rs | 2 +- third_party/rust/neqo-crypto/src/constants.rs | 2 +- third_party/rust/neqo-crypto/src/p11.rs | 26 +- third_party/rust/neqo-http3/.cargo-checksum.json | 2 +- third_party/rust/neqo-http3/Cargo.toml | 6 +- .../rust/neqo-http3/src/buffered_send_stream.rs | 51 +- third_party/rust/neqo-http3/src/connection.rs | 20 +- .../rust/neqo-http3/src/connection_client.rs | 20 +- .../tests/webtransport/negotiation.rs | 7 +- third_party/rust/neqo-http3/src/send_message.rs | 4 +- third_party/rust/neqo-http3/src/server.rs | 4 +- third_party/rust/neqo-http3/tests/httpconn.rs | 4 +- third_party/rust/neqo-qpack/.cargo-checksum.json | 2 +- third_party/rust/neqo-qpack/Cargo.toml | 6 +- .../rust/neqo-transport/.cargo-checksum.json | 2 +- third_party/rust/neqo-transport/Cargo.toml | 22 +- .../rust/neqo-transport/src/cc/classic_cc.rs | 105 +- third_party/rust/neqo-transport/src/cc/mod.rs | 3 + .../rust/neqo-transport/src/cc/tests/cubic.rs | 34 +- .../rust/neqo-transport/src/cc/tests/new_reno.rs | 89 +- .../rust/neqo-transport/src/connection/mod.rs | 285 +- .../rust/neqo-transport/src/connection/state.rs | 39 +- .../rust/neqo-transport/src/connection/tests/cc.rs | 36 +- .../neqo-transport/src/connection/tests/close.rs | 25 +- .../src/connection/tests/datagram.rs | 14 +- .../neqo-transport/src/connection/tests/ecn.rs | 392 + .../src/connection/tests/handshake.rs | 26 +- .../neqo-transport/src/connection/tests/keys.rs | 10 +- .../src/connection/tests/migration.rs | 8 +- .../neqo-transport/src/connection/tests/mod.rs | 31 +- .../neqo-transport/src/connection/tests/stream.rs | 9 +- .../rust/neqo-transport/src/connection/tests/vn.rs | 8 +- third_party/rust/neqo-transport/src/ecn.rs | 225 + third_party/rust/neqo-transport/src/events.rs | 4 +- third_party/rust/neqo-transport/src/frame.rs | 143 +- third_party/rust/neqo-transport/src/lib.rs | 27 +- third_party/rust/neqo-transport/src/packet/mod.rs | 1 + third_party/rust/neqo-transport/src/path.rs | 77 +- third_party/rust/neqo-transport/src/qlog.rs | 73 +- third_party/rust/neqo-transport/src/recovery.rs | 52 +- third_party/rust/neqo-transport/src/send_stream.rs | 18 +- third_party/rust/neqo-transport/src/sender.rs | 5 + third_party/rust/neqo-transport/src/server.rs | 7 + third_party/rust/neqo-transport/src/tracking.rs | 47 +- .../rust/neqo-transport/tests/common/mod.rs | 108 - .../rust/neqo-transport/tests/connection.rs | 41 +- third_party/rust/neqo-transport/tests/network.rs | 10 +- third_party/rust/neqo-transport/tests/retry.rs | 20 +- third_party/rust/neqo-transport/tests/server.rs | 93 +- third_party/rust/nix/.cargo-checksum.json | 2 +- third_party/rust/nix/CHANGELOG.md | 205 +- third_party/rust/nix/Cargo.toml | 16 +- third_party/rust/nix/README.md | 4 +- third_party/rust/nix/build.rs | 25 + third_party/rust/nix/src/dir.rs | 27 +- third_party/rust/nix/src/env.rs | 7 +- third_party/rust/nix/src/errno.rs | 1114 ++- third_party/rust/nix/src/fcntl.rs | 561 +- third_party/rust/nix/src/features.rs | 12 +- third_party/rust/nix/src/ifaddrs.rs | 38 +- third_party/rust/nix/src/kmod.rs | 4 + third_party/rust/nix/src/lib.rs | 34 +- third_party/rust/nix/src/macros.rs | 8 +- third_party/rust/nix/src/mount/bsd.rs | 51 +- third_party/rust/nix/src/mount/linux.rs | 2 +- third_party/rust/nix/src/mount/mod.rs | 22 +- third_party/rust/nix/src/mqueue.rs | 15 +- third_party/rust/nix/src/net/if_.rs | 329 +- third_party/rust/nix/src/poll.rs | 61 +- third_party/rust/nix/src/poll_timeout.rs | 224 + third_party/rust/nix/src/pty.rs | 15 +- third_party/rust/nix/src/sched.rs | 43 +- third_party/rust/nix/src/sys/aio.rs | 80 +- third_party/rust/nix/src/sys/epoll.rs | 25 +- third_party/rust/nix/src/sys/event.rs | 171 +- third_party/rust/nix/src/sys/eventfd.rs | 77 +- third_party/rust/nix/src/sys/fanotify.rs | 416 + third_party/rust/nix/src/sys/inotify.rs | 16 +- third_party/rust/nix/src/sys/ioctl/bsd.rs | 4 +- third_party/rust/nix/src/sys/ioctl/linux.rs | 2 + third_party/rust/nix/src/sys/ioctl/mod.rs | 112 +- third_party/rust/nix/src/sys/memfd.rs | 43 + third_party/rust/nix/src/sys/mman.rs | 320 +- third_party/rust/nix/src/sys/mod.rs | 82 +- third_party/rust/nix/src/sys/personality.rs | 2 - third_party/rust/nix/src/sys/prctl.rs | 23 +- third_party/rust/nix/src/sys/ptrace/bsd.rs | 42 +- third_party/rust/nix/src/sys/ptrace/linux.rs | 58 +- third_party/rust/nix/src/sys/ptrace/mod.rs | 20 +- third_party/rust/nix/src/sys/quota.rs | 6 +- third_party/rust/nix/src/sys/reboot.rs | 175 +- third_party/rust/nix/src/sys/resource.rs | 109 +- third_party/rust/nix/src/sys/select.rs | 267 +- third_party/rust/nix/src/sys/sendfile.rs | 116 +- third_party/rust/nix/src/sys/signal.rs | 461 +- third_party/rust/nix/src/sys/signalfd.rs | 66 +- third_party/rust/nix/src/sys/socket/addr.rs | 873 +-- third_party/rust/nix/src/sys/socket/mod.rs | 943 +-- third_party/rust/nix/src/sys/socket/sockopt.rs | 454 +- third_party/rust/nix/src/sys/stat.rs | 73 +- third_party/rust/nix/src/sys/statfs.rs | 363 +- third_party/rust/nix/src/sys/statvfs.rs | 48 +- third_party/rust/nix/src/sys/termios.rs | 570 +- third_party/rust/nix/src/sys/time.rs | 121 +- third_party/rust/nix/src/sys/timerfd.rs | 2 +- third_party/rust/nix/src/sys/uio.rs | 49 +- third_party/rust/nix/src/sys/utsname.rs | 23 +- third_party/rust/nix/src/sys/wait.rs | 58 +- third_party/rust/nix/src/time.rs | 236 +- third_party/rust/nix/src/unistd.rs | 1313 ++-- third_party/rust/nix/test/common/mod.rs | 10 +- third_party/rust/nix/test/sys/mod.rs | 54 +- third_party/rust/nix/test/sys/test_aio.rs | 66 +- third_party/rust/nix/test/sys/test_aio_drop.rs | 3 +- third_party/rust/nix/test/sys/test_event.rs | 41 + third_party/rust/nix/test/sys/test_fanotify.rs | 149 + third_party/rust/nix/test/sys/test_ioctl.rs | 33 +- third_party/rust/nix/test/sys/test_mman.rs | 55 +- third_party/rust/nix/test/sys/test_ptrace.rs | 12 +- third_party/rust/nix/test/sys/test_resource.rs | 43 + third_party/rust/nix/test/sys/test_select.rs | 247 +- third_party/rust/nix/test/sys/test_signal.rs | 320 +- third_party/rust/nix/test/sys/test_signalfd.rs | 63 + third_party/rust/nix/test/sys/test_socket.rs | 474 +- third_party/rust/nix/test/sys/test_sockopt.rs | 454 +- third_party/rust/nix/test/sys/test_statfs.rs | 99 + third_party/rust/nix/test/sys/test_statvfs.rs | 13 + third_party/rust/nix/test/sys/test_termios.rs | 13 +- third_party/rust/nix/test/sys/test_time.rs | 91 + third_party/rust/nix/test/sys/test_timer.rs | 102 + third_party/rust/nix/test/sys/test_uio.rs | 36 +- third_party/rust/nix/test/sys/test_utsname.rs | 17 + third_party/rust/nix/test/sys/test_wait.rs | 16 +- third_party/rust/nix/test/test.rs | 32 +- third_party/rust/nix/test/test_dir.rs | 4 +- third_party/rust/nix/test/test_errno.rs | 16 + third_party/rust/nix/test/test_fcntl.rs | 182 +- third_party/rust/nix/test/test_mount.rs | 390 +- third_party/rust/nix/test/test_mq.rs | 20 +- third_party/rust/nix/test/test_net.rs | 8 +- third_party/rust/nix/test/test_poll.rs | 31 +- third_party/rust/nix/test/test_pty.rs | 24 +- third_party/rust/nix/test/test_resource.rs | 34 - third_party/rust/nix/test/test_sendfile.rs | 90 +- third_party/rust/nix/test/test_stat.rs | 104 +- third_party/rust/nix/test/test_time.rs | 49 +- third_party/rust/nix/test/test_timer.rs | 102 - third_party/rust/nix/test/test_unistd.rs | 260 +- .../rust/objc_exception/.cargo-checksum.json | 1 - third_party/rust/objc_exception/Cargo.toml | 25 - third_party/rust/objc_exception/build.rs | 7 - third_party/rust/objc_exception/extern/exception.m | 21 - third_party/rust/objc_exception/src/lib.rs | 100 - third_party/rust/owning_ref/.cargo-checksum.json | 1 - third_party/rust/owning_ref/CHANGELOG.md | 8 - third_party/rust/owning_ref/Cargo.toml | 24 - third_party/rust/owning_ref/LICENSE | 21 - third_party/rust/owning_ref/README.md | 64 - third_party/rust/owning_ref/src/lib.rs | 2016 ----- third_party/rust/packed_simd/.cargo-checksum.json | 1 - third_party/rust/packed_simd/Cargo.toml | 83 - third_party/rust/packed_simd/LICENSE-APACHE | 201 - third_party/rust/packed_simd/LICENSE-MIT | 25 - third_party/rust/packed_simd/README.md | 144 - third_party/rust/packed_simd/bors.toml | 3 - third_party/rust/packed_simd/build.rs | 6 - third_party/rust/packed_simd/ci/all.sh | 71 - .../rust/packed_simd/ci/android-install-ndk.sh | 21 - .../rust/packed_simd/ci/android-install-sdk.sh | 60 - .../rust/packed_simd/ci/android-sysimage.sh | 56 - third_party/rust/packed_simd/ci/benchmark.sh | 32 - .../ci/deploy_and_run_on_ios_simulator.rs | 176 - .../ci/docker/aarch64-linux-android/Dockerfile | 47 - .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 14 - .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 15 - .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 13 - .../ci/docker/armv7-linux-androideabi/Dockerfile | 47 - .../armv7-unknown-linux-gnueabihf/Dockerfile | 13 - .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 7 - .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 7 - .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 13 - .../mips64-unknown-linux-gnuabi64/Dockerfile | 10 - .../mips64el-unknown-linux-gnuabi64/Dockerfile | 10 - .../ci/docker/mipsel-unknown-linux-musl/Dockerfile | 25 - .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 13 - .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 17 - .../powerpc64le-unknown-linux-gnu/Dockerfile | 11 - .../ci/docker/s390x-unknown-linux-gnu/Dockerfile | 20 - .../ci/docker/sparc64-unknown-linux-gnu/Dockerfile | 18 - .../thumbv7neon-linux-androideabi/Dockerfile | 47 - .../thumbv7neon-unknown-linux-gnueabihf/Dockerfile | 13 - .../ci/docker/wasm32-unknown-unknown/Dockerfile | 39 - .../ci/docker/x86_64-linux-android/Dockerfile | 31 - .../x86_64-unknown-linux-gnu-emulated/Dockerfile | 16 - .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 10 - third_party/rust/packed_simd/ci/dox.sh | 27 - third_party/rust/packed_simd/ci/linux-s390x.sh | 18 - third_party/rust/packed_simd/ci/linux-sparc64.sh | 17 - third_party/rust/packed_simd/ci/lld-shim.rs | 11 - third_party/rust/packed_simd/ci/max_line_width.sh | 17 - third_party/rust/packed_simd/ci/run-docker.sh | 38 - third_party/rust/packed_simd/ci/run.sh | 99 - third_party/rust/packed_simd/ci/run_examples.sh | 51 - third_party/rust/packed_simd/ci/runtest-android.rs | 45 - .../rust/packed_simd/ci/setup_benchmarks.sh | 7 - third_party/rust/packed_simd/ci/test-runner-linux | 24 - third_party/rust/packed_simd/contributing.md | 67 - third_party/rust/packed_simd/perf-guide/book.toml | 12 - .../rust/packed_simd/perf-guide/src/SUMMARY.md | 21 - .../rust/packed_simd/perf-guide/src/ascii.css | 4 - .../packed_simd/perf-guide/src/bound_checks.md | 22 - .../perf-guide/src/float-math/approx.md | 8 - .../packed_simd/perf-guide/src/float-math/fma.md | 6 - .../packed_simd/perf-guide/src/float-math/fp.md | 3 - .../packed_simd/perf-guide/src/float-math/svml.md | 7 - .../packed_simd/perf-guide/src/introduction.md | 26 - .../rust/packed_simd/perf-guide/src/prof/linux.md | 107 - .../rust/packed_simd/perf-guide/src/prof/mca.md | 100 - .../packed_simd/perf-guide/src/prof/profiling.md | 14 - .../perf-guide/src/target-feature/attribute.md | 5 - .../perf-guide/src/target-feature/features.md | 13 - .../perf-guide/src/target-feature/inlining.md | 5 - .../perf-guide/src/target-feature/practice.md | 31 - .../perf-guide/src/target-feature/runtime.md | 5 - .../perf-guide/src/target-feature/rustflags.md | 77 - .../packed_simd/perf-guide/src/vert-hor-ops.md | 76 - third_party/rust/packed_simd/rust-toolchain | 1 - third_party/rust/packed_simd/rustfmt.toml | 5 - third_party/rust/packed_simd/src/api.rs | 309 - third_party/rust/packed_simd/src/api/bit_manip.rs | 129 - third_party/rust/packed_simd/src/api/bitmask.rs | 79 - third_party/rust/packed_simd/src/api/cast.rs | 108 - .../rust/packed_simd/src/api/cast/macros.rs | 82 - third_party/rust/packed_simd/src/api/cast/v128.rs | 302 - third_party/rust/packed_simd/src/api/cast/v16.rs | 68 - third_party/rust/packed_simd/src/api/cast/v256.rs | 298 - third_party/rust/packed_simd/src/api/cast/v32.rs | 132 - third_party/rust/packed_simd/src/api/cast/v512.rs | 209 - third_party/rust/packed_simd/src/api/cast/v64.rs | 208 - third_party/rust/packed_simd/src/api/cmp.rs | 16 - third_party/rust/packed_simd/src/api/cmp/eq.rs | 27 - third_party/rust/packed_simd/src/api/cmp/ord.rs | 43 - .../rust/packed_simd/src/api/cmp/partial_eq.rs | 65 - .../rust/packed_simd/src/api/cmp/partial_ord.rs | 230 - .../rust/packed_simd/src/api/cmp/vertical.rs | 114 - third_party/rust/packed_simd/src/api/default.rs | 30 - third_party/rust/packed_simd/src/api/fmt.rs | 12 - third_party/rust/packed_simd/src/api/fmt/binary.rs | 54 - third_party/rust/packed_simd/src/api/fmt/debug.rs | 60 - .../rust/packed_simd/src/api/fmt/lower_hex.rs | 54 - third_party/rust/packed_simd/src/api/fmt/octal.rs | 54 - .../rust/packed_simd/src/api/fmt/upper_hex.rs | 54 - third_party/rust/packed_simd/src/api/from.rs | 7 - .../rust/packed_simd/src/api/from/from_array.rs | 124 - .../rust/packed_simd/src/api/from/from_vector.rs | 67 - third_party/rust/packed_simd/src/api/hash.rs | 49 - third_party/rust/packed_simd/src/api/into_bits.rs | 59 - .../packed_simd/src/api/into_bits/arch_specific.rs | 345 - .../rust/packed_simd/src/api/into_bits/macros.rs | 74 - .../rust/packed_simd/src/api/into_bits/v128.rs | 232 - .../rust/packed_simd/src/api/into_bits/v16.rs | 9 - .../rust/packed_simd/src/api/into_bits/v256.rs | 232 - .../rust/packed_simd/src/api/into_bits/v32.rs | 13 - .../rust/packed_simd/src/api/into_bits/v512.rs | 232 - .../rust/packed_simd/src/api/into_bits/v64.rs | 18 - third_party/rust/packed_simd/src/api/math.rs | 4 - third_party/rust/packed_simd/src/api/math/float.rs | 64 - .../rust/packed_simd/src/api/math/float/abs.rs | 31 - .../rust/packed_simd/src/api/math/float/consts.rs | 74 - .../rust/packed_simd/src/api/math/float/cos.rs | 44 - .../rust/packed_simd/src/api/math/float/exp.rs | 33 - .../rust/packed_simd/src/api/math/float/ln.rs | 33 - .../rust/packed_simd/src/api/math/float/mul_add.rs | 44 - .../packed_simd/src/api/math/float/mul_adde.rs | 48 - .../rust/packed_simd/src/api/math/float/powf.rs | 36 - .../rust/packed_simd/src/api/math/float/recpre.rs | 36 - .../rust/packed_simd/src/api/math/float/rsqrte.rs | 40 - .../rust/packed_simd/src/api/math/float/sin.rs | 50 - .../rust/packed_simd/src/api/math/float/sqrt.rs | 35 - .../rust/packed_simd/src/api/math/float/sqrte.rs | 44 - .../rust/packed_simd/src/api/math/float/tanh.rs | 29 - third_party/rust/packed_simd/src/api/minimal.rs | 6 - .../rust/packed_simd/src/api/minimal/iuf.rs | 169 - .../rust/packed_simd/src/api/minimal/mask.rs | 176 - .../rust/packed_simd/src/api/minimal/ptr.rs | 1373 ---- third_party/rust/packed_simd/src/api/ops.rs | 32 - .../packed_simd/src/api/ops/scalar_arithmetic.rs | 203 - .../rust/packed_simd/src/api/ops/scalar_bitwise.rs | 162 - .../packed_simd/src/api/ops/scalar_mask_bitwise.rs | 140 - .../rust/packed_simd/src/api/ops/scalar_shifts.rs | 106 - .../packed_simd/src/api/ops/vector_arithmetic.rs | 148 - .../rust/packed_simd/src/api/ops/vector_bitwise.rs | 129 - .../src/api/ops/vector_float_min_max.rs | 74 - .../packed_simd/src/api/ops/vector_int_min_max.rs | 57 - .../packed_simd/src/api/ops/vector_mask_bitwise.rs | 116 - .../rust/packed_simd/src/api/ops/vector_neg.rs | 43 - .../rust/packed_simd/src/api/ops/vector_rotates.rs | 92 - .../rust/packed_simd/src/api/ops/vector_shifts.rs | 106 - third_party/rust/packed_simd/src/api/ptr.rs | 4 - .../rust/packed_simd/src/api/ptr/gather_scatter.rs | 216 - third_party/rust/packed_simd/src/api/reductions.rs | 12 - .../rust/packed_simd/src/api/reductions/bitwise.rs | 151 - .../src/api/reductions/float_arithmetic.rs | 313 - .../src/api/reductions/integer_arithmetic.rs | 193 - .../rust/packed_simd/src/api/reductions/mask.rs | 89 - .../rust/packed_simd/src/api/reductions/min_max.rs | 360 - third_party/rust/packed_simd/src/api/select.rs | 73 - third_party/rust/packed_simd/src/api/shuffle.rs | 184 - .../rust/packed_simd/src/api/shuffle1_dyn.rs | 159 - third_party/rust/packed_simd/src/api/slice.rs | 7 - .../rust/packed_simd/src/api/slice/from_slice.rs | 202 - .../packed_simd/src/api/slice/write_to_slice.rs | 196 - third_party/rust/packed_simd/src/api/swap_bytes.rs | 192 - third_party/rust/packed_simd/src/codegen.rs | 62 - .../rust/packed_simd/src/codegen/bit_manip.rs | 347 - third_party/rust/packed_simd/src/codegen/llvm.rs | 122 - third_party/rust/packed_simd/src/codegen/math.rs | 3 - .../rust/packed_simd/src/codegen/math/float.rs | 19 - .../rust/packed_simd/src/codegen/math/float/abs.rs | 103 - .../rust/packed_simd/src/codegen/math/float/cos.rs | 103 - .../packed_simd/src/codegen/math/float/cos_pi.rs | 87 - .../rust/packed_simd/src/codegen/math/float/exp.rs | 112 - .../rust/packed_simd/src/codegen/math/float/ln.rs | 112 - .../packed_simd/src/codegen/math/float/macros.rs | 470 -- .../packed_simd/src/codegen/math/float/mul_add.rs | 109 - .../packed_simd/src/codegen/math/float/mul_adde.rs | 60 - .../packed_simd/src/codegen/math/float/powf.rs | 112 - .../rust/packed_simd/src/codegen/math/float/sin.rs | 103 - .../src/codegen/math/float/sin_cos_pi.rs | 188 - .../packed_simd/src/codegen/math/float/sin_pi.rs | 87 - .../packed_simd/src/codegen/math/float/sqrt.rs | 103 - .../packed_simd/src/codegen/math/float/sqrte.rs | 67 - .../packed_simd/src/codegen/math/float/tanh.rs | 120 - .../packed_simd/src/codegen/pointer_sized_int.rs | 28 - .../rust/packed_simd/src/codegen/reductions.rs | 1 - .../packed_simd/src/codegen/reductions/mask.rs | 69 - .../src/codegen/reductions/mask/aarch64.rs | 81 - .../packed_simd/src/codegen/reductions/mask/arm.rs | 56 - .../src/codegen/reductions/mask/fallback.rs | 8 - .../src/codegen/reductions/mask/fallback_impl.rs | 237 - .../packed_simd/src/codegen/reductions/mask/x86.rs | 216 - .../src/codegen/reductions/mask/x86/avx.rs | 95 - .../src/codegen/reductions/mask/x86/avx2.rs | 35 - .../src/codegen/reductions/mask/x86/sse.rs | 35 - .../src/codegen/reductions/mask/x86/sse2.rs | 68 - .../rust/packed_simd/src/codegen/shuffle.rs | 150 - .../rust/packed_simd/src/codegen/shuffle1_dyn.rs | 408 - .../rust/packed_simd/src/codegen/swap_bytes.rs | 149 - third_party/rust/packed_simd/src/codegen/v128.rs | 46 - third_party/rust/packed_simd/src/codegen/v16.rs | 7 - third_party/rust/packed_simd/src/codegen/v256.rs | 78 - third_party/rust/packed_simd/src/codegen/v32.rs | 11 - third_party/rust/packed_simd/src/codegen/v512.rs | 145 - third_party/rust/packed_simd/src/codegen/v64.rs | 21 - third_party/rust/packed_simd/src/codegen/vPtr.rs | 35 - third_party/rust/packed_simd/src/codegen/vSize.rs | 16 - third_party/rust/packed_simd/src/lib.rs | 348 - third_party/rust/packed_simd/src/masks.rs | 126 - third_party/rust/packed_simd/src/sealed.rs | 42 - third_party/rust/packed_simd/src/testing.rs | 8 - third_party/rust/packed_simd/src/testing/macros.rs | 44 - third_party/rust/packed_simd/src/testing/utils.rs | 130 - third_party/rust/packed_simd/src/v128.rs | 80 - third_party/rust/packed_simd/src/v16.rs | 16 - third_party/rust/packed_simd/src/v256.rs | 86 - third_party/rust/packed_simd/src/v32.rs | 29 - third_party/rust/packed_simd/src/v512.rs | 99 - third_party/rust/packed_simd/src/v64.rs | 66 - third_party/rust/packed_simd/src/vPtr.rs | 34 - third_party/rust/packed_simd/src/vSize.rs | 53 - third_party/rust/packed_simd/tests/endianness.rs | 268 - third_party/rust/plist/Cargo.toml | 2 +- third_party/rust/plist/src/lib.rs | 2 + third_party/rust/plist/src/stream/binary_writer.rs | 2 +- third_party/rust/prio/.cargo-checksum.json | 2 +- third_party/rust/prio/Cargo.toml | 66 +- third_party/rust/prio/README.md | 27 +- third_party/rust/prio/benches/cycle_counts.rs | 63 +- third_party/rust/prio/benches/speed_tests.rs | 127 +- .../rust/prio/documentation/field_parameters.sage | 117 + third_party/rust/prio/src/codec.rs | 210 +- third_party/rust/prio/src/dp.rs | 1 + third_party/rust/prio/src/dp/distributions.rs | 22 +- third_party/rust/prio/src/fft.rs | 1 + third_party/rust/prio/src/field.rs | 379 +- third_party/rust/prio/src/field/field255.rs | 31 +- third_party/rust/prio/src/flp.rs | 241 +- third_party/rust/prio/src/flp/types.rs | 460 +- .../rust/prio/src/flp/types/fixedpoint_l2.rs | 131 +- third_party/rust/prio/src/idpf.rs | 152 +- third_party/rust/prio/src/lib.rs | 7 + third_party/rust/prio/src/polynomial.rs | 4 +- third_party/rust/prio/src/prng.rs | 71 +- third_party/rust/prio/src/topology/ping_pong.rs | 125 +- third_party/rust/prio/src/vdaf.rs | 437 +- third_party/rust/prio/src/vdaf/dummy.rs | 147 +- third_party/rust/prio/src/vdaf/poplar1.rs | 306 +- third_party/rust/prio/src/vdaf/prio2.rs | 30 +- third_party/rust/prio/src/vdaf/prio2/client.rs | 16 +- third_party/rust/prio/src/vdaf/prio2/server.rs | 50 +- .../rust/prio/src/vdaf/prio2/test_vector.rs | 32 +- third_party/rust/prio/src/vdaf/prio3.rs | 630 +- third_party/rust/prio/src/vdaf/prio3_test.rs | 162 +- .../prio/src/vdaf/test_vec/07/IdpfPoplar_0.json | 52 - .../rust/prio/src/vdaf/test_vec/07/Poplar1_0.json | 56 - .../rust/prio/src/vdaf/test_vec/07/Poplar1_1.json | 64 - .../rust/prio/src/vdaf/test_vec/07/Poplar1_2.json | 64 - .../rust/prio/src/vdaf/test_vec/07/Poplar1_3.json | 76 - .../prio/src/vdaf/test_vec/07/Prio3Count_0.json | 39 - .../prio/src/vdaf/test_vec/07/Prio3Count_1.json | 45 - .../src/vdaf/test_vec/07/Prio3Histogram_0.json | 52 - .../src/vdaf/test_vec/07/Prio3Histogram_1.json | 89 - .../prio/src/vdaf/test_vec/07/Prio3SumVec_0.json | 194 - .../prio/src/vdaf/test_vec/07/Prio3SumVec_1.json | 146 - .../rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json | 40 - .../rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json | 46 - .../src/vdaf/test_vec/07/XofFixedKeyAes128.json | 8 - .../prio/src/vdaf/test_vec/07/XofShake128.json | 8 - .../prio/src/vdaf/test_vec/08/IdpfPoplar_0.json | 52 + .../rust/prio/src/vdaf/test_vec/08/Poplar1_0.json | 56 + .../rust/prio/src/vdaf/test_vec/08/Poplar1_1.json | 64 + .../rust/prio/src/vdaf/test_vec/08/Poplar1_2.json | 64 + .../rust/prio/src/vdaf/test_vec/08/Poplar1_3.json | 76 + .../prio/src/vdaf/test_vec/08/Prio3Count_0.json | 39 + .../prio/src/vdaf/test_vec/08/Prio3Count_1.json | 45 + .../src/vdaf/test_vec/08/Prio3Histogram_0.json | 52 + .../src/vdaf/test_vec/08/Prio3Histogram_1.json | 89 + .../prio/src/vdaf/test_vec/08/Prio3SumVec_0.json | 194 + .../prio/src/vdaf/test_vec/08/Prio3SumVec_1.json | 146 + .../rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json | 40 + .../rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json | 46 + .../src/vdaf/test_vec/08/XofFixedKeyAes128.json | 8 + .../src/vdaf/test_vec/08/XofTurboShake128.json | 8 + .../src/vdaf/test_vec/XofHmacSha256Aes128.json | 8 + third_party/rust/prio/src/vdaf/xof.rs | 148 +- third_party/rust/prio/src/vidpf.rs | 827 ++ third_party/rust/prio/tests/discrete_gauss.rs | 25 +- .../tests/test_vectors/discrete_gauss_100.json | 92 +- .../tests/test_vectors/discrete_gauss_2.342.json | 54 +- .../prio/tests/test_vectors/discrete_gauss_3.json | 62 +- .../test_vectors/discrete_gauss_41293847.json | 98 +- .../prio/tests/test_vectors/discrete_gauss_9.json | 80 +- .../discrete_gauss_9999999999999999999999.json | 98 +- third_party/rust/qlog/.cargo-checksum.json | 2 +- third_party/rust/qlog/Cargo.toml | 2 +- third_party/rust/qlog/src/events/mod.rs | 3 + third_party/rust/qlog/src/events/quic.rs | 21 +- third_party/rust/qlog/src/lib.rs | 28 +- third_party/rust/relevancy/.cargo-checksum.json | 2 +- third_party/rust/relevancy/Cargo.toml | 13 + third_party/rust/relevancy/src/db.rs | 68 +- third_party/rust/relevancy/src/error.rs | 15 + third_party/rust/relevancy/src/ingest.rs | 394 + third_party/rust/relevancy/src/interest.rs | 152 +- third_party/rust/relevancy/src/lib.rs | 80 +- .../rust/relevancy/src/populate_interests.rs | 157 - third_party/rust/relevancy/src/relevancy.udl | 17 +- third_party/rust/relevancy/src/rs.rs | 60 + third_party/rust/relevancy/src/url_hash.rs | 15 +- third_party/rust/relevancy/test-data | Bin 192 -> 188 bytes .../rust/remote_settings/.cargo-checksum.json | 2 +- third_party/rust/remote_settings/src/client.rs | 89 +- third_party/rust/remote_settings/src/config.rs | 30 +- third_party/rust/remote_settings/src/error.rs | 2 + third_party/rust/remote_settings/src/lib.rs | 17 +- .../rust/remote_settings/src/remote_settings.udl | 10 + third_party/rust/serde/.cargo-checksum.json | 2 +- third_party/rust/serde/Cargo.toml | 4 +- third_party/rust/serde/build.rs | 6 + third_party/rust/serde/src/de/impls.rs | 119 +- third_party/rust/serde/src/de/mod.rs | 8 +- third_party/rust/serde/src/lib.rs | 5 +- third_party/rust/serde/src/private/de.rs | 7 + third_party/rust/serde/src/private/doc.rs | 5 +- third_party/rust/serde/src/private/ser.rs | 132 +- third_party/rust/serde/src/ser/fmt.rs | 16 +- third_party/rust/serde/src/ser/impls.rs | 51 +- third_party/rust/serde/src/ser/impossible.rs | 32 +- third_party/rust/serde/src/ser/mod.rs | 79 +- third_party/rust/serde_derive/.cargo-checksum.json | 2 +- third_party/rust/serde_derive/Cargo.toml | 3 +- third_party/rust/serde_derive/src/lib.rs | 2 +- third_party/rust/serde_derive/src/ser.rs | 4 +- third_party/rust/serde_json/.cargo-checksum.json | 2 +- third_party/rust/serde_json/Cargo.toml | 33 +- third_party/rust/serde_json/README.md | 2 +- third_party/rust/serde_json/build.rs | 39 +- third_party/rust/serde_json/src/de.rs | 295 +- third_party/rust/serde_json/src/error.rs | 128 +- .../rust/serde_json/src/features_check/error.rs | 1 - .../rust/serde_json/src/features_check/mod.rs | 13 - third_party/rust/serde_json/src/io/core.rs | 2 +- .../rust/serde_json/src/lexical/algorithm.rs | 5 +- third_party/rust/serde_json/src/lexical/bignum.rs | 1 + third_party/rust/serde_json/src/lexical/digit.rs | 5 +- third_party/rust/serde_json/src/lexical/errors.rs | 3 +- .../rust/serde_json/src/lexical/exponent.rs | 4 +- .../rust/serde_json/src/lexical/large_powers32.rs | 2 +- .../rust/serde_json/src/lexical/large_powers64.rs | 2 +- third_party/rust/serde_json/src/lexical/math.rs | 4 +- third_party/rust/serde_json/src/lexical/num.rs | 13 +- .../rust/serde_json/src/lexical/rounding.rs | 2 +- third_party/rust/serde_json/src/lib.rs | 35 +- third_party/rust/serde_json/src/macros.rs | 3 +- third_party/rust/serde_json/src/map.rs | 131 +- third_party/rust/serde_json/src/number.rs | 76 +- third_party/rust/serde_json/src/raw.rs | 270 +- third_party/rust/serde_json/src/read.rs | 6 +- third_party/rust/serde_json/src/ser.rs | 122 +- third_party/rust/serde_json/src/value/de.rs | 94 +- third_party/rust/serde_json/src/value/from.rs | 37 +- third_party/rust/serde_json/src/value/index.rs | 2 +- third_party/rust/serde_json/src/value/mod.rs | 30 +- .../rust/serde_json/src/value/partial_eq.rs | 14 +- third_party/rust/serde_json/src/value/ser.rs | 41 +- third_party/rust/serde_json/tests/lexical.rs | 6 +- .../rust/serde_json/tests/lexical/exponent.rs | 34 +- third_party/rust/serde_json/tests/lexical/parse.rs | 2 +- third_party/rust/serde_json/tests/map.rs | 1 - .../rust/serde_json/tests/regression/issue1004.rs | 12 + .../rust/serde_json/tests/regression/issue520.rs | 2 +- .../rust/serde_json/tests/regression/issue795.rs | 5 +- .../rust/serde_json/tests/regression/issue845.rs | 2 +- third_party/rust/serde_json/tests/test.rs | 245 +- .../rust/serde_json/tests/ui/parse_key.stderr | 2 +- third_party/rust/sfv/.cargo-checksum.json | 2 +- third_party/rust/sfv/Cargo.toml | 4 +- third_party/rust/sql-support/.cargo-checksum.json | 2 +- third_party/rust/sql-support/Cargo.toml | 1 + third_party/rust/sql-support/src/lazy.rs | 151 + third_party/rust/sql-support/src/lib.rs | 10 +- third_party/rust/sql-support/src/open_database.rs | 204 +- third_party/rust/suggest/.cargo-checksum.json | 2 +- third_party/rust/suggest/src/benchmarks/client.rs | 1 + third_party/rust/suggest/src/db.rs | 6 + third_party/rust/suggest/src/lib.rs | 2 +- third_party/rust/suggest/src/schema.rs | 454 +- third_party/rust/suggest/src/store.rs | 216 +- third_party/rust/suggest/src/suggest.udl | 15 + .../rust/thiserror-impl/.cargo-checksum.json | 2 +- third_party/rust/thiserror-impl/Cargo.toml | 2 +- third_party/rust/thiserror-impl/src/ast.rs | 2 +- third_party/rust/thiserror-impl/src/attr.rs | 15 +- third_party/rust/thiserror-impl/src/expand.rs | 4 +- third_party/rust/thiserror/.cargo-checksum.json | 2 +- third_party/rust/thiserror/Cargo.toml | 4 +- third_party/rust/thiserror/build.rs | 20 +- third_party/rust/thiserror/src/lib.rs | 2 +- third_party/rust/thiserror/tests/test_lints.rs | 2 + .../uniffi-example-arithmetic/.cargo-checksum.json | 1 - .../rust/uniffi-example-arithmetic/Cargo.toml | 42 - .../rust/uniffi-example-arithmetic/build.rs | 7 - .../uniffi-example-arithmetic/src/arithmetic.udl | 16 - .../rust/uniffi-example-arithmetic/src/lib.rs | 34 - .../tests/bindings/test_arithmetic.kts | 29 - .../tests/bindings/test_arithmetic.py | 37 - .../tests/bindings/test_arithmetic.rb | 31 - .../tests/bindings/test_arithmetic.swift | 32 - .../tests/test_generated_bindings.rs | 6 - .../rust/uniffi-example-arithmetic/uniffi.toml | 2 - .../uniffi-example-geometry/.cargo-checksum.json | 1 - .../rust/uniffi-example-geometry/Cargo.toml | 39 - third_party/rust/uniffi-example-geometry/build.rs | 7 - .../rust/uniffi-example-geometry/src/geometry.udl | 15 - .../rust/uniffi-example-geometry/src/lib.rs | 47 - .../tests/bindings/test_geometry.kts | 10 - .../tests/bindings/test_geometry.py | 10 - .../tests/bindings/test_geometry.rb | 16 - .../tests/bindings/test_geometry.swift | 10 - .../tests/test_generated_bindings.rs | 6 - .../uniffi-example-rondpoint/.cargo-checksum.json | 1 - .../rust/uniffi-example-rondpoint/Cargo.toml | 39 - third_party/rust/uniffi-example-rondpoint/build.rs | 7 - .../rust/uniffi-example-rondpoint/src/lib.rs | 293 - .../uniffi-example-rondpoint/src/rondpoint.udl | 146 - .../tests/bindings/test_rondpoint.kts | 250 - .../tests/bindings/test_rondpoint.py | 146 - .../tests/bindings/test_rondpoint.rb | 147 - .../tests/bindings/test_rondpoint.swift | 232 - .../tests/test_generated_bindings.rs | 6 - .../uniffi-example-sprites/.cargo-checksum.json | 1 - third_party/rust/uniffi-example-sprites/Cargo.toml | 39 - third_party/rust/uniffi-example-sprites/build.rs | 7 - third_party/rust/uniffi-example-sprites/src/lib.rs | 65 - .../rust/uniffi-example-sprites/src/sprites.udl | 22 - .../tests/bindings/test_sprites.kts | 25 - .../tests/bindings/test_sprites.py | 17 - .../tests/bindings/test_sprites.rb | 22 - .../tests/bindings/test_sprites.swift | 16 - .../tests/test_generated_bindings.rs | 6 - .../uniffi-example-todolist/.cargo-checksum.json | 1 - .../rust/uniffi-example-todolist/Cargo.toml | 43 - third_party/rust/uniffi-example-todolist/build.rs | 7 - .../rust/uniffi-example-todolist/src/lib.rs | 150 - .../rust/uniffi-example-todolist/src/todolist.udl | 38 - .../tests/bindings/test_todolist.kts | 83 - .../tests/bindings/test_todolist.py | 44 - .../tests/bindings/test_todolist.rb | 47 - .../tests/bindings/test_todolist.swift | 69 - .../tests/test_generated_bindings.rs | 6 - third_party/rust/wasm-encoder/.cargo-checksum.json | 2 +- third_party/rust/wasm-encoder/Cargo.toml | 4 +- .../rust/wasm-encoder/src/component/types.rs | 16 +- third_party/rust/wasm-encoder/src/core/code.rs | 60 +- third_party/rust/wasm-encoder/src/core/data.rs | 1 + third_party/rust/wasm-encoder/src/core/globals.rs | 13 +- third_party/rust/wasm-encoder/src/core/imports.rs | 1 + third_party/rust/wasm-encoder/src/core/memories.rs | 25 +- third_party/rust/wasm-encoder/src/core/types.rs | 15 +- third_party/rust/wasm-smith/.cargo-checksum.json | 2 +- third_party/rust/wasm-smith/Cargo.toml | 10 +- third_party/rust/wasm-smith/src/component.rs | 17 +- third_party/rust/wasm-smith/src/config.rs | 9 +- third_party/rust/wasm-smith/src/core.rs | 202 +- .../rust/wasm-smith/src/core/code_builder.rs | 77 +- .../wasm-smith/src/core/code_builder/no_traps.rs | 10 +- third_party/rust/wasm-smith/src/core/terminate.rs | 1 + third_party/rust/wasm-smith/src/lib.rs | 6 + third_party/rust/wasm-smith/tests/common/mod.rs | 52 +- third_party/rust/wasm-smith/tests/component.rs | 8 +- third_party/rust/wasm-smith/tests/core.rs | 55 +- third_party/rust/wasm-smith/tests/exports.rs | 32 +- third_party/rust/wast/.cargo-checksum.json | 2 +- third_party/rust/wast/Cargo.toml | 8 +- third_party/rust/wast/src/component/binary.rs | 30 +- third_party/rust/wast/src/component/resolve.rs | 3 +- third_party/rust/wast/src/component/types.rs | 16 +- third_party/rust/wast/src/component/wast.rs | 10 +- third_party/rust/wast/src/core/binary.rs | 84 +- third_party/rust/wast/src/core/expr.rs | 158 +- third_party/rust/wast/src/core/memory.rs | 11 +- .../src/core/resolve/deinline_import_export.rs | 6 +- third_party/rust/wast/src/core/resolve/names.rs | 28 +- third_party/rust/wast/src/core/resolve/types.rs | 4 - third_party/rust/wast/src/core/types.rs | 78 +- third_party/rust/wast/src/core/wast.rs | 18 +- third_party/rust/wast/src/lib.rs | 5 + third_party/rust/wast/src/token.rs | 20 +- third_party/rust/wast/src/wast.rs | 75 +- third_party/rust/wast/src/wat.rs | 8 + third_party/rust/wast/tests/parse-fail.rs | 42 +- third_party/rust/wgpu-core/.cargo-checksum.json | 2 +- third_party/rust/wgpu-core/Cargo.toml | 10 +- third_party/rust/wgpu-core/src/any_surface.rs | 95 - third_party/rust/wgpu-core/src/binding_model.rs | 2 - .../rust/wgpu-core/src/command/allocator.rs | 67 + third_party/rust/wgpu-core/src/command/bundle.rs | 21 +- third_party/rust/wgpu-core/src/command/clear.rs | 9 + third_party/rust/wgpu-core/src/command/compute.rs | 318 +- .../rust/wgpu-core/src/command/compute_command.rs | 322 + third_party/rust/wgpu-core/src/command/mod.rs | 249 +- third_party/rust/wgpu-core/src/command/query.rs | 11 +- third_party/rust/wgpu-core/src/command/render.rs | 168 +- third_party/rust/wgpu-core/src/command/transfer.rs | 35 + .../rust/wgpu-core/src/device/any_device.rs | 2 +- third_party/rust/wgpu-core/src/device/bgl.rs | 2 +- third_party/rust/wgpu-core/src/device/global.rs | 77 +- third_party/rust/wgpu-core/src/device/life.rs | 123 +- third_party/rust/wgpu-core/src/device/mod.rs | 37 - third_party/rust/wgpu-core/src/device/queue.rs | 169 +- third_party/rust/wgpu-core/src/device/resource.rs | 544 +- third_party/rust/wgpu-core/src/global.rs | 10 +- third_party/rust/wgpu-core/src/hal_api.rs | 20 +- third_party/rust/wgpu-core/src/hub.rs | 36 +- third_party/rust/wgpu-core/src/id.rs | 47 +- third_party/rust/wgpu-core/src/identity.rs | 40 +- third_party/rust/wgpu-core/src/instance.rs | 357 +- third_party/rust/wgpu-core/src/lib.rs | 4 +- third_party/rust/wgpu-core/src/lock/mod.rs | 41 + third_party/rust/wgpu-core/src/lock/rank.rs | 170 + third_party/rust/wgpu-core/src/lock/ranked.rs | 397 + third_party/rust/wgpu-core/src/lock/vanilla.rs | 121 + third_party/rust/wgpu-core/src/pipeline.rs | 102 +- third_party/rust/wgpu-core/src/pool.rs | 12 +- third_party/rust/wgpu-core/src/present.rs | 30 +- third_party/rust/wgpu-core/src/registry.rs | 89 +- third_party/rust/wgpu-core/src/resource.rs | 74 +- third_party/rust/wgpu-core/src/snatch.rs | 88 +- third_party/rust/wgpu-core/src/storage.rs | 5 +- third_party/rust/wgpu-core/src/track/buffer.rs | 24 +- third_party/rust/wgpu-core/src/track/metadata.rs | 10 +- third_party/rust/wgpu-core/src/track/mod.rs | 45 +- third_party/rust/wgpu-core/src/track/stateless.rs | 22 +- third_party/rust/wgpu-core/src/track/texture.rs | 4 +- third_party/rust/wgpu-core/src/validation.rs | 3 +- third_party/rust/wgpu-hal/.cargo-checksum.json | 2 +- third_party/rust/wgpu-hal/Cargo.toml | 19 +- third_party/rust/wgpu-hal/README.md | 129 +- third_party/rust/wgpu-hal/examples/halmark/main.rs | 6 + .../wgpu-hal/examples/ray-traced-triangle/main.rs | 2 + third_party/rust/wgpu-hal/src/auxil/dxgi/conv.rs | 1 + third_party/rust/wgpu-hal/src/dx12/adapter.rs | 99 +- third_party/rust/wgpu-hal/src/dx12/conv.rs | 2 +- third_party/rust/wgpu-hal/src/dx12/device.rs | 33 +- third_party/rust/wgpu-hal/src/dx12/mod.rs | 3 +- third_party/rust/wgpu-hal/src/dx12/types.rs | 22 + third_party/rust/wgpu-hal/src/gles/adapter.rs | 33 +- third_party/rust/wgpu-hal/src/gles/conv.rs | 1 + third_party/rust/wgpu-hal/src/gles/device.rs | 37 +- third_party/rust/wgpu-hal/src/gles/egl.rs | 74 +- third_party/rust/wgpu-hal/src/gles/mod.rs | 1 + third_party/rust/wgpu-hal/src/gles/queue.rs | 71 +- third_party/rust/wgpu-hal/src/gles/wgl.rs | 2 + third_party/rust/wgpu-hal/src/lib.rs | 346 +- third_party/rust/wgpu-hal/src/metal/adapter.rs | 22 +- third_party/rust/wgpu-hal/src/metal/conv.rs | 1 + third_party/rust/wgpu-hal/src/metal/device.rs | 24 +- third_party/rust/wgpu-hal/src/metal/mod.rs | 12 +- third_party/rust/wgpu-hal/src/vulkan/adapter.rs | 123 +- third_party/rust/wgpu-hal/src/vulkan/command.rs | 5 + third_party/rust/wgpu-hal/src/vulkan/conv.rs | 1 + third_party/rust/wgpu-hal/src/vulkan/device.rs | 30 +- third_party/rust/wgpu-hal/src/vulkan/mod.rs | 109 +- third_party/rust/wgpu-types/.cargo-checksum.json | 2 +- third_party/rust/wgpu-types/Cargo.toml | 4 +- third_party/rust/wgpu-types/src/lib.rs | 100 +- .../rust/zerocopy-derive/.cargo-checksum.json | 1 + third_party/rust/zerocopy-derive/Cargo.toml | 44 + third_party/rust/zerocopy-derive/LICENSE-APACHE | 202 + third_party/rust/zerocopy-derive/LICENSE-BSD | 24 + third_party/rust/zerocopy-derive/LICENSE-MIT | 26 + third_party/rust/zerocopy-derive/src/ext.rs | 53 + third_party/rust/zerocopy-derive/src/lib.rs | 882 +++ third_party/rust/zerocopy-derive/src/repr.rs | 311 + .../rust/zerocopy-derive/tests/enum_as_bytes.rs | 101 + .../rust/zerocopy-derive/tests/enum_from_zeroes.rs | 35 + .../zerocopy-derive/tests/enum_known_layout.rs | 46 + .../rust/zerocopy-derive/tests/enum_unaligned.rs | 47 + third_party/rust/zerocopy-derive/tests/hygiene.rs | 43 + .../zerocopy-derive/tests/paths_and_modules.rs | 38 + .../rust/zerocopy-derive/tests/priv_in_pub.rs | 24 + .../rust/zerocopy-derive/tests/struct_as_bytes.rs | 161 + .../zerocopy-derive/tests/struct_from_bytes.rs | 79 + .../zerocopy-derive/tests/struct_from_zeroes.rs | 77 + .../zerocopy-derive/tests/struct_known_layout.rs | 65 + .../rust/zerocopy-derive/tests/struct_unaligned.rs | 100 + third_party/rust/zerocopy-derive/tests/trybuild.rs | 19 + .../tests/ui-msrv/derive_transparent.rs | 40 + .../tests/ui-msrv/derive_transparent.stderr | 71 + .../rust/zerocopy-derive/tests/ui-msrv/enum.rs | 194 + .../rust/zerocopy-derive/tests/ui-msrv/enum.stderr | 199 + .../tests/ui-msrv/enum_from_bytes_u8_too_few.rs | 272 + .../ui-msrv/enum_from_bytes_u8_too_few.stderr | 11 + .../tests/ui-msrv/late_compile_pass.rs | 75 + .../tests/ui-msrv/late_compile_pass.stderr | 74 + .../tests/ui-msrv/mid_compile_pass.rs | 61 + .../tests/ui-msrv/mid_compile_pass.stderr | 104 + .../rust/zerocopy-derive/tests/ui-msrv/struct.rs | 99 + .../zerocopy-derive/tests/ui-msrv/struct.stderr | 113 + .../rust/zerocopy-derive/tests/ui-msrv/union.rs | 73 + .../zerocopy-derive/tests/ui-msrv/union.stderr | 42 + .../tests/ui-nightly/derive_transparent.rs | 40 + .../tests/ui-nightly/derive_transparent.stderr | 111 + .../rust/zerocopy-derive/tests/ui-nightly/enum.rs | 194 + .../zerocopy-derive/tests/ui-nightly/enum.stderr | 201 + .../tests/ui-nightly/enum_from_bytes_u8_too_few.rs | 272 + .../ui-nightly/enum_from_bytes_u8_too_few.stderr | 11 + .../tests/ui-nightly/late_compile_pass.rs | 75 + .../tests/ui-nightly/late_compile_pass.stderr | 150 + .../tests/ui-nightly/mid_compile_pass.rs | 61 + .../tests/ui-nightly/mid_compile_pass.stderr | 104 + .../zerocopy-derive/tests/ui-nightly/struct.rs | 99 + .../zerocopy-derive/tests/ui-nightly/struct.stderr | 143 + .../rust/zerocopy-derive/tests/ui-nightly/union.rs | 73 + .../zerocopy-derive/tests/ui-nightly/union.stderr | 48 + .../tests/ui-stable/derive_transparent.rs | 40 + .../tests/ui-stable/derive_transparent.stderr | 111 + .../rust/zerocopy-derive/tests/ui-stable/enum.rs | 194 + .../zerocopy-derive/tests/ui-stable/enum.stderr | 201 + .../tests/ui-stable/enum_from_bytes_u8_too_few.rs | 272 + .../ui-stable/enum_from_bytes_u8_too_few.stderr | 11 + .../tests/ui-stable/late_compile_pass.rs | 75 + .../tests/ui-stable/late_compile_pass.stderr | 144 + .../tests/ui-stable/mid_compile_pass.rs | 61 + .../tests/ui-stable/mid_compile_pass.stderr | 104 + .../rust/zerocopy-derive/tests/ui-stable/struct.rs | 99 + .../zerocopy-derive/tests/ui-stable/struct.stderr | 131 + .../rust/zerocopy-derive/tests/ui-stable/union.rs | 73 + .../zerocopy-derive/tests/ui-stable/union.stderr | 41 + .../rust/zerocopy-derive/tests/union_as_bytes.rs | 75 + .../rust/zerocopy-derive/tests/union_from_bytes.rs | 72 + .../zerocopy-derive/tests/union_from_zeroes.rs | 72 + .../zerocopy-derive/tests/union_known_layout.rs | 65 + .../rust/zerocopy-derive/tests/union_unaligned.rs | 77 + third_party/rust/zerocopy-derive/tests/util.rs | 20 + third_party/rust/zerocopy/.cargo-checksum.json | 1 + third_party/rust/zerocopy/CONTRIBUTING.md | 215 + third_party/rust/zerocopy/Cargo.toml | 87 + third_party/rust/zerocopy/INTERNAL.md | 44 + third_party/rust/zerocopy/LICENSE-APACHE | 202 + third_party/rust/zerocopy/LICENSE-BSD | 24 + third_party/rust/zerocopy/LICENSE-MIT | 26 + third_party/rust/zerocopy/POLICIES.md | 103 + third_party/rust/zerocopy/README.md | 154 + third_party/rust/zerocopy/cargo.sh | 120 + third_party/rust/zerocopy/clippy.toml | 10 + third_party/rust/zerocopy/generate-readme.sh | 50 + third_party/rust/zerocopy/rustfmt.toml | 19 + third_party/rust/zerocopy/src/byteorder.rs | 1075 +++ third_party/rust/zerocopy/src/lib.rs | 8256 ++++++++++++++++++++ third_party/rust/zerocopy/src/macro_util.rs | 670 ++ third_party/rust/zerocopy/src/macros.rs | 417 + .../post_monomorphization_compile_fail_tests.rs | 118 + .../zerocopy/src/third_party/rust/LICENSE-APACHE | 176 + .../rust/zerocopy/src/third_party/rust/LICENSE-MIT | 23 + .../zerocopy/src/third_party/rust/README.fuchsia | 7 + .../rust/zerocopy/src/third_party/rust/layout.rs | 45 + third_party/rust/zerocopy/src/util.rs | 808 ++ third_party/rust/zerocopy/src/wrappers.rs | 503 ++ .../rust/zerocopy/testdata/include_value/data | 1 + third_party/rust/zerocopy/tests/trybuild.rs | 41 + .../tests/ui-msrv/include_value_not_from_bytes.rs | 12 + .../ui-msrv/include_value_not_from_bytes.stderr | 12 + .../tests/ui-msrv/include_value_wrong_size.rs | 11 + .../tests/ui-msrv/include_value_wrong_size.stderr | 9 + .../tests/ui-msrv/invalid-impls/invalid-impls.rs | 29 + .../ui-msrv/invalid-impls/invalid-impls.stderr | 127 + .../rust/zerocopy/tests/ui-msrv/max-align.rs | 99 + .../rust/zerocopy/tests/ui-msrv/max-align.stderr | 5 + .../tests/ui-msrv/transmute-dst-not-frombytes.rs | 18 + .../ui-msrv/transmute-dst-not-frombytes.stderr | 12 + .../ui-msrv/transmute-mut-alignment-increase.rs | 19 + .../transmute-mut-alignment-increase.stderr | 36 + .../zerocopy/tests/ui-msrv/transmute-mut-const.rs | 20 + .../tests/ui-msrv/transmute-mut-const.stderr | 41 + .../tests/ui-msrv/transmute-mut-dst-generic.rs | 18 + .../tests/ui-msrv/transmute-mut-dst-generic.stderr | 19 + .../ui-msrv/transmute-mut-dst-not-a-reference.rs | 17 + .../transmute-mut-dst-not-a-reference.stderr | 39 + .../tests/ui-msrv/transmute-mut-dst-not-asbytes.rs | 24 + .../ui-msrv/transmute-mut-dst-not-asbytes.stderr | 12 + .../ui-msrv/transmute-mut-dst-not-frombytes.rs | 24 + .../ui-msrv/transmute-mut-dst-not-frombytes.stderr | 12 + .../tests/ui-msrv/transmute-mut-dst-unsized.rs | 17 + .../tests/ui-msrv/transmute-mut-dst-unsized.stderr | 108 + .../ui-msrv/transmute-mut-illegal-lifetime.rs | 15 + .../ui-msrv/transmute-mut-illegal-lifetime.stderr | 9 + .../tests/ui-msrv/transmute-mut-size-decrease.rs | 17 + .../ui-msrv/transmute-mut-size-decrease.stderr | 36 + .../tests/ui-msrv/transmute-mut-size-increase.rs | 17 + .../ui-msrv/transmute-mut-size-increase.stderr | 36 + .../tests/ui-msrv/transmute-mut-src-dst-generic.rs | 19 + .../ui-msrv/transmute-mut-src-dst-generic.stderr | 19 + .../transmute-mut-src-dst-not-references.rs | 17 + .../transmute-mut-src-dst-not-references.stderr | 12 + .../tests/ui-msrv/transmute-mut-src-dst-unsized.rs | 17 + .../ui-msrv/transmute-mut-src-dst-unsized.stderr | 237 + .../tests/ui-msrv/transmute-mut-src-generic.rs | 18 + .../tests/ui-msrv/transmute-mut-src-generic.stderr | 10 + .../tests/ui-msrv/transmute-mut-src-immutable.rs | 18 + .../ui-msrv/transmute-mut-src-immutable.stderr | 11 + .../ui-msrv/transmute-mut-src-not-a-reference.rs | 17 + .../transmute-mut-src-not-a-reference.stderr | 12 + .../tests/ui-msrv/transmute-mut-src-not-asbytes.rs | 24 + .../ui-msrv/transmute-mut-src-not-asbytes.stderr | 25 + .../ui-msrv/transmute-mut-src-not-frombytes.rs | 24 + .../ui-msrv/transmute-mut-src-not-frombytes.stderr | 25 + .../tests/ui-msrv/transmute-mut-src-unsized.rs | 16 + .../tests/ui-msrv/transmute-mut-src-unsized.stderr | 198 + .../tests/ui-msrv/transmute-ptr-to-usize.rs | 20 + .../tests/ui-msrv/transmute-ptr-to-usize.stderr | 37 + .../ui-msrv/transmute-ref-alignment-increase.rs | 19 + .../transmute-ref-alignment-increase.stderr | 9 + .../tests/ui-msrv/transmute-ref-dst-generic.rs | 18 + .../tests/ui-msrv/transmute-ref-dst-generic.stderr | 19 + .../tests/ui-msrv/transmute-ref-dst-mutable.rs | 19 + .../tests/ui-msrv/transmute-ref-dst-mutable.stderr | 29 + .../ui-msrv/transmute-ref-dst-not-a-reference.rs | 17 + .../transmute-ref-dst-not-a-reference.stderr | 29 + .../ui-msrv/transmute-ref-dst-not-frombytes.rs | 18 + .../ui-msrv/transmute-ref-dst-not-frombytes.stderr | 12 + .../tests/ui-msrv/transmute-ref-dst-unsized.rs | 17 + .../tests/ui-msrv/transmute-ref-dst-unsized.stderr | 94 + .../ui-msrv/transmute-ref-illegal-lifetime.rs | 15 + .../ui-msrv/transmute-ref-illegal-lifetime.stderr | 9 + .../tests/ui-msrv/transmute-ref-size-decrease.rs | 17 + .../ui-msrv/transmute-ref-size-decrease.stderr | 9 + .../tests/ui-msrv/transmute-ref-size-increase.rs | 17 + .../ui-msrv/transmute-ref-size-increase.stderr | 9 + .../tests/ui-msrv/transmute-ref-src-dst-generic.rs | 19 + .../ui-msrv/transmute-ref-src-dst-generic.stderr | 19 + .../transmute-ref-src-dst-not-references.rs | 17 + .../transmute-ref-src-dst-not-references.stderr | 42 + .../tests/ui-msrv/transmute-ref-src-dst-unsized.rs | 17 + .../ui-msrv/transmute-ref-src-dst-unsized.stderr | 195 + .../tests/ui-msrv/transmute-ref-src-generic.rs | 18 + .../tests/ui-msrv/transmute-ref-src-generic.stderr | 19 + .../ui-msrv/transmute-ref-src-not-a-reference.rs | 17 + .../transmute-ref-src-not-a-reference.stderr | 12 + .../tests/ui-msrv/transmute-ref-src-not-asbytes.rs | 18 + .../ui-msrv/transmute-ref-src-not-asbytes.stderr | 25 + .../tests/ui-msrv/transmute-ref-src-unsized.rs | 16 + .../tests/ui-msrv/transmute-ref-src-unsized.stderr | 170 + .../tests/ui-msrv/transmute-size-decrease.rs | 19 + .../tests/ui-msrv/transmute-size-decrease.stderr | 9 + .../tests/ui-msrv/transmute-size-increase.rs | 19 + .../tests/ui-msrv/transmute-size-increase.stderr | 9 + .../tests/ui-msrv/transmute-src-not-asbytes.rs | 18 + .../tests/ui-msrv/transmute-src-not-asbytes.stderr | 25 + .../ui-nightly/include_value_not_from_bytes.rs | 12 + .../ui-nightly/include_value_not_from_bytes.stderr | 25 + .../tests/ui-nightly/include_value_wrong_size.rs | 11 + .../ui-nightly/include_value_wrong_size.stderr | 9 + .../ui-nightly/invalid-impls/invalid-impls.rs | 29 + .../ui-nightly/invalid-impls/invalid-impls.stderr | 107 + .../rust/zerocopy/tests/ui-nightly/max-align.rs | 99 + .../zerocopy/tests/ui-nightly/max-align.stderr | 5 + .../ui-nightly/transmute-dst-not-frombytes.rs | 18 + .../ui-nightly/transmute-dst-not-frombytes.stderr | 25 + .../ui-nightly/transmute-mut-alignment-increase.rs | 19 + .../transmute-mut-alignment-increase.stderr | 9 + .../tests/ui-nightly/transmute-mut-const.rs | 20 + .../tests/ui-nightly/transmute-mut-const.stderr | 42 + .../tests/ui-nightly/transmute-mut-dst-generic.rs | 18 + .../ui-nightly/transmute-mut-dst-generic.stderr | 19 + .../transmute-mut-dst-not-a-reference.rs | 17 + .../transmute-mut-dst-not-a-reference.stderr | 39 + .../ui-nightly/transmute-mut-dst-not-asbytes.rs | 24 + .../transmute-mut-dst-not-asbytes.stderr | 25 + .../ui-nightly/transmute-mut-dst-not-frombytes.rs | 24 + .../transmute-mut-dst-not-frombytes.stderr | 25 + .../tests/ui-nightly/transmute-mut-dst-unsized.rs | 17 + .../ui-nightly/transmute-mut-dst-unsized.stderr | 86 + .../ui-nightly/transmute-mut-illegal-lifetime.rs | 15 + .../transmute-mut-illegal-lifetime.stderr | 12 + .../ui-nightly/transmute-mut-size-decrease.rs | 17 + .../ui-nightly/transmute-mut-size-decrease.stderr | 9 + .../ui-nightly/transmute-mut-size-increase.rs | 17 + .../ui-nightly/transmute-mut-size-increase.stderr | 9 + .../ui-nightly/transmute-mut-src-dst-generic.rs | 19 + .../transmute-mut-src-dst-generic.stderr | 19 + .../transmute-mut-src-dst-not-references.rs | 17 + .../transmute-mut-src-dst-not-references.stderr | 15 + .../ui-nightly/transmute-mut-src-dst-unsized.rs | 17 + .../transmute-mut-src-dst-unsized.stderr | 231 + .../tests/ui-nightly/transmute-mut-src-generic.rs | 18 + .../ui-nightly/transmute-mut-src-generic.stderr | 10 + .../ui-nightly/transmute-mut-src-immutable.rs | 18 + .../ui-nightly/transmute-mut-src-immutable.stderr | 11 + .../transmute-mut-src-not-a-reference.rs | 17 + .../transmute-mut-src-not-a-reference.stderr | 15 + .../ui-nightly/transmute-mut-src-not-asbytes.rs | 24 + .../transmute-mut-src-not-asbytes.stderr | 48 + .../ui-nightly/transmute-mut-src-not-frombytes.rs | 24 + .../transmute-mut-src-not-frombytes.stderr | 48 + .../tests/ui-nightly/transmute-mut-src-unsized.rs | 16 + .../ui-nightly/transmute-mut-src-unsized.stderr | 158 + .../tests/ui-nightly/transmute-ptr-to-usize.rs | 20 + .../tests/ui-nightly/transmute-ptr-to-usize.stderr | 30 + .../ui-nightly/transmute-ref-alignment-increase.rs | 19 + .../transmute-ref-alignment-increase.stderr | 9 + .../tests/ui-nightly/transmute-ref-dst-generic.rs | 18 + .../ui-nightly/transmute-ref-dst-generic.stderr | 19 + .../tests/ui-nightly/transmute-ref-dst-mutable.rs | 19 + .../ui-nightly/transmute-ref-dst-mutable.stderr | 29 + .../transmute-ref-dst-not-a-reference.rs | 17 + .../transmute-ref-dst-not-a-reference.stderr | 29 + .../ui-nightly/transmute-ref-dst-not-frombytes.rs | 18 + .../transmute-ref-dst-not-frombytes.stderr | 25 + .../tests/ui-nightly/transmute-ref-dst-unsized.rs | 17 + .../ui-nightly/transmute-ref-dst-unsized.stderr | 69 + .../ui-nightly/transmute-ref-illegal-lifetime.rs | 15 + .../transmute-ref-illegal-lifetime.stderr | 12 + .../ui-nightly/transmute-ref-size-decrease.rs | 17 + .../ui-nightly/transmute-ref-size-decrease.stderr | 9 + .../ui-nightly/transmute-ref-size-increase.rs | 17 + .../ui-nightly/transmute-ref-size-increase.stderr | 9 + .../ui-nightly/transmute-ref-src-dst-generic.rs | 19 + .../transmute-ref-src-dst-generic.stderr | 19 + .../transmute-ref-src-dst-not-references.rs | 17 + .../transmute-ref-src-dst-not-references.stderr | 45 + .../ui-nightly/transmute-ref-src-dst-unsized.rs | 17 + .../transmute-ref-src-dst-unsized.stderr | 183 + .../tests/ui-nightly/transmute-ref-src-generic.rs | 18 + .../ui-nightly/transmute-ref-src-generic.stderr | 19 + .../transmute-ref-src-not-a-reference.rs | 17 + .../transmute-ref-src-not-a-reference.stderr | 15 + .../ui-nightly/transmute-ref-src-not-asbytes.rs | 18 + .../transmute-ref-src-not-asbytes.stderr | 48 + .../tests/ui-nightly/transmute-ref-src-unsized.rs | 16 + .../ui-nightly/transmute-ref-src-unsized.stderr | 127 + .../tests/ui-nightly/transmute-size-decrease.rs | 19 + .../ui-nightly/transmute-size-decrease.stderr | 9 + .../tests/ui-nightly/transmute-size-increase.rs | 19 + .../ui-nightly/transmute-size-increase.stderr | 9 + .../tests/ui-nightly/transmute-src-not-asbytes.rs | 18 + .../ui-nightly/transmute-src-not-asbytes.stderr | 48 + .../ui-stable/include_value_not_from_bytes.rs | 12 + .../ui-stable/include_value_not_from_bytes.stderr | 25 + .../tests/ui-stable/include_value_wrong_size.rs | 11 + .../ui-stable/include_value_wrong_size.stderr | 9 + .../tests/ui-stable/invalid-impls/invalid-impls.rs | 29 + .../ui-stable/invalid-impls/invalid-impls.stderr | 107 + .../rust/zerocopy/tests/ui-stable/max-align.rs | 99 + .../rust/zerocopy/tests/ui-stable/max-align.stderr | 5 + .../tests/ui-stable/transmute-dst-not-frombytes.rs | 18 + .../ui-stable/transmute-dst-not-frombytes.stderr | 25 + .../ui-stable/transmute-mut-alignment-increase.rs | 19 + .../transmute-mut-alignment-increase.stderr | 9 + .../tests/ui-stable/transmute-mut-const.rs | 20 + .../tests/ui-stable/transmute-mut-const.stderr | 41 + .../tests/ui-stable/transmute-mut-dst-generic.rs | 18 + .../ui-stable/transmute-mut-dst-generic.stderr | 19 + .../ui-stable/transmute-mut-dst-not-a-reference.rs | 17 + .../transmute-mut-dst-not-a-reference.stderr | 39 + .../ui-stable/transmute-mut-dst-not-asbytes.rs | 24 + .../ui-stable/transmute-mut-dst-not-asbytes.stderr | 25 + .../ui-stable/transmute-mut-dst-not-frombytes.rs | 24 + .../transmute-mut-dst-not-frombytes.stderr | 25 + .../tests/ui-stable/transmute-mut-dst-unsized.rs | 17 + .../ui-stable/transmute-mut-dst-unsized.stderr | 106 + .../ui-stable/transmute-mut-illegal-lifetime.rs | 15 + .../transmute-mut-illegal-lifetime.stderr | 12 + .../tests/ui-stable/transmute-mut-size-decrease.rs | 17 + .../ui-stable/transmute-mut-size-decrease.stderr | 9 + .../tests/ui-stable/transmute-mut-size-increase.rs | 17 + .../ui-stable/transmute-mut-size-increase.stderr | 9 + .../ui-stable/transmute-mut-src-dst-generic.rs | 19 + .../ui-stable/transmute-mut-src-dst-generic.stderr | 19 + .../transmute-mut-src-dst-not-references.rs | 17 + .../transmute-mut-src-dst-not-references.stderr | 15 + .../ui-stable/transmute-mut-src-dst-unsized.rs | 17 + .../ui-stable/transmute-mut-src-dst-unsized.stderr | 288 + .../tests/ui-stable/transmute-mut-src-generic.rs | 18 + .../ui-stable/transmute-mut-src-generic.stderr | 10 + .../tests/ui-stable/transmute-mut-src-immutable.rs | 18 + .../ui-stable/transmute-mut-src-immutable.stderr | 11 + .../ui-stable/transmute-mut-src-not-a-reference.rs | 17 + .../transmute-mut-src-not-a-reference.stderr | 15 + .../ui-stable/transmute-mut-src-not-asbytes.rs | 24 + .../ui-stable/transmute-mut-src-not-asbytes.stderr | 48 + .../ui-stable/transmute-mut-src-not-frombytes.rs | 24 + .../transmute-mut-src-not-frombytes.stderr | 48 + .../tests/ui-stable/transmute-mut-src-unsized.rs | 16 + .../ui-stable/transmute-mut-src-unsized.stderr | 195 + .../tests/ui-stable/transmute-ptr-to-usize.rs | 20 + .../tests/ui-stable/transmute-ptr-to-usize.stderr | 30 + .../ui-stable/transmute-ref-alignment-increase.rs | 19 + .../transmute-ref-alignment-increase.stderr | 9 + .../tests/ui-stable/transmute-ref-dst-generic.rs | 18 + .../ui-stable/transmute-ref-dst-generic.stderr | 19 + .../tests/ui-stable/transmute-ref-dst-mutable.rs | 19 + .../ui-stable/transmute-ref-dst-mutable.stderr | 29 + .../ui-stable/transmute-ref-dst-not-a-reference.rs | 17 + .../transmute-ref-dst-not-a-reference.stderr | 29 + .../ui-stable/transmute-ref-dst-not-frombytes.rs | 18 + .../transmute-ref-dst-not-frombytes.stderr | 25 + .../tests/ui-stable/transmute-ref-dst-unsized.rs | 17 + .../ui-stable/transmute-ref-dst-unsized.stderr | 89 + .../ui-stable/transmute-ref-illegal-lifetime.rs | 15 + .../transmute-ref-illegal-lifetime.stderr | 12 + .../tests/ui-stable/transmute-ref-size-decrease.rs | 17 + .../ui-stable/transmute-ref-size-decrease.stderr | 9 + .../tests/ui-stable/transmute-ref-size-increase.rs | 17 + .../ui-stable/transmute-ref-size-increase.stderr | 9 + .../ui-stable/transmute-ref-src-dst-generic.rs | 19 + .../ui-stable/transmute-ref-src-dst-generic.stderr | 19 + .../transmute-ref-src-dst-not-references.rs | 17 + .../transmute-ref-src-dst-not-references.stderr | 45 + .../ui-stable/transmute-ref-src-dst-unsized.rs | 17 + .../ui-stable/transmute-ref-src-dst-unsized.stderr | 240 + .../tests/ui-stable/transmute-ref-src-generic.rs | 18 + .../ui-stable/transmute-ref-src-generic.stderr | 19 + .../ui-stable/transmute-ref-src-not-a-reference.rs | 17 + .../transmute-ref-src-not-a-reference.stderr | 15 + .../ui-stable/transmute-ref-src-not-asbytes.rs | 18 + .../ui-stable/transmute-ref-src-not-asbytes.stderr | 48 + .../tests/ui-stable/transmute-ref-src-unsized.rs | 16 + .../ui-stable/transmute-ref-src-unsized.stderr | 164 + .../tests/ui-stable/transmute-size-decrease.rs | 19 + .../tests/ui-stable/transmute-size-decrease.stderr | 9 + .../tests/ui-stable/transmute-size-increase.rs | 19 + .../tests/ui-stable/transmute-size-increase.stderr | 9 + .../tests/ui-stable/transmute-src-not-asbytes.rs | 18 + .../ui-stable/transmute-src-not-asbytes.stderr | 48 + 1544 files changed, 84853 insertions(+), 46569 deletions(-) create mode 100644 third_party/rust/any_all_workaround/.cargo-checksum.json create mode 100644 third_party/rust/any_all_workaround/Cargo.toml create mode 100644 third_party/rust/any_all_workaround/LICENSE-APACHE create mode 100644 third_party/rust/any_all_workaround/LICENSE-MIT create mode 100644 third_party/rust/any_all_workaround/LICENSE-MIT-QCMS create mode 100644 third_party/rust/any_all_workaround/README.md create mode 100644 third_party/rust/any_all_workaround/build.rs create mode 100644 third_party/rust/any_all_workaround/src/lib.rs create mode 100644 third_party/rust/bitflags/src/tests/all.rs create mode 100644 third_party/rust/bitflags/src/tests/bits.rs create mode 100644 third_party/rust/bitflags/src/tests/complement.rs create mode 100644 third_party/rust/bitflags/src/tests/contains.rs create mode 100644 third_party/rust/bitflags/src/tests/difference.rs create mode 100644 third_party/rust/bitflags/src/tests/empty.rs create mode 100644 third_party/rust/bitflags/src/tests/eq.rs create mode 100644 third_party/rust/bitflags/src/tests/extend.rs create mode 100644 third_party/rust/bitflags/src/tests/flags.rs create mode 100644 third_party/rust/bitflags/src/tests/fmt.rs create mode 100644 third_party/rust/bitflags/src/tests/from_bits.rs create mode 100644 third_party/rust/bitflags/src/tests/from_bits_retain.rs create mode 100644 third_party/rust/bitflags/src/tests/from_bits_truncate.rs create mode 100644 third_party/rust/bitflags/src/tests/from_name.rs create mode 100644 third_party/rust/bitflags/src/tests/insert.rs create mode 100644 third_party/rust/bitflags/src/tests/intersection.rs create mode 100644 third_party/rust/bitflags/src/tests/intersects.rs create mode 100644 third_party/rust/bitflags/src/tests/is_all.rs create mode 100644 third_party/rust/bitflags/src/tests/is_empty.rs create mode 100644 third_party/rust/bitflags/src/tests/iter.rs create mode 100644 third_party/rust/bitflags/src/tests/parser.rs create mode 100644 third_party/rust/bitflags/src/tests/remove.rs create mode 100644 third_party/rust/bitflags/src/tests/symmetric_difference.rs create mode 100644 third_party/rust/bitflags/src/tests/union.rs delete mode 100644 third_party/rust/core-foundation-sys/build.rs create mode 100644 third_party/rust/core-foundation-sys/src/bag.rs create mode 100644 third_party/rust/core-foundation-sys/src/binary_heap.rs create mode 100644 third_party/rust/core-foundation-sys/src/bit_vector.rs create mode 100644 third_party/rust/core-foundation-sys/src/calendar.rs create mode 100644 third_party/rust/core-foundation-sys/src/date_formatter.rs create mode 100644 third_party/rust/core-foundation-sys/src/file_security.rs create mode 100644 third_party/rust/core-foundation-sys/src/locale.rs create mode 100644 third_party/rust/core-foundation-sys/src/notification_center.rs create mode 100644 third_party/rust/core-foundation-sys/src/number_formatter.rs create mode 100644 third_party/rust/core-foundation-sys/src/plugin.rs create mode 100644 third_party/rust/core-foundation-sys/src/preferences.rs create mode 100644 third_party/rust/core-foundation-sys/src/socket.rs create mode 100644 third_party/rust/core-foundation-sys/src/stream.rs create mode 100644 third_party/rust/core-foundation-sys/src/string_tokenizer.rs create mode 100644 third_party/rust/core-foundation-sys/src/tree.rs create mode 100644 third_party/rust/core-foundation-sys/src/url_enumerator.rs create mode 100644 third_party/rust/core-foundation-sys/src/user_notification.rs create mode 100644 third_party/rust/core-foundation-sys/src/xml_node.rs create mode 100644 third_party/rust/core-foundation-sys/src/xml_parser.rs create mode 100644 third_party/rust/core-graphics-types/LICENSE-APACHE create mode 100644 third_party/rust/core-graphics-types/LICENSE-MIT delete mode 100644 third_party/rust/cssparser/.github/workflows/main.yml delete mode 100644 third_party/rust/cssparser/docs/.nojekyll create mode 100644 third_party/rust/equivalent/.cargo-checksum.json create mode 100644 third_party/rust/equivalent/Cargo.toml create mode 100644 third_party/rust/equivalent/LICENSE-APACHE create mode 100644 third_party/rust/equivalent/LICENSE-MIT create mode 100644 third_party/rust/equivalent/README.md create mode 100644 third_party/rust/equivalent/src/lib.rs create mode 100644 third_party/rust/fallible_collections/src/try_reserve_error.rs create mode 100644 third_party/rust/getrandom/src/lazy.rs create mode 100644 third_party/rust/getrandom/src/linux_android_with_fallback.rs delete mode 100644 third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs create mode 100644 third_party/rust/glean-core/src/metrics/remote_settings_config.rs create mode 100644 third_party/rust/hashbrown/src/external_trait_impls/rayon/table.rs create mode 100644 third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_map.rs create mode 100644 third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_set.rs create mode 100644 third_party/rust/hashbrown/src/external_trait_impls/rkyv/mod.rs create mode 100644 third_party/rust/hashbrown/src/raw/neon.rs create mode 100644 third_party/rust/hashbrown/src/table.rs create mode 100644 third_party/rust/hashbrown/tests/equivalent_trait.rs create mode 100644 third_party/rust/hashbrown/tests/raw.rs delete mode 100644 third_party/rust/indexmap/build.rs create mode 100644 third_party/rust/indexmap/src/borsh.rs delete mode 100644 third_party/rust/indexmap/src/equivalent.rs create mode 100644 third_party/rust/indexmap/src/map/core/entry.rs create mode 100644 third_party/rust/indexmap/src/map/core/raw_entry_v1.rs create mode 100644 third_party/rust/indexmap/src/map/iter.rs create mode 100644 third_party/rust/indexmap/src/map/mutable.rs create mode 100644 third_party/rust/indexmap/src/map/serde_seq.rs create mode 100644 third_party/rust/indexmap/src/map/slice.rs create mode 100644 third_party/rust/indexmap/src/map/tests.rs delete mode 100644 third_party/rust/indexmap/src/mutable_keys.rs delete mode 100644 third_party/rust/indexmap/src/serde_seq.rs create mode 100644 third_party/rust/indexmap/src/set/iter.rs create mode 100644 third_party/rust/indexmap/src/set/mutable.rs create mode 100644 third_party/rust/indexmap/src/set/slice.rs create mode 100644 third_party/rust/indexmap/src/set/tests.rs create mode 100644 third_party/rust/interrupt-support/build.rs create mode 100644 third_party/rust/interrupt-support/src/interrupt_support.udl create mode 100644 third_party/rust/naga/src/back/pipeline_constants.rs create mode 100644 third_party/rust/naga/src/back/spv/subgroup.rs create mode 100644 third_party/rust/naga/src/error.rs create mode 100644 third_party/rust/neqo-common/src/fuzz.rs create mode 100644 third_party/rust/neqo-transport/src/connection/tests/ecn.rs create mode 100644 third_party/rust/neqo-transport/src/ecn.rs create mode 100644 third_party/rust/nix/build.rs create mode 100644 third_party/rust/nix/src/poll_timeout.rs create mode 100644 third_party/rust/nix/src/sys/fanotify.rs create mode 100644 third_party/rust/nix/test/sys/test_event.rs create mode 100644 third_party/rust/nix/test/sys/test_fanotify.rs create mode 100644 third_party/rust/nix/test/sys/test_resource.rs create mode 100644 third_party/rust/nix/test/sys/test_statfs.rs create mode 100644 third_party/rust/nix/test/sys/test_statvfs.rs create mode 100644 third_party/rust/nix/test/sys/test_time.rs create mode 100644 third_party/rust/nix/test/sys/test_timer.rs create mode 100644 third_party/rust/nix/test/sys/test_utsname.rs create mode 100644 third_party/rust/nix/test/test_errno.rs delete mode 100644 third_party/rust/nix/test/test_resource.rs delete mode 100644 third_party/rust/nix/test/test_timer.rs delete mode 100644 third_party/rust/objc_exception/.cargo-checksum.json delete mode 100644 third_party/rust/objc_exception/Cargo.toml delete mode 100644 third_party/rust/objc_exception/build.rs delete mode 100644 third_party/rust/objc_exception/extern/exception.m delete mode 100644 third_party/rust/objc_exception/src/lib.rs delete mode 100644 third_party/rust/owning_ref/.cargo-checksum.json delete mode 100644 third_party/rust/owning_ref/CHANGELOG.md delete mode 100644 third_party/rust/owning_ref/Cargo.toml delete mode 100644 third_party/rust/owning_ref/LICENSE delete mode 100644 third_party/rust/owning_ref/README.md delete mode 100644 third_party/rust/owning_ref/src/lib.rs delete mode 100644 third_party/rust/packed_simd/.cargo-checksum.json delete mode 100644 third_party/rust/packed_simd/Cargo.toml delete mode 100644 third_party/rust/packed_simd/LICENSE-APACHE delete mode 100644 third_party/rust/packed_simd/LICENSE-MIT delete mode 100644 third_party/rust/packed_simd/README.md delete mode 100644 third_party/rust/packed_simd/bors.toml delete mode 100644 third_party/rust/packed_simd/build.rs delete mode 100755 third_party/rust/packed_simd/ci/all.sh delete mode 100644 third_party/rust/packed_simd/ci/android-install-ndk.sh delete mode 100644 third_party/rust/packed_simd/ci/android-install-sdk.sh delete mode 100644 third_party/rust/packed_simd/ci/android-sysimage.sh delete mode 100755 third_party/rust/packed_simd/ci/benchmark.sh delete mode 100644 third_party/rust/packed_simd/ci/deploy_and_run_on_ios_simulator.rs delete mode 100644 third_party/rust/packed_simd/ci/docker/aarch64-linux-android/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/aarch64-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabi/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/armv7-linux-androideabi/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/i586-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/i686-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/mips-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/mipsel-unknown-linux-musl/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/powerpc-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/s390x-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/sparc64-unknown-linux-gnu/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/thumbv7neon-linux-androideabi/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/thumbv7neon-unknown-linux-gnueabihf/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/wasm32-unknown-unknown/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/x86_64-linux-android/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu-emulated/Dockerfile delete mode 100644 third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu/Dockerfile delete mode 100755 third_party/rust/packed_simd/ci/dox.sh delete mode 100644 third_party/rust/packed_simd/ci/linux-s390x.sh delete mode 100644 third_party/rust/packed_simd/ci/linux-sparc64.sh delete mode 100644 third_party/rust/packed_simd/ci/lld-shim.rs delete mode 100755 third_party/rust/packed_simd/ci/max_line_width.sh delete mode 100755 third_party/rust/packed_simd/ci/run-docker.sh delete mode 100755 third_party/rust/packed_simd/ci/run.sh delete mode 100644 third_party/rust/packed_simd/ci/run_examples.sh delete mode 100644 third_party/rust/packed_simd/ci/runtest-android.rs delete mode 100755 third_party/rust/packed_simd/ci/setup_benchmarks.sh delete mode 100755 third_party/rust/packed_simd/ci/test-runner-linux delete mode 100644 third_party/rust/packed_simd/contributing.md delete mode 100644 third_party/rust/packed_simd/perf-guide/book.toml delete mode 100644 third_party/rust/packed_simd/perf-guide/src/SUMMARY.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/ascii.css delete mode 100644 third_party/rust/packed_simd/perf-guide/src/bound_checks.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/float-math/approx.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/float-math/fma.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/float-math/fp.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/float-math/svml.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/introduction.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/prof/linux.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/prof/mca.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/prof/profiling.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/target-feature/attribute.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/target-feature/features.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/target-feature/inlining.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/target-feature/practice.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/target-feature/runtime.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/target-feature/rustflags.md delete mode 100644 third_party/rust/packed_simd/perf-guide/src/vert-hor-ops.md delete mode 100644 third_party/rust/packed_simd/rust-toolchain delete mode 100644 third_party/rust/packed_simd/rustfmt.toml delete mode 100644 third_party/rust/packed_simd/src/api.rs delete mode 100644 third_party/rust/packed_simd/src/api/bit_manip.rs delete mode 100644 third_party/rust/packed_simd/src/api/bitmask.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast/macros.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast/v128.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast/v16.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast/v256.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast/v32.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast/v512.rs delete mode 100644 third_party/rust/packed_simd/src/api/cast/v64.rs delete mode 100644 third_party/rust/packed_simd/src/api/cmp.rs delete mode 100644 third_party/rust/packed_simd/src/api/cmp/eq.rs delete mode 100644 third_party/rust/packed_simd/src/api/cmp/ord.rs delete mode 100644 third_party/rust/packed_simd/src/api/cmp/partial_eq.rs delete mode 100644 third_party/rust/packed_simd/src/api/cmp/partial_ord.rs delete mode 100644 third_party/rust/packed_simd/src/api/cmp/vertical.rs delete mode 100644 third_party/rust/packed_simd/src/api/default.rs delete mode 100644 third_party/rust/packed_simd/src/api/fmt.rs delete mode 100644 third_party/rust/packed_simd/src/api/fmt/binary.rs delete mode 100644 third_party/rust/packed_simd/src/api/fmt/debug.rs delete mode 100644 third_party/rust/packed_simd/src/api/fmt/lower_hex.rs delete mode 100644 third_party/rust/packed_simd/src/api/fmt/octal.rs delete mode 100644 third_party/rust/packed_simd/src/api/fmt/upper_hex.rs delete mode 100644 third_party/rust/packed_simd/src/api/from.rs delete mode 100644 third_party/rust/packed_simd/src/api/from/from_array.rs delete mode 100644 third_party/rust/packed_simd/src/api/from/from_vector.rs delete mode 100644 third_party/rust/packed_simd/src/api/hash.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/arch_specific.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/macros.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/v128.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/v16.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/v256.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/v32.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/v512.rs delete mode 100644 third_party/rust/packed_simd/src/api/into_bits/v64.rs delete mode 100644 third_party/rust/packed_simd/src/api/math.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/abs.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/consts.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/cos.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/exp.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/ln.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/mul_add.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/mul_adde.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/powf.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/recpre.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/rsqrte.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/sin.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/sqrt.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/sqrte.rs delete mode 100644 third_party/rust/packed_simd/src/api/math/float/tanh.rs delete mode 100644 third_party/rust/packed_simd/src/api/minimal.rs delete mode 100644 third_party/rust/packed_simd/src/api/minimal/iuf.rs delete mode 100644 third_party/rust/packed_simd/src/api/minimal/mask.rs delete mode 100644 third_party/rust/packed_simd/src/api/minimal/ptr.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/scalar_arithmetic.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/scalar_bitwise.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/scalar_mask_bitwise.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/scalar_shifts.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_arithmetic.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_bitwise.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_float_min_max.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_int_min_max.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_mask_bitwise.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_neg.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_rotates.rs delete mode 100644 third_party/rust/packed_simd/src/api/ops/vector_shifts.rs delete mode 100644 third_party/rust/packed_simd/src/api/ptr.rs delete mode 100644 third_party/rust/packed_simd/src/api/ptr/gather_scatter.rs delete mode 100644 third_party/rust/packed_simd/src/api/reductions.rs delete mode 100644 third_party/rust/packed_simd/src/api/reductions/bitwise.rs delete mode 100644 third_party/rust/packed_simd/src/api/reductions/float_arithmetic.rs delete mode 100644 third_party/rust/packed_simd/src/api/reductions/integer_arithmetic.rs delete mode 100644 third_party/rust/packed_simd/src/api/reductions/mask.rs delete mode 100644 third_party/rust/packed_simd/src/api/reductions/min_max.rs delete mode 100644 third_party/rust/packed_simd/src/api/select.rs delete mode 100644 third_party/rust/packed_simd/src/api/shuffle.rs delete mode 100644 third_party/rust/packed_simd/src/api/shuffle1_dyn.rs delete mode 100644 third_party/rust/packed_simd/src/api/slice.rs delete mode 100644 third_party/rust/packed_simd/src/api/slice/from_slice.rs delete mode 100644 third_party/rust/packed_simd/src/api/slice/write_to_slice.rs delete mode 100644 third_party/rust/packed_simd/src/api/swap_bytes.rs delete mode 100644 third_party/rust/packed_simd/src/codegen.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/bit_manip.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/llvm.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/abs.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/cos.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/cos_pi.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/exp.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/ln.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/macros.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/mul_add.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/mul_adde.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/powf.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/sin.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/sin_cos_pi.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/sin_pi.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/sqrt.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/sqrte.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/math/float/tanh.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/pointer_sized_int.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/aarch64.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/arm.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/fallback.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/fallback_impl.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/x86.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx2.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse2.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/shuffle.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/shuffle1_dyn.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/swap_bytes.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/v128.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/v16.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/v256.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/v32.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/v512.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/v64.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/vPtr.rs delete mode 100644 third_party/rust/packed_simd/src/codegen/vSize.rs delete mode 100644 third_party/rust/packed_simd/src/lib.rs delete mode 100644 third_party/rust/packed_simd/src/masks.rs delete mode 100644 third_party/rust/packed_simd/src/sealed.rs delete mode 100644 third_party/rust/packed_simd/src/testing.rs delete mode 100644 third_party/rust/packed_simd/src/testing/macros.rs delete mode 100644 third_party/rust/packed_simd/src/testing/utils.rs delete mode 100644 third_party/rust/packed_simd/src/v128.rs delete mode 100644 third_party/rust/packed_simd/src/v16.rs delete mode 100644 third_party/rust/packed_simd/src/v256.rs delete mode 100644 third_party/rust/packed_simd/src/v32.rs delete mode 100644 third_party/rust/packed_simd/src/v512.rs delete mode 100644 third_party/rust/packed_simd/src/v64.rs delete mode 100644 third_party/rust/packed_simd/src/vPtr.rs delete mode 100644 third_party/rust/packed_simd/src/vSize.rs delete mode 100644 third_party/rust/packed_simd/tests/endianness.rs create mode 100755 third_party/rust/prio/documentation/field_parameters.sage delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json delete mode 100644 third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json create mode 100644 third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json create mode 100644 third_party/rust/prio/src/vidpf.rs create mode 100644 third_party/rust/relevancy/src/ingest.rs delete mode 100644 third_party/rust/relevancy/src/populate_interests.rs create mode 100644 third_party/rust/relevancy/src/rs.rs delete mode 100644 third_party/rust/serde_json/src/features_check/error.rs delete mode 100644 third_party/rust/serde_json/src/features_check/mod.rs create mode 100644 third_party/rust/serde_json/tests/regression/issue1004.rs create mode 100644 third_party/rust/sql-support/src/lazy.rs delete mode 100644 third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json delete mode 100644 third_party/rust/uniffi-example-arithmetic/Cargo.toml delete mode 100644 third_party/rust/uniffi-example-arithmetic/build.rs delete mode 100644 third_party/rust/uniffi-example-arithmetic/src/arithmetic.udl delete mode 100644 third_party/rust/uniffi-example-arithmetic/src/lib.rs delete mode 100644 third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.kts delete mode 100644 third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.py delete mode 100644 third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.rb delete mode 100644 third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.swift delete mode 100644 third_party/rust/uniffi-example-arithmetic/tests/test_generated_bindings.rs delete mode 100644 third_party/rust/uniffi-example-arithmetic/uniffi.toml delete mode 100644 third_party/rust/uniffi-example-geometry/.cargo-checksum.json delete mode 100644 third_party/rust/uniffi-example-geometry/Cargo.toml delete mode 100644 third_party/rust/uniffi-example-geometry/build.rs delete mode 100644 third_party/rust/uniffi-example-geometry/src/geometry.udl delete mode 100644 third_party/rust/uniffi-example-geometry/src/lib.rs delete mode 100644 third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.kts delete mode 100644 third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py delete mode 100644 third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb delete mode 100644 third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.swift delete mode 100644 third_party/rust/uniffi-example-geometry/tests/test_generated_bindings.rs delete mode 100644 third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json delete mode 100644 third_party/rust/uniffi-example-rondpoint/Cargo.toml delete mode 100644 third_party/rust/uniffi-example-rondpoint/build.rs delete mode 100644 third_party/rust/uniffi-example-rondpoint/src/lib.rs delete mode 100644 third_party/rust/uniffi-example-rondpoint/src/rondpoint.udl delete mode 100644 third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.kts delete mode 100644 third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py delete mode 100644 third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb delete mode 100644 third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.swift delete mode 100644 third_party/rust/uniffi-example-rondpoint/tests/test_generated_bindings.rs delete mode 100644 third_party/rust/uniffi-example-sprites/.cargo-checksum.json delete mode 100644 third_party/rust/uniffi-example-sprites/Cargo.toml delete mode 100644 third_party/rust/uniffi-example-sprites/build.rs delete mode 100644 third_party/rust/uniffi-example-sprites/src/lib.rs delete mode 100644 third_party/rust/uniffi-example-sprites/src/sprites.udl delete mode 100644 third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.kts delete mode 100644 third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py delete mode 100644 third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb delete mode 100644 third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.swift delete mode 100644 third_party/rust/uniffi-example-sprites/tests/test_generated_bindings.rs delete mode 100644 third_party/rust/uniffi-example-todolist/.cargo-checksum.json delete mode 100644 third_party/rust/uniffi-example-todolist/Cargo.toml delete mode 100644 third_party/rust/uniffi-example-todolist/build.rs delete mode 100644 third_party/rust/uniffi-example-todolist/src/lib.rs delete mode 100644 third_party/rust/uniffi-example-todolist/src/todolist.udl delete mode 100644 third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts delete mode 100644 third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py delete mode 100644 third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb delete mode 100644 third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift delete mode 100644 third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs delete mode 100644 third_party/rust/wgpu-core/src/any_surface.rs create mode 100644 third_party/rust/wgpu-core/src/command/allocator.rs create mode 100644 third_party/rust/wgpu-core/src/command/compute_command.rs create mode 100644 third_party/rust/wgpu-core/src/lock/mod.rs create mode 100644 third_party/rust/wgpu-core/src/lock/rank.rs create mode 100644 third_party/rust/wgpu-core/src/lock/ranked.rs create mode 100644 third_party/rust/wgpu-core/src/lock/vanilla.rs create mode 100644 third_party/rust/zerocopy-derive/.cargo-checksum.json create mode 100644 third_party/rust/zerocopy-derive/Cargo.toml create mode 100644 third_party/rust/zerocopy-derive/LICENSE-APACHE create mode 100644 third_party/rust/zerocopy-derive/LICENSE-BSD create mode 100644 third_party/rust/zerocopy-derive/LICENSE-MIT create mode 100644 third_party/rust/zerocopy-derive/src/ext.rs create mode 100644 third_party/rust/zerocopy-derive/src/lib.rs create mode 100644 third_party/rust/zerocopy-derive/src/repr.rs create mode 100644 third_party/rust/zerocopy-derive/tests/enum_as_bytes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/enum_from_zeroes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/enum_known_layout.rs create mode 100644 third_party/rust/zerocopy-derive/tests/enum_unaligned.rs create mode 100644 third_party/rust/zerocopy-derive/tests/hygiene.rs create mode 100644 third_party/rust/zerocopy-derive/tests/paths_and_modules.rs create mode 100644 third_party/rust/zerocopy-derive/tests/priv_in_pub.rs create mode 100644 third_party/rust/zerocopy-derive/tests/struct_as_bytes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/struct_from_bytes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/struct_from_zeroes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/struct_known_layout.rs create mode 100644 third_party/rust/zerocopy-derive/tests/struct_unaligned.rs create mode 100644 third_party/rust/zerocopy-derive/tests/trybuild.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/enum.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/enum.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/struct.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/struct.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/union.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-msrv/union.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/enum.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/enum.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/struct.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/struct.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/union.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-nightly/union.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/enum.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/enum.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/struct.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/struct.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/union.rs create mode 100644 third_party/rust/zerocopy-derive/tests/ui-stable/union.stderr create mode 100644 third_party/rust/zerocopy-derive/tests/union_as_bytes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/union_from_bytes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/union_from_zeroes.rs create mode 100644 third_party/rust/zerocopy-derive/tests/union_known_layout.rs create mode 100644 third_party/rust/zerocopy-derive/tests/union_unaligned.rs create mode 100644 third_party/rust/zerocopy-derive/tests/util.rs create mode 100644 third_party/rust/zerocopy/.cargo-checksum.json create mode 100644 third_party/rust/zerocopy/CONTRIBUTING.md create mode 100644 third_party/rust/zerocopy/Cargo.toml create mode 100644 third_party/rust/zerocopy/INTERNAL.md create mode 100644 third_party/rust/zerocopy/LICENSE-APACHE create mode 100644 third_party/rust/zerocopy/LICENSE-BSD create mode 100644 third_party/rust/zerocopy/LICENSE-MIT create mode 100644 third_party/rust/zerocopy/POLICIES.md create mode 100644 third_party/rust/zerocopy/README.md create mode 100755 third_party/rust/zerocopy/cargo.sh create mode 100644 third_party/rust/zerocopy/clippy.toml create mode 100755 third_party/rust/zerocopy/generate-readme.sh create mode 100644 third_party/rust/zerocopy/rustfmt.toml create mode 100644 third_party/rust/zerocopy/src/byteorder.rs create mode 100644 third_party/rust/zerocopy/src/lib.rs create mode 100644 third_party/rust/zerocopy/src/macro_util.rs create mode 100644 third_party/rust/zerocopy/src/macros.rs create mode 100644 third_party/rust/zerocopy/src/post_monomorphization_compile_fail_tests.rs create mode 100644 third_party/rust/zerocopy/src/third_party/rust/LICENSE-APACHE create mode 100644 third_party/rust/zerocopy/src/third_party/rust/LICENSE-MIT create mode 100644 third_party/rust/zerocopy/src/third_party/rust/README.fuchsia create mode 100644 third_party/rust/zerocopy/src/third_party/rust/layout.rs create mode 100644 third_party/rust/zerocopy/src/util.rs create mode 100644 third_party/rust/zerocopy/src/wrappers.rs create mode 100644 third_party/rust/zerocopy/testdata/include_value/data create mode 100644 third_party/rust/zerocopy/tests/trybuild.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/max-align.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/max-align.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/max-align.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/max-align.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/max-align.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/max-align.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.stderr create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.rs create mode 100644 third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.stderr (limited to 'third_party/rust') diff --git a/third_party/rust/ahash/.cargo-checksum.json b/third_party/rust/ahash/.cargo-checksum.json index d2fa45cb86..f72f808ffc 100644 --- a/third_party/rust/ahash/.cargo-checksum.json +++ b/third_party/rust/ahash/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"a519809f46c9aad28d6c48748f330fe31e05029d234b6d1743522ec403441744","FAQ.md":"9eb41898523ee209a0a937f9bcb78afe45ad55ca0556f8a4d4063558098f6d1e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"72185284f100e149998fe5301f70489e617cc4415b51cc77e967c63c6e970a67","build.rs":"f80cb1cdb731a63d16513f1f0b0871d9c077d2c6bf2312af40a202f9c0fefe49","rustfmt.toml":"e090969e99df9360705680cc0097cfaddae10c22dc2e01470592cf3b9787fd36","src/aes_hash.rs":"0b11ce066931396222d2bed7eff678fdd7c8351819485efb721f62a30551866b","src/convert.rs":"f0e78840046493d0679a9ec077c8164cf57cf30d5e852b11bfadfdd996d29bd1","src/fallback_hash.rs":"ec00691bd555c69f7446afe893b6631cb84207cb7b512260dec8ef488e1905f3","src/hash_map.rs":"ed0c79c41c2218ad9591a585670a2b9b983807c9725880b780138a44c126cbfd","src/hash_quality_test.rs":"61695e5cac46ea25021a9d04199fb00c513e0c0c9c0f67aca0c647b9d2f7dd5a","src/hash_set.rs":"dc3d33e290aad62457ab1f5e64d3e33eb79e28c9468bfc8686339f0bbd8b19aa","src/lib.rs":"9fec7d1d412e414231c9b929081b1daa7c3b788a9f91eedd79a55efdf5d0d291","src/operations.rs":"10772e65b8b7106f195428c5eb8dbf6cbd49dd5a2165ac750e54af5995210f88","src/random_state.rs":"ce9689147659efa975887debe1481daddca09386ea8e1d5b4ee90ebeda6c8745","src/specialize.rs":"38d3b56ef4f264d564f48dbcb8ac137928babf90635090c9771c1a62140d1f30","tests/bench.rs":"0851dffebaffd7a437f6f9946ed5e03a957e9a6eb0da7911451af58778c411ec","tests/map_tests.rs":"e0f155f964dd965740b072ee1da110a8c6ef34491c95219f7c89064112c7840f","tests/nopanic.rs":"3363675c4c1a197b86604a0aebbe958fb5ec7c01a414fbfd70e9eb8a29707400"},"package":"891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"} \ No newline at end of file +{"files":{"Cargo.toml":"ddcbd9309cebf3ffd26f87e09bb8f971793535955ebfd9a7196eba31a53471f8","FAQ.md":"9eb41898523ee209a0a937f9bcb78afe45ad55ca0556f8a4d4063558098f6d1e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0444c6991eead6822f7b9102e654448d51624431119546492e8b231db42c48bb","README.md":"d7f74d616a751bcca23d5d3b58a6daf556356a526c5f0b6aa0504715d176549a","build.rs":"23cbf4cf1b742e2c4da8bc58d06d1d021479dec80cec6a0bc3704c7172e2864a","rustfmt.toml":"e090969e99df9360705680cc0097cfaddae10c22dc2e01470592cf3b9787fd36","src/aes_hash.rs":"013602aec42150e59ba9ed6135525a624a4b42c1b1328b9857ec238aa12c3178","src/convert.rs":"54e49f93d51665366923d4d815cfd67790d3c769e84ab4386ba97f928d17d1bd","src/fallback_hash.rs":"a82451f6458a6e7a7e7da82a3c982e9bb825a2092ab79c41459d8011775fb0b1","src/hash_map.rs":"5ee97baa64fa528ba9c01bd018332c4974846c4813c6f8c30cee9f3546598f1c","src/hash_quality_test.rs":"1a560a181a804791bc6ad797df5352cdd87123fed7f19f659de0c2d883248bed","src/hash_set.rs":"360e55d066b44624f06e49efa140c03fda635fb17a59622cc29a83830bd1f263","src/lib.rs":"e2f4e7bfcf2807c73e3b8d3b1bd83c6789313b6b55edd59e15e04146e55e01b6","src/operations.rs":"38ed2b48a13d826c48ede5f304c9c2572c0c8f64ac8ac5a1ed4e112e536f3a97","src/random_state.rs":"03f40a654cfca2e00a2dabd21c85368ee50b8b6289efe98ea1745b25c721b9c6","src/specialize.rs":"56354db8a0f7e6ee1340a08f2ab6f79a0ff439fd61badac5e7e59fe4f4a653ba","tests/bench.rs":"7a425f564201560f9a8fb6c77f91f29bb88ec815b10bd27d15740c922a4f928e","tests/map_tests.rs":"e56b6f700e3b1176210e4b266d7a42b3263e966e5e565d53b1bc27af7a87168e","tests/nopanic.rs":"0d28a46248d77283941db1d9fd154c68b965c81a0e3db1fe4a43e06fc448da8f"},"package":"e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"} \ No newline at end of file diff --git a/third_party/rust/ahash/Cargo.toml b/third_party/rust/ahash/Cargo.toml index 5830a500d9..279954f9a7 100644 --- a/third_party/rust/ahash/Cargo.toml +++ b/third_party/rust/ahash/Cargo.toml @@ -11,8 +11,9 @@ [package] edition = "2018" +rust-version = "1.60.0" name = "ahash" -version = "0.7.8" +version = "0.8.11" authors = ["Tom Kaitchuck "] build = "./build.rs" exclude = [ @@ -84,8 +85,33 @@ name = "map" path = "tests/map_tests.rs" harness = false +[dependencies.atomic-polyfill] +version = "1.0.1" +optional = true + +[dependencies.cfg-if] +version = "1.0" + +[dependencies.const-random] +version = "0.1.17" +optional = true + +[dependencies.getrandom] +version = "0.2.7" +optional = true + +[dependencies.serde] +version = "1.0.117" +optional = true + +[dependencies.zerocopy] +version = "0.7.31" +features = ["simd"] +default-features = false + [dev-dependencies.criterion] version = "0.3.2" +features = ["html_reports"] [dev-dependencies.fnv] version = "1.0.5" @@ -93,14 +119,20 @@ version = "1.0.5" [dev-dependencies.fxhash] version = "0.2.1" +[dev-dependencies.hashbrown] +version = "0.14.3" + [dev-dependencies.hex] version = "0.4.2" [dev-dependencies.no-panic] version = "0.1.10" +[dev-dependencies.pcg-mwc] +version = "0.2.1" + [dev-dependencies.rand] -version = "0.7.3" +version = "0.8.5" [dev-dependencies.seahash] version = "4.0" @@ -108,8 +140,11 @@ version = "4.0" [dev-dependencies.serde_json] version = "1.0.59" +[dev-dependencies.smallvec] +version = "1.13.1" + [build-dependencies.version_check] -version = "0.9" +version = "0.9.4" [features] atomic-polyfill = [ @@ -117,33 +152,16 @@ atomic-polyfill = [ "once_cell/atomic-polyfill", ] compile-time-rng = ["const-random"] -default = ["std"] +default = [ + "std", + "runtime-rng", +] +nightly-arm-aes = [] +no-rng = [] +runtime-rng = ["getrandom"] std = [] -[target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.const-random] -version = "0.1.12" -optional = true - -[target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.getrandom] -version = "0.2.3" - -[target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.serde] -version = "1.0.117" -optional = true - [target."cfg(not(all(target_arch = \"arm\", target_os = \"none\")))".dependencies.once_cell] -version = "1.13.1" +version = "1.18.0" features = ["alloc"] default-features = false - -[target."cfg(not(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\")))".dependencies.atomic-polyfill] -version = "1.0.1" -optional = true - -[target."cfg(not(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\")))".dependencies.const-random] -version = "0.1.12" -optional = true - -[target."cfg(not(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\")))".dependencies.serde] -version = "1.0.117" -optional = true diff --git a/third_party/rust/ahash/LICENSE-MIT b/third_party/rust/ahash/LICENSE-MIT index 5afc2a7b0a..cba20106dd 100644 --- a/third_party/rust/ahash/LICENSE-MIT +++ b/third_party/rust/ahash/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2016 Amanieu d'Antras +Copyright (c) 2018 Tom Kaitchuck Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/third_party/rust/ahash/README.md b/third_party/rust/ahash/README.md index be365a79f1..aa071cf51d 100644 --- a/third_party/rust/ahash/README.md +++ b/third_party/rust/ahash/README.md @@ -1,4 +1,4 @@ -# aHash ![Build Status](https://img.shields.io/github/workflow/status/tkaitchuck/ahash/Rust) ![Licence](https://img.shields.io/crates/l/ahash) ![Downloads](https://img.shields.io/crates/d/ahash) +# aHash ![Build Status](https://img.shields.io/github/actions/workflow/status/tkaitchuck/aHash/rust.yml?branch=master) ![Licence](https://img.shields.io/crates/l/ahash) ![Downloads](https://img.shields.io/crates/d/ahash) AHash is the [fastest](https://github.com/tkaitchuck/aHash/blob/master/compare/readme.md#Speed), [DOS resistant hash](https://github.com/tkaitchuck/aHash/wiki/How-aHash-is-resists-DOS-attacks) currently available in Rust. @@ -53,18 +53,17 @@ map.insert(56, 78); The aHash package has the following flags: * `std`: This enables features which require the standard library. (On by default) This includes providing the utility classes `AHashMap` and `AHashSet`. * `serde`: Enables `serde` support for the utility classes `AHashMap` and `AHashSet`. -* `compile-time-rng`: Whenever possible aHash will seed hashers with random numbers using the [getrandom](https://github.com/rust-random/getrandom) crate. -This is possible for OS targets which provide a source of randomness. (see the [full list](https://docs.rs/getrandom/0.2.0/getrandom/#supported-targets).) -For OS targets without access to a random number generator, `compile-time-rng` provides an alternative. +* `runtime-rng`: To obtain a seed for Hashers will obtain randomness from the operating system. (On by default) +This is done using the [getrandom](https://github.com/rust-random/getrandom) crate. +* `compile-time-rng`: For OS targets without access to a random number generator, `compile-time-rng` provides an alternative. If `getrandom` is unavailable and `compile-time-rng` is enabled, aHash will generate random numbers at compile time and embed them in the binary. +* `nightly-arm-aes`: To use AES instructions on 32-bit ARM, which requires nightly. This is not needed on AArch64. This allows for DOS resistance even if there is no random number generator available at runtime (assuming the compiled binary is not public). -This makes the binary non-deterministic, unless `getrandom` is available for the target in which case the flag does nothing. -(If non-determinism is a problem see [constrandom's documentation](https://github.com/tkaitchuck/constrandom#deterministic-builds)) +This makes the binary non-deterministic. (If non-determinism is a problem see [constrandom's documentation](https://github.com/tkaitchuck/constrandom#deterministic-builds)) -**NOTE:** If `getrandom` is unavailable and `compile-time-rng` is disabled aHash will fall back on using the numeric -value of memory addresses as a source of randomness. This is somewhat strong if ALSR is turned on (it is by default) -but for embedded platforms this will result in weak keys. As a result, it is recommended to use `compile-time-rng` anytime -random numbers will not be available at runtime. +If both `runtime-rng` and `compile-time-rng` are enabled the `runtime-rng` will take precedence and `compile-time-rng` will do nothing. +If neither flag is set, seeds can be supplied by the application. [Multiple apis](https://docs.rs/ahash/latest/ahash/random_state/struct.RandomState.html) +are available to do this. ## Comparison with other hashers diff --git a/third_party/rust/ahash/build.rs b/third_party/rust/ahash/build.rs index 6aba02526b..a136b3666c 100644 --- a/third_party/rust/ahash/build.rs +++ b/third_party/rust/ahash/build.rs @@ -4,34 +4,8 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); - if let Some(channel) = version_check::Channel::read() { - if channel.supports_features() { - println!("cargo:rustc-cfg=feature=\"specialize\""); - if version_check::Version::read().map_or(false, |v| v.at_most("1.77.9")) { - println!("cargo:rustc-cfg=feature=\"stdsimd\""); - } - } - } - let os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); - if os.eq_ignore_ascii_case("linux") - || os.eq_ignore_ascii_case("android") - || os.eq_ignore_ascii_case("windows") - || os.eq_ignore_ascii_case("macos") - || os.eq_ignore_ascii_case("ios") - || os.eq_ignore_ascii_case("freebsd") - || os.eq_ignore_ascii_case("openbsd") - || os.eq_ignore_ascii_case("dragonfly") - || os.eq_ignore_ascii_case("solaris") - || os.eq_ignore_ascii_case("illumos") - || os.eq_ignore_ascii_case("fuchsia") - || os.eq_ignore_ascii_case("redox") - || os.eq_ignore_ascii_case("cloudabi") - || os.eq_ignore_ascii_case("haiku") - || os.eq_ignore_ascii_case("vxworks") - || os.eq_ignore_ascii_case("emscripten") - || os.eq_ignore_ascii_case("wasi") - { - println!("cargo:rustc-cfg=feature=\"runtime-rng\""); + if let Some(true) = version_check::supports_feature("specialize") { + println!("cargo:rustc-cfg=feature=\"specialize\""); } let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set"); if arch.eq_ignore_ascii_case("x86_64") @@ -43,5 +17,4 @@ fn main() { { println!("cargo:rustc-cfg=feature=\"folded_multiply\""); } - } diff --git a/third_party/rust/ahash/src/aes_hash.rs b/third_party/rust/ahash/src/aes_hash.rs index 7e619b520b..daf3ae4fad 100644 --- a/third_party/rust/ahash/src/aes_hash.rs +++ b/third_party/rust/ahash/src/aes_hash.rs @@ -1,10 +1,8 @@ use crate::convert::*; -#[cfg(feature = "specialize")] -use crate::fallback_hash::MULTIPLE; use crate::operations::*; +use crate::random_state::PI; use crate::RandomState; use core::hash::Hasher; -use crate::random_state::PI; /// A `Hasher` for hashing an arbitrary stream of bytes. /// @@ -50,7 +48,7 @@ impl AHasher { /// println!("Hash is {:x}!", hasher.finish()); /// ``` #[inline] - pub fn new_with_keys(key1: u128, key2: u128) -> Self { + pub(crate) fn new_with_keys(key1: u128, key2: u128) -> Self { let pi: [u128; 2] = PI.convert(); let key1 = key1 ^ pi[0]; let key2 = key2 ^ pi[1]; @@ -70,7 +68,6 @@ impl AHasher { } } - #[inline] pub(crate) fn from_random_state(rand_state: &RandomState) -> Self { let key1 = [rand_state.k0, rand_state.k1].convert(); @@ -82,33 +79,25 @@ impl AHasher { } } - #[inline(always)] - fn add_in_length(&mut self, length: u64) { - //This will be scrambled by the next AES round. - let mut enc: [u64; 2] = self.enc.convert(); - enc[0] = enc[0].wrapping_add(length); - self.enc = enc.convert(); - } - #[inline(always)] fn hash_in(&mut self, new_value: u128) { - self.enc = aesenc(self.enc, new_value); + self.enc = aesdec(self.enc, new_value); self.sum = shuffle_and_add(self.sum, new_value); } #[inline(always)] fn hash_in_2(&mut self, v1: u128, v2: u128) { - self.enc = aesenc(self.enc, v1); + self.enc = aesdec(self.enc, v1); self.sum = shuffle_and_add(self.sum, v1); - self.enc = aesenc(self.enc, v2); + self.enc = aesdec(self.enc, v2); self.sum = shuffle_and_add(self.sum, v2); } #[inline] #[cfg(feature = "specialize")] fn short_finish(&self) -> u64 { - let combined = aesdec(self.sum, self.enc); - let result: [u64; 2] = aesenc(combined, combined).convert(); + let combined = aesenc(self.sum, self.enc); + let result: [u64; 2] = aesdec(combined, combined).convert(); result[0] } } @@ -138,7 +127,11 @@ impl Hasher for AHasher { } #[inline] - #[cfg(any(target_pointer_width = "64", target_pointer_width = "32", target_pointer_width = "16"))] + #[cfg(any( + target_pointer_width = "64", + target_pointer_width = "32", + target_pointer_width = "16" + ))] fn write_usize(&mut self, i: usize) { self.write_u64(i as u64); } @@ -159,7 +152,8 @@ impl Hasher for AHasher { fn write(&mut self, input: &[u8]) { let mut data = input; let length = data.len(); - self.add_in_length(length as u64); + add_in_length(&mut self.enc, length as u64); + //A 'binary search' on sizes reduces the number of comparisons. if data.len() <= 8 { let value = read_small(data); @@ -180,10 +174,10 @@ impl Hasher for AHasher { sum[1] = shuffle_and_add(sum[1], tail[3]); while data.len() > 64 { let (blocks, rest) = data.read_u128x4(); - current[0] = aesenc(current[0], blocks[0]); - current[1] = aesenc(current[1], blocks[1]); - current[2] = aesenc(current[2], blocks[2]); - current[3] = aesenc(current[3], blocks[3]); + current[0] = aesdec(current[0], blocks[0]); + current[1] = aesdec(current[1], blocks[1]); + current[2] = aesdec(current[2], blocks[2]); + current[3] = aesdec(current[3], blocks[3]); sum[0] = shuffle_and_add(sum[0], blocks[0]); sum[1] = shuffle_and_add(sum[1], blocks[1]); sum[0] = shuffle_and_add(sum[0], blocks[2]); @@ -214,9 +208,9 @@ impl Hasher for AHasher { } #[inline] fn finish(&self) -> u64 { - let combined = aesdec(self.sum, self.enc); - let result: [u64; 2] = aesenc(aesenc(combined, self.key), combined).convert(); - result[1] + let combined = aesenc(self.sum, self.enc); + let result: [u64; 2] = aesdec(aesdec(combined, self.key), combined).convert(); + result[0] } } @@ -231,8 +225,7 @@ pub(crate) struct AHasherU64 { impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { - let rot = (self.pad & 63) as u32; - self.buffer.rotate_left(rot) + folded_multiply(self.buffer, self.pad) } #[inline] @@ -327,7 +320,7 @@ pub(crate) struct AHasherStr(pub AHasher); impl Hasher for AHasherStr { #[inline] fn finish(&self) -> u64 { - let result : [u64; 2] = self.0.enc.convert(); + let result: [u64; 2] = self.0.enc.convert(); result[0] } @@ -335,14 +328,15 @@ impl Hasher for AHasherStr { fn write(&mut self, bytes: &[u8]) { if bytes.len() > 8 { self.0.write(bytes); - self.0.enc = aesdec(self.0.sum, self.0.enc); - self.0.enc = aesenc(aesenc(self.0.enc, self.0.key), self.0.enc); + self.0.enc = aesenc(self.0.sum, self.0.enc); + self.0.enc = aesdec(aesdec(self.0.enc, self.0.key), self.0.enc); } else { - self.0.add_in_length(bytes.len() as u64); + add_in_length(&mut self.0.enc, bytes.len() as u64); + let value = read_small(bytes).convert(); self.0.sum = shuffle_and_add(self.0.sum, value); - self.0.enc = aesdec(self.0.sum, self.0.enc); - self.0.enc = aesenc(aesenc(self.0.enc, self.0.key), self.0.enc); + self.0.enc = aesenc(self.0.sum, self.0.enc); + self.0.enc = aesdec(aesdec(self.0.enc, self.0.key), self.0.enc); } } @@ -437,4 +431,3 @@ mod tests { assert_eq!(bytes, 0x6464646464646464); } } - diff --git a/third_party/rust/ahash/src/convert.rs b/third_party/rust/ahash/src/convert.rs index 4c0a00eb7c..712eae163b 100644 --- a/third_party/rust/ahash/src/convert.rs +++ b/third_party/rust/ahash/src/convert.rs @@ -7,17 +7,13 @@ macro_rules! convert { impl Convert<$b> for $a { #[inline(always)] fn convert(self) -> $b { - unsafe { - core::mem::transmute::<$a, $b>(self) - } + zerocopy::transmute!(self) } } impl Convert<$a> for $b { #[inline(always)] fn convert(self) -> $a { - unsafe { - core::mem::transmute::<$b, $a>(self) - } + zerocopy::transmute!(self) } } }; @@ -69,8 +65,7 @@ macro_rules! as_array { { #[inline(always)] fn as_array(slice: &[T]) -> &[T; $len] { - assert_eq!(slice.len(), $len); - unsafe { &*(slice.as_ptr() as *const [_; $len]) } + core::convert::TryFrom::try_from(slice).unwrap() } as_array($input) } diff --git a/third_party/rust/ahash/src/fallback_hash.rs b/third_party/rust/ahash/src/fallback_hash.rs index aad9efc859..bc5cbfeeec 100644 --- a/third_party/rust/ahash/src/fallback_hash.rs +++ b/third_party/rust/ahash/src/fallback_hash.rs @@ -1,12 +1,11 @@ use crate::convert::*; use crate::operations::folded_multiply; use crate::operations::read_small; +use crate::operations::MULTIPLE; use crate::random_state::PI; use crate::RandomState; use core::hash::Hasher; -///This constant come from Kunth's prng (Empirically it works better than those from splitmix32). -pub(crate) const MULTIPLE: u64 = 6364136223846793005; const ROT: u32 = 23; //17 /// A `Hasher` for hashing an arbitrary stream of bytes. @@ -31,7 +30,7 @@ impl AHasher { /// Creates a new hasher keyed to the provided key. #[inline] #[allow(dead_code)] // Is not called if non-fallback hash is used. - pub fn new_with_keys(key1: u128, key2: u128) -> AHasher { + pub(crate) fn new_with_keys(key1: u128, key2: u128) -> AHasher { let pi: [u128; 2] = PI.convert(); let key1: [u64; 2] = (key1 ^ pi[0]).convert(); let key2: [u64; 2] = (key2 ^ pi[1]).convert(); @@ -57,8 +56,8 @@ impl AHasher { #[allow(dead_code)] // Is not called if non-fallback hash is used. pub(crate) fn from_random_state(rand_state: &RandomState) -> AHasher { AHasher { - buffer: rand_state.k0, - pad: rand_state.k1, + buffer: rand_state.k1, + pad: rand_state.k0, extra_keys: [rand_state.k2, rand_state.k3], } } @@ -93,19 +92,10 @@ impl AHasher { /// attacker somehow knew part of (but not all) the contents of the buffer before hand, /// they would not be able to predict any of the bits in the buffer at the end. #[inline(always)] - #[cfg(feature = "folded_multiply")] fn update(&mut self, new_data: u64) { self.buffer = folded_multiply(new_data ^ self.buffer, MULTIPLE); } - #[inline(always)] - #[cfg(not(feature = "folded_multiply"))] - fn update(&mut self, new_data: u64) { - let d1 = (new_data ^ self.buffer).wrapping_mul(MULTIPLE); - self.pad = (self.pad ^ d1).rotate_left(8).wrapping_mul(MULTIPLE); - self.buffer = (self.buffer ^ self.pad).rotate_left(24); - } - /// Similar to the above this function performs an update using a "folded multiply". /// However it takes in 128 bits of data instead of 64. Both halves must be masked. /// @@ -118,25 +108,16 @@ impl AHasher { /// can't be changed by the same set of input bits. To cancel this sequence with subsequent input would require /// knowing the keys. #[inline(always)] - #[cfg(feature = "folded_multiply")] fn large_update(&mut self, new_data: u128) { let block: [u64; 2] = new_data.convert(); let combined = folded_multiply(block[0] ^ self.extra_keys[0], block[1] ^ self.extra_keys[1]); self.buffer = (self.buffer.wrapping_add(self.pad) ^ combined).rotate_left(ROT); } - #[inline(always)] - #[cfg(not(feature = "folded_multiply"))] - fn large_update(&mut self, new_data: u128) { - let block: [u64; 2] = new_data.convert(); - self.update(block[0] ^ self.extra_keys[0]); - self.update(block[1] ^ self.extra_keys[1]); - } - #[inline] #[cfg(feature = "specialize")] fn short_finish(&self) -> u64 { - self.buffer.wrapping_add(self.pad) + folded_multiply(self.buffer, self.pad) } } @@ -170,7 +151,11 @@ impl Hasher for AHasher { } #[inline] - #[cfg(any(target_pointer_width = "64", target_pointer_width = "32", target_pointer_width = "16"))] + #[cfg(any( + target_pointer_width = "64", + target_pointer_width = "32", + target_pointer_width = "16" + ))] fn write_usize(&mut self, i: usize) { self.write_u64(i as u64); } @@ -208,18 +193,10 @@ impl Hasher for AHasher { } #[inline] - #[cfg(feature = "folded_multiply")] fn finish(&self) -> u64 { let rot = (self.buffer & 63) as u32; folded_multiply(self.buffer, self.pad).rotate_left(rot) } - - #[inline] - #[cfg(not(feature = "folded_multiply"))] - fn finish(&self) -> u64 { - let rot = (self.buffer & 63) as u32; - (self.buffer.wrapping_mul(MULTIPLE) ^ self.pad).rotate_left(rot) - } } #[cfg(feature = "specialize")] @@ -233,8 +210,8 @@ pub(crate) struct AHasherU64 { impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { - let rot = (self.pad & 63) as u32; - self.buffer.rotate_left(rot) + folded_multiply(self.buffer, self.pad) + //self.buffer } #[inline] @@ -338,8 +315,7 @@ impl Hasher for AHasherStr { self.0.write(bytes) } else { let value = read_small(bytes); - self.0.buffer = folded_multiply(value[0] ^ self.0.buffer, - value[1] ^ self.0.extra_keys[1]); + self.0.buffer = folded_multiply(value[0] ^ self.0.buffer, value[1] ^ self.0.extra_keys[1]); self.0.pad = self.0.pad.wrapping_add(bytes.len() as u64); } } @@ -365,7 +341,6 @@ impl Hasher for AHasherStr { #[cfg(test)] mod tests { - use crate::convert::Convert; use crate::fallback_hash::*; #[test] diff --git a/third_party/rust/ahash/src/hash_map.rs b/third_party/rust/ahash/src/hash_map.rs index ec8fa433bb..2b6fbdc89f 100644 --- a/third_party/rust/ahash/src/hash_map.rs +++ b/third_party/rust/ahash/src/hash_map.rs @@ -1,4 +1,5 @@ use std::borrow::Borrow; +use std::collections::hash_map::{IntoKeys, IntoValues}; use std::collections::{hash_map, HashMap}; use std::fmt::{self, Debug}; use std::hash::{BuildHasher, Hash}; @@ -25,6 +26,24 @@ impl From> for AHashMap { } } +impl From<[(K, V); N]> for AHashMap +where + K: Eq + Hash, +{ + /// # Examples + /// + /// ``` + /// use ahash::AHashMap; + /// + /// let map1 = AHashMap::from([(1, 2), (3, 4)]); + /// let map2: AHashMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + Self::from_iter(arr) + } +} + impl Into> for AHashMap { fn into(self) -> HashMap { self.0 @@ -32,12 +51,16 @@ impl Into> for AHashMap { } impl AHashMap { + /// This crates a hashmap using [RandomState::new] which obtains its keys from [RandomSource]. + /// See the documentation in [RandomSource] for notes about key strength. pub fn new() -> Self { - AHashMap(HashMap::with_hasher(RandomState::default())) + AHashMap(HashMap::with_hasher(RandomState::new())) } + /// This crates a hashmap with the specified capacity using [RandomState::new]. + /// See the documentation in [RandomSource] for notes about key strength. pub fn with_capacity(capacity: usize) -> Self { - AHashMap(HashMap::with_capacity_and_hasher(capacity, RandomState::default())) + AHashMap(HashMap::with_capacity_and_hasher(capacity, RandomState::new())) } } @@ -145,8 +168,6 @@ where /// types that can be `==` without being identical. See the [module-level /// documentation] for more. /// - /// [module-level documentation]: crate::collections#insert-and-complex-keys - /// /// # Examples /// /// ``` @@ -165,6 +186,68 @@ where self.0.insert(k, v) } + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over keys takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[inline] + pub fn into_keys(self) -> IntoKeys { + self.0.into_keys() + } + + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec = map.into_values().collect(); + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over values takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[inline] + pub fn into_values(self) -> IntoValues { + self.0.into_values() + } + /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. /// @@ -261,13 +344,16 @@ where } } -impl FromIterator<(K, V)> for AHashMap +impl FromIterator<(K, V)> for AHashMap where K: Eq + Hash, - S: BuildHasher + Default, { + /// This crates a hashmap from the provided iterator using [RandomState::new]. + /// See the documentation in [RandomSource] for notes about key strength. fn from_iter>(iter: T) -> Self { - AHashMap(HashMap::from_iter(iter)) + let mut inner = HashMap::with_hasher(RandomState::new()); + inner.extend(iter); + AHashMap(inner) } } @@ -318,10 +404,14 @@ where } } +/// NOTE: For safety this trait impl is only available available if either of the flags `runtime-rng` (on by default) or +/// `compile-time-rng` are enabled. This is to prevent weakly keyed maps from being accidentally created. Instead one of +/// constructors for [RandomState] must be used. +#[cfg(any(feature = "compile-time-rng", feature = "runtime-rng", feature = "no-rng"))] impl Default for AHashMap { #[inline] fn default() -> AHashMap { - AHashMap::new() + AHashMap(HashMap::default()) } } @@ -346,6 +436,40 @@ where let hash_map = HashMap::deserialize(deserializer); hash_map.map(|hash_map| Self(hash_map)) } + + fn deserialize_in_place>(deserializer: D, place: &mut Self) -> Result<(), D::Error> { + use serde::de::{MapAccess, Visitor}; + + struct MapInPlaceVisitor<'a, K: 'a, V: 'a>(&'a mut AHashMap); + + impl<'a, 'de, K, V> Visitor<'de> for MapInPlaceVisitor<'a, K, V> + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + self.0.clear(); + self.0.reserve(map.size_hint().unwrap_or(0).min(4096)); + + while let Some((key, value)) = map.next_entry()? { + self.0.insert(key, value); + } + + Ok(()) + } + } + + deserializer.deserialize_map(MapInPlaceVisitor(place)) + } } #[cfg(test)] @@ -364,8 +488,14 @@ mod test { let mut map = AHashMap::new(); map.insert("for".to_string(), 0); map.insert("bar".to_string(), 1); - let serialization = serde_json::to_string(&map).unwrap(); - let deserialization: AHashMap = serde_json::from_str(&serialization).unwrap(); + let mut serialization = serde_json::to_string(&map).unwrap(); + let mut deserialization: AHashMap = serde_json::from_str(&serialization).unwrap(); + assert_eq!(deserialization, map); + + map.insert("baz".to_string(), 2); + serialization = serde_json::to_string(&map).unwrap(); + let mut deserializer = serde_json::Deserializer::from_str(&serialization); + AHashMap::deserialize_in_place(&mut deserializer, &mut deserialization).unwrap(); assert_eq!(deserialization, map); } } diff --git a/third_party/rust/ahash/src/hash_quality_test.rs b/third_party/rust/ahash/src/hash_quality_test.rs index 17228d4716..f2fab16013 100644 --- a/third_party/rust/ahash/src/hash_quality_test.rs +++ b/third_party/rust/ahash/src/hash_quality_test.rs @@ -1,5 +1,5 @@ use core::hash::{Hash, Hasher}; -use std::collections::{HashMap}; +use std::collections::HashMap; fn assert_sufficiently_different(a: u64, b: u64, tolerance: i32) { let (same_byte_count, same_nibble_count) = count_same_bytes_and_nibbles(a, b); @@ -50,7 +50,7 @@ fn count_same_bytes_and_nibbles(a: u64, b: u64) -> (i32, i32) { (same_byte_count, same_nibble_count) } -fn gen_combinations(options: &[u32; 8], depth: u32, so_far: Vec, combinations: &mut Vec>) { +fn gen_combinations(options: &[u32; 11], depth: u32, so_far: Vec, combinations: &mut Vec>) { if depth == 0 { return; } @@ -63,19 +63,15 @@ fn gen_combinations(options: &[u32; 8], depth: u32, so_far: Vec, combinatio } fn test_no_full_collisions(gen_hash: impl Fn() -> T) { - let options: [u32; 8] = [ - 0x00000000, 0x20000000, 0x40000000, 0x60000000, 0x80000000, 0xA0000000, 0xC0000000, 0xE0000000, + let options: [u32; 11] = [ + 0x00000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0xF0000000, 1, 2, 4, 8, 15, ]; let mut combinations = Vec::new(); gen_combinations(&options, 7, Vec::new(), &mut combinations); let mut map: HashMap> = HashMap::new(); for combination in combinations { - let array = unsafe { - let (begin, middle, end) = combination.align_to::(); - assert_eq!(0, begin.len()); - assert_eq!(0, end.len()); - middle.to_vec() - }; + use zerocopy::AsBytes; + let array = combination.as_slice().as_bytes().to_vec(); let mut hasher = gen_hash(); hasher.write(&array); let hash = hasher.finish(); @@ -89,7 +85,7 @@ fn test_no_full_collisions(gen_hash: impl Fn() -> T) { map.insert(hash, array); } } - assert_eq!(2396744, map.len()); + assert_eq!(21435887, map.len()); //11^7 + 11^6 ... } fn test_keys_change_output(constructor: impl Fn(u128, u128) -> T) { @@ -112,13 +108,13 @@ fn test_keys_change_output(constructor: impl Fn(u128, u128) -> T) { fn test_input_affect_every_byte(constructor: impl Fn(u128, u128) -> T) { let base = hash_with(&0, constructor(0, 0)); for shift in 0..16 { - let mut alternitives = vec![]; + let mut alternatives = vec![]; for v in 0..256 { let input = (v as u128) << (shift * 8); let hasher = constructor(0, 0); - alternitives.push(hash_with(&input, hasher)); + alternatives.push(hash_with(&input, hasher)); } - assert_each_byte_differs(shift, base, alternitives); + assert_each_byte_differs(shift, base, alternatives); } } @@ -126,28 +122,35 @@ fn test_input_affect_every_byte(constructor: impl Fn(u128, u128) -> T fn test_keys_affect_every_byte(item: H, constructor: impl Fn(u128, u128) -> T) { let base = hash_with(&item, constructor(0, 0)); for shift in 0..16 { - let mut alternitives1 = vec![]; - let mut alternitives2 = vec![]; + let mut alternatives1 = vec![]; + let mut alternatives2 = vec![]; for v in 0..256 { let input = (v as u128) << (shift * 8); let hasher1 = constructor(input, 0); let hasher2 = constructor(0, input); let h1 = hash_with(&item, hasher1); let h2 = hash_with(&item, hasher2); - alternitives1.push(h1); - alternitives2.push(h2); + alternatives1.push(h1); + alternatives2.push(h2); } - assert_each_byte_differs(shift, base, alternitives1); - assert_each_byte_differs(shift, base, alternitives2); + assert_each_byte_differs(shift, base, alternatives1); + assert_each_byte_differs(shift, base, alternatives2); } } -fn assert_each_byte_differs(num: u64, base: u64, alternitives: Vec) { +fn assert_each_byte_differs(num: u64, base: u64, alternatives: Vec) { let mut changed_bits = 0_u64; - for alternitive in alternitives { - changed_bits |= base ^ alternitive - } - assert_eq!(core::u64::MAX, changed_bits, "Bits changed: {:x} on num: {:?}", changed_bits, num); + for alternative in alternatives { + changed_bits |= base ^ alternative + } + assert_eq!( + core::u64::MAX, + changed_bits, + "Bits changed: {:x} on num: {:?}. base {:x}", + changed_bits, + num, + base + ); } fn test_finish_is_consistent(constructor: impl Fn(u128, u128) -> T) { @@ -273,11 +276,19 @@ fn test_padding_doesnot_collide(hasher: impl Fn() -> T) { let (same_bytes, same_nibbles) = count_same_bytes_and_nibbles(value, long.finish()); assert!( same_bytes <= 3, - "{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish() + "{} bytes of {} -> {:x} vs {:x}", + num, + c, + value, + long.finish() ); assert!( same_nibbles <= 8, - "{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish() + "{} bytes of {} -> {:x} vs {:x}", + num, + c, + value, + long.finish() ); let flipped_bits = (value ^ long.finish()).count_ones(); assert!(flipped_bits > 10); @@ -327,19 +338,24 @@ fn test_length_extension(hasher: impl Fn(u128, u128) -> T) { } fn test_sparse(hasher: impl Fn() -> T) { + use smallvec::SmallVec; + let mut buf = [0u8; 256]; let mut hashes = HashMap::new(); - for idx_1 in 0..256 { - for idx_2 in idx_1+1..256 { + for idx_1 in 0..255_u8 { + for idx_2 in idx_1 + 1..=255_u8 { for value_1 in [1, 2, 4, 8, 16, 32, 64, 128] { - for value_2 in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 16, 17, 18, 20, 24, 31, 32, 33, 48, 64, 96, 127, 128, 129, 192, 254, 255] { - buf[idx_1] = value_1; - buf[idx_2] = value_2; + for value_2 in [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 16, 17, 18, 20, 24, 31, 32, 33, 48, 64, 96, 127, 128, 129, + 192, 254, 255, + ] { + buf[idx_1 as usize] = value_1; + buf[idx_2 as usize] = value_2; let hash_value = hash_with(&buf, &mut hasher()); - let keys = hashes.entry(hash_value).or_insert(Vec::new()); - keys.push((idx_1, value_1, idx_2, value_2)); - buf[idx_1] = 0; - buf[idx_2] = 0; + let keys = hashes.entry(hash_value).or_insert(SmallVec::<[[u8; 4]; 1]>::new()); + keys.push([idx_1, value_1, idx_2, value_2]); + buf[idx_1 as usize] = 0; + buf[idx_2 as usize] = 0; } } } @@ -392,7 +408,7 @@ mod fallback_tests { fn fallback_keys_affect_every_byte() { //For fallback second key is not used in every hash. #[cfg(all(not(feature = "specialize"), feature = "folded_multiply"))] - test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a)); + test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a)); test_keys_affect_every_byte("", |a, b| AHasher::new_with_keys(a ^ b, a)); test_keys_affect_every_byte((0, 0), |a, b| AHasher::new_with_keys(a ^ b, a)); } @@ -425,7 +441,8 @@ mod fallback_tests { ///Basic sanity tests of the cypto properties of aHash. #[cfg(any( all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") + all(target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), ))] #[cfg(test)] mod aes_tests { @@ -488,7 +505,7 @@ mod aes_tests { #[test] fn aes_keys_affect_every_byte() { #[cfg(not(feature = "specialize"))] - test_keys_affect_every_byte(0, AHasher::test_with_keys); + test_keys_affect_every_byte(0, AHasher::test_with_keys); test_keys_affect_every_byte("", AHasher::test_with_keys); test_keys_affect_every_byte((0, 0), AHasher::test_with_keys); } diff --git a/third_party/rust/ahash/src/hash_set.rs b/third_party/rust/ahash/src/hash_set.rs index 9766b676ff..d03bef580f 100644 --- a/third_party/rust/ahash/src/hash_set.rs +++ b/third_party/rust/ahash/src/hash_set.rs @@ -14,27 +14,49 @@ use serde::{ /// A [`HashSet`](std::collections::HashSet) using [`RandomState`](crate::RandomState) to hash the items. /// (Requires the `std` feature to be enabled.) #[derive(Clone)] -pub struct AHashSet(HashSet); +pub struct AHashSet(HashSet); -impl From> for AHashSet { - fn from(item: HashSet) -> Self { +impl From> for AHashSet { + fn from(item: HashSet) -> Self { AHashSet(item) } } -impl Into> for AHashSet { - fn into(self) -> HashSet { +impl From<[T; N]> for AHashSet +where + T: Eq + Hash, +{ + /// # Examples + /// + /// ``` + /// use ahash::AHashSet; + /// + /// let set1 = AHashSet::from([1, 2, 3, 4]); + /// let set2: AHashSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + Self::from_iter(arr) + } +} + +impl Into> for AHashSet { + fn into(self) -> HashSet { self.0 } } impl AHashSet { + /// This crates a hashset using [RandomState::new]. + /// See the documentation in [RandomSource] for notes about key strength. pub fn new() -> Self { - AHashSet(HashSet::with_hasher(RandomState::default())) + AHashSet(HashSet::with_hasher(RandomState::new())) } + /// This crates a hashset with the specified capacity using [RandomState::new]. + /// See the documentation in [RandomSource] for notes about key strength. pub fn with_capacity(capacity: usize) -> Self { - AHashSet(HashSet::with_capacity_and_hasher(capacity, RandomState::default())) + AHashSet(HashSet::with_capacity_and_hasher(capacity, RandomState::new())) } } @@ -219,14 +241,17 @@ where } } -impl FromIterator for AHashSet +impl FromIterator for AHashSet where T: Eq + Hash, - S: BuildHasher + Default, { + /// This crates a hashset from the provided iterator using [RandomState::new]. + /// See the documentation in [RandomSource] for notes about key strength. #[inline] - fn from_iter>(iter: I) -> AHashSet { - AHashSet(HashSet::from_iter(iter)) + fn from_iter>(iter: I) -> AHashSet { + let mut inner = HashSet::with_hasher(RandomState::new()); + inner.extend(iter); + AHashSet(inner) } } @@ -268,6 +293,10 @@ where } } +/// NOTE: For safety this trait impl is only available available if either of the flags `runtime-rng` (on by default) or +/// `compile-time-rng` are enabled. This is to prevent weakly keyed maps from being accidentally created. Instead one of +/// constructors for [RandomState] must be used. +#[cfg(any(feature = "compile-time-rng", feature = "runtime-rng", feature = "no-rng"))] impl Default for AHashSet { /// Creates an empty `AHashSet` with the `Default` value for the hasher. #[inline] @@ -295,6 +324,10 @@ where let hash_set = HashSet::deserialize(deserializer); hash_set.map(|hash_set| Self(hash_set)) } + + fn deserialize_in_place>(deserializer: D, place: &mut Self) -> Result<(), D::Error> { + HashSet::deserialize_in_place(deserializer, place) + } } #[cfg(all(test, feature = "serde"))] @@ -306,8 +339,14 @@ mod test { let mut set = AHashSet::new(); set.insert("for".to_string()); set.insert("bar".to_string()); - let serialization = serde_json::to_string(&set).unwrap(); - let deserialization: AHashSet = serde_json::from_str(&serialization).unwrap(); + let mut serialization = serde_json::to_string(&set).unwrap(); + let mut deserialization: AHashSet = serde_json::from_str(&serialization).unwrap(); + assert_eq!(deserialization, set); + + set.insert("baz".to_string()); + serialization = serde_json::to_string(&set).unwrap(); + let mut deserializer = serde_json::Deserializer::from_str(&serialization); + AHashSet::deserialize_in_place(&mut deserializer, &mut deserialization).unwrap(); assert_eq!(deserialization, set); } } diff --git a/third_party/rust/ahash/src/lib.rs b/third_party/rust/ahash/src/lib.rs index 9964a7c47b..69fb2ca237 100644 --- a/third_party/rust/ahash/src/lib.rs +++ b/third_party/rust/ahash/src/lib.rs @@ -1,86 +1,208 @@ -//! AHash is a hashing algorithm is intended to be a high performance, (hardware specific), keyed hash function. -//! This can be seen as a DOS resistant alternative to `FxHash`, or a fast equivalent to `SipHash`. -//! It provides a high speed hash algorithm, but where the result is not predictable without knowing a Key. -//! This allows it to be used in a `HashMap` without allowing for the possibility that an malicious user can +//! AHash is a high performance keyed hash function. +//! +//! It quickly provides a high quality hash where the result is not predictable without knowing the Key. +//! AHash works with `HashMap` to hash keys, but without allowing for the possibility that an malicious user can //! induce a collision. //! //! # How aHash works //! -//! aHash uses the hardware AES instruction on x86 processors to provide a keyed hash function. -//! aHash is not a cryptographically secure hash. -//! -//! # Example -//! ``` -//! use ahash::{AHasher, RandomState}; -//! use std::collections::HashMap; +//! When it is available aHash uses the hardware AES instructions to provide a keyed hash function. +//! When it is not, aHash falls back on a slightly slower alternative algorithm. //! -//! let mut map: HashMap = HashMap::default(); -//! map.insert(12, 34); -//! ``` -//! For convinence wrappers called `AHashMap` and `AHashSet` are also provided. -//! These to the same thing with slightly less typing. -//! ```ignore -//! use ahash::AHashMap; -//! -//! let mut map: AHashMap = AHashMap::with_capacity(4); -//! map.insert(12, 34); -//! map.insert(56, 78); -//! ``` +//! Because aHash does not have a fixed standard for its output, it is able to improve over time. +//! But this also means that different computers or computers using different versions of ahash may observe different +//! hash values for the same input. +#![cfg_attr( + all( + feature = "std", + any(feature = "compile-time-rng", feature = "runtime-rng", feature = "no-rng") + ), + doc = r##" +# Basic Usage +AHash provides an implementation of the [Hasher] trait. +To construct a HashMap using aHash as its hasher do the following: +``` +use ahash::{AHasher, RandomState}; +use std::collections::HashMap; + +let mut map: HashMap = HashMap::default(); +map.insert(12, 34); +``` + +### Randomness + +The above requires a source of randomness to generate keys for the hashmap. By default this obtained from the OS. +It is also possible to have randomness supplied via the `compile-time-rng` flag, or manually. + +### If randomess is not available + +[AHasher::default()] can be used to hash using fixed keys. This works with +[BuildHasherDefault](std::hash::BuildHasherDefault). For example: + +``` +use std::hash::BuildHasherDefault; +use std::collections::HashMap; +use ahash::AHasher; + +let mut m: HashMap<_, _, BuildHasherDefault> = HashMap::default(); + # m.insert(12, 34); +``` +It is also possible to instantiate [RandomState] directly: + +``` +use ahash::HashMap; +use ahash::RandomState; + +let mut m = HashMap::with_hasher(RandomState::with_seed(42)); + # m.insert(1, 2); +``` +Or for uses besides a hashhmap: +``` +use std::hash::BuildHasher; +use ahash::RandomState; + +let hash_builder = RandomState::with_seed(42); +let hash = hash_builder.hash_one("Some Data"); +``` +There are several constructors for [RandomState] with different ways to supply seeds. + +# Convenience wrappers + +For convenience, both new-type wrappers and type aliases are provided. + +The new type wrappers are called called `AHashMap` and `AHashSet`. +``` +use ahash::AHashMap; + +let mut map: AHashMap = AHashMap::new(); +map.insert(12, 34); +``` +This avoids the need to type "RandomState". (For convenience `From`, `Into`, and `Deref` are provided). + +# Aliases + +For even less typing and better interop with existing libraries (such as rayon) which require a `std::collection::HashMap` , +the type aliases [HashMap], [HashSet] are provided. + +``` +use ahash::{HashMap, HashMapExt}; + +let mut map: HashMap = HashMap::new(); +map.insert(12, 34); +``` +Note the import of [HashMapExt]. This is needed for the constructor. + +"## +)] #![deny(clippy::correctness, clippy::complexity, clippy::perf)] #![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)] #![cfg_attr(all(not(test), not(feature = "std")), no_std)] #![cfg_attr(feature = "specialize", feature(min_specialization))] -#![cfg_attr(feature = "stdsimd", feature(stdsimd))] +#![cfg_attr(feature = "nightly-arm-aes", feature(stdarch_arm_neon_intrinsics))] #[macro_use] mod convert; -#[cfg(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -))] -mod aes_hash; mod fallback_hash; + +cfg_if::cfg_if! { + if #[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), + ))] { + mod aes_hash; + pub use crate::aes_hash::AHasher; + } else { + pub use crate::fallback_hash::AHasher; + } +} + +cfg_if::cfg_if! { + if #[cfg(feature = "std")] { + mod hash_map; + mod hash_set; + + pub use crate::hash_map::AHashMap; + pub use crate::hash_set::AHashSet; + + /// [Hasher]: std::hash::Hasher + /// [HashMap]: std::collections::HashMap + /// Type alias for [HashMap] + pub type HashMap = std::collections::HashMap; + + /// Type alias for [HashSet] + pub type HashSet = std::collections::HashSet; + } +} + #[cfg(test)] mod hash_quality_test; -#[cfg(feature = "std")] -mod hash_map; -#[cfg(feature = "std")] -mod hash_set; mod operations; -mod random_state; +pub mod random_state; mod specialize; -#[cfg(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -))] -pub use crate::aes_hash::AHasher; - -#[cfg(not(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -)))] -pub use crate::fallback_hash::AHasher; pub use crate::random_state::RandomState; -pub use crate::specialize::CallHasher; - -#[cfg(feature = "std")] -pub use crate::hash_map::AHashMap; -#[cfg(feature = "std")] -pub use crate::hash_set::AHashSet; use core::hash::BuildHasher; use core::hash::Hash; use core::hash::Hasher; +#[cfg(feature = "std")] +/// A convenience trait that can be used together with the type aliases defined to +/// get access to the `new()` and `with_capacity()` methods for the HashMap type alias. +pub trait HashMapExt { + /// Constructs a new HashMap + fn new() -> Self; + /// Constructs a new HashMap with a given initial capacity + fn with_capacity(capacity: usize) -> Self; +} + +#[cfg(feature = "std")] +/// A convenience trait that can be used together with the type aliases defined to +/// get access to the `new()` and `with_capacity()` methods for the HashSet type aliases. +pub trait HashSetExt { + /// Constructs a new HashSet + fn new() -> Self; + /// Constructs a new HashSet with a given initial capacity + fn with_capacity(capacity: usize) -> Self; +} + +#[cfg(feature = "std")] +impl HashMapExt for std::collections::HashMap +where + S: BuildHasher + Default, +{ + fn new() -> Self { + std::collections::HashMap::with_hasher(S::default()) + } + + fn with_capacity(capacity: usize) -> Self { + std::collections::HashMap::with_capacity_and_hasher(capacity, S::default()) + } +} + +#[cfg(feature = "std")] +impl HashSetExt for std::collections::HashSet +where + S: BuildHasher + Default, +{ + fn new() -> Self { + std::collections::HashSet::with_hasher(S::default()) + } + + fn with_capacity(capacity: usize) -> Self { + std::collections::HashSet::with_capacity_and_hasher(capacity, S::default()) + } +} + /// Provides a default [Hasher] with fixed keys. /// This is typically used in conjunction with [BuildHasherDefault] to create /// [AHasher]s in order to hash the keys of the map. /// /// Generally it is preferable to use [RandomState] instead, so that different -/// hashmaps will have different keys. However if fixed keys are desireable this +/// hashmaps will have different keys. However if fixed keys are desirable this /// may be used instead. /// /// # Example @@ -194,9 +316,21 @@ impl BuildHasherExt for B { #[cfg(test)] mod test { use crate::convert::Convert; + use crate::specialize::CallHasher; use crate::*; use std::collections::HashMap; - use std::hash::Hash; + + #[test] + fn test_ahash_alias_map_construction() { + let mut map = super::HashMap::with_capacity(1234); + map.insert(1, "test"); + } + + #[test] + fn test_ahash_alias_set_construction() { + let mut set = super::HashSet::with_capacity(1234); + set.insert(1); + } #[test] fn test_default_builder() { @@ -219,7 +353,6 @@ mod test { assert_eq!(bytes, 0x6464646464646464); } - #[test] fn test_non_zero() { let mut hasher1 = AHasher::new_with_keys(0, 0); @@ -241,7 +374,7 @@ mod test { #[test] fn test_non_zero_specialized() { - let hasher_build = RandomState::with_seeds(0,0,0,0); + let hasher_build = RandomState::with_seeds(0, 0, 0, 0); let h1 = str::get_hash("foo", &hasher_build); let h2 = str::get_hash("bar", &hasher_build); diff --git a/third_party/rust/ahash/src/operations.rs b/third_party/rust/ahash/src/operations.rs index b71fd5a743..8395007535 100644 --- a/third_party/rust/ahash/src/operations.rs +++ b/third_party/rust/ahash/src/operations.rs @@ -1,4 +1,9 @@ use crate::convert::*; +#[allow(unused)] +use zerocopy::transmute; + +///This constant comes from Kunth's prng (Empirically it works better than those from splitmix32). +pub(crate) const MULTIPLE: u64 = 6364136223846793005; /// This is a constant with a lot of special properties found by automated search. /// See the unit tests below. (Below are alternative values) @@ -8,11 +13,19 @@ const SHUFFLE_MASK: u128 = 0x020a0700_0c01030e_050f0d08_06090b04_u128; //const SHUFFLE_MASK: u128 = 0x040A0700_030E0106_0D050F08_020B0C09_u128; #[inline(always)] +#[cfg(feature = "folded_multiply")] pub(crate) const fn folded_multiply(s: u64, by: u64) -> u64 { let result = (s as u128).wrapping_mul(by as u128); ((result & 0xffff_ffff_ffff_ffff) as u64) ^ ((result >> 64) as u64) } +#[inline(always)] +#[cfg(not(feature = "folded_multiply"))] +pub(crate) const fn folded_multiply(s: u64, by: u64) -> u64 { + let b1 = s.wrapping_mul(by.swap_bytes()); + let b2 = s.swap_bytes().wrapping_mul(!by); + b1 ^ b2.swap_bytes() +} /// Given a small (less than 8 byte slice) returns the same data stored in two u32s. /// (order of and non-duplication of bytes is NOT guaranteed) @@ -44,8 +57,7 @@ pub(crate) fn shuffle(a: u128) -> u128 { use core::arch::x86::*; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::*; - use core::mem::transmute; - unsafe { transmute(_mm_shuffle_epi8(transmute(a), transmute(SHUFFLE_MASK))) } + unsafe { transmute!(_mm_shuffle_epi8(transmute!(a), transmute!(SHUFFLE_MASK))) } } #[cfg(not(all(target_feature = "ssse3", not(miri))))] { @@ -60,7 +72,7 @@ pub(crate) fn add_and_shuffle(a: u128, b: u128) -> u128 { shuffle(sum.convert()) } -#[allow(unused)] //not used by fallbac +#[allow(unused)] //not used by fallback #[inline(always)] pub(crate) fn shuffle_and_add(base: u128, to_add: u128) -> u128 { let shuffled: [u64; 2] = shuffle(base).convert(); @@ -70,13 +82,12 @@ pub(crate) fn shuffle_and_add(base: u128, to_add: u128) -> u128 { #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri)))] #[inline(always)] pub(crate) fn add_by_64s(a: [u64; 2], b: [u64; 2]) -> [u64; 2] { - use core::mem::transmute; unsafe { #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::*; - transmute(_mm_add_epi64(transmute(a), transmute(b))) + transmute!(_mm_add_epi64(transmute!(a), transmute!(b))) } } @@ -94,26 +105,26 @@ pub(crate) fn aesenc(value: u128, xor: u128) -> u128 { use core::arch::x86::*; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::*; - use core::mem::transmute; unsafe { - let value = transmute(value); - transmute(_mm_aesenc_si128(value, transmute(xor))) + let value = transmute!(value); + transmute!(_mm_aesenc_si128(value, transmute!(xor))) } } -#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))] +#[cfg(any( + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), +))] #[allow(unused)] #[inline(always)] pub(crate) fn aesenc(value: u128, xor: u128) -> u128 { - #[cfg(target_arch = "arm")] - use core::arch::arm::*; #[cfg(target_arch = "aarch64")] use core::arch::aarch64::*; - use core::mem::transmute; - unsafe { - let value = transmute(value); - transmute(vaesmcq_u8(vaeseq_u8(value, transmute(xor)))) - } + #[cfg(target_arch = "arm")] + use core::arch::arm::*; + let res = unsafe { vaesmcq_u8(vaeseq_u8(transmute!(value), transmute!(0u128))) }; + let value: u128 = transmute!(res); + xor ^ value } #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))] @@ -124,32 +135,55 @@ pub(crate) fn aesdec(value: u128, xor: u128) -> u128 { use core::arch::x86::*; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::*; - use core::mem::transmute; unsafe { - let value = transmute(value); - transmute(_mm_aesdec_si128(value, transmute(xor))) + let value = transmute!(value); + transmute!(_mm_aesdec_si128(value, transmute!(xor))) } } -#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))] +#[cfg(any( + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), +))] #[allow(unused)] #[inline(always)] pub(crate) fn aesdec(value: u128, xor: u128) -> u128 { - #[cfg(target_arch = "arm")] - use core::arch::arm::*; #[cfg(target_arch = "aarch64")] use core::arch::aarch64::*; - use core::mem::transmute; - unsafe { - let value = transmute(value); - transmute(vaesimcq_u8(vaesdq_u8(value, transmute(xor)))) + #[cfg(target_arch = "arm")] + use core::arch::arm::*; + let res = unsafe { vaesimcq_u8(vaesdq_u8(transmute!(value), transmute!(0u128))) }; + let value: u128 = transmute!(res); + xor ^ value +} + +#[allow(unused)] +#[inline(always)] +pub(crate) fn add_in_length(enc: &mut u128, len: u64) { + #[cfg(all(target_arch = "x86_64", target_feature = "sse2", not(miri)))] + { + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + + unsafe { + let enc = enc as *mut u128; + let len = _mm_cvtsi64_si128(len as i64); + let data = _mm_loadu_si128(enc.cast()); + let sum = _mm_add_epi64(data, len); + _mm_storeu_si128(enc.cast(), sum); + } + } + #[cfg(not(all(target_arch = "x86_64", target_feature = "sse2", not(miri))))] + { + let mut t: [u64; 2] = enc.convert(); + t[0] = t[0].wrapping_add(len); + *enc = t.convert(); } } #[cfg(test)] mod test { use super::*; - use crate::convert::Convert; // This is code to search for the shuffle constant // @@ -162,7 +196,7 @@ mod test { // #[cfg(target_arch = "x86_64")] // use core::arch::x86_64::*; // MASK.with(|mask| { - // unsafe { transmute(_mm_shuffle_epi8(transmute(a), transmute(mask.get()))) } + // unsafe { transmute!(_mm_shuffle_epi8(transmute!(a), transmute!(mask.get()))) } // }) // } // @@ -327,4 +361,12 @@ mod test { shuffled = shuffle(shuffled); } } + + #[test] + fn test_add_length() { + let mut enc = (u64::MAX as u128) << 64 | 50; + add_in_length(&mut enc, u64::MAX); + assert_eq!(enc >> 64, u64::MAX as u128); + assert_eq!(enc as u64, 49); + } } diff --git a/third_party/rust/ahash/src/random_state.rs b/third_party/rust/ahash/src/random_state.rs index 9ac2f3ec43..46a39ab068 100644 --- a/third_party/rust/ahash/src/random_state.rs +++ b/third_party/rust/ahash/src/random_state.rs @@ -1,33 +1,27 @@ -#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))] -use crate::convert::Convert; -#[cfg(feature = "specialize")] -use crate::BuildHasherExt; - -#[cfg(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -))] -pub use crate::aes_hash::*; - -#[cfg(not(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -)))] -pub use crate::fallback_hash::*; - -#[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))] -use const_random::const_random; -use core::any::{Any, TypeId}; -use core::fmt; -use core::hash::BuildHasher; -#[cfg(feature = "specialize")] use core::hash::Hash; -use core::hash::Hasher; - -#[cfg(not(feature = "std"))] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std as alloc; +cfg_if::cfg_if! { + if #[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), + ))] { + use crate::aes_hash::*; + } else { + use crate::fallback_hash::*; + } +} +cfg_if::cfg_if! { + if #[cfg(feature = "specialize")]{ + use crate::BuildHasherExt; + } +} +cfg_if::cfg_if! { + if #[cfg(feature = "std")] { + extern crate std as alloc; + } else { + extern crate alloc; + } +} #[cfg(feature = "atomic-polyfill")] use atomic_polyfill as atomic; @@ -36,32 +30,10 @@ use core::sync::atomic; use alloc::boxed::Box; use atomic::{AtomicUsize, Ordering}; -#[cfg(not(all(target_arch = "arm", target_os = "none")))] -use once_cell::race::OnceBox; - -#[cfg(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -))] -use crate::aes_hash::*; -#[cfg(not(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -)))] -use crate::fallback_hash::*; - -#[cfg(not(all(target_arch = "arm", target_os = "none")))] -static RAND_SOURCE: OnceBox> = OnceBox::new(); - -/// A supplier of Randomness used for different hashers. -/// See [RandomState.set_random_source]. -pub trait RandomSource { - - fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2]; - - fn gen_hasher_seed(&self) -> usize; - -} +use core::any::{Any, TypeId}; +use core::fmt; +use core::hash::BuildHasher; +use core::hash::Hasher; pub(crate) const PI: [u64; 4] = [ 0x243f_6a88_85a3_08d3, @@ -77,6 +49,90 @@ pub(crate) const PI2: [u64; 4] = [ 0x3f84_d5b5_b547_0917, ]; +cfg_if::cfg_if! { + if #[cfg(all(feature = "compile-time-rng", any(test, fuzzing)))] { + #[inline] + fn get_fixed_seeds() -> &'static [[u64; 4]; 2] { + use const_random::const_random; + + const RAND: [[u64; 4]; 2] = [ + [ + const_random!(u64), + const_random!(u64), + const_random!(u64), + const_random!(u64), + ], [ + const_random!(u64), + const_random!(u64), + const_random!(u64), + const_random!(u64), + ] + ]; + &RAND + } + } else if #[cfg(all(feature = "runtime-rng", not(fuzzing)))] { + #[inline] + fn get_fixed_seeds() -> &'static [[u64; 4]; 2] { + use crate::convert::Convert; + + static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new(); + + SEEDS.get_or_init(|| { + let mut result: [u8; 64] = [0; 64]; + getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed."); + Box::new(result.convert()) + }) + } + } else if #[cfg(feature = "compile-time-rng")] { + #[inline] + fn get_fixed_seeds() -> &'static [[u64; 4]; 2] { + use const_random::const_random; + + const RAND: [[u64; 4]; 2] = [ + [ + const_random!(u64), + const_random!(u64), + const_random!(u64), + const_random!(u64), + ], [ + const_random!(u64), + const_random!(u64), + const_random!(u64), + const_random!(u64), + ] + ]; + &RAND + } + } else { + #[inline] + fn get_fixed_seeds() -> &'static [[u64; 4]; 2] { + &[PI, PI2] + } + } +} + +cfg_if::cfg_if! { + if #[cfg(not(all(target_arch = "arm", target_os = "none")))] { + use once_cell::race::OnceBox; + + static RAND_SOURCE: OnceBox> = OnceBox::new(); + } +} +/// A supplier of Randomness used for different hashers. +/// See [set_random_source]. +/// +/// If [set_random_source] aHash will default to the best available source of randomness. +/// In order this is: +/// 1. OS provided random number generator (available if the `runtime-rng` flag is enabled which it is by default) - This should be very strong. +/// 2. Strong compile time random numbers used to permute a static "counter". (available if `compile-time-rng` is enabled. +/// __Enabling this is recommended if `runtime-rng` is not possible__) +/// 3. A static counter that adds the memory address of each [RandomState] created permuted with fixed constants. +/// (Similar to above but with fixed keys) - This is the weakest option. The strength of this heavily depends on whether or not ASLR is enabled. +/// (Rust enables ASLR by default) +pub trait RandomSource { + fn gen_hasher_seed(&self) -> usize; +} + struct DefaultRandomSource { counter: AtomicUsize, } @@ -88,6 +144,7 @@ impl DefaultRandomSource { } } + #[cfg(all(target_arch = "arm", target_os = "none"))] const fn default() -> DefaultRandomSource { DefaultRandomSource { counter: AtomicUsize::new(PI[3] as usize), @@ -96,55 +153,50 @@ impl DefaultRandomSource { } impl RandomSource for DefaultRandomSource { - - #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))] - fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] { - static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new(); - - SEEDS.get_or_init(|| { - let mut result: [u8; 64] = [0; 64]; - getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed."); - Box::new(result.convert()) - }) - } - - #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))] - fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] { - const RAND: [[u64; 4]; 2] = [ - [ - const_random!(u64), - const_random!(u64), - const_random!(u64), - const_random!(u64), - ], [ - const_random!(u64), - const_random!(u64), - const_random!(u64), - const_random!(u64), - ] - ]; - &RAND - } - - #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))] - fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] { - &[PI, PI2] - } - - #[cfg(not(all(target_arch = "arm", target_os = "none")))] - fn gen_hasher_seed(&self) -> usize { - let stack = self as *const _ as usize; - self.counter.fetch_add(stack, Ordering::Relaxed) + cfg_if::cfg_if! { + if #[cfg(all(target_arch = "arm", target_os = "none"))] { + fn gen_hasher_seed(&self) -> usize { + let stack = self as *const _ as usize; + let previous = self.counter.load(Ordering::Relaxed); + let new = previous.wrapping_add(stack); + self.counter.store(new, Ordering::Relaxed); + new + } + } else { + fn gen_hasher_seed(&self) -> usize { + let stack = self as *const _ as usize; + self.counter.fetch_add(stack, Ordering::Relaxed) + } + } } +} - #[cfg(all(target_arch = "arm", target_os = "none"))] - fn gen_hasher_seed(&self) -> usize { - let stack = self as *const _ as usize; - let previous = self.counter.load(Ordering::Relaxed); - let new = previous.wrapping_add(stack); - self.counter.store(new, Ordering::Relaxed); - new - } +cfg_if::cfg_if! { + if #[cfg(all(target_arch = "arm", target_os = "none"))] { + #[inline] + fn get_src() -> &'static dyn RandomSource { + static RAND_SOURCE: DefaultRandomSource = DefaultRandomSource::default(); + &RAND_SOURCE + } + } else { + /// Provides an optional way to manually supply a source of randomness for Hasher keys. + /// + /// The provided [RandomSource] will be used to be used as a source of randomness by [RandomState] to generate new states. + /// If this method is not invoked the standard source of randomness is used as described in the Readme. + /// + /// The source of randomness can only be set once, and must be set before the first RandomState is created. + /// If the source has already been specified `Err` is returned with a `bool` indicating if the set failed because + /// method was previously invoked (true) or if the default source is already being used (false). + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + pub fn set_random_source(source: impl RandomSource + Send + Sync + 'static) -> Result<(), bool> { + RAND_SOURCE.set(Box::new(Box::new(source))).map_err(|s| s.as_ref().type_id() != TypeId::of::<&DefaultRandomSource>()) + } + + #[inline] + fn get_src() -> &'static dyn RandomSource { + RAND_SOURCE.get_or_init(|| Box::new(Box::new(DefaultRandomSource::new()))).as_ref() + } + } } /// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create @@ -154,6 +206,16 @@ impl RandomSource for DefaultRandomSource { /// [Hasher]: std::hash::Hasher /// [BuildHasher]: std::hash::BuildHasher /// [HashMap]: std::collections::HashMap +/// +/// There are multiple constructors each is documented in more detail below: +/// +/// | Constructor | Dynamically random? | Seed | +/// |---------------|---------------------|------| +/// |`new` | Each instance unique|_[RandomSource]_| +/// |`generate_with`| Each instance unique|`u64` x 4 + [RandomSource]| +/// |`with_seed` | Fixed per process |`u64` + static random number| +/// |`with_seeds` | Fixed |`u64` x 4| +/// #[derive(Clone)] pub struct RandomState { pub(crate) k0: u64, @@ -169,47 +231,30 @@ impl fmt::Debug for RandomState { } impl RandomState { - - /// Provides an optional way to manually supply a source of randomness for Hasher keys. + /// Create a new `RandomState` `BuildHasher` using random keys. /// - /// The provided [RandomSource] will be used to be used as a source of randomness by [RandomState] to generate new states. - /// If this method is not invoked the standard source of randomness is used as described in the Readme. + /// Each instance will have a unique set of keys derived from [RandomSource]. /// - /// The source of randomness can only be set once, and must be set before the first RandomState is created. - /// If the source has already been specified `Err` is returned with a `bool` indicating if the set failed because - /// method was previously invoked (true) or if the default source is already being used (false). - #[cfg(not(all(target_arch = "arm", target_os = "none")))] - pub fn set_random_source(source: impl RandomSource + Send + Sync + 'static) -> Result<(), bool> { - RAND_SOURCE.set(Box::new(Box::new(source))).map_err(|s| s.as_ref().type_id() != TypeId::of::<&DefaultRandomSource>()) - } - - #[inline] - #[cfg(not(all(target_arch = "arm", target_os = "none")))] - fn get_src() -> &'static dyn RandomSource { - RAND_SOURCE.get_or_init(|| Box::new(Box::new(DefaultRandomSource::new()))).as_ref() - } - - #[inline] - #[cfg(all(target_arch = "arm", target_os = "none"))] - fn get_src() -> &'static dyn RandomSource { - static RAND_SOURCE: DefaultRandomSource = DefaultRandomSource::default(); - &RAND_SOURCE - } - - /// Use randomly generated keys #[inline] pub fn new() -> RandomState { - let src = Self::get_src(); - let fixed = src.get_fixed_seeds(); + let src = get_src(); + let fixed = get_fixed_seeds(); Self::from_keys(&fixed[0], &fixed[1], src.gen_hasher_seed()) } - /// Allows for supplying seeds, but each time it is called the resulting state will be different. - /// This is done using a static counter, so it can safely be used with a fixed keys. + /// Create a new `RandomState` `BuildHasher` based on the provided seeds, but in such a way + /// that each time it is called the resulting state will be different and of high quality. + /// This allows fixed constant or poor quality seeds to be provided without the problem of different + /// `BuildHasher`s being identical or weak. + /// + /// This is done via permuting the provided values with the value of a static counter and memory address. + /// (This makes this method somewhat more expensive than `with_seeds` below which does not do this). + /// + /// The provided values (k0-k3) do not need to be of high quality but they should not all be the same value. #[inline] pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState { - let src = Self::get_src(); - let fixed = src.get_fixed_seeds(); + let src = get_src(); + let fixed = get_fixed_seeds(); RandomState::from_keys(&fixed[0], &[k0, k1, k2, k3], src.gen_hasher_seed()) } @@ -217,45 +262,117 @@ impl RandomState { let &[k0, k1, k2, k3] = a; let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 }); hasher.write_usize(c); - let mix = |k: u64| { + let mix = |l: u64, r: u64| { let mut h = hasher.clone(); - h.write_u64(k); + h.write_u64(l); + h.write_u64(r); h.finish() }; RandomState { - k0: mix(b[0]), - k1: mix(b[1]), - k2: mix(b[2]), - k3: mix(b[3]), + k0: mix(b[0], b[2]), + k1: mix(b[1], b[3]), + k2: mix(b[2], b[1]), + k3: mix(b[3], b[0]), } } /// Internal. Used by Default. #[inline] pub(crate) fn with_fixed_keys() -> RandomState { - let [k0, k1, k2, k3] = Self::get_src().get_fixed_seeds()[0]; + let [k0, k1, k2, k3] = get_fixed_seeds()[0]; RandomState { k0, k1, k2, k3 } } - /// Allows for explicitly setting a seed to used. + /// Build a `RandomState` from a single key. The provided key does not need to be of high quality, + /// but all `RandomState`s created from the same key will produce identical hashers. + /// (In contrast to `generate_with` above) + /// + /// This allows for explicitly setting the seed to be used. /// /// Note: This method does not require the provided seed to be strong. #[inline] pub fn with_seed(key: usize) -> RandomState { - let fixed = Self::get_src().get_fixed_seeds(); + let fixed = get_fixed_seeds(); RandomState::from_keys(&fixed[0], &fixed[1], key) } /// Allows for explicitly setting the seeds to used. + /// All `RandomState`s created with the same set of keys key will produce identical hashers. + /// (In contrast to `generate_with` above) /// - /// Note: This method is robust against 0s being passed for one or more of the parameters - /// or the same value being passed for more than one parameter. + /// Note: If DOS resistance is desired one of these should be a decent quality random number. + /// If 4 high quality random number are not cheaply available this method is robust against 0s being passed for + /// one or more of the parameters or the same value being passed for more than one parameter. + /// It is recommended to pass numbers in order from highest to lowest quality (if there is any difference). #[inline] pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState { - RandomState { k0: k0 ^ PI2[0], k1: k1 ^ PI2[1], k2: k2 ^ PI2[2], k3: k3 ^ PI2[3] } + RandomState { + k0: k0 ^ PI2[0], + k1: k1 ^ PI2[1], + k2: k2 ^ PI2[2], + k3: k3 ^ PI2[3], + } + } + + /// Calculates the hash of a single value. This provides a more convenient (and faster) way to obtain a hash: + /// For example: + #[cfg_attr( + feature = "std", + doc = r##" # Examples +``` + use std::hash::BuildHasher; + use ahash::RandomState; + + let hash_builder = RandomState::new(); + let hash = hash_builder.hash_one("Some Data"); +``` + "## + )] + /// This is similar to: + #[cfg_attr( + feature = "std", + doc = r##" # Examples +``` + use std::hash::{BuildHasher, Hash, Hasher}; + use ahash::RandomState; + + let hash_builder = RandomState::new(); + let mut hasher = hash_builder.build_hasher(); + "Some Data".hash(&mut hasher); + let hash = hasher.finish(); +``` + "## + )] + /// (Note that these two ways to get a hash may not produce the same value for the same data) + /// + /// This is intended as a convenience for code which *consumes* hashes, such + /// as the implementation of a hash table or in unit tests that check + /// whether a custom [`Hash`] implementation behaves as expected. + /// + /// This must not be used in any code which *creates* hashes, such as in an + /// implementation of [`Hash`]. The way to create a combined hash of + /// multiple values is to call [`Hash::hash`] multiple times using the same + /// [`Hasher`], not to call this method repeatedly and combine the results. + #[inline] + pub fn hash_one(&self, x: T) -> u64 + where + Self: Sized, + { + use crate::specialize::CallHasher; + T::get_hash(&x, self) } } +/// Creates an instance of RandomState using keys obtained from the random number generator. +/// Each instance created in this way will have a unique set of keys. (But the resulting instance +/// can be used to create many hashers each or which will have the same keys.) +/// +/// This is the same as [RandomState::new()] +/// +/// NOTE: For safety this trait impl is only available available if either of the flags `runtime-rng` (on by default) or +/// `compile-time-rng` are enabled. This is to prevent weakly keyed maps from being accidentally created. Instead one of +/// constructors for [RandomState] must be used. +#[cfg(any(feature = "compile-time-rng", feature = "runtime-rng", feature = "no-rng"))] impl Default for RandomState { #[inline] fn default() -> Self { @@ -271,26 +388,29 @@ impl BuildHasher for RandomState { /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher] /// will generate the same hashes for the same input data. /// - /// # Examples - /// - /// ``` - /// use ahash::{AHasher, RandomState}; - /// use std::hash::{Hasher, BuildHasher}; - /// - /// let build_hasher = RandomState::new(); - /// let mut hasher_1 = build_hasher.build_hasher(); - /// let mut hasher_2 = build_hasher.build_hasher(); - /// - /// hasher_1.write_u32(1234); - /// hasher_2.write_u32(1234); - /// - /// assert_eq!(hasher_1.finish(), hasher_2.finish()); - /// - /// let other_build_hasher = RandomState::new(); - /// let mut different_hasher = other_build_hasher.build_hasher(); - /// different_hasher.write_u32(1234); - /// assert_ne!(different_hasher.finish(), hasher_1.finish()); - /// ``` + #[cfg_attr( + feature = "std", + doc = r##" # Examples +``` + use ahash::{AHasher, RandomState}; + use std::hash::{Hasher, BuildHasher}; + + let build_hasher = RandomState::new(); + let mut hasher_1 = build_hasher.build_hasher(); + let mut hasher_2 = build_hasher.build_hasher(); + + hasher_1.write_u32(1234); + hasher_2.write_u32(1234); + + assert_eq!(hasher_1.finish(), hasher_2.finish()); + + let other_build_hasher = RandomState::new(); + let mut different_hasher = other_build_hasher.build_hasher(); + different_hasher.write_u32(1234); + assert_ne!(different_hasher.finish(), hasher_1.finish()); +``` + "## + )] /// [Hasher]: std::hash::Hasher /// [BuildHasher]: std::hash::BuildHasher /// [HashMap]: std::collections::HashMap @@ -298,6 +418,51 @@ impl BuildHasher for RandomState { fn build_hasher(&self) -> AHasher { AHasher::from_random_state(self) } + + /// Calculates the hash of a single value. This provides a more convenient (and faster) way to obtain a hash: + /// For example: + #[cfg_attr( + feature = "std", + doc = r##" # Examples +``` + use std::hash::BuildHasher; + use ahash::RandomState; + + let hash_builder = RandomState::new(); + let hash = hash_builder.hash_one("Some Data"); +``` + "## + )] + /// This is similar to: + #[cfg_attr( + feature = "std", + doc = r##" # Examples +``` + use std::hash::{BuildHasher, Hash, Hasher}; + use ahash::RandomState; + + let hash_builder = RandomState::new(); + let mut hasher = hash_builder.build_hasher(); + "Some Data".hash(&mut hasher); + let hash = hasher.finish(); +``` + "## + )] + /// (Note that these two ways to get a hash may not produce the same value for the same data) + /// + /// This is intended as a convenience for code which *consumes* hashes, such + /// as the implementation of a hash table or in unit tests that check + /// whether a custom [`Hash`] implementation behaves as expected. + /// + /// This must not be used in any code which *creates* hashes, such as in an + /// implementation of [`Hash`]. The way to create a combined hash of + /// multiple values is to call [`Hash::hash`] multiple times using the same + /// [`Hasher`], not to call this method repeatedly and combine the results. + #[cfg(feature = "specialize")] + #[inline] + fn hash_one(&self, x: T) -> u64 { + RandomState::hash_one(self, x) + } } #[cfg(feature = "specialize")] @@ -305,8 +470,8 @@ impl BuildHasherExt for RandomState { #[inline] fn hash_as_u64(&self, value: &T) -> u64 { let mut hasher = AHasherU64 { - buffer: self.k0, - pad: self.k1, + buffer: self.k1, + pad: self.k0, }; value.hash(&mut hasher); hasher.finish() @@ -333,27 +498,27 @@ mod test { #[test] fn test_unique() { - let a = RandomState::new(); - let b = RandomState::new(); + let a = RandomState::generate_with(1, 2, 3, 4); + let b = RandomState::generate_with(1, 2, 3, 4); assert_ne!(a.build_hasher().finish(), b.build_hasher().finish()); } #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))] #[test] fn test_not_pi() { - assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]); + assert_ne!(PI, get_fixed_seeds()[0]); } #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))] #[test] fn test_not_pi_const() { - assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]); + assert_ne!(PI, get_fixed_seeds()[0]); } #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))] #[test] fn test_pi() { - assert_eq!(PI, RandomState::get_src().get_fixed_seeds()[0]); + assert_eq!(PI, get_fixed_seeds()[0]); } #[test] diff --git a/third_party/rust/ahash/src/specialize.rs b/third_party/rust/ahash/src/specialize.rs index d94a4eed0d..05d335b191 100644 --- a/third_party/rust/ahash/src/specialize.rs +++ b/third_party/rust/ahash/src/specialize.rs @@ -17,28 +17,7 @@ use alloc::vec::Vec; /// Provides a way to get an optimized hasher for a given data type. /// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash /// for a specific type. So this may be faster for primitive types. -/// # Example -/// ``` -/// use std::hash::BuildHasher; -/// use ahash::RandomState; -/// use ahash::CallHasher; -/// -/// let hash_builder = RandomState::new(); -/// //... -/// let value: u32 = 17; -/// let hash = u32::get_hash(&value, &hash_builder); -/// ``` -/// Note that the type used to invoke `get_hash` must be the same a the type of value passed. -/// For example get a hasher specialized on `[u8]` can invoke: -/// ``` -/// /// use std::hash::BuildHasher; -/// # use ahash::RandomState; -/// # use ahash::CallHasher; -/// # let hash_builder = RandomState::new(); -/// let bytes: [u8; 4] = [1, 2, 3, 4]; -/// let hash = <[u8]>::get_hash(&bytes, &hash_builder); -/// ``` -pub trait CallHasher { +pub(crate) trait CallHasher { fn get_hash(value: &H, build_hasher: &B) -> u64; } diff --git a/third_party/rust/ahash/tests/bench.rs b/third_party/rust/ahash/tests/bench.rs index 9e6dccc481..2d000c0a6a 100644 --- a/third_party/rust/ahash/tests/bench.rs +++ b/third_party/rust/ahash/tests/bench.rs @@ -1,39 +1,35 @@ -use ahash::{CallHasher, RandomState}; +#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))] + +use ahash::{AHasher, RandomState}; use criterion::*; use fxhash::FxHasher; +use rand::Rng; use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; - -#[cfg(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -))] -fn aeshash(b: &H) -> u64 { +use std::hash::{BuildHasherDefault, Hash, Hasher}; + +// Needs to be in sync with `src/lib.rs` +const AHASH_IMPL: &str = if cfg!(any( + all( + any(target_arch = "x86", target_arch = "x86_64"), + target_feature = "aes", + not(miri), + ), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), + all( + feature = "nightly-arm-aes", + target_arch = "arm", + target_feature = "aes", + not(miri) + ), +)) { + "aeshash" +} else { + "fallbackhash" +}; + +fn ahash(b: &H) -> u64 { let build_hasher = RandomState::with_seeds(1, 2, 3, 4); - H::get_hash(b, &build_hasher) -} -#[cfg(not(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -)))] -fn aeshash(_b: &H) -> u64 { - panic!("aes must be enabled") -} - -#[cfg(not(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -)))] -fn fallbackhash(b: &H) -> u64 { - let build_hasher = RandomState::with_seeds(1, 2, 3, 4); - H::get_hash(b, &build_hasher) -} -#[cfg(any( - all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") -))] -fn fallbackhash(_b: &H) -> u64 { - panic!("aes must be disabled") + build_hasher.hash_one(b) } fn fnvhash(b: &H) -> u64 { @@ -76,79 +72,128 @@ fn gen_strings() -> Vec { .collect() } -const U8_VALUE: u8 = 123; -const U16_VALUE: u16 = 1234; -const U32_VALUE: u32 = 12345678; -const U64_VALUE: u64 = 1234567890123456; -const U128_VALUE: u128 = 12345678901234567890123456789012; - -fn bench_ahash(c: &mut Criterion) { - let mut group = c.benchmark_group("aeshash"); - group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); - group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); - group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); - group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); - group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); - group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(aeshash(s)))); +macro_rules! bench_inputs { + ($group:ident, $hash:ident) => { + // Number of iterations per batch should be high enough to hide timing overhead. + let size = BatchSize::NumIterations(50_000); + + let mut rng = rand::thread_rng(); + $group.bench_function("u8", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); + $group.bench_function("u16", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); + $group.bench_function("u32", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); + $group.bench_function("u64", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); + $group.bench_function("u128", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); + $group.bench_with_input("strings", &gen_strings(), |b, s| b.iter(|| $hash(black_box(s)))); + }; } -fn bench_fallback(c: &mut Criterion) { - let mut group = c.benchmark_group("fallback"); - group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); - group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); - group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); - group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); - group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); - group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(fallbackhash(s)))); +fn bench_ahash(c: &mut Criterion) { + let mut group = c.benchmark_group(AHASH_IMPL); + bench_inputs!(group, ahash); } fn bench_fx(c: &mut Criterion) { let mut group = c.benchmark_group("fx"); - group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); - group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); - group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); - group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); - group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); - group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(fxhash(s)))); + bench_inputs!(group, fxhash); } fn bench_fnv(c: &mut Criterion) { let mut group = c.benchmark_group("fnv"); - group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); - group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); - group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); - group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); - group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); - group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(fnvhash(s)))); + bench_inputs!(group, fnvhash); } fn bench_sea(c: &mut Criterion) { let mut group = c.benchmark_group("sea"); - group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); - group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); - group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); - group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); - group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); - group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(seahash(s)))); + bench_inputs!(group, seahash); } fn bench_sip(c: &mut Criterion) { let mut group = c.benchmark_group("sip"); - group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); - group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); - group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); - group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); - group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); - group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(siphash(s)))); + bench_inputs!(group, siphash); +} + +fn bench_map(c: &mut Criterion) { + #[cfg(feature = "std")] + { + let mut group = c.benchmark_group("map"); + group.bench_function("aHash-alias", |b| { + b.iter(|| { + let hm: ahash::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); + let mut sum = 0; + for i in 0..1_000_000 { + if let Some(x) = hm.get(&i) { + sum += x; + } + } + }) + }); + group.bench_function("aHash-hashBrown", |b| { + b.iter(|| { + let hm: hashbrown::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); + let mut sum = 0; + for i in 0..1_000_000 { + if let Some(x) = hm.get(&i) { + sum += x; + } + } + }) + }); + group.bench_function("aHash-hashBrown-explicit", |b| { + b.iter(|| { + let hm: hashbrown::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); + let mut sum = 0; + for i in 0..1_000_000 { + if let Some(x) = hm.get(&i) { + sum += x; + } + } + }) + }); + group.bench_function("aHash-wrapper", |b| { + b.iter(|| { + let hm: ahash::AHashMap = (0..1_000_000).map(|i| (i, i)).collect(); + let mut sum = 0; + for i in 0..1_000_000 { + if let Some(x) = hm.get(&i) { + sum += x; + } + } + }) + }); + group.bench_function("aHash-rand", |b| { + b.iter(|| { + let hm: std::collections::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); + let mut sum = 0; + for i in 0..1_000_000 { + if let Some(x) = hm.get(&i) { + sum += x; + } + } + }) + }); + group.bench_function("aHash-default", |b| { + b.iter(|| { + let hm: std::collections::HashMap> = + (0..1_000_000).map(|i| (i, i)).collect(); + let mut sum = 0; + for i in 0..1_000_000 { + if let Some(x) = hm.get(&i) { + sum += x; + } + } + }) + }); + } } criterion_main!(benches); + criterion_group!( benches, bench_ahash, - bench_fallback, bench_fx, bench_fnv, bench_sea, - bench_sip + bench_sip, + bench_map ); diff --git a/third_party/rust/ahash/tests/map_tests.rs b/third_party/rust/ahash/tests/map_tests.rs index be617a2e72..97fdbee0f9 100644 --- a/third_party/rust/ahash/tests/map_tests.rs +++ b/third_party/rust/ahash/tests/map_tests.rs @@ -1,10 +1,11 @@ +#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))] + use std::hash::{BuildHasher, Hash, Hasher}; +use ahash::RandomState; use criterion::*; use fxhash::FxHasher; -use ahash::{AHasher, CallHasher, RandomState}; - fn gen_word_pairs() -> Vec { let words: Vec<_> = r#" a, ability, able, about, above, accept, according, account, across, act, action, @@ -150,9 +151,18 @@ fn check_for_collisions(build_hasher: &B, items: &[H], ); } +#[cfg(feature = "specialize")] +#[allow(unused)] // False positive +fn hash(b: &H, build_hasher: &B) -> u64 { + build_hasher.hash_one(b) +} + +#[cfg(not(feature = "specialize"))] #[allow(unused)] // False positive fn hash(b: &H, build_hasher: &B) -> u64 { - H::get_hash(b, build_hasher) + let mut hasher = build_hasher.build_hasher(); + b.hash(&mut hasher); + hasher.finish() } #[test] @@ -169,10 +179,107 @@ fn test_bucket_distribution() { check_for_collisions(&build_hasher, &sequence, 256); } +#[cfg(feature = "std")] +#[test] +fn test_ahash_alias_map_construction() { + let mut map = ahash::HashMap::default(); + map.insert(1, "test"); + use ahash::HashMapExt; + let mut map = ahash::HashMap::with_capacity(1234); + map.insert(1, "test"); +} + +#[cfg(feature = "std")] +#[test] +fn test_ahash_alias_set_construction() { + let mut set = ahash::HashSet::default(); + set.insert(1); + + use ahash::HashSetExt; + let mut set = ahash::HashSet::with_capacity(1235); + set.insert(1); +} + + +#[cfg(feature = "std")] +#[test] +fn test_key_ref() { + let mut map = ahash::HashMap::default(); + map.insert(1, "test"); + assert_eq!(Some((1, "test")), map.remove_entry(&1)); + + let mut map = ahash::HashMap::default(); + map.insert(&1, "test"); + assert_eq!(Some((&1, "test")), map.remove_entry(&&1)); + + let mut m = ahash::HashSet::>::default(); + m.insert(Box::from("hello".to_string())); + assert!(m.contains(&"hello".to_string())); + + let mut m = ahash::HashSet::::default(); + m.insert("hello".to_string()); + assert!(m.contains("hello")); + + let mut m = ahash::HashSet::>::default(); + m.insert(Box::from(&b"hello"[..])); + assert!(m.contains(&b"hello"[..])); +} + +#[cfg(feature = "std")] +#[test] +fn test_byte_dist() { + use rand::{SeedableRng, Rng, RngCore}; + use pcg_mwc::Mwc256XXA64; + + let mut r = Mwc256XXA64::seed_from_u64(0xe786_c22b_119c_1479); + let mut lowest = 2.541; + let mut highest = 2.541; + for _round in 0..100 { + let mut table: [bool; 256 * 8] = [false; 256 * 8]; + let hasher = RandomState::with_seeds(r.gen(), r.gen(), r.gen(), r.gen()); + for i in 0..128 { + let mut keys: [u8; 8] = hasher.hash_one((i as u64) << 30).to_ne_bytes(); + //let mut keys = r.next_u64().to_ne_bytes(); //This is a control to test assert sensitivity. + for idx in 0..8 { + while table[idx * 256 + keys[idx] as usize] { + keys[idx] = keys[idx].wrapping_add(1); + } + table[idx * 256 + keys[idx] as usize] = true; + } + } + + for idx in 0..8 { + let mut len = 0; + let mut total_len = 0; + let mut num_seq = 0; + for i in 0..256 { + if table[idx * 256 + i] { + len += 1; + } else if len != 0 { + num_seq += 1; + total_len += len; + len = 0; + } + } + let mean = total_len as f32 / num_seq as f32; + println!("Mean sequence length = {}", mean); + if mean > highest { + highest = mean; + } + if mean < lowest { + lowest = mean; + } + } + } + assert!(lowest > 1.9, "Lowest = {}", lowest); + assert!(highest < 3.9, "Highest = {}", highest); +} + + fn ahash_vec(b: &Vec) -> u64 { let mut total: u64 = 0; for item in b { - let mut hasher = AHasher::new_with_keys(1234, 5678); + let mut hasher = RandomState::with_seeds(12, 34, 56, 78).build_hasher(); item.hash(&mut hasher); total = total.wrapping_add(hasher.finish()); } diff --git a/third_party/rust/ahash/tests/nopanic.rs b/third_party/rust/ahash/tests/nopanic.rs index d48ff559d2..56f754cbee 100644 --- a/third_party/rust/ahash/tests/nopanic.rs +++ b/third_party/rust/ahash/tests/nopanic.rs @@ -1,5 +1,5 @@ -use ahash::{AHasher, CallHasher, RandomState}; -use std::hash::BuildHasher; +use ahash::{AHasher, RandomState}; +use std::hash::{BuildHasher, Hash, Hasher}; #[macro_use] extern crate no_panic; @@ -8,8 +8,8 @@ extern crate no_panic; #[no_panic] fn hash_test_final(num: i32, string: &str) -> (u64, u64) { use core::hash::Hasher; - let mut hasher1 = AHasher::new_with_keys(1, 2); - let mut hasher2 = AHasher::new_with_keys(3, 4); + let mut hasher1 = RandomState::with_seeds(1, 2, 3, 4).build_hasher(); + let mut hasher2 = RandomState::with_seeds(3, 4, 5, 6).build_hasher(); hasher1.write_i32(num); hasher2.write(string.as_bytes()); (hasher1.finish(), hasher2.finish()) @@ -24,6 +24,17 @@ struct SimpleBuildHasher { hasher: AHasher, } +impl SimpleBuildHasher { + fn hash_one(&self, x: T) -> u64 + where + Self: Sized, + { + let mut hasher = self.build_hasher(); + x.hash(&mut hasher); + hasher.finish() + } +} + impl BuildHasher for SimpleBuildHasher { type Hasher = AHasher; @@ -35,11 +46,11 @@ impl BuildHasher for SimpleBuildHasher { #[inline(never)] #[no_panic] fn hash_test_specialize(num: i32, string: &str) -> (u64, u64) { - let hasher1 = AHasher::new_with_keys(1, 2); - let hasher2 = AHasher::new_with_keys(1, 2); + let hasher1 = RandomState::with_seeds(1, 2, 3, 4).build_hasher(); + let hasher2 = RandomState::with_seeds(1, 2, 3, 4).build_hasher(); ( - i32::get_hash(&num, &SimpleBuildHasher { hasher: hasher1 }), - <[u8]>::get_hash(string.as_bytes(), &SimpleBuildHasher { hasher: hasher2 }), + SimpleBuildHasher { hasher: hasher1 }.hash_one(num), + SimpleBuildHasher { hasher: hasher2 }.hash_one(string.as_bytes()), ) } @@ -53,10 +64,7 @@ fn hash_test_random_wrapper(num: i32, string: &str) { fn hash_test_random(num: i32, string: &str) -> (u64, u64) { let build_hasher1 = RandomState::with_seeds(1, 2, 3, 4); let build_hasher2 = RandomState::with_seeds(1, 2, 3, 4); - ( - i32::get_hash(&num, &build_hasher1), - <[u8]>::get_hash(string.as_bytes(), &build_hasher2), - ) + (build_hasher1.hash_one(&num), build_hasher2.hash_one(string.as_bytes())) } #[inline(never)] @@ -68,5 +76,6 @@ fn hash_test_specialize_wrapper(num: i32, string: &str) { fn test_no_panic() { hash_test_final_wrapper(2, "Foo"); hash_test_specialize_wrapper(2, "Bar"); - hash_test_random_wrapper(2, "Baz"); + hash_test_random(2, "Baz"); + hash_test_random_wrapper(2, "Bat"); } diff --git a/third_party/rust/any_all_workaround/.cargo-checksum.json b/third_party/rust/any_all_workaround/.cargo-checksum.json new file mode 100644 index 0000000000..8d16e68a7e --- /dev/null +++ b/third_party/rust/any_all_workaround/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"f8c127449dc9432d404c21c99833e4617ab88a797445af249a7fe3c989985d6d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","LICENSE-MIT-QCMS":"36d847ae882f6574ebc72f56a4f354e4f104fde4a584373496482e97d52d31bc","README.md":"4c617b8ced3a27b7edecf0e5e41ed451c04e88dab529e7a35fccc4e1551efbd7","build.rs":"56b29ab6da3e49075bfd0a7b690267c8016298bf0d332e2e68bbaf19decbbf71","src/lib.rs":"7118106690b9d25c5d0a3e2079feb83d76f1d434d0da36b9d0351806d27c850d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/any_all_workaround/Cargo.toml b/third_party/rust/any_all_workaround/Cargo.toml new file mode 100644 index 0000000000..4b03a35781 --- /dev/null +++ b/third_party/rust/any_all_workaround/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "any_all_workaround" +version = "0.1.0" +authors = ["Henri Sivonen "] +description = "Workaround for bad LLVM codegen for boolean reductions on 32-bit ARM" +homepage = "https://docs.rs/any_all_workaround/" +documentation = "https://docs.rs/any_all_workaround/" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/hsivonen/any_all_workaround" + +[dependencies] +cfg-if = "1.0" + +[build-dependencies] +version_check = "0.9" diff --git a/third_party/rust/any_all_workaround/LICENSE-APACHE b/third_party/rust/any_all_workaround/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/any_all_workaround/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/any_all_workaround/LICENSE-MIT b/third_party/rust/any_all_workaround/LICENSE-MIT new file mode 100644 index 0000000000..39d4bdb5ac --- /dev/null +++ b/third_party/rust/any_all_workaround/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/any_all_workaround/LICENSE-MIT-QCMS b/third_party/rust/any_all_workaround/LICENSE-MIT-QCMS new file mode 100644 index 0000000000..eec8246dfa --- /dev/null +++ b/third_party/rust/any_all_workaround/LICENSE-MIT-QCMS @@ -0,0 +1,21 @@ +qcms +Copyright (C) 2009-2024 Mozilla Corporation +Copyright (C) 1998-2007 Marti Maria + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/any_all_workaround/README.md b/third_party/rust/any_all_workaround/README.md new file mode 100644 index 0000000000..9f83ac3695 --- /dev/null +++ b/third_party/rust/any_all_workaround/README.md @@ -0,0 +1,13 @@ +# any_all_workaround + +This is a workaround for bad codegen ([Rust bug](https://github.com/rust-lang/portable-simd/issues/146), [LLVM bug](https://github.com/llvm/llvm-project/issues/50466)) for the `any()` and `all()` reductions for NEON-backed SIMD vectors on 32-bit ARM. On other platforms these delegate to `any()` and `all()` in `core::simd`. + +The plan is to abandon this crate once the LLVM bug is fixed or `core::simd` works around the LLVM bug. + +The code is forked from the [`packed_simd` crate](https://raw.githubusercontent.com/hsivonen/packed_simd/d938e39bee9bc5c222f5f2f2a0df9e53b5ce36ae/src/codegen/reductions/mask/arm.rs). + +This crate requires Nightly Rust as it depends on the `portable_simd` feature. + +# License + +`MIT OR Apache-2.0`, since that's how `packed_simd` is licensed. (The ARM intrinsics Rust version workaround is from qcms, see LICENSE-MIT-QCMS.) diff --git a/third_party/rust/any_all_workaround/build.rs b/third_party/rust/any_all_workaround/build.rs new file mode 100644 index 0000000000..6810a8828e --- /dev/null +++ b/third_party/rust/any_all_workaround/build.rs @@ -0,0 +1,7 @@ +extern crate version_check as rustc; + +fn main() { + if rustc::is_min_version("1.78.0").unwrap_or(false) { + println!("cargo:rustc-cfg=stdsimd_split"); + } +} diff --git a/third_party/rust/any_all_workaround/src/lib.rs b/third_party/rust/any_all_workaround/src/lib.rs new file mode 100644 index 0000000000..f0b8b13609 --- /dev/null +++ b/third_party/rust/any_all_workaround/src/lib.rs @@ -0,0 +1,110 @@ +// This code began as a fork of +// https://raw.githubusercontent.com/rust-lang/packed_simd/d938e39bee9bc5c222f5f2f2a0df9e53b5ce36ae/src/codegen/reductions/mask/arm.rs +// which didn't have a license header on the file, but Cargo.toml said "MIT OR Apache-2.0". +// See LICENSE-MIT and LICENSE-APACHE. + +#![no_std] +#![feature(portable_simd)] +#![cfg_attr( + all( + stdsimd_split, + target_arch = "arm", + target_endian = "little", + target_feature = "neon", + target_feature = "v7" + ), + feature(stdarch_arm_neon_intrinsics) +)] +#![cfg_attr( + all( + not(stdsimd_split), + target_arch = "arm", + target_endian = "little", + target_feature = "neon", + target_feature = "v7" + ), + feature(stdsimd) +)] + +use cfg_if::cfg_if; +use core::simd::mask16x8; +use core::simd::mask32x4; +use core::simd::mask8x16; + +cfg_if! { + if #[cfg(all(target_arch = "arm", target_endian = "little", target_feature = "neon", target_feature = "v7"))] { + use core::simd::mask8x8; + use core::simd::mask16x4; + use core::simd::mask32x2; + macro_rules! arm_128_v7_neon_impl { + ($all:ident, $any:ident, $id:ident, $half:ident, $vpmin:ident, $vpmax:ident) => { + #[inline] + pub fn $all(s: $id) -> bool { + use core::arch::arm::$vpmin; + use core::mem::transmute; + unsafe { + union U { + halves: ($half, $half), + vec: $id, + } + let halves = U { vec: s }.halves; + let h: $half = transmute($vpmin(transmute(halves.0), transmute(halves.1))); + h.all() + } + } + #[inline] + pub fn $any(s: $id) -> bool { + use core::arch::arm::$vpmax; + use core::mem::transmute; + unsafe { + union U { + halves: ($half, $half), + vec: $id, + } + let halves = U { vec: s }.halves; + let h: $half = transmute($vpmax(transmute(halves.0), transmute(halves.1))); + h.any() + } + } + } + } + } else { + macro_rules! arm_128_v7_neon_impl { + ($all:ident, $any:ident, $id:ident, $half:ident, $vpmin:ident, $vpmax:ident) => { + #[inline(always)] + pub fn $all(s: $id) -> bool { + s.all() + } + #[inline(always)] + pub fn $any(s: $id) -> bool { + s.any() + } + } + } + } +} + +arm_128_v7_neon_impl!( + all_mask8x16, + any_mask8x16, + mask8x16, + mask8x8, + vpmin_u8, + vpmax_u8 +); +arm_128_v7_neon_impl!( + all_mask16x8, + any_mask16x8, + mask16x8, + mask16x4, + vpmin_u16, + vpmax_u16 +); +arm_128_v7_neon_impl!( + all_mask32x4, + any_mask32x4, + mask32x4, + mask32x2, + vpmin_u32, + vpmax_u32 +); diff --git a/third_party/rust/audio-mixer/.cargo-checksum.json b/third_party/rust/audio-mixer/.cargo-checksum.json index 4fbdd1518d..9872eab023 100644 --- a/third_party/rust/audio-mixer/.cargo-checksum.json +++ b/third_party/rust/audio-mixer/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"ac8d6a7af46ee8f72d22abb80575109b75bcb2a20ea6cacb6626a20f337fe51f","Cargo.toml":"9316753099606b9531ea52aec87270a83e74c15b6563f8f979b0e961e0cf73fd","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"e2e6b7d80550743e01faa26c19f6c8520fd0dc5db68021c042fd523eed46c799","benches/benchmark.rs":"33e9d85cee38fb7752e9315ccf5f816179309062bfb78118288f7e1495e3616f","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_sanitizers.sh":"e31b4a11559b52043920c63e6ad4e57051d6205883ecf2b2c48e105ba522015b","run_tests.sh":"21ca30cb6d41c6b35e6207e3283292933ef6628575dd587287fad6db2afb22bd","src/channel.rs":"d948d890219b810632277d2b04297334a47dc6639ef93309e74495ff408f82b6","src/coefficient.rs":"24f56281a1b800769feefc735d77c2ec03f1aa8d7c58c256b25ce1a9053a06cc","src/lib.rs":"f0ee59ac224ce6ba0cc6cb9e1796e85b9b751ba4d92c58fe3fb8b10c95b72cc4","src/main.rs":"b5ba05638c727040581c49ffd2d784493af658495cd424ce8c9365f779994baf"},"package":"c41dc008c1973ce58ff3cfc52df53814a9b7b78d73d95b071b5ff0ed4b2db3e1"} \ No newline at end of file +{"files":{"Cargo.lock":"819b29d15e418e551415a161f56eee3d2848f4e2e0936a4d8f3d4be11d2ef598","Cargo.toml":"b3de055f40a2d1895630310c8b41d7dd86fcd99b5c719f625e5ddaa9c2a3775d","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"e2e6b7d80550743e01faa26c19f6c8520fd0dc5db68021c042fd523eed46c799","benches/benchmark.rs":"33e9d85cee38fb7752e9315ccf5f816179309062bfb78118288f7e1495e3616f","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_sanitizers.sh":"e31b4a11559b52043920c63e6ad4e57051d6205883ecf2b2c48e105ba522015b","run_tests.sh":"21ca30cb6d41c6b35e6207e3283292933ef6628575dd587287fad6db2afb22bd","src/channel.rs":"243a51c37d07755b67bcce54ca2a27e0f3099b4ea510a7b7e60c4b3f17402167","src/coefficient.rs":"64a6cda5fc8630f033c80717616183f6e172da5fd2d338028e52f77d8b7e0830","src/lib.rs":"f0ee59ac224ce6ba0cc6cb9e1796e85b9b751ba4d92c58fe3fb8b10c95b72cc4","src/main.rs":"b5ba05638c727040581c49ffd2d784493af658495cd424ce8c9365f779994baf"},"package":"4f1245ab2f85c284bac1ac1f03565539644566295ef6eb9c4eae42e9a40c51b2"} \ No newline at end of file diff --git a/third_party/rust/audio-mixer/Cargo.lock b/third_party/rust/audio-mixer/Cargo.lock index 68d1ba2441..ac92b80559 100644 --- a/third_party/rust/audio-mixer/Cargo.lock +++ b/third_party/rust/audio-mixer/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -17,14 +17,14 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] [[package]] name = "audio-mixer" -version = "0.1.3" +version = "0.2.0" dependencies = [ "bitflags", "criterion", @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "bitflags" @@ -45,9 +45,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cast" @@ -108,54 +108,36 @@ dependencies = [ "itertools", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "csv" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" dependencies = [ "csv-core", "itoa", @@ -165,18 +147,18 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" dependencies = [ "memchr", ] [[package]] name = "either" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "float-cmp" @@ -189,9 +171,9 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hermit-abi" @@ -202,12 +184,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - [[package]] name = "itertools" version = "0.10.5" @@ -219,15 +195,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -240,55 +216,36 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.2", - "libc", -] - [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -326,27 +283,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -354,21 +311,19 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "regex" -version = "1.9.5" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -378,9 +333,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -389,15 +344,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -408,17 +363,11 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "serde" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -435,9 +384,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -446,9 +395,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -457,9 +406,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" dependencies = [ "proc-macro2", "quote", @@ -493,15 +442,15 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -509,9 +458,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -519,9 +468,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -534,9 +483,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -544,9 +493,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -557,15 +506,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -589,9 +538,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] diff --git a/third_party/rust/audio-mixer/Cargo.toml b/third_party/rust/audio-mixer/Cargo.toml index 92293f25db..703d89bd23 100644 --- a/third_party/rust/audio-mixer/Cargo.toml +++ b/third_party/rust/audio-mixer/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "audio-mixer" -version = "0.1.3" +version = "0.2.0" authors = ["Chun-Min Chang "] description = "Mixing audio by the input and output channel layout" readme = "README.md" diff --git a/third_party/rust/audio-mixer/src/channel.rs b/third_party/rust/audio-mixer/src/channel.rs index b32936895e..d913df39e8 100644 --- a/third_party/rust/audio-mixer/src/channel.rs +++ b/third_party/rust/audio-mixer/src/channel.rs @@ -21,6 +21,7 @@ pub enum Channel { TopBackCenter = 16, TopBackRight = 17, Silence = 18, + Discrete = 19, // To be used based on its index } impl Channel { @@ -29,7 +30,7 @@ impl Channel { } pub const fn count() -> usize { - Channel::Silence as usize + 1 + Channel::Discrete as usize + 1 } pub const fn bitmask(self) -> u32 { @@ -58,6 +59,7 @@ bitflags! { const TOP_BACK_CENTER = Channel::TopBackCenter.bitmask(); const TOP_BACK_RIGHT = Channel::TopBackRight.bitmask(); const SILENCE = Channel::Silence.bitmask(); + const DISCRETE = Channel::Discrete.bitmask(); } } diff --git a/third_party/rust/audio-mixer/src/coefficient.rs b/third_party/rust/audio-mixer/src/coefficient.rs index 799d50289c..c7999ee929 100644 --- a/third_party/rust/audio-mixer/src/coefficient.rs +++ b/third_party/rust/audio-mixer/src/coefficient.rs @@ -9,7 +9,7 @@ const CHANNELS: usize = Channel::count(); #[derive(Debug)] enum Error { - DuplicateNonSilenceChannel, + DuplicateChannel, AsymmetricChannels, } @@ -28,13 +28,15 @@ impl ChannelLayout { }) } - // Except Silence channel, the duplicate channels are not allowed. + // Except Silence and Discrete channels, duplicate channels aren't allowed. fn get_channel_map(channels: &[Channel]) -> Result { let mut map = ChannelMap::empty(); for channel in channels { let bitmask = ChannelMap::from(*channel); - if channel != &Channel::Silence && map.contains(bitmask) { - return Err(Error::DuplicateNonSilenceChannel); + if (channel != &Channel::Silence && channel != &Channel::Discrete) + && map.contains(bitmask) + { + return Err(Error::DuplicateChannel); } map.insert(bitmask); } @@ -83,15 +85,41 @@ where let input_layout = ChannelLayout::new(input_channels).expect("Invalid input layout"); let output_layout = ChannelLayout::new(output_channels).expect("Invalid output layout"); - let mixing_matrix = - Self::build_mixing_matrix(input_layout.channel_map, output_layout.channel_map) - .unwrap_or_else(|_| Self::get_basic_matrix()); - - let coefficient_matrix = Self::pick_coefficients( - &input_layout.channels, - &output_layout.channels, - &mixing_matrix, - ); + // Check if this is a professional audio interface rather than a sound card for playback, in + // which case it is expected to simply pass all the channel through without change. + // Those interfaces only have an explicit mapping for the stereo pair, but have lots of channels. + let mut only_stereo_or_discrete = true; + for channel in output_channels { + if *channel != Channel::Discrete + && *channel != Channel::FrontLeft + && *channel != Channel::FrontRight + { + only_stereo_or_discrete = false; + break; + } + } + let coefficient_matrix = if only_stereo_or_discrete && output_channels.len() > 2 { + let mut matrix = Vec::with_capacity(output_channels.len()); + // Create a diagonal line of 1.0 for input channels + for (output_channel_index, _) in output_channels.iter().enumerate() { + let mut coefficients = Vec::with_capacity(input_channels.len()); + coefficients.resize(input_channels.len(), 0.0); + if output_channel_index < coefficients.len() { + coefficients[output_channel_index] = 1.0; + } + matrix.push(coefficients); + } + matrix + } else { + let mixing_matrix = + Self::build_mixing_matrix(input_layout.channel_map, output_layout.channel_map) + .unwrap_or_else(|_| Self::get_basic_matrix()); + Self::pick_coefficients( + &input_layout.channels, + &output_layout.channels, + &mixing_matrix, + ) + }; let normalized_matrix = Self::normalize(T::max_coefficients_sum(), coefficient_matrix); @@ -430,7 +458,7 @@ impl MixingCoefficient for f32 { type Coef = f32; fn max_coefficients_sum() -> f64 { - f64::from(std::i32::MAX) + f64::from(i32::MAX) } fn coefficient_from_f64(value: f64) -> Self::Coef { @@ -550,12 +578,12 @@ mod test { #[test] fn test_create_with_duplicate_silience_channels_f32() { - test_create_with_duplicate_silience_channels::() + test_create_with_duplicate_channels::() } #[test] fn test_create_with_duplicate_silience_channels_i16() { - test_create_with_duplicate_silience_channels::() + test_create_with_duplicate_channels::() } #[test] @@ -582,7 +610,7 @@ mod test { test_create_with_duplicate_output_channels::() } - fn test_create_with_duplicate_silience_channels() + fn test_create_with_duplicate_channels() where T: MixingCoefficient, T::Coef: Copy, @@ -649,78 +677,155 @@ mod test { } #[test] - fn test_get_redirect_matrix_f32() { - test_get_redirect_matrix::(); + fn test_get_discrete_mapping() { + test_get_discrete_mapping_matrix::(); + test_get_discrete_mapping_matrix::(); } #[test] - fn test_get_redirect_matrix_i16() { - test_get_redirect_matrix::(); + fn test_get_discrete_mapping_too_many_channels() { + test_get_discrete_mapping_matrix_too_many_channels::(); + test_get_discrete_mapping_matrix_too_many_channels::(); } - fn test_get_redirect_matrix() - where + #[test] + fn test_get_regular_mapping_too_many_channels() { + test_get_regular_mapping_matrix_too_many_channels::(); + test_get_regular_mapping_matrix_too_many_channels::(); + } + + // Check that a matrix is diagonal (1.0 on the diagnoal, 0.0 elsewhere). It's valid to have more input or output channels + fn assert_is_diagonal( + coefficients: &Coefficient, + input_channels: usize, + output_channels: usize, + ) where T: MixingCoefficient, T::Coef: Copy + Debug + PartialEq, { - // Create a matrix that only redirect the channels from input side to output side, - // without mixing input audio data to output audio data. - fn compute_redirect_matrix( - input_channels: &[Channel], - output_channels: &[Channel], - ) -> Vec> - where - T: MixingCoefficient, - { - let mut matrix = Vec::with_capacity(output_channels.len()); - for output_channel in output_channels { - let mut row = Vec::with_capacity(input_channels.len()); - for input_channel in input_channels { - row.push( - if input_channel != output_channel - || input_channel == &Channel::Silence - || output_channel == &Channel::Silence - { - 0.0 - } else { - 1.0 - }, - ); + for i in 0..input_channels { + for j in 0..output_channels { + if i == j { + assert_eq!(coefficients.get(i, j), T::coefficient_from_f64(1.0)); + } else { + assert_eq!(coefficients.get(i, j), T::coefficient_from_f64(0.0)); } - matrix.push(row); } - - // Convert the type of the coefficients from f64 to T::Coef. - matrix - .into_iter() - .map(|row| row.into_iter().map(T::coefficient_from_f64).collect()) - .collect() } + println!( + "{:?} = {:?} * {:?}", + output_channels, coefficients.matrix, input_channels + ); + } + fn test_get_discrete_mapping_matrix() + where + T: MixingCoefficient, + T::Coef: Copy + Debug + PartialEq, + { + // typical 5.1 let input_channels = [ Channel::FrontLeft, - Channel::Silence, Channel::FrontRight, Channel::FrontCenter, + Channel::BackLeft, + Channel::BackRight, + Channel::LowFrequency, ]; + // going into 8 channels with a tagged stereo pair and discrete channels let output_channels = [ - Channel::Silence, Channel::FrontLeft, - Channel::Silence, + Channel::FrontRight, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, + ]; + + // Get a pass-through matrix in the first 6 channels + let coefficients = Coefficient::::create(&input_channels, &output_channels); + assert_is_diagonal::(&coefficients, input_channels.len(), output_channels.len()); + } + + fn test_get_discrete_mapping_matrix_too_many_channels() + where + T: MixingCoefficient, + T::Coef: Copy + Debug + PartialEq, + { + // 5.1.4 + let input_channels = [ + Channel::FrontLeft, + Channel::FrontRight, Channel::FrontCenter, - Channel::BackCenter, + Channel::LowFrequency, + Channel::FrontLeftOfCenter, + Channel::FrontRightOfCenter, + Channel::TopFrontLeft, + Channel::TopFrontRight, + Channel::BackLeft, + Channel::BackRight, + ]; + // going into 8 channels with a tagged stereo pair and discrete channels + let output_channels = [ + Channel::FrontLeft, + Channel::FrontRight, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, + Channel::Discrete, ]; - // Get a redirect matrix since the output layout is asymmetric. - let coefficient = Coefficient::::create(&input_channels, &output_channels); + // First 8 channels are to be played, last two are to be dropped. + let coefficients = Coefficient::::create(&input_channels, &output_channels); + assert_is_diagonal(&coefficients, input_channels.len(), output_channels.len()); + } + + fn test_get_regular_mapping_matrix_too_many_channels() + where + T: MixingCoefficient, + T::Coef: Copy + Debug + PartialEq, + { + // 5.1.4 + let input_channels = [ + Channel::FrontLeft, + Channel::FrontRight, + Channel::FrontCenter, + Channel::LowFrequency, + Channel::FrontLeftOfCenter, + Channel::FrontRightOfCenter, + Channel::TopFrontLeft, + Channel::TopFrontRight, + Channel::BackLeft, + Channel::BackRight, + ]; + // going into a regular 5.1 sound card + let output_channels = [ + Channel::FrontLeft, + Channel::FrontRight, + Channel::FrontCenter, + Channel::LowFrequency, + Channel::BackLeft, + Channel::BackRight, + ]; - let expected = compute_redirect_matrix::(&input_channels, &output_channels); - assert_eq!(coefficient.matrix, expected); + let coefficients = Coefficient::::create(&input_channels, &output_channels); - println!( - "{:?} = {:?} * {:?}", - output_channels, coefficient.matrix, input_channels - ); + // Non-unity gain non-silence coefficients must be present when down mixing. + let mut found_non_unity_non_silence = false; + for row in coefficients.matrix.iter() { + for coeff in row.iter() { + if T::coefficient_from_f64(1.0) != *coeff || T::coefficient_from_f64(0.0) != *coeff + { + found_non_unity_non_silence = true; + break; + } + } + } + assert!(found_non_unity_non_silence); } #[test] @@ -732,7 +837,7 @@ mod test { vec![4.0_f64, 6.0_f64, 10.0_f64], ]; - let mut max_row_sum: f64 = std::f64::MIN; + let mut max_row_sum: f64 = f64::MIN; for row in &m { max_row_sum = max_row_sum.max(row.iter().sum()); } @@ -746,7 +851,7 @@ mod test { let smaller_max = max_row_sum - 0.5_f64; assert!(smaller_max > 0.0_f64); let n = Coefficient::::normalize(smaller_max, m); - let mut max_row_sum: f64 = std::f64::MIN; + let mut max_row_sum: f64 = f64::MIN; for row in &n { max_row_sum = max_row_sum.max(row.iter().sum()); assert!(row.iter().sum::() <= smaller_max); diff --git a/third_party/rust/bindgen/clang.rs b/third_party/rust/bindgen/clang.rs index 4a4ed89d69..19f3e703a7 100644 --- a/third_party/rust/bindgen/clang.rs +++ b/third_party/rust/bindgen/clang.rs @@ -1608,7 +1608,7 @@ impl SourceLocation { let mut line = 0; let mut col = 0; let mut off = 0; - clang_getSpellingLocation( + clang_getFileLocation( self.x, &mut file, &mut line, &mut col, &mut off, ); (File { x: file }, line as usize, col as usize, off as usize) diff --git a/third_party/rust/bitflags/.cargo-checksum.json b/third_party/rust/bitflags/.cargo-checksum.json index 99936c770d..bef288da56 100644 --- a/third_party/rust/bitflags/.cargo-checksum.json +++ b/third_party/rust/bitflags/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"0905d91abfd8162750daeb51b69e1a4add85cd0e8e2b136a4fd20ea28df4da42","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","CONTRIBUTING.md":"6c9f96eacb20af877ae2d16f024904f3038b93448a8488e9dbcac0df7f6439a5","Cargo.lock":"fb581ed64bd34dbdbcc2386c394394d5f46db3186edc7b129f1669cef66a0b57","Cargo.toml":"418f0ef5e370bf88b0d7bd8c3b2f25b533ae2b671036d30f7c524dc39133045c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"a403792a6099aeda15dc7bf3da529409652039b5dd2227dfc5549bd2f3fad7db","SECURITY.md":"68704c8128fa2e776ed7cbda741fbf61ad52f998a96350ee7ee4dbf64c6573bc","benches/parse.rs":"f1390d62322c6880d65bd931e183d49b313f287879a6bfaa36b1cb1921090b51","examples/custom_bits_type.rs":"e53b32051adc5d97860e0b48c8f3a301a041d73b4939c0d7caa5f0cfcc0b9739","examples/custom_derive.rs":"29dd7b845345a103ca31e91b579aeb01fb74935b8223c29184eb42223edadb65","examples/fmt.rs":"87ba37a1fb8528570c74ea26d8e8948e1179c3d867b928bea1080880258e0a99","examples/macro_free.rs":"69e7f284b53b5214d51228a686e87f127b52a3b74711e45537ebfa5583a180e5","examples/serde.rs":"08b21b35d5c10fdca132fe0f36c8067bb44f559e96617a9257ab6316a20cbc75","spec.md":"fcdd939df30c59b0643be09027df664b71cbea9b9989185441482c5576160fed","src/example_generated.rs":"d018caf059f6ffc4c2403b771a6d76679fa5af03c329a91bd9252957df695e7f","src/external.rs":"11599248db17d395c6b45bf2400266f221d3eb1523908e5f17715964bf8d99ed","src/external/arbitrary.rs":"fa8c9187028b9bc54856977b0914676f62101010e7a9450abd577fd78c89552f","src/external/bytemuck.rs":"3afcef382122867040fddd5e4153d633d1ed5596fe5d7dfac66a8e61c2513df5","src/external/serde.rs":"4a09db12534a20fe554a08dc5f1c8124b379292d41fa75628abcd2ca21587573","src/internal.rs":"fd939154cbebf43bfc329a4a3cd08618ca30a6a5f6e6abea07d23f75bf5b3b2d","src/iter.rs":"dbaa6437c1c044f689185ce3fafe43df8796bed19bbdd2c20334a52de5eeee73","src/lib.rs":"e45c07f43b0e142c41e99de8d20ceb909148762c876d765c11ac8b8ceaca0af5","src/parser.rs":"52f6352620ce3d5973bc38b42d56a760307294162c9d5668eb774eb92a6ef941","src/public.rs":"72b41639711bab95e8e75f37401a487088e7be1a427715cea40563fb3f64ed60","src/tests.rs":"b120c27ff0c67a819527de9d8171f1f4c5d37ba4009c54abeb869c70e6035f14","src/traits.rs":"0a8764c3e2378043e2724cf1bfc514d4ff1985026db33509f6451a7897e2675d"},"package":"327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"} \ No newline at end of file +{"files":{"CHANGELOG.md":"cb81297fc686539a786805dfef959e6f7c9b5fd55e451150cea68bcacc73ee8c","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","CONTRIBUTING.md":"6c9f96eacb20af877ae2d16f024904f3038b93448a8488e9dbcac0df7f6439a5","Cargo.lock":"04c2a120060e71f281a3a3f26f9be8dbc5a80102204f1f982ae0e2089557e646","Cargo.toml":"ed18e06a8a26ae38abea369bb062b6e6c1b714913ee9e64c060151f5ec966f5b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"e37efef64c50b073d5afcb6d2d43649cec6bf26d4022f32b5d77665bcb4c9049","SECURITY.md":"68704c8128fa2e776ed7cbda741fbf61ad52f998a96350ee7ee4dbf64c6573bc","benches/parse.rs":"f1390d62322c6880d65bd931e183d49b313f287879a6bfaa36b1cb1921090b51","examples/custom_bits_type.rs":"e53b32051adc5d97860e0b48c8f3a301a041d73b4939c0d7caa5f0cfcc0b9739","examples/custom_derive.rs":"29dd7b845345a103ca31e91b579aeb01fb74935b8223c29184eb42223edadb65","examples/fmt.rs":"87ba37a1fb8528570c74ea26d8e8948e1179c3d867b928bea1080880258e0a99","examples/macro_free.rs":"69e7f284b53b5214d51228a686e87f127b52a3b74711e45537ebfa5583a180e5","examples/serde.rs":"08b21b35d5c10fdca132fe0f36c8067bb44f559e96617a9257ab6316a20cbc75","spec.md":"fcdd939df30c59b0643be09027df664b71cbea9b9989185441482c5576160fed","src/example_generated.rs":"d018caf059f6ffc4c2403b771a6d76679fa5af03c329a91bd9252957df695e7f","src/external.rs":"734d3f470e6a669297d2df421ce3976fe613d8aa9c071d5ce6fe3ca890e5b815","src/external/arbitrary.rs":"fa8c9187028b9bc54856977b0914676f62101010e7a9450abd577fd78c89552f","src/external/bytemuck.rs":"3afcef382122867040fddd5e4153d633d1ed5596fe5d7dfac66a8e61c2513df5","src/external/serde.rs":"4a09db12534a20fe554a08dc5f1c8124b379292d41fa75628abcd2ca21587573","src/internal.rs":"645b13af0c7302258df61239073a4b8203d09f27b6c17f8a6f1f8c3e427f5334","src/iter.rs":"dbaa6437c1c044f689185ce3fafe43df8796bed19bbdd2c20334a52de5eeee73","src/lib.rs":"c7ade9eb151425815a8fc5afc558951a256d14143be36c4442bcae477571783b","src/parser.rs":"4e788b29f5d0542c409a8b43c703bcb4a6c2a57c181cadd17f565f0abb39681e","src/public.rs":"d151f7db62fefdb6cd2cad1038a785f02d1ce32eaab4c4cc84376283699182cc","src/tests.rs":"b120c27ff0c67a819527de9d8171f1f4c5d37ba4009c54abeb869c70e6035f14","src/tests/all.rs":"e99a865cd4271a524c2fe95503e96d851b35990570aed6fb2e9dac7a14da31b6","src/tests/bits.rs":"3840c34b2ea5d1802404b9ce5bcc1d3fa6ccd8dfba2e29e6d07c605f817d90df","src/tests/complement.rs":"d0e6d4c3daf49e0a7438c9f1c1ac91fad1b37f258c03593f6cd6a695ee626f5e","src/tests/contains.rs":"58bb3cb8c86550e775d11134da1d4aca85c83f943ea454e3a5f222772c674a24","src/tests/difference.rs":"d0d2b96bb52658b8ac019210da74ca75a53e76622f668855142ea6e97c28cb0e","src/tests/empty.rs":"817d6e93ced7cb7576ff0e334aa1a44703f3f96871ff2c6bdcb8f207e6551f67","src/tests/eq.rs":"b816767680a029e9c163e37af074dd4e604c4a3e4936f829f0ca3774fd5f0e37","src/tests/extend.rs":"5fabb9fd0254c64da019149c24063fceff72da3eb4ad73b57c1cc4c04b008364","src/tests/flags.rs":"2f48d3a25db1cf66fe98c9959abc70875deb9f7b38b2c278dc70c46e0d4ec277","src/tests/fmt.rs":"a2d4148491f3202f030f63633eee941b741e3be29a68cf376f008dbe5cb11e5c","src/tests/from_bits.rs":"d94c65b88bf89961d0cfc1b3152a7f1acc285bae160a1628438effda11b8e2c1","src/tests/from_bits_retain.rs":"980591dfaf91e940f42d9a1ce890f237514dd59d458fc264abcf9ceabbc40677","src/tests/from_bits_truncate.rs":"d3406b5e107ebb6449b98a59eee6cc5d84f947d4aaee1ee7e80dc7202de179f0","src/tests/from_name.rs":"f4a055d1f3c86decef70ef8f3020cef5c4e229718c20b3d59d5a3abc3a8b1298","src/tests/insert.rs":"3fab5da800a6fc0654dfb5f859f95da65a507eb9fda8695083c2712266dff0b9","src/tests/intersection.rs":"baf1454c9e4eba552264870a556ee0032d9f2bb8cac361833d571235e0b52221","src/tests/intersects.rs":"c55e36179fd8bc636f04ea9bbce346dcaafe57915d13f1df28c5b83117dbd08e","src/tests/is_all.rs":"b2f11faa7c954bd85c8fb39999e0c37d983cf7895152bc13c7ddde106aa33b6d","src/tests/is_empty.rs":"11f21323cdca7ff92dd89e09de667dba69e8dce88e2d3e27ea68ace91d15d070","src/tests/iter.rs":"4ba121932b527e787b82745405c7c65c1084c242e2dda3290d475ec160d265e4","src/tests/parser.rs":"fa2fb8dedcf16601af609a5e21d9c5840c7f96a1e3a587f7f2ea3dc8387f7628","src/tests/remove.rs":"6e75f8508d2dc1a2cba89ef691f4387a665a4fd13853bb1dd0fd80c783b89947","src/tests/symmetric_difference.rs":"0a89f084f9de1dd5b1932fe72c3b10a3c93cbaa16832b3a31b6a85e3bbd3ba6e","src/tests/union.rs":"88f398ee4600bb1e59bf6d02d1f6ff33f5f853eab5a6c700bd8a683c6ee4651a","src/traits.rs":"b79d008daec546136fae4497966fc85a33663d86ea2d9213fd23b412d4d77b66"},"package":"cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"} \ No newline at end of file diff --git a/third_party/rust/bitflags/CHANGELOG.md b/third_party/rust/bitflags/CHANGELOG.md index 5081ed5767..5d410fc65a 100644 --- a/third_party/rust/bitflags/CHANGELOG.md +++ b/third_party/rust/bitflags/CHANGELOG.md @@ -1,3 +1,29 @@ +# 2.5.0 + +## What's Changed +* Derive `Debug` for `Flag` by @tgross35 in https://github.com/bitflags/bitflags/pull/398 +* Support truncating or strict-named variants of parsing and formatting by @KodrAus in https://github.com/bitflags/bitflags/pull/400 + +## New Contributors +* @tgross35 made their first contribution in https://github.com/bitflags/bitflags/pull/398 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.4.2...2.5.0 + +# 2.4.2 + +## What's Changed +* Cargo.toml: Anchor excludes to root of the package by @jamessan in https://github.com/bitflags/bitflags/pull/387 +* Update error messages by @KodrAus in https://github.com/bitflags/bitflags/pull/390 +* Add support for impl mode structs to be repr(packed) by @GnomedDev in https://github.com/bitflags/bitflags/pull/388 +* Remove old `unused_tuple_struct_fields` lint by @dtolnay in https://github.com/bitflags/bitflags/pull/393 +* Delete use of `local_inner_macros` by @dtolnay in https://github.com/bitflags/bitflags/pull/392 + +## New Contributors +* @jamessan made their first contribution in https://github.com/bitflags/bitflags/pull/387 +* @GnomedDev made their first contribution in https://github.com/bitflags/bitflags/pull/388 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.4.1...2.4.2 + # 2.4.1 ## What's Changed diff --git a/third_party/rust/bitflags/Cargo.lock b/third_party/rust/bitflags/Cargo.lock index 53d2d7a686..2c16b119fa 100644 --- a/third_party/rust/bitflags/Cargo.lock +++ b/third_party/rust/bitflags/Cargo.lock @@ -4,25 +4,16 @@ version = 3 [[package]] name = "arbitrary" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2e1373abdaa212b704512ec2bd8b26bd0b7d5c3f70117411a5d9a451383c859" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" dependencies = [ "derive_arbitrary", ] -[[package]] -name = "basic-toml" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" -dependencies = [ - "serde", -] - [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" dependencies = [ "arbitrary", "bytemuck", @@ -39,18 +30,18 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ "proc-macro2", "quote", @@ -65,53 +56,81 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "compiler_builtins" -version = "0.1.101" +version = "0.1.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a6d58e9c3408138099a396a98fd0d0e6cfb25d723594d2ae48b5004513fd5b" +checksum = "d68bc55329711cd719c2687bb147bc06211b0521f97ef398280108ccb23227e9" [[package]] name = "derive_arbitrary" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "memchr" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -130,24 +149,24 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -156,15 +175,24 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_test" version = "1.0.176" @@ -176,9 +204,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -187,26 +215,60 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c12219811e0c1ba077867254e5ad62ee2c9c190b0d957110750ac0cda1ae96cd" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "trybuild" -version = "1.0.85" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" +checksum = "2aa6f84ec205ebf87fb7a0abdbcd1467fa5af0e86878eb6d888b78ecbb10b6d5" dependencies = [ - "basic-toml", "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", + "toml", ] [[package]] @@ -246,11 +308,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + [[package]] name = "zerocopy" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20707b61725734c595e840fb3704378a0cd2b9c74cc9e6e20724838fc6a1e2f9" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" dependencies = [ "byteorder", "zerocopy-derive", @@ -258,9 +329,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56097d5b91d711293a42be9289403896b68654625021732067eac7a4ca388a1f" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" dependencies = [ "proc-macro2", "quote", diff --git a/third_party/rust/bitflags/Cargo.toml b/third_party/rust/bitflags/Cargo.toml index 5fd2c7dc17..b274599a46 100644 --- a/third_party/rust/bitflags/Cargo.toml +++ b/third_party/rust/bitflags/Cargo.toml @@ -13,11 +13,11 @@ edition = "2021" rust-version = "1.56.0" name = "bitflags" -version = "2.4.1" +version = "2.5.0" authors = ["The Rust Project Developers"] exclude = [ - "tests", - ".github", + "/tests", + "/.github", ] description = """ A macro to generate structures which behave like bitflags. diff --git a/third_party/rust/bitflags/README.md b/third_party/rust/bitflags/README.md index ecad515e17..652a880f6b 100644 --- a/third_party/rust/bitflags/README.md +++ b/third_party/rust/bitflags/README.md @@ -28,7 +28,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -bitflags = "2.4.1" +bitflags = "2.5.0" ``` and this to your source code: diff --git a/third_party/rust/bitflags/src/external.rs b/third_party/rust/bitflags/src/external.rs index efeaa82796..716af83c0f 100644 --- a/third_party/rust/bitflags/src/external.rs +++ b/third_party/rust/bitflags/src/external.rs @@ -14,7 +14,7 @@ Next, re-export the library from the `__private` module here. Next, define a macro like so: ```rust -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(feature = "serde")] macro_rules! __impl_external_bitflags_my_library { @@ -30,7 +30,7 @@ macro_rules! __impl_external_bitflags_my_library { }; } -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(not(feature = "my_library"))] macro_rules! __impl_external_bitflags_my_library { @@ -77,7 +77,7 @@ pub(crate) mod __private { } /// Implements traits from external libraries for the internal bitflags type. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_external_bitflags { ( @@ -92,7 +92,7 @@ macro_rules! __impl_external_bitflags { // Use `serde` as an example: generate code when the feature is available, // and a no-op when it isn't - __impl_external_bitflags_serde! { + $crate::__impl_external_bitflags_serde! { $InternalBitFlags: $T, $PublicBitFlags { $( $(#[$inner $($args)*])* @@ -101,7 +101,7 @@ macro_rules! __impl_external_bitflags { } } - __impl_external_bitflags_arbitrary! { + $crate::__impl_external_bitflags_arbitrary! { $InternalBitFlags: $T, $PublicBitFlags { $( $(#[$inner $($args)*])* @@ -110,7 +110,7 @@ macro_rules! __impl_external_bitflags { } } - __impl_external_bitflags_bytemuck! { + $crate::__impl_external_bitflags_bytemuck! { $InternalBitFlags: $T, $PublicBitFlags { $( $(#[$inner $($args)*])* @@ -125,7 +125,7 @@ macro_rules! __impl_external_bitflags { pub mod serde; /// Implement `Serialize` and `Deserialize` for the internal bitflags type. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(feature = "serde")] macro_rules! __impl_external_bitflags_serde { @@ -161,7 +161,7 @@ macro_rules! __impl_external_bitflags_serde { }; } -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(not(feature = "serde"))] macro_rules! __impl_external_bitflags_serde { @@ -182,7 +182,7 @@ pub mod arbitrary; mod bytemuck; /// Implement `Arbitrary` for the internal bitflags type. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(feature = "arbitrary")] macro_rules! __impl_external_bitflags_arbitrary { @@ -204,7 +204,7 @@ macro_rules! __impl_external_bitflags_arbitrary { }; } -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(not(feature = "arbitrary"))] macro_rules! __impl_external_bitflags_arbitrary { @@ -219,7 +219,7 @@ macro_rules! __impl_external_bitflags_arbitrary { } /// Implement `Pod` and `Zeroable` for the internal bitflags type. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(feature = "bytemuck")] macro_rules! __impl_external_bitflags_bytemuck { @@ -247,7 +247,7 @@ macro_rules! __impl_external_bitflags_bytemuck { }; } -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] #[cfg(not(feature = "bytemuck"))] macro_rules! __impl_external_bitflags_bytemuck { diff --git a/third_party/rust/bitflags/src/internal.rs b/third_party/rust/bitflags/src/internal.rs index aca1ac4db1..87d01cc0cb 100644 --- a/third_party/rust/bitflags/src/internal.rs +++ b/third_party/rust/bitflags/src/internal.rs @@ -6,7 +6,7 @@ /// Declare the `bitflags`-facing bitflags struct. /// /// This type is part of the `bitflags` crate's public API, but not part of the user's. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __declare_internal_bitflags { ( @@ -25,7 +25,7 @@ macro_rules! __declare_internal_bitflags { /// /// Methods and trait implementations can be freely added here without breaking end-users. /// If we want to expose new functionality to `#[derive]`, this is the place to do it. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_internal_bitflags { ( @@ -97,7 +97,7 @@ macro_rules! __impl_internal_bitflags { // The internal flags type offers a similar API to the public one - __impl_public_bitflags! { + $crate::__impl_public_bitflags! { $InternalBitFlags: $T, $PublicBitFlags { $( $(#[$inner $($args)*])* @@ -106,11 +106,11 @@ macro_rules! __impl_internal_bitflags { } } - __impl_public_bitflags_ops! { + $crate::__impl_public_bitflags_ops! { $InternalBitFlags } - __impl_public_bitflags_iter! { + $crate::__impl_public_bitflags_iter! { $InternalBitFlags: $T, $PublicBitFlags } diff --git a/third_party/rust/bitflags/src/lib.rs b/third_party/rust/bitflags/src/lib.rs index c8aff6873f..8f7225915e 100644 --- a/third_party/rust/bitflags/src/lib.rs +++ b/third_party/rust/bitflags/src/lib.rs @@ -17,7 +17,7 @@ Add `bitflags` to your `Cargo.toml`: ```toml [dependencies.bitflags] -version = "2.4.1" +version = "2.5.0" ``` ## Generating flags types @@ -252,6 +252,8 @@ mod traits; #[doc(hidden)] pub mod __private { + #[allow(unused_imports)] + // Easier than conditionally checking any optional external dependencies pub use crate::{external::__private::*, traits::__private::*}; pub use core; @@ -441,7 +443,7 @@ bitflags! { } ``` */ -#[macro_export(local_inner_macros)] +#[macro_export] macro_rules! bitflags { ( $(#[$outer:meta])* @@ -456,13 +458,13 @@ macro_rules! bitflags { ) => { // Declared in the scope of the `bitflags!` call // This type appears in the end-user's API - __declare_public_bitflags! { + $crate::__declare_public_bitflags! { $(#[$outer])* $vis struct $BitFlags } // Workaround for: https://github.com/bitflags/bitflags/issues/320 - __impl_public_bitflags_consts! { + $crate::__impl_public_bitflags_consts! { $BitFlags: $T { $( $(#[$inner $($args)*])* @@ -487,11 +489,11 @@ macro_rules! bitflags { const _: () = { // Declared in a "hidden" scope that can't be reached directly // These types don't appear in the end-user's API - __declare_internal_bitflags! { + $crate::__declare_internal_bitflags! { $vis struct InternalBitFlags: $T } - __impl_internal_bitflags! { + $crate::__impl_internal_bitflags! { InternalBitFlags: $T, $BitFlags { $( $(#[$inner $($args)*])* @@ -501,7 +503,7 @@ macro_rules! bitflags { } // This is where new library trait implementations can be added - __impl_external_bitflags! { + $crate::__impl_external_bitflags! { InternalBitFlags: $T, $BitFlags { $( $(#[$inner $($args)*])* @@ -510,20 +512,20 @@ macro_rules! bitflags { } } - __impl_public_bitflags_forward! { + $crate::__impl_public_bitflags_forward! { $BitFlags: $T, InternalBitFlags } - __impl_public_bitflags_ops! { + $crate::__impl_public_bitflags_ops! { $BitFlags } - __impl_public_bitflags_iter! { + $crate::__impl_public_bitflags_iter! { $BitFlags: $T, $BitFlags } }; - bitflags! { + $crate::bitflags! { $($t)* } }; @@ -537,7 +539,7 @@ macro_rules! bitflags { $($t:tt)* ) => { - __impl_public_bitflags_consts! { + $crate::__impl_public_bitflags_consts! { $BitFlags: $T { $( $(#[$inner $($args)*])* @@ -558,7 +560,7 @@ macro_rules! bitflags { clippy::iter_without_into_iter, )] const _: () = { - __impl_public_bitflags! { + $crate::__impl_public_bitflags! { $BitFlags: $T, $BitFlags { $( $(#[$inner $($args)*])* @@ -567,16 +569,16 @@ macro_rules! bitflags { } } - __impl_public_bitflags_ops! { + $crate::__impl_public_bitflags_ops! { $BitFlags } - __impl_public_bitflags_iter! { + $crate::__impl_public_bitflags_iter! { $BitFlags: $T, $BitFlags } }; - bitflags! { + $crate::bitflags! { $($t)* } }; @@ -587,7 +589,7 @@ macro_rules! bitflags { /// /// We need to be careful about adding new methods and trait implementations here because they /// could conflict with items added by the end-user. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_bitflags { ( @@ -796,7 +798,7 @@ macro_rules! __impl_bitflags { /// /// If you find yourself with an attribute that should be considered expression-safe /// and isn't, it can be added here. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __bitflags_expr_safe_attrs { // Entrypoint: Move all flags and all attributes into `unprocessed` lists @@ -805,7 +807,7 @@ macro_rules! __bitflags_expr_safe_attrs { $(#[$inner:ident $($args:tt)*])* { $e:expr } ) => { - __bitflags_expr_safe_attrs! { + $crate::__bitflags_expr_safe_attrs! { expr: { $e }, attrs: { // All attributes start here @@ -830,7 +832,7 @@ macro_rules! __bitflags_expr_safe_attrs { processed: [$($expr:tt)*], }, ) => { - __bitflags_expr_safe_attrs! { + $crate::__bitflags_expr_safe_attrs! { expr: { $e }, attrs: { unprocessed: [ @@ -857,7 +859,7 @@ macro_rules! __bitflags_expr_safe_attrs { processed: [$($expr:tt)*], }, ) => { - __bitflags_expr_safe_attrs! { + $crate::__bitflags_expr_safe_attrs! { expr: { $e }, attrs: { unprocessed: [ @@ -884,7 +886,7 @@ macro_rules! __bitflags_expr_safe_attrs { } /// Implement a flag, which may be a wildcard `_`. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __bitflags_flag { ( diff --git a/third_party/rust/bitflags/src/parser.rs b/third_party/rust/bitflags/src/parser.rs index 130dc2e1f8..34b432da39 100644 --- a/third_party/rust/bitflags/src/parser.rs +++ b/third_party/rust/bitflags/src/parser.rs @@ -77,8 +77,10 @@ where fmt::Result::Ok(()) } +#[cfg(feature = "serde")] pub(crate) struct AsDisplay<'a, B>(pub(crate) &'a B); +#[cfg(feature = "serde")] impl<'a, B: Flags> fmt::Display for AsDisplay<'a, B> where B::Bits: WriteHex, @@ -134,6 +136,89 @@ where Ok(parsed_flags) } +/** +Write a flags value as text, ignoring any unknown bits. +*/ +pub fn to_writer_truncate(flags: &B, writer: impl Write) -> Result<(), fmt::Error> +where + B::Bits: WriteHex, +{ + to_writer(&B::from_bits_truncate(flags.bits()), writer) +} + +/** +Parse a flags value from text. + +This function will fail on any names that don't correspond to defined flags. +Unknown bits will be ignored. +*/ +pub fn from_str_truncate(input: &str) -> Result +where + B::Bits: ParseHex, +{ + Ok(B::from_bits_truncate(from_str::(input)?.bits())) +} + +/** +Write only the contained, defined, named flags in a flags value as text. +*/ +pub fn to_writer_strict(flags: &B, mut writer: impl Write) -> Result<(), fmt::Error> { + // This is a simplified version of `to_writer` that ignores + // any bits not corresponding to a named flag + + let mut first = true; + let mut iter = flags.iter_names(); + for (name, _) in &mut iter { + if !first { + writer.write_str(" | ")?; + } + + first = false; + writer.write_str(name)?; + } + + fmt::Result::Ok(()) +} + +/** +Parse a flags value from text. + +This function will fail on any names that don't correspond to defined flags. +This function will fail to parse hex values. +*/ +pub fn from_str_strict(input: &str) -> Result { + // This is a simplified version of `from_str` that ignores + // any bits not corresponding to a named flag + + let mut parsed_flags = B::empty(); + + // If the input is empty then return an empty set of flags + if input.trim().is_empty() { + return Ok(parsed_flags); + } + + for flag in input.split('|') { + let flag = flag.trim(); + + // If the flag is empty then we've got missing input + if flag.is_empty() { + return Err(ParseError::empty_flag()); + } + + // If the flag starts with `0x` then it's a hex number + // These aren't supported in the strict parser + if flag.starts_with("0x") { + return Err(ParseError::invalid_hex_flag("unsupported hex flag value")); + } + + let parsed_flag = B::from_name(flag).ok_or_else(|| ParseError::invalid_named_flag(flag))?; + + parsed_flags.insert(parsed_flag); + } + + Ok(parsed_flags) +} + /** Encode a value as a hex string. diff --git a/third_party/rust/bitflags/src/public.rs b/third_party/rust/bitflags/src/public.rs index 967e0dacbf..dc2d726782 100644 --- a/third_party/rust/bitflags/src/public.rs +++ b/third_party/rust/bitflags/src/public.rs @@ -6,7 +6,7 @@ /// Declare the user-facing bitflags struct. /// /// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __declare_public_bitflags { ( @@ -22,13 +22,13 @@ macro_rules! __declare_public_bitflags { /// /// We need to be careful about adding new methods and trait implementations here because they /// could conflict with items added by the end-user. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_public_bitflags_forward { ( $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident ) => { - __impl_bitflags! { + $crate::__impl_bitflags! { $PublicBitFlags: $T { fn empty() { Self($InternalBitFlags::empty()) @@ -124,7 +124,7 @@ macro_rules! __impl_public_bitflags_forward { /// /// We need to be careful about adding new methods and trait implementations here because they /// could conflict with items added by the end-user. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_public_bitflags { ( @@ -135,7 +135,7 @@ macro_rules! __impl_public_bitflags { )* } ) => { - __impl_bitflags! { + $crate::__impl_bitflags! { $BitFlags: $T { fn empty() { Self(<$T as $crate::Bits>::EMPTY) @@ -146,7 +146,7 @@ macro_rules! __impl_public_bitflags { let mut i = 0; $( - __bitflags_expr_safe_attrs!( + $crate::__bitflags_expr_safe_attrs!( $(#[$inner $($args)*])* {{ let flag = <$PublicBitFlags as $crate::Flags>::FLAGS[i].value().bits(); @@ -185,10 +185,10 @@ macro_rules! __impl_public_bitflags { fn from_name(name) { $( - __bitflags_flag!({ + $crate::__bitflags_flag!({ name: $Flag, named: { - __bitflags_expr_safe_attrs!( + $crate::__bitflags_expr_safe_attrs!( $(#[$inner $($args)*])* { if name == $crate::__private::core::stringify!($Flag) { @@ -268,7 +268,7 @@ macro_rules! __impl_public_bitflags { } /// Implement iterators on the public (user-facing) bitflags type. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_public_bitflags_iter { ($BitFlags:ident: $T:ty, $PublicBitFlags:ident) => { @@ -312,7 +312,7 @@ macro_rules! __impl_public_bitflags_iter { } /// Implement traits on the public (user-facing) bitflags type. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_public_bitflags_ops { ($PublicBitFlags:ident) => { @@ -321,7 +321,8 @@ macro_rules! __impl_public_bitflags_ops { &self, f: &mut $crate::__private::core::fmt::Formatter, ) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::Binary::fmt(&self.0, f) + let inner = self.0; + $crate::__private::core::fmt::Binary::fmt(&inner, f) } } @@ -330,7 +331,8 @@ macro_rules! __impl_public_bitflags_ops { &self, f: &mut $crate::__private::core::fmt::Formatter, ) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::Octal::fmt(&self.0, f) + let inner = self.0; + $crate::__private::core::fmt::Octal::fmt(&inner, f) } } @@ -339,7 +341,8 @@ macro_rules! __impl_public_bitflags_ops { &self, f: &mut $crate::__private::core::fmt::Formatter, ) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::LowerHex::fmt(&self.0, f) + let inner = self.0; + $crate::__private::core::fmt::LowerHex::fmt(&inner, f) } } @@ -348,7 +351,8 @@ macro_rules! __impl_public_bitflags_ops { &self, f: &mut $crate::__private::core::fmt::Formatter, ) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::UpperHex::fmt(&self.0, f) + let inner = self.0; + $crate::__private::core::fmt::UpperHex::fmt(&inner, f) } } @@ -468,7 +472,7 @@ macro_rules! __impl_public_bitflags_ops { } /// Implement constants on the public (user-facing) bitflags type. -#[macro_export(local_inner_macros)] +#[macro_export] #[doc(hidden)] macro_rules! __impl_public_bitflags_consts { ( @@ -481,7 +485,7 @@ macro_rules! __impl_public_bitflags_consts { ) => { impl $PublicBitFlags { $( - __bitflags_flag!({ + $crate::__bitflags_flag!({ name: $Flag, named: { $(#[$inner $($args)*])* @@ -499,10 +503,10 @@ macro_rules! __impl_public_bitflags_consts { impl $crate::Flags for $PublicBitFlags { const FLAGS: &'static [$crate::Flag<$PublicBitFlags>] = &[ $( - __bitflags_flag!({ + $crate::__bitflags_flag!({ name: $Flag, named: { - __bitflags_expr_safe_attrs!( + $crate::__bitflags_expr_safe_attrs!( $(#[$inner $($args)*])* { #[allow( @@ -514,7 +518,7 @@ macro_rules! __impl_public_bitflags_consts { ) }, unnamed: { - __bitflags_expr_safe_attrs!( + $crate::__bitflags_expr_safe_attrs!( $(#[$inner $($args)*])* { #[allow( diff --git a/third_party/rust/bitflags/src/tests/all.rs b/third_party/rust/bitflags/src/tests/all.rs new file mode 100644 index 0000000000..cceb93a469 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/all.rs @@ -0,0 +1,23 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(1 | 1 << 1 | 1 << 2, TestFlags::all); + + case(0, TestZero::all); + + case(0, TestEmpty::all); + + case(!0, TestExternal::all); +} + +#[track_caller] +fn case(expected: T::Bits, inherent: impl FnOnce() -> T) +where + ::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!(expected, inherent().bits(), "T::all()"); + assert_eq!(expected, T::all().bits(), "Flags::all()"); +} diff --git a/third_party/rust/bitflags/src/tests/bits.rs b/third_party/rust/bitflags/src/tests/bits.rs new file mode 100644 index 0000000000..678f153e36 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/bits.rs @@ -0,0 +1,36 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(0, TestFlags::empty(), TestFlags::bits); + + case(1, TestFlags::A, TestFlags::bits); + case(1 | 1 << 1 | 1 << 2, TestFlags::ABC, TestFlags::bits); + + case(!0, TestFlags::from_bits_retain(u8::MAX), TestFlags::bits); + case(1 << 3, TestFlags::from_bits_retain(1 << 3), TestFlags::bits); + + case(1 << 3, TestZero::from_bits_retain(1 << 3), TestZero::bits); + + case(1 << 3, TestEmpty::from_bits_retain(1 << 3), TestEmpty::bits); + + case( + 1 << 4 | 1 << 6, + TestExternal::from_bits_retain(1 << 4 | 1 << 6), + TestExternal::bits, + ); +} + +#[track_caller] +fn case( + expected: T::Bits, + value: T, + inherent: impl FnOnce(&T) -> T::Bits, +) where + T::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!(expected, inherent(&value), "{:?}.bits()", value); + assert_eq!(expected, Flags::bits(&value), "Flags::bits({:?})", value); +} diff --git a/third_party/rust/bitflags/src/tests/complement.rs b/third_party/rust/bitflags/src/tests/complement.rs new file mode 100644 index 0000000000..ac7a421af0 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/complement.rs @@ -0,0 +1,53 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(0, TestFlags::all(), TestFlags::complement); + case(0, TestFlags::from_bits_retain(!0), TestFlags::complement); + + case(1 | 1 << 1, TestFlags::C, TestFlags::complement); + case( + 1 | 1 << 1, + TestFlags::C | TestFlags::from_bits_retain(1 << 3), + TestFlags::complement, + ); + + case( + 1 | 1 << 1 | 1 << 2, + TestFlags::empty(), + TestFlags::complement, + ); + case( + 1 | 1 << 1 | 1 << 2, + TestFlags::from_bits_retain(1 << 3), + TestFlags::complement, + ); + + case(0, TestZero::empty(), TestZero::complement); + + case(0, TestEmpty::empty(), TestEmpty::complement); + + case(1 << 2, TestOverlapping::AB, TestOverlapping::complement); + + case(!0, TestExternal::empty(), TestExternal::complement); +} + +#[track_caller] +fn case + Copy>( + expected: T::Bits, + value: T, + inherent: impl FnOnce(T) -> T, +) where + T::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!(expected, inherent(value).bits(), "{:?}.complement()", value); + assert_eq!( + expected, + Flags::complement(value).bits(), + "Flags::complement({:?})", + value + ); + assert_eq!(expected, (!value).bits(), "!{:?}", value); +} diff --git a/third_party/rust/bitflags/src/tests/contains.rs b/third_party/rust/bitflags/src/tests/contains.rs new file mode 100644 index 0000000000..12428ddcb0 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/contains.rs @@ -0,0 +1,108 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::empty(), + &[ + (TestFlags::empty(), true), + (TestFlags::A, false), + (TestFlags::B, false), + (TestFlags::C, false), + (TestFlags::from_bits_retain(1 << 3), false), + ], + TestFlags::contains, + ); + + case( + TestFlags::A, + &[ + (TestFlags::empty(), true), + (TestFlags::A, true), + (TestFlags::B, false), + (TestFlags::C, false), + (TestFlags::ABC, false), + (TestFlags::from_bits_retain(1 << 3), false), + (TestFlags::from_bits_retain(1 | (1 << 3)), false), + ], + TestFlags::contains, + ); + + case( + TestFlags::ABC, + &[ + (TestFlags::empty(), true), + (TestFlags::A, true), + (TestFlags::B, true), + (TestFlags::C, true), + (TestFlags::ABC, true), + (TestFlags::from_bits_retain(1 << 3), false), + ], + TestFlags::contains, + ); + + case( + TestFlags::from_bits_retain(1 << 3), + &[ + (TestFlags::empty(), true), + (TestFlags::A, false), + (TestFlags::B, false), + (TestFlags::C, false), + (TestFlags::from_bits_retain(1 << 3), true), + ], + TestFlags::contains, + ); + + case( + TestZero::ZERO, + &[(TestZero::ZERO, true)], + TestZero::contains, + ); + + case( + TestOverlapping::AB, + &[ + (TestOverlapping::AB, true), + (TestOverlapping::BC, false), + (TestOverlapping::from_bits_retain(1 << 1), true), + ], + TestOverlapping::contains, + ); + + case( + TestExternal::all(), + &[ + (TestExternal::A, true), + (TestExternal::B, true), + (TestExternal::C, true), + (TestExternal::from_bits_retain(1 << 5 | 1 << 7), true), + ], + TestExternal::contains, + ); +} + +#[track_caller] +fn case( + value: T, + inputs: &[(T, bool)], + mut inherent: impl FnMut(&T, T) -> bool, +) { + for (input, expected) in inputs { + assert_eq!( + *expected, + inherent(&value, *input), + "{:?}.contains({:?})", + value, + input + ); + assert_eq!( + *expected, + Flags::contains(&value, *input), + "Flags::contains({:?}, {:?})", + value, + input + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/difference.rs b/third_party/rust/bitflags/src/tests/difference.rs new file mode 100644 index 0000000000..6ce9c0bf19 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/difference.rs @@ -0,0 +1,92 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::A | TestFlags::B, + &[ + (TestFlags::A, 1 << 1), + (TestFlags::B, 1), + (TestFlags::from_bits_retain(1 << 3), 1 | 1 << 1), + ], + TestFlags::difference, + ); + + case( + TestFlags::from_bits_retain(1 | 1 << 3), + &[ + (TestFlags::A, 1 << 3), + (TestFlags::from_bits_retain(1 << 3), 1), + ], + TestFlags::difference, + ); + + case( + TestExternal::from_bits_retain(!0), + &[(TestExternal::A, 0b1111_1110)], + TestExternal::difference, + ); + + assert_eq!( + 0b1111_1110, + (TestExternal::from_bits_retain(!0) & !TestExternal::A).bits() + ); + + assert_eq!( + 0b1111_1110, + (TestFlags::from_bits_retain(!0).difference(TestFlags::A)).bits() + ); + + // The `!` operator unsets bits that don't correspond to known flags + assert_eq!( + 1 << 1 | 1 << 2, + (TestFlags::from_bits_retain(!0) & !TestFlags::A).bits() + ); +} + +#[track_caller] +fn case + std::ops::SubAssign + Copy>( + value: T, + inputs: &[(T, T::Bits)], + mut inherent: impl FnMut(T, T) -> T, +) where + T::Bits: std::fmt::Debug + PartialEq + Copy, +{ + for (input, expected) in inputs { + assert_eq!( + *expected, + inherent(value, *input).bits(), + "{:?}.difference({:?})", + value, + input + ); + assert_eq!( + *expected, + Flags::difference(value, *input).bits(), + "Flags::difference({:?}, {:?})", + value, + input + ); + assert_eq!( + *expected, + (value - *input).bits(), + "{:?} - {:?}", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + value -= *input; + value + } + .bits(), + "{:?} -= {:?}", + value, + input, + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/empty.rs b/third_party/rust/bitflags/src/tests/empty.rs new file mode 100644 index 0000000000..57fb1c7cf1 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/empty.rs @@ -0,0 +1,23 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(0, TestFlags::empty); + + case(0, TestZero::empty); + + case(0, TestEmpty::empty); + + case(0, TestExternal::empty); +} + +#[track_caller] +fn case(expected: T::Bits, inherent: impl FnOnce() -> T) +where + ::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!(expected, inherent().bits(), "T::empty()"); + assert_eq!(expected, T::empty().bits(), "Flags::empty()"); +} diff --git a/third_party/rust/bitflags/src/tests/eq.rs b/third_party/rust/bitflags/src/tests/eq.rs new file mode 100644 index 0000000000..9779af7629 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/eq.rs @@ -0,0 +1,10 @@ +use super::*; + +#[test] +fn cases() { + assert_eq!(TestFlags::empty(), TestFlags::empty()); + assert_eq!(TestFlags::all(), TestFlags::all()); + + assert!(TestFlags::from_bits_retain(1) < TestFlags::from_bits_retain(2)); + assert!(TestFlags::from_bits_retain(2) > TestFlags::from_bits_retain(1)); +} diff --git a/third_party/rust/bitflags/src/tests/extend.rs b/third_party/rust/bitflags/src/tests/extend.rs new file mode 100644 index 0000000000..869dc17fc8 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/extend.rs @@ -0,0 +1,42 @@ +use super::*; + +#[test] +fn cases() { + let mut flags = TestFlags::empty(); + + flags.extend(TestFlags::A); + + assert_eq!(TestFlags::A, flags); + + flags.extend(TestFlags::A | TestFlags::B | TestFlags::C); + + assert_eq!(TestFlags::ABC, flags); + + flags.extend(TestFlags::from_bits_retain(1 << 5)); + + assert_eq!(TestFlags::ABC | TestFlags::from_bits_retain(1 << 5), flags); +} + +mod external { + use super::*; + + #[test] + fn cases() { + let mut flags = TestExternal::empty(); + + flags.extend(TestExternal::A); + + assert_eq!(TestExternal::A, flags); + + flags.extend(TestExternal::A | TestExternal::B | TestExternal::C); + + assert_eq!(TestExternal::ABC, flags); + + flags.extend(TestExternal::from_bits_retain(1 << 5)); + + assert_eq!( + TestExternal::ABC | TestExternal::from_bits_retain(1 << 5), + flags + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/flags.rs b/third_party/rust/bitflags/src/tests/flags.rs new file mode 100644 index 0000000000..7a625b312c --- /dev/null +++ b/third_party/rust/bitflags/src/tests/flags.rs @@ -0,0 +1,46 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + let flags = TestFlags::FLAGS + .iter() + .map(|flag| (flag.name(), flag.value().bits())) + .collect::>(); + + assert_eq!( + vec![ + ("A", 1u8), + ("B", 1 << 1), + ("C", 1 << 2), + ("ABC", 1 | 1 << 1 | 1 << 2), + ], + flags, + ); + + assert_eq!(0, TestEmpty::FLAGS.iter().count()); +} + +mod external { + use super::*; + + #[test] + fn cases() { + let flags = TestExternal::FLAGS + .iter() + .map(|flag| (flag.name(), flag.value().bits())) + .collect::>(); + + assert_eq!( + vec![ + ("A", 1u8), + ("B", 1 << 1), + ("C", 1 << 2), + ("ABC", 1 | 1 << 1 | 1 << 2), + ("", !0), + ], + flags, + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/fmt.rs b/third_party/rust/bitflags/src/tests/fmt.rs new file mode 100644 index 0000000000..ed4571877d --- /dev/null +++ b/third_party/rust/bitflags/src/tests/fmt.rs @@ -0,0 +1,97 @@ +use super::*; + +#[test] +fn cases() { + case(TestFlags::empty(), "TestFlags(0x0)", "0", "0", "0", "0"); + case(TestFlags::A, "TestFlags(A)", "1", "1", "1", "1"); + case( + TestFlags::all(), + "TestFlags(A | B | C)", + "7", + "7", + "7", + "111", + ); + case( + TestFlags::from_bits_retain(1 << 3), + "TestFlags(0x8)", + "8", + "8", + "10", + "1000", + ); + case( + TestFlags::A | TestFlags::from_bits_retain(1 << 3), + "TestFlags(A | 0x8)", + "9", + "9", + "11", + "1001", + ); + + case(TestZero::ZERO, "TestZero(0x0)", "0", "0", "0", "0"); + case( + TestZero::ZERO | TestZero::from_bits_retain(1), + "TestZero(0x1)", + "1", + "1", + "1", + "1", + ); + + case(TestZeroOne::ONE, "TestZeroOne(ONE)", "1", "1", "1", "1"); + + case( + TestOverlapping::from_bits_retain(1 << 1), + "TestOverlapping(0x2)", + "2", + "2", + "2", + "10", + ); + + case( + TestExternal::from_bits_retain(1 | 1 << 1 | 1 << 3), + "TestExternal(A | B | 0x8)", + "B", + "b", + "13", + "1011", + ); + + case( + TestExternal::all(), + "TestExternal(A | B | C | 0xf8)", + "FF", + "ff", + "377", + "11111111", + ); + + case( + TestExternalFull::all(), + "TestExternalFull(0xff)", + "FF", + "ff", + "377", + "11111111", + ); +} + +#[track_caller] +fn case< + T: std::fmt::Debug + std::fmt::UpperHex + std::fmt::LowerHex + std::fmt::Octal + std::fmt::Binary, +>( + value: T, + debug: &str, + uhex: &str, + lhex: &str, + oct: &str, + bin: &str, +) { + assert_eq!(debug, format!("{:?}", value)); + assert_eq!(uhex, format!("{:X}", value)); + assert_eq!(lhex, format!("{:x}", value)); + assert_eq!(oct, format!("{:o}", value)); + assert_eq!(bin, format!("{:b}", value)); +} diff --git a/third_party/rust/bitflags/src/tests/from_bits.rs b/third_party/rust/bitflags/src/tests/from_bits.rs new file mode 100644 index 0000000000..dada9aff82 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/from_bits.rs @@ -0,0 +1,45 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(Some(0), 0, TestFlags::from_bits); + case(Some(1), 1, TestFlags::from_bits); + case( + Some(1 | 1 << 1 | 1 << 2), + 1 | 1 << 1 | 1 << 2, + TestFlags::from_bits, + ); + + case(None, 1 << 3, TestFlags::from_bits); + case(None, 1 | 1 << 3, TestFlags::from_bits); + + case(Some(1 | 1 << 1), 1 | 1 << 1, TestOverlapping::from_bits); + + case(Some(1 << 1), 1 << 1, TestOverlapping::from_bits); + + case(Some(1 << 5), 1 << 5, TestExternal::from_bits); +} + +#[track_caller] +fn case( + expected: Option, + input: T::Bits, + inherent: impl FnOnce(T::Bits) -> Option, +) where + ::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!( + expected, + inherent(input).map(|f| f.bits()), + "T::from_bits({:?})", + input + ); + assert_eq!( + expected, + T::from_bits(input).map(|f| f.bits()), + "Flags::from_bits({:?})", + input + ); +} diff --git a/third_party/rust/bitflags/src/tests/from_bits_retain.rs b/third_party/rust/bitflags/src/tests/from_bits_retain.rs new file mode 100644 index 0000000000..1ae28a663f --- /dev/null +++ b/third_party/rust/bitflags/src/tests/from_bits_retain.rs @@ -0,0 +1,38 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(0, TestFlags::from_bits_retain); + case(1, TestFlags::from_bits_retain); + case(1 | 1 << 1 | 1 << 2, TestFlags::from_bits_retain); + + case(1 << 3, TestFlags::from_bits_retain); + case(1 | 1 << 3, TestFlags::from_bits_retain); + + case(1 | 1 << 1, TestOverlapping::from_bits_retain); + + case(1 << 1, TestOverlapping::from_bits_retain); + + case(1 << 5, TestExternal::from_bits_retain); +} + +#[track_caller] +fn case(input: T::Bits, inherent: impl FnOnce(T::Bits) -> T) +where + ::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!( + input, + inherent(input).bits(), + "T::from_bits_retain({:?})", + input + ); + assert_eq!( + input, + T::from_bits_retain(input).bits(), + "Flags::from_bits_retain({:?})", + input + ); +} diff --git a/third_party/rust/bitflags/src/tests/from_bits_truncate.rs b/third_party/rust/bitflags/src/tests/from_bits_truncate.rs new file mode 100644 index 0000000000..e4f3e537c4 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/from_bits_truncate.rs @@ -0,0 +1,42 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(0, 0, TestFlags::from_bits_truncate); + case(1, 1, TestFlags::from_bits_truncate); + case( + 1 | 1 << 1 | 1 << 2, + 1 | 1 << 1 | 1 << 2, + TestFlags::from_bits_truncate, + ); + + case(0, 1 << 3, TestFlags::from_bits_truncate); + case(1, 1 | 1 << 3, TestFlags::from_bits_truncate); + + case(1 | 1 << 1, 1 | 1 << 1, TestOverlapping::from_bits_truncate); + + case(1 << 1, 1 << 1, TestOverlapping::from_bits_truncate); + + case(1 << 5, 1 << 5, TestExternal::from_bits_truncate); +} + +#[track_caller] +fn case(expected: T::Bits, input: T::Bits, inherent: impl FnOnce(T::Bits) -> T) +where + ::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!( + expected, + inherent(input).bits(), + "T::from_bits_truncate({:?})", + input + ); + assert_eq!( + expected, + T::from_bits_truncate(input).bits(), + "Flags::from_bits_truncate({:?})", + input + ); +} diff --git a/third_party/rust/bitflags/src/tests/from_name.rs b/third_party/rust/bitflags/src/tests/from_name.rs new file mode 100644 index 0000000000..1d9a4e48b6 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/from_name.rs @@ -0,0 +1,42 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(Some(1), "A", TestFlags::from_name); + case(Some(1 << 1), "B", TestFlags::from_name); + case(Some(1 | 1 << 1 | 1 << 2), "ABC", TestFlags::from_name); + + case(None, "", TestFlags::from_name); + case(None, "a", TestFlags::from_name); + case(None, "0x1", TestFlags::from_name); + case(None, "A | B", TestFlags::from_name); + + case(Some(0), "ZERO", TestZero::from_name); + + case(Some(2), "二", TestUnicode::from_name); + + case(None, "_", TestExternal::from_name); + + case(None, "", TestExternal::from_name); +} + +#[track_caller] +fn case(expected: Option, input: &str, inherent: impl FnOnce(&str) -> Option) +where + ::Bits: std::fmt::Debug + PartialEq, +{ + assert_eq!( + expected, + inherent(input).map(|f| f.bits()), + "T::from_name({:?})", + input + ); + assert_eq!( + expected, + T::from_name(input).map(|f| f.bits()), + "Flags::from_name({:?})", + input + ); +} diff --git a/third_party/rust/bitflags/src/tests/insert.rs b/third_party/rust/bitflags/src/tests/insert.rs new file mode 100644 index 0000000000..b18cd17235 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/insert.rs @@ -0,0 +1,91 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::empty(), + &[ + (TestFlags::A, 1), + (TestFlags::A | TestFlags::B, 1 | 1 << 1), + (TestFlags::empty(), 0), + (TestFlags::from_bits_retain(1 << 3), 1 << 3), + ], + TestFlags::insert, + TestFlags::set, + ); + + case( + TestFlags::A, + &[ + (TestFlags::A, 1), + (TestFlags::empty(), 1), + (TestFlags::B, 1 | 1 << 1), + ], + TestFlags::insert, + TestFlags::set, + ); +} + +#[track_caller] +fn case( + value: T, + inputs: &[(T, T::Bits)], + mut inherent_insert: impl FnMut(&mut T, T), + mut inherent_set: impl FnMut(&mut T, T, bool), +) where + T::Bits: std::fmt::Debug + PartialEq + Copy, +{ + for (input, expected) in inputs { + assert_eq!( + *expected, + { + let mut value = value; + inherent_insert(&mut value, *input); + value + } + .bits(), + "{:?}.insert({:?})", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + Flags::insert(&mut value, *input); + value + } + .bits(), + "Flags::insert({:?}, {:?})", + value, + input + ); + + assert_eq!( + *expected, + { + let mut value = value; + inherent_set(&mut value, *input, true); + value + } + .bits(), + "{:?}.set({:?}, true)", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + Flags::set(&mut value, *input, true); + value + } + .bits(), + "Flags::set({:?}, {:?}, true)", + value, + input + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/intersection.rs b/third_party/rust/bitflags/src/tests/intersection.rs new file mode 100644 index 0000000000..10a8ae9fb6 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/intersection.rs @@ -0,0 +1,79 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::empty(), + &[(TestFlags::empty(), 0), (TestFlags::all(), 0)], + TestFlags::intersection, + ); + + case( + TestFlags::all(), + &[ + (TestFlags::all(), 1 | 1 << 1 | 1 << 2), + (TestFlags::A, 1), + (TestFlags::from_bits_retain(1 << 3), 0), + ], + TestFlags::intersection, + ); + + case( + TestFlags::from_bits_retain(1 << 3), + &[(TestFlags::from_bits_retain(1 << 3), 1 << 3)], + TestFlags::intersection, + ); + + case( + TestOverlapping::AB, + &[(TestOverlapping::BC, 1 << 1)], + TestOverlapping::intersection, + ); +} + +#[track_caller] +fn case + std::ops::BitAndAssign + Copy>( + value: T, + inputs: &[(T, T::Bits)], + mut inherent: impl FnMut(T, T) -> T, +) where + T::Bits: std::fmt::Debug + PartialEq + Copy, +{ + for (input, expected) in inputs { + assert_eq!( + *expected, + inherent(value, *input).bits(), + "{:?}.intersection({:?})", + value, + input + ); + assert_eq!( + *expected, + Flags::intersection(value, *input).bits(), + "Flags::intersection({:?}, {:?})", + value, + input + ); + assert_eq!( + *expected, + (value & *input).bits(), + "{:?} & {:?}", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + value &= *input; + value + } + .bits(), + "{:?} &= {:?}", + value, + input, + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/intersects.rs b/third_party/rust/bitflags/src/tests/intersects.rs new file mode 100644 index 0000000000..fe907981a2 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/intersects.rs @@ -0,0 +1,91 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::empty(), + &[ + (TestFlags::empty(), false), + (TestFlags::A, false), + (TestFlags::B, false), + (TestFlags::C, false), + (TestFlags::from_bits_retain(1 << 3), false), + ], + TestFlags::intersects, + ); + + case( + TestFlags::A, + &[ + (TestFlags::empty(), false), + (TestFlags::A, true), + (TestFlags::B, false), + (TestFlags::C, false), + (TestFlags::ABC, true), + (TestFlags::from_bits_retain(1 << 3), false), + (TestFlags::from_bits_retain(1 | (1 << 3)), true), + ], + TestFlags::intersects, + ); + + case( + TestFlags::ABC, + &[ + (TestFlags::empty(), false), + (TestFlags::A, true), + (TestFlags::B, true), + (TestFlags::C, true), + (TestFlags::ABC, true), + (TestFlags::from_bits_retain(1 << 3), false), + ], + TestFlags::intersects, + ); + + case( + TestFlags::from_bits_retain(1 << 3), + &[ + (TestFlags::empty(), false), + (TestFlags::A, false), + (TestFlags::B, false), + (TestFlags::C, false), + (TestFlags::from_bits_retain(1 << 3), true), + ], + TestFlags::intersects, + ); + + case( + TestOverlapping::AB, + &[ + (TestOverlapping::AB, true), + (TestOverlapping::BC, true), + (TestOverlapping::from_bits_retain(1 << 1), true), + ], + TestOverlapping::intersects, + ); +} + +#[track_caller] +fn case( + value: T, + inputs: &[(T, bool)], + mut inherent: impl FnMut(&T, T) -> bool, +) { + for (input, expected) in inputs { + assert_eq!( + *expected, + inherent(&value, *input), + "{:?}.intersects({:?})", + value, + input + ); + assert_eq!( + *expected, + Flags::intersects(&value, *input), + "Flags::intersects({:?}, {:?})", + value, + input + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/is_all.rs b/third_party/rust/bitflags/src/tests/is_all.rs new file mode 100644 index 0000000000..382a458f61 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/is_all.rs @@ -0,0 +1,32 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(false, TestFlags::empty(), TestFlags::is_all); + case(false, TestFlags::A, TestFlags::is_all); + + case(true, TestFlags::ABC, TestFlags::is_all); + + case( + true, + TestFlags::ABC | TestFlags::from_bits_retain(1 << 3), + TestFlags::is_all, + ); + + case(true, TestZero::empty(), TestZero::is_all); + + case(true, TestEmpty::empty(), TestEmpty::is_all); +} + +#[track_caller] +fn case(expected: bool, value: T, inherent: impl FnOnce(&T) -> bool) { + assert_eq!(expected, inherent(&value), "{:?}.is_all()", value); + assert_eq!( + expected, + Flags::is_all(&value), + "Flags::is_all({:?})", + value + ); +} diff --git a/third_party/rust/bitflags/src/tests/is_empty.rs b/third_party/rust/bitflags/src/tests/is_empty.rs new file mode 100644 index 0000000000..92165f18e3 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/is_empty.rs @@ -0,0 +1,31 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case(true, TestFlags::empty(), TestFlags::is_empty); + + case(false, TestFlags::A, TestFlags::is_empty); + case(false, TestFlags::ABC, TestFlags::is_empty); + case( + false, + TestFlags::from_bits_retain(1 << 3), + TestFlags::is_empty, + ); + + case(true, TestZero::empty(), TestZero::is_empty); + + case(true, TestEmpty::empty(), TestEmpty::is_empty); +} + +#[track_caller] +fn case(expected: bool, value: T, inherent: impl FnOnce(&T) -> bool) { + assert_eq!(expected, inherent(&value), "{:?}.is_empty()", value); + assert_eq!( + expected, + Flags::is_empty(&value), + "Flags::is_empty({:?})", + value + ); +} diff --git a/third_party/rust/bitflags/src/tests/iter.rs b/third_party/rust/bitflags/src/tests/iter.rs new file mode 100644 index 0000000000..54b1d27d4c --- /dev/null +++ b/third_party/rust/bitflags/src/tests/iter.rs @@ -0,0 +1,209 @@ +use super::*; + +use crate::Flags; + +#[test] +#[cfg(not(miri))] // Very slow in miri +fn roundtrip() { + for a in 0u8..=255 { + for b in 0u8..=255 { + let f = TestFlags::from_bits_retain(a | b); + + assert_eq!(f, f.iter().collect::()); + assert_eq!( + TestFlags::from_bits_truncate(f.bits()), + f.iter_names().map(|(_, f)| f).collect::() + ); + + let f = TestExternal::from_bits_retain(a | b); + + assert_eq!(f, f.iter().collect::()); + } + } +} + +mod collect { + use super::*; + + #[test] + fn cases() { + assert_eq!(0, [].into_iter().collect::().bits()); + + assert_eq!(1, [TestFlags::A,].into_iter().collect::().bits()); + + assert_eq!( + 1 | 1 << 1 | 1 << 2, + [TestFlags::A, TestFlags::B | TestFlags::C,] + .into_iter() + .collect::() + .bits() + ); + + assert_eq!( + 1 | 1 << 3, + [ + TestFlags::from_bits_retain(1 << 3), + TestFlags::empty(), + TestFlags::A, + ] + .into_iter() + .collect::() + .bits() + ); + + assert_eq!( + 1 << 5 | 1 << 7, + [ + TestExternal::empty(), + TestExternal::from_bits_retain(1 << 5), + TestExternal::from_bits_retain(1 << 7), + ] + .into_iter() + .collect::() + .bits() + ); + } +} + +mod iter { + use super::*; + + #[test] + fn cases() { + case(&[], TestFlags::empty(), TestFlags::iter); + + case(&[1], TestFlags::A, TestFlags::iter); + case(&[1, 1 << 1], TestFlags::A | TestFlags::B, TestFlags::iter); + case( + &[1, 1 << 1, 1 << 3], + TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3), + TestFlags::iter, + ); + + case(&[1, 1 << 1, 1 << 2], TestFlags::ABC, TestFlags::iter); + case( + &[1, 1 << 1, 1 << 2, 1 << 3], + TestFlags::ABC | TestFlags::from_bits_retain(1 << 3), + TestFlags::iter, + ); + + case( + &[1 | 1 << 1 | 1 << 2], + TestFlagsInvert::ABC, + TestFlagsInvert::iter, + ); + + case(&[], TestZero::ZERO, TestZero::iter); + + case( + &[1, 1 << 1, 1 << 2, 0b1111_1000], + TestExternal::all(), + TestExternal::iter, + ); + } + + #[track_caller] + fn case + Copy>( + expected: &[T::Bits], + value: T, + inherent: impl FnOnce(&T) -> crate::iter::Iter, + ) where + T::Bits: std::fmt::Debug + PartialEq, + { + assert_eq!( + expected, + inherent(&value).map(|f| f.bits()).collect::>(), + "{:?}.iter()", + value + ); + assert_eq!( + expected, + Flags::iter(&value).map(|f| f.bits()).collect::>(), + "Flags::iter({:?})", + value + ); + assert_eq!( + expected, + value.into_iter().map(|f| f.bits()).collect::>(), + "{:?}.into_iter()", + value + ); + } +} + +mod iter_names { + use super::*; + + #[test] + fn cases() { + case(&[], TestFlags::empty(), TestFlags::iter_names); + + case(&[("A", 1)], TestFlags::A, TestFlags::iter_names); + case( + &[("A", 1), ("B", 1 << 1)], + TestFlags::A | TestFlags::B, + TestFlags::iter_names, + ); + case( + &[("A", 1), ("B", 1 << 1)], + TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3), + TestFlags::iter_names, + ); + + case( + &[("A", 1), ("B", 1 << 1), ("C", 1 << 2)], + TestFlags::ABC, + TestFlags::iter_names, + ); + case( + &[("A", 1), ("B", 1 << 1), ("C", 1 << 2)], + TestFlags::ABC | TestFlags::from_bits_retain(1 << 3), + TestFlags::iter_names, + ); + + case( + &[("ABC", 1 | 1 << 1 | 1 << 2)], + TestFlagsInvert::ABC, + TestFlagsInvert::iter_names, + ); + + case(&[], TestZero::ZERO, TestZero::iter_names); + + case( + &[("A", 1)], + TestOverlappingFull::A, + TestOverlappingFull::iter_names, + ); + case( + &[("A", 1), ("D", 1 << 1)], + TestOverlappingFull::A | TestOverlappingFull::D, + TestOverlappingFull::iter_names, + ); + } + + #[track_caller] + fn case( + expected: &[(&'static str, T::Bits)], + value: T, + inherent: impl FnOnce(&T) -> crate::iter::IterNames, + ) where + T::Bits: std::fmt::Debug + PartialEq, + { + assert_eq!( + expected, + inherent(&value) + .map(|(n, f)| (n, f.bits())) + .collect::>(), + "{:?}.iter_names()", + value + ); + assert_eq!( + expected, + Flags::iter_names(&value) + .map(|(n, f)| (n, f.bits())) + .collect::>(), + "Flags::iter_names({:?})", + value + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/parser.rs b/third_party/rust/bitflags/src/tests/parser.rs new file mode 100644 index 0000000000..fb27225ece --- /dev/null +++ b/third_party/rust/bitflags/src/tests/parser.rs @@ -0,0 +1,332 @@ +use super::*; + +use crate::{parser::*, Flags}; + +#[test] +#[cfg(not(miri))] // Very slow in miri +fn roundtrip() { + let mut s = String::new(); + + for a in 0u8..=255 { + for b in 0u8..=255 { + let f = TestFlags::from_bits_retain(a | b); + + s.clear(); + to_writer(&f, &mut s).unwrap(); + + assert_eq!(f, from_str::(&s).unwrap()); + } + } +} + +#[test] +#[cfg(not(miri))] // Very slow in miri +fn roundtrip_truncate() { + let mut s = String::new(); + + for a in 0u8..=255 { + for b in 0u8..=255 { + let f = TestFlags::from_bits_retain(a | b); + + s.clear(); + to_writer_truncate(&f, &mut s).unwrap(); + + assert_eq!( + TestFlags::from_bits_truncate(f.bits()), + from_str_truncate::(&s).unwrap() + ); + } + } +} + +#[test] +#[cfg(not(miri))] // Very slow in miri +fn roundtrip_strict() { + let mut s = String::new(); + + for a in 0u8..=255 { + for b in 0u8..=255 { + let f = TestFlags::from_bits_retain(a | b); + + s.clear(); + to_writer_strict(&f, &mut s).unwrap(); + + let mut strict = TestFlags::empty(); + for (_, flag) in f.iter_names() { + strict |= flag; + } + let f = strict; + + if let Ok(s) = from_str_strict::(&s) { + assert_eq!(f, s); + } + } + } +} + +mod from_str { + use super::*; + + #[test] + fn valid() { + assert_eq!(0, from_str::("").unwrap().bits()); + + assert_eq!(1, from_str::("A").unwrap().bits()); + assert_eq!(1, from_str::(" A ").unwrap().bits()); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str::("A | B | C").unwrap().bits() + ); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str::("A\n|\tB\r\n| C ").unwrap().bits() + ); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str::("A|B|C").unwrap().bits() + ); + + assert_eq!(1 << 3, from_str::("0x8").unwrap().bits()); + assert_eq!(1 | 1 << 3, from_str::("A | 0x8").unwrap().bits()); + assert_eq!( + 1 | 1 << 1 | 1 << 3, + from_str::("0x1 | 0x8 | B").unwrap().bits() + ); + + assert_eq!( + 1 | 1 << 1, + from_str::("一 | 二").unwrap().bits() + ); + } + + #[test] + fn invalid() { + assert!(from_str::("a") + .unwrap_err() + .to_string() + .starts_with("unrecognized named flag")); + assert!(from_str::("A & B") + .unwrap_err() + .to_string() + .starts_with("unrecognized named flag")); + + assert!(from_str::("0xg") + .unwrap_err() + .to_string() + .starts_with("invalid hex flag")); + assert!(from_str::("0xffffffffffff") + .unwrap_err() + .to_string() + .starts_with("invalid hex flag")); + } +} + +mod to_writer { + use super::*; + + #[test] + fn cases() { + assert_eq!("", write(TestFlags::empty())); + assert_eq!("A", write(TestFlags::A)); + assert_eq!("A | B | C", write(TestFlags::all())); + assert_eq!("0x8", write(TestFlags::from_bits_retain(1 << 3))); + assert_eq!( + "A | 0x8", + write(TestFlags::A | TestFlags::from_bits_retain(1 << 3)) + ); + + assert_eq!("", write(TestZero::ZERO)); + + assert_eq!("ABC", write(TestFlagsInvert::all())); + + assert_eq!("0x1", write(TestOverlapping::from_bits_retain(1))); + + assert_eq!("A", write(TestOverlappingFull::C)); + assert_eq!( + "A | D", + write(TestOverlappingFull::C | TestOverlappingFull::D) + ); + } + + fn write(value: F) -> String + where + F::Bits: crate::parser::WriteHex, + { + let mut s = String::new(); + + to_writer(&value, &mut s).unwrap(); + s + } +} + +mod from_str_truncate { + use super::*; + + #[test] + fn valid() { + assert_eq!(0, from_str_truncate::("").unwrap().bits()); + + assert_eq!(1, from_str_truncate::("A").unwrap().bits()); + assert_eq!(1, from_str_truncate::(" A ").unwrap().bits()); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str_truncate::("A | B | C").unwrap().bits() + ); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str_truncate::("A\n|\tB\r\n| C ") + .unwrap() + .bits() + ); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str_truncate::("A|B|C").unwrap().bits() + ); + + assert_eq!(0, from_str_truncate::("0x8").unwrap().bits()); + assert_eq!(1, from_str_truncate::("A | 0x8").unwrap().bits()); + assert_eq!( + 1 | 1 << 1, + from_str_truncate::("0x1 | 0x8 | B") + .unwrap() + .bits() + ); + + assert_eq!( + 1 | 1 << 1, + from_str_truncate::("一 | 二").unwrap().bits() + ); + } +} + +mod to_writer_truncate { + use super::*; + + #[test] + fn cases() { + assert_eq!("", write(TestFlags::empty())); + assert_eq!("A", write(TestFlags::A)); + assert_eq!("A | B | C", write(TestFlags::all())); + assert_eq!("", write(TestFlags::from_bits_retain(1 << 3))); + assert_eq!( + "A", + write(TestFlags::A | TestFlags::from_bits_retain(1 << 3)) + ); + + assert_eq!("", write(TestZero::ZERO)); + + assert_eq!("ABC", write(TestFlagsInvert::all())); + + assert_eq!("0x1", write(TestOverlapping::from_bits_retain(1))); + + assert_eq!("A", write(TestOverlappingFull::C)); + assert_eq!( + "A | D", + write(TestOverlappingFull::C | TestOverlappingFull::D) + ); + } + + fn write(value: F) -> String + where + F::Bits: crate::parser::WriteHex, + { + let mut s = String::new(); + + to_writer_truncate(&value, &mut s).unwrap(); + s + } +} + +mod from_str_strict { + use super::*; + + #[test] + fn valid() { + assert_eq!(0, from_str_strict::("").unwrap().bits()); + + assert_eq!(1, from_str_strict::("A").unwrap().bits()); + assert_eq!(1, from_str_strict::(" A ").unwrap().bits()); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str_strict::("A | B | C").unwrap().bits() + ); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str_strict::("A\n|\tB\r\n| C ") + .unwrap() + .bits() + ); + assert_eq!( + 1 | 1 << 1 | 1 << 2, + from_str_strict::("A|B|C").unwrap().bits() + ); + + assert_eq!( + 1 | 1 << 1, + from_str_strict::("一 | 二").unwrap().bits() + ); + } + + #[test] + fn invalid() { + assert!(from_str_strict::("a") + .unwrap_err() + .to_string() + .starts_with("unrecognized named flag")); + assert!(from_str_strict::("A & B") + .unwrap_err() + .to_string() + .starts_with("unrecognized named flag")); + + assert!(from_str_strict::("0x1") + .unwrap_err() + .to_string() + .starts_with("invalid hex flag")); + assert!(from_str_strict::("0xg") + .unwrap_err() + .to_string() + .starts_with("invalid hex flag")); + assert!(from_str_strict::("0xffffffffffff") + .unwrap_err() + .to_string() + .starts_with("invalid hex flag")); + } +} + +mod to_writer_strict { + use super::*; + + #[test] + fn cases() { + assert_eq!("", write(TestFlags::empty())); + assert_eq!("A", write(TestFlags::A)); + assert_eq!("A | B | C", write(TestFlags::all())); + assert_eq!("", write(TestFlags::from_bits_retain(1 << 3))); + assert_eq!( + "A", + write(TestFlags::A | TestFlags::from_bits_retain(1 << 3)) + ); + + assert_eq!("", write(TestZero::ZERO)); + + assert_eq!("ABC", write(TestFlagsInvert::all())); + + assert_eq!("", write(TestOverlapping::from_bits_retain(1))); + + assert_eq!("A", write(TestOverlappingFull::C)); + assert_eq!( + "A | D", + write(TestOverlappingFull::C | TestOverlappingFull::D) + ); + } + + fn write(value: F) -> String + where + F::Bits: crate::parser::WriteHex, + { + let mut s = String::new(); + + to_writer_strict(&value, &mut s).unwrap(); + s + } +} diff --git a/third_party/rust/bitflags/src/tests/remove.rs b/third_party/rust/bitflags/src/tests/remove.rs new file mode 100644 index 0000000000..574b1edbf2 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/remove.rs @@ -0,0 +1,100 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::empty(), + &[ + (TestFlags::A, 0), + (TestFlags::empty(), 0), + (TestFlags::from_bits_retain(1 << 3), 0), + ], + TestFlags::remove, + TestFlags::set, + ); + + case( + TestFlags::A, + &[ + (TestFlags::A, 0), + (TestFlags::empty(), 1), + (TestFlags::B, 1), + ], + TestFlags::remove, + TestFlags::set, + ); + + case( + TestFlags::ABC, + &[ + (TestFlags::A, 1 << 1 | 1 << 2), + (TestFlags::A | TestFlags::C, 1 << 1), + ], + TestFlags::remove, + TestFlags::set, + ); +} + +#[track_caller] +fn case( + value: T, + inputs: &[(T, T::Bits)], + mut inherent_remove: impl FnMut(&mut T, T), + mut inherent_set: impl FnMut(&mut T, T, bool), +) where + T::Bits: std::fmt::Debug + PartialEq + Copy, +{ + for (input, expected) in inputs { + assert_eq!( + *expected, + { + let mut value = value; + inherent_remove(&mut value, *input); + value + } + .bits(), + "{:?}.remove({:?})", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + Flags::remove(&mut value, *input); + value + } + .bits(), + "Flags::remove({:?}, {:?})", + value, + input + ); + + assert_eq!( + *expected, + { + let mut value = value; + inherent_set(&mut value, *input, false); + value + } + .bits(), + "{:?}.set({:?}, false)", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + Flags::set(&mut value, *input, false); + value + } + .bits(), + "Flags::set({:?}, {:?}, false)", + value, + input + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/symmetric_difference.rs b/third_party/rust/bitflags/src/tests/symmetric_difference.rs new file mode 100644 index 0000000000..75e9123ac5 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/symmetric_difference.rs @@ -0,0 +1,110 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::empty(), + &[ + (TestFlags::empty(), 0), + (TestFlags::all(), 1 | 1 << 1 | 1 << 2), + (TestFlags::from_bits_retain(1 << 3), 1 << 3), + ], + TestFlags::symmetric_difference, + TestFlags::toggle, + ); + + case( + TestFlags::A, + &[ + (TestFlags::empty(), 1), + (TestFlags::A, 0), + (TestFlags::all(), 1 << 1 | 1 << 2), + ], + TestFlags::symmetric_difference, + TestFlags::toggle, + ); + + case( + TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3), + &[ + (TestFlags::ABC, 1 << 2 | 1 << 3), + (TestFlags::from_bits_retain(1 << 3), 1 | 1 << 1), + ], + TestFlags::symmetric_difference, + TestFlags::toggle, + ); +} + +#[track_caller] +fn case + std::ops::BitXorAssign + Copy>( + value: T, + inputs: &[(T, T::Bits)], + mut inherent_sym_diff: impl FnMut(T, T) -> T, + mut inherent_toggle: impl FnMut(&mut T, T), +) where + T::Bits: std::fmt::Debug + PartialEq + Copy, +{ + for (input, expected) in inputs { + assert_eq!( + *expected, + inherent_sym_diff(value, *input).bits(), + "{:?}.symmetric_difference({:?})", + value, + input + ); + assert_eq!( + *expected, + Flags::symmetric_difference(value, *input).bits(), + "Flags::symmetric_difference({:?}, {:?})", + value, + input + ); + assert_eq!( + *expected, + (value ^ *input).bits(), + "{:?} ^ {:?}", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + value ^= *input; + value + } + .bits(), + "{:?} ^= {:?}", + value, + input, + ); + + assert_eq!( + *expected, + { + let mut value = value; + inherent_toggle(&mut value, *input); + value + } + .bits(), + "{:?}.toggle({:?})", + value, + input, + ); + + assert_eq!( + *expected, + { + let mut value = value; + Flags::toggle(&mut value, *input); + value + } + .bits(), + "{:?}.toggle({:?})", + value, + input, + ); + } +} diff --git a/third_party/rust/bitflags/src/tests/union.rs b/third_party/rust/bitflags/src/tests/union.rs new file mode 100644 index 0000000000..6190681931 --- /dev/null +++ b/third_party/rust/bitflags/src/tests/union.rs @@ -0,0 +1,71 @@ +use super::*; + +use crate::Flags; + +#[test] +fn cases() { + case( + TestFlags::empty(), + &[ + (TestFlags::A, 1), + (TestFlags::all(), 1 | 1 << 1 | 1 << 2), + (TestFlags::empty(), 0), + (TestFlags::from_bits_retain(1 << 3), 1 << 3), + ], + TestFlags::union, + ); + + case( + TestFlags::A | TestFlags::C, + &[ + (TestFlags::A | TestFlags::B, 1 | 1 << 1 | 1 << 2), + (TestFlags::A, 1 | 1 << 2), + ], + TestFlags::union, + ); +} + +#[track_caller] +fn case + std::ops::BitOrAssign + Copy>( + value: T, + inputs: &[(T, T::Bits)], + mut inherent: impl FnMut(T, T) -> T, +) where + T::Bits: std::fmt::Debug + PartialEq + Copy, +{ + for (input, expected) in inputs { + assert_eq!( + *expected, + inherent(value, *input).bits(), + "{:?}.union({:?})", + value, + input + ); + assert_eq!( + *expected, + Flags::union(value, *input).bits(), + "Flags::union({:?}, {:?})", + value, + input + ); + assert_eq!( + *expected, + (value | *input).bits(), + "{:?} | {:?}", + value, + input + ); + assert_eq!( + *expected, + { + let mut value = value; + value |= *input; + value + } + .bits(), + "{:?} |= {:?}", + value, + input, + ); + } +} diff --git a/third_party/rust/bitflags/src/traits.rs b/third_party/rust/bitflags/src/traits.rs index 28235142de..3905d7d5b0 100644 --- a/third_party/rust/bitflags/src/traits.rs +++ b/third_party/rust/bitflags/src/traits.rs @@ -11,6 +11,7 @@ use crate::{ /** A defined flags value that may be named or unnamed. */ +#[derive(Debug)] pub struct Flag { name: &'static str, value: B, diff --git a/third_party/rust/byteorder/.cargo-checksum.json b/third_party/rust/byteorder/.cargo-checksum.json index 434cc1a16f..bffae5de46 100644 --- a/third_party/rust/byteorder/.cargo-checksum.json +++ b/third_party/rust/byteorder/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"3a745d94ee9dce0d9dc638c02078cd5001d3d9d12d58b4f220c0101e32cfc16a","COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"8585455e5a0e638cf5d489a21e286e93680f835cb8a13595918b5eb7c8c7f212","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"9d57556868344534de2489317e3c6bb611348ecd44438dcb982bd8d2a55a5a1b","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","benches/bench.rs":"a80bf3cd446c9b6c0cca3865c4de047bdf4644b74cdf696822f8ff87adfa1fca","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/io.rs":"9612530634d0e7ce9887a23836b58c0d972c1f45b05d9ada8355961567075627","src/lib.rs":"813ce6a8beafee3fd4e63325d783108aa02e8c57e412bc97580191d84082fbc9"},"package":"14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"} \ No newline at end of file +{"files":{"CHANGELOG.md":"c1cb69be6db5933c4bb4ebb6591e0fe3e7b97d491face3abcf947383c218bb31","COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"94ba374cb26f3c68fb83da2e5e7dce85920fc4fb827620b06b39d71a9d0e1e18","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"2f2d64924c35b7203e3e3f3d136fcb714281762d145ca3513246da5547b1d014","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","benches/bench.rs":"8b114080042d3292ec8de425904e4114b7f532fe3add0d807521e6cc166a17ea","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/io.rs":"9612530634d0e7ce9887a23836b58c0d972c1f45b05d9ada8355961567075627","src/lib.rs":"ab3394c385b32457795931440cfb8dbca70ba5d9e1a428fcf651f7ccb2d6c34f"},"package":"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"} \ No newline at end of file diff --git a/third_party/rust/byteorder/CHANGELOG.md b/third_party/rust/byteorder/CHANGELOG.md index 6b51eb0760..9efb7ed29a 100644 --- a/third_party/rust/byteorder/CHANGELOG.md +++ b/third_party/rust/byteorder/CHANGELOG.md @@ -1,3 +1,7 @@ +**WARNING:** This CHANGELOG is no longer updated. The activity for this project +is sparse enough that you should refer to the commit log instead. + + 1.3.4 ===== This patch release squashes deprecation warnings for the `try!` macro, in diff --git a/third_party/rust/byteorder/Cargo.toml b/third_party/rust/byteorder/Cargo.toml index c71f90ba9c..da515d9d90 100644 --- a/third_party/rust/byteorder/Cargo.toml +++ b/third_party/rust/byteorder/Cargo.toml @@ -3,33 +3,44 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" +rust-version = "1.60" name = "byteorder" -version = "1.4.3" +version = "1.5.0" authors = ["Andrew Gallant "] -exclude = ["/ci/*"] description = "Library for reading/writing numbers in big-endian and little-endian." homepage = "https://github.com/BurntSushi/byteorder" documentation = "https://docs.rs/byteorder" readme = "README.md" -keywords = ["byte", "endian", "big-endian", "little-endian", "binary"] -categories = ["encoding", "parsing", "no-std"] +keywords = [ + "byte", + "endian", + "big-endian", + "little-endian", + "binary", +] +categories = [ + "encoding", + "parsing", + "no-std", +] license = "Unlicense OR MIT" repository = "https://github.com/BurntSushi/byteorder" + [profile.bench] opt-level = 3 [lib] name = "byteorder" bench = false + [dev-dependencies.quickcheck] version = "0.9.2" default-features = false diff --git a/third_party/rust/byteorder/README.md b/third_party/rust/byteorder/README.md index d8461c58f7..7c46019e0e 100644 --- a/third_party/rust/byteorder/README.md +++ b/third_party/rust/byteorder/README.md @@ -4,7 +4,7 @@ This crate provides convenience methods for encoding and decoding numbers in either big-endian or little-endian order. [![Build status](https://github.com/BurntSushi/byteorder/workflows/ci/badge.svg)](https://github.com/BurntSushi/byteorder/actions) -[![](https://meritbadge.herokuapp.com/byteorder)](https://crates.io/crates/byteorder) +[![crates.io](https://img.shields.io/crates/v/byteorder.svg)](https://crates.io/crates/byteorder) Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/). @@ -56,6 +56,20 @@ byteorder = { version = "1", default-features = false } ``` +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.60.0`. + +The current policy is that the minimum Rust version required to use this crate +can be increased in minor version updates. For example, if `crate 1.0` requires +Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust +1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum +version of Rust. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. + + ### Alternatives Note that as of Rust 1.32, the standard numeric types provide built-in methods diff --git a/third_party/rust/byteorder/benches/bench.rs b/third_party/rust/byteorder/benches/bench.rs index bb00422f79..963251ce56 100644 --- a/third_party/rust/byteorder/benches/bench.rs +++ b/third_party/rust/byteorder/benches/bench.rs @@ -321,4 +321,6 @@ macro_rules! bench_slice { }; } +bench_slice!(slice_u16, u16, read_u16_into, write_u16_into); bench_slice!(slice_u64, u64, read_u64_into, write_u64_into); +bench_slice!(slice_i64, i64, read_i64_into, write_i64_into); diff --git a/third_party/rust/byteorder/src/lib.rs b/third_party/rust/byteorder/src/lib.rs index cc37cca6ae..cfd53c3f95 100644 --- a/third_party/rust/byteorder/src/lib.rs +++ b/third_party/rust/byteorder/src/lib.rs @@ -69,9 +69,13 @@ cases. #![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +// When testing under miri, we disable tests that take too long. But this +// provokes lots of dead code warnings. So we just squash them. +#![cfg_attr(miri, allow(dead_code, unused_macros))] use core::{ - convert::TryInto, fmt::Debug, hash::Hash, ptr::copy_nonoverlapping, slice, + convert::TryInto, fmt::Debug, hash::Hash, mem::align_of, + ptr::copy_nonoverlapping, slice, }; #[cfg(feature = "std")] @@ -1202,6 +1206,7 @@ pub trait ByteOrder: #[inline] fn read_f32_into(src: &[u8], dst: &mut [f32]) { let dst = unsafe { + const _: () = assert!(align_of::() <= align_of::()); slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u32, dst.len()) }; Self::read_u32_into(src, dst); @@ -1263,6 +1268,7 @@ pub trait ByteOrder: #[inline] fn read_f64_into(src: &[u8], dst: &mut [f64]) { let dst = unsafe { + const _: () = assert!(align_of::() <= align_of::()); slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u64, dst.len()) }; Self::read_u64_into(src, dst); @@ -1895,74 +1901,36 @@ pub type NativeEndian = LittleEndian; #[cfg(target_endian = "big")] pub type NativeEndian = BigEndian; -/// Copies $size bytes from a number $n to a &mut [u8] $dst. $ty represents the -/// numeric type of $n and $which must be either to_be or to_le, depending on -/// which endianness one wants to use when writing to $dst. +/// Copies a &[u8] $src into a &mut [$ty] $dst for the endianness given by +/// $from_bytes (must be either from_be_bytes or from_le_bytes). /// -/// This macro is only safe to call when $ty is a numeric type and $size == -/// size_of::<$ty>() and where $dst is a &mut [u8]. -macro_rules! unsafe_write_num_bytes { - ($ty:ty, $size:expr, $n:expr, $dst:expr, $which:ident) => {{ - assert!($size <= $dst.len()); - unsafe { - // N.B. https://github.com/rust-lang/rust/issues/22776 - let bytes = *(&$n.$which() as *const _ as *const [u8; $size]); - copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size); +/// Panics if $src.len() != $dst.len() * size_of::<$ty>(). +macro_rules! read_slice { + ($src:expr, $dst:expr, $ty:ty, $from_bytes:ident) => {{ + const SIZE: usize = core::mem::size_of::<$ty>(); + // Check types: + let src: &[u8] = $src; + let dst: &mut [$ty] = $dst; + assert_eq!(src.len(), dst.len() * SIZE); + for (src, dst) in src.chunks_exact(SIZE).zip(dst.iter_mut()) { + *dst = <$ty>::$from_bytes(src.try_into().unwrap()); } }}; } -/// Copies a &[u8] $src into a &mut [] $dst for the endianness given -/// by $which (must be either to_be or to_le). +/// Copies a &[$ty] $src into a &mut [u8] $dst for the endianness given by +/// $from_bytes (must be either from_be_bytes or from_le_bytes). /// -/// This macro is only safe to call when $src and $dst are &[u8] and &mut [u8], -/// respectively. The macro will panic if $src.len() != $size * $dst.len(), -/// where $size represents the size of the integers encoded in $src. -macro_rules! unsafe_read_slice { - ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ - assert_eq!($src.len(), $size * $dst.len()); - - unsafe { - copy_nonoverlapping( - $src.as_ptr(), - $dst.as_mut_ptr() as *mut u8, - $src.len(), - ); - } - for v in $dst.iter_mut() { - *v = v.$which(); - } - }}; -} - -/// Copies a &[$ty] $src into a &mut [u8] $dst, where $ty must be a numeric -/// type. This panics if size_of::<$ty>() * $src.len() != $dst.len(). -/// -/// This macro is only safe to call when $src is a slice of numeric types and -/// $dst is a &mut [u8] and where $ty represents the type of the integers in -/// $src. -macro_rules! unsafe_write_slice_native { - ($src:expr, $dst:expr, $ty:ty) => {{ - let size = core::mem::size_of::<$ty>(); - assert_eq!(size * $src.len(), $dst.len()); - - unsafe { - copy_nonoverlapping( - $src.as_ptr() as *const u8, - $dst.as_mut_ptr(), - $dst.len(), - ); - } - }}; -} - +/// Panics if $src.len() * size_of::<$ty>() != $dst.len(). macro_rules! write_slice { - ($src:expr, $dst:expr, $ty:ty, $size:expr, $write:expr) => {{ - assert!($size == ::core::mem::size_of::<$ty>()); - assert_eq!($size * $src.len(), $dst.len()); - - for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { - $write(chunk, n); + ($src:expr, $dst:expr, $ty:ty, $to_bytes:ident) => {{ + const SIZE: usize = core::mem::size_of::<$ty>(); + // Check types: + let src: &[$ty] = $src; + let dst: &mut [u8] = $dst; + assert_eq!(src.len() * SIZE, dst.len()); + for (src, dst) in src.iter().zip(dst.chunks_exact_mut(SIZE)) { + dst.copy_from_slice(&src.$to_bytes()); } }}; } @@ -1990,52 +1958,40 @@ impl ByteOrder for BigEndian { #[inline] fn read_uint(buf: &[u8], nbytes: usize) -> u64 { - assert!(1 <= nbytes && nbytes <= 8 && nbytes <= buf.len()); - let mut out = 0u64; - let ptr_out = &mut out as *mut u64 as *mut u8; - unsafe { - copy_nonoverlapping( - buf.as_ptr(), - ptr_out.offset((8 - nbytes) as isize), - nbytes, - ); - } - out.to_be() + let mut out = [0; 8]; + assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len()); + let start = out.len() - nbytes; + out[start..].copy_from_slice(&buf[..nbytes]); + u64::from_be_bytes(out) } #[inline] fn read_uint128(buf: &[u8], nbytes: usize) -> u128 { - assert!(1 <= nbytes && nbytes <= 16 && nbytes <= buf.len()); - let mut out: u128 = 0; - let ptr_out = &mut out as *mut u128 as *mut u8; - unsafe { - copy_nonoverlapping( - buf.as_ptr(), - ptr_out.offset((16 - nbytes) as isize), - nbytes, - ); - } - out.to_be() + let mut out = [0; 16]; + assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len()); + let start = out.len() - nbytes; + out[start..].copy_from_slice(&buf[..nbytes]); + u128::from_be_bytes(out) } #[inline] fn write_u16(buf: &mut [u8], n: u16) { - unsafe_write_num_bytes!(u16, 2, n, buf, to_be); + buf[..2].copy_from_slice(&n.to_be_bytes()); } #[inline] fn write_u32(buf: &mut [u8], n: u32) { - unsafe_write_num_bytes!(u32, 4, n, buf, to_be); + buf[..4].copy_from_slice(&n.to_be_bytes()); } #[inline] fn write_u64(buf: &mut [u8], n: u64) { - unsafe_write_num_bytes!(u64, 8, n, buf, to_be); + buf[..8].copy_from_slice(&n.to_be_bytes()); } #[inline] fn write_u128(buf: &mut [u8], n: u128) { - unsafe_write_num_bytes!(u128, 16, n, buf, to_be); + buf[..16].copy_from_slice(&n.to_be_bytes()); } #[inline] @@ -2068,58 +2024,42 @@ impl ByteOrder for BigEndian { #[inline] fn read_u16_into(src: &[u8], dst: &mut [u16]) { - unsafe_read_slice!(src, dst, 2, to_be); + read_slice!(src, dst, u16, from_be_bytes); } #[inline] fn read_u32_into(src: &[u8], dst: &mut [u32]) { - unsafe_read_slice!(src, dst, 4, to_be); + read_slice!(src, dst, u32, from_be_bytes); } #[inline] fn read_u64_into(src: &[u8], dst: &mut [u64]) { - unsafe_read_slice!(src, dst, 8, to_be); + read_slice!(src, dst, u64, from_be_bytes); } #[inline] fn read_u128_into(src: &[u8], dst: &mut [u128]) { - unsafe_read_slice!(src, dst, 16, to_be); + read_slice!(src, dst, u128, from_be_bytes); } #[inline] fn write_u16_into(src: &[u16], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u16); - } else { - write_slice!(src, dst, u16, 2, Self::write_u16); - } + write_slice!(src, dst, u16, to_be_bytes); } #[inline] fn write_u32_into(src: &[u32], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u32); - } else { - write_slice!(src, dst, u32, 4, Self::write_u32); - } + write_slice!(src, dst, u32, to_be_bytes); } #[inline] fn write_u64_into(src: &[u64], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u64); - } else { - write_slice!(src, dst, u64, 8, Self::write_u64); - } + write_slice!(src, dst, u64, to_be_bytes); } #[inline] fn write_u128_into(src: &[u128], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u128); - } else { - write_slice!(src, dst, u128, 16, Self::write_u128); - } + write_slice!(src, dst, u128, to_be_bytes); } #[inline] @@ -2206,44 +2146,38 @@ impl ByteOrder for LittleEndian { #[inline] fn read_uint(buf: &[u8], nbytes: usize) -> u64 { - assert!(1 <= nbytes && nbytes <= 8 && nbytes <= buf.len()); - let mut out = 0u64; - let ptr_out = &mut out as *mut u64 as *mut u8; - unsafe { - copy_nonoverlapping(buf.as_ptr(), ptr_out, nbytes); - } - out.to_le() + let mut out = [0; 8]; + assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len()); + out[..nbytes].copy_from_slice(&buf[..nbytes]); + u64::from_le_bytes(out) } #[inline] fn read_uint128(buf: &[u8], nbytes: usize) -> u128 { - assert!(1 <= nbytes && nbytes <= 16 && nbytes <= buf.len()); - let mut out: u128 = 0; - let ptr_out = &mut out as *mut u128 as *mut u8; - unsafe { - copy_nonoverlapping(buf.as_ptr(), ptr_out, nbytes); - } - out.to_le() + let mut out = [0; 16]; + assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len()); + out[..nbytes].copy_from_slice(&buf[..nbytes]); + u128::from_le_bytes(out) } #[inline] fn write_u16(buf: &mut [u8], n: u16) { - unsafe_write_num_bytes!(u16, 2, n, buf, to_le); + buf[..2].copy_from_slice(&n.to_le_bytes()); } #[inline] fn write_u32(buf: &mut [u8], n: u32) { - unsafe_write_num_bytes!(u32, 4, n, buf, to_le); + buf[..4].copy_from_slice(&n.to_le_bytes()); } #[inline] fn write_u64(buf: &mut [u8], n: u64) { - unsafe_write_num_bytes!(u64, 8, n, buf, to_le); + buf[..8].copy_from_slice(&n.to_le_bytes()); } #[inline] fn write_u128(buf: &mut [u8], n: u128) { - unsafe_write_num_bytes!(u128, 16, n, buf, to_le); + buf[..16].copy_from_slice(&n.to_le_bytes()); } #[inline] @@ -2268,58 +2202,42 @@ impl ByteOrder for LittleEndian { #[inline] fn read_u16_into(src: &[u8], dst: &mut [u16]) { - unsafe_read_slice!(src, dst, 2, to_le); + read_slice!(src, dst, u16, from_le_bytes); } #[inline] fn read_u32_into(src: &[u8], dst: &mut [u32]) { - unsafe_read_slice!(src, dst, 4, to_le); + read_slice!(src, dst, u32, from_le_bytes); } #[inline] fn read_u64_into(src: &[u8], dst: &mut [u64]) { - unsafe_read_slice!(src, dst, 8, to_le); + read_slice!(src, dst, u64, from_le_bytes); } #[inline] fn read_u128_into(src: &[u8], dst: &mut [u128]) { - unsafe_read_slice!(src, dst, 16, to_le); + read_slice!(src, dst, u128, from_le_bytes); } #[inline] fn write_u16_into(src: &[u16], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u16); - } else { - write_slice!(src, dst, u16, 2, Self::write_u16); - } + write_slice!(src, dst, u16, to_le_bytes); } #[inline] fn write_u32_into(src: &[u32], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u32); - } else { - write_slice!(src, dst, u32, 4, Self::write_u32); - } + write_slice!(src, dst, u32, to_le_bytes); } #[inline] fn write_u64_into(src: &[u64], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u64); - } else { - write_slice!(src, dst, u64, 8, Self::write_u64); - } + write_slice!(src, dst, u64, to_le_bytes); } #[inline] fn write_u128_into(src: &[u128], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u128); - } else { - write_slice!(src, dst, u128, 16, Self::write_u128); - } + write_slice!(src, dst, u128, to_le_bytes); } #[inline] @@ -2449,6 +2367,7 @@ mod test { macro_rules! qc_byte_order { ($name:ident, $ty_int:ty, $max:expr, $bytes:expr, $read:ident, $write:ident) => { + #[cfg(not(miri))] mod $name { #[allow(unused_imports)] use super::{qc_sized, Wi128}; @@ -2489,6 +2408,7 @@ mod test { }; ($name:ident, $ty_int:ty, $max:expr, $read:ident, $write:ident) => { + #[cfg(not(miri))] mod $name { #[allow(unused_imports)] use super::{qc_sized, Wi128}; @@ -3405,6 +3325,7 @@ mod stdtests { macro_rules! qc_bytes_ext { ($name:ident, $ty_int:ty, $max:expr, $bytes:expr, $read:ident, $write:ident) => { + #[cfg(not(miri))] mod $name { #[allow(unused_imports)] use crate::test::{qc_sized, Wi128}; @@ -3455,6 +3376,7 @@ mod stdtests { } }; ($name:ident, $ty_int:ty, $max:expr, $read:ident, $write:ident) => { + #[cfg(not(miri))] mod $name { #[allow(unused_imports)] use crate::test::{qc_sized, Wi128}; @@ -3951,6 +3873,7 @@ mod stdtests { // Test slice serialization/deserialization. macro_rules! qc_slice { ($name:ident, $ty_int:ty, $read:ident, $write:ident, $zero:expr) => { + #[cfg(not(miri))] mod $name { use super::qc_unsized; #[allow(unused_imports)] diff --git a/third_party/rust/core-foundation-sys/.cargo-checksum.json b/third_party/rust/core-foundation-sys/.cargo-checksum.json index 0bdf990864..7dd167643b 100644 --- a/third_party/rust/core-foundation-sys/.cargo-checksum.json +++ b/third_party/rust/core-foundation-sys/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ddcd13ba60bd9368949654be284efac4a55e482b7233e42c9d2fef97ff825eb8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","build.rs":"9433ed3b20cc99e716dda4c6d8507c29bc04882544cbbea8d4e48ba80fd0fa12","src/array.rs":"40c305658e16b07d86353a5ad34e7b5fb98720f19cc2b5173360d6a61ce2642f","src/attributed_string.rs":"48c2d161d6f54136ae895a9f52efad1f831718ea331b875d25498039158a2d51","src/base.rs":"7b21281e9a01903c79a7891ee4e1865a11504b281b468815d1a3838e1744a3c2","src/bundle.rs":"2a3413e649e1cf5eb1557fa5e3e6d442389caa2978a4a0c2c7afdfa4c388c0bf","src/characterset.rs":"a10bbb42ddc74b3dc50b43ae6a50cc9d9a1cd08b975a1ce1b092be4bf64448a6","src/data.rs":"2b121f102b4c2778475f4902016820c4a70e2f8ac532af53913561d42757fa2e","src/date.rs":"c064ee4c3ebd1927532c34871e2e41179d6e3c3e400f6b409a18ad9e2337477f","src/dictionary.rs":"3327a6f90f1e0db5e3fde1973e2df4143ca896716a816d03f2b17c8e988c5159","src/error.rs":"6205ebeb7631daa8bcd560862b6daa10f640c8c117ce5f6f7184f268dcbcb42a","src/filedescriptor.rs":"49580654b657811fade7adaa256f5f895cb011c9baa4731e2f44a6ec7fdba235","src/lib.rs":"e0b6b9d16f6cae1328de772e056e90003b0a5aa5859f5cde58f6aac4683bb543","src/mach_port.rs":"bd413d44772eaeb24e74e1b7b4f234b159b916caa0896c8e82fe54ce1b9deeb6","src/messageport.rs":"e9227d5907cba8e29cdeea41bcb3ae5c7840220442953ab19aace31a84542f47","src/number.rs":"f28040accfbbec99c4e55f411facac7cde4ad89298af2d7d907312f18e4263bf","src/propertylist.rs":"7ec928438826c4ce40befedf3de0a37c8ecbc0fc17896dfa629d5864000b2cfe","src/runloop.rs":"26ca33e2472d191f583e01c24e8cd262f54de8b542fbe7278f33ab08b2925794","src/set.rs":"116c2f18008bfbeecac570d366dbd95b8fe5b9373e3e1bdd2c1d588314d776c5","src/string.rs":"b2856d0bf7a8583370d18d3f041ac5eb00fd6a1aabc69503e7c11a93d42036d8","src/timezone.rs":"c7dd9557646b7ff2bfd6a98bf92142b8304125b4e78dd651b687abc8da191159","src/url.rs":"4358f756ed3d5e9afd5a7f3e2e9115adc6133b47dc7ce59d6ebb32c6610b0e8f","src/uuid.rs":"82f75efa73d0842dff2e13d299c166c6593a77fcb69c4b7629a2df1c17ae507d"},"package":"5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"} \ No newline at end of file +{"files":{"Cargo.toml":"f8b5e9fa6c6bbfad4e3c0acfbad03f05cbd98073e664e3ad2fe16a56dd492aa1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","src/array.rs":"4d469ca3f6aceb42dfaf7b26aa9ef14a8ebce05e02d0beda985fa32f2ec48963","src/attributed_string.rs":"7042f3fbf6904efecb15f01ce2e96eecf84973e0fef9be4c10d14944b0f90a24","src/bag.rs":"dec9ff467ac713526c3be8148ae41b21ab8840f393733bb53c77224ef089787c","src/base.rs":"5d0dee358519712e881e2edbea0ca6d3539958ed1ff3d70aa136af7e25292f22","src/binary_heap.rs":"0565125dbdb1fa578888e00f5b195ab91f0bf65881eabcd39de99ca811d756de","src/bit_vector.rs":"dcdaa573d90b25bdc6b98f2330110e8591b7c329601643dcc6aa23b1b9ec7210","src/bundle.rs":"83ac9d7c45f06161767588c465eed086a773714734da0614d98d000326df3603","src/calendar.rs":"b73796956e50d92f0479479e84246712804537d694e4cdd01d5440e5fbcbd333","src/characterset.rs":"ba60f78884cd860e151df35c1953bcd6eae46d9f27c36584b66e508e2301a7a8","src/data.rs":"fe4e2effbfd9348575507d06aa53cd583808c908f9e03ac1a076b077230c9c01","src/date.rs":"971d681f6eeefa3764d8a43e53cbf7c937c419331207c7bb003a25c9b0b0722f","src/date_formatter.rs":"05e84ac3cf4c0daae2e939a9bedddfd10dd5309ea1536bf8241de41971d11f8a","src/dictionary.rs":"ac23d99208131049c82c13b37a99b4fd129224d1dafcd65ff2f9de200d73e9d1","src/error.rs":"b523faa8c498e1115c72e71a10e7a3bf8bcc01588cb02e70dc9fd45cbdaa35f6","src/file_security.rs":"542c5d8eef22424479abcb448601611d85c9cc96e41cd6cd6de5ea3efe1213a6","src/filedescriptor.rs":"706eebde408713cc49bbab078e86fe51e95fe29b167420bbcbb573847dcf29e2","src/lib.rs":"8ae5082d92ebf6b1a53332211b87986aa7228534f5e341b62100e522b7fcadec","src/locale.rs":"372190a9cb5659fba0b92598c5dcbdaa3f90b29b3440ddcfe77931e85c1f96d9","src/mach_port.rs":"e52c2ce794e82ebeeb0cba170902409f18626b7d9e29d6dcd333e9c13411408a","src/messageport.rs":"d8e342f0eabe47f6f4746fdbf996bf9008b4b5f1fa24e0bc4ecd73b2de81b234","src/notification_center.rs":"0ab30523bc4ac799016970c9c59594cbb3afeda054705c15d0979eb07abb7c7d","src/number.rs":"28b10c9d2361cac18549ef66839f595e98490096e756e9a7f25536b6ceb1f687","src/number_formatter.rs":"024fbd3b2ecaecf19cfdb463e0f0096d1fa28bc4ce636659e53459d1b01af658","src/plugin.rs":"0904b1b4b882e626d5d63ac91c540dfdf65f5f4428cf38c9def6acfc7ed84cd3","src/preferences.rs":"49d8ac0c669a01678fa0dc26d6cb13bc72004c8422e525bf3e26f01feb5a3693","src/propertylist.rs":"f7f12cb8c67098e5b96cb8a63b4a947549a2cbf7a6523ce314141b4f8cc202c4","src/runloop.rs":"8fa6e5e74a013f8101d5a4f6616818573adc7ed197e28b799dca4c3a1cedaac9","src/set.rs":"0e619ec75a6b975be6b6d59ed3b01c803dd635020288b178db949b1c45442d17","src/socket.rs":"b67737b8c04142fa4d198c19f0867fd653837e529bf2665e78750c94f469a793","src/stream.rs":"f9b1099191010a96ce0aadcc22385732710dfc1521873096a9db67ad80472e36","src/string.rs":"fa46e7b7865709494bb05c9c7c6006f165fafa956ab41f053af0e4b41904efa4","src/string_tokenizer.rs":"0da4ae1a841591871602f21cc1c9b51289a0514a255b269e4b61afdeb0097c10","src/timezone.rs":"f584ea76627f12f33eba25d7ea054c2d2c10a2d96474fce12858ccb4bdf688c1","src/tree.rs":"50d513ea1801797c549218c51f5ebf77be4cf80901b12ce3ba0a223c602995d4","src/url.rs":"cb08b0bd24708e6572711f4f82b88370e811aabf4f58f22c34f0f873a44c7486","src/url_enumerator.rs":"bd531f31f6c62b2849d5ccbc82bfc3ae3866c4cdd6768b6c2fe380f24c290540","src/user_notification.rs":"e86b052817028847e62121752e7d58f8ed6f8ad15f5ef947c1fa93bbd0fcbf26","src/uuid.rs":"48af493dc6c8b00d804d6ae92a2fd71eabdae8a2be0500baaa55ce56345c350a","src/xml_node.rs":"c7894a4d08f695ba75d539b3c8d6cc3a90544000786fe3f9cd9c02ad7541213b","src/xml_parser.rs":"ac8a3d2c71ec8ec80603ce5ef214147c0e93bed211c1559a47f14fc31cb0bbaf"},"package":"06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"} \ No newline at end of file diff --git a/third_party/rust/core-foundation-sys/Cargo.toml b/third_party/rust/core-foundation-sys/Cargo.toml index bd17103b56..345cbab915 100644 --- a/third_party/rust/core-foundation-sys/Cargo.toml +++ b/third_party/rust/core-foundation-sys/Cargo.toml @@ -3,27 +3,30 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] +edition = "2018" name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.6" authors = ["The Servo Project Developers"] -build = "build.rs" description = "Bindings to Core Foundation for macOS" homepage = "https://github.com/servo/core-foundation-rs" -license = "MIT / Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/servo/core-foundation-rs" + [package.metadata.docs.rs] +all-features = true default-target = "x86_64-apple-darwin" [dependencies] [features] +default = ["link"] +link = [] mac_os_10_7_support = [] mac_os_10_8_features = [] diff --git a/third_party/rust/core-foundation-sys/build.rs b/third_party/rust/core-foundation-sys/build.rs deleted file mode 100644 index 1f03b0602e..0000000000 --- a/third_party/rust/core-foundation-sys/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - if std::env::var("TARGET").unwrap().contains("-apple") { - println!("cargo:rustc-link-lib=framework=CoreFoundation"); - } -} diff --git a/third_party/rust/core-foundation-sys/src/array.rs b/third_party/rust/core-foundation-sys/src/array.rs index 5090302fc2..1e521b3e48 100644 --- a/third_party/rust/core-foundation-sys/src/array.rs +++ b/third_party/rust/core-foundation-sys/src/array.rs @@ -9,16 +9,19 @@ use std::os::raw::c_void; -use base::{CFRange, CFIndex, CFAllocatorRef, CFTypeID, Boolean}; -use string::CFStringRef; +use crate::base::{Boolean, CFAllocatorRef, CFComparatorFunction, CFIndex, CFRange, CFTypeID}; +use crate::string::CFStringRef; -pub type CFArrayRetainCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; +pub type CFArrayRetainCallBack = + extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; pub type CFArrayReleaseCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void); pub type CFArrayCopyDescriptionCallBack = extern "C" fn(value: *const c_void) -> CFStringRef; -pub type CFArrayEqualCallBack = extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; +pub type CFArrayEqualCallBack = + extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; +pub type CFArrayApplierFunction = extern "C" fn(value: *const c_void, context: *mut c_void); #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct CFArrayCallBacks { pub version: CFIndex, pub retain: CFArrayRetainCallBack, @@ -31,25 +34,109 @@ pub struct CFArrayCallBacks { pub struct __CFArray(c_void); pub type CFArrayRef = *const __CFArray; +pub type CFMutableArrayRef = *mut __CFArray; -extern { +extern "C" { /* * CFArray.h */ + pub static kCFTypeArrayCallBacks: CFArrayCallBacks; - pub fn CFArrayCreate(allocator: CFAllocatorRef, values: *const *const c_void, - numValues: CFIndex, callBacks: *const CFArrayCallBacks) -> CFArrayRef; - pub fn CFArrayCreateCopy(allocator: CFAllocatorRef , theArray: CFArrayRef) -> CFArrayRef; - - // CFArrayBSearchValues - // CFArrayContainsValue + /* CFArray */ + /* Creating an Array */ + pub fn CFArrayCreate( + allocator: CFAllocatorRef, + values: *const *const c_void, + numValues: CFIndex, + callBacks: *const CFArrayCallBacks, + ) -> CFArrayRef; + pub fn CFArrayCreateCopy(allocator: CFAllocatorRef, theArray: CFArrayRef) -> CFArrayRef; + + /* Examining an Array */ + pub fn CFArrayBSearchValues( + theArray: CFArrayRef, + range: CFRange, + value: *const c_void, + comparator: CFComparatorFunction, + context: *mut c_void, + ) -> CFIndex; + pub fn CFArrayContainsValue( + theArray: CFArrayRef, + range: CFRange, + value: *const c_void, + ) -> Boolean; pub fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex; - // CFArrayGetCountOfValue - // CFArrayGetFirstIndexOfValue - // CFArrayGetLastIndexOfValue + pub fn CFArrayGetCountOfValue( + theArray: CFArrayRef, + range: CFRange, + value: *const c_void, + ) -> CFIndex; + pub fn CFArrayGetFirstIndexOfValue( + theArray: CFArrayRef, + range: CFRange, + value: *const c_void, + ) -> CFIndex; + pub fn CFArrayGetLastIndexOfValue( + theArray: CFArrayRef, + range: CFRange, + value: *const c_void, + ) -> CFIndex; pub fn CFArrayGetValues(theArray: CFArrayRef, range: CFRange, values: *mut *const c_void); pub fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *const c_void; - // CFArrayApplyFunction + + /* Applying a Function to Elements */ + pub fn CFArrayApplyFunction( + theArray: CFArrayRef, + range: CFRange, + applier: CFArrayApplierFunction, + context: *mut c_void, + ); + + /* Getting the CFArray Type ID */ pub fn CFArrayGetTypeID() -> CFTypeID; + + /* CFMutableArray */ + /* CFMutableArray Miscellaneous Functions */ + pub fn CFArrayAppendArray( + theArray: CFMutableArrayRef, + otherArray: CFArrayRef, + otherRange: CFRange, + ); + pub fn CFArrayAppendValue(theArray: CFMutableArrayRef, value: *const c_void); + pub fn CFArrayCreateMutable( + allocator: CFAllocatorRef, + capacity: CFIndex, + callBacks: *const CFArrayCallBacks, + ) -> CFMutableArrayRef; + pub fn CFArrayCreateMutableCopy( + allocator: CFAllocatorRef, + capacity: CFIndex, + theArray: CFArrayRef, + ) -> CFMutableArrayRef; + pub fn CFArrayExchangeValuesAtIndices( + theArray: CFMutableArrayRef, + idx1: CFIndex, + idx2: CFIndex, + ); + pub fn CFArrayInsertValueAtIndex( + theArray: CFMutableArrayRef, + idx: CFIndex, + value: *const c_void, + ); + pub fn CFArrayRemoveAllValues(theArray: CFMutableArrayRef); + pub fn CFArrayRemoveValueAtIndex(theArray: CFMutableArrayRef, idx: CFIndex); + pub fn CFArrayReplaceValues( + theArray: CFMutableArrayRef, + range: CFRange, + newValues: *mut *const c_void, + newCount: CFIndex, + ); + pub fn CFArraySetValueAtIndex(theArray: CFMutableArrayRef, idx: CFIndex, value: *const c_void); + pub fn CFArraySortValues( + theArray: CFMutableArrayRef, + range: CFRange, + comparator: CFComparatorFunction, + context: *mut c_void, + ); } diff --git a/third_party/rust/core-foundation-sys/src/attributed_string.rs b/third_party/rust/core-foundation-sys/src/attributed_string.rs index c91bf5be38..54c27ec416 100644 --- a/third_party/rust/core-foundation-sys/src/attributed_string.rs +++ b/third_party/rust/core-foundation-sys/src/attributed_string.rs @@ -7,49 +7,114 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFRange, CFTypeID, CFTypeRef}; +use crate::dictionary::CFDictionaryRef; +use crate::string::CFMutableStringRef; +use crate::string::CFStringRef; use std::os::raw::c_void; -use base::{CFAllocatorRef, CFTypeRef, CFIndex, CFRange, CFTypeID}; -use string::CFStringRef; -use dictionary::CFDictionaryRef; #[repr(C)] pub struct __CFAttributedString(c_void); pub type CFAttributedStringRef = *const __CFAttributedString; -pub type CFMutableAttributedStringRef = *const __CFAttributedString; +pub type CFMutableAttributedStringRef = *mut __CFAttributedString; -extern { - /* CFAttributedString */ +extern "C" { + /* + * CFAttributedString.h + */ + /* CFAttributedString */ + /* Creating a CFAttributedString */ pub fn CFAttributedStringCreate( allocator: CFAllocatorRef, str: CFStringRef, attributes: CFDictionaryRef, ) -> CFAttributedStringRef; - + pub fn CFAttributedStringCreateCopy( + alloc: CFAllocatorRef, + aStr: CFAttributedStringRef, + ) -> CFAttributedStringRef; + pub fn CFAttributedStringCreateWithSubstring( + alloc: CFAllocatorRef, + aStr: CFAttributedStringRef, + range: CFRange, + ) -> CFAttributedStringRef; pub fn CFAttributedStringGetLength(astr: CFAttributedStringRef) -> CFIndex; + pub fn CFAttributedStringGetString(aStr: CFAttributedStringRef) -> CFStringRef; + + /* Accessing Attributes */ + pub fn CFAttributedStringGetAttribute( + aStr: CFAttributedStringRef, + loc: CFIndex, + attrName: CFStringRef, + effectiveRange: *mut CFRange, + ) -> CFTypeRef; + pub fn CFAttributedStringGetAttributes( + aStr: CFAttributedStringRef, + loc: CFIndex, + effectiveRange: *mut CFRange, + ) -> CFDictionaryRef; + pub fn CFAttributedStringGetAttributeAndLongestEffectiveRange( + aStr: CFAttributedStringRef, + loc: CFIndex, + attrName: CFStringRef, + inRange: CFRange, + longestEffectiveRange: *mut CFRange, + ) -> CFTypeRef; + pub fn CFAttributedStringGetAttributesAndLongestEffectiveRange( + aStr: CFAttributedStringRef, + loc: CFIndex, + inRange: CFRange, + longestEffectiveRange: *mut CFRange, + ) -> CFDictionaryRef; + /* Getting Attributed String Properties */ pub fn CFAttributedStringGetTypeID() -> CFTypeID; /* CFMutableAttributedString */ - - pub fn CFAttributedStringCreateMutableCopy( - allocator: CFAllocatorRef, max_length: CFIndex, astr: CFAttributedStringRef - ) -> CFMutableAttributedStringRef; - + /* Creating a CFMutableAttributedString */ pub fn CFAttributedStringCreateMutable( allocator: CFAllocatorRef, max_length: CFIndex, ) -> CFMutableAttributedStringRef; + pub fn CFAttributedStringCreateMutableCopy( + allocator: CFAllocatorRef, + max_length: CFIndex, + astr: CFAttributedStringRef, + ) -> CFMutableAttributedStringRef; + /* Modifying a CFMutableAttributedString */ + pub fn CFAttributedStringBeginEditing(aStr: CFMutableAttributedStringRef); + pub fn CFAttributedStringEndEditing(aStr: CFMutableAttributedStringRef); + pub fn CFAttributedStringGetMutableString( + aStr: CFMutableAttributedStringRef, + ) -> CFMutableStringRef; + pub fn CFAttributedStringRemoveAttribute( + aStr: CFMutableAttributedStringRef, + range: CFRange, + attrName: CFStringRef, + ); pub fn CFAttributedStringReplaceString( - astr: CFMutableAttributedStringRef, range: CFRange, replacement: CFStringRef); - + aStr: CFMutableAttributedStringRef, + range: CFRange, + replacement: CFStringRef, + ); + pub fn CFAttributedStringReplaceAttributedString( + aStr: CFMutableAttributedStringRef, + range: CFRange, + replacement: CFAttributedStringRef, + ); pub fn CFAttributedStringSetAttribute( - astr: CFMutableAttributedStringRef, + aStr: CFMutableAttributedStringRef, range: CFRange, - attr_name: CFStringRef, + attrName: CFStringRef, value: CFTypeRef, ); - + pub fn CFAttributedStringSetAttributes( + aStr: CFMutableAttributedStringRef, + range: CFRange, + replacement: CFDictionaryRef, + clearOtherAttributes: Boolean, + ); } diff --git a/third_party/rust/core-foundation-sys/src/bag.rs b/third_party/rust/core-foundation-sys/src/bag.rs new file mode 100644 index 0000000000..041caa59c2 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/bag.rs @@ -0,0 +1,101 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{Boolean, CFAllocatorRef, CFHashCode, CFIndex, CFTypeID}; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFBag(c_void); + +pub type CFBagRef = *const __CFBag; +pub type CFMutableBagRef = *mut __CFBag; + +pub type CFBagRetainCallBack = + extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; +pub type CFBagReleaseCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void); +pub type CFBagCopyDescriptionCallBack = extern "C" fn(value: *const c_void) -> CFStringRef; +pub type CFBagEqualCallBack = + extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; +pub type CFBagHashCallBack = extern "C" fn(value: *const c_void) -> CFHashCode; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFBagCallBacks { + pub version: CFIndex, + pub retain: CFBagRetainCallBack, + pub release: CFBagReleaseCallBack, + pub copyDescription: CFBagCopyDescriptionCallBack, + pub equal: CFBagEqualCallBack, + pub hash: CFBagHashCallBack, +} + +pub type CFBagApplierFunction = extern "C" fn(value: *const c_void, context: *mut c_void); + +extern "C" { + /* + * CFBag.h + */ + /* Predefined Callback Structures */ + pub static kCFTypeBagCallBacks: CFBagCallBacks; + pub static kCFCopyStringBagCallBacks: CFBagCallBacks; + + /* CFBag */ + /* Creating a Bag */ + pub fn CFBagCreate( + allocator: CFAllocatorRef, + values: *const *const c_void, + numValues: CFIndex, + callBacks: *const CFBagCallBacks, + ) -> CFBagRef; + pub fn CFBagCreateCopy(allocator: CFAllocatorRef, theBag: CFBagRef) -> CFBagRef; + + /* Examining a Bag */ + pub fn CFBagContainsValue(theBag: CFBagRef, value: *const c_void) -> Boolean; + pub fn CFBagGetCount(theBag: CFBagRef) -> CFIndex; + pub fn CFBagGetCountOfValue(theBag: CFBagRef, value: *const c_void) -> CFIndex; + pub fn CFBagGetValue(theBag: CFBagRef, value: *const c_void) -> *const c_void; + pub fn CFBagGetValueIfPresent( + theBag: CFBagRef, + candidate: *const c_void, + value: *const *const c_void, + ) -> Boolean; + pub fn CFBagGetValues(theBag: CFBagRef, values: *const *const c_void); + + /* Applying a Function to the Contents of a Bag */ + pub fn CFBagApplyFunction( + theBag: CFBagRef, + applier: CFBagApplierFunction, + context: *mut c_void, + ); + + /* Getting the CFBag Type ID */ + pub fn CFBagGetTypeID() -> CFTypeID; + + /* CFMutableBag */ + /* Creating a Mutable Bag */ + pub fn CFBagCreateMutable( + allocator: CFAllocatorRef, + capacity: CFIndex, + callBacks: *const CFBagCallBacks, + ) -> CFMutableBagRef; + pub fn CFBagCreateMutableCopy( + allocator: CFAllocatorRef, + capacity: CFIndex, + theBag: CFBagRef, + ) -> CFMutableBagRef; + + /* Modifying a Mutable Bag */ + pub fn CFBagAddValue(theBag: CFMutableBagRef, value: *const c_void); + pub fn CFBagRemoveAllValues(theBag: CFMutableBagRef); + pub fn CFBagRemoveValue(theBag: CFMutableBagRef, value: *const c_void); + pub fn CFBagReplaceValue(theBag: CFMutableBagRef, value: *const c_void); + pub fn CFBagSetValue(theBag: CFMutableBagRef, value: *const c_void); +} diff --git a/third_party/rust/core-foundation-sys/src/base.rs b/third_party/rust/core-foundation-sys/src/base.rs index 52a166fdf6..78e06a65f5 100644 --- a/third_party/rust/core-foundation-sys/src/base.rs +++ b/third_party/rust/core-foundation-sys/src/base.rs @@ -7,21 +7,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::string::CFStringRef; use std::cmp::Ordering; -use std::os::raw::{c_uint, c_void, c_int}; -use string::CFStringRef; +use std::os::raw::{c_int, c_short, c_uchar, c_uint, c_ushort, c_void}; pub type Boolean = u8; pub type mach_port_t = c_uint; pub type CFAllocatorRef = *const c_void; pub type CFNullRef = *const c_void; pub type CFTypeRef = *const c_void; +pub type ConstStr255Param = *const c_uchar; +pub type StringPtr = *mut c_uchar; +pub type ConstStringPtr = *const c_uchar; pub type OSStatus = i32; +pub type UInt8 = c_uchar; +pub type UInt16 = c_ushort; +pub type SInt16 = c_short; pub type SInt32 = c_int; +pub type UInt32 = c_uint; pub type CFTypeID = usize; pub type CFOptionFlags = usize; pub type CFHashCode = usize; pub type CFIndex = isize; +pub type LangCode = SInt16; +pub type RegionCode = SInt16; +pub type UTF32Char = c_uint; +pub type UTF16Char = c_ushort; +pub type UTF8Char = c_uchar; #[repr(isize)] #[derive(Clone, Copy, Debug, PartialEq)] @@ -31,43 +43,53 @@ pub enum CFComparisonResult { GreaterThan = 1, } -impl Into for CFComparisonResult { - fn into(self) -> Ordering { - match self { +pub type CFComparatorFunction = extern "C" fn( + val1: *const c_void, + val2: *const c_void, + context: *mut c_void, +) -> CFComparisonResult; + +impl From for Ordering { + fn from(val: CFComparisonResult) -> Self { + match val { CFComparisonResult::LessThan => Ordering::Less, CFComparisonResult::EqualTo => Ordering::Equal, - CFComparisonResult::GreaterThan => Ordering::Greater + CFComparisonResult::GreaterThan => Ordering::Greater, } } } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct CFRange { pub location: CFIndex, - pub length: CFIndex + pub length: CFIndex, } // for back-compat impl CFRange { pub fn init(location: CFIndex, length: CFIndex) -> CFRange { - CFRange { - location: location, - length: length, - } + CFRange { location, length } } } pub type CFAllocatorRetainCallBack = extern "C" fn(info: *mut c_void) -> *mut c_void; pub type CFAllocatorReleaseCallBack = extern "C" fn(info: *mut c_void); pub type CFAllocatorCopyDescriptionCallBack = extern "C" fn(info: *mut c_void) -> CFStringRef; -pub type CFAllocatorAllocateCallBack = extern "C" fn(allocSize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; -pub type CFAllocatorReallocateCallBack = extern "C" fn(ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; +pub type CFAllocatorAllocateCallBack = + extern "C" fn(allocSize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; +pub type CFAllocatorReallocateCallBack = extern "C" fn( + ptr: *mut c_void, + newsize: CFIndex, + hint: CFOptionFlags, + info: *mut c_void, +) -> *mut c_void; pub type CFAllocatorDeallocateCallBack = extern "C" fn(ptr: *mut c_void, info: *mut c_void); -pub type CFAllocatorPreferredSizeCallBack = extern "C" fn(size: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> CFIndex; +pub type CFAllocatorPreferredSizeCallBack = + extern "C" fn(size: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> CFIndex; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct CFAllocatorContext { pub version: CFIndex, pub info: *mut c_void, @@ -77,7 +99,7 @@ pub struct CFAllocatorContext { pub allocate: Option, pub reallocate: Option, pub deallocate: Option, - pub preferredSize: Option + pub preferredSize: Option, } /// Trait for all types which are Core Foundation reference types. @@ -110,7 +132,7 @@ impl TCFTypeRef for *mut T { /// Constant used by some functions to indicate failed searches. pub static kCFNotFound: CFIndex = -1; -extern { +extern "C" { /* * CFBase.h */ @@ -124,11 +146,27 @@ extern { pub static kCFAllocatorNull: CFAllocatorRef; pub static kCFAllocatorUseContext: CFAllocatorRef; - pub fn CFAllocatorCreate(allocator: CFAllocatorRef, context: *mut CFAllocatorContext) -> CFAllocatorRef; - pub fn CFAllocatorAllocate(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> *mut c_void; + pub fn CFAllocatorCreate( + allocator: CFAllocatorRef, + context: *mut CFAllocatorContext, + ) -> CFAllocatorRef; + pub fn CFAllocatorAllocate( + allocator: CFAllocatorRef, + size: CFIndex, + hint: CFOptionFlags, + ) -> *mut c_void; pub fn CFAllocatorDeallocate(allocator: CFAllocatorRef, ptr: *mut c_void); - pub fn CFAllocatorGetPreferredSizeForSize(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> CFIndex; - pub fn CFAllocatorReallocate(allocator: CFAllocatorRef, ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags) -> *mut c_void; + pub fn CFAllocatorGetPreferredSizeForSize( + allocator: CFAllocatorRef, + size: CFIndex, + hint: CFOptionFlags, + ) -> CFIndex; + pub fn CFAllocatorReallocate( + allocator: CFAllocatorRef, + ptr: *mut c_void, + newsize: CFIndex, + hint: CFOptionFlags, + ) -> *mut c_void; pub fn CFAllocatorGetDefault() -> CFAllocatorRef; pub fn CFAllocatorSetDefault(allocator: CFAllocatorRef); pub fn CFAllocatorGetContext(allocator: CFAllocatorRef, context: *mut CFAllocatorContext); @@ -138,10 +176,12 @@ extern { pub static kCFNull: CFNullRef; + pub fn CFNullGetTypeID() -> CFTypeID; + /* CFType Reference */ - //fn CFCopyTypeIDDescription - //fn CFGetAllocator + pub fn CFCopyTypeIDDescription(type_id: CFTypeID) -> CFStringRef; + pub fn CFGetAllocator(cf: CFTypeRef) -> CFAllocatorRef; pub fn CFCopyDescription(cf: CFTypeRef) -> CFStringRef; pub fn CFEqual(cf1: CFTypeRef, cf2: CFTypeRef) -> Boolean; pub fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex; diff --git a/third_party/rust/core-foundation-sys/src/binary_heap.rs b/third_party/rust/core-foundation-sys/src/binary_heap.rs new file mode 100644 index 0000000000..8bcaa8e26e --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/binary_heap.rs @@ -0,0 +1,83 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{Boolean, CFAllocatorRef, CFComparisonResult, CFIndex, CFTypeID}; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFBinaryHeap(c_void); + +pub type CFBinaryHeapRef = *mut __CFBinaryHeap; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFBinaryHeapCompareContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn(info: *const c_void) -> *const c_void, + pub release: extern "C" fn(info: *const c_void), + pub copyDescription: extern "C" fn(info: *const c_void) -> CFStringRef, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFBinaryHeapCallBacks { + pub version: CFIndex, + pub retain: extern "C" fn(allocator: CFAllocatorRef, ptr: *const c_void) -> *const c_void, + pub release: extern "C" fn(allocator: CFAllocatorRef, ptr: *const c_void), + pub copyDescription: extern "C" fn(ptr: *const c_void) -> CFStringRef, + pub compare: extern "C" fn( + ptr1: *const c_void, + ptr2: *const c_void, + context: *mut c_void, + ) -> CFComparisonResult, +} + +pub type CFBinaryHeapApplierFunction = extern "C" fn(val: *const c_void, context: *const c_void); + +extern "C" { + /* + * CFBinaryHeap.h + */ + /* Predefined Callback Structures */ + pub static kCFStringBinaryHeapCallBacks: CFBinaryHeapCallBacks; + + /* CFBinaryHeap Miscellaneous Functions */ + pub fn CFBinaryHeapAddValue(heap: CFBinaryHeapRef, value: *const c_void); + pub fn CFBinaryHeapApplyFunction( + heap: CFBinaryHeapRef, + applier: CFBinaryHeapApplierFunction, + context: *mut c_void, + ); + pub fn CFBinaryHeapContainsValue(heap: CFBinaryHeapRef, value: *const c_void) -> Boolean; + pub fn CFBinaryHeapCreate( + allocator: CFAllocatorRef, + capacity: CFIndex, + callBacks: *const CFBinaryHeapCallBacks, + compareContext: *const CFBinaryHeapCompareContext, + ) -> CFBinaryHeapRef; + pub fn CFBinaryHeapCreateCopy( + allocator: CFAllocatorRef, + capacity: CFIndex, + heap: CFBinaryHeapRef, + ) -> CFBinaryHeapRef; + pub fn CFBinaryHeapGetCount(heap: CFBinaryHeapRef) -> CFIndex; + pub fn CFBinaryHeapGetCountOfValue(heap: CFBinaryHeapRef, value: *const c_void) -> CFIndex; + pub fn CFBinaryHeapGetMinimum(heap: CFBinaryHeapRef) -> *const c_void; + pub fn CFBinaryHeapGetMinimumIfPresent( + heap: CFBinaryHeapRef, + value: *const *const c_void, + ) -> Boolean; + pub fn CFBinaryHeapGetTypeID() -> CFTypeID; + pub fn CFBinaryHeapGetValues(heap: CFBinaryHeapRef, values: *const *const c_void); + pub fn CFBinaryHeapRemoveAllValues(heap: CFBinaryHeapRef); + pub fn CFBinaryHeapRemoveMinimumValue(heap: CFBinaryHeapRef); +} diff --git a/third_party/rust/core-foundation-sys/src/bit_vector.rs b/third_party/rust/core-foundation-sys/src/bit_vector.rs new file mode 100644 index 0000000000..f270c3d1d3 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/bit_vector.rs @@ -0,0 +1,74 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFRange, CFTypeID, UInt32, UInt8}; + +#[repr(C)] +pub struct __CFBitVector(c_void); + +pub type CFBitVectorRef = *const __CFBitVector; +pub type CFMutableBitVectorRef = *mut __CFBitVector; +pub type CFBit = UInt32; + +extern "C" { + /* + * CFBitVector.h + */ + + /* CFBitVector */ + /* Creating a Bit Vector */ + pub fn CFBitVectorCreate( + allocator: CFAllocatorRef, + bytes: *const UInt8, + numBits: CFIndex, + ) -> CFBitVectorRef; + pub fn CFBitVectorCreateCopy(allocator: CFAllocatorRef, bv: CFBitVectorRef) -> CFBitVectorRef; + + /* Getting Information About a Bit Vector */ + pub fn CFBitVectorContainsBit(bv: CFBitVectorRef, range: CFRange, value: CFBit) -> Boolean; + pub fn CFBitVectorGetBitAtIndex(bv: CFBitVectorRef, idx: CFIndex) -> CFBit; + pub fn CFBitVectorGetBits(bv: CFBitVectorRef, range: CFRange, bytes: *mut UInt8); + pub fn CFBitVectorGetCount(bv: CFBitVectorRef) -> CFIndex; + pub fn CFBitVectorGetCountOfBit(bv: CFBitVectorRef, range: CFRange, value: CFBit) -> CFIndex; + pub fn CFBitVectorGetFirstIndexOfBit( + bv: CFBitVectorRef, + range: CFRange, + value: CFBit, + ) -> CFIndex; + pub fn CFBitVectorGetLastIndexOfBit( + bv: CFBitVectorRef, + range: CFRange, + value: CFBit, + ) -> CFIndex; + + /* Getting the CFBitVector Type ID */ + pub fn CFBitVectorGetTypeID() -> CFTypeID; + + /* CFMutableBitVector */ + /* Creating a CFMutableBitVector Object */ + pub fn CFBitVectorCreateMutable( + allocator: CFAllocatorRef, + capacity: CFIndex, + ) -> CFMutableBitVectorRef; + pub fn CFBitVectorCreateMutableCopy( + allocator: CFAllocatorRef, + capacity: CFIndex, + bv: CFBitVectorRef, + ) -> CFMutableBitVectorRef; + + /* Modifying a Bit Vector */ + pub fn CFBitVectorFlipBitAtIndex(bv: CFMutableBitVectorRef, idx: CFIndex); + pub fn CFBitVectorFlipBits(bv: CFMutableBitVectorRef, range: CFRange); + pub fn CFBitVectorSetAllBits(bv: CFMutableBitVectorRef, value: CFBit); + pub fn CFBitVectorSetBitAtIndex(bv: CFMutableBitVectorRef, idx: CFIndex, value: CFBit); + pub fn CFBitVectorSetBits(bv: CFMutableBitVectorRef, range: CFRange, value: CFBit); + pub fn CFBitVectorSetCount(bv: CFMutableBitVectorRef, count: CFIndex); +} diff --git a/third_party/rust/core-foundation-sys/src/bundle.rs b/third_party/rust/core-foundation-sys/src/bundle.rs index 29f8e1261f..60aaa4c777 100644 --- a/third_party/rust/core-foundation-sys/src/bundle.rs +++ b/third_party/rust/core-foundation-sys/src/bundle.rs @@ -9,31 +9,226 @@ use std::os::raw::c_void; -use base::{CFTypeID, CFAllocatorRef}; -use url::CFURLRef; -use dictionary::CFDictionaryRef; -use string::CFStringRef; +use crate::array::CFArrayRef; +#[cfg(target_os = "macos")] +use crate::base::SInt32; +use crate::base::{Boolean, CFAllocatorRef, CFTypeID, CFTypeRef, UInt32}; +use crate::dictionary::CFDictionaryRef; +use crate::error::CFErrorRef; +use crate::string::CFStringRef; +use crate::url::CFURLRef; +use std::os::raw::{c_int, c_uint}; #[repr(C)] pub struct __CFBundle(c_void); pub type CFBundleRef = *mut __CFBundle; +pub type CFPlugInRef = *mut __CFBundle; +pub type CFBundleRefNum = c_int; -extern { +#[allow(unused)] +#[inline(always)] +pub unsafe fn CFCopyLocalizedString(key: CFStringRef, comment: CFStringRef) -> CFStringRef { + CFBundleCopyLocalizedString(CFBundleGetMainBundle(), key, key, std::ptr::null()) +} +#[allow(unused)] +#[inline(always)] +pub unsafe fn CFCopyLocalizedStringFromTable( + key: CFStringRef, + tbl: CFStringRef, + comment: CFStringRef, +) -> CFStringRef { + CFBundleCopyLocalizedString(CFBundleGetMainBundle(), key, key, tbl) +} +#[allow(unused)] +#[inline(always)] +pub unsafe fn CFCopyLocalizedStringFromTableInBundle( + key: CFStringRef, + tbl: CFStringRef, + bundle: CFBundleRef, + comment: CFStringRef, +) -> CFStringRef { + CFBundleCopyLocalizedString(bundle, key, key, tbl) +} +#[allow(unused)] +#[inline(always)] +pub unsafe fn CFCopyLocalizedStringWithDefaultValue( + key: CFStringRef, + tbl: CFStringRef, + bundle: CFBundleRef, + value: CFStringRef, + comment: CFStringRef, +) -> CFStringRef { + CFBundleCopyLocalizedString(bundle, key, value, tbl) +} + +pub static kCFBundleExecutableArchitectureI386: c_uint = 0x00000007; +pub static kCFBundleExecutableArchitecturePPC: c_uint = 0x00000012; +pub static kCFBundleExecutableArchitectureX86_64: c_uint = 0x01000007; +pub static kCFBundleExecutableArchitecturePPC64: c_uint = 0x01000012; +//pub static kCFBundleExecutableArchitectureARM64: c_uint = 0x0100000c; //macos(11.0)+ + +extern "C" { /* * CFBundle.h */ - pub fn CFBundleCreate(allocator: CFAllocatorRef, bundleURL: CFURLRef) -> CFBundleRef; + /* Information Property List Keys */ + pub static kCFBundleInfoDictionaryVersionKey: CFStringRef; + pub static kCFBundleExecutableKey: CFStringRef; + pub static kCFBundleIdentifierKey: CFStringRef; + pub static kCFBundleVersionKey: CFStringRef; + pub static kCFBundleDevelopmentRegionKey: CFStringRef; + pub static kCFBundleNameKey: CFStringRef; + pub static kCFBundleLocalizationsKey: CFStringRef; + + /* Creating and Accessing Bundles */ + pub fn CFBundleCreate(allocator: CFAllocatorRef, bundleURL: CFURLRef) -> CFBundleRef; + pub fn CFBundleCreateBundlesFromDirectory( + allocator: CFAllocatorRef, + directoryURL: CFURLRef, + bundleType: CFStringRef, + ) -> CFArrayRef; + pub fn CFBundleGetAllBundles() -> CFArrayRef; pub fn CFBundleGetBundleWithIdentifier(bundleID: CFStringRef) -> CFBundleRef; - pub fn CFBundleGetFunctionPointerForName(bundle: CFBundleRef, function_name: CFStringRef) -> *const c_void; pub fn CFBundleGetMainBundle() -> CFBundleRef; - pub fn CFBundleGetInfoDictionary(bundle: CFBundleRef) -> CFDictionaryRef; - pub fn CFBundleGetTypeID() -> CFTypeID; + /* Loading and Unloading a Bundle */ + pub fn CFBundleIsExecutableLoaded(bundle: CFBundleRef) -> Boolean; + pub fn CFBundlePreflightExecutable(bundle: CFBundleRef, error: *mut CFErrorRef) -> Boolean; + pub fn CFBundleLoadExecutable(bundle: CFBundleRef) -> Boolean; + pub fn CFBundleLoadExecutableAndReturnError( + bundle: CFBundleRef, + error: *mut CFErrorRef, + ) -> Boolean; + pub fn CFBundleUnloadExecutable(bundle: CFBundleRef); + + /* Finding Locations in a Bundle */ + pub fn CFBundleCopyAuxiliaryExecutableURL( + bundle: CFBundleRef, + executableName: CFStringRef, + ) -> CFURLRef; + pub fn CFBundleCopyBuiltInPlugInsURL(bundle: CFBundleRef) -> CFURLRef; pub fn CFBundleCopyExecutableURL(bundle: CFBundleRef) -> CFURLRef; pub fn CFBundleCopyPrivateFrameworksURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleCopyResourcesDirectoryURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleCopySharedFrameworksURL(bundle: CFBundleRef) -> CFURLRef; pub fn CFBundleCopySharedSupportURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleCopySupportFilesDirectoryURL(bundle: CFBundleRef) -> CFURLRef; + + /* Locating Bundle Resources */ + #[cfg(target_os = "macos")] + pub fn CFBundleCloseBundleResourceMap(bundle: CFBundleRef, refNum: CFBundleRefNum); // DEPRECATED macosx(10.0, 10.15) + pub fn CFBundleCopyResourceURL( + bundle: CFBundleRef, + resourceName: CFStringRef, + resourceType: CFStringRef, + subDirName: CFStringRef, + ) -> CFURLRef; + pub fn CFBundleCopyResourceURLInDirectory( + bundleURL: CFURLRef, + resourceName: CFStringRef, + resourceType: CFStringRef, + subDirName: CFStringRef, + ) -> CFURLRef; + pub fn CFBundleCopyResourceURLsOfType( + bundle: CFBundleRef, + resourceType: CFStringRef, + subDirName: CFStringRef, + ) -> CFArrayRef; + pub fn CFBundleCopyResourceURLsOfTypeInDirectory( + bundleURL: CFURLRef, + resourceType: CFStringRef, + subDirName: CFStringRef, + ) -> CFArrayRef; + pub fn CFBundleCopyResourceURLForLocalization( + bundle: CFBundleRef, + resourceName: CFStringRef, + resourceType: CFStringRef, + subDirName: CFStringRef, + localizationName: CFStringRef, + ) -> CFURLRef; + pub fn CFBundleCopyResourceURLsOfTypeForLocalization( + bundle: CFBundleRef, + resourceType: CFStringRef, + subDirName: CFStringRef, + localizationName: CFStringRef, + ) -> CFArrayRef; + #[cfg(target_os = "macos")] + pub fn CFBundleOpenBundleResourceFiles( + bundle: CFBundleRef, + refNum: *mut CFBundleRefNum, + localizedRefNum: *mut CFBundleRefNum, + ) -> SInt32; // DEPRECATED macosx(10.0, 10.15) + #[cfg(target_os = "macos")] + pub fn CFBundleOpenBundleResourceMap(bundle: CFBundleRef) -> CFBundleRefNum; // DEPRECATED macosx(10.0, 10.15) + + /* Managing Localizations */ + pub fn CFBundleCopyBundleLocalizations(bundle: CFBundleRef) -> CFArrayRef; + pub fn CFBundleCopyLocalizedString( + bundle: CFBundleRef, + key: CFStringRef, + value: CFStringRef, + tableName: CFStringRef, + ) -> CFStringRef; + pub fn CFBundleCopyLocalizationsForPreferences( + locArray: CFArrayRef, + prefArray: CFArrayRef, + ) -> CFArrayRef; + pub fn CFBundleCopyLocalizationsForURL(url: CFURLRef) -> CFArrayRef; + pub fn CFBundleCopyPreferredLocalizationsFromArray(locArray: CFArrayRef) -> CFArrayRef; + + /* Managing Executable Code */ + pub fn CFBundleGetDataPointerForName( + bundle: CFBundleRef, + symbolName: CFStringRef, + ) -> *mut c_void; + pub fn CFBundleGetDataPointersForNames( + bundle: CFBundleRef, + symbolNames: CFArrayRef, + stbl: *mut [c_void], + ); + pub fn CFBundleGetFunctionPointerForName( + bundle: CFBundleRef, + function_name: CFStringRef, + ) -> *const c_void; + pub fn CFBundleGetFunctionPointersForNames( + bundle: CFBundleRef, + functionNames: CFArrayRef, + ftbl: *mut [c_void], + ); + pub fn CFBundleGetPlugIn(bundle: CFBundleRef) -> CFPlugInRef; + + /* Getting Bundle Properties */ pub fn CFBundleCopyBundleURL(bundle: CFBundleRef) -> CFURLRef; - pub fn CFBundleCopyResourcesDirectoryURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleGetDevelopmentRegion(bundle: CFBundleRef) -> CFStringRef; + pub fn CFBundleGetIdentifier(bundle: CFBundleRef) -> CFStringRef; + pub fn CFBundleGetInfoDictionary(bundle: CFBundleRef) -> CFDictionaryRef; + pub fn CFBundleGetLocalInfoDictionary(bundle: CFBundleRef) -> CFDictionaryRef; + pub fn CFBundleGetValueForInfoDictionaryKey(bundle: CFBundleRef, key: CFStringRef) + -> CFTypeRef; + pub fn CFBundleCopyInfoDictionaryInDirectory(bundleURL: CFURLRef) -> CFDictionaryRef; + pub fn CFBundleCopyInfoDictionaryForURL(url: CFURLRef) -> CFDictionaryRef; + pub fn CFBundleGetPackageInfo( + bundle: CFBundleRef, + packageType: *mut UInt32, + packageCreator: *mut UInt32, + ); + pub fn CFBundleGetPackageInfoInDirectory( + url: CFURLRef, + packageType: *mut UInt32, + packageCreator: *mut UInt32, + ) -> Boolean; + pub fn CFBundleCopyExecutableArchitectures(bundle: CFBundleRef) -> CFArrayRef; + pub fn CFBundleCopyExecutableArchitecturesForURL(url: CFURLRef) -> CFArrayRef; + pub fn CFBundleGetVersionNumber(bundle: CFBundleRef) -> UInt32; + + /* macos(11.0)+ + pub fn CFBundleIsExecutableLoadable(bundle: CFBundleRef) -> Boolean; + pub fn CFBundleIsExecutableLoadableForURL(url: CFURLRef) -> Boolean; + pub fn CFBundleIsArchitectureLoadable(arch: cpu_type_t) -> Boolean; + */ + + /* Getting the CFBundle Type ID */ + pub fn CFBundleGetTypeID() -> CFTypeID; } diff --git a/third_party/rust/core-foundation-sys/src/calendar.rs b/third_party/rust/core-foundation-sys/src/calendar.rs new file mode 100644 index 0000000000..54c2a00cd2 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/calendar.rs @@ -0,0 +1,128 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::{c_char, c_void}; + +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFRange, CFTypeID}; +use crate::date::{CFAbsoluteTime, CFTimeInterval}; +use crate::locale::{CFCalendarIdentifier, CFLocaleRef}; +use crate::timezone::CFTimeZoneRef; + +#[repr(C)] +pub struct __CFCalendar(c_void); +pub type CFCalendarRef = *mut __CFCalendar; + +pub type CFCalendarUnit = CFOptionFlags; +pub const kCFCalendarUnitEra: CFCalendarUnit = 1 << 1; +pub const kCFCalendarUnitYear: CFCalendarUnit = 1 << 2; +pub const kCFCalendarUnitMonth: CFCalendarUnit = 1 << 3; +pub const kCFCalendarUnitDay: CFCalendarUnit = 1 << 4; +pub const kCFCalendarUnitHour: CFCalendarUnit = 1 << 5; +pub const kCFCalendarUnitMinute: CFCalendarUnit = 1 << 6; +pub const kCFCalendarUnitSecond: CFCalendarUnit = 1 << 7; +pub const kCFCalendarUnitWeek: CFCalendarUnit = 1 << 8; // deprecated since macos 10.10 +pub const kCFCalendarUnitWeekday: CFCalendarUnit = 1 << 9; +pub const kCFCalendarUnitWeekdayOrdinal: CFCalendarUnit = 1 << 10; +pub const kCFCalendarUnitQuarter: CFCalendarUnit = 1 << 11; +pub const kCFCalendarUnitWeekOfMonth: CFCalendarUnit = 1 << 12; +pub const kCFCalendarUnitWeekOfYear: CFCalendarUnit = 1 << 13; +pub const kCFCalendarUnitYearForWeekOfYear: CFCalendarUnit = 1 << 14; + +pub const kCFCalendarComponentsWrap: CFOptionFlags = 1 << 0; + +extern "C" { + /* + * CFCalendar.h + */ + + /* Creating a Calendar */ + pub fn CFCalendarCopyCurrent() -> CFCalendarRef; + pub fn CFCalendarCreateWithIdentifier( + allocator: CFAllocatorRef, + identifier: CFCalendarIdentifier, + ) -> CFCalendarRef; + + /* Calendrical Calculations */ + pub fn CFCalendarAddComponents( + identifier: CFCalendarIdentifier, + /* inout */ at: *mut CFAbsoluteTime, + options: CFOptionFlags, + componentDesc: *const char, + ... + ) -> Boolean; + pub fn CFCalendarComposeAbsoluteTime( + identifier: CFCalendarIdentifier, + /* out */ at: *mut CFAbsoluteTime, + componentDesc: *const c_char, + ... + ) -> Boolean; + pub fn CFCalendarDecomposeAbsoluteTime( + identifier: CFCalendarIdentifier, + at: CFAbsoluteTime, + componentDesc: *const c_char, + ... + ) -> Boolean; + pub fn CFCalendarGetComponentDifference( + identifier: CFCalendarIdentifier, + startingAT: CFAbsoluteTime, + resultAT: CFAbsoluteTime, + options: CFOptionFlags, + componentDesc: *const c_char, + ... + ) -> Boolean; + + /* Getting Ranges of Units */ + pub fn CFCalendarGetRangeOfUnit( + identifier: CFCalendarIdentifier, + smallerUnit: CFCalendarUnit, + biggerUnit: CFCalendarUnit, + at: CFAbsoluteTime, + ) -> CFRange; + pub fn CFCalendarGetOrdinalityOfUnit( + identifier: CFCalendarIdentifier, + smallerUnit: CFCalendarUnit, + biggerUnit: CFCalendarUnit, + at: CFAbsoluteTime, + ) -> CFIndex; + pub fn CFCalendarGetTimeRangeOfUnit( + identifier: CFCalendarIdentifier, + unit: CFCalendarUnit, + at: CFAbsoluteTime, + startp: *mut CFAbsoluteTime, + tip: *mut CFTimeInterval, + ) -> Boolean; + pub fn CFCalendarGetMaximumRangeOfUnit( + identifier: CFCalendarIdentifier, + unit: CFCalendarUnit, + ) -> CFRange; + pub fn CFCalendarGetMinimumRangeOfUnit( + identifier: CFCalendarIdentifier, + unit: CFCalendarUnit, + ) -> CFRange; + + /* Getting and Setting the Time Zone */ + pub fn CFCalendarCopyTimeZone(identifier: CFCalendarIdentifier) -> CFTimeZoneRef; + pub fn CFCalendarSetTimeZone(identifier: CFCalendarIdentifier, tz: CFTimeZoneRef); + + /* Getting the Identifier */ + pub fn CFCalendarGetIdentifier(identifier: CFCalendarIdentifier) -> CFCalendarIdentifier; + + /* Getting and Setting the Locale */ + pub fn CFCalendarCopyLocale(identifier: CFCalendarIdentifier) -> CFLocaleRef; + pub fn CFCalendarSetLocale(identifier: CFCalendarIdentifier, locale: CFLocaleRef); + + /* Getting and Setting Day Information */ + pub fn CFCalendarGetFirstWeekday(identifier: CFCalendarIdentifier) -> CFIndex; + pub fn CFCalendarSetFirstWeekday(identifier: CFCalendarIdentifier, wkdy: CFIndex); + pub fn CFCalendarGetMinimumDaysInFirstWeek(identifier: CFCalendarIdentifier) -> CFIndex; + pub fn CFCalendarSetMinimumDaysInFirstWeek(identifier: CFCalendarIdentifier, mwd: CFIndex); + + /* Getting the Type ID */ + pub fn CFCalendarGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/characterset.rs b/third_party/rust/core-foundation-sys/src/characterset.rs index 6b347a5cdd..8d75679af9 100644 --- a/third_party/rust/core-foundation-sys/src/characterset.rs +++ b/third_party/rust/core-foundation-sys/src/characterset.rs @@ -7,10 +7,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFRange, CFTypeID, UTF32Char}; +use crate::data::CFDataRef; +use crate::string::{CFStringRef, UniChar}; use std::os::raw::c_void; -use base::{Boolean, CFAllocatorRef, CFIndex, CFRange, CFTypeID}; -use data::CFDataRef; -use string::{CFStringRef, UniChar}; pub type CFCharacterSetPredefinedSet = CFIndex; @@ -35,24 +35,90 @@ pub static kCFCharacterSetNewline: CFCharacterSetPredefinedSet = 15; pub struct __CFCharacterSet(c_void); pub type CFCharacterSetRef = *const __CFCharacterSet; -pub type CFMutableCharacterSetRef = *const __CFCharacterSet; +pub type CFMutableCharacterSetRef = *mut __CFCharacterSet; -extern { +extern "C" { + /* + * CFCharacterSet.h + */ + + /* CFCharacterSet */ + /* Creating Character Sets */ + pub fn CFCharacterSetCreateCopy( + alloc: CFAllocatorRef, + theSet: CFCharacterSetRef, + ) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateInvertedSet( + alloc: CFAllocatorRef, + theSet: CFCharacterSetRef, + ) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateWithCharactersInRange( + alloc: CFAllocatorRef, + theRange: CFRange, + ) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateWithCharactersInString( + alloc: CFAllocatorRef, + theString: CFStringRef, + ) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateWithBitmapRepresentation( + alloc: CFAllocatorRef, + theData: CFDataRef, + ) -> CFCharacterSetRef; + + /* Getting Predefined Character Sets */ + pub fn CFCharacterSetGetPredefined( + theSetIdentifier: CFCharacterSetPredefinedSet, + ) -> CFCharacterSetRef; + + /* Querying Character Sets */ + pub fn CFCharacterSetCreateBitmapRepresentation( + alloc: CFAllocatorRef, + theSet: CFCharacterSetRef, + ) -> CFDataRef; + pub fn CFCharacterSetHasMemberInPlane(theSet: CFCharacterSetRef, thePlane: CFIndex) -> Boolean; + pub fn CFCharacterSetIsCharacterMember(theSet: CFCharacterSetRef, theChar: UniChar) -> Boolean; + pub fn CFCharacterSetIsLongCharacterMember( + theSet: CFCharacterSetRef, + theChar: UTF32Char, + ) -> Boolean; + pub fn CFCharacterSetIsSupersetOfSet( + theSet: CFCharacterSetRef, + theOtherset: CFCharacterSetRef, + ) -> Boolean; + + /* Getting the Character Set Type Identifier */ pub fn CFCharacterSetGetTypeID() -> CFTypeID; - pub fn CFCharacterSetGetPredefined(theSetIdentifier: CFCharacterSetPredefinedSet) -> CFCharacterSetRef; - pub fn CFCharacterSetCreateWithCharactersInRange(alloc: CFAllocatorRef, theRange: CFRange) -> CFCharacterSetRef; - pub fn CFCharacterSetCreateWithCharactersInString(alloc: CFAllocatorRef, theString: CFStringRef) -> CFCharacterSetRef; - pub fn CFCharacterSetCreateWithBitmapRepresentation(alloc: CFAllocatorRef, theData: CFDataRef) -> CFCharacterSetRef; + + /* CFMutableCharacterSet */ + /* Creating a Mutable Character Set */ pub fn CFCharacterSetCreateMutable(alloc: CFAllocatorRef) -> CFMutableCharacterSetRef; - pub fn CFCharacterSetCreateCopy(alloc: CFAllocatorRef, theSet: CFCharacterSetRef) -> CFCharacterSetRef; - pub fn CFCharacterSetCreateMutableCopy(alloc: CFAllocatorRef, theSet: CFCharacterSetRef) -> CFMutableCharacterSetRef; - pub fn CFCharacterSetIsCharacterMember(theSet: CFCharacterSetRef, theChar: UniChar) -> Boolean; - pub fn CFCharacterSetCreateBitmapRepresentation(alloc: CFAllocatorRef, theSet: CFCharacterSetRef) -> CFDataRef; + pub fn CFCharacterSetCreateMutableCopy( + alloc: CFAllocatorRef, + theSet: CFCharacterSetRef, + ) -> CFMutableCharacterSetRef; + + /* Adding Characters */ pub fn CFCharacterSetAddCharactersInRange(theSet: CFMutableCharacterSetRef, theRange: CFRange); - pub fn CFCharacterSetRemoveCharactersInRange(theSet: CFMutableCharacterSetRef, theRange: CFRange); - pub fn CFCharacterSetAddCharactersInString(theSet: CFMutableCharacterSetRef, theString: CFStringRef); - pub fn CFCharacterSetRemoveCharactersInString(theSet: CFMutableCharacterSetRef, theString: CFStringRef); - pub fn CFCharacterSetUnion(theSet: CFMutableCharacterSetRef, theOtherSet: CFCharacterSetRef); - pub fn CFCharacterSetIntersect(theSet: CFMutableCharacterSetRef, theOtherSet: CFCharacterSetRef); + pub fn CFCharacterSetAddCharactersInString( + theSet: CFMutableCharacterSetRef, + theString: CFStringRef, + ); + + /* Removing Characters */ + pub fn CFCharacterSetRemoveCharactersInRange( + theSet: CFMutableCharacterSetRef, + theRange: CFRange, + ); + pub fn CFCharacterSetRemoveCharactersInString( + theSet: CFMutableCharacterSetRef, + theString: CFStringRef, + ); + + /* Logical Operations */ + pub fn CFCharacterSetIntersect( + theSet: CFMutableCharacterSetRef, + theOtherSet: CFCharacterSetRef, + ); pub fn CFCharacterSetInvert(theSet: CFMutableCharacterSetRef); + pub fn CFCharacterSetUnion(theSet: CFMutableCharacterSetRef, theOtherSet: CFCharacterSetRef); } diff --git a/third_party/rust/core-foundation-sys/src/data.rs b/third_party/rust/core-foundation-sys/src/data.rs index e5ed0dc9f0..ba87d0c5d3 100644 --- a/third_party/rust/core-foundation-sys/src/data.rs +++ b/third_party/rust/core-foundation-sys/src/data.rs @@ -7,32 +7,71 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRange, CFTypeID}; use std::os::raw::c_void; -use base::{CFAllocatorRef, CFTypeID, CFIndex, CFRange}; - #[repr(C)] pub struct __CFData(c_void); pub type CFDataRef = *const __CFData; +pub type CFMutableDataRef = *mut __CFData; +pub type CFDataSearchFlags = CFOptionFlags; + +// typedef CF_OPTIONS(CFOptionFlags, CFDataSearchFlags) +pub const kCFDataSearchBackwards: CFDataSearchFlags = 1usize << 0; +pub const kCFDataSearchAnchored: CFDataSearchFlags = 1usize << 1; -extern { +extern "C" { /* * CFData.h */ - pub fn CFDataCreate(allocator: CFAllocatorRef, - bytes: *const u8, length: CFIndex) -> CFDataRef; - //fn CFDataFind - pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8; - pub fn CFDataGetBytes(theData: CFDataRef, range: CFRange, buffer: *mut u8); - pub fn CFDataGetLength(theData: CFDataRef) -> CFIndex; + /* CFData */ + /* Creating a CFData Object */ + pub fn CFDataCreate(allocator: CFAllocatorRef, bytes: *const u8, length: CFIndex) -> CFDataRef; + pub fn CFDataCreateCopy(allocator: CFAllocatorRef, theData: CFDataRef) -> CFDataRef; pub fn CFDataCreateWithBytesNoCopy( allocator: CFAllocatorRef, bytes: *const u8, length: CFIndex, - allocator: CFAllocatorRef, + bytesDeallocator: CFAllocatorRef, ) -> CFDataRef; + /* Examining a CFData Object */ + pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8; + pub fn CFDataGetBytes(theData: CFDataRef, range: CFRange, buffer: *mut u8); + pub fn CFDataGetLength(theData: CFDataRef) -> CFIndex; + pub fn CFDataFind( + theData: CFDataRef, + dataToFind: CFDataRef, + searchRange: CFRange, + compareOptions: CFDataSearchFlags, + ) -> CFRange; + + /* Getting the CFData Type ID */ pub fn CFDataGetTypeID() -> CFTypeID; + + /* CFMutableData */ + /* Creating a Mutable Data Object */ + pub fn CFDataCreateMutable(allocator: CFAllocatorRef, capacity: CFIndex) -> CFMutableDataRef; + pub fn CFDataCreateMutableCopy( + allocator: CFAllocatorRef, + capacity: CFIndex, + theData: CFDataRef, + ) -> CFMutableDataRef; + + /* Accessing Data */ + pub fn CFDataGetMutableBytePtr(theData: CFMutableDataRef) -> *mut u8; + + /* Modifying a Mutable Data Object */ + pub fn CFDataAppendBytes(theData: CFMutableDataRef, bytes: *const u8, length: CFIndex); + pub fn CFDataDeleteBytes(theData: CFMutableDataRef, range: CFRange); + pub fn CFDataReplaceBytes( + theData: CFMutableDataRef, + range: CFRange, + newBytes: *const u8, + newLength: CFIndex, + ); + pub fn CFDataIncreaseLength(theData: CFMutableDataRef, extraLength: CFIndex); + pub fn CFDataSetLength(theData: CFMutableDataRef, length: CFIndex); } diff --git a/third_party/rust/core-foundation-sys/src/date.rs b/third_party/rust/core-foundation-sys/src/date.rs index f83ce1dd18..26b55d402a 100644 --- a/third_party/rust/core-foundation-sys/src/date.rs +++ b/third_party/rust/core-foundation-sys/src/date.rs @@ -9,7 +9,7 @@ use std::os::raw::c_void; -use base::{CFAllocatorRef, CFComparisonResult, CFTypeID}; +use crate::base::{CFAllocatorRef, CFComparisonResult, CFTypeID}; #[repr(C)] pub struct __CFDate(c_void); @@ -19,7 +19,7 @@ pub type CFDateRef = *const __CFDate; pub type CFTimeInterval = f64; pub type CFAbsoluteTime = CFTimeInterval; -extern { +extern "C" { pub static kCFAbsoluteTimeIntervalSince1904: CFTimeInterval; pub static kCFAbsoluteTimeIntervalSince1970: CFTimeInterval; @@ -28,7 +28,11 @@ extern { pub fn CFDateCreate(allocator: CFAllocatorRef, at: CFAbsoluteTime) -> CFDateRef; pub fn CFDateGetAbsoluteTime(date: CFDateRef) -> CFAbsoluteTime; pub fn CFDateGetTimeIntervalSinceDate(date: CFDateRef, other: CFDateRef) -> CFTimeInterval; - pub fn CFDateCompare(date: CFDateRef, other: CFDateRef, context: *mut c_void) -> CFComparisonResult; + pub fn CFDateCompare( + date: CFDateRef, + other: CFDateRef, + context: *mut c_void, + ) -> CFComparisonResult; pub fn CFDateGetTypeID() -> CFTypeID; } diff --git a/third_party/rust/core-foundation-sys/src/date_formatter.rs b/third_party/rust/core-foundation-sys/src/date_formatter.rs new file mode 100644 index 0000000000..83c6e1fa76 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/date_formatter.rs @@ -0,0 +1,147 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFRange, CFTypeID, CFTypeRef}; +use crate::date::{CFAbsoluteTime, CFDateRef}; +use crate::locale::CFLocaleRef; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFDateFormatter(c_void); +pub type CFDateFormatterRef = *mut __CFDateFormatter; + +pub type CFDateFormatterKey = CFStringRef; +pub type CFDateFormatterStyle = CFIndex; +pub type CFISO8601DateFormatOptions = CFOptionFlags; + +/* Date Formatter Styles */ +pub const kCFDateFormatterNoStyle: CFDateFormatterStyle = 0; +pub const kCFDateFormatterShortStyle: CFDateFormatterStyle = 1; +pub const kCFDateFormatterMediumStyle: CFDateFormatterStyle = 2; +pub const kCFDateFormatterLongStyle: CFDateFormatterStyle = 3; +pub const kCFDateFormatterFullStyle: CFDateFormatterStyle = 4; + +//pub const kCFISO8601DateFormatWithYear: CFISO8601DateFormatOptions = 1 << 0; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithMonth: CFISO8601DateFormatOptions = 1 << 1; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithWeekOfYear: CFISO8601DateFormatOptions = 1 << 2; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithDay: CFISO8601DateFormatOptions = 1 << 4; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithTime: CFISO8601DateFormatOptions = 1 << 5; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithTimeZone: CFISO8601DateFormatOptions = 1 << 6; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithSpaceBetweenDateAndTime: CFISO8601DateFormatOptions = 1 << 7; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithDashSeparatorInDate: CFISO8601DateFormatOptions = 1 << 8; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithColonSeparatorInTime: CFISO8601DateFormatOptions = 1 << 9; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithColonSeparatorInTimeZone: CFISO8601DateFormatOptions = 1 << 10; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithFractionalSeconds: CFISO8601DateFormatOptions = 1 << 11; // macosx(10.13)+ +//pub const kCFISO8601DateFormatWithFullDate: CFISO8601DateFormatOptions = kCFISO8601DateFormatWithYear | kCFISO8601DateFormatWithMonth | kCFISO8601DateFormatWithDay | kCFISO8601DateFormatWithDashSeparatorInDate; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithFullTime: CFISO8601DateFormatOptions = kCFISO8601DateFormatWithTime | kCFISO8601DateFormatWithColonSeparatorInTime | kCFISO8601DateFormatWithTimeZone | kCFISO8601DateFormatWithColonSeparatorInTimeZone; // macosx(10.12)+ +//pub const kCFISO8601DateFormatWithInternetDateTime: CFISO8601DateFormatOptions = kCFISO8601DateFormatWithFullDate | kCFISO8601DateFormatWithFullTime; // macosx(10.12)+ + +extern "C" { + /* + * CFDateFormatter.h + */ + + /* Date Formatter Property Keys */ + // The values for these keys are all CFType objects. + // The specific types for each key are specified above. + pub static kCFDateFormatterIsLenient: CFDateFormatterKey; // CFBoolean + pub static kCFDateFormatterTimeZone: CFDateFormatterKey; // CFTimeZone + pub static kCFDateFormatterCalendarName: CFDateFormatterKey; // CFString + pub static kCFDateFormatterDefaultFormat: CFDateFormatterKey; // CFString + pub static kCFDateFormatterTwoDigitStartDate: CFDateFormatterKey; // CFDate + pub static kCFDateFormatterDefaultDate: CFDateFormatterKey; // CFDate + pub static kCFDateFormatterCalendar: CFDateFormatterKey; // CFCalendar + pub static kCFDateFormatterEraSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterMonthSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterShortMonthSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterWeekdaySymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterShortWeekdaySymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterAMSymbol: CFDateFormatterKey; // CFString + pub static kCFDateFormatterPMSymbol: CFDateFormatterKey; // CFString + pub static kCFDateFormatterLongEraSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterVeryShortMonthSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterStandaloneMonthSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterShortStandaloneMonthSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterVeryShortStandaloneMonthSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterVeryShortWeekdaySymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterStandaloneWeekdaySymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterShortStandaloneWeekdaySymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterVeryShortStandaloneWeekdaySymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterQuarterSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterShortQuarterSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterStandaloneQuarterSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterShortStandaloneQuarterSymbols: CFDateFormatterKey; // CFArray of CFString + pub static kCFDateFormatterGregorianStartDate: CFDateFormatterKey; // CFDate + pub static kCFDateFormatterDoesRelativeDateFormattingKey: CFDateFormatterKey; // CFBoolean + + /* Creating a Date Formatter */ + pub fn CFDateFormatterCreate( + allocator: CFAllocatorRef, + locale: CFLocaleRef, + dateStyle: CFDateFormatterStyle, + timeStyle: CFDateFormatterStyle, + ) -> CFDateFormatterRef; + + /* Configuring a Date Formatter */ + pub fn CFDateFormatterSetFormat(formatter: CFDateFormatterRef, formatString: CFStringRef); + pub fn CFDateFormatterSetProperty( + formatter: CFDateFormatterRef, + key: CFStringRef, + value: CFTypeRef, + ); + + /* Parsing Strings */ + pub fn CFDateFormatterCreateDateFromString( + allocator: CFAllocatorRef, + formatter: CFDateFormatterRef, + string: CFStringRef, + rangep: *mut CFRange, + ) -> CFDateRef; + pub fn CFDateFormatterGetAbsoluteTimeFromString( + formatter: CFDateFormatterRef, + string: CFStringRef, + rangep: *mut CFRange, + atp: *mut CFAbsoluteTime, + ) -> Boolean; + + /* Creating Strings From Data */ + pub fn CFDateFormatterCreateStringWithAbsoluteTime( + allocator: CFAllocatorRef, + formatter: CFDateFormatterRef, + at: CFAbsoluteTime, + ) -> CFStringRef; + pub fn CFDateFormatterCreateStringWithDate( + allocator: CFAllocatorRef, + formatter: CFDateFormatterRef, + date: CFDateRef, + ) -> CFStringRef; + pub fn CFDateFormatterCreateDateFormatFromTemplate( + allocator: CFAllocatorRef, + tmplate: CFStringRef, + options: CFOptionFlags, + locale: CFLocaleRef, + ) -> CFStringRef; + + /* Getting Information About a Date Formatter */ + pub fn CFDateFormatterCopyProperty( + formatter: CFDateFormatterRef, + key: CFDateFormatterKey, + ) -> CFTypeRef; + pub fn CFDateFormatterGetDateStyle(formatter: CFDateFormatterRef) -> CFDateFormatterStyle; + pub fn CFDateFormatterGetFormat(formatter: CFDateFormatterRef) -> CFStringRef; + pub fn CFDateFormatterGetLocale(formatter: CFDateFormatterRef) -> CFLocaleRef; + pub fn CFDateFormatterGetTimeStyle(formatter: CFDateFormatterRef) -> CFDateFormatterStyle; + + /* Getting the CFDateFormatter Type ID */ + pub fn CFDateFormatterGetTypeID() -> CFTypeID; + + //pub fn CFDateFormatterCreateISO8601Formatter(allocator: CFAllocatorRef, formatOptions: CFISO8601DateFormatOptions) -> CFDateFormatterRef; // macosx(10.12)+ +} diff --git a/third_party/rust/core-foundation-sys/src/dictionary.rs b/third_party/rust/core-foundation-sys/src/dictionary.rs index d10e9c1200..8c04d680df 100644 --- a/third_party/rust/core-foundation-sys/src/dictionary.rs +++ b/third_party/rust/core-foundation-sys/src/dictionary.rs @@ -9,15 +9,19 @@ use std::os::raw::c_void; -use base::{CFAllocatorRef, CFHashCode, CFIndex, CFTypeID, Boolean}; -use string::CFStringRef; +use crate::base::{Boolean, CFAllocatorRef, CFHashCode, CFIndex, CFTypeID}; +use crate::string::CFStringRef; -pub type CFDictionaryApplierFunction = extern "C" fn(key: *const c_void, value: *const c_void, context: *mut c_void); +pub type CFDictionaryApplierFunction = + extern "C" fn(key: *const c_void, value: *const c_void, context: *mut c_void); -pub type CFDictionaryRetainCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; -pub type CFDictionaryReleaseCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void); +pub type CFDictionaryRetainCallBack = + extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; +pub type CFDictionaryReleaseCallBack = + extern "C" fn(allocator: CFAllocatorRef, value: *const c_void); pub type CFDictionaryCopyDescriptionCallBack = extern "C" fn(value: *const c_void) -> CFStringRef; -pub type CFDictionaryEqualCallBack = extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; +pub type CFDictionaryEqualCallBack = + extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; pub type CFDictionaryHashCallBack = extern "C" fn(value: *const c_void) -> CFHashCode; #[repr(C)] @@ -28,7 +32,7 @@ pub struct CFDictionaryKeyCallBacks { pub release: CFDictionaryReleaseCallBack, pub copyDescription: CFDictionaryCopyDescriptionCallBack, pub equal: CFDictionaryEqualCallBack, - pub hash: CFDictionaryHashCallBack + pub hash: CFDictionaryHashCallBack, } #[repr(C)] @@ -38,7 +42,7 @@ pub struct CFDictionaryValueCallBacks { pub retain: CFDictionaryRetainCallBack, pub release: CFDictionaryReleaseCallBack, pub copyDescription: CFDictionaryCopyDescriptionCallBack, - pub equal: CFDictionaryEqualCallBack + pub equal: CFDictionaryEqualCallBack, } #[repr(C)] @@ -47,45 +51,89 @@ pub struct __CFDictionary(c_void); pub type CFDictionaryRef = *const __CFDictionary; pub type CFMutableDictionaryRef = *mut __CFDictionary; -extern { +extern "C" { /* * CFDictionary.h */ pub static kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks; + pub static kCFCopyStringDictionaryKeyCallBacks: CFDictionaryKeyCallBacks; pub static kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks; + /* CFDictionary */ + /* Creating a dictionary */ + pub fn CFDictionaryCreate( + allocator: CFAllocatorRef, + keys: *const *const c_void, + values: *const *const c_void, + numValues: CFIndex, + keyCallBacks: *const CFDictionaryKeyCallBacks, + valueCallBacks: *const CFDictionaryValueCallBacks, + ) -> CFDictionaryRef; + pub fn CFDictionaryCreateCopy( + allocator: CFAllocatorRef, + theDict: CFDictionaryRef, + ) -> CFDictionaryRef; + + /* Examining a dictionary */ pub fn CFDictionaryContainsKey(theDict: CFDictionaryRef, key: *const c_void) -> Boolean; - pub fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: *const *const c_void, values: *const *const c_void, - numValues: CFIndex, keyCallBacks: *const CFDictionaryKeyCallBacks, - valueCallBacks: *const CFDictionaryValueCallBacks) - -> CFDictionaryRef; + pub fn CFDictionaryContainsValue(theDict: CFDictionaryRef, value: *const c_void) -> Boolean; pub fn CFDictionaryGetCount(theDict: CFDictionaryRef) -> CFIndex; + pub fn CFDictionaryGetCountOfKey(theDict: CFDictionaryRef, key: *const c_void) -> CFIndex; + pub fn CFDictionaryGetCountOfValue(heDict: CFDictionaryRef, value: *const c_void) -> CFIndex; + pub fn CFDictionaryGetKeysAndValues( + theDict: CFDictionaryRef, + keys: *mut *const c_void, + values: *mut *const c_void, + ); + pub fn CFDictionaryGetValue(theDict: CFDictionaryRef, key: *const c_void) -> *const c_void; + pub fn CFDictionaryGetValueIfPresent( + theDict: CFDictionaryRef, + key: *const c_void, + value: *mut *const c_void, + ) -> Boolean; + + /* Applying a function to a dictionary */ + pub fn CFDictionaryApplyFunction( + theDict: CFDictionaryRef, + applier: CFDictionaryApplierFunction, + context: *mut c_void, + ); + + /* Getting the CFDictionary type ID */ pub fn CFDictionaryGetTypeID() -> CFTypeID; - pub fn CFDictionaryGetValueIfPresent(theDict: CFDictionaryRef, key: *const c_void, value: *mut *const c_void) - -> Boolean; - pub fn CFDictionaryApplyFunction(theDict: CFDictionaryRef, - applier: CFDictionaryApplierFunction, - context: *mut c_void); - pub fn CFDictionaryGetKeysAndValues(theDict: CFDictionaryRef, - keys: *mut *const c_void, - values: *mut *const c_void); - - pub fn CFDictionaryCreateMutable(allocator: CFAllocatorRef, capacity: CFIndex, - keyCallbacks: *const CFDictionaryKeyCallBacks, - valueCallbacks: *const CFDictionaryValueCallBacks) -> CFMutableDictionaryRef; - pub fn CFDictionaryCreateMutableCopy(allocator: CFAllocatorRef, capacity: CFIndex, - theDict: CFDictionaryRef) -> CFMutableDictionaryRef; - pub fn CFDictionaryAddValue(theDict: CFMutableDictionaryRef, - key: *const c_void, - value: *const c_void); - pub fn CFDictionarySetValue(theDict: CFMutableDictionaryRef, - key: *const c_void, - value: *const c_void); - pub fn CFDictionaryReplaceValue(theDict: CFMutableDictionaryRef, - key: *const c_void, - value: *const c_void); - pub fn CFDictionaryRemoveValue(theDict: CFMutableDictionaryRef, - key: *const c_void); + + /* CFMutableDictionary */ + /* Creating a Mutable Dictionary */ + pub fn CFDictionaryCreateMutable( + allocator: CFAllocatorRef, + capacity: CFIndex, + keyCallbacks: *const CFDictionaryKeyCallBacks, + valueCallbacks: *const CFDictionaryValueCallBacks, + ) -> CFMutableDictionaryRef; + pub fn CFDictionaryCreateMutableCopy( + allocator: CFAllocatorRef, + capacity: CFIndex, + theDict: CFDictionaryRef, + ) -> CFMutableDictionaryRef; + + /* Modifying a Dictionary */ + pub fn CFDictionaryAddValue( + theDict: CFMutableDictionaryRef, + key: *const c_void, + value: *const c_void, + ); pub fn CFDictionaryRemoveAllValues(theDict: CFMutableDictionaryRef); + pub fn CFDictionaryRemoveValue(theDict: CFMutableDictionaryRef, key: *const c_void); + pub fn CFDictionaryReplaceValue( + theDict: CFMutableDictionaryRef, + key: *const c_void, + value: *const c_void, + ); + pub fn CFDictionarySetValue( + theDict: CFMutableDictionaryRef, + key: *const c_void, + value: *const c_void, + ); + } diff --git a/third_party/rust/core-foundation-sys/src/error.rs b/third_party/rust/core-foundation-sys/src/error.rs index 8a4c1d4940..e8ebd6c421 100644 --- a/third_party/rust/core-foundation-sys/src/error.rs +++ b/third_party/rust/core-foundation-sys/src/error.rs @@ -9,24 +9,54 @@ use std::os::raw::c_void; -use base::{CFTypeID, CFIndex}; -use string::CFStringRef; +use crate::base::{CFAllocatorRef, CFIndex, CFTypeID}; +use crate::dictionary::CFDictionaryRef; +use crate::string::CFStringRef; #[repr(C)] pub struct __CFError(c_void); pub type CFErrorRef = *mut __CFError; +pub type CFErrorDomain = CFStringRef; extern "C" { - pub fn CFErrorGetTypeID() -> CFTypeID; + /* + * CFError.h + */ + /* Error domains */ pub static kCFErrorDomainPOSIX: CFStringRef; pub static kCFErrorDomainOSStatus: CFStringRef; pub static kCFErrorDomainMach: CFStringRef; pub static kCFErrorDomainCocoa: CFStringRef; + /* Keys for the user info dictionary */ + pub static kCFErrorLocalizedDescriptionKey: CFStringRef; + // pub static kCFErrorLocalizedFailureKey: CFStringRef; // macos(10.13)+ + pub static kCFErrorLocalizedFailureReasonKey: CFStringRef; + pub static kCFErrorLocalizedRecoverySuggestionKey: CFStringRef; + pub static kCFErrorDescriptionKey: CFStringRef; + pub static kCFErrorUnderlyingErrorKey: CFStringRef; + pub static kCFErrorURLKey: CFStringRef; + pub static kCFErrorFilePathKey: CFStringRef; + + /* Creating a CFError */ + pub fn CFErrorCreate( + allocator: CFAllocatorRef, + domain: CFErrorDomain, + code: CFIndex, + userInfo: CFDictionaryRef, + ) -> CFErrorRef; + //pub fn CFErrorCreateWithUserInfoKeysAndValues + + /* Getting Information About an Error */ pub fn CFErrorGetDomain(err: CFErrorRef) -> CFStringRef; pub fn CFErrorGetCode(err: CFErrorRef) -> CFIndex; - + pub fn CFErrorCopyUserInfo(err: CFErrorRef) -> CFDictionaryRef; pub fn CFErrorCopyDescription(err: CFErrorRef) -> CFStringRef; + pub fn CFErrorCopyFailureReason(err: CFErrorRef) -> CFStringRef; + pub fn CFErrorCopyRecoverySuggestion(err: CFErrorRef) -> CFStringRef; + + /* Getting the CFError Type ID */ + pub fn CFErrorGetTypeID() -> CFTypeID; } diff --git a/third_party/rust/core-foundation-sys/src/file_security.rs b/third_party/rust/core-foundation-sys/src/file_security.rs new file mode 100644 index 0000000000..a4ec6112b5 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/file_security.rs @@ -0,0 +1,71 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +#[cfg(feature = "mac_os_10_8_features")] +use crate::base::CFOptionFlags; +use crate::base::{Boolean, CFAllocatorRef, CFTypeID}; +use crate::uuid::CFUUIDRef; + +#[repr(C)] +pub struct __CFFileSecurity(c_void); +pub type CFFileSecurityRef = *mut __CFFileSecurity; + +#[cfg(feature = "mac_os_10_8_features")] +pub type CFFileSecurityClearOptions = CFOptionFlags; +#[cfg(feature = "mac_os_10_8_features")] +pub const kCFFileSecurityClearOwner: CFFileSecurityClearOptions = 1 << 0; +#[cfg(feature = "mac_os_10_8_features")] +pub const kCFFileSecurityClearGroup: CFFileSecurityClearOptions = 1 << 1; +#[cfg(feature = "mac_os_10_8_features")] +pub const kCFFileSecurityClearMode: CFFileSecurityClearOptions = 1 << 2; +#[cfg(feature = "mac_os_10_8_features")] +pub const kCFFileSecurityClearOwnerUUID: CFFileSecurityClearOptions = 1 << 3; +#[cfg(feature = "mac_os_10_8_features")] +pub const kCFFileSecurityClearGroupUUID: CFFileSecurityClearOptions = 1 << 4; +#[cfg(feature = "mac_os_10_8_features")] +pub const kCFFileSecurityClearAccessControlList: CFFileSecurityClearOptions = 1 << 5; + +extern "C" { + /* + * CFFileSecurity.h + */ + pub fn CFFileSecurityGetTypeID() -> CFTypeID; + pub fn CFFileSecurityCreate(allocator: CFAllocatorRef) -> CFFileSecurityRef; + pub fn CFFileSecurityCreateCopy( + allocator: CFAllocatorRef, + fileSec: CFFileSecurityRef, + ) -> CFFileSecurityRef; + pub fn CFFileSecurityCopyOwnerUUID( + fileSec: CFFileSecurityRef, + ownerUUID: *mut CFUUIDRef, + ) -> Boolean; + pub fn CFFileSecuritySetOwnerUUID(fileSec: CFFileSecurityRef, ownerUUID: CFUUIDRef) -> Boolean; + pub fn CFFileSecurityCopyGroupUUID( + fileSec: CFFileSecurityRef, + groupUUID: *mut CFUUIDRef, + ) -> Boolean; + pub fn CFFileSecuritySetGroupUUID(fileSec: CFFileSecurityRef, groupUUID: CFUUIDRef) -> Boolean; + //pub fn CFFileSecurityCopyAccessControlList(fileSec: CFFileSecurityRef, accessControlList: *mut acl_t) -> Boolean; + //pub fn CFFileSecuritySetAccessControlList(fileSec: CFFileSecurityRef, accessControlList: acl_t) -> Boolean; + //pub fn CFFileSecurityGetOwner(fileSec: CFFileSecurityRef, owner: *mut uid_t) -> Boolean; + //pub fn CFFileSecuritySetOwner(fileSec: CFFileSecurityRef, owner: uid_t) -> Boolean; + //pub fn CFFileSecurityGetGroup(fileSec: CFFileSecurityRef, group: *mut gid_t) -> Boolean; + //pub fn CFFileSecuritySetGroup(fileSec: CFFileSecurityRef, group: gid_t) -> Boolean; + //pub fn CFFileSecurityGetMode(fileSec: CFFileSecurityRef, mode: *mut mode_t) -> Boolean; + //pub fn CFFileSecuritySetMode(fileSec: CFFileSecurityRef, mode: mode_t) -> Boolean; + + #[cfg(feature = "mac_os_10_8_features")] + #[cfg_attr(feature = "mac_os_10_7_support", linkage = "extern_weak")] + pub fn CFFileSecurityClearProperties( + fileSec: CFFileSecurityRef, + clearPropertyMask: CFFileSecurityClearOptions, + ) -> Boolean; +} diff --git a/third_party/rust/core-foundation-sys/src/filedescriptor.rs b/third_party/rust/core-foundation-sys/src/filedescriptor.rs index 3f51d10729..271adb716c 100644 --- a/third_party/rust/core-foundation-sys/src/filedescriptor.rs +++ b/third_party/rust/core-foundation-sys/src/filedescriptor.rs @@ -9,9 +9,9 @@ use std::os::raw::{c_int, c_void}; -use base::{Boolean, CFIndex, CFTypeID, CFOptionFlags, CFAllocatorRef}; -use string::CFStringRef; -use runloop::CFRunLoopSourceRef; +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeID}; +use crate::runloop::CFRunLoopSourceRef; +use crate::string::CFStringRef; pub type CFFileDescriptorNativeDescriptor = c_int; @@ -21,38 +21,60 @@ pub struct __CFFileDescriptor(c_void); pub type CFFileDescriptorRef = *mut __CFFileDescriptor; /* Callback Reason Types */ -pub const kCFFileDescriptorReadCallBack: CFOptionFlags = 1 << 0; +pub const kCFFileDescriptorReadCallBack: CFOptionFlags = 1 << 0; pub const kCFFileDescriptorWriteCallBack: CFOptionFlags = 1 << 1; -pub type CFFileDescriptorCallBack = extern "C" fn (f: CFFileDescriptorRef, callBackTypes: CFOptionFlags, info: *mut c_void); +pub type CFFileDescriptorCallBack = + extern "C" fn(f: CFFileDescriptorRef, callBackTypes: CFOptionFlags, info: *mut c_void); #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct CFFileDescriptorContext { pub version: CFIndex, pub info: *mut c_void, - pub retain: Option *const c_void>, - pub release: Option, - pub copyDescription: Option CFStringRef>, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, } -extern { +extern "C" { /* * CFFileDescriptor.h */ - pub fn CFFileDescriptorGetTypeID() -> CFTypeID; - pub fn CFFileDescriptorCreate(allocator: CFAllocatorRef, fd: CFFileDescriptorNativeDescriptor, closeOnInvalidate: Boolean, callout: CFFileDescriptorCallBack, context: *const CFFileDescriptorContext) -> CFFileDescriptorRef; + /* Creating a CFFileDescriptor */ + pub fn CFFileDescriptorCreate( + allocator: CFAllocatorRef, + fd: CFFileDescriptorNativeDescriptor, + closeOnInvalidate: Boolean, + callout: CFFileDescriptorCallBack, + context: *const CFFileDescriptorContext, + ) -> CFFileDescriptorRef; - pub fn CFFileDescriptorGetNativeDescriptor(f: CFFileDescriptorRef) -> CFFileDescriptorNativeDescriptor; + /* Getting Information About a File Descriptor */ + pub fn CFFileDescriptorGetNativeDescriptor( + f: CFFileDescriptorRef, + ) -> CFFileDescriptorNativeDescriptor; + pub fn CFFileDescriptorIsValid(f: CFFileDescriptorRef) -> Boolean; + pub fn CFFileDescriptorGetContext( + f: CFFileDescriptorRef, + context: *mut CFFileDescriptorContext, + ); - pub fn CFFileDescriptorGetContext(f: CFFileDescriptorRef, context: *mut CFFileDescriptorContext); + /* Invalidating a File Descriptor */ + pub fn CFFileDescriptorInvalidate(f: CFFileDescriptorRef); + /* Managing Callbacks */ pub fn CFFileDescriptorEnableCallBacks(f: CFFileDescriptorRef, callBackTypes: CFOptionFlags); pub fn CFFileDescriptorDisableCallBacks(f: CFFileDescriptorRef, callBackTypes: CFOptionFlags); - pub fn CFFileDescriptorInvalidate(f: CFFileDescriptorRef); - pub fn CFFileDescriptorIsValid(f: CFFileDescriptorRef) -> Boolean; + /* Creating a Run Loop Source */ + pub fn CFFileDescriptorCreateRunLoopSource( + allocator: CFAllocatorRef, + f: CFFileDescriptorRef, + order: CFIndex, + ) -> CFRunLoopSourceRef; - pub fn CFFileDescriptorCreateRunLoopSource(allocator: CFAllocatorRef, f: CFFileDescriptorRef, order: CFIndex) -> CFRunLoopSourceRef; + /* Getting the CFFileDescriptor Type ID */ + pub fn CFFileDescriptorGetTypeID() -> CFTypeID; } diff --git a/third_party/rust/core-foundation-sys/src/lib.rs b/third_party/rust/core-foundation-sys/src/lib.rs index f9a1884169..948ce807d3 100644 --- a/third_party/rust/core-foundation-sys/src/lib.rs +++ b/third_party/rust/core-foundation-sys/src/lib.rs @@ -6,27 +6,69 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals, improper_ctypes)] +#![allow( + non_snake_case, + non_camel_case_types, + non_upper_case_globals, + improper_ctypes +)] +#![cfg_attr( + all(feature = "mac_os_10_7_support", feature = "mac_os_10_8_features"), + feature(linkage) +)] // back-compat requires weak linkage -#![cfg_attr(all(feature="mac_os_10_7_support", feature="mac_os_10_8_features"), feature(linkage))] // back-compat requires weak linkage +// Link to CoreFoundation on any Apple device. +// +// We don't use `target_vendor` since that is going to be deprecated: +// https://github.com/rust-lang/lang-team/issues/102 +#[cfg_attr( + all( + any(target_os = "macos", target_os = "ios", target_os = "tvos"), + feature = "link" + ), + link(name = "CoreFoundation", kind = "framework") +)] +extern "C" {} pub mod array; pub mod attributed_string; +pub mod bag; pub mod base; +pub mod binary_heap; +pub mod bit_vector; pub mod bundle; +pub mod calendar; pub mod characterset; pub mod data; pub mod date; +pub mod date_formatter; pub mod dictionary; pub mod error; +pub mod file_security; pub mod filedescriptor; +pub mod locale; +pub mod mach_port; pub mod messageport; +pub mod notification_center; pub mod number; +pub mod number_formatter; +pub mod plugin; +pub mod preferences; pub mod propertylist; pub mod runloop; pub mod set; +pub mod socket; +pub mod stream; pub mod string; +pub mod string_tokenizer; pub mod timezone; +pub mod tree; pub mod url; +pub mod url_enumerator; +#[cfg(target_os = "macos")] +pub mod user_notification; pub mod uuid; -pub mod mach_port; +#[cfg(target_os = "macos")] +pub mod xml_node; +#[cfg(target_os = "macos")] +pub mod xml_parser; diff --git a/third_party/rust/core-foundation-sys/src/locale.rs b/third_party/rust/core-foundation-sys/src/locale.rs new file mode 100644 index 0000000000..f80e5c4a6a --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/locale.rs @@ -0,0 +1,146 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::array::CFArrayRef; +use crate::base::{CFAllocatorRef, CFIndex, CFTypeID, CFTypeRef, LangCode, RegionCode}; +use crate::dictionary::CFDictionaryRef; +use crate::notification_center::CFNotificationName; +use crate::string::CFStringRef; +use std::os::raw::c_void; + +#[repr(C)] +pub struct __CFLocale(c_void); +pub type CFLocaleRef = *const __CFLocale; + +pub type CFLocaleIdentifier = CFStringRef; +pub type CFLocaleKey = CFStringRef; +pub type CFCalendarIdentifier = CFStringRef; +pub type CFLocaleLanguageDirection = CFIndex; + +pub const kCFLocaleLanguageDirectionUnknown: CFLocaleLanguageDirection = 0; +pub const kCFLocaleLanguageDirectionLeftToRight: CFLocaleLanguageDirection = 1; +pub const kCFLocaleLanguageDirectionRightToLeft: CFLocaleLanguageDirection = 2; +pub const kCFLocaleLanguageDirectionTopToBottom: CFLocaleLanguageDirection = 3; +pub const kCFLocaleLanguageDirectionBottomToTop: CFLocaleLanguageDirection = 4; + +extern "C" { + /* + * CFLocale.h + */ + + /* Locale Change Notification */ + pub static kCFLocaleCurrentLocaleDidChangeNotification: CFNotificationName; + + /* Locale Property Keys */ + pub static kCFLocaleIdentifier: CFLocaleKey; + pub static kCFLocaleLanguageCode: CFLocaleKey; + pub static kCFLocaleCountryCode: CFLocaleKey; + pub static kCFLocaleScriptCode: CFLocaleKey; + pub static kCFLocaleVariantCode: CFLocaleKey; + + pub static kCFLocaleExemplarCharacterSet: CFLocaleKey; + pub static kCFLocaleCalendarIdentifier: CFLocaleKey; + pub static kCFLocaleCalendar: CFLocaleKey; + pub static kCFLocaleCollationIdentifier: CFLocaleKey; + pub static kCFLocaleUsesMetricSystem: CFLocaleKey; + pub static kCFLocaleMeasurementSystem: CFLocaleKey; + pub static kCFLocaleDecimalSeparator: CFLocaleKey; + pub static kCFLocaleGroupingSeparator: CFLocaleKey; + pub static kCFLocaleCurrencySymbol: CFLocaleKey; + pub static kCFLocaleCurrencyCode: CFLocaleKey; + pub static kCFLocaleCollatorIdentifier: CFLocaleKey; + pub static kCFLocaleQuotationBeginDelimiterKey: CFLocaleKey; + pub static kCFLocaleQuotationEndDelimiterKey: CFLocaleKey; + pub static kCFLocaleAlternateQuotationBeginDelimiterKey: CFLocaleKey; + pub static kCFLocaleAlternateQuotationEndDelimiterKey: CFLocaleKey; + + /* Locale Calendar Identifiers */ + pub static kCFGregorianCalendar: CFCalendarIdentifier; + pub static kCFBuddhistCalendar: CFCalendarIdentifier; + pub static kCFChineseCalendar: CFCalendarIdentifier; + pub static kCFHebrewCalendar: CFCalendarIdentifier; + pub static kCFIslamicCalendar: CFCalendarIdentifier; + pub static kCFIslamicCivilCalendar: CFCalendarIdentifier; + pub static kCFJapaneseCalendar: CFCalendarIdentifier; + pub static kCFRepublicOfChinaCalendar: CFCalendarIdentifier; + pub static kCFPersianCalendar: CFCalendarIdentifier; + pub static kCFIndianCalendar: CFCalendarIdentifier; + pub static kCFISO8601Calendar: CFCalendarIdentifier; + //pub static kCFIslamicTabularCalendar: CFCalendarIdentifier; // macos(10.10)+ + //pub static kCFIslamicUmmAlQuraCalendar: CFCalendarIdentifier; // macos(10.10)+ + + /* Creating a Locale */ + pub fn CFLocaleCopyCurrent() -> CFLocaleRef; + pub fn CFLocaleCreate( + allocator: CFAllocatorRef, + localeIdentifier: CFLocaleIdentifier, + ) -> CFLocaleRef; + pub fn CFLocaleCreateCopy(allocator: CFAllocatorRef, locale: CFLocaleRef) -> CFLocaleRef; + pub fn CFLocaleGetSystem() -> CFLocaleRef; + + /* Getting System Locale Information */ + pub fn CFLocaleCopyAvailableLocaleIdentifiers() -> CFArrayRef; + + /* Getting ISO Information */ + pub fn CFLocaleCopyISOCountryCodes() -> CFArrayRef; + pub fn CFLocaleCopyISOLanguageCodes() -> CFArrayRef; + pub fn CFLocaleCopyISOCurrencyCodes() -> CFArrayRef; + pub fn CFLocaleCopyCommonISOCurrencyCodes() -> CFArrayRef; + + /* Language Preferences */ + pub fn CFLocaleCopyPreferredLanguages() -> CFArrayRef; + + /* Getting Information About a Locale */ + pub fn CFLocaleCopyDisplayNameForPropertyValue( + displayLocale: CFLocaleRef, + key: CFLocaleKey, + value: CFStringRef, + ) -> CFStringRef; + pub fn CFLocaleGetValue(locale: CFLocaleRef, key: CFLocaleKey) -> CFTypeRef; + pub fn CFLocaleGetIdentifier(locale: CFLocaleRef) -> CFLocaleIdentifier; + + /* Getting and Creating Locale Identifiers */ + pub fn CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes( + allocator: CFAllocatorRef, + lcode: LangCode, + rcode: RegionCode, + ) -> CFLocaleIdentifier; + pub fn CFLocaleCreateCanonicalLanguageIdentifierFromString( + allocator: CFAllocatorRef, + localeIdentifier: CFStringRef, + ) -> CFLocaleIdentifier; + pub fn CFLocaleCreateCanonicalLocaleIdentifierFromString( + allocator: CFAllocatorRef, + localeIdentifier: CFStringRef, + ) -> CFLocaleIdentifier; + pub fn CFLocaleCreateComponentsFromLocaleIdentifier( + allocator: CFAllocatorRef, + localeID: CFLocaleIdentifier, + ) -> CFDictionaryRef; + pub fn CFLocaleCreateLocaleIdentifierFromComponents( + allocator: CFAllocatorRef, + dictionary: CFDictionaryRef, + ) -> CFLocaleIdentifier; + pub fn CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode( + allocator: CFAllocatorRef, + lcid: u32, + ) -> CFLocaleIdentifier; + pub fn CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier( + localeIdentifier: CFLocaleIdentifier, + ) -> u32; + + /* Getting Line and Character Direction for a Language */ + pub fn CFLocaleGetLanguageCharacterDirection( + isoLangCode: CFStringRef, + ) -> CFLocaleLanguageDirection; + pub fn CFLocaleGetLanguageLineDirection(isoLangCode: CFStringRef) -> CFLocaleLanguageDirection; + + /* Getting the CFLocale Type ID */ + pub fn CFLocaleGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/mach_port.rs b/third_party/rust/core-foundation-sys/src/mach_port.rs index 2341fd4e74..1f47275dec 100644 --- a/third_party/rust/core-foundation-sys/src/mach_port.rs +++ b/third_party/rust/core-foundation-sys/src/mach_port.rs @@ -1,20 +1,75 @@ -pub use base::{CFAllocatorRef, CFIndex, CFTypeID}; -use runloop::CFRunLoopSourceRef; +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::base::{mach_port_t, Boolean}; +pub use crate::base::{CFAllocatorRef, CFIndex, CFTypeID}; +use crate::runloop::CFRunLoopSourceRef; +use crate::string::CFStringRef; use std::os::raw::c_void; #[repr(C)] pub struct __CFMachPort(c_void); -pub type CFMachPortRef = *const __CFMachPort; +pub type CFMachPortRef = *mut __CFMachPort; + +pub type CFMachPortCallBack = + extern "C" fn(port: CFMachPortRef, msg: *mut c_void, size: CFIndex, info: *mut c_void); +pub type CFMachPortInvalidationCallBack = extern "C" fn(port: CFMachPortRef, info: *mut c_void); + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFMachPortContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn(info: *const c_void) -> *const c_void, + pub release: extern "C" fn(info: *const c_void), + pub copyDescription: extern "C" fn(info: *const c_void) -> CFStringRef, +} extern "C" { /* * CFMachPort.h */ + + /* Creating a CFMachPort Object */ + pub fn CFMachPortCreate( + allocator: CFAllocatorRef, + callout: CFMachPortCallBack, + context: *mut CFMachPortContext, + shouldFreeInfo: *mut Boolean, + ) -> CFMachPortRef; + pub fn CFMachPortCreateWithPort( + allocator: CFAllocatorRef, + portNum: mach_port_t, + callout: CFMachPortCallBack, + context: *mut CFMachPortContext, + shouldFreeInfo: *mut Boolean, + ) -> CFMachPortRef; + + /* Configuring a CFMachPort Object */ + pub fn CFMachPortInvalidate(port: CFMachPortRef); pub fn CFMachPortCreateRunLoopSource( allocator: CFAllocatorRef, port: CFMachPortRef, order: CFIndex, ) -> CFRunLoopSourceRef; - + pub fn CFMachPortSetInvalidationCallBack( + port: CFMachPortRef, + callout: CFMachPortInvalidationCallBack, + ); + + /* Examining a CFMachPort Object */ + pub fn CFMachPortGetContext(port: CFMachPortRef, context: *mut CFMachPortContext); + pub fn CFMachPortGetInvalidationCallBack(port: CFMachPortRef) + -> CFMachPortInvalidationCallBack; + pub fn CFMachPortGetPort(port: CFMachPortRef) -> mach_port_t; + pub fn CFMachPortIsValid(port: CFMachPortRef) -> Boolean; + + /* Getting the CFMachPort Type ID */ pub fn CFMachPortGetTypeID() -> CFTypeID; } diff --git a/third_party/rust/core-foundation-sys/src/messageport.rs b/third_party/rust/core-foundation-sys/src/messageport.rs index e33d9aa4bc..4ccdcc8b37 100644 --- a/third_party/rust/core-foundation-sys/src/messageport.rs +++ b/third_party/rust/core-foundation-sys/src/messageport.rs @@ -9,71 +9,98 @@ use std::os::raw::c_void; -use base::{CFAllocatorRef, CFIndex, CFTypeID, Boolean}; -use data::CFDataRef; -use date::CFTimeInterval; -use runloop::CFRunLoopSourceRef; -use string::CFStringRef; +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFTypeID, SInt32}; +use crate::data::CFDataRef; +use crate::date::CFTimeInterval; +use crate::runloop::CFRunLoopSourceRef; +use crate::string::CFStringRef; #[repr(C)] -#[derive(Copy, Clone)] -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub struct CFMessagePortContext { pub version: CFIndex, pub info: *mut c_void, - pub retain: Option *const c_void>, - pub release: Option, - pub copyDescription: Option CFStringRef>, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, } pub type CFMessagePortCallBack = Option< - unsafe extern fn(local: CFMessagePortRef, - msgid: i32, - data: CFDataRef, - info: *mut c_void) -> CFDataRef>; + unsafe extern "C" fn( + local: CFMessagePortRef, + msgid: i32, + data: CFDataRef, + info: *mut c_void, + ) -> CFDataRef, +>; -pub type CFMessagePortInvalidationCallBack = Option< - unsafe extern "C" fn(ms: CFMessagePortRef, info: *mut c_void)>; +pub type CFMessagePortInvalidationCallBack = + Option; + +/* CFMessagePortSendRequest Error Codes */ +pub const kCFMessagePortSuccess: SInt32 = 0; +pub const kCFMessagePortSendTimeout: SInt32 = -1; +pub const kCFMessagePortReceiveTimeout: SInt32 = -2; +pub const kCFMessagePortIsInvalid: SInt32 = -3; +pub const kCFMessagePortTransportError: SInt32 = -4; +pub const kCFMessagePortBecameInvalidError: SInt32 = -5; #[repr(C)] pub struct __CFMessagePort(c_void); pub type CFMessagePortRef = *mut __CFMessagePort; -extern { +extern "C" { /* * CFMessagePort.h */ - pub fn CFMessagePortGetTypeID() -> CFTypeID; - pub fn CFMessagePortCreateLocal(allocator: CFAllocatorRef, - name: CFStringRef, - callout: CFMessagePortCallBack, - context: *const CFMessagePortContext, - shouldFreeInfo: *mut Boolean) - -> CFMessagePortRef; - pub fn CFMessagePortCreateRemote(allocator: CFAllocatorRef, - name: CFStringRef) -> CFMessagePortRef; - pub fn CFMessagePortIsRemote(ms: CFMessagePortRef) -> Boolean; - pub fn CFMessagePortGetName(ms: CFMessagePortRef) -> CFStringRef; - pub fn CFMessagePortSetName(ms: CFMessagePortRef, newName: CFStringRef) - -> Boolean; - pub fn CFMessagePortGetContext(ms: CFMessagePortRef, - context: *mut CFMessagePortContext); + + /* Creating a CFMessagePort Object */ + pub fn CFMessagePortCreateLocal( + allocator: CFAllocatorRef, + name: CFStringRef, + callout: CFMessagePortCallBack, + context: *const CFMessagePortContext, + shouldFreeInfo: *mut Boolean, + ) -> CFMessagePortRef; + pub fn CFMessagePortCreateRemote( + allocator: CFAllocatorRef, + name: CFStringRef, + ) -> CFMessagePortRef; + + /* Configuring a CFMessagePort Object */ + pub fn CFMessagePortCreateRunLoopSource( + allocator: CFAllocatorRef, + local: CFMessagePortRef, + order: CFIndex, + ) -> CFRunLoopSourceRef; + pub fn CFMessagePortSetInvalidationCallBack( + ms: CFMessagePortRef, + callout: CFMessagePortInvalidationCallBack, + ); + pub fn CFMessagePortSetName(ms: CFMessagePortRef, newName: CFStringRef) -> Boolean; + + /* Using a Message Port */ pub fn CFMessagePortInvalidate(ms: CFMessagePortRef); + pub fn CFMessagePortSendRequest( + remote: CFMessagePortRef, + msgid: i32, + data: CFDataRef, + sendTimeout: CFTimeInterval, + rcvTimeout: CFTimeInterval, + replyMode: CFStringRef, + returnData: *mut CFDataRef, + ) -> i32; + //pub fn CFMessagePortSetDispatchQueue(ms: CFMessagePortRef, queue: dispatch_queue_t); + + /* Examining a Message Port */ + pub fn CFMessagePortGetContext(ms: CFMessagePortRef, context: *mut CFMessagePortContext); + pub fn CFMessagePortGetInvalidationCallBack( + ms: CFMessagePortRef, + ) -> CFMessagePortInvalidationCallBack; + pub fn CFMessagePortGetName(ms: CFMessagePortRef) -> CFStringRef; + pub fn CFMessagePortIsRemote(ms: CFMessagePortRef) -> Boolean; pub fn CFMessagePortIsValid(ms: CFMessagePortRef) -> Boolean; - pub fn CFMessagePortGetInvalidationCallBack(ms: CFMessagePortRef) - -> CFMessagePortInvalidationCallBack; - pub fn CFMessagePortSetInvalidationCallBack(ms: CFMessagePortRef, - callout: CFMessagePortInvalidationCallBack); - pub fn CFMessagePortSendRequest(remote: CFMessagePortRef, msgid: i32, - data: CFDataRef, - sendTimeout: CFTimeInterval, - rcvTimeout: CFTimeInterval, - replyMode: CFStringRef, - returnData: *mut CFDataRef) -> i32; - pub fn CFMessagePortCreateRunLoopSource(allocator: CFAllocatorRef, - local: CFMessagePortRef, - order: CFIndex) - -> CFRunLoopSourceRef; - // CFMessagePortSetDispatchQueue + + /* Getting the CFMessagePort Type ID */ + pub fn CFMessagePortGetTypeID() -> CFTypeID; } diff --git a/third_party/rust/core-foundation-sys/src/notification_center.rs b/third_party/rust/core-foundation-sys/src/notification_center.rs new file mode 100644 index 0000000000..2ed829233e --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/notification_center.rs @@ -0,0 +1,89 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{Boolean, CFIndex, CFOptionFlags, CFTypeID}; +use crate::dictionary::CFDictionaryRef; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFNotificationCenter(c_void); + +pub type CFNotificationCenterRef = *mut __CFNotificationCenter; + +pub type CFNotificationName = CFStringRef; +pub type CFNotificationCallback = extern "C" fn( + center: CFNotificationCenterRef, + observer: *mut c_void, + name: CFNotificationName, + object: *const c_void, + userInfo: CFDictionaryRef, +); +pub type CFNotificationSuspensionBehavior = CFIndex; + +pub const CFNotificationSuspensionBehaviorDrop: CFNotificationSuspensionBehavior = 1; +pub const CFNotificationSuspensionBehaviorCoalesce: CFNotificationSuspensionBehavior = 2; +pub const CFNotificationSuspensionBehaviorHold: CFNotificationSuspensionBehavior = 3; +pub const CFNotificationSuspensionBehaviorDeliverImmediately: CFNotificationSuspensionBehavior = 4; + +/* Notification Posting Options */ +pub const kCFNotificationDeliverImmediately: CFOptionFlags = 1usize << 0; +pub const kCFNotificationPostToAllSessions: CFOptionFlags = 1usize << 1; + +extern "C" { + /* + * CFNotificationCenter.h + */ + + /* Accessing a Notification Center */ + pub fn CFNotificationCenterGetDarwinNotifyCenter() -> CFNotificationCenterRef; + #[cfg(any(target_os = "macos", target_os = "windows"))] + pub fn CFNotificationCenterGetDistributedCenter() -> CFNotificationCenterRef; + pub fn CFNotificationCenterGetLocalCenter() -> CFNotificationCenterRef; + + /* Posting a Notification */ + pub fn CFNotificationCenterPostNotification( + center: CFNotificationCenterRef, + name: CFNotificationName, + object: *const c_void, + userInfo: CFDictionaryRef, + deliverImmediately: Boolean, + ); + pub fn CFNotificationCenterPostNotificationWithOptions( + center: CFNotificationCenterRef, + name: CFNotificationName, + object: *const c_void, + userInfo: CFDictionaryRef, + options: CFOptionFlags, + ); + + /* Adding and Removing Observers */ + pub fn CFNotificationCenterAddObserver( + center: CFNotificationCenterRef, + observer: *const c_void, + callBack: CFNotificationCallback, + name: CFStringRef, + object: *const c_void, + suspensionBehavior: CFNotificationSuspensionBehavior, + ); + pub fn CFNotificationCenterRemoveEveryObserver( + center: CFNotificationCenterRef, + observer: *const c_void, + ); + pub fn CFNotificationCenterRemoveObserver( + center: CFNotificationCenterRef, + observer: *const c_void, + name: CFNotificationName, + object: *const c_void, + ); + + /* Getting the CFNotificationCenter Type ID */ + pub fn CFNotificationCenterGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/number.rs b/third_party/rust/core-foundation-sys/src/number.rs index c056a245b0..d822d417d9 100644 --- a/third_party/rust/core-foundation-sys/src/number.rs +++ b/third_party/rust/core-foundation-sys/src/number.rs @@ -9,7 +9,7 @@ use std::os::raw::c_void; -use base::{CFAllocatorRef, CFTypeID, CFComparisonResult}; +use crate::base::{Boolean, CFAllocatorRef, CFComparisonResult, CFIndex, CFTypeID}; #[repr(C)] pub struct __CFBoolean(c_void); @@ -19,23 +19,23 @@ pub type CFBooleanRef = *const __CFBoolean; pub type CFNumberType = u32; // members of enum CFNumberType -pub const kCFNumberSInt8Type: CFNumberType = 1; -pub const kCFNumberSInt16Type: CFNumberType = 2; -pub const kCFNumberSInt32Type: CFNumberType = 3; -pub const kCFNumberSInt64Type: CFNumberType = 4; -pub const kCFNumberFloat32Type: CFNumberType = 5; -pub const kCFNumberFloat64Type: CFNumberType = 6; -pub const kCFNumberCharType: CFNumberType = 7; -pub const kCFNumberShortType: CFNumberType = 8; -pub const kCFNumberIntType: CFNumberType = 9; -pub const kCFNumberLongType: CFNumberType = 10; -pub const kCFNumberLongLongType: CFNumberType = 11; -pub const kCFNumberFloatType: CFNumberType = 12; -pub const kCFNumberDoubleType: CFNumberType = 13; -pub const kCFNumberCFIndexType: CFNumberType = 14; +pub const kCFNumberSInt8Type: CFNumberType = 1; +pub const kCFNumberSInt16Type: CFNumberType = 2; +pub const kCFNumberSInt32Type: CFNumberType = 3; +pub const kCFNumberSInt64Type: CFNumberType = 4; +pub const kCFNumberFloat32Type: CFNumberType = 5; +pub const kCFNumberFloat64Type: CFNumberType = 6; +pub const kCFNumberCharType: CFNumberType = 7; +pub const kCFNumberShortType: CFNumberType = 8; +pub const kCFNumberIntType: CFNumberType = 9; +pub const kCFNumberLongType: CFNumberType = 10; +pub const kCFNumberLongLongType: CFNumberType = 11; +pub const kCFNumberFloatType: CFNumberType = 12; +pub const kCFNumberDoubleType: CFNumberType = 13; +pub const kCFNumberCFIndexType: CFNumberType = 14; pub const kCFNumberNSIntegerType: CFNumberType = 15; -pub const kCFNumberCGFloatType: CFNumberType = 16; -pub const kCFNumberMaxType: CFNumberType = 16; +pub const kCFNumberCGFloatType: CFNumberType = 16; +pub const kCFNumberMaxType: CFNumberType = 16; // This is an enum due to zero-sized types warnings. // For more details see https://github.com/rust-lang/rust/issues/27303 @@ -43,23 +43,45 @@ pub enum __CFNumber {} pub type CFNumberRef = *const __CFNumber; -extern { +extern "C" { /* * CFNumber.h */ pub static kCFBooleanTrue: CFBooleanRef; pub static kCFBooleanFalse: CFBooleanRef; + pub static kCFNumberPositiveInfinity: CFNumberRef; + pub static kCFNumberNegativeInfinity: CFNumberRef; + pub static kCFNumberNaN: CFNumberRef; - pub fn CFBooleanGetTypeID() -> CFTypeID; - pub fn CFBooleanGetValue(boolean: CFBooleanRef) -> bool; + /* Creating a Number */ + pub fn CFNumberCreate( + allocator: CFAllocatorRef, + theType: CFNumberType, + valuePtr: *const c_void, + ) -> CFNumberRef; - pub fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *const c_void) - -> CFNumberRef; - //fn CFNumberGetByteSize - pub fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *mut c_void) -> bool; - pub fn CFNumberCompare(date: CFNumberRef, other: CFNumberRef, context: *mut c_void) -> CFComparisonResult; - pub fn CFNumberGetTypeID() -> CFTypeID; + /* Getting Information About Numbers */ + pub fn CFNumberGetByteSize(number: CFNumberRef) -> CFIndex; pub fn CFNumberGetType(number: CFNumberRef) -> CFNumberType; + pub fn CFNumberGetValue( + number: CFNumberRef, + theType: CFNumberType, + valuePtr: *mut c_void, + ) -> bool; + pub fn CFNumberIsFloatType(number: CFNumberRef) -> Boolean; + + /* Comparing Numbers */ + pub fn CFNumberCompare( + date: CFNumberRef, + other: CFNumberRef, + context: *mut c_void, + ) -> CFComparisonResult; + + /* Getting the CFNumber Type ID */ + pub fn CFNumberGetTypeID() -> CFTypeID; + + pub fn CFBooleanGetValue(boolean: CFBooleanRef) -> bool; + pub fn CFBooleanGetTypeID() -> CFTypeID; } #[cfg(test)] diff --git a/third_party/rust/core-foundation-sys/src/number_formatter.rs b/third_party/rust/core-foundation-sys/src/number_formatter.rs new file mode 100644 index 0000000000..cae7b11b00 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/number_formatter.rs @@ -0,0 +1,163 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::{c_double, c_void}; + +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFRange, CFTypeID, CFTypeRef}; +use crate::locale::CFLocaleRef; +use crate::number::{CFNumberRef, CFNumberType}; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFNumberFormatter(c_void); + +pub type CFNumberFormatterRef = *mut __CFNumberFormatter; + +pub type CFNumberFormatterKey = CFStringRef; +pub type CFNumberFormatterStyle = CFIndex; +pub type CFNumberFormatterOptionFlags = CFOptionFlags; +pub type CFNumberFormatterRoundingMode = CFIndex; +pub type CFNumberFormatterPadPosition = CFIndex; + +/* Number Formatter Styles */ +pub const kCFNumberFormatterNoStyle: CFNumberFormatterStyle = 0; +pub const kCFNumberFormatterDecimalStyle: CFNumberFormatterStyle = 1; +pub const kCFNumberFormatterCurrencyStyle: CFNumberFormatterStyle = 2; +pub const kCFNumberFormatterPercentStyle: CFNumberFormatterStyle = 3; +pub const kCFNumberFormatterScientificStyle: CFNumberFormatterStyle = 4; +pub const kCFNumberFormatterSpellOutStyle: CFNumberFormatterStyle = 5; +//pub const kCFNumberFormatterOrdinalStyle: CFNumberFormatterStyle = 6; // macos(10.11)+ +//pub const kCFNumberFormatterCurrencyISOCodeStyle: CFNumberFormatterStyle = 8; // macos(10.11)+ +//pub const kCFNumberFormatterCurrencyPluralStyle: CFNumberFormatterStyle = 9; // macos(10.11)+ +//pub const kCFNumberFormatterCurrencyAccountingStyle: CFNumberFormatterStyle = 10; // macos(10.11)+ + +/* Number Format Options */ +pub const kCFNumberFormatterParseIntegersOnly: CFNumberFormatterOptionFlags = 1; + +/* CFNumberFormatterRoundingMode */ +pub const kCFNumberFormatterRoundCeiling: CFNumberFormatterRoundingMode = 0; +pub const kCFNumberFormatterRoundFloor: CFNumberFormatterRoundingMode = 1; +pub const kCFNumberFormatterRoundDown: CFNumberFormatterRoundingMode = 2; +pub const kCFNumberFormatterRoundUp: CFNumberFormatterRoundingMode = 3; +pub const kCFNumberFormatterRoundHalfEven: CFNumberFormatterRoundingMode = 4; +pub const kCFNumberFormatterRoundHalfDown: CFNumberFormatterRoundingMode = 5; +pub const kCFNumberFormatterRoundHalfUp: CFNumberFormatterRoundingMode = 6; + +/* Padding Positions */ +pub const kCFNumberFormatterPadBeforePrefix: CFNumberFormatterPadPosition = 0; +pub const kCFNumberFormatterPadAfterPrefix: CFNumberFormatterPadPosition = 1; +pub const kCFNumberFormatterPadBeforeSuffix: CFNumberFormatterPadPosition = 2; +pub const kCFNumberFormatterPadAfterSuffix: CFNumberFormatterPadPosition = 3; + +extern "C" { + /* + * CFNumberFormatter.h + */ + + /* Number Formatter Property Keys */ + // The values for these keys are all CFType objects. + // The specific types for each key are specified above. + pub static kCFNumberFormatterCurrencyCode: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterDecimalSeparator: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterCurrencyDecimalSeparator: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterAlwaysShowDecimalSeparator: CFNumberFormatterKey; // CFBoolean + pub static kCFNumberFormatterGroupingSeparator: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterUseGroupingSeparator: CFNumberFormatterKey; // CFBoolean + pub static kCFNumberFormatterPercentSymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterZeroSymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterNaNSymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterInfinitySymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterMinusSign: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterPlusSign: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterCurrencySymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterExponentSymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterMinIntegerDigits: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterMaxIntegerDigits: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterMinFractionDigits: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterMaxFractionDigits: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterGroupingSize: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterSecondaryGroupingSize: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterRoundingMode: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterRoundingIncrement: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterFormatWidth: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterPaddingPosition: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterPaddingCharacter: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterDefaultFormat: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterMultiplier: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterPositivePrefix: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterPositiveSuffix: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterNegativePrefix: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterNegativeSuffix: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterPerMillSymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterInternationalCurrencySymbol: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterCurrencyGroupingSeparator: CFNumberFormatterKey; // CFString + pub static kCFNumberFormatterIsLenient: CFNumberFormatterKey; // CFBoolean + pub static kCFNumberFormatterUseSignificantDigits: CFNumberFormatterKey; // CFBoolean + pub static kCFNumberFormatterMinSignificantDigits: CFNumberFormatterKey; // CFNumber + pub static kCFNumberFormatterMaxSignificantDigits: CFNumberFormatterKey; // CFNumber + + /* Creating a Number Formatter */ + pub fn CFNumberFormatterCreate( + allocator: CFAllocatorRef, + locale: CFLocaleRef, + style: CFNumberFormatterStyle, + ) -> CFNumberFormatterRef; + + /* Configuring a Number Formatter */ + pub fn CFNumberFormatterSetFormat(formatter: CFNumberFormatterRef, formatString: CFStringRef); + pub fn CFNumberFormatterSetProperty( + formatter: CFNumberFormatterRef, + key: CFNumberFormatterKey, + value: CFTypeRef, + ); + + /* Formatting Values */ + pub fn CFNumberFormatterCreateNumberFromString( + allocator: CFAllocatorRef, + formatter: CFNumberFormatterRef, + string: CFStringRef, + rangep: *mut CFRange, + options: CFOptionFlags, + ) -> CFNumberRef; + pub fn CFNumberFormatterCreateStringWithNumber( + allocator: CFAllocatorRef, + formatter: CFNumberFormatterRef, + number: CFNumberRef, + ) -> CFStringRef; + pub fn CFNumberFormatterCreateStringWithValue( + allocator: CFAllocatorRef, + formatter: CFNumberFormatterRef, + numberType: CFNumberType, + valuePtr: *const c_void, + ) -> CFStringRef; + pub fn CFNumberFormatterGetDecimalInfoForCurrencyCode( + currencyCode: CFStringRef, + defaultFractionDigits: *mut i32, + roundingIncrement: *mut c_double, + ) -> Boolean; + pub fn CFNumberFormatterGetValueFromString( + formatter: CFNumberFormatterRef, + string: CFStringRef, + rangep: *mut CFRange, + numberType: CFNumberType, + valuePtr: *mut c_void, + ) -> Boolean; + + /* Examining a Number Formatter */ + pub fn CFNumberFormatterCopyProperty( + formatter: CFNumberFormatterRef, + key: CFNumberFormatterKey, + ) -> CFTypeRef; + pub fn CFNumberFormatterGetFormat(formatter: CFNumberFormatterRef) -> CFStringRef; + pub fn CFNumberFormatterGetLocale(formatter: CFNumberFormatterRef) -> CFLocaleRef; + pub fn CFNumberFormatterGetStyle(formatter: CFNumberFormatterRef) -> CFNumberFormatterStyle; + + /* Getting the CFNumberFormatter Type ID */ + pub fn CFNumberFormatterGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/plugin.rs b/third_party/rust/core-foundation-sys/src/plugin.rs new file mode 100644 index 0000000000..fa236777c2 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/plugin.rs @@ -0,0 +1,99 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::array::CFArrayRef; +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFTypeID}; +use crate::bundle::{CFBundleRef, CFPlugInRef}; +use crate::string::CFStringRef; +use crate::url::CFURLRef; +use crate::uuid::CFUUIDRef; + +#[repr(C)] +pub struct __CFPlugInInstance(c_void); +pub type CFPlugInInstanceRef = *mut __CFPlugInInstance; + +pub type CFPlugInDynamicRegisterFunction = extern "C" fn(plugIn: CFPlugInRef); +pub type CFPlugInUnloadFunction = extern "C" fn(plugIn: CFPlugInRef); +pub type CFPlugInFactoryFunction = + extern "C" fn(allocator: CFAllocatorRef, typeUUID: CFUUIDRef) -> *mut c_void; + +pub type CFPlugInInstanceGetInterfaceFunction = extern "C" fn( + instance: CFPlugInInstanceRef, + interfaceName: CFStringRef, + ftbl: *mut *mut c_void, +) -> Boolean; +pub type CFPlugInInstanceDeallocateInstanceDataFunction = extern "C" fn(instanceData: *mut c_void); + +extern "C" { + /* + * CFPlugIn.h + */ + + /* CFPlugIn */ + /* Information Property List Keys */ + pub static kCFPlugInDynamicRegistrationKey: CFStringRef; + pub static kCFPlugInDynamicRegisterFunctionKey: CFStringRef; + pub static kCFPlugInUnloadFunctionKey: CFStringRef; + pub static kCFPlugInFactoriesKey: CFStringRef; + pub static kCFPlugInTypesKey: CFStringRef; + + /* Creating Plug-ins */ + pub fn CFPlugInCreate(allocator: CFAllocatorRef, plugInURL: CFURLRef) -> CFPlugInRef; + pub fn CFPlugInInstanceCreate( + allocator: CFAllocatorRef, + factoryUUID: CFUUIDRef, + typeUUID: CFUUIDRef, + ) -> *mut c_void; + + /* Registration */ + pub fn CFPlugInRegisterFactoryFunction( + factoryUUID: CFUUIDRef, + func: CFPlugInFactoryFunction, + ) -> Boolean; + pub fn CFPlugInRegisterFactoryFunctionByName( + CfactoryUUID: CFUUIDRef, + plugIn: CFPlugInRef, + functionName: CFStringRef, + ) -> Boolean; + pub fn CFPlugInRegisterPlugInType(factoryUUID: CFUUIDRef, typeUUID: CFUUIDRef) -> Boolean; + pub fn CFPlugInUnregisterFactory(factoryUUID: CFUUIDRef) -> Boolean; + pub fn CFPlugInUnregisterPlugInType(factoryUUID: CFUUIDRef, typeUUID: CFUUIDRef) -> Boolean; + + /* CFPlugIn Miscellaneous Functions */ + pub fn CFPlugInAddInstanceForFactory(factoryID: CFUUIDRef); + pub fn CFPlugInFindFactoriesForPlugInType(typeUUID: CFUUIDRef) -> CFArrayRef; + pub fn CFPlugInFindFactoriesForPlugInTypeInPlugIn( + typeUUID: CFUUIDRef, + plugIn: CFPlugInRef, + ) -> CFArrayRef; + pub fn CFPlugInGetBundle(plugIn: CFPlugInRef) -> CFBundleRef; + pub fn CFPlugInGetTypeID() -> CFTypeID; + pub fn CFPlugInIsLoadOnDemand(plugIn: CFPlugInRef) -> Boolean; + pub fn CFPlugInRemoveInstanceForFactory(factoryID: CFUUIDRef); + pub fn CFPlugInSetLoadOnDemand(plugIn: CFPlugInRef, flag: Boolean); + + /* CFPlugInInstance: deprecated */ + pub fn CFPlugInInstanceCreateWithInstanceDataSize( + allocator: CFAllocatorRef, + instanceDataSize: CFIndex, + deallocateInstanceFunction: CFPlugInInstanceDeallocateInstanceDataFunction, + factoryName: CFStringRef, + getInterfaceFunction: CFPlugInInstanceGetInterfaceFunction, + ) -> CFPlugInInstanceRef; + pub fn CFPlugInInstanceGetFactoryName(instance: CFPlugInInstanceRef) -> CFStringRef; + pub fn CFPlugInInstanceGetInstanceData(instance: CFPlugInInstanceRef) -> *mut c_void; + pub fn CFPlugInInstanceGetInterfaceFunctionTable( + instance: CFPlugInInstanceRef, + interfaceName: CFStringRef, + ftbl: *mut *mut c_void, + ) -> Boolean; + pub fn CFPlugInInstanceGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/preferences.rs b/third_party/rust/core-foundation-sys/src/preferences.rs new file mode 100644 index 0000000000..0899938e58 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/preferences.rs @@ -0,0 +1,103 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::array::CFArrayRef; +use crate::base::{Boolean, CFIndex}; +use crate::dictionary::CFDictionaryRef; +use crate::propertylist::CFPropertyListRef; +use crate::string::CFStringRef; + +extern "C" { + /* + * CFPreferences.h + */ + /* Application, Host, and User Keys */ + pub static kCFPreferencesAnyApplication: CFStringRef; + pub static kCFPreferencesCurrentApplication: CFStringRef; + pub static kCFPreferencesAnyHost: CFStringRef; + pub static kCFPreferencesCurrentHost: CFStringRef; + pub static kCFPreferencesAnyUser: CFStringRef; + pub static kCFPreferencesCurrentUser: CFStringRef; + + /* Getting Preference Values */ + pub fn CFPreferencesCopyAppValue( + key: CFStringRef, + applicationID: CFStringRef, + ) -> CFPropertyListRef; + pub fn CFPreferencesCopyKeyList( + applicationID: CFStringRef, + userName: CFStringRef, + hostName: CFStringRef, + ) -> CFArrayRef; + pub fn CFPreferencesCopyMultiple( + keysToFetch: CFArrayRef, + applicationID: CFStringRef, + userName: CFStringRef, + hostName: CFStringRef, + ) -> CFDictionaryRef; + pub fn CFPreferencesCopyValue( + key: CFStringRef, + applicationID: CFStringRef, + userName: CFStringRef, + hostName: CFStringRef, + ) -> CFPropertyListRef; + pub fn CFPreferencesGetAppBooleanValue( + key: CFStringRef, + applicationID: CFStringRef, + keyExistsAndHasValidFormat: *mut Boolean, + ) -> Boolean; + pub fn CFPreferencesGetAppIntegerValue( + key: CFStringRef, + applicationID: CFStringRef, + keyExistsAndHasValidFormat: *mut Boolean, + ) -> CFIndex; + + /* Setting Preference Values */ + pub fn CFPreferencesSetAppValue( + key: CFStringRef, + value: CFPropertyListRef, + applicationID: CFStringRef, + ); + pub fn CFPreferencesSetMultiple( + keysToSet: CFDictionaryRef, + keysToRemove: CFArrayRef, + applicationID: CFStringRef, + userName: CFStringRef, + hostName: CFStringRef, + ); + pub fn CFPreferencesSetValue( + key: CFStringRef, + value: CFPropertyListRef, + applicationID: CFStringRef, + userName: CFStringRef, + hostName: CFStringRef, + ); + + /* Synchronizing Preferences */ + pub fn CFPreferencesAppSynchronize(applicationID: CFStringRef) -> Boolean; + pub fn CFPreferencesSynchronize( + applicationID: CFStringRef, + userName: CFStringRef, + hostName: CFStringRef, + ) -> Boolean; + + /* Adding and Removing Suite Preferences */ + pub fn CFPreferencesAddSuitePreferencesToApp(applicationID: CFStringRef, suiteID: CFStringRef); + pub fn CFPreferencesRemoveSuitePreferencesFromApp( + applicationID: CFStringRef, + suiteID: CFStringRef, + ); + + /* Miscellaneous Functions */ + pub fn CFPreferencesAppValueIsForced(key: CFStringRef, applicationID: CFStringRef) -> Boolean; + pub fn CFPreferencesCopyApplicationList( + userName: CFStringRef, + hostName: CFStringRef, + ) -> CFArrayRef; // deprecated since macos 10.9 +} diff --git a/third_party/rust/core-foundation-sys/src/propertylist.rs b/third_party/rust/core-foundation-sys/src/propertylist.rs index 574c4d13f3..d4ceb1b0c0 100644 --- a/third_party/rust/core-foundation-sys/src/propertylist.rs +++ b/third_party/rust/core-foundation-sys/src/propertylist.rs @@ -7,9 +7,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeRef}; -use data::CFDataRef; -use error::CFErrorRef; +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeRef}; +use crate::data::CFDataRef; +use crate::error::CFErrorRef; +use crate::stream::{CFReadStreamRef, CFWriteStreamRef}; +use crate::string::CFStringRef; pub type CFPropertyListRef = CFTypeRef; @@ -23,24 +25,80 @@ pub const kCFPropertyListImmutable: CFPropertyListMutabilityOptions = 0; pub const kCFPropertyListMutableContainers: CFPropertyListMutabilityOptions = 1; pub const kCFPropertyListMutableContainersAndLeaves: CFPropertyListMutabilityOptions = 2; +/* Reading and Writing Error Codes */ +pub const kCFPropertyListReadCorruptError: CFIndex = 3840; +pub const kCFPropertyListReadUnknownVersionError: CFIndex = 3841; +pub const kCFPropertyListReadStreamError: CFIndex = 3842; +pub const kCFPropertyListWriteStreamError: CFIndex = 3851; + extern "C" { - // CFPropertyList.h - // - - // fn CFPropertyListCreateDeepCopy - // fn CFPropertyListIsValid - pub fn CFPropertyListCreateWithData(allocator: CFAllocatorRef, - data: CFDataRef, - options: CFPropertyListMutabilityOptions, - format: *mut CFPropertyListFormat, - error: *mut CFErrorRef) - -> CFPropertyListRef; - // fn CFPropertyListCreateWithStream - // fn CFPropertyListWrite - pub fn CFPropertyListCreateData(allocator: CFAllocatorRef, - propertyList: CFPropertyListRef, - format: CFPropertyListFormat, - options: CFOptionFlags, - error: *mut CFErrorRef) - -> CFDataRef; + /* + * CFPropertyList.h + */ + + /* Creating a Property List */ + pub fn CFPropertyListCreateWithData( + allocator: CFAllocatorRef, + data: CFDataRef, + options: CFPropertyListMutabilityOptions, + format: *mut CFPropertyListFormat, + error: *mut CFErrorRef, + ) -> CFPropertyListRef; + pub fn CFPropertyListCreateWithStream( + allocator: CFAllocatorRef, + stream: CFReadStreamRef, + streamLength: CFIndex, + options: CFOptionFlags, + format: *mut CFPropertyListFormat, + error: *mut CFErrorRef, + ) -> CFPropertyListRef; + pub fn CFPropertyListCreateDeepCopy( + allocator: CFAllocatorRef, + propertyList: CFPropertyListRef, + mutabilityOption: CFOptionFlags, + ) -> CFPropertyListRef; + pub fn CFPropertyListCreateFromXMLData( + allocator: CFAllocatorRef, + xmlData: CFDataRef, + mutabilityOption: CFOptionFlags, + errorString: *mut CFStringRef, + ) -> CFPropertyListRef; // deprecated + pub fn CFPropertyListCreateFromStream( + allocator: CFAllocatorRef, + stream: CFReadStreamRef, + streamLength: CFIndex, + mutabilityOption: CFOptionFlags, + format: *mut CFPropertyListFormat, + errorString: *mut CFStringRef, + ) -> CFPropertyListRef; // deprecated + + /* Exporting a Property List */ + pub fn CFPropertyListCreateData( + allocator: CFAllocatorRef, + propertyList: CFPropertyListRef, + format: CFPropertyListFormat, + options: CFOptionFlags, + error: *mut CFErrorRef, + ) -> CFDataRef; + pub fn CFPropertyListWrite( + propertyList: CFPropertyListRef, + stream: CFWriteStreamRef, + format: CFPropertyListFormat, + options: CFOptionFlags, + error: *mut CFErrorRef, + ) -> CFIndex; + pub fn CFPropertyListCreateXMLData( + allocator: CFAllocatorRef, + propertyList: CFPropertyListRef, + ) -> CFDataRef; // deprecated + pub fn CFPropertyListWriteToStream( + propertyList: CFPropertyListRef, + stream: CFWriteStreamRef, + format: CFPropertyListFormat, + errorString: *mut CFStringRef, + ) -> CFIndex; + + /* Validating a Property List */ + pub fn CFPropertyListIsValid(plist: CFPropertyListRef, format: CFPropertyListFormat) + -> Boolean; } diff --git a/third_party/rust/core-foundation-sys/src/runloop.rs b/third_party/rust/core-foundation-sys/src/runloop.rs index 53035a2e75..5d5fda7a01 100644 --- a/third_party/rust/core-foundation-sys/src/runloop.rs +++ b/third_party/rust/core-foundation-sys/src/runloop.rs @@ -9,10 +9,12 @@ use std::os::raw::c_void; -use array::CFArrayRef; -use base::{Boolean, CFIndex, CFTypeID, CFAllocatorRef, CFOptionFlags, CFHashCode, mach_port_t}; -use date::{CFAbsoluteTime, CFTimeInterval}; -use string::CFStringRef; +use crate::array::CFArrayRef; +use crate::base::{ + mach_port_t, Boolean, CFAllocatorRef, CFHashCode, CFIndex, CFOptionFlags, CFTypeID, +}; +use crate::date::{CFAbsoluteTime, CFTimeInterval}; +use crate::string::CFStringRef; #[repr(C)] pub struct __CFRunLoop(c_void); @@ -30,135 +32,225 @@ pub struct __CFRunLoopObserver(c_void); pub type CFRunLoopObserverRef = *mut __CFRunLoopObserver; // Reasons for CFRunLoopRunInMode() to Return -pub const kCFRunLoopRunFinished: i32 = 1; -pub const kCFRunLoopRunStopped: i32 = 2; -pub const kCFRunLoopRunTimedOut: i32 = 3; +pub const kCFRunLoopRunFinished: i32 = 1; +pub const kCFRunLoopRunStopped: i32 = 2; +pub const kCFRunLoopRunTimedOut: i32 = 3; pub const kCFRunLoopRunHandledSource: i32 = 4; // Run Loop Observer Activities //typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { pub type CFRunLoopActivity = CFOptionFlags; -pub const kCFRunLoopEntry: CFOptionFlags = 1 << 0; -pub const kCFRunLoopBeforeTimers: CFOptionFlags = 1 << 1; +pub const kCFRunLoopEntry: CFOptionFlags = 1 << 0; +pub const kCFRunLoopBeforeTimers: CFOptionFlags = 1 << 1; pub const kCFRunLoopBeforeSources: CFOptionFlags = 1 << 2; pub const kCFRunLoopBeforeWaiting: CFOptionFlags = 1 << 5; -pub const kCFRunLoopAfterWaiting: CFOptionFlags = 1 << 6; -pub const kCFRunLoopExit: CFOptionFlags = 1 << 7; +pub const kCFRunLoopAfterWaiting: CFOptionFlags = 1 << 6; +pub const kCFRunLoopExit: CFOptionFlags = 1 << 7; pub const kCFRunLoopAllActivities: CFOptionFlags = 0x0FFFFFFF; #[repr(C)] +#[derive(Debug, Clone, Copy)] pub struct CFRunLoopSourceContext { pub version: CFIndex, pub info: *mut c_void, - pub retain: Option *const c_void>, - pub release: Option, - pub copyDescription: Option CFStringRef>, - pub equal: Option Boolean>, - pub hash: Option CFHashCode>, - pub schedule: Option, - pub cancel: Option, - pub perform: extern "C" fn (info: *const c_void), + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, + pub equal: Option Boolean>, + pub hash: Option CFHashCode>, + pub schedule: Option, + pub cancel: Option, + pub perform: extern "C" fn(info: *const c_void), } #[repr(C)] +#[derive(Debug, Clone, Copy)] pub struct CFRunLoopSourceContext1 { pub version: CFIndex, pub info: *mut c_void, - pub retain: Option *const c_void>, - pub release: Option, - pub copyDescription: Option CFStringRef>, - pub equal: Option Boolean>, - pub hash: Option CFHashCode>, - // note that the following two fields are platform dependent in the C header, the ones here are for macOS - pub getPort: extern "C" fn (info: *mut c_void) -> mach_port_t, - pub perform: extern "C" fn (msg: *mut c_void, size: CFIndex, allocator: CFAllocatorRef, info: *mut c_void) -> *mut c_void, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, + pub equal: Option Boolean>, + pub hash: Option CFHashCode>, + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub getPort: extern "C" fn(info: *mut c_void) -> mach_port_t, + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub perform: extern "C" fn( + msg: *mut c_void, + size: CFIndex, + allocator: CFAllocatorRef, + info: *mut c_void, + ) -> *mut c_void, + + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + pub getPort: extern "C" fn(info: *mut c_void) -> *mut c_void, + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + pub perform: extern "C" fn(info: *mut c_void) -> *mut c_void, } #[repr(C)] +#[derive(Debug, Clone, Copy)] pub struct CFRunLoopObserverContext { pub version: CFIndex, pub info: *mut c_void, - pub retain: Option *const c_void>, - pub release: Option, - pub copyDescription: Option CFStringRef>, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, } -pub type CFRunLoopObserverCallBack = extern "C" fn (observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); +pub type CFRunLoopObserverCallBack = + extern "C" fn(observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); #[repr(C)] +#[derive(Clone, Copy, Debug)] pub struct CFRunLoopTimerContext { pub version: CFIndex, pub info: *mut c_void, - pub retain: Option *const c_void>, - pub release: Option, - pub copyDescription: Option CFStringRef>, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, } -pub type CFRunLoopTimerCallBack = extern "C" fn (timer: CFRunLoopTimerRef, info: *mut c_void); +pub type CFRunLoopTimerCallBack = extern "C" fn(timer: CFRunLoopTimerRef, info: *mut c_void); #[repr(C)] pub struct __CFRunLoopTimer(c_void); pub type CFRunLoopTimerRef = *mut __CFRunLoopTimer; -extern { +extern "C" { /* * CFRunLoop.h */ + pub static kCFRunLoopDefaultMode: CFStringRef; pub static kCFRunLoopCommonModes: CFStringRef; - pub fn CFRunLoopGetTypeID() -> CFTypeID; + + /* CFRunLoop */ + /* Getting a Run Loop */ pub fn CFRunLoopGetCurrent() -> CFRunLoopRef; pub fn CFRunLoopGetMain() -> CFRunLoopRef; - pub fn CFRunLoopCopyCurrentMode(rl: CFRunLoopRef) -> CFStringRef; - pub fn CFRunLoopCopyAllModes(rl: CFRunLoopRef) -> CFArrayRef; - pub fn CFRunLoopAddCommonMode(rl: CFRunLoopRef, mode: CFStringRef); - pub fn CFRunLoopGetNextTimerFireDate(rl: CFRunLoopRef, mode: CFStringRef) -> CFAbsoluteTime; + + /* Starting and Stopping a Run Loop */ pub fn CFRunLoopRun(); - pub fn CFRunLoopRunInMode(mode: CFStringRef, seconds: CFTimeInterval, returnAfterSourceHandled: Boolean) -> i32; - pub fn CFRunLoopIsWaiting(rl: CFRunLoopRef) -> Boolean; + pub fn CFRunLoopRunInMode( + mode: CFStringRef, + seconds: CFTimeInterval, + returnAfterSourceHandled: Boolean, + ) -> i32; pub fn CFRunLoopWakeUp(rl: CFRunLoopRef); pub fn CFRunLoopStop(rl: CFRunLoopRef); - // fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: void (^)(void)); - pub fn CFRunLoopContainsSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef) -> Boolean; + pub fn CFRunLoopIsWaiting(rl: CFRunLoopRef) -> Boolean; + + /* Managing Sources */ pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); + pub fn CFRunLoopContainsSource( + rl: CFRunLoopRef, + source: CFRunLoopSourceRef, + mode: CFStringRef, + ) -> Boolean; pub fn CFRunLoopRemoveSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); - pub fn CFRunLoopContainsObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef) -> Boolean; - pub fn CFRunLoopAddObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); - pub fn CFRunLoopRemoveObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); - pub fn CFRunLoopContainsTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef) -> Boolean; + + /* Managing Observers */ + pub fn CFRunLoopAddObserver( + rl: CFRunLoopRef, + observer: CFRunLoopObserverRef, + mode: CFStringRef, + ); + pub fn CFRunLoopContainsObserver( + rl: CFRunLoopRef, + observer: CFRunLoopObserverRef, + mode: CFStringRef, + ) -> Boolean; + pub fn CFRunLoopRemoveObserver( + rl: CFRunLoopRef, + observer: CFRunLoopObserverRef, + mode: CFStringRef, + ); + + /* Managing Run Loop Modes */ + pub fn CFRunLoopAddCommonMode(rl: CFRunLoopRef, mode: CFStringRef); + pub fn CFRunLoopCopyAllModes(rl: CFRunLoopRef) -> CFArrayRef; + pub fn CFRunLoopCopyCurrentMode(rl: CFRunLoopRef) -> CFStringRef; + + /* Managing Timers */ pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); + pub fn CFRunLoopGetNextTimerFireDate(rl: CFRunLoopRef, mode: CFStringRef) -> CFAbsoluteTime; pub fn CFRunLoopRemoveTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); + pub fn CFRunLoopContainsTimer( + rl: CFRunLoopRef, + timer: CFRunLoopTimerRef, + mode: CFStringRef, + ) -> Boolean; - pub fn CFRunLoopSourceGetTypeID() -> CFTypeID; - pub fn CFRunLoopSourceCreate(allocator: CFAllocatorRef, order: CFIndex, context: *mut CFRunLoopSourceContext) -> CFRunLoopSourceRef; + /* Scheduling Blocks */ + // fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: void (^)(void)); + + /* Getting the CFRunLoop Type ID */ + pub fn CFRunLoopGetTypeID() -> CFTypeID; + + /* CFRunLoopSource */ + /* CFRunLoopSource Miscellaneous Functions */ + pub fn CFRunLoopSourceCreate( + allocator: CFAllocatorRef, + order: CFIndex, + context: *mut CFRunLoopSourceContext, + ) -> CFRunLoopSourceRef; + pub fn CFRunLoopSourceGetContext( + source: CFRunLoopSourceRef, + context: *mut CFRunLoopSourceContext, + ); pub fn CFRunLoopSourceGetOrder(source: CFRunLoopSourceRef) -> CFIndex; + pub fn CFRunLoopSourceGetTypeID() -> CFTypeID; pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef); pub fn CFRunLoopSourceIsValid(source: CFRunLoopSourceRef) -> Boolean; - pub fn CFRunLoopSourceGetContext(source: CFRunLoopSourceRef, context: *mut CFRunLoopSourceContext); pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef); - pub fn CFRunLoopObserverGetTypeID() -> CFTypeID; - pub fn CFRunLoopObserverCreate(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, callout: CFRunLoopObserverCallBack, context: *mut CFRunLoopObserverContext) -> CFRunLoopObserverRef; + /* CFRunLoopObserver */ + /* CFRunLoopObserver Miscellaneous Functions */ // fn CFRunLoopObserverCreateWithHandler(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, block: void (^) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) -> CFRunLoopObserverRef; - pub fn CFRunLoopObserverGetActivities(observer: CFRunLoopObserverRef) -> CFOptionFlags; + pub fn CFRunLoopObserverCreate( + allocator: CFAllocatorRef, + activities: CFOptionFlags, + repeats: Boolean, + order: CFIndex, + callout: CFRunLoopObserverCallBack, + context: *mut CFRunLoopObserverContext, + ) -> CFRunLoopObserverRef; pub fn CFRunLoopObserverDoesRepeat(observer: CFRunLoopObserverRef) -> Boolean; + pub fn CFRunLoopObserverGetActivities(observer: CFRunLoopObserverRef) -> CFOptionFlags; + pub fn CFRunLoopObserverGetContext( + observer: CFRunLoopObserverRef, + context: *mut CFRunLoopObserverContext, + ); pub fn CFRunLoopObserverGetOrder(observer: CFRunLoopObserverRef) -> CFIndex; + pub fn CFRunLoopObserverGetTypeID() -> CFTypeID; pub fn CFRunLoopObserverInvalidate(observer: CFRunLoopObserverRef); pub fn CFRunLoopObserverIsValid(observer: CFRunLoopObserverRef) -> Boolean; - pub fn CFRunLoopObserverGetContext(observer: CFRunLoopObserverRef, context: *mut CFRunLoopObserverContext); - pub fn CFRunLoopTimerGetTypeID() -> CFTypeID; - pub fn CFRunLoopTimerCreate(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimerRef; + /* CFRunLoopTimer */ + /* CFRunLoopTimer Miscellaneous Functions */ // fn CFRunLoopTimerCreateWithHandler(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, block: void (^) (CFRunLoopTimerRef timer)) -> CFRunLoopTimerRef; - pub fn CFRunLoopTimerGetNextFireDate(timer: CFRunLoopTimerRef) -> CFAbsoluteTime; - pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); - pub fn CFRunLoopTimerGetInterval(timer: CFRunLoopTimerRef) -> CFTimeInterval; + pub fn CFRunLoopTimerCreate( + allocator: CFAllocatorRef, + fireDate: CFAbsoluteTime, + interval: CFTimeInterval, + flags: CFOptionFlags, + order: CFIndex, + callout: CFRunLoopTimerCallBack, + context: *mut CFRunLoopTimerContext, + ) -> CFRunLoopTimerRef; pub fn CFRunLoopTimerDoesRepeat(timer: CFRunLoopTimerRef) -> Boolean; + pub fn CFRunLoopTimerGetContext(timer: CFRunLoopTimerRef, context: *mut CFRunLoopTimerContext); + pub fn CFRunLoopTimerGetInterval(timer: CFRunLoopTimerRef) -> CFTimeInterval; + pub fn CFRunLoopTimerGetNextFireDate(timer: CFRunLoopTimerRef) -> CFAbsoluteTime; pub fn CFRunLoopTimerGetOrder(timer: CFRunLoopTimerRef) -> CFIndex; + pub fn CFRunLoopTimerGetTypeID() -> CFTypeID; pub fn CFRunLoopTimerInvalidate(timer: CFRunLoopTimerRef); pub fn CFRunLoopTimerIsValid(timer: CFRunLoopTimerRef) -> Boolean; - pub fn CFRunLoopTimerGetContext(timer: CFRunLoopTimerRef, context: *mut CFRunLoopTimerContext); - pub fn CFRunLoopTimerGetTolerance(timer: CFRunLoopTimerRef) -> CFTimeInterval; - pub fn CFRunLoopTimerSetTolerance(timer: CFRunLoopTimerRef, tolerance: CFTimeInterval); + pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); + pub fn CFRunLoopTimerGetTolerance(timer: CFRunLoopTimerRef) -> CFTimeInterval; //macos(10.9)+ + pub fn CFRunLoopTimerSetTolerance(timer: CFRunLoopTimerRef, tolerance: CFTimeInterval); //macos(10.9)+ } diff --git a/third_party/rust/core-foundation-sys/src/set.rs b/third_party/rust/core-foundation-sys/src/set.rs index a5cc1b16f7..8141c5999d 100644 --- a/third_party/rust/core-foundation-sys/src/set.rs +++ b/third_party/rust/core-foundation-sys/src/set.rs @@ -9,15 +9,17 @@ use std::os::raw::c_void; -use base::{CFAllocatorRef, CFIndex, CFTypeID, Boolean}; +use crate::base::{Boolean, CFAllocatorRef, CFHashCode, CFIndex, CFTypeID}; +use crate::string::CFStringRef; -pub type CFSetApplierFunction = extern "C" fn (value: *const c_void, - context: *const c_void); -pub type CFSetRetainCallBack = *const u8; -pub type CFSetReleaseCallBack = *const u8; -pub type CFSetCopyDescriptionCallBack = *const u8; -pub type CFSetEqualCallBack = *const u8; -pub type CFSetHashCallBack = *const u8; +pub type CFSetApplierFunction = extern "C" fn(value: *const c_void, context: *const c_void); +pub type CFSetRetainCallBack = + extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; +pub type CFSetReleaseCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void); +pub type CFSetCopyDescriptionCallBack = extern "C" fn(value: *const c_void) -> CFStringRef; +pub type CFSetEqualCallBack = + extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; +pub type CFSetHashCallBack = extern "C" fn(value: *const c_void) -> CFHashCode; #[repr(C)] #[derive(Clone, Copy)] @@ -34,17 +36,24 @@ pub struct CFSetCallBacks { pub struct __CFSet(c_void); pub type CFSetRef = *const __CFSet; +pub type CFMutableSetRef = *mut __CFSet; -extern { +extern "C" { /* * CFSet.h */ pub static kCFTypeSetCallBacks: CFSetCallBacks; + pub static kCFCopyStringSetCallBacks: CFSetCallBacks; + /* CFSet */ /* Creating Sets */ - pub fn CFSetCreate(allocator: CFAllocatorRef, values: *const *const c_void, numValues: CFIndex, - callBacks: *const CFSetCallBacks) -> CFSetRef; + pub fn CFSetCreate( + allocator: CFAllocatorRef, + values: *const *const c_void, + numValues: CFIndex, + callBacks: *const CFSetCallBacks, + ) -> CFSetRef; pub fn CFSetCreateCopy(allocator: CFAllocatorRef, theSet: CFSetRef) -> CFSetRef; /* Examining a Set */ @@ -52,15 +61,38 @@ extern { pub fn CFSetGetCount(theSet: CFSetRef) -> CFIndex; pub fn CFSetGetCountOfValue(theSet: CFSetRef, value: *const c_void) -> CFIndex; pub fn CFSetGetValue(theSet: CFSetRef, value: *const c_void) -> *const c_void; - pub fn CFSetGetValueIfPresent(theSet: CFSetRef, candidate: *const c_void, value: *mut *const c_void) -> Boolean; + pub fn CFSetGetValueIfPresent( + theSet: CFSetRef, + candidate: *const c_void, + value: *mut *const c_void, + ) -> Boolean; pub fn CFSetGetValues(theSet: CFSetRef, values: *mut *const c_void); /* Applying a Function to Set Members */ - pub fn CFSetApplyFunction(theSet: CFSetRef, - applier: CFSetApplierFunction, - context: *const c_void); + pub fn CFSetApplyFunction( + theSet: CFSetRef, + applier: CFSetApplierFunction, + context: *const c_void, + ); /* Getting the CFSet Type ID */ pub fn CFSetGetTypeID() -> CFTypeID; -} + /* CFMutableSet */ + /* CFMutableSet Miscellaneous Functions */ + pub fn CFSetAddValue(theSet: CFMutableSetRef, value: *const c_void); + pub fn CFSetCreateMutable( + allocator: CFAllocatorRef, + capacity: CFIndex, + callBacks: *const CFSetCallBacks, + ) -> CFMutableSetRef; + pub fn CFSetCreateMutableCopy( + allocator: CFAllocatorRef, + capacity: CFIndex, + theSet: CFSetRef, + ) -> CFMutableSetRef; + pub fn CFSetRemoveAllValues(theSet: CFMutableSetRef); + pub fn CFSetRemoveValue(theSet: CFMutableSetRef, value: *const c_void); + pub fn CFSetReplaceValue(theSet: CFMutableSetRef, value: *const c_void); + pub fn CFSetSetValue(theSet: CFMutableSetRef, value: *const c_void); +} diff --git a/third_party/rust/core-foundation-sys/src/socket.rs b/third_party/rust/core-foundation-sys/src/socket.rs new file mode 100644 index 0000000000..6fb70a1080 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/socket.rs @@ -0,0 +1,188 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeID, SInt32, UInt16}; +use crate::data::CFDataRef; +use crate::date::CFTimeInterval; +use crate::propertylist::CFPropertyListRef; +use crate::runloop::CFRunLoopSourceRef; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFSocket(c_void); + +pub type CFSocketRef = *mut __CFSocket; + +pub type CFSocketError = CFIndex; +pub type CFSocketCallBackType = CFOptionFlags; +pub type CFSocketCallBack = extern "C" fn( + s: CFSocketRef, + _type: CFSocketCallBackType, + address: CFDataRef, + cdata: *const c_void, + info: *mut c_void, +); +#[cfg(not(target_os = "windows"))] +pub type CFSocketNativeHandle = std::os::raw::c_int; +#[cfg(target_os = "windows")] +pub type CFSocketNativeHandle = std::os::raw::c_ulong; + +pub const kCFSocketSuccess: CFSocketError = 0; +pub const kCFSocketError: CFSocketError = -1; +pub const kCFSocketTimeout: CFSocketError = -2; + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct CFSocketSignature { + pub protocolFamily: SInt32, + pub socketType: SInt32, + pub protocol: SInt32, + pub address: CFDataRef, +} + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct CFSocketContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn(info: *const c_void) -> *const c_void, + pub release: extern "C" fn(info: *const c_void), + pub copyDescription: extern "C" fn(info: *const c_void) -> CFStringRef, +} + +pub const kCFSocketNoCallBack: CFSocketError = 0; +pub const kCFSocketReadCallBack: CFSocketError = 1; +pub const kCFSocketAcceptCallBack: CFSocketError = 2; +pub const kCFSocketDataCallBack: CFSocketError = 3; +pub const kCFSocketConnectCallBack: CFSocketError = 4; +pub const kCFSocketWriteCallBack: CFSocketError = 8; + +pub const kCFSocketAutomaticallyReenableReadCallBack: CFOptionFlags = 1; +pub const kCFSocketAutomaticallyReenableAcceptCallBack: CFOptionFlags = 2; +pub const kCFSocketAutomaticallyReenableDataCallBack: CFOptionFlags = 3; +pub const kCFSocketAutomaticallyReenableWriteCallBack: CFOptionFlags = 8; +pub const kCFSocketLeaveErrors: CFOptionFlags = 64; +pub const kCFSocketCloseOnInvalidate: CFOptionFlags = 128; + +extern "C" { + /* + * CFSocket.h + */ + + /* CFSocket Name Server Keys: Not used */ + pub static kCFSocketCommandKey: CFStringRef; + pub static kCFSocketNameKey: CFStringRef; + pub static kCFSocketValueKey: CFStringRef; + pub static kCFSocketResultKey: CFStringRef; + pub static kCFSocketErrorKey: CFStringRef; + pub static kCFSocketRegisterCommand: CFStringRef; + pub static kCFSocketRetrieveCommand: CFStringRef; + + /* Creating Sockets */ + pub fn CFSocketCreate( + allocator: CFAllocatorRef, + protocolFamily: SInt32, + socketType: SInt32, + protocol: SInt32, + callBackTypes: CFOptionFlags, + callout: CFSocketCallBack, + context: *const CFSocketContext, + ) -> CFSocketRef; + pub fn CFSocketCreateConnectedToSocketSignature( + allocator: CFAllocatorRef, + signature: *const CFSocketSignature, + callBackTypes: CFOptionFlags, + callout: CFSocketCallBack, + context: *const CFSocketContext, + timeout: CFTimeInterval, + ) -> CFSocketRef; + pub fn CFSocketCreateWithNative( + allocator: CFAllocatorRef, + sock: CFSocketNativeHandle, + callBackTypes: CFOptionFlags, + callout: CFSocketCallBack, + context: *const CFSocketContext, + ) -> CFSocketRef; + pub fn CFSocketCreateWithSocketSignature( + allocator: CFAllocatorRef, + signature: *const CFSocketSignature, + callBackTypes: CFOptionFlags, + callout: CFSocketCallBack, + context: *const CFSocketContext, + ) -> CFSocketRef; + + /* Configuring Sockets */ + pub fn CFSocketCopyAddress(s: CFSocketRef) -> CFDataRef; + pub fn CFSocketCopyPeerAddress(s: CFSocketRef) -> CFDataRef; + pub fn CFSocketDisableCallBacks(s: CFSocketRef, callBackTypes: CFOptionFlags); + pub fn CFSocketEnableCallBacks(s: CFSocketRef, callBackTypes: CFOptionFlags); + pub fn CFSocketGetContext(s: CFSocketRef, context: *mut CFSocketContext); + pub fn CFSocketGetNative(s: CFSocketRef) -> CFSocketNativeHandle; + pub fn CFSocketGetSocketFlags(s: CFSocketRef) -> CFOptionFlags; + pub fn CFSocketSetAddress(s: CFSocketRef, address: CFDataRef) -> CFSocketError; + pub fn CFSocketSetSocketFlags(s: CFSocketRef, flags: CFOptionFlags); + + /* Using Sockets */ + pub fn CFSocketConnectToAddress( + s: CFSocketRef, + address: CFDataRef, + timeout: CFTimeInterval, + ) -> CFSocketError; + pub fn CFSocketCreateRunLoopSource( + allocator: CFAllocatorRef, + s: CFSocketRef, + order: CFIndex, + ) -> CFRunLoopSourceRef; + pub fn CFSocketGetTypeID() -> CFTypeID; + pub fn CFSocketInvalidate(s: CFSocketRef); + pub fn CFSocketIsValid(s: CFSocketRef) -> Boolean; + pub fn CFSocketSendData( + s: CFSocketRef, + address: CFDataRef, + data: CFDataRef, + timeout: CFTimeInterval, + ) -> CFSocketError; + + /* Socket Name Server Utilities */ + pub fn CFSocketCopyRegisteredSocketSignature( + nameServerSignature: *const CFSocketSignature, + timeout: CFTimeInterval, + name: CFStringRef, + signature: *mut CFSocketSignature, + nameServerAddress: *mut CFDataRef, + ) -> CFSocketError; + pub fn CFSocketCopyRegisteredValue( + nameServerSignature: *const CFSocketSignature, + timeout: CFTimeInterval, + name: CFStringRef, + value: *mut CFPropertyListRef, + nameServerAddress: *mut CFDataRef, + ) -> CFSocketError; + pub fn CFSocketGetDefaultNameRegistryPortNumber() -> UInt16; + pub fn CFSocketRegisterSocketSignature( + nameServerSignature: *const CFSocketSignature, + timeout: CFTimeInterval, + name: CFStringRef, + signature: *const CFSocketSignature, + ) -> CFSocketError; + pub fn CFSocketRegisterValue( + nameServerSignature: *const CFSocketSignature, + timeout: CFTimeInterval, + name: CFStringRef, + value: CFPropertyListRef, + ) -> CFSocketError; + pub fn CFSocketSetDefaultNameRegistryPortNumber(port: UInt16); + pub fn CFSocketUnregister( + nameServerSignature: *const CFSocketSignature, + timeout: CFTimeInterval, + name: CFStringRef, + ) -> CFSocketError; +} diff --git a/third_party/rust/core-foundation-sys/src/stream.rs b/third_party/rust/core-foundation-sys/src/stream.rs new file mode 100644 index 0000000000..922700e489 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/stream.rs @@ -0,0 +1,281 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::{c_int, c_void}; + +use crate::base::{ + Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeID, CFTypeRef, SInt32, UInt32, UInt8, +}; +use crate::error::CFErrorRef; +use crate::runloop::CFRunLoopRef; +use crate::socket::{CFSocketNativeHandle, CFSocketSignature}; +use crate::string::CFStringRef; +use crate::url::CFURLRef; + +#[repr(C)] +pub struct __CFReadStream(c_void); + +#[repr(C)] +pub struct __CFWriteStream(c_void); + +pub type CFReadStreamRef = *mut __CFReadStream; +pub type CFWriteStreamRef = *mut __CFWriteStream; +pub type CFStreamPropertyKey = CFStringRef; +pub type CFStreamStatus = CFIndex; +pub type CFStreamEventType = CFOptionFlags; +pub type CFStreamErrorDomain = CFIndex; + +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CFStreamError { + pub domain: CFIndex, + pub error: SInt32, +} + +/* CFStreamStatus: Constants that describe the status of a stream */ +pub const kCFStreamStatusNotOpen: CFStreamStatus = 0; +pub const kCFStreamStatusOpening: CFStreamStatus = 1; +pub const kCFStreamStatusOpen: CFStreamStatus = 2; +pub const kCFStreamStatusReading: CFStreamStatus = 3; +pub const kCFStreamStatusWriting: CFStreamStatus = 4; +pub const kCFStreamStatusAtEnd: CFStreamStatus = 5; +pub const kCFStreamStatusClosed: CFStreamStatus = 6; +pub const kCFStreamStatusError: CFStreamStatus = 7; + +// deprecated +pub const kCFStreamErrorDomainCustom: CFStreamErrorDomain = -1; +pub const kCFStreamErrorDomainPOSIX: CFStreamErrorDomain = 1; +pub const kCFStreamErrorDomainMacOSStatus: CFStreamErrorDomain = 2; + +/* CFStreamEventType: Defines constants for stream-related events */ +pub const kCFStreamEventNone: CFStreamEventType = 0; +pub const kCFStreamEventOpenCompleted: CFStreamEventType = 1; +pub const kCFStreamEventHasBytesAvailable: CFStreamEventType = 2; +pub const kCFStreamEventCanAcceptBytes: CFStreamEventType = 4; +pub const kCFStreamEventErrorOccurred: CFStreamEventType = 8; +pub const kCFStreamEventEndEncountered: CFStreamEventType = 16; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFStreamClientContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn(info: *const c_void) -> *const c_void, + pub release: extern "C" fn(info: *const c_void), + pub copyDescription: extern "C" fn(info: *const c_void) -> CFStringRef, +} + +pub type CFReadStreamClientCallBack = extern "C" fn( + stream: CFReadStreamRef, + _type: CFStreamEventType, + clientCallBackInfo: *mut c_void, +); +pub type CFWriteStreamClientCallBack = extern "C" fn( + stream: CFWriteStreamRef, + _type: CFStreamEventType, + clientCallBackInfo: *mut c_void, +); + +extern "C" { + /* + * CFStream.h + */ + + /* Stream Properties */ + pub static kCFStreamPropertyAppendToFile: CFStreamPropertyKey; + pub static kCFStreamPropertyDataWritten: CFStreamPropertyKey; + pub static kCFStreamPropertyFileCurrentOffset: CFStreamPropertyKey; + pub static kCFStreamPropertySocketNativeHandle: CFStreamPropertyKey; + pub static kCFStreamPropertySocketRemoteHostName: CFStreamPropertyKey; + pub static kCFStreamPropertySocketRemotePortNumber: CFStreamPropertyKey; + pub static kCFStreamPropertyShouldCloseNativeSocket: CFStringRef; + pub static kCFStreamPropertySocketSecurityLevel: CFStringRef; + + /* CFStream Socket Security Level Constants */ + pub static kCFStreamSocketSecurityLevelNone: CFStringRef; + pub static kCFStreamSocketSecurityLevelSSLv2: CFStringRef; + pub static kCFStreamSocketSecurityLevelSSLv3: CFStringRef; + pub static kCFStreamSocketSecurityLevelTLSv1: CFStringRef; + pub static kCFStreamSocketSecurityLevelNegotiatedSSL: CFStringRef; + + /* CFStream SOCKS Proxy Key Constants */ + pub static kCFStreamPropertySOCKSProxy: CFStringRef; + pub static kCFStreamPropertySOCKSProxyHost: CFStringRef; + pub static kCFStreamPropertySOCKSProxyPort: CFStringRef; + pub static kCFStreamPropertySOCKSVersion: CFStringRef; + pub static kCFStreamSocketSOCKSVersion4: CFStringRef; + pub static kCFStreamSocketSOCKSVersion5: CFStringRef; + pub static kCFStreamPropertySOCKSUser: CFStringRef; + pub static kCFStreamPropertySOCKSPassword: CFStringRef; + + /* CFStream Error Domain Constants (CFHost) */ + pub static kCFStreamErrorDomainSOCKS: c_int; + pub static kCFStreamErrorDomainSSL: c_int; + + /* CFStream: Creating Streams */ + pub fn CFStreamCreatePairWithPeerSocketSignature( + alloc: CFAllocatorRef, + signature: *const CFSocketSignature, + readStream: *mut CFReadStreamRef, + writeStream: *mut CFWriteStreamRef, + ); // deprecated + pub fn CFStreamCreatePairWithSocketToHost( + alloc: CFAllocatorRef, + host: CFStringRef, + port: UInt32, + readStream: *mut CFReadStreamRef, + writeStream: *mut CFWriteStreamRef, + ); // deprecated + pub fn CFStreamCreatePairWithSocket( + alloc: CFAllocatorRef, + sock: CFSocketNativeHandle, + readStream: *mut CFReadStreamRef, + writeStream: *mut CFWriteStreamRef, + ); // deprecated + pub fn CFStreamCreateBoundPair( + alloc: CFAllocatorRef, + readStream: *mut CFReadStreamRef, + writeStream: *mut CFWriteStreamRef, + transferBufferSize: CFIndex, + ); + + //pub fn CFReadStreamSetDispatchQueue(stream: CFReadStreamRef, q: dispatch_queue_t); // macos(10.9)+ + //pub fn CFWriteStreamSetDispatchQueue(stream: CFWriteStreamRef, q: dispatch_queue_t); // macos(10.9)+ + //pub fn CFReadStreamCopyDispatchQueue(stream: CFReadStreamRef) -> dispatch_queue_t; // macos(10.9)+ + //pub fn CFWriteStreamCopyDispatchQueue(stream: CFReadStreamRef) -> dispatch_queue_t; // macos(10.9)+ + + /* CFReadStream */ + /* Creating a Read Stream */ + pub fn CFReadStreamCreateWithBytesNoCopy( + alloc: CFAllocatorRef, + bytes: *const UInt8, + length: CFIndex, + bytesDeallocator: CFAllocatorRef, + ) -> CFReadStreamRef; + pub fn CFReadStreamCreateWithFile(alloc: CFAllocatorRef, fileURL: CFURLRef) -> CFReadStreamRef; + + /* Opening and Closing a Read Stream */ + pub fn CFReadStreamClose(stream: CFReadStreamRef); + pub fn CFReadStreamOpen(stream: CFReadStreamRef) -> Boolean; + + /* Reading from a Stream */ + pub fn CFReadStreamRead( + stream: CFReadStreamRef, + buffer: *mut UInt8, + bufferLength: CFIndex, + ) -> CFIndex; + + /* Scheduling a Read Stream */ + pub fn CFReadStreamScheduleWithRunLoop( + stream: CFReadStreamRef, + runLoop: CFRunLoopRef, + runLoopMode: CFStringRef, + ); + pub fn CFReadStreamUnscheduleFromRunLoop( + stream: CFReadStreamRef, + runLoop: CFRunLoopRef, + runLoopMode: CFStringRef, + ); + + /* Examining Stream Properties */ + pub fn CFReadStreamCopyProperty( + stream: CFReadStreamRef, + propertyName: CFStreamPropertyKey, + ) -> CFTypeRef; + pub fn CFReadStreamGetBuffer( + stream: CFReadStreamRef, + maxBytesToRead: CFIndex, + numBytesRead: *mut CFIndex, + ) -> *const UInt8; + pub fn CFReadStreamCopyError(stream: CFReadStreamRef) -> CFErrorRef; + pub fn CFReadStreamGetError(stream: CFReadStreamRef) -> CFStreamError; // deprecated + pub fn CFReadStreamGetStatus(stream: CFReadStreamRef) -> CFStreamStatus; + pub fn CFReadStreamHasBytesAvailable(stream: CFReadStreamRef) -> Boolean; + + /* Setting Stream Properties */ + pub fn CFReadStreamSetClient( + stream: CFReadStreamRef, + streamEvents: CFOptionFlags, + clientCB: CFReadStreamClientCallBack, + clientContext: *mut CFStreamClientContext, + ) -> Boolean; + pub fn CFReadStreamSetProperty( + stream: CFReadStreamRef, + propertyName: CFStreamPropertyKey, + propertyValue: CFTypeRef, + ) -> Boolean; + + /* Getting the CFReadStream Type ID */ + pub fn CFReadStreamGetTypeID() -> CFTypeID; + + /* CFWriteStream */ + /* Creating a Write Stream */ + pub fn CFWriteStreamCreateWithAllocatedBuffers( + alloc: CFAllocatorRef, + bufferAllocator: CFAllocatorRef, + ) -> CFWriteStreamRef; + pub fn CFWriteStreamCreateWithBuffer( + alloc: CFAllocatorRef, + buffer: *mut UInt8, + bufferCapacity: CFIndex, + ) -> CFWriteStreamRef; + pub fn CFWriteStreamCreateWithFile( + alloc: CFAllocatorRef, + fileURL: CFURLRef, + ) -> CFWriteStreamRef; + + /* Opening and Closing a Stream */ + pub fn CFWriteStreamClose(stream: CFWriteStreamRef); + pub fn CFWriteStreamOpen(stream: CFWriteStreamRef) -> Boolean; + + /* Writing to a Stream */ + pub fn CFWriteStreamWrite( + stream: CFWriteStreamRef, + buffer: *const UInt8, + bufferLength: CFIndex, + ) -> CFIndex; + + /* Scheduling a Write Stream */ + pub fn CFWriteStreamScheduleWithRunLoop( + stream: CFWriteStreamRef, + runLoop: CFRunLoopRef, + runLoopMode: CFStringRef, + ); + pub fn CFWriteStreamUnscheduleFromRunLoop( + stream: CFWriteStreamRef, + runLoop: CFRunLoopRef, + runLoopMode: CFStringRef, + ); + + /* Examining Stream Properties */ + pub fn CFWriteStreamCanAcceptBytes(stream: CFWriteStreamRef) -> Boolean; + pub fn CFWriteStreamCopyProperty( + stream: CFWriteStreamRef, + propertyName: CFStreamPropertyKey, + ) -> CFTypeRef; + pub fn CFWriteStreamCopyError(stream: CFWriteStreamRef) -> CFErrorRef; + pub fn CFWriteStreamGetError(stream: CFWriteStreamRef) -> CFStreamError; // deprecated + pub fn CFWriteStreamGetStatus(stream: CFWriteStreamRef) -> CFStreamStatus; + + /* Setting Stream Properties */ + pub fn CFWriteStreamSetClient( + stream: CFWriteStreamRef, + streamEvents: CFOptionFlags, + clientCB: CFWriteStreamClientCallBack, + clientContext: *mut CFStreamClientContext, + ) -> Boolean; + pub fn CFWriteStreamSetProperty( + stream: CFWriteStreamRef, + propertyName: CFStreamPropertyKey, + propertyValue: CFTypeRef, + ) -> Boolean; + + /* Getting the CFWriteStream Type ID */ + pub fn CFWriteStreamGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/string.rs b/third_party/rust/core-foundation-sys/src/string.rs index d4f6550784..2cb6ae948a 100644 --- a/third_party/rust/core-foundation-sys/src/string.rs +++ b/third_party/rust/core-foundation-sys/src/string.rs @@ -7,317 +7,540 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os::raw::{c_char, c_ushort, c_void}; - -use base::{Boolean, CFOptionFlags, CFIndex, CFAllocatorRef, CFRange, CFTypeID}; - -pub type UniChar = c_ushort; - -// CFString.h +use crate::array::CFArrayRef; +use crate::base::{ + Boolean, CFAllocatorRef, CFComparisonResult, CFIndex, CFOptionFlags, CFRange, CFTypeID, + ConstStr255Param, ConstStringPtr, SInt32, StringPtr, UInt32, UInt8, UTF32Char, +}; +use crate::characterset::CFCharacterSetRef; +use crate::data::CFDataRef; +use crate::dictionary::CFDictionaryRef; +use crate::locale::CFLocaleRef; +use std::os::raw::{c_char, c_double, c_ulong, c_ushort, c_void}; pub type CFStringCompareFlags = CFOptionFlags; -//static kCFCompareCaseInsensitive: CFStringCompareFlags = 1; -//static kCFCompareBackwards: CFStringCompareFlags = 4; -//static kCFCompareAnchored: CFStringCompareFlags = 8; -//static kCFCompareNonliteral: CFStringCompareFlags = 16; -//static kCFCompareLocalized: CFStringCompareFlags = 32; -//static kCFCompareNumerically: CFStringCompareFlags = 64; -//static kCFCompareDiacriticInsensitive: CFStringCompareFlags = 128; -//static kCFCompareWidthInsensitive: CFStringCompareFlags = 256; -//static kCFCompareForcedOrdering: CFStringCompareFlags = 512; +pub const kCFCompareCaseInsensitive: CFStringCompareFlags = 1; +pub const kCFCompareBackwards: CFStringCompareFlags = 4; +pub const kCFCompareAnchored: CFStringCompareFlags = 8; +pub const kCFCompareNonliteral: CFStringCompareFlags = 16; +pub const kCFCompareLocalized: CFStringCompareFlags = 32; +pub const kCFCompareNumerically: CFStringCompareFlags = 64; +pub const kCFCompareDiacriticInsensitive: CFStringCompareFlags = 128; +pub const kCFCompareWidthInsensitive: CFStringCompareFlags = 256; +pub const kCFCompareForcedOrdering: CFStringCompareFlags = 512; -pub type CFStringEncoding = u32; +pub type CFStringEncoding = UInt32; +pub type UniChar = c_ushort; // macOS built-in encodings. -//static kCFStringEncodingMacRoman: CFStringEncoding = 0; -//static kCFStringEncodingWindowsLatin1: CFStringEncoding = 0x0500; -//static kCFStringEncodingISOLatin1: CFStringEncoding = 0x0201; -//static kCFStringEncodingNextStepLatin: CFStringEncoding = 0x0B01; -//static kCFStringEncodingASCII: CFStringEncoding = 0x0600; -//static kCFStringEncodingUnicode: CFStringEncoding = 0x0100; -pub static kCFStringEncodingUTF8: CFStringEncoding = 0x08000100; -//static kCFStringEncodingNonLossyASCII: CFStringEncoding = 0x0BFF; - -//static kCFStringEncodingUTF16: CFStringEncoding = 0x0100; -//static kCFStringEncodingUTF16BE: CFStringEncoding = 0x10000100; -//static kCFStringEncodingUTF16LE: CFStringEncoding = 0x14000100; -//static kCFStringEncodingUTF32: CFStringEncoding = 0x0c000100; -//static kCFStringEncodingUTF32BE: CFStringEncoding = 0x18000100; -//static kCFStringEncodingUTF32LE: CFStringEncoding = 0x1c000100; +pub const kCFStringEncodingMacRoman: CFStringEncoding = 0; +pub const kCFStringEncodingWindowsLatin1: CFStringEncoding = 0x0500; +pub const kCFStringEncodingISOLatin1: CFStringEncoding = 0x0201; +pub const kCFStringEncodingNextStepLatin: CFStringEncoding = 0x0B01; +pub const kCFStringEncodingASCII: CFStringEncoding = 0x0600; +pub const kCFStringEncodingUnicode: CFStringEncoding = 0x0100; +pub const kCFStringEncodingUTF8: CFStringEncoding = 0x08000100; +pub const kCFStringEncodingNonLossyASCII: CFStringEncoding = 0x0BFF; +pub const kCFStringEncodingUTF16: CFStringEncoding = 0x0100; +pub const kCFStringEncodingUTF16BE: CFStringEncoding = 0x10000100; +pub const kCFStringEncodingUTF16LE: CFStringEncoding = 0x14000100; +pub const kCFStringEncodingUTF32: CFStringEncoding = 0x0c000100; +pub const kCFStringEncodingUTF32BE: CFStringEncoding = 0x18000100; +pub const kCFStringEncodingUTF32LE: CFStringEncoding = 0x1c000100; // CFStringEncodingExt.h +// External encodings, except those defined above. +pub const kCFStringEncodingMacJapanese: CFStringEncoding = 1; +pub const kCFStringEncodingMacChineseTrad: CFStringEncoding = 2; +pub const kCFStringEncodingMacKorean: CFStringEncoding = 3; +pub const kCFStringEncodingMacArabic: CFStringEncoding = 4; +pub const kCFStringEncodingMacHebrew: CFStringEncoding = 5; +pub const kCFStringEncodingMacGreek: CFStringEncoding = 6; +pub const kCFStringEncodingMacCyrillic: CFStringEncoding = 7; +pub const kCFStringEncodingMacDevanagari: CFStringEncoding = 9; +pub const kCFStringEncodingMacGurmukhi: CFStringEncoding = 10; +pub const kCFStringEncodingMacGujarati: CFStringEncoding = 11; +pub const kCFStringEncodingMacOriya: CFStringEncoding = 12; +pub const kCFStringEncodingMacBengali: CFStringEncoding = 13; +pub const kCFStringEncodingMacTamil: CFStringEncoding = 14; +pub const kCFStringEncodingMacTelugu: CFStringEncoding = 15; +pub const kCFStringEncodingMacKannada: CFStringEncoding = 16; +pub const kCFStringEncodingMacMalayalam: CFStringEncoding = 17; +pub const kCFStringEncodingMacSinhalese: CFStringEncoding = 18; +pub const kCFStringEncodingMacBurmese: CFStringEncoding = 19; +pub const kCFStringEncodingMacKhmer: CFStringEncoding = 20; +pub const kCFStringEncodingMacThai: CFStringEncoding = 21; +pub const kCFStringEncodingMacLaotian: CFStringEncoding = 22; +pub const kCFStringEncodingMacGeorgian: CFStringEncoding = 23; +pub const kCFStringEncodingMacArmenian: CFStringEncoding = 24; +pub const kCFStringEncodingMacChineseSimp: CFStringEncoding = 25; +pub const kCFStringEncodingMacTibetan: CFStringEncoding = 26; +pub const kCFStringEncodingMacMongolian: CFStringEncoding = 27; +pub const kCFStringEncodingMacEthiopic: CFStringEncoding = 28; +pub const kCFStringEncodingMacCentralEurRoman: CFStringEncoding = 29; +pub const kCFStringEncodingMacVietnamese: CFStringEncoding = 30; +pub const kCFStringEncodingMacExtArabic: CFStringEncoding = 31; +pub const kCFStringEncodingMacSymbol: CFStringEncoding = 33; +pub const kCFStringEncodingMacDingbats: CFStringEncoding = 34; +pub const kCFStringEncodingMacTurkish: CFStringEncoding = 35; +pub const kCFStringEncodingMacCroatian: CFStringEncoding = 36; +pub const kCFStringEncodingMacIcelandic: CFStringEncoding = 37; +pub const kCFStringEncodingMacRomanian: CFStringEncoding = 38; +pub const kCFStringEncodingMacCeltic: CFStringEncoding = 39; +pub const kCFStringEncodingMacGaelic: CFStringEncoding = 40; +pub const kCFStringEncodingMacFarsi: CFStringEncoding = 0x8C; +pub const kCFStringEncodingMacUkrainian: CFStringEncoding = 0x98; +pub const kCFStringEncodingMacInuit: CFStringEncoding = 0xEC; +pub const kCFStringEncodingMacVT100: CFStringEncoding = 0xFC; +pub const kCFStringEncodingMacHFS: CFStringEncoding = 0xFF; +pub const kCFStringEncodingISOLatin2: CFStringEncoding = 0x0202; +pub const kCFStringEncodingISOLatin3: CFStringEncoding = 0x0203; +pub const kCFStringEncodingISOLatin4: CFStringEncoding = 0x0204; +pub const kCFStringEncodingISOLatinCyrillic: CFStringEncoding = 0x0205; +pub const kCFStringEncodingISOLatinArabic: CFStringEncoding = 0x0206; +pub const kCFStringEncodingISOLatinGreek: CFStringEncoding = 0x0207; +pub const kCFStringEncodingISOLatinHebrew: CFStringEncoding = 0x0208; +pub const kCFStringEncodingISOLatin5: CFStringEncoding = 0x0209; +pub const kCFStringEncodingISOLatin6: CFStringEncoding = 0x020A; +pub const kCFStringEncodingISOLatinThai: CFStringEncoding = 0x020B; +pub const kCFStringEncodingISOLatin7: CFStringEncoding = 0x020D; +pub const kCFStringEncodingISOLatin8: CFStringEncoding = 0x020E; +pub const kCFStringEncodingISOLatin9: CFStringEncoding = 0x020F; +pub const kCFStringEncodingISOLatin10: CFStringEncoding = 0x0210; +pub const kCFStringEncodingDOSLatinUS: CFStringEncoding = 0x0400; +pub const kCFStringEncodingDOSGreek: CFStringEncoding = 0x0405; +pub const kCFStringEncodingDOSBalticRim: CFStringEncoding = 0x0406; +pub const kCFStringEncodingDOSLatin1: CFStringEncoding = 0x0410; +pub const kCFStringEncodingDOSGreek1: CFStringEncoding = 0x0411; +pub const kCFStringEncodingDOSLatin2: CFStringEncoding = 0x0412; +pub const kCFStringEncodingDOSCyrillic: CFStringEncoding = 0x0413; +pub const kCFStringEncodingDOSTurkish: CFStringEncoding = 0x0414; +pub const kCFStringEncodingDOSPortuguese: CFStringEncoding = 0x0415; +pub const kCFStringEncodingDOSIcelandic: CFStringEncoding = 0x0416; +pub const kCFStringEncodingDOSHebrew: CFStringEncoding = 0x0417; +pub const kCFStringEncodingDOSCanadianFrench: CFStringEncoding = 0x0418; +pub const kCFStringEncodingDOSArabic: CFStringEncoding = 0x0419; +pub const kCFStringEncodingDOSNordic: CFStringEncoding = 0x041A; +pub const kCFStringEncodingDOSRussian: CFStringEncoding = 0x041B; +pub const kCFStringEncodingDOSGreek2: CFStringEncoding = 0x041C; +pub const kCFStringEncodingDOSThai: CFStringEncoding = 0x041D; +pub const kCFStringEncodingDOSJapanese: CFStringEncoding = 0x0420; +pub const kCFStringEncodingDOSChineseSimplif: CFStringEncoding = 0x0421; +pub const kCFStringEncodingDOSKorean: CFStringEncoding = 0x0422; +pub const kCFStringEncodingDOSChineseTrad: CFStringEncoding = 0x0423; +pub const kCFStringEncodingWindowsLatin2: CFStringEncoding = 0x0501; +pub const kCFStringEncodingWindowsCyrillic: CFStringEncoding = 0x0502; +pub const kCFStringEncodingWindowsGreek: CFStringEncoding = 0x0503; +pub const kCFStringEncodingWindowsLatin5: CFStringEncoding = 0x0504; +pub const kCFStringEncodingWindowsHebrew: CFStringEncoding = 0x0505; +pub const kCFStringEncodingWindowsArabic: CFStringEncoding = 0x0506; +pub const kCFStringEncodingWindowsBalticRim: CFStringEncoding = 0x0507; +pub const kCFStringEncodingWindowsVietnamese: CFStringEncoding = 0x0508; +pub const kCFStringEncodingWindowsKoreanJohab: CFStringEncoding = 0x0510; +pub const kCFStringEncodingANSEL: CFStringEncoding = 0x0601; +pub const kCFStringEncodingJIS_X0201_76: CFStringEncoding = 0x0620; +pub const kCFStringEncodingJIS_X0208_83: CFStringEncoding = 0x0621; +pub const kCFStringEncodingJIS_X0208_90: CFStringEncoding = 0x0622; +pub const kCFStringEncodingJIS_X0212_90: CFStringEncoding = 0x0623; +pub const kCFStringEncodingJIS_C6226_78: CFStringEncoding = 0x0624; +pub const kCFStringEncodingShiftJIS_X0213: CFStringEncoding = 0x0628; +pub const kCFStringEncodingShiftJIS_X0213_MenKuTen: CFStringEncoding = 0x0629; +pub const kCFStringEncodingGB_2312_80: CFStringEncoding = 0x0630; +pub const kCFStringEncodingGBK_95: CFStringEncoding = 0x0631; +pub const kCFStringEncodingGB_18030_2000: CFStringEncoding = 0x0632; +pub const kCFStringEncodingKSC_5601_87: CFStringEncoding = 0x0640; +pub const kCFStringEncodingKSC_5601_92_Johab: CFStringEncoding = 0x0641; +pub const kCFStringEncodingCNS_11643_92_P1: CFStringEncoding = 0x0651; +pub const kCFStringEncodingCNS_11643_92_P2: CFStringEncoding = 0x0652; +pub const kCFStringEncodingCNS_11643_92_P3: CFStringEncoding = 0x0653; +pub const kCFStringEncodingISO_2022_JP: CFStringEncoding = 0x0820; +pub const kCFStringEncodingISO_2022_JP_2: CFStringEncoding = 0x0821; +pub const kCFStringEncodingISO_2022_JP_1: CFStringEncoding = 0x0822; +pub const kCFStringEncodingISO_2022_JP_3: CFStringEncoding = 0x0823; +pub const kCFStringEncodingISO_2022_CN: CFStringEncoding = 0x0830; +pub const kCFStringEncodingISO_2022_CN_EXT: CFStringEncoding = 0x0831; +pub const kCFStringEncodingISO_2022_KR: CFStringEncoding = 0x0840; +pub const kCFStringEncodingEUC_JP: CFStringEncoding = 0x0920; +pub const kCFStringEncodingEUC_CN: CFStringEncoding = 0x0930; +pub const kCFStringEncodingEUC_TW: CFStringEncoding = 0x0931; +pub const kCFStringEncodingEUC_KR: CFStringEncoding = 0x0940; +pub const kCFStringEncodingShiftJIS: CFStringEncoding = 0x0A01; +pub const kCFStringEncodingKOI8_R: CFStringEncoding = 0x0A02; +pub const kCFStringEncodingBig5: CFStringEncoding = 0x0A03; +pub const kCFStringEncodingMacRomanLatin1: CFStringEncoding = 0x0A04; +pub const kCFStringEncodingHZ_GB_2312: CFStringEncoding = 0x0A05; +pub const kCFStringEncodingBig5_HKSCS_1999: CFStringEncoding = 0x0A06; +pub const kCFStringEncodingVISCII: CFStringEncoding = 0x0A07; +pub const kCFStringEncodingKOI8_U: CFStringEncoding = 0x0A08; +pub const kCFStringEncodingBig5_E: CFStringEncoding = 0x0A09; +pub const kCFStringEncodingNextStepJapanese: CFStringEncoding = 0x0B02; +pub const kCFStringEncodingEBCDIC_US: CFStringEncoding = 0x0C01; +pub const kCFStringEncodingEBCDIC_CP037: CFStringEncoding = 0x0C02; +pub const kCFStringEncodingUTF7: CFStringEncoding = 0x04000100; +pub const kCFStringEncodingUTF7_IMAP: CFStringEncoding = 0x0A10; +pub const kCFStringEncodingShiftJIS_X0213_00: CFStringEncoding = 0x0628; /* Deprecated */ -pub type CFStringEncodings = CFIndex; +pub const kCFStringEncodingInvalidId: u32 = 0xffffffff; -// External encodings, except those defined above. -// Defined above: kCFStringEncodingMacRoman = 0 -//static kCFStringEncodingMacJapanese: CFStringEncoding = 1; -//static kCFStringEncodingMacChineseTrad: CFStringEncoding = 2; -//static kCFStringEncodingMacKorean: CFStringEncoding = 3; -//static kCFStringEncodingMacArabic: CFStringEncoding = 4; -//static kCFStringEncodingMacHebrew: CFStringEncoding = 5; -//static kCFStringEncodingMacGreek: CFStringEncoding = 6; -//static kCFStringEncodingMacCyrillic: CFStringEncoding = 7; -//static kCFStringEncodingMacDevanagari: CFStringEncoding = 9; -//static kCFStringEncodingMacGurmukhi: CFStringEncoding = 10; -//static kCFStringEncodingMacGujarati: CFStringEncoding = 11; -//static kCFStringEncodingMacOriya: CFStringEncoding = 12; -//static kCFStringEncodingMacBengali: CFStringEncoding = 13; -//static kCFStringEncodingMacTamil: CFStringEncoding = 14; -//static kCFStringEncodingMacTelugu: CFStringEncoding = 15; -//static kCFStringEncodingMacKannada: CFStringEncoding = 16; -//static kCFStringEncodingMacMalayalam: CFStringEncoding = 17; -//static kCFStringEncodingMacSinhalese: CFStringEncoding = 18; -//static kCFStringEncodingMacBurmese: CFStringEncoding = 19; -//static kCFStringEncodingMacKhmer: CFStringEncoding = 20; -//static kCFStringEncodingMacThai: CFStringEncoding = 21; -//static kCFStringEncodingMacLaotian: CFStringEncoding = 22; -//static kCFStringEncodingMacGeorgian: CFStringEncoding = 23; -//static kCFStringEncodingMacArmenian: CFStringEncoding = 24; -//static kCFStringEncodingMacChineseSimp: CFStringEncoding = 25; -//static kCFStringEncodingMacTibetan: CFStringEncoding = 26; -//static kCFStringEncodingMacMongolian: CFStringEncoding = 27; -//static kCFStringEncodingMacEthiopic: CFStringEncoding = 28; -//static kCFStringEncodingMacCentralEurRoman: CFStringEncoding = 29; -//static kCFStringEncodingMacVietnamese: CFStringEncoding = 30; -//static kCFStringEncodingMacExtArabic: CFStringEncoding = 31; -//static kCFStringEncodingMacSymbol: CFStringEncoding = 33; -//static kCFStringEncodingMacDingbats: CFStringEncoding = 34; -//static kCFStringEncodingMacTurkish: CFStringEncoding = 35; -//static kCFStringEncodingMacCroatian: CFStringEncoding = 36; -//static kCFStringEncodingMacIcelandic: CFStringEncoding = 37; -//static kCFStringEncodingMacRomanian: CFStringEncoding = 38; -//static kCFStringEncodingMacCeltic: CFStringEncoding = 39; -//static kCFStringEncodingMacGaelic: CFStringEncoding = 40; -//static kCFStringEncodingMacFarsi: CFStringEncoding = 0x8C; -//static kCFStringEncodingMacUkrainian: CFStringEncoding = 0x98; -//static kCFStringEncodingMacInuit: CFStringEncoding = 0xEC; -//static kCFStringEncodingMacVT100: CFStringEncoding = 0xFC; -//static kCFStringEncodingMacHFS: CFStringEncoding = 0xFF; -// Defined above: kCFStringEncodingISOLatin1 = 0x0201 -//static kCFStringEncodingISOLatin2: CFStringEncoding = 0x0202; -//static kCFStringEncodingISOLatin3: CFStringEncoding = 0x0203; -//static kCFStringEncodingISOLatin4: CFStringEncoding = 0x0204; -//static kCFStringEncodingISOLatinCyrillic: CFStringEncoding = 0x0205; -//static kCFStringEncodingISOLatinArabic: CFStringEncoding = 0x0206; -//static kCFStringEncodingISOLatinGreek: CFStringEncoding = 0x0207; -//static kCFStringEncodingISOLatinHebrew: CFStringEncoding = 0x0208; -//static kCFStringEncodingISOLatin5: CFStringEncoding = 0x0209; -//static kCFStringEncodingISOLatin6: CFStringEncoding = 0x020A; -//static kCFStringEncodingISOLatinThai: CFStringEncoding = 0x020B; -//static kCFStringEncodingISOLatin7: CFStringEncoding = 0x020D; -//static kCFStringEncodingISOLatin8: CFStringEncoding = 0x020E; -//static kCFStringEncodingISOLatin9: CFStringEncoding = 0x020F; -//static kCFStringEncodingISOLatin10: CFStringEncoding = 0x0210; -//static kCFStringEncodingDOSLatinUS: CFStringEncoding = 0x0400; -//static kCFStringEncodingDOSGreek: CFStringEncoding = 0x0405; -//static kCFStringEncodingDOSBalticRim: CFStringEncoding = 0x0406; -//static kCFStringEncodingDOSLatin1: CFStringEncoding = 0x0410; -//static kCFStringEncodingDOSGreek1: CFStringEncoding = 0x0411; -//static kCFStringEncodingDOSLatin2: CFStringEncoding = 0x0412; -//static kCFStringEncodingDOSCyrillic: CFStringEncoding = 0x0413; -//static kCFStringEncodingDOSTurkish: CFStringEncoding = 0x0414; -//static kCFStringEncodingDOSPortuguese: CFStringEncoding = 0x0415; -//static kCFStringEncodingDOSIcelandic: CFStringEncoding = 0x0416; -//static kCFStringEncodingDOSHebrew: CFStringEncoding = 0x0417; -//static kCFStringEncodingDOSCanadianFrench: CFStringEncoding = 0x0418; -//static kCFStringEncodingDOSArabic: CFStringEncoding = 0x0419; -//static kCFStringEncodingDOSNordic: CFStringEncoding = 0x041A; -//static kCFStringEncodingDOSRussian: CFStringEncoding = 0x041B; -//static kCFStringEncodingDOSGreek2: CFStringEncoding = 0x041C; -//static kCFStringEncodingDOSThai: CFStringEncoding = 0x041D; -//static kCFStringEncodingDOSJapanese: CFStringEncoding = 0x0420; -//static kCFStringEncodingDOSChineseSimplif: CFStringEncoding = 0x0421; -//static kCFStringEncodingDOSKorean: CFStringEncoding = 0x0422; -//static kCFStringEncodingDOSChineseTrad: CFStringEncoding = 0x0423; -// Defined above: kCFStringEncodingWindowsLatin1 = 0x0500 -//static kCFStringEncodingWindowsLatin2: CFStringEncoding = 0x0501; -//static kCFStringEncodingWindowsCyrillic: CFStringEncoding = 0x0502; -//static kCFStringEncodingWindowsGreek: CFStringEncoding = 0x0503; -//static kCFStringEncodingWindowsLatin5: CFStringEncoding = 0x0504; -//static kCFStringEncodingWindowsHebrew: CFStringEncoding = 0x0505; -//static kCFStringEncodingWindowsArabic: CFStringEncoding = 0x0506; -//static kCFStringEncodingWindowsBalticRim: CFStringEncoding = 0x0507; -//static kCFStringEncodingWindowsVietnamese: CFStringEncoding = 0x0508; -//static kCFStringEncodingWindowsKoreanJohab: CFStringEncoding = 0x0510; -// Defined above: kCFStringEncodingASCII = 0x0600 -//static kCFStringEncodingANSEL: CFStringEncoding = 0x0601; -//static kCFStringEncodingJIS_X0201_76: CFStringEncoding = 0x0620; -//static kCFStringEncodingJIS_X0208_83: CFStringEncoding = 0x0621; -//static kCFStringEncodingJIS_X0208_90: CFStringEncoding = 0x0622; -//static kCFStringEncodingJIS_X0212_90: CFStringEncoding = 0x0623; -//static kCFStringEncodingJIS_C6226_78: CFStringEncoding = 0x0624; -//static kCFStringEncodingShiftJIS_X0213: CFStringEncoding = 0x0628; -//static kCFStringEncodingShiftJIS_X0213_MenKuTen: CFStringEncoding = 0x0629; -//static kCFStringEncodingGB_2312_80: CFStringEncoding = 0x0630; -//static kCFStringEncodingGBK_95: CFStringEncoding = 0x0631; -//static kCFStringEncodingGB_18030_2000: CFStringEncoding = 0x0632; -//static kCFStringEncodingKSC_5601_87: CFStringEncoding = 0x0640; -//static kCFStringEncodingKSC_5601_92_Johab: CFStringEncoding = 0x0641; -//static kCFStringEncodingCNS_11643_92_P1: CFStringEncoding = 0x0651; -//static kCFStringEncodingCNS_11643_92_P2: CFStringEncoding = 0x0652; -//static kCFStringEncodingCNS_11643_92_P3: CFStringEncoding = 0x0653; -//static kCFStringEncodingISO_2022_JP: CFStringEncoding = 0x0820; -//static kCFStringEncodingISO_2022_JP_2: CFStringEncoding = 0x0821; -//static kCFStringEncodingISO_2022_JP_1: CFStringEncoding = 0x0822; -//static kCFStringEncodingISO_2022_JP_3: CFStringEncoding = 0x0823; -//static kCFStringEncodingISO_2022_CN: CFStringEncoding = 0x0830; -//static kCFStringEncodingISO_2022_CN_EXT: CFStringEncoding = 0x0831; -//static kCFStringEncodingISO_2022_KR: CFStringEncoding = 0x0840; -//static kCFStringEncodingEUC_JP: CFStringEncoding = 0x0920; -//static kCFStringEncodingEUC_CN: CFStringEncoding = 0x0930; -//static kCFStringEncodingEUC_TW: CFStringEncoding = 0x0931; -//static kCFStringEncodingEUC_KR: CFStringEncoding = 0x0940; -//static kCFStringEncodingShiftJIS: CFStringEncoding = 0x0A01; -//static kCFStringEncodingKOI8_R: CFStringEncoding = 0x0A02; -//static kCFStringEncodingBig5: CFStringEncoding = 0x0A03; -//static kCFStringEncodingMacRomanLatin1: CFStringEncoding = 0x0A04; -//static kCFStringEncodingHZ_GB_2312: CFStringEncoding = 0x0A05; -//static kCFStringEncodingBig5_HKSCS_1999: CFStringEncoding = 0x0A06; -//static kCFStringEncodingVISCII: CFStringEncoding = 0x0A07; -//static kCFStringEncodingKOI8_U: CFStringEncoding = 0x0A08; -//static kCFStringEncodingBig5_E: CFStringEncoding = 0x0A09; -// Defined above: kCFStringEncodingNextStepLatin = 0x0B01 -//static kCFStringEncodingNextStepJapanese: CFStringEncoding = 0x0B02; -//static kCFStringEncodingEBCDIC_US: CFStringEncoding = 0x0C01; -//static kCFStringEncodingEBCDIC_CP037: CFStringEncoding = 0x0C02; -//static kCFStringEncodingUTF7: CFStringEncoding = 0x04000100; -//static kCFStringEncodingUTF7_IMAP: CFStringEncoding = 0x0A10; -//static kCFStringEncodingShiftJIS_X0213_00: CFStringEncoding = 0x0628; /* Deprecated */ +pub type CFStringNormalizationForm = CFIndex; +pub const kCFStringNormalizationFormD: CFStringNormalizationForm = 0; +pub const kCFStringNormalizationFormKD: CFStringNormalizationForm = 1; +pub const kCFStringNormalizationFormC: CFStringNormalizationForm = 2; +pub const kCFStringNormalizationFormKC: CFStringNormalizationForm = 3; #[repr(C)] pub struct __CFString(c_void); pub type CFStringRef = *const __CFString; +pub type CFMutableStringRef = *mut __CFString; + +/* todo: The source code of the following functions is right in CFString.h */ +/* +pub fn CFStringGetLongCharacterForSurrogatePair(surrogateHigh: UniChar, surrogateLow: UniChar) -> UTF32Char; +pub fn CFStringGetSurrogatePairForLongCharacter(character: UTF32Char, surrogates: *mut UniChar) -> Boolean; +pub fn CFStringIsSurrogateHighCharacter(character: UniChar) -> Boolean; +pub fn CFStringIsSurrogateLowCharacter(character: UniChar) -> Boolean; +pub fn CFStringInitInlineBuffer(str: CFStringRef, buf: *mut CFStringInlineBuffer, range: CFRange); +pub fn CFStringGetCharacterFromInlineBuffer(buf: *mut CFStringInlineBuffer, idx: CFIndex) -> UniChar; +*/ -extern { +extern "C" { /* * CFString.h */ // N.B. organized according to "Functions by task" in docs + /* CFString */ /* Creating a CFString */ //fn CFSTR - //fn CFStringCreateArrayBySeparatingStrings - //fn CFStringCreateByCombiningStrings - //fn CFStringCreateCopy - //fn CFStringCreateFromExternalRepresentation - pub fn CFStringCreateWithBytes(alloc: CFAllocatorRef, - bytes: *const u8, - numBytes: CFIndex, - encoding: CFStringEncoding, - isExternalRepresentation: Boolean) - -> CFStringRef; - pub fn CFStringCreateWithBytesNoCopy(alloc: CFAllocatorRef, - bytes: *const u8, - numBytes: CFIndex, - encoding: CFStringEncoding, - isExternalRepresentation: Boolean, - contentsDeallocator: CFAllocatorRef) - -> CFStringRef; - //fn CFStringCreateWithCharacters - pub fn CFStringCreateWithCharactersNoCopy(alloc: CFAllocatorRef, - chars: *const UniChar, - numChars: CFIndex, - contentsDeallocator: CFAllocatorRef) - -> CFStringRef; - pub fn CFStringCreateWithCString(alloc: CFAllocatorRef, - cStr: *const c_char, - encoding: CFStringEncoding) - -> CFStringRef; - //fn CFStringCreateWithCStringNoCopy - //fn CFStringCreateWithFormat - //fn CFStringCreateWithFormatAndArguments - //fn CFStringCreateWithPascalString - //fn CFStringCreateWithPascalStringNoCopy - //fn CFStringCreateWithSubstring + pub fn CFStringCreateArrayBySeparatingStrings( + alloc: CFAllocatorRef, + theString: CFStringRef, + separatorString: CFStringRef, + ) -> CFArrayRef; + pub fn CFStringCreateByCombiningStrings( + alloc: CFAllocatorRef, + theArray: CFArrayRef, + separatorString: CFStringRef, + ) -> CFStringRef; + pub fn CFStringCreateCopy(alloc: CFAllocatorRef, theString: CFStringRef) -> CFStringRef; + pub fn CFStringCreateFromExternalRepresentation( + alloc: CFAllocatorRef, + data: CFDataRef, + encoding: CFStringEncoding, + ) -> CFStringRef; + pub fn CFStringCreateWithBytes( + alloc: CFAllocatorRef, + bytes: *const UInt8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: Boolean, + ) -> CFStringRef; + pub fn CFStringCreateWithBytesNoCopy( + alloc: CFAllocatorRef, + bytes: *const UInt8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: Boolean, + contentsDeallocator: CFAllocatorRef, + ) -> CFStringRef; + pub fn CFStringCreateWithCharacters( + alloc: CFAllocatorRef, + chars: *const UniChar, + numChars: CFIndex, + ) -> CFStringRef; + pub fn CFStringCreateWithCharactersNoCopy( + alloc: CFAllocatorRef, + chars: *const UniChar, + numChars: CFIndex, + contentsDeallocator: CFAllocatorRef, + ) -> CFStringRef; + pub fn CFStringCreateWithCString( + alloc: CFAllocatorRef, + cStr: *const c_char, + encoding: CFStringEncoding, + ) -> CFStringRef; + pub fn CFStringCreateWithCStringNoCopy( + alloc: CFAllocatorRef, + cStr: *const c_char, + encoding: CFStringEncoding, + contentsDeallocator: CFAllocatorRef, + ) -> CFStringRef; + pub fn CFStringCreateWithFormat( + alloc: CFAllocatorRef, + formatOptions: CFDictionaryRef, + format: CFStringRef, + ... + ) -> CFStringRef; + //pub fn CFStringCreateWithFormatAndArguments(alloc: CFAllocatorRef, formatOptions: CFDictionaryRef, format: CFStringRef, arguments: va_list) -> CFStringRef; + pub fn CFStringCreateWithPascalString( + alloc: CFAllocatorRef, + pStr: ConstStr255Param, + encoding: CFStringEncoding, + ) -> CFStringRef; + pub fn CFStringCreateWithPascalStringNoCopy( + alloc: CFAllocatorRef, + pStr: ConstStr255Param, + encoding: CFStringEncoding, + contentsDeallocator: CFAllocatorRef, + ) -> CFStringRef; + pub fn CFStringCreateWithSubstring( + alloc: CFAllocatorRef, + str: CFStringRef, + range: CFRange, + ) -> CFStringRef; /* Searching Strings */ - //fn CFStringCreateArrayWithFindResults - //fn CFStringFind - //fn CFStringFindCharacterFromSet - //fn CFStringFindWithOptions - //fn CFStringFindWithOptionsAndLocale - //fn CFStringGetLineBounds + pub fn CFStringCreateArrayWithFindResults( + alloc: CFAllocatorRef, + theString: CFStringRef, + stringToFind: CFStringRef, + rangeToSearch: CFRange, + compareOptions: CFStringCompareFlags, + ) -> CFArrayRef; + pub fn CFStringFind( + theString: CFStringRef, + stringToFind: CFStringRef, + compareOptions: CFStringCompareFlags, + ) -> CFRange; + pub fn CFStringFindCharacterFromSet( + theString: CFStringRef, + theSet: CFCharacterSetRef, + rangeToSearch: CFRange, + searchOptions: CFStringCompareFlags, + result: *mut CFRange, + ) -> Boolean; + pub fn CFStringFindWithOptions( + theString: CFStringRef, + stringToFind: CFStringRef, + rangeToSearch: CFRange, + searchOptions: CFStringCompareFlags, + result: *mut CFRange, + ) -> Boolean; + pub fn CFStringFindWithOptionsAndLocale( + theString: CFStringRef, + stringToFind: CFStringRef, + rangeToSearch: CFRange, + searchOptions: CFStringCompareFlags, + locale: CFLocaleRef, + result: *mut CFRange, + ) -> Boolean; + pub fn CFStringGetLineBounds( + theString: CFStringRef, + range: CFRange, + lineBeginIndex: *mut CFIndex, + lineEndIndex: *mut CFIndex, + contentsEndIndex: *mut CFIndex, + ); /* Comparing Strings */ - //fn CFStringCompare - //fn CFStringCompareWithOptions - //fn CFStringCompareWithOptionsAndLocale - //fn CFStringHasPrefix - //fn CFStringHasSuffix + pub fn CFStringCompare( + theString1: CFStringRef, + theString2: CFStringRef, + compareOptions: CFStringCompareFlags, + ) -> CFComparisonResult; + pub fn CFStringCompareWithOptions( + theString1: CFStringRef, + theString2: CFStringRef, + rangeToCompare: CFRange, + compareOptions: CFStringCompareFlags, + ) -> CFComparisonResult; + pub fn CFStringCompareWithOptionsAndLocale( + theString1: CFStringRef, + theString2: CFStringRef, + rangeToCompare: CFRange, + compareOptions: CFStringCompareFlags, + locale: CFLocaleRef, + ) -> CFComparisonResult; + pub fn CFStringHasPrefix(theString: CFStringRef, prefix: CFStringRef) -> Boolean; + pub fn CFStringHasSuffix(theString: CFStringRef, suffix: CFStringRef) -> Boolean; /* Accessing Characters */ - //fn CFStringCreateExternalRepresentation - pub fn CFStringGetBytes(theString: CFStringRef, - range: CFRange, - encoding: CFStringEncoding, - lossByte: u8, - isExternalRepresentation: Boolean, - buffer: *mut u8, - maxBufLen: CFIndex, - usedBufLen: *mut CFIndex) - -> CFIndex; - //fn CFStringGetCharacterAtIndex - //fn CFStringGetCharacters - //fn CFStringGetCharactersPtr - //fn CFStringGetCharacterFromInlineBuffer - pub fn CFStringGetCString(theString: CFStringRef, - buffer: *mut c_char, - bufferSize: CFIndex, - encoding: CFStringEncoding) - -> Boolean; - pub fn CFStringGetCStringPtr(theString: CFStringRef, - encoding: CFStringEncoding) - -> *const c_char; + pub fn CFStringCreateExternalRepresentation( + alloc: CFAllocatorRef, + theString: CFStringRef, + encoding: CFStringEncoding, + lossByte: UInt8, + ) -> CFDataRef; + pub fn CFStringGetBytes( + theString: CFStringRef, + range: CFRange, + encoding: CFStringEncoding, + lossByte: UInt8, + isExternalRepresentation: Boolean, + buffer: *mut UInt8, + maxBufLen: CFIndex, + usedBufLen: *mut CFIndex, + ) -> CFIndex; + pub fn CFStringGetCharacterAtIndex(theString: CFStringRef, idx: CFIndex) -> UniChar; + pub fn CFStringGetCharacters(theString: CFStringRef, range: CFRange, buffer: *mut UniChar); + pub fn CFStringGetCharactersPtr(theString: CFStringRef) -> *const UniChar; + pub fn CFStringGetCString( + theString: CFStringRef, + buffer: *mut c_char, + bufferSize: CFIndex, + encoding: CFStringEncoding, + ) -> Boolean; + pub fn CFStringGetCStringPtr( + theString: CFStringRef, + encoding: CFStringEncoding, + ) -> *const c_char; pub fn CFStringGetLength(theString: CFStringRef) -> CFIndex; - //fn CFStringGetPascalString - //fn CFStringGetPascalStringPtr - //fn CFStringGetRangeOfComposedCharactersAtIndex - //fn CFStringInitInlineBuffer + pub fn CFStringGetPascalString( + theString: CFStringRef, + buffer: StringPtr, + bufferSize: CFIndex, + encoding: CFStringEncoding, + ) -> Boolean; + pub fn CFStringGetPascalStringPtr( + theString: CFStringRef, + encoding: CFStringEncoding, + ) -> ConstStringPtr; + pub fn CFStringGetRangeOfComposedCharactersAtIndex( + theString: CFStringRef, + theIndex: CFIndex, + ) -> CFRange; /* Working With Hyphenation */ - //fn CFStringGetHyphenationLocationBeforeIndex - //fn CFStringIsHyphenationAvailableForLocale + pub fn CFStringGetHyphenationLocationBeforeIndex( + string: CFStringRef, + location: CFIndex, + limitRange: CFRange, + options: CFOptionFlags, + locale: CFLocaleRef, + character: *mut UTF32Char, + ) -> CFIndex; + pub fn CFStringIsHyphenationAvailableForLocale(locale: CFLocaleRef) -> Boolean; /* Working With Encodings */ - //fn CFStringConvertEncodingToIANACharSetName - //fn CFStringConvertEncodingToNSStringEncoding - //fn CFStringConvertEncodingToWindowsCodepage - //fn CFStringConvertIANACharSetNameToEncoding - //fn CFStringConvertNSStringEncodingToEncoding - //fn CFStringConvertWindowsCodepageToEncoding - //fn CFStringGetFastestEncoding - //fn CFStringGetListOfAvailableEncodings - //fn CFStringGetMaximumSizeForEncoding - //fn CFStringGetMostCompatibleMacStringEncoding - //fn CFStringGetNameOfEncoding - //fn CFStringGetSmallestEncoding - //fn CFStringGetSystemEncoding - //fn CFStringIsEncodingAvailable + pub fn CFStringConvertEncodingToIANACharSetName(encoding: CFStringEncoding) -> CFStringRef; + pub fn CFStringConvertEncodingToNSStringEncoding(encoding: CFStringEncoding) -> c_ulong; + pub fn CFStringConvertEncodingToWindowsCodepage(encoding: CFStringEncoding) -> UInt32; + pub fn CFStringConvertIANACharSetNameToEncoding(theString: CFStringRef) -> CFStringEncoding; + pub fn CFStringConvertNSStringEncodingToEncoding(encoding: c_ulong) -> CFStringEncoding; + pub fn CFStringConvertWindowsCodepageToEncoding(codepage: UInt32) -> CFStringEncoding; + pub fn CFStringGetFastestEncoding(theString: CFStringRef) -> CFStringEncoding; + pub fn CFStringGetListOfAvailableEncodings() -> *const CFStringEncoding; + pub fn CFStringGetMaximumSizeForEncoding( + length: CFIndex, + encoding: CFStringEncoding, + ) -> CFIndex; + pub fn CFStringGetMostCompatibleMacStringEncoding( + encoding: CFStringEncoding, + ) -> CFStringEncoding; + pub fn CFStringGetNameOfEncoding(encoding: CFStringEncoding) -> CFStringRef; + pub fn CFStringGetSmallestEncoding(theString: CFStringRef) -> CFStringEncoding; + pub fn CFStringGetSystemEncoding() -> CFStringEncoding; + pub fn CFStringIsEncodingAvailable(encoding: CFStringEncoding) -> Boolean; /* Getting Numeric Values */ - //fn CFStringGetDoubleValue - //fn CFStringGetIntValue + pub fn CFStringGetDoubleValue(str: CFStringRef) -> c_double; + pub fn CFStringGetIntValue(str: CFStringRef) -> SInt32; /* Getting String Properties */ - //fn CFShowStr + pub fn CFShowStr(str: CFStringRef); pub fn CFStringGetTypeID() -> CFTypeID; /* String File System Representations */ - //fn CFStringCreateWithFileSystemRepresentation - //fn CFStringGetFileSystemRepresentation - //fn CFStringGetMaximumSizeOfFileSystemRepresentation + pub fn CFStringCreateWithFileSystemRepresentation( + alloc: CFAllocatorRef, + buffer: *const c_char, + ) -> CFStringRef; + pub fn CFStringGetFileSystemRepresentation( + string: CFStringRef, + buffer: *mut c_char, + maxBufLen: CFIndex, + ) -> Boolean; + pub fn CFStringGetMaximumSizeOfFileSystemRepresentation(string: CFStringRef) -> CFIndex; /* Getting Paragraph Bounds */ - //fn CFStringGetParagraphBounds + pub fn CFStringGetParagraphBounds( + string: CFStringRef, + range: CFRange, + parBeginIndex: *mut CFIndex, + parEndIndex: *mut CFIndex, + contentsEndIndex: *mut CFIndex, + ); - /* Managing Surrogates */ - //fn CFStringGetLongCharacterForSurrogatePair - //fn CFStringGetSurrogatePairForLongCharacter - //fn CFStringIsSurrogateHighCharacter - //fn CFStringIsSurrogateLowCharacter + /* CFMutableString */ + /* CFMutableString Miscellaneous Functions */ + pub fn CFStringAppend(theString: CFMutableStringRef, appendedString: CFStringRef); + pub fn CFStringAppendCharacters( + theString: CFMutableStringRef, + chars: *const UniChar, + numChars: CFIndex, + ); + pub fn CFStringAppendCString( + theString: CFMutableStringRef, + cStr: *const c_char, + encoding: CFStringEncoding, + ); + pub fn CFStringAppendFormat( + theString: CFMutableStringRef, + formatOptions: CFDictionaryRef, + format: CFStringRef, + ... + ); + //pub fn CFStringAppendFormatAndArguments(theString: CFMutableStringRef, formatOptions: CFDictionaryRef, format: CFStringRef, arguments: va_list); + pub fn CFStringAppendPascalString( + theString: CFMutableStringRef, + pStr: ConstStr255Param, + encoding: CFStringEncoding, + ); + pub fn CFStringCapitalize(theString: CFMutableStringRef, locale: CFLocaleRef); + pub fn CFStringCreateMutable(alloc: CFAllocatorRef, maxLength: CFIndex) -> CFMutableStringRef; + pub fn CFStringCreateMutableCopy( + alloc: CFAllocatorRef, + maxLength: CFIndex, + theString: CFStringRef, + ) -> CFMutableStringRef; + pub fn CFStringCreateMutableWithExternalCharactersNoCopy( + alloc: CFAllocatorRef, + chars: *mut UniChar, + numChars: CFIndex, + capacity: CFIndex, + externalCharactersAllocator: CFAllocatorRef, + ) -> CFMutableStringRef; + pub fn CFStringDelete(theString: CFMutableStringRef, range: CFRange); + pub fn CFStringFindAndReplace( + theString: CFMutableStringRef, + stringToFind: CFStringRef, + replacementString: CFStringRef, + rangeToSearch: CFRange, + compareOptions: CFStringCompareFlags, + ) -> CFIndex; + pub fn CFStringFold( + theString: CFMutableStringRef, + theFlags: CFStringCompareFlags, + theLocale: CFLocaleRef, + ); + pub fn CFStringInsert(str: CFMutableStringRef, idx: CFIndex, insertedStr: CFStringRef); + pub fn CFStringLowercase(theString: CFMutableStringRef, locale: CFLocaleRef); + pub fn CFStringNormalize(theString: CFMutableStringRef, theForm: CFStringNormalizationForm); + pub fn CFStringPad( + theString: CFMutableStringRef, + padString: CFStringRef, + length: CFIndex, + indexIntoPad: CFIndex, + ); + pub fn CFStringReplace(theString: CFMutableStringRef, range: CFRange, replacement: CFStringRef); + pub fn CFStringReplaceAll(theString: CFMutableStringRef, replacement: CFStringRef); + pub fn CFStringSetExternalCharactersNoCopy( + theString: CFMutableStringRef, + chars: *mut UniChar, + length: CFIndex, + capacity: CFIndex, + ); + pub fn CFStringTransform( + string: CFMutableStringRef, + range: *mut CFRange, + transform: CFStringRef, + reverse: Boolean, + ) -> Boolean; + pub fn CFStringTrim(theString: CFMutableStringRef, trimString: CFStringRef); + pub fn CFStringTrimWhitespace(theString: CFMutableStringRef); + pub fn CFStringUppercase(theString: CFMutableStringRef, locale: CFLocaleRef); } diff --git a/third_party/rust/core-foundation-sys/src/string_tokenizer.rs b/third_party/rust/core-foundation-sys/src/string_tokenizer.rs new file mode 100644 index 0000000000..b23d6a2d34 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/string_tokenizer.rs @@ -0,0 +1,91 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::array::CFMutableArrayRef; +use crate::base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRange, CFTypeID, CFTypeRef}; +use crate::locale::CFLocaleRef; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFStringTokenizer(c_void); +pub type CFStringTokenizerRef = *mut __CFStringTokenizer; + +pub type CFStringTokenizerTokenType = CFOptionFlags; + +pub const kCFStringTokenizerTokenNone: CFStringTokenizerTokenType = 0; +pub const kCFStringTokenizerTokenNormal: CFStringTokenizerTokenType = 1 << 0; +pub const kCFStringTokenizerTokenHasSubTokensMask: CFStringTokenizerTokenType = 1 << 1; +pub const kCFStringTokenizerTokenHasDerivedSubTokensMask: CFStringTokenizerTokenType = 1 << 2; +pub const kCFStringTokenizerTokenHasHasNumbersMask: CFStringTokenizerTokenType = 1 << 3; +pub const kCFStringTokenizerTokenHasNonLettersMask: CFStringTokenizerTokenType = 1 << 4; +pub const kCFStringTokenizerTokenIsCJWordMask: CFStringTokenizerTokenType = 1 << 5; + +/* Tokenization Modifiers */ +pub const kCFStringTokenizerUnitWord: CFOptionFlags = 0; +pub const kCFStringTokenizerUnitSentence: CFOptionFlags = 1; +pub const kCFStringTokenizerUnitParagraph: CFOptionFlags = 2; +pub const kCFStringTokenizerUnitLineBreak: CFOptionFlags = 3; +pub const kCFStringTokenizerUnitWordBoundary: CFOptionFlags = 4; +pub const kCFStringTokenizerAttributeLatinTranscription: CFOptionFlags = 1 << 16; +pub const kCFStringTokenizerAttributeLanguage: CFOptionFlags = 1 << 17; + +extern "C" { + /* + * CFStringTokenizer.h + */ + + /* Creating a Tokenizer */ + pub fn CFStringTokenizerCreate( + alloc: CFAllocatorRef, + string: CFStringRef, + range: CFRange, + options: CFOptionFlags, + locale: CFLocaleRef, + ) -> CFStringTokenizerRef; + + /* Setting the String */ + pub fn CFStringTokenizerSetString( + tokenizer: CFStringTokenizerRef, + string: CFStringRef, + range: CFRange, + ); + + /* Changing the Location */ + pub fn CFStringTokenizerAdvanceToNextToken( + tokenizer: CFStringTokenizerRef, + ) -> CFStringTokenizerTokenType; + pub fn CFStringTokenizerGoToTokenAtIndex( + tokenizer: CFStringTokenizerRef, + index: CFIndex, + ) -> CFStringTokenizerTokenType; + + /* Getting Information About the Current Token */ + pub fn CFStringTokenizerCopyCurrentTokenAttribute( + tokenizer: CFStringTokenizerRef, + attribute: CFOptionFlags, + ) -> CFTypeRef; + pub fn CFStringTokenizerGetCurrentTokenRange(tokenizer: CFStringTokenizerRef) -> CFRange; + pub fn CFStringTokenizerGetCurrentSubTokens( + tokenizer: CFStringTokenizerRef, + ranges: *mut CFRange, + maxRangeLength: CFIndex, + derivedSubTokens: CFMutableArrayRef, + ) -> CFIndex; + + /* Identifying a Language */ + pub fn CFStringTokenizerCopyBestStringLanguage( + string: CFStringRef, + range: CFRange, + ) -> CFStringRef; + + /* Getting the CFStringTokenizer Type ID */ + pub fn CFStringTokenizerGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/timezone.rs b/third_party/rust/core-foundation-sys/src/timezone.rs index 0b279db188..076062a491 100644 --- a/third_party/rust/core-foundation-sys/src/timezone.rs +++ b/third_party/rust/core-foundation-sys/src/timezone.rs @@ -9,21 +9,83 @@ use std::os::raw::c_void; -use base::{CFAllocatorRef, CFTypeID}; -use date::{CFTimeInterval, CFAbsoluteTime}; -use string::CFStringRef; +use crate::array::CFArrayRef; +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFTypeID}; +use crate::data::CFDataRef; +use crate::date::{CFAbsoluteTime, CFTimeInterval}; +use crate::dictionary::CFDictionaryRef; +use crate::locale::CFLocaleRef; +use crate::notification_center::CFNotificationName; +use crate::string::CFStringRef; #[repr(C)] pub struct __CFTimeZone(c_void); pub type CFTimeZoneRef = *const __CFTimeZone; +pub type CFTimeZoneNameStyle = CFIndex; -extern { - pub fn CFTimeZoneCopySystem() -> CFTimeZoneRef; +/* Constants to specify styles for time zone names */ +pub const kCFTimeZoneNameStyleStandard: CFTimeZoneNameStyle = 0; +pub const kCFTimeZoneNameStyleShortStandard: CFTimeZoneNameStyle = 1; +pub const kCFTimeZoneNameStyleDaylightSaving: CFTimeZoneNameStyle = 2; +pub const kCFTimeZoneNameStyleShortDaylightSaving: CFTimeZoneNameStyle = 3; +pub const kCFTimeZoneNameStyleGeneric: CFTimeZoneNameStyle = 4; +pub const kCFTimeZoneNameStyleShortGeneric: CFTimeZoneNameStyle = 5; + +extern "C" { + /* + * CFTimeZone.h + */ + + pub static kCFTimeZoneSystemTimeZoneDidChangeNotification: CFNotificationName; + + /* Creating a Time Zone */ + pub fn CFTimeZoneCreate( + allocator: CFAllocatorRef, + name: CFStringRef, + data: CFDataRef, + ) -> CFTimeZoneRef; + pub fn CFTimeZoneCreateWithName( + allocator: CFAllocatorRef, + name: CFStringRef, + tryAbbrev: Boolean, + ) -> CFTimeZoneRef; + pub fn CFTimeZoneCreateWithTimeIntervalFromGMT( + allocator: CFAllocatorRef, + interval: CFTimeInterval, + ) -> CFTimeZoneRef; + + /* System and Default Time Zones and Information */ + pub fn CFTimeZoneCopyAbbreviationDictionary() -> CFDictionaryRef; + pub fn CFTimeZoneCopyAbbreviation(tz: CFTimeZoneRef, at: CFAbsoluteTime) -> CFStringRef; pub fn CFTimeZoneCopyDefault() -> CFTimeZoneRef; - pub fn CFTimeZoneCreateWithTimeIntervalFromGMT(allocator: CFAllocatorRef, interval: CFTimeInterval) -> CFTimeZoneRef; + pub fn CFTimeZoneCopySystem() -> CFTimeZoneRef; + pub fn CFTimeZoneSetDefault(tz: CFTimeZoneRef); + pub fn CFTimeZoneCopyKnownNames() -> CFArrayRef; + pub fn CFTimeZoneResetSystem(); + pub fn CFTimeZoneSetAbbreviationDictionary(dict: CFDictionaryRef); + + /* Getting Information About Time Zones */ + pub fn CFTimeZoneGetName(tz: CFTimeZoneRef) -> CFStringRef; + pub fn CFTimeZoneCopyLocalizedName( + tz: CFTimeZoneRef, + style: CFTimeZoneNameStyle, + locale: CFLocaleRef, + ) -> CFStringRef; pub fn CFTimeZoneGetSecondsFromGMT(tz: CFTimeZoneRef, time: CFAbsoluteTime) -> CFTimeInterval; + pub fn CFTimeZoneGetData(tz: CFTimeZoneRef) -> CFDataRef; + /* Getting Daylight Savings Time Information */ + pub fn CFTimeZoneIsDaylightSavingTime(tz: CFTimeZoneRef, at: CFAbsoluteTime) -> Boolean; + pub fn CFTimeZoneGetDaylightSavingTimeOffset( + tz: CFTimeZoneRef, + at: CFAbsoluteTime, + ) -> CFTimeInterval; + pub fn CFTimeZoneGetNextDaylightSavingTimeTransition( + tz: CFTimeZoneRef, + at: CFAbsoluteTime, + ) -> CFAbsoluteTime; + + /* Getting the CFTimeZone Type ID */ pub fn CFTimeZoneGetTypeID() -> CFTypeID; - pub fn CFTimeZoneGetName(tz: CFTimeZoneRef) -> CFStringRef; } diff --git a/third_party/rust/core-foundation-sys/src/tree.rs b/third_party/rust/core-foundation-sys/src/tree.rs new file mode 100644 index 0000000000..da6fdd607d --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/tree.rs @@ -0,0 +1,74 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{CFAllocatorRef, CFComparatorFunction, CFIndex, CFTypeID}; +use crate::string::CFStringRef; + +#[repr(C)] +pub struct __CFTree(c_void); +pub type CFTreeRef = *mut __CFTree; + +pub type CFTreeRetainCallBack = extern "C" fn(info: *const c_void) -> *const c_void; +pub type CFTreeReleaseCallBack = extern "C" fn(info: *const c_void); +pub type CFTreeCopyDescriptionCallBack = extern "C" fn(info: *const c_void) -> CFStringRef; +pub type CFTreeApplierFunction = extern "C" fn(value: *const c_void, context: *mut c_void); + +#[repr(C)] +pub struct CFTreeContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: CFTreeRetainCallBack, + pub release: CFTreeReleaseCallBack, + pub copyDescription: CFTreeCopyDescriptionCallBack, +} + +extern "C" { + /* + * CFTree.h + */ + /* Creating Trees */ + pub fn CFTreeCreate(allocator: CFAllocatorRef, context: *const CFTreeContext) -> CFTreeRef; + + /* Modifying a Tree */ + pub fn CFTreeAppendChild(tree: CFTreeRef, newChild: CFTreeRef); + pub fn CFTreeInsertSibling(tree: CFTreeRef, newSibling: CFTreeRef); + pub fn CFTreeRemoveAllChildren(tree: CFTreeRef); + pub fn CFTreePrependChild(tree: CFTreeRef, newChild: CFTreeRef); + pub fn CFTreeRemove(tree: CFTreeRef); + pub fn CFTreeSetContext(tree: CFTreeRef, context: *const CFTreeContext); + + /* Sorting a Tree */ + pub fn CFTreeSortChildren( + tree: CFTreeRef, + comparator: CFComparatorFunction, + context: *mut c_void, + ); + + /* Examining a Tree */ + pub fn CFTreeFindRoot(tree: CFTreeRef) -> CFTreeRef; + pub fn CFTreeGetChildAtIndex(tree: CFTreeRef, idx: CFIndex) -> CFTreeRef; + pub fn CFTreeGetChildCount(tree: CFTreeRef) -> CFIndex; + pub fn CFTreeGetChildren(tree: CFTreeRef, children: *mut CFTreeRef); + pub fn CFTreeGetContext(tree: CFTreeRef, context: *mut CFTreeContext); + pub fn CFTreeGetFirstChild(tree: CFTreeRef) -> CFTreeRef; + pub fn CFTreeGetNextSibling(tree: CFTreeRef) -> CFTreeRef; + pub fn CFTreeGetParent(tree: CFTreeRef) -> CFTreeRef; + + /* Performing an Operation on Tree Elements */ + pub fn CFTreeApplyFunctionToChildren( + tree: CFTreeRef, + applier: CFTreeApplierFunction, + context: *mut c_void, + ); + + /* Getting the Tree Type ID */ + pub fn CFTreeGetTypeID() -> CFTypeID; +} diff --git a/third_party/rust/core-foundation-sys/src/url.rs b/third_party/rust/core-foundation-sys/src/url.rs index 08e7bcd9fe..2274d3608f 100644 --- a/third_party/rust/core-foundation-sys/src/url.rs +++ b/third_party/rust/core-foundation-sys/src/url.rs @@ -9,12 +9,14 @@ use std::os::raw::c_void; -use base::{CFOptionFlags, CFIndex, CFAllocatorRef, Boolean, CFTypeID, CFTypeRef, SInt32}; -use data::CFDataRef; -use array::CFArrayRef; -use dictionary::CFDictionaryRef; -use string::{CFStringRef, CFStringEncoding}; -use error::CFErrorRef; +use crate::array::CFArrayRef; +use crate::base::{ + Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFRange, CFTypeID, CFTypeRef, SInt32, +}; +use crate::data::CFDataRef; +use crate::dictionary::CFDictionaryRef; +use crate::error::CFErrorRef; +use crate::string::{CFStringEncoding, CFStringRef}; #[repr(C)] pub struct __CFURL(c_void); @@ -28,95 +30,330 @@ pub type CFURLBookmarkFileCreationOptions = CFOptionFlags; pub type CFURLPathStyle = CFIndex; /* typedef CF_ENUM(CFIndex, CFURLPathStyle) */ -pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0; -pub const kCFURLHFSPathStyle: CFURLPathStyle = 1; +pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0; +pub const kCFURLHFSPathStyle: CFURLPathStyle = 1; pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2; -pub static kCFURLBookmarkCreationPreferFileIDResolutionMask: CFURLBookmarkCreationOptions = - (1u32 << 8) as usize; +/* Bookmark Data Creation Options */ pub static kCFURLBookmarkCreationMinimalBookmarkMask: CFURLBookmarkCreationOptions = (1u32 << 9) as usize; pub static kCFURLBookmarkCreationSuitableForBookmarkFile: CFURLBookmarkCreationOptions = (1u32 << 10) as usize; + +#[cfg(target_os = "macos")] pub static kCFURLBookmarkCreationWithSecurityScope: CFURLBookmarkCreationOptions = (1u32 << 11) as usize; + +#[cfg(target_os = "macos")] pub static kCFURLBookmarkCreationSecurityScopeAllowOnlyReadAccess: CFURLBookmarkCreationOptions = (1u32 << 12) as usize; -// TODO: there are a lot of missing keys and constants. Add if you are bored or need them. +pub static kCFURLBookmarkCreationWithoutImplicitSecurityScope: CFURLBookmarkCreationOptions = + (1u32 << 29) as usize; + +pub static kCFURLBookmarkCreationPreferFileIDResolutionMask: CFURLBookmarkCreationOptions = + (1u32 << 8) as usize; // deprecated + +/* The types of components in a URL. */ +pub type CFURLComponentType = CFIndex; +pub const kCFURLComponentScheme: CFIndex = 1; +pub const kCFURLComponentNetLocation: CFIndex = 2; +pub const kCFURLComponentPath: CFIndex = 3; +pub const kCFURLComponentResourceSpecifier: CFIndex = 4; +pub const kCFURLComponentUser: CFIndex = 5; +pub const kCFURLComponentPassword: CFIndex = 6; +pub const kCFURLComponentUserInfo: CFIndex = 7; +pub const kCFURLComponentHost: CFIndex = 8; +pub const kCFURLComponentPort: CFIndex = 9; +pub const kCFURLComponentParameterString: CFIndex = 10; +pub const kCFURLComponentQuery: CFIndex = 11; +pub const kCFURLComponentFragment: CFIndex = 12; -extern { +/* Bookmark Data Resolution Options */ +pub const kCFURLBookmarkResolutionWithoutUIMask: CFURLBookmarkResolutionOptions = + (1u32 << 8) as usize; +pub const kCFURLBookmarkResolutionWithoutMountingMask: CFURLBookmarkResolutionOptions = + (1u32 << 9) as usize; +#[cfg(target_os = "macos")] +pub const kCFURLBookmarkResolutionWithSecurityScope: CFURLBookmarkResolutionOptions = + (1u32 << 10) as usize; +//pub const kCFURLBookmarkResolutionWithoutImplicitStartAccessing: CFURLBookmarkResolutionOptions = ( 1u32 << 15 ) as usize; // macos(11.2)+ +pub const kCFBookmarkResolutionWithoutUIMask: CFURLBookmarkResolutionOptions = (1u32 << 8) as usize; +pub const kCFBookmarkResolutionWithoutMountingMask: CFURLBookmarkResolutionOptions = + (1u32 << 9) as usize; + +extern "C" { /* * CFURL.h */ /* Common File System Resource Keys */ - pub static kCFURLAttributeModificationDateKey: CFStringRef; - pub static kCFURLContentAccessDateKey: CFStringRef; - pub static kCFURLContentModificationDateKey: CFStringRef; - pub static kCFURLCreationDateKey: CFStringRef; - pub static kCFURLFileResourceIdentifierKey: CFStringRef; - pub static kCFURLFileSecurityKey: CFStringRef; - pub static kCFURLHasHiddenExtensionKey: CFStringRef; - pub static kCFURLIsDirectoryKey: CFStringRef; - pub static kCFURLIsExecutableKey: CFStringRef; - pub static kCFURLIsHiddenKey: CFStringRef; - pub static kCFURLIsPackageKey: CFStringRef; - pub static kCFURLIsReadableKey: CFStringRef; + pub static kCFURLNameKey: CFStringRef; + pub static kCFURLLocalizedNameKey: CFStringRef; pub static kCFURLIsRegularFileKey: CFStringRef; + pub static kCFURLIsDirectoryKey: CFStringRef; pub static kCFURLIsSymbolicLinkKey: CFStringRef; + pub static kCFURLIsVolumeKey: CFStringRef; + pub static kCFURLIsPackageKey: CFStringRef; + pub static kCFURLIsApplicationKey: CFStringRef; + // pub static kCFURLApplicationIsScriptableKey: CFStringRef; //macos(10.11)+ + pub static kCFURLIsSystemImmutableKey: CFStringRef; pub static kCFURLIsUserImmutableKey: CFStringRef; - pub static kCFURLIsVolumeKey: CFStringRef; - pub static kCFURLIsWritableKey: CFStringRef; - pub static kCFURLLabelNumberKey: CFStringRef; + pub static kCFURLIsHiddenKey: CFStringRef; + pub static kCFURLHasHiddenExtensionKey: CFStringRef; + pub static kCFURLCreationDateKey: CFStringRef; + pub static kCFURLContentAccessDateKey: CFStringRef; + pub static kCFURLContentModificationDateKey: CFStringRef; + pub static kCFURLAttributeModificationDateKey: CFStringRef; + // pub static kCFURLFileIdentifierKey: CFStringRef; //macos(13.3)+ + // pub static kCFURLFileContentIdentifierKey: CFStringRef; //macos(11.0)+ + // pub static kCFURLMayShareFileContentKey: CFStringRef; //macos(11.0)+ + // pub static kCFURLMayHaveExtendedAttributesKey: CFStringRef; //macos(11.0)+ + // pub static kCFURLIsPurgeableKey: CFStringRef; //macos(11.0)+ + // pub static kCFURLIsSparseKey: CFStringRef; //macos(11.0)+ + pub static kCFURLLinkCountKey: CFStringRef; - pub static kCFURLLocalizedLabelKey: CFStringRef; - pub static kCFURLLocalizedNameKey: CFStringRef; - pub static kCFURLLocalizedTypeDescriptionKey: CFStringRef; - pub static kCFURLNameKey: CFStringRef; pub static kCFURLParentDirectoryURLKey: CFStringRef; - pub static kCFURLPreferredIOBlockSizeKey: CFStringRef; - pub static kCFURLTypeIdentifierKey: CFStringRef; - pub static kCFURLVolumeIdentifierKey: CFStringRef; pub static kCFURLVolumeURLKey: CFStringRef; - #[cfg(feature="mac_os_10_8_features")] + pub static kCFURLTypeIdentifierKey: CFStringRef; //deprecated + + pub static kCFURLLocalizedTypeDescriptionKey: CFStringRef; + pub static kCFURLLabelNumberKey: CFStringRef; + pub static kCFURLLabelColorKey: CFStringRef; //deprecated + pub static kCFURLLocalizedLabelKey: CFStringRef; + pub static kCFURLEffectiveIconKey: CFStringRef; //deprecated + pub static kCFURLCustomIconKey: CFStringRef; //deprecated + + pub static kCFURLFileResourceIdentifierKey: CFStringRef; + pub static kCFURLVolumeIdentifierKey: CFStringRef; + pub static kCFURLPreferredIOBlockSizeKey: CFStringRef; + pub static kCFURLIsReadableKey: CFStringRef; + pub static kCFURLIsWritableKey: CFStringRef; + pub static kCFURLIsExecutableKey: CFStringRef; + pub static kCFURLFileSecurityKey: CFStringRef; + + #[cfg(feature = "mac_os_10_8_features")] #[cfg_attr(feature = "mac_os_10_7_support", linkage = "extern_weak")] pub static kCFURLIsExcludedFromBackupKey: CFStringRef; + // pub static kCFURLTagNamesKey: CFStringRef; //macos(10.9)+ + #[cfg(feature = "mac_os_10_8_features")] + #[cfg_attr(feature = "mac_os_10_7_support", linkage = "extern_weak")] + pub static kCFURLPathKey: CFStringRef; // macos(10.8)+ + pub static kCFURLCanonicalPathKey: CFStringRef; // macos(10.12)+ + + pub static kCFURLIsMountTriggerKey: CFStringRef; + + // pub static kCFURLGenerationIdentifierKey: CFStringRef; // macos(10.10)+ + // pub static kCFURLDocumentIdentifierKey: CFStringRef; // macos(10.10)+ + // pub static kCFURLAddedToDirectoryDateKey: CFStringRef; // macos(10.10)+ + // pub static kCFURLQuarantinePropertiesKey: CFStringRef; // macos(10.10)+ + pub static kCFURLFileResourceTypeKey: CFStringRef; + /* File Resource Types. The file system object type values returned for the kCFURLFileResourceTypeKey */ + pub static kCFURLFileResourceTypeNamedPipe: CFStringRef; + pub static kCFURLFileResourceTypeCharacterSpecial: CFStringRef; + pub static kCFURLFileResourceTypeDirectory: CFStringRef; + pub static kCFURLFileResourceTypeBlockSpecial: CFStringRef; + pub static kCFURLFileResourceTypeRegular: CFStringRef; + pub static kCFURLFileResourceTypeSymbolicLink: CFStringRef; + pub static kCFURLFileResourceTypeSocket: CFStringRef; + pub static kCFURLFileResourceTypeUnknown: CFStringRef; + + /* File Property Keys */ + pub static kCFURLFileSizeKey: CFStringRef; + pub static kCFURLFileAllocatedSizeKey: CFStringRef; + pub static kCFURLTotalFileSizeKey: CFStringRef; + pub static kCFURLTotalFileAllocatedSizeKey: CFStringRef; + pub static kCFURLIsAliasFileKey: CFStringRef; + + // pub static kCFURLFileProtectionKey: CFStringRef; // ios(9.0)+ + + /* The protection level values returned for the kCFURLFileProtectionKey */ + // pub static kCFURLFileProtectionNone: CFStringRef; // ios(9.0)+ + // pub static kCFURLFileProtectionComplete: CFStringRef; // ios(9.0)+ + // pub static kCFURLFileProtectionCompleteUnlessOpen: CFStringRef; // ios(9.0)+ + // pub static kCFURLFileProtectionCompleteUntilFirstUserAuthentication: CFStringRef; // ios(9.0)+ + + /* Volume Property Keys */ + pub static kCFURLVolumeLocalizedFormatDescriptionKey: CFStringRef; + pub static kCFURLVolumeTotalCapacityKey: CFStringRef; + pub static kCFURLVolumeAvailableCapacityKey: CFStringRef; + //pub static kCFURLVolumeAvailableCapacityForImportantUsageKey: CFStringRef; //macos(10.13)+ + //pub static kCFURLVolumeAvailableCapacityForOpportunisticUsageKey: CFStringRef; //macos(10.13)+ + + pub static kCFURLVolumeResourceCountKey: CFStringRef; + pub static kCFURLVolumeSupportsPersistentIDsKey: CFStringRef; + pub static kCFURLVolumeSupportsSymbolicLinksKey: CFStringRef; + pub static kCFURLVolumeSupportsHardLinksKey: CFStringRef; + pub static kCFURLVolumeSupportsJournalingKey: CFStringRef; + pub static kCFURLVolumeIsJournalingKey: CFStringRef; + pub static kCFURLVolumeSupportsSparseFilesKey: CFStringRef; + pub static kCFURLVolumeSupportsZeroRunsKey: CFStringRef; + pub static kCFURLVolumeSupportsCaseSensitiveNamesKey: CFStringRef; + pub static kCFURLVolumeSupportsCasePreservedNamesKey: CFStringRef; + pub static kCFURLVolumeSupportsRootDirectoryDatesKey: CFStringRef; + pub static kCFURLVolumeSupportsVolumeSizesKey: CFStringRef; + pub static kCFURLVolumeSupportsRenamingKey: CFStringRef; + pub static kCFURLVolumeSupportsAdvisoryFileLockingKey: CFStringRef; + pub static kCFURLVolumeSupportsExtendedSecurityKey: CFStringRef; + pub static kCFURLVolumeIsBrowsableKey: CFStringRef; + pub static kCFURLVolumeMaximumFileSizeKey: CFStringRef; + pub static kCFURLVolumeIsEjectableKey: CFStringRef; + pub static kCFURLVolumeIsRemovableKey: CFStringRef; + pub static kCFURLVolumeIsInternalKey: CFStringRef; + pub static kCFURLVolumeIsAutomountedKey: CFStringRef; + pub static kCFURLVolumeIsLocalKey: CFStringRef; + pub static kCFURLVolumeIsReadOnlyKey: CFStringRef; + pub static kCFURLVolumeCreationDateKey: CFStringRef; + pub static kCFURLVolumeURLForRemountingKey: CFStringRef; + pub static kCFURLVolumeUUIDStringKey: CFStringRef; + pub static kCFURLVolumeNameKey: CFStringRef; + pub static kCFURLVolumeLocalizedNameKey: CFStringRef; + // pub static kCFURLVolumeIsEncryptedKey: CFStringRef; //macos(10.12)+ + // pub static kCFURLVolumeIsRootFileSystemKey: CFStringRef; //macos(10.12)+ + // pub static kCFURLVolumeSupportsCompressionKey: CFStringRef; //macos(10.12)+ + // pub static kCFURLVolumeSupportsFileCloningKey: CFStringRef; //macos(10.12)+ + // pub static kCFURLVolumeSupportsSwapRenamingKey: CFStringRef; //macos(10.12)+ + // pub static kCFURLVolumeSupportsExclusiveRenamingKey: CFStringRef; //macos(10.12)+ + // pub static kCFURLVolumeSupportsImmutableFilesKey: CFStringRef; //macos(10.13)+ + // pub static kCFURLVolumeSupportsAccessPermissionsKey: CFStringRef; //macos(10.13)+ + // pub static kCFURLVolumeSupportsFileProtectionKey: CFStringRef; //macos(11.0)+ + // pub static kCFURLVolumeTypeNameKey: CFStringRef; //macos(13.3)+ + // pub static kCFURLVolumeSubtypeKey: CFStringRef; //macos(13.3)+ + // pub static kCFURLVolumeMountFromLocationKey: CFStringRef; //macos(13.3)+ + + /* iCloud Constants */ + pub static kCFURLIsUbiquitousItemKey: CFStringRef; + pub static kCFURLUbiquitousItemHasUnresolvedConflictsKey: CFStringRef; + pub static kCFURLUbiquitousItemIsDownloadedKey: CFStringRef; // deprecated + pub static kCFURLUbiquitousItemIsDownloadingKey: CFStringRef; + pub static kCFURLUbiquitousItemIsUploadedKey: CFStringRef; + pub static kCFURLUbiquitousItemIsUploadingKey: CFStringRef; + pub static kCFURLUbiquitousItemPercentDownloadedKey: CFStringRef; // deprecated + pub static kCFURLUbiquitousItemPercentUploadedKey: CFStringRef; // deprecated + // pub static kCFURLUbiquitousItemDownloadingStatusKey: CFStringRef; // macos(10.9)+ + // pub static kCFURLUbiquitousItemDownloadingErrorKey: CFStringRef; // macos(10.9)+ + // pub static kCFURLUbiquitousItemUploadingErrorKey: CFStringRef; // macos(10.9)+ + // pub static kCFURLUbiquitousItemIsExcludedFromSyncKey: CFStringRef; // macos(11.3)+ + + /* The values returned for kCFURLUbiquitousItemDownloadingStatusKey */ + // pub static kCFURLUbiquitousItemDownloadingStatusNotDownloaded: CFStringRef; // macos(10.9)+ + // pub static kCFURLUbiquitousItemDownloadingStatusDownloaded: CFStringRef; // macos(10.9)+ + // pub static kCFURLUbiquitousItemDownloadingStatusCurrent: CFStringRef; // macos(10.9)+ + + /* CFError userInfo Dictionary Keys */ + pub static kCFURLKeysOfUnsetValuesKey: CFStringRef; + /* Creating a CFURL */ pub fn CFURLCopyAbsoluteURL(anURL: CFURLRef) -> CFURLRef; - pub fn CFURLCreateAbsoluteURLWithBytes(allocator: CFAllocatorRef, relativeURLBytes: *const u8, length: CFIndex, encoding: CFStringEncoding, baseURL: CFURLRef, useCompatibilityMode: Boolean) -> CFURLRef; - pub fn CFURLCreateByResolvingBookmarkData(allocator: CFAllocatorRef, bookmark: CFDataRef, options: CFURLBookmarkResolutionOptions, relativeToURL: CFURLRef, resourcePropertiesToInclude: CFArrayRef, isStale: *mut Boolean, error: *mut CFErrorRef) -> CFURLRef; - //fn CFURLCreateCopyAppendingPathComponent - //fn CFURLCreateCopyAppendingPathExtension - //fn CFURLCreateCopyDeletingLastPathComponent - //fn CFURLCreateCopyDeletingPathExtension - pub fn CFURLCreateFilePathURL(allocator: CFAllocatorRef, url: CFURLRef, error: *mut CFErrorRef) -> CFURLRef; - //fn CFURLCreateFileReferenceURL - pub fn CFURLCreateFromFileSystemRepresentation(allocator: CFAllocatorRef, buffer: *const u8, bufLen: CFIndex, isDirectory: Boolean) -> CFURLRef; - //fn CFURLCreateFromFileSystemRepresentationRelativeToBase - //fn CFURLCreateFromFSRef - pub fn CFURLCreateWithBytes(allocator: CFAllocatorRef, URLBytes: *const u8, length: CFIndex, encoding: CFStringEncoding, baseURL: CFURLRef) -> CFURLRef; - pub fn CFURLCreateWithFileSystemPath(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean) -> CFURLRef; - pub fn CFURLCreateWithFileSystemPathRelativeToBase(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean, baseURL: CFURLRef) -> CFURLRef; - //fn CFURLCreateWithString(allocator: CFAllocatorRef, urlString: CFStringRef, - // baseURL: CFURLRef) -> CFURLRef; + pub fn CFURLCreateAbsoluteURLWithBytes( + allocator: CFAllocatorRef, + relativeURLBytes: *const u8, + length: CFIndex, + encoding: CFStringEncoding, + baseURL: CFURLRef, + useCompatibilityMode: Boolean, + ) -> CFURLRef; + pub fn CFURLCreateByResolvingBookmarkData( + allocator: CFAllocatorRef, + bookmark: CFDataRef, + options: CFURLBookmarkResolutionOptions, + relativeToURL: CFURLRef, + resourcePropertiesToInclude: CFArrayRef, + isStale: *mut Boolean, + error: *mut CFErrorRef, + ) -> CFURLRef; + pub fn CFURLCreateCopyAppendingPathComponent( + allocator: CFAllocatorRef, + url: CFURLRef, + pathComponent: CFStringRef, + isDirectory: Boolean, + ) -> CFURLRef; + pub fn CFURLCreateCopyAppendingPathExtension( + allocator: CFAllocatorRef, + url: CFURLRef, + extension: CFStringRef, + ) -> CFURLRef; + pub fn CFURLCreateCopyDeletingLastPathComponent( + allocator: CFAllocatorRef, + url: CFURLRef, + ) -> CFURLRef; + pub fn CFURLCreateCopyDeletingPathExtension( + allocator: CFAllocatorRef, + url: CFURLRef, + ) -> CFURLRef; + pub fn CFURLCreateFilePathURL( + allocator: CFAllocatorRef, + url: CFURLRef, + error: *mut CFErrorRef, + ) -> CFURLRef; + pub fn CFURLCreateFileReferenceURL( + allocator: CFAllocatorRef, + url: CFURLRef, + error: *mut CFErrorRef, + ) -> CFURLRef; + pub fn CFURLCreateFromFileSystemRepresentation( + allocator: CFAllocatorRef, + buffer: *const u8, + bufLen: CFIndex, + isDirectory: Boolean, + ) -> CFURLRef; + pub fn CFURLCreateFromFileSystemRepresentationRelativeToBase( + allocator: CFAllocatorRef, + buffer: *const u8, + bufLen: CFIndex, + isDirectory: Boolean, + baseURL: CFURLRef, + ) -> CFURLRef; + //pub fn CFURLCreateFromFSRef(allocator: CFAllocatorRef, fsRef: *const FSRef) -> CFURLRef + pub fn CFURLCreateWithBytes( + allocator: CFAllocatorRef, + URLBytes: *const u8, + length: CFIndex, + encoding: CFStringEncoding, + baseURL: CFURLRef, + ) -> CFURLRef; + pub fn CFURLCreateWithFileSystemPath( + allocator: CFAllocatorRef, + filePath: CFStringRef, + pathStyle: CFURLPathStyle, + isDirectory: Boolean, + ) -> CFURLRef; + pub fn CFURLCreateWithFileSystemPathRelativeToBase( + allocator: CFAllocatorRef, + filePath: CFStringRef, + pathStyle: CFURLPathStyle, + isDirectory: Boolean, + baseURL: CFURLRef, + ) -> CFURLRef; + pub fn CFURLCreateWithString( + allocator: CFAllocatorRef, + URLString: CFStringRef, + baseURL: CFURLRef, + ) -> CFURLRef; /* Accessing the Parts of a URL */ pub fn CFURLCanBeDecomposed(anURL: CFURLRef) -> Boolean; pub fn CFURLCopyFileSystemPath(anURL: CFURLRef, pathStyle: CFURLPathStyle) -> CFStringRef; - pub fn CFURLCopyFragment(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyFragment(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) + -> CFStringRef; pub fn CFURLCopyHostName(anURL: CFURLRef) -> CFStringRef; pub fn CFURLCopyLastPathComponent(anURL: CFURLRef) -> CFStringRef; pub fn CFURLCopyNetLocation(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyParameterString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyParameterString( + anURL: CFURLRef, + charactersToLeaveEscaped: CFStringRef, + ) -> CFStringRef; // deprecated pub fn CFURLCopyPassword(anURL: CFURLRef) -> CFStringRef; pub fn CFURLCopyPath(anURL: CFURLRef) -> CFStringRef; pub fn CFURLCopyPathExtension(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyQueryString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyQueryString( + anURL: CFURLRef, + charactersToLeaveEscaped: CFStringRef, + ) -> CFStringRef; pub fn CFURLCopyResourceSpecifier(anURL: CFURLRef) -> CFStringRef; pub fn CFURLCopyScheme(anURL: CFURLRef) -> CFStringRef; pub fn CFURLCopyStrictPath(anURL: CFURLRef, isAbsolute: *mut Boolean) -> CFStringRef; @@ -125,45 +362,120 @@ extern { pub fn CFURLHasDirectoryPath(anURL: CFURLRef) -> Boolean; /* Converting URLs to Other Representations */ - //fn CFURLCreateData(allocator: CFAllocatorRef, url: CFURLRef, - // encoding: CFStringEncoding, escapeWhitespace: bool) -> CFDataRef; - //fn CFURLCreateStringByAddingPercentEscapes - //fn CFURLCreateStringByReplacingPercentEscapes - //fn CFURLCreateStringByReplacingPercentEscapesUsingEncoding - pub fn CFURLGetFileSystemRepresentation(anURL: CFURLRef, resolveAgainstBase: Boolean, buffer: *mut u8, maxBufLen: CFIndex) -> Boolean; - - //fn CFURLGetFSRef + pub fn CFURLCreateData( + allocator: CFAllocatorRef, + url: CFURLRef, + encoding: CFStringEncoding, + escapeWhitespace: Boolean, + ) -> CFDataRef; + pub fn CFURLCreateStringByAddingPercentEscapes( + allocator: CFAllocatorRef, + originalString: CFStringRef, + charactersToLeaveUnescaped: CFStringRef, + legalURLCharactersToBeEscaped: CFStringRef, + encoding: CFStringEncoding, + ) -> CFStringRef; // API_DEPRECATED("Use [NSString stringByAddingPercentEncodingWithAllowedCharacters:] instead, which always uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent (since each URL component or subcomponent has different rules for what characters are valid).", macos(10.0,10.11), ios(2.0,9.0), watchos(2.0,2.0), tvos(9.0,9.0)); + pub fn CFURLCreateStringByReplacingPercentEscapes( + allocator: CFAllocatorRef, + originalString: CFStringRef, + charactersToLeaveEscaped: CFStringRef, + ) -> CFStringRef; + pub fn CFURLCreateStringByReplacingPercentEscapesUsingEncoding( + allocator: CFAllocatorRef, + origString: CFStringRef, + charsToLeaveEscaped: CFStringRef, + encoding: CFStringEncoding, + ) -> CFStringRef; // deprecated + pub fn CFURLGetFileSystemRepresentation( + anURL: CFURLRef, + resolveAgainstBase: Boolean, + buffer: *mut u8, + maxBufLen: CFIndex, + ) -> Boolean; + //pub fn CFURLIsFileReferenceURL(url: CFURLRef) -> Boolean; // macos(10.9)+ + //pub fn CFURLGetFSRef(url: CFURLRef, fsRef: *mut FSRef) -> Boolean; pub fn CFURLGetString(anURL: CFURLRef) -> CFStringRef; /* Getting URL Properties */ - //fn CFURLGetBaseURL(anURL: CFURLRef) -> CFURLRef; + pub fn CFURLGetBaseURL(anURL: CFURLRef) -> CFURLRef; pub fn CFURLGetBytes(anURL: CFURLRef, buffer: *mut u8, bufferLength: CFIndex) -> CFIndex; - //fn CFURLGetByteRangeForComponent + pub fn CFURLGetByteRangeForComponent( + url: CFURLRef, + component: CFURLComponentType, + rangeIncludingSeparators: *mut CFRange, + ) -> CFRange; pub fn CFURLGetTypeID() -> CFTypeID; - //fn CFURLResourceIsReachable + pub fn CFURLResourceIsReachable(url: CFURLRef, error: *mut CFErrorRef) -> Boolean; /* Getting and Setting File System Resource Properties */ pub fn CFURLClearResourcePropertyCache(url: CFURLRef); - //fn CFURLClearResourcePropertyCacheForKey - //fn CFURLCopyResourcePropertiesForKeys - //fn CFURLCopyResourcePropertyForKey - pub fn CFURLCreateResourcePropertiesForKeysFromBookmarkData(allocator: CFAllocatorRef, resourcePropertiesToReturn: CFArrayRef, bookmark: CFDataRef) -> CFDictionaryRef; - pub fn CFURLCreateResourcePropertyForKeyFromBookmarkData(allocator: CFAllocatorRef, resourcePropertyKey: CFStringRef, bookmark: CFDataRef) -> CFTypeRef; - //fn CFURLSetResourcePropertiesForKeys - pub fn CFURLSetResourcePropertyForKey(url: CFURLRef, key: CFStringRef, value: CFTypeRef, error: *mut CFErrorRef) -> Boolean; - //fn CFURLSetTemporaryResourcePropertyForKey + pub fn CFURLClearResourcePropertyCacheForKey(url: CFURLRef, key: CFStringRef); + pub fn CFURLCopyResourcePropertiesForKeys( + url: CFURLRef, + keys: CFArrayRef, + error: *mut CFErrorRef, + ) -> CFDictionaryRef; + //pub fn CFURLCopyResourcePropertyForKey(url: CFURLRef, key: CFStringRef, propertyValueTypeRefPtr: *mut c_void, error: *mut CFErrorRef) -> Boolean + pub fn CFURLCreateResourcePropertiesForKeysFromBookmarkData( + allocator: CFAllocatorRef, + resourcePropertiesToReturn: CFArrayRef, + bookmark: CFDataRef, + ) -> CFDictionaryRef; + pub fn CFURLCreateResourcePropertyForKeyFromBookmarkData( + allocator: CFAllocatorRef, + resourcePropertyKey: CFStringRef, + bookmark: CFDataRef, + ) -> CFTypeRef; + pub fn CFURLSetResourcePropertiesForKeys( + url: CFURLRef, + keyedPropertyValues: CFDictionaryRef, + error: *mut CFErrorRef, + ) -> Boolean; + pub fn CFURLSetResourcePropertyForKey( + url: CFURLRef, + key: CFStringRef, + value: CFTypeRef, + error: *mut CFErrorRef, + ) -> Boolean; + pub fn CFURLSetTemporaryResourcePropertyForKey( + url: CFURLRef, + key: CFStringRef, + propertyValue: CFTypeRef, + ); /* Working with Bookmark Data */ - pub fn CFURLCreateBookmarkData(allocator: CFAllocatorRef, url: CFURLRef, options: CFURLBookmarkCreationOptions, resourcePropertiesToInclude: CFArrayRef, relativeToURL: CFURLRef, error: *mut CFErrorRef) -> CFDataRef; - pub fn CFURLCreateBookmarkDataFromAliasRecord(allocator: CFAllocatorRef, aliasRecordDataRef: CFDataRef) -> CFDataRef; - pub fn CFURLCreateBookmarkDataFromFile(allocator: CFAllocatorRef, fileURL: CFURLRef, errorRef: *mut CFErrorRef) -> CFDataRef; - pub fn CFURLWriteBookmarkDataToFile(bookmarkRef: CFDataRef, fileURL: CFURLRef, options: CFURLBookmarkFileCreationOptions, errorRef: *mut CFErrorRef) -> Boolean; + pub fn CFURLCreateBookmarkData( + allocator: CFAllocatorRef, + url: CFURLRef, + options: CFURLBookmarkCreationOptions, + resourcePropertiesToInclude: CFArrayRef, + relativeToURL: CFURLRef, + error: *mut CFErrorRef, + ) -> CFDataRef; + + #[cfg(target_os = "macos")] + pub fn CFURLCreateBookmarkDataFromAliasRecord( + allocator: CFAllocatorRef, + aliasRecordDataRef: CFDataRef, + ) -> CFDataRef; // deprecated + + pub fn CFURLCreateBookmarkDataFromFile( + allocator: CFAllocatorRef, + fileURL: CFURLRef, + errorRef: *mut CFErrorRef, + ) -> CFDataRef; + pub fn CFURLWriteBookmarkDataToFile( + bookmarkRef: CFDataRef, + fileURL: CFURLRef, + options: CFURLBookmarkFileCreationOptions, + errorRef: *mut CFErrorRef, + ) -> Boolean; pub fn CFURLStartAccessingSecurityScopedResource(url: CFURLRef) -> Boolean; pub fn CFURLStopAccessingSecurityScopedResource(url: CFURLRef); } #[test] -#[cfg(feature="mac_os_10_8_features")] +#[cfg(feature = "mac_os_10_8_features")] fn can_see_excluded_from_backup_key() { let _ = unsafe { kCFURLIsExcludedFromBackupKey }; } diff --git a/third_party/rust/core-foundation-sys/src/url_enumerator.rs b/third_party/rust/core-foundation-sys/src/url_enumerator.rs new file mode 100644 index 0000000000..71b74beb5b --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/url_enumerator.rs @@ -0,0 +1,62 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::array::CFArrayRef; +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeID}; +use crate::error::CFErrorRef; +use crate::url::CFURLRef; + +#[repr(C)] +pub struct __CFURLEnumerator(c_void); + +pub type CFURLEnumeratorRef = *mut __CFURLEnumerator; + +pub type CFURLEnumeratorOptions = CFOptionFlags; +pub const kCFURLEnumeratorDefaultBehavior: CFURLEnumeratorOptions = 0; +pub const kCFURLEnumeratorDescendRecursively: CFURLEnumeratorOptions = 1 << 0; +pub const kCFURLEnumeratorSkipInvisibles: CFURLEnumeratorOptions = 1 << 1; +pub const kCFURLEnumeratorGenerateFileReferenceURLs: CFURLEnumeratorOptions = 1 << 2; +pub const kCFURLEnumeratorSkipPackageContents: CFURLEnumeratorOptions = 1 << 3; +pub const kCFURLEnumeratorIncludeDirectoriesPreOrder: CFURLEnumeratorOptions = 1 << 4; +pub const kCFURLEnumeratorIncludeDirectoriesPostOrder: CFURLEnumeratorOptions = 1 << 5; +//pub const kCFURLEnumeratorGenerateRelativePathURLs = 1UL << 6; // macos(10.15)+ + +pub type CFURLEnumeratorResult = CFIndex; +pub const kCFURLEnumeratorSuccess: CFURLEnumeratorOptions = 1; +pub const kCFURLEnumeratorEnd: CFURLEnumeratorOptions = 2; +pub const kCFURLEnumeratorError: CFURLEnumeratorOptions = 3; +pub const kCFURLEnumeratorDirectoryPostOrderSuccess: CFURLEnumeratorOptions = 4; + +extern "C" { + /* + * CFURLEnumerator.h + */ + pub fn CFURLEnumeratorGetTypeID() -> CFTypeID; + pub fn CFURLEnumeratorCreateForDirectoryURL( + alloc: CFAllocatorRef, + directoryURL: CFURLRef, + option: CFURLEnumeratorOptions, + propertyKeys: CFArrayRef, + ) -> CFURLEnumeratorRef; + pub fn CFURLEnumeratorCreateForMountedVolumes( + alloc: CFAllocatorRef, + option: CFURLEnumeratorOptions, + propertyKeys: CFArrayRef, + ) -> CFURLEnumeratorRef; + pub fn CFURLEnumeratorGetNextURL( + enumerator: CFURLEnumeratorRef, + url: *mut CFURLRef, + error: *mut CFErrorRef, + ) -> CFURLEnumeratorResult; + pub fn CFURLEnumeratorSkipDescendents(enumerator: CFURLEnumeratorRef); + pub fn CFURLEnumeratorGetDescendentLevel(enumerator: CFURLEnumeratorRef) -> CFIndex; + pub fn CFURLEnumeratorGetSourceDidChange(enumerator: CFURLEnumeratorRef) -> Boolean; // deprecated since macos 10.7 +} diff --git a/third_party/rust/core-foundation-sys/src/user_notification.rs b/third_party/rust/core-foundation-sys/src/user_notification.rs new file mode 100644 index 0000000000..6432718261 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/user_notification.rs @@ -0,0 +1,138 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeID, SInt32}; +use crate::date::CFTimeInterval; +use crate::dictionary::CFDictionaryRef; +use crate::runloop::CFRunLoopSourceRef; +use crate::string::CFStringRef; +use crate::url::CFURLRef; + +#[repr(C)] +pub struct __CFUserNotification(c_void); + +pub type CFUserNotificationCallBack = + extern "C" fn(userNotification: CFUserNotificationRef, responseFlags: CFOptionFlags); +pub type CFUserNotificationRef = *mut __CFUserNotification; + +/* Alert Levels */ +pub const kCFUserNotificationStopAlertLevel: CFOptionFlags = 0; +pub const kCFUserNotificationNoteAlertLevel: CFOptionFlags = 1; +pub const kCFUserNotificationCautionAlertLevel: CFOptionFlags = 2; +pub const kCFUserNotificationPlainAlertLevel: CFOptionFlags = 3; + +/* Response Codes */ +pub const kCFUserNotificationDefaultResponse: CFOptionFlags = 0; +pub const kCFUserNotificationAlternateResponse: CFOptionFlags = 1; +pub const kCFUserNotificationOtherResponse: CFOptionFlags = 2; +pub const kCFUserNotificationCancelResponse: CFOptionFlags = 3; + +/* Button Flags */ +pub const kCFUserNotificationNoDefaultButtonFlag: CFOptionFlags = 1usize << 5; +pub const kCFUserNotificationUseRadioButtonsFlag: CFOptionFlags = 1usize << 6; + +#[inline(always)] +pub fn CFUserNotificationCheckBoxChecked(i: CFIndex) -> CFOptionFlags { + (1u32 << (8 + i)) as CFOptionFlags +} + +#[inline(always)] +pub fn CFUserNotificationSecureTextField(i: CFIndex) -> CFOptionFlags { + (1u32 << (16 + i)) as CFOptionFlags +} + +#[inline(always)] +pub fn CFUserNotificationPopUpSelection(n: CFIndex) -> CFOptionFlags { + (n << 24) as CFOptionFlags +} + +extern "C" { + /* + * CFUserNotification.h + */ + + /* Dialog Description Keys */ + pub static kCFUserNotificationIconURLKey: CFStringRef; + pub static kCFUserNotificationSoundURLKey: CFStringRef; + pub static kCFUserNotificationLocalizationURLKey: CFStringRef; + pub static kCFUserNotificationAlertHeaderKey: CFStringRef; + pub static kCFUserNotificationAlertMessageKey: CFStringRef; + pub static kCFUserNotificationDefaultButtonTitleKey: CFStringRef; + pub static kCFUserNotificationAlternateButtonTitleKey: CFStringRef; + pub static kCFUserNotificationOtherButtonTitleKey: CFStringRef; + pub static kCFUserNotificationProgressIndicatorValueKey: CFStringRef; + pub static kCFUserNotificationPopUpTitlesKey: CFStringRef; + pub static kCFUserNotificationTextFieldTitlesKey: CFStringRef; + pub static kCFUserNotificationCheckBoxTitlesKey: CFStringRef; + pub static kCFUserNotificationTextFieldValuesKey: CFStringRef; + pub static kCFUserNotificationPopUpSelectionKey: CFStringRef; + pub static kCFUserNotificationAlertTopMostKey: CFStringRef; + pub static kCFUserNotificationKeyboardTypesKey: CFStringRef; + + /* CFUserNotification Miscellaneous Functions */ + pub fn CFUserNotificationCancel(userNotification: CFUserNotificationRef) -> SInt32; + pub fn CFUserNotificationCreate( + allocator: CFAllocatorRef, + timeout: CFTimeInterval, + flags: CFOptionFlags, + error: *mut SInt32, + dictionary: CFDictionaryRef, + ) -> CFUserNotificationRef; + pub fn CFUserNotificationCreateRunLoopSource( + allocator: CFAllocatorRef, + userNotification: CFUserNotificationRef, + callout: CFUserNotificationCallBack, + order: CFIndex, + ) -> CFRunLoopSourceRef; + pub fn CFUserNotificationDisplayAlert( + timeout: CFTimeInterval, + flags: CFOptionFlags, + iconURL: CFURLRef, + soundURL: CFURLRef, + localizationURL: CFURLRef, + alertHeader: CFStringRef, + alertMessage: CFStringRef, + defaultButtonTitle: CFStringRef, + alternateButtonTitle: CFStringRef, + otherButtonTitle: CFStringRef, + responseFlags: *mut CFOptionFlags, + ) -> SInt32; + pub fn CFUserNotificationDisplayNotice( + timeout: CFTimeInterval, + flags: CFOptionFlags, + iconURL: CFURLRef, + soundURL: CFURLRef, + localizationURL: CFURLRef, + alertHeader: CFStringRef, + alertMessage: CFStringRef, + defaultButtonTitle: CFStringRef, + ) -> SInt32; + pub fn CFUserNotificationGetTypeID() -> CFTypeID; + pub fn CFUserNotificationGetResponseDictionary( + userNotification: CFUserNotificationRef, + ) -> CFDictionaryRef; + pub fn CFUserNotificationGetResponseValue( + userNotification: CFUserNotificationRef, + key: CFStringRef, + idx: CFIndex, + ) -> CFStringRef; + pub fn CFUserNotificationReceiveResponse( + userNotification: CFUserNotificationRef, + timeout: CFTimeInterval, + responseFlags: *mut CFOptionFlags, + ) -> SInt32; + pub fn CFUserNotificationUpdate( + userNotification: CFUserNotificationRef, + timeout: CFTimeInterval, + flags: CFOptionFlags, + dictionary: CFDictionaryRef, + ) -> SInt32; +} diff --git a/third_party/rust/core-foundation-sys/src/uuid.rs b/third_party/rust/core-foundation-sys/src/uuid.rs index 4253952938..a1714a8a8c 100644 --- a/third_party/rust/core-foundation-sys/src/uuid.rs +++ b/third_party/rust/core-foundation-sys/src/uuid.rs @@ -9,7 +9,8 @@ use std::os::raw::c_void; -use base::{CFAllocatorRef, CFTypeID}; +use crate::base::{CFAllocatorRef, CFTypeID}; +use crate::string::CFStringRef; #[repr(C)] pub struct __CFUUID(c_void); @@ -17,33 +18,78 @@ pub struct __CFUUID(c_void); pub type CFUUIDRef = *const __CFUUID; #[repr(C)] -#[derive(Clone, Copy, Default)] +#[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct CFUUIDBytes { - pub byte0: u8, - pub byte1: u8, - pub byte2: u8, - pub byte3: u8, - pub byte4: u8, - pub byte5: u8, - pub byte6: u8, - pub byte7: u8, - pub byte8: u8, - pub byte9: u8, + pub byte0: u8, + pub byte1: u8, + pub byte2: u8, + pub byte3: u8, + pub byte4: u8, + pub byte5: u8, + pub byte6: u8, + pub byte7: u8, + pub byte8: u8, + pub byte9: u8, pub byte10: u8, pub byte11: u8, pub byte12: u8, pub byte13: u8, pub byte14: u8, - pub byte15: u8 + pub byte15: u8, } -extern { +extern "C" { /* * CFUUID.h */ + + /* Creating CFUUID Objects */ pub fn CFUUIDCreate(allocator: CFAllocatorRef) -> CFUUIDRef; + pub fn CFUUIDCreateFromString(alloc: CFAllocatorRef, uuidStr: CFStringRef) -> CFUUIDRef; pub fn CFUUIDCreateFromUUIDBytes(allocator: CFAllocatorRef, bytes: CFUUIDBytes) -> CFUUIDRef; + pub fn CFUUIDCreateWithBytes( + alloc: CFAllocatorRef, + byte0: u8, + byte1: u8, + byte2: u8, + byte3: u8, + byte4: u8, + byte5: u8, + byte6: u8, + byte7: u8, + byte8: u8, + byte9: u8, + byte10: u8, + byte11: u8, + byte12: u8, + byte13: u8, + byte14: u8, + byte15: u8, + ) -> CFUUIDRef; + + /* Getting Information About CFUUID Objects */ + pub fn CFUUIDCreateString(allocator: CFAllocatorRef, uid: CFUUIDRef) -> CFStringRef; + pub fn CFUUIDGetConstantUUIDWithBytes( + alloc: CFAllocatorRef, + byte0: u8, + byte1: u8, + byte2: u8, + byte3: u8, + byte4: u8, + byte5: u8, + byte6: u8, + byte7: u8, + byte8: u8, + byte9: u8, + byte10: u8, + byte11: u8, + byte12: u8, + byte13: u8, + byte14: u8, + byte15: u8, + ) -> CFUUIDRef; pub fn CFUUIDGetUUIDBytes(uuid: CFUUIDRef) -> CFUUIDBytes; + /* Getting the CFUUID Type Identifier */ pub fn CFUUIDGetTypeID() -> CFTypeID; } diff --git a/third_party/rust/core-foundation-sys/src/xml_node.rs b/third_party/rust/core-foundation-sys/src/xml_node.rs new file mode 100644 index 0000000000..332beec823 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/xml_node.rs @@ -0,0 +1,147 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::{c_char, c_void}; + +use crate::array::CFArrayRef; +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFTypeID}; +use crate::dictionary::CFDictionaryRef; +use crate::string::{CFStringEncoding, CFStringRef}; +use crate::tree::CFTreeRef; +use crate::url::CFURLRef; + +#[repr(C)] +pub struct __CFXMLNode(c_void); + +pub type CFXMLNodeRef = *mut __CFXMLNode; +pub type CFXMLTreeRef = CFTreeRef; + +pub const kCFXMLNodeCurrentVersion: CFIndex = 1; + +pub type CFXMLNodeTypeCode = CFIndex; +pub const kCFXMLNodeTypeDocument: CFXMLNodeTypeCode = 1; +pub const kCFXMLNodeTypeElement: CFXMLNodeTypeCode = 2; +pub const kCFXMLNodeTypeAttribute: CFXMLNodeTypeCode = 3; +pub const kCFXMLNodeTypeProcessingInstruction: CFXMLNodeTypeCode = 4; +pub const kCFXMLNodeTypeComment: CFXMLNodeTypeCode = 5; +pub const kCFXMLNodeTypeText: CFXMLNodeTypeCode = 6; +pub const kCFXMLNodeTypeCDATASection: CFXMLNodeTypeCode = 7; +pub const kCFXMLNodeTypeDocumentFragment: CFXMLNodeTypeCode = 8; +pub const kCFXMLNodeTypeEntity: CFXMLNodeTypeCode = 9; +pub const kCFXMLNodeTypeEntityReference: CFXMLNodeTypeCode = 10; +pub const kCFXMLNodeTypeDocumentType: CFXMLNodeTypeCode = 11; +pub const kCFXMLNodeTypeWhitespace: CFXMLNodeTypeCode = 12; +pub const kCFXMLNodeTypeNotation: CFXMLNodeTypeCode = 13; +pub const kCFXMLNodeTypeElementTypeDeclaration: CFXMLNodeTypeCode = 14; +pub const kCFXMLNodeTypeAttributeListDeclaration: CFXMLNodeTypeCode = 15; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLElementInfo { + pub attributes: CFDictionaryRef, + pub attributeOrder: CFArrayRef, + pub isEmpty: Boolean, + pub _reserved: [c_char; 3], +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLProcessingInstructionInfo { + pub dataString: CFStringRef, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLDocumentInfo { + pub sourceURL: CFURLRef, + pub encoding: CFStringEncoding, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLExternalID { + pub systemID: CFURLRef, + pub publicID: CFStringRef, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLDocumentTypeInfo { + pub externalID: CFXMLExternalID, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLNotationInfo { + pub externalID: CFXMLExternalID, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLElementTypeDeclarationInfo { + pub contentDescription: CFStringRef, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLAttributeDeclarationInfo { + pub attributeName: CFStringRef, + pub typeString: CFStringRef, + pub defaultString: CFStringRef, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLAttributeListDeclarationInfo { + pub numberOfAttributes: CFIndex, + pub attributes: *mut CFXMLAttributeDeclarationInfo, +} + +pub type CFXMLEntityTypeCode = CFIndex; +pub const kCFXMLEntityTypeParameter: CFXMLEntityTypeCode = 0; +pub const kCFXMLEntityTypeParsedInternal: CFXMLEntityTypeCode = 1; +pub const kCFXMLEntityTypeParsedExternal: CFXMLEntityTypeCode = 2; +pub const kCFXMLEntityTypeUnparsed: CFXMLEntityTypeCode = 3; +pub const kCFXMLEntityTypeCharacter: CFXMLEntityTypeCode = 4; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLEntityInfo { + pub entityType: CFXMLEntityTypeCode, + pub replacementText: CFStringRef, + pub entityID: CFXMLExternalID, + pub notationName: CFStringRef, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLEntityReferenceInfo { + pub entityType: CFXMLEntityTypeCode, +} + +extern "C" { + /* + * CFXMLNode.h + */ + pub fn CFXMLNodeGetTypeID() -> CFTypeID; + pub fn CFXMLNodeCreate( + alloc: CFAllocatorRef, + xmlType: CFXMLNodeTypeCode, + dataString: CFStringRef, + additionalInfoPtr: *const c_void, + version: CFIndex, + ) -> CFXMLNodeRef; + pub fn CFXMLNodeCreateCopy(alloc: CFAllocatorRef, origNode: CFXMLNodeRef) -> CFXMLNodeRef; + pub fn CFXMLNodeGetTypeCode(node: CFXMLNodeRef) -> CFXMLNodeTypeCode; + pub fn CFXMLNodeGetString(node: CFXMLNodeRef) -> CFStringRef; + pub fn CFXMLNodeGetInfoPtr(node: CFXMLNodeRef) -> *const c_void; + pub fn CFXMLNodeGetVersion(node: CFXMLNodeRef) -> CFIndex; + pub fn CFXMLTreeCreateWithNode(alloc: CFAllocatorRef, node: CFXMLNodeRef) -> CFXMLTreeRef; + pub fn CFXMLTreeGetNode(xmlTree: CFXMLTreeRef) -> CFXMLNodeRef; +} diff --git a/third_party/rust/core-foundation-sys/src/xml_parser.rs b/third_party/rust/core-foundation-sys/src/xml_parser.rs new file mode 100644 index 0000000000..32dc709a60 --- /dev/null +++ b/third_party/rust/core-foundation-sys/src/xml_parser.rs @@ -0,0 +1,174 @@ +// Copyright 2023 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use crate::base::{Boolean, CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeID}; +use crate::data::CFDataRef; +use crate::dictionary::CFDictionaryRef; +use crate::string::CFStringRef; +use crate::url::CFURLRef; +use crate::xml_node::{CFXMLExternalID, CFXMLNodeRef, CFXMLTreeRef}; + +#[repr(C)] +pub struct __CFXMLParser(c_void); + +pub type CFXMLParserRef = *mut __CFXMLParser; + +pub type CFXMLParserOptions = CFOptionFlags; +pub const kCFXMLParserValidateDocument: CFXMLParserOptions = 1 << 0; +pub const kCFXMLParserSkipMetaData: CFXMLParserOptions = 1 << 1; +pub const kCFXMLParserReplacePhysicalEntities: CFXMLParserOptions = 1 << 2; +pub const kCFXMLParserSkipWhitespace: CFXMLParserOptions = 1 << 3; +pub const kCFXMLParserResolveExternalEntities: CFXMLParserOptions = 1 << 4; +pub const kCFXMLParserAddImpliedAttributes: CFXMLParserOptions = 1 << 5; +pub const kCFXMLParserAllOptions: CFXMLParserOptions = 0x00FFFFFF; +pub const kCFXMLParserNoOptions: CFXMLParserOptions = 0; + +pub type CFXMLParserStatusCode = CFIndex; +pub const kCFXMLStatusParseNotBegun: CFIndex = -2; +pub const kCFXMLStatusParseInProgress: CFIndex = -1; +pub const kCFXMLStatusParseSuccessful: CFIndex = 0; +pub const kCFXMLErrorUnexpectedEOF: CFIndex = 1; +pub const kCFXMLErrorUnknownEncoding: CFIndex = 2; +pub const kCFXMLErrorEncodingConversionFailure: CFIndex = 3; +pub const kCFXMLErrorMalformedProcessingInstruction: CFIndex = 4; +pub const kCFXMLErrorMalformedDTD: CFIndex = 5; +pub const kCFXMLErrorMalformedName: CFIndex = 6; +pub const kCFXMLErrorMalformedCDSect: CFIndex = 7; +pub const kCFXMLErrorMalformedCloseTag: CFIndex = 8; +pub const kCFXMLErrorMalformedStartTag: CFIndex = 9; +pub const kCFXMLErrorMalformedDocument: CFIndex = 10; +pub const kCFXMLErrorElementlessDocument: CFIndex = 11; +pub const kCFXMLErrorMalformedComment: CFIndex = 12; +pub const kCFXMLErrorMalformedCharacterReference: CFIndex = 13; +pub const kCFXMLErrorMalformedParsedCharacterData: CFIndex = 14; +pub const kCFXMLErrorNoData: CFIndex = 15; + +pub type CFXMLParserCreateXMLStructureCallBack = + extern "C" fn(parser: CFXMLParserRef, nodeDesc: CFXMLNodeRef, info: *mut c_void) -> *mut c_void; +pub type CFXMLParserAddChildCallBack = extern "C" fn( + parser: CFXMLParserRef, + parent: *mut c_void, + child: *mut c_void, + info: *mut c_void, +); +pub type CFXMLParserEndXMLStructureCallBack = + extern "C" fn(parser: CFXMLParserRef, xmlType: *mut c_void, info: *mut c_void); +pub type CFXMLParserResolveExternalEntityCallBack = extern "C" fn( + parser: CFXMLParserRef, + extID: *mut CFXMLExternalID, + info: *mut c_void, +) -> CFDataRef; +pub type CFXMLParserHandleErrorCallBack = extern "C" fn( + parser: CFXMLParserRef, + error: CFXMLParserStatusCode, + info: *mut c_void, +) -> Boolean; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLParserCallBacks { + pub version: CFIndex, + pub createXMLStructure: CFXMLParserCreateXMLStructureCallBack, + pub addChild: CFXMLParserAddChildCallBack, + pub endXMLStructure: CFXMLParserEndXMLStructureCallBack, + pub resolveExternalEntity: CFXMLParserResolveExternalEntityCallBack, + pub handleError: CFXMLParserHandleErrorCallBack, +} + +pub type CFXMLParserRetainCallBack = extern "C" fn(info: *const c_void) -> *const c_void; +pub type CFXMLParserReleaseCallBack = extern "C" fn(info: *const c_void); +pub type CFXMLParserCopyDescriptionCallBack = extern "C" fn(info: *const c_void) -> CFStringRef; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CFXMLParserContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: CFXMLParserRetainCallBack, + pub release: CFXMLParserReleaseCallBack, + pub copyDescription: CFXMLParserCopyDescriptionCallBack, +} + +extern "C" { + /* + * CFXMLParser.h + */ + + pub static kCFXMLTreeErrorDescription: CFStringRef; + pub static kCFXMLTreeErrorLineNumber: CFStringRef; + pub static kCFXMLTreeErrorLocation: CFStringRef; + pub static kCFXMLTreeErrorStatusCode: CFStringRef; + + pub fn CFXMLParserGetTypeID() -> CFTypeID; + pub fn CFXMLParserCreate( + allocator: CFAllocatorRef, + xmlData: CFDataRef, + dataSource: CFURLRef, + parseOptions: CFOptionFlags, + versionOfNodes: CFIndex, + callBacks: *mut CFXMLParserCallBacks, + context: *mut CFXMLParserContext, + ) -> CFXMLParserRef; + pub fn CFXMLParserCreateWithDataFromURL( + allocator: CFAllocatorRef, + dataSource: CFURLRef, + parseOptions: CFOptionFlags, + versionOfNodes: CFIndex, + callBacks: *mut CFXMLParserCallBacks, + context: *mut CFXMLParserContext, + ) -> CFXMLParserRef; + pub fn CFXMLParserGetContext(parser: CFXMLParserRef, context: *mut CFXMLParserContext); + pub fn CFXMLParserGetCallBacks(parser: CFXMLParserRef, callBacks: *mut CFXMLParserCallBacks); + pub fn CFXMLParserGetSourceURL(parser: CFXMLParserRef) -> CFURLRef; + pub fn CFXMLParserGetLocation(parser: CFXMLParserRef) -> CFIndex; + pub fn CFXMLParserGetLineNumber(parser: CFXMLParserRef) -> CFIndex; + pub fn CFXMLParserGetDocument(parser: CFXMLParserRef) -> *mut c_void; + pub fn CFXMLParserGetStatusCode(parser: CFXMLParserRef) -> CFXMLParserStatusCode; + pub fn CFXMLParserCopyErrorDescription(parser: CFXMLParserRef) -> CFStringRef; + pub fn CFXMLParserAbort( + parser: CFXMLParserRef, + errorCode: CFXMLParserStatusCode, + errorDescription: CFStringRef, + ); + pub fn CFXMLParserParse(parser: CFXMLParserRef) -> Boolean; + pub fn CFXMLTreeCreateFromData( + allocator: CFAllocatorRef, + xmlData: CFDataRef, + dataSource: CFURLRef, + parseOptions: CFOptionFlags, + versionOfNodes: CFIndex, + ) -> CFXMLTreeRef; + pub fn CFXMLTreeCreateFromDataWithError( + allocator: CFAllocatorRef, + xmlData: CFDataRef, + dataSource: CFURLRef, + parseOptions: CFOptionFlags, + versionOfNodes: CFIndex, + errorDict: *mut CFDictionaryRef, + ) -> CFXMLTreeRef; + pub fn CFXMLTreeCreateWithDataFromURL( + allocator: CFAllocatorRef, + dataSource: CFURLRef, + parseOptions: CFOptionFlags, + versionOfNodes: CFIndex, + ) -> CFXMLTreeRef; + pub fn CFXMLTreeCreateXMLData(allocator: CFAllocatorRef, xmlTree: CFXMLTreeRef) -> CFDataRef; + pub fn CFXMLCreateStringByEscapingEntities( + allocator: CFAllocatorRef, + string: CFStringRef, + entitiesDictionary: CFDictionaryRef, + ) -> CFStringRef; + pub fn CFXMLCreateStringByUnescapingEntities( + allocator: CFAllocatorRef, + string: CFStringRef, + entitiesDictionary: CFDictionaryRef, + ) -> CFStringRef; +} diff --git a/third_party/rust/core-foundation/.cargo-checksum.json b/third_party/rust/core-foundation/.cargo-checksum.json index 93d6c58e7c..05422dac50 100644 --- a/third_party/rust/core-foundation/.cargo-checksum.json +++ b/third_party/rust/core-foundation/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"5909548b679fccc46cd25a91f3784139e4e53bbed284e3b7cc72c599e599e138","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","src/array.rs":"e5e6ea11e660e5e6676568c9b5b4595633c16fad770755b13bb4fde6c7436a4e","src/attributed_string.rs":"c04c5a3c912b6ab58d3081fa5dfa8fda07957b26396ebc907bba5ad07dc1087d","src/base.rs":"9ed46d59afdb22ecc65504ccd77f1c98108ea0ff96fad568dadb7ed49fde588c","src/boolean.rs":"f5b4d295aaf6cc3681212afebeae2974c5d551125badcc066e6089ac0d2a0873","src/bundle.rs":"c290a87d8bc43d8c9e1935c18e6d7127f46fd211cc2b041ed9e7b618b9df270c","src/characterset.rs":"a3ffb46c5463c99813eebfc177a65794f44a1b9343534e28bbccd262034714c2","src/data.rs":"c8d2ec30d8ac6249ef84afa0f7638d950b5c70d687aeb4ba9e3e46806aa872aa","src/date.rs":"a02f6cca7b6e8fbabc7713177429012658dba5146556e14a08e7baaf81958d83","src/dictionary.rs":"780599de45d64e8f4bca18ad50fc4a909f6e9aab1c3f2cea451f469d766f6782","src/error.rs":"22c21087d9c2c103d1bcb2c4af33b684317bbda5d4747902e510d410f8c1a14b","src/filedescriptor.rs":"022463c6dce8823231dc88064e5d9cffb494b410391388fe1feb50d3419d98b7","src/lib.rs":"2d0b007b264642cbad31e8c901f5f2235ed55515ef73e573a8d86306a7cd4f06","src/mach_port.rs":"87aa8dd28060bbb976197e7cc981eb733762b9bcc29eddd742f44aa8141e71b1","src/number.rs":"5a6cc9036c156e7e9d787864dd671087677abf4175cd840cbf123ccd89abcafe","src/propertylist.rs":"3c964d976709562b96f391265130c0f8fced307267a2b6385bab469048518b55","src/runloop.rs":"514a8ea7b185812fbb6d4835b0f7d26208f3121dadf1553a3a39c5013f2820af","src/set.rs":"da75b31f894bd04c0518211e113ca21a2781cd6ac71018104eeb354dd2f1a19e","src/string.rs":"bea7f3fd2528377442d1bebfeacf7e905d879320ae662fe6a8ef917b6a8e9c36","src/timezone.rs":"6dcf188db76303292b519d6283b71b71c7b3d6ed1afddc28de16d727075f5ef1","src/url.rs":"c544725399d3fbc4de54fd9d1c987e02f81760effd08c5c64c8deacd11478950","src/uuid.rs":"c3457e43fc22ba0f3fcab3ee8108500585ba005dbcbfa7edad0d389701ddf379","tests/use_macro_outside_crate.rs":"ed5e74ac9e988f2609c0b785189f1e6368d693f6401603ad065521f3ab51df94"},"package":"194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"} \ No newline at end of file +{"files":{"Cargo.toml":"2e85272c5cffb75aadcbb83d8ca1a619af3ccb9d810c1e07349f3b618fa05b7e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","src/array.rs":"1ec64187ec7c3ff0a9cf9739fb83d1f0b6141d827e4f21a14203b7058ca12056","src/attributed_string.rs":"7c129d266872bf9e0f8cbd9477d8cc27405b806395e59e1647bedf9af06f8949","src/base.rs":"7ec2afcbc200aabaa01687efce2eb27c9effc9eae64d3c579827de731fbd290e","src/boolean.rs":"60aef5be531e867f03524c32a88609100d07d9166184545feab760af9eb3d7ec","src/bundle.rs":"00f7ae30df3cc59079e771da0eda2b1972f52b13cc7bd95ae48b0e9bd1836ff4","src/characterset.rs":"126884d51e75db5be4cb2988f4e97e0e1b592c900e0158082d8c0dda7a453b0f","src/data.rs":"bfaa4427b6bc4c838188506ee154622983bbfcc10641be3f58525b89a854d4cd","src/date.rs":"d1ec3f918cf6c62d0e36d50d495c125d275a9a89442a740eea5d41dcc71a96fa","src/dictionary.rs":"f6d73c08fa9afd30d1df70cceea55dd30c7b81b8a78117d8843f1b3390051dca","src/error.rs":"433982fb7b421f5bf386d7eba22a7ffb8673486bb6455ff3fa30c875b064f718","src/filedescriptor.rs":"d3ece69ff461b215f7ff98dc6139723c4a5a53849a9747cccd24e72c185c4ffd","src/lib.rs":"92502d5f7d0e2ba266ec3531c01dd996e1832f1e6e9e66b10596e6fb870480cb","src/mach_port.rs":"e5400039696a70bdc0e6e14b1a68c493b741136945ce0eb67208cd4d0f895e1b","src/number.rs":"48e2efe219a7eaa4bc7bc3a48fa45f32fbbfd6363620838fef16a98b86e05061","src/propertylist.rs":"23e9a42d506983374d0c3439ab80407bbd472a3487812693a411597ff5eb1bd8","src/runloop.rs":"ff5bbb8a145befa7f244d937161d87f059ea60c9c482ab32e845222ee6fabf34","src/set.rs":"39e41a3d4f9e4dd50864a9c3581508e1b09549dc89d57fa84935964d98469bad","src/string.rs":"3b25b169d0f18dae66e6f123a116a04c79096f9e44e4221d4dbdcea4e152355c","src/timezone.rs":"7b8e46bde9e8aa71a906ab26b8ff7b6251568ebf210bab10d11c6ba0ce64ecd5","src/url.rs":"dc125dd95e9b8386770b89f5437ab904ceff0843e1bf820f548bddfc31e1c40c","src/uuid.rs":"e290c592871b7cea6ec09d2b3e34ec9033968dda725cf49e410535f79d2b41f8","tests/use_macro_outside_crate.rs":"ed5e74ac9e988f2609c0b785189f1e6368d693f6401603ad065521f3ab51df94"},"package":"91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"} \ No newline at end of file diff --git a/third_party/rust/core-foundation/Cargo.toml b/third_party/rust/core-foundation/Cargo.toml index 7ea9578156..47cf3f2640 100644 --- a/third_party/rust/core-foundation/Cargo.toml +++ b/third_party/rust/core-foundation/Cargo.toml @@ -10,23 +10,32 @@ # See Cargo.toml.orig for the original contents. [package] +edition = "2018" name = "core-foundation" -version = "0.9.3" +version = "0.9.4" authors = ["The Servo Project Developers"] description = "Bindings to Core Foundation for macOS" homepage = "https://github.com/servo/core-foundation-rs" -keywords = ["macos", "framework", "objc"] +keywords = [ + "macos", + "framework", + "objc", +] categories = ["os::macos-apis"] -license = "MIT / Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/servo/core-foundation-rs" + [package.metadata.docs.rs] +all-features = true default-target = "x86_64-apple-darwin" + [dependencies.chrono] version = "0.4" optional = true [dependencies.core-foundation-sys] -version = "0.8.3" +version = "0.8.6" +default-features = false [dependencies.libc] version = "0.2" @@ -36,6 +45,8 @@ version = "0.5" optional = true [features] +default = ["link"] +link = ["core-foundation-sys/link"] mac_os_10_7_support = ["core-foundation-sys/mac_os_10_7_support"] mac_os_10_8_features = ["core-foundation-sys/mac_os_10_8_features"] with-chrono = ["chrono"] diff --git a/third_party/rust/core-foundation/src/array.rs b/third_party/rust/core-foundation/src/array.rs index d66ffc5b82..b6f5d5c740 100644 --- a/third_party/rust/core-foundation/src/array.rs +++ b/third_party/rust/core-foundation/src/array.rs @@ -9,17 +9,17 @@ //! Heterogeneous immutable arrays. +use crate::ConcreteCFType; pub use core_foundation_sys::array::*; pub use core_foundation_sys::base::CFIndex; -use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault}; -use std::mem; +use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease, CFTypeRef}; use std::marker::PhantomData; +use std::mem; use std::os::raw::c_void; use std::ptr; -use ConcreteCFType; -use base::{CFIndexConvertible, TCFType, CFRange}; -use base::{FromVoid, ItemRef}; +use crate::base::{CFIndexConvertible, CFRange, TCFType}; +use crate::base::{FromVoid, ItemRef}; /// A heterogeneous immutable array. pub struct CFArray(CFArrayRef, PhantomData); @@ -63,24 +63,34 @@ unsafe impl ConcreteCFType for CFArray<*const c_void> {} impl CFArray { /// Creates a new `CFArray` with the given elements, which must implement `Copy`. - pub fn from_copyable(elems: &[T]) -> CFArray where T: Copy { + pub fn from_copyable(elems: &[T]) -> CFArray + where + T: Copy, + { unsafe { - let array_ref = CFArrayCreate(kCFAllocatorDefault, - elems.as_ptr() as *const *const c_void, - elems.len().to_CFIndex(), - ptr::null()); + let array_ref = CFArrayCreate( + kCFAllocatorDefault, + elems.as_ptr() as *const *const c_void, + elems.len().to_CFIndex(), + ptr::null(), + ); TCFType::wrap_under_create_rule(array_ref) } } /// Creates a new `CFArray` with the given elements, which must be `CFType` objects. - pub fn from_CFTypes(elems: &[T]) -> CFArray where T: TCFType { + pub fn from_CFTypes(elems: &[T]) -> CFArray + where + T: TCFType, + { unsafe { let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); - let array_ref = CFArrayCreate(kCFAllocatorDefault, - elems.as_ptr(), - elems.len().to_CFIndex(), - &kCFTypeArrayCallBacks); + let array_ref = CFArrayCreate( + kCFAllocatorDefault, + elems.as_ptr(), + elems.len().to_CFIndex(), + &kCFTypeArrayCallBacks, + ); TCFType::wrap_under_create_rule(array_ref) } } @@ -105,7 +115,7 @@ impl CFArray { /// Core Foundation objects (not always true), they need to be wrapped with /// `TCFType::wrap_under_get_rule()`. #[inline] - pub fn iter<'a>(&'a self) -> CFArrayIterator<'a, T> { + pub fn iter(&self) -> CFArrayIterator<'_, T> { CFArrayIterator { array: self, index: 0, @@ -115,20 +125,30 @@ impl CFArray { #[inline] pub fn len(&self) -> CFIndex { - unsafe { - CFArrayGetCount(self.0) - } + unsafe { CFArrayGetCount(self.0) } } + /// Returns `true` if the array contains no elements. #[inline] - pub unsafe fn get_unchecked<'a>(&'a self, index: CFIndex) -> ItemRef<'a, T> where T: FromVoid { + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub unsafe fn get_unchecked(&self, index: CFIndex) -> ItemRef<'_, T> + where + T: FromVoid, + { T::from_void(CFArrayGetValueAtIndex(self.0, index)) } #[inline] - pub fn get<'a>(&'a self, index: CFIndex) -> Option> where T: FromVoid { + pub fn get(&self, index: CFIndex) -> Option> + where + T: FromVoid, + { if index < self.len() { - Some(unsafe { T::from_void(CFArrayGetValueAtIndex(self.0, index)) } ) + Some(unsafe { T::from_void(CFArrayGetValueAtIndex(self.0, index)) }) } else { None } @@ -146,7 +166,7 @@ impl CFArray { pub fn get_all_values(&self) -> Vec<*const c_void> { self.get_values(CFRange { location: 0, - length: self.len() + length: self.len(), }) } } @@ -162,13 +182,15 @@ impl<'a, T: FromVoid> IntoIterator for &'a CFArray { #[cfg(test)] mod tests { + use crate::number::CFNumber; + use super::*; + use crate::base::CFType; use std::mem; - use base::CFType; #[test] fn to_untyped_correct_retain_count() { - let array = CFArray::::from_CFTypes(&[]); + let array = CFArray::::from_CFTypes(&[CFNumber::from(4).as_CFType()]); assert_eq!(array.retain_count(), 1); let untyped_array = array.to_untyped(); @@ -181,7 +203,7 @@ mod tests { #[test] fn into_untyped() { - let array = CFArray::::from_CFTypes(&[]); + let array = CFArray::::from_CFTypes(&[CFNumber::from(4).as_CFType()]); let array2 = array.to_untyped(); assert_eq!(array.retain_count(), 2); @@ -194,9 +216,9 @@ mod tests { #[test] fn borrow() { - use string::CFString; + use crate::string::CFString; - let string = CFString::from_static_string("bar"); + let string = CFString::from_static_string("alongerstring"); assert_eq!(string.retain_count(), 1); let x; { @@ -208,7 +230,7 @@ mod tests { { x = arr.get(0).unwrap().clone(); assert_eq!(x.retain_count(), 2); - assert_eq!(x.to_string(), "bar"); + assert_eq!(x.to_string(), "alongerstring"); } } assert_eq!(x.retain_count(), 1); @@ -216,23 +238,24 @@ mod tests { #[test] fn iter_untyped_array() { - use string::{CFString, CFStringRef}; - use base::TCFTypeRef; + use crate::base::TCFTypeRef; + use crate::string::{CFString, CFStringRef}; - let cf_string = CFString::from_static_string("bar"); + let cf_string = CFString::from_static_string("alongerstring"); let array: CFArray = CFArray::from_CFTypes(&[cf_string.clone()]).into_untyped(); - let cf_strings = array.iter().map(|ptr| { - unsafe { CFString::wrap_under_get_rule(CFStringRef::from_void_ptr(*ptr)) } - }).collect::>(); + let cf_strings = array + .iter() + .map(|ptr| unsafe { CFString::wrap_under_get_rule(CFStringRef::from_void_ptr(*ptr)) }) + .collect::>(); let strings = cf_strings.iter().map(|s| s.to_string()).collect::>(); assert_eq!(cf_string.retain_count(), 3); - assert_eq!(&strings[..], &["bar"]); + assert_eq!(&strings[..], &["alongerstring"]); } #[test] fn should_box_and_unbox() { - use number::CFNumber; + use crate::number::CFNumber; let n0 = CFNumber::from(0); let n1 = CFNumber::from(1); diff --git a/third_party/rust/core-foundation/src/attributed_string.rs b/third_party/rust/core-foundation/src/attributed_string.rs index d4a467946d..6a2b349f1a 100644 --- a/third_party/rust/core-foundation/src/attributed_string.rs +++ b/third_party/rust/core-foundation/src/attributed_string.rs @@ -9,22 +9,26 @@ pub use core_foundation_sys::attributed_string::*; -use base::TCFType; -use core_foundation_sys::base::{CFIndex, CFRange, kCFAllocatorDefault}; +use crate::base::TCFType; +use crate::string::{CFString, CFStringRef}; +use core_foundation_sys::base::{kCFAllocatorDefault, CFIndex, CFRange}; use std::ptr::null; -use string::{CFString, CFStringRef}; -declare_TCFType!{ +declare_TCFType! { CFAttributedString, CFAttributedStringRef } -impl_TCFType!(CFAttributedString, CFAttributedStringRef, CFAttributedStringGetTypeID); +impl_TCFType!( + CFAttributedString, + CFAttributedStringRef, + CFAttributedStringGetTypeID +); impl CFAttributedString { #[inline] pub fn new(string: &CFString) -> Self { unsafe { - let astr_ref = CFAttributedStringCreate( - kCFAllocatorDefault, string.as_concrete_TypeRef(), null()); + let astr_ref = + CFAttributedStringCreate(kCFAllocatorDefault, string.as_concrete_TypeRef(), null()); CFAttributedString::wrap_under_create_rule(astr_ref) } @@ -32,23 +36,24 @@ impl CFAttributedString { #[inline] pub fn char_len(&self) -> CFIndex { - unsafe { - CFAttributedStringGetLength(self.0) - } + unsafe { CFAttributedStringGetLength(self.0) } } } -declare_TCFType!{ +declare_TCFType! { CFMutableAttributedString, CFMutableAttributedStringRef } -impl_TCFType!(CFMutableAttributedString, CFMutableAttributedStringRef, CFAttributedStringGetTypeID); +impl_TCFType!( + CFMutableAttributedString, + CFMutableAttributedStringRef, + CFAttributedStringGetTypeID +); impl CFMutableAttributedString { #[inline] pub fn new() -> Self { unsafe { - let astr_ref = CFAttributedStringCreateMutable( - kCFAllocatorDefault, 0); + let astr_ref = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0); CFMutableAttributedString::wrap_under_create_rule(astr_ref) } @@ -56,24 +61,20 @@ impl CFMutableAttributedString { #[inline] pub fn char_len(&self) -> CFIndex { - unsafe { - CFAttributedStringGetLength(self.0) - } + unsafe { CFAttributedStringGetLength(self.0) } } #[inline] pub fn replace_str(&mut self, string: &CFString, range: CFRange) { unsafe { - CFAttributedStringReplaceString( - self.0, range, string.as_concrete_TypeRef()); + CFAttributedStringReplaceString(self.0, range, string.as_concrete_TypeRef()); } } #[inline] pub fn set_attribute(&mut self, range: CFRange, name: CFStringRef, value: &T) { unsafe { - CFAttributedStringSetAttribute( - self.0, range, name, value.as_CFTypeRef()); + CFAttributedStringSetAttribute(self.0, range, name, value.as_CFTypeRef()); } } } @@ -84,7 +85,6 @@ impl Default for CFMutableAttributedString { } } - #[cfg(test)] mod tests { use super::*; @@ -93,6 +93,9 @@ mod tests { fn attributed_string_type_id_comparison() { // CFMutableAttributedString TypeID must be equal to CFAttributedString TypeID. // Compilation must not fail. - assert_eq!(::type_id(), ::type_id()); + assert_eq!( + ::type_id(), + ::type_id() + ); } -} \ No newline at end of file +} diff --git a/third_party/rust/core-foundation/src/base.rs b/third_party/rust/core-foundation/src/base.rs index f08f2b2e85..b44c1262ab 100644 --- a/third_party/rust/core-foundation/src/base.rs +++ b/third_party/rust/core-foundation/src/base.rs @@ -17,8 +17,8 @@ use std::os::raw::c_void; pub use core_foundation_sys::base::*; -use string::CFString; -use ConcreteCFType; +use crate::string::CFString; +use crate::ConcreteCFType; pub trait CFIndexConvertible { /// Always use this method to construct a `CFIndex` value. It performs bounds checking to @@ -37,7 +37,7 @@ impl CFIndexConvertible for usize { } } -declare_TCFType!{ +declare_TCFType! { /// Superclass of all Core Foundation objects. CFType, CFTypeRef } @@ -111,13 +111,11 @@ impl CFType { } impl fmt::Debug for CFType { - /// Formats the value using [`CFCopyDescription`]. - /// - /// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc + /// Formats the value using [`CFCopyDescription`]. + /// + /// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let desc = unsafe { - CFString::wrap_under_create_rule(CFCopyDescription(self.0)) - }; + let desc = unsafe { CFString::wrap_under_create_rule(CFCopyDescription(self.0)) }; desc.fmt(f) } } @@ -125,18 +123,14 @@ impl fmt::Debug for CFType { impl Clone for CFType { #[inline] fn clone(&self) -> CFType { - unsafe { - TCFType::wrap_under_get_rule(self.0) - } + unsafe { TCFType::wrap_under_get_rule(self.0) } } } impl PartialEq for CFType { #[inline] fn eq(&self, other: &CFType) -> bool { - unsafe { - CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0 - } + unsafe { CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0 } } } @@ -153,7 +147,6 @@ impl CFAllocator { } } - /// All Core Foundation types implement this trait. The associated type `Ref` specifies the /// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is /// `CFArrayRef`. @@ -165,7 +158,7 @@ pub trait TCFType { /// The reference type wrapped inside this type. type Ref: TCFTypeRef; - /// Returns the object as its concrete TypeRef. + /// Returns the object as its concrete `TypeRef`. fn as_concrete_TypeRef(&self) -> Self::Ref; /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this @@ -178,9 +171,7 @@ pub trait TCFType { /// Returns the object as a wrapped `CFType`. The reference count is incremented by one. #[inline] fn as_CFType(&self) -> CFType { - unsafe { - TCFType::wrap_under_get_rule(self.as_CFTypeRef()) - } + unsafe { TCFType::wrap_under_get_rule(self.as_CFTypeRef()) } } /// Returns the object as a wrapped `CFType`. Consumes self and avoids changing the reference @@ -206,27 +197,21 @@ pub trait TCFType { /// whether the return value of this method is greater than zero. #[inline] fn retain_count(&self) -> CFIndex { - unsafe { - CFGetRetainCount(self.as_CFTypeRef()) - } + unsafe { CFGetRetainCount(self.as_CFTypeRef()) } } /// Returns the type ID of this object. #[inline] fn type_of(&self) -> CFTypeID { - unsafe { - CFGetTypeID(self.as_CFTypeRef()) - } + unsafe { CFGetTypeID(self.as_CFTypeRef()) } } /// Writes a debugging version of this object on standard error. fn show(&self) { - unsafe { - CFShow(self.as_CFTypeRef()) - } + unsafe { CFShow(self.as_CFTypeRef()) } } - /// Returns true if this value is an instance of another type. + /// Returns `true` if this value is an instance of another type. #[inline] fn instance_of(&self) -> bool { self.type_of() == OtherCFType::type_id() @@ -318,9 +303,11 @@ impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> { } } -/// A trait describing how to convert from the stored *mut c_void to the desired T +/// A trait describing how to convert from the stored `*mut c_void` to the desired `T` pub unsafe trait FromMutVoid { - unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized; + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> + where + Self: std::marker::Sized; } unsafe impl FromMutVoid for u32 { @@ -337,13 +324,18 @@ unsafe impl FromMutVoid for *const c_void { unsafe impl FromMutVoid for T { unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { - ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) + ItemMutRef( + ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), + PhantomData, + ) } } -/// A trait describing how to convert from the stored *const c_void to the desired T +/// A trait describing how to convert from the stored `*const c_void` to the desired `T` pub unsafe trait FromVoid { - unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized; + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> + where + Self: std::marker::Sized; } unsafe impl FromVoid for u32 { @@ -362,11 +354,14 @@ unsafe impl FromVoid for *const c_void { unsafe impl FromVoid for T { unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { - ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) + ItemRef( + ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), + PhantomData, + ) } } -/// A trait describing how to convert from the stored *const c_void to the desired T +/// A trait describing how to convert from the stored `*const c_void` to the desired `T` pub unsafe trait ToVoid { fn to_void(&self) -> *const c_void; } @@ -395,12 +390,11 @@ unsafe impl ToVoid for CFTypeRef { } } - #[cfg(test)] mod tests { use super::*; + use crate::boolean::CFBoolean; use std::mem; - use boolean::CFBoolean; #[test] fn cftype_instance_of() { @@ -413,7 +407,7 @@ mod tests { #[test] fn as_cftype_retain_count() { - let string = CFString::from_static_string("bar"); + let string = CFString::from_static_string("alongerstring"); assert_eq!(string.retain_count(), 1); let cftype = string.as_CFType(); assert_eq!(cftype.retain_count(), 2); @@ -423,7 +417,7 @@ mod tests { #[test] fn into_cftype_retain_count() { - let string = CFString::from_static_string("bar"); + let string = CFString::from_static_string("alongerstring"); assert_eq!(string.retain_count(), 1); let cftype = string.into_CFType(); assert_eq!(cftype.retain_count(), 1); @@ -431,10 +425,10 @@ mod tests { #[test] fn as_cftype_and_downcast() { - let string = CFString::from_static_string("bar"); + let string = CFString::from_static_string("alongerstring"); let cftype = string.as_CFType(); let string2 = cftype.downcast::().unwrap(); - assert_eq!(string2.to_string(), "bar"); + assert_eq!(string2.to_string(), "alongerstring"); assert_eq!(string.retain_count(), 3); assert_eq!(cftype.retain_count(), 3); @@ -443,10 +437,10 @@ mod tests { #[test] fn into_cftype_and_downcast_into() { - let string = CFString::from_static_string("bar"); + let string = CFString::from_static_string("alongerstring"); let cftype = string.into_CFType(); let string2 = cftype.downcast_into::().unwrap(); - assert_eq!(string2.to_string(), "bar"); + assert_eq!(string2.to_string(), "alongerstring"); assert_eq!(string2.retain_count(), 1); } } diff --git a/third_party/rust/core-foundation/src/boolean.rs b/third_party/rust/core-foundation/src/boolean.rs index 8c13b907da..e0e2ff762f 100644 --- a/third_party/rust/core-foundation/src/boolean.rs +++ b/third_party/rust/core-foundation/src/boolean.rs @@ -9,12 +9,13 @@ //! A Boolean type. -pub use core_foundation_sys::number::{CFBooleanRef, CFBooleanGetTypeID, kCFBooleanTrue, kCFBooleanFalse}; +pub use core_foundation_sys::number::{ + kCFBooleanFalse, kCFBooleanTrue, CFBooleanGetTypeID, CFBooleanRef, +}; -use base::TCFType; +use crate::base::TCFType; - -declare_TCFType!{ +declare_TCFType! { /// A Boolean type. /// /// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. @@ -25,15 +26,11 @@ impl_CFTypeDescription!(CFBoolean); impl CFBoolean { pub fn true_value() -> CFBoolean { - unsafe { - TCFType::wrap_under_get_rule(kCFBooleanTrue) - } + unsafe { TCFType::wrap_under_get_rule(kCFBooleanTrue) } } pub fn false_value() -> CFBoolean { - unsafe { - TCFType::wrap_under_get_rule(kCFBooleanFalse) - } + unsafe { TCFType::wrap_under_get_rule(kCFBooleanFalse) } } } diff --git a/third_party/rust/core-foundation/src/bundle.rs b/third_party/rust/core-foundation/src/bundle.rs index b9ab1f65f6..f6d53a991f 100644 --- a/third_party/rust/core-foundation/src/bundle.rs +++ b/third_party/rust/core-foundation/src/bundle.rs @@ -14,13 +14,13 @@ pub use core_foundation_sys::bundle::*; use core_foundation_sys::url::kCFURLPOSIXPathStyle; use std::path::PathBuf; -use base::{CFType, TCFType}; -use url::CFURL; -use dictionary::CFDictionary; +use crate::base::{CFType, TCFType}; +use crate::dictionary::CFDictionary; +use crate::string::CFString; +use crate::url::CFURL; use std::os::raw::c_void; -use string::CFString; -declare_TCFType!{ +declare_TCFType! { /// A Bundle type. CFBundle, CFBundleRef } @@ -51,8 +51,10 @@ impl CFBundle { pub fn function_pointer_for_name(&self, function_name: CFString) -> *const c_void { unsafe { - CFBundleGetFunctionPointerForName(self.as_concrete_TypeRef(), - function_name.as_concrete_TypeRef()) + CFBundleGetFunctionPointerForName( + self.as_concrete_TypeRef(), + function_name.as_concrete_TypeRef(), + ) } } @@ -96,7 +98,9 @@ impl CFBundle { /// Bundle's own location pub fn path(&self) -> Option { let url = self.bundle_url()?; - Some(PathBuf::from(url.get_file_system_path(kCFURLPOSIXPathStyle).to_string())) + Some(PathBuf::from( + url.get_file_system_path(kCFURLPOSIXPathStyle).to_string(), + )) } /// Bundle's resources location @@ -114,7 +118,9 @@ impl CFBundle { /// Bundle's resources location pub fn resources_path(&self) -> Option { let url = self.bundle_resources_url()?; - Some(PathBuf::from(url.get_file_system_path(kCFURLPOSIXPathStyle).to_string())) + Some(PathBuf::from( + url.get_file_system_path(kCFURLPOSIXPathStyle).to_string(), + )) } pub fn private_frameworks_url(&self) -> Option { @@ -140,11 +146,10 @@ impl CFBundle { } } - #[test] fn safari_executable_url() { - use string::CFString; - use url::{CFURL, kCFURLPOSIXPathStyle}; + use crate::string::CFString; + use crate::url::{kCFURLPOSIXPathStyle, CFURL}; let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); @@ -152,18 +157,20 @@ fn safari_executable_url() { .expect("Safari not present") .executable_url(); assert!(cfurl_executable.is_some()); - assert_eq!(cfurl_executable - .unwrap() - .absolute() - .get_file_system_path(kCFURLPOSIXPathStyle) - .to_string(), - "/Applications/Safari.app/Contents/MacOS/Safari"); + assert_eq!( + cfurl_executable + .unwrap() + .absolute() + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + "/Applications/Safari.app/Contents/MacOS/Safari" + ); } #[test] fn safari_private_frameworks_url() { - use string::CFString; - use url::{CFURL, kCFURLPOSIXPathStyle}; + use crate::string::CFString; + use crate::url::{kCFURLPOSIXPathStyle, CFURL}; let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); @@ -171,18 +178,20 @@ fn safari_private_frameworks_url() { .expect("Safari not present") .private_frameworks_url(); assert!(cfurl_executable.is_some()); - assert_eq!(cfurl_executable - .unwrap() - .absolute() - .get_file_system_path(kCFURLPOSIXPathStyle) - .to_string(), - "/Applications/Safari.app/Contents/Frameworks"); + assert_eq!( + cfurl_executable + .unwrap() + .absolute() + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + "/Applications/Safari.app/Contents/Frameworks" + ); } #[test] fn non_existant_bundle() { - use string::CFString; - use url::{CFURL, kCFURLPOSIXPathStyle}; + use crate::string::CFString; + use crate::url::{kCFURLPOSIXPathStyle, CFURL}; let cfstr_path = CFString::from_static_string("/usr/local/foo"); let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); diff --git a/third_party/rust/core-foundation/src/characterset.rs b/third_party/rust/core-foundation/src/characterset.rs index d1b9439d6e..2a05a931d4 100644 --- a/third_party/rust/core-foundation/src/characterset.rs +++ b/third_party/rust/core-foundation/src/characterset.rs @@ -11,9 +11,9 @@ pub use core_foundation_sys::characterset::*; -use base::TCFType; +use crate::base::TCFType; -declare_TCFType!{ +declare_TCFType! { /// An immutable set of Unicde characters. CFCharacterSet, CFCharacterSetRef } diff --git a/third_party/rust/core-foundation/src/data.rs b/third_party/rust/core-foundation/src/data.rs index c510c7434d..9f952199aa 100644 --- a/third_party/rust/core-foundation/src/data.rs +++ b/third_party/rust/core-foundation/src/data.rs @@ -9,18 +9,16 @@ //! Core Foundation byte buffers. -pub use core_foundation_sys::data::*; +use core_foundation_sys::base::kCFAllocatorDefault; use core_foundation_sys::base::CFIndex; -use core_foundation_sys::base::{kCFAllocatorDefault}; +pub use core_foundation_sys::data::*; use std::ops::Deref; use std::slice; use std::sync::Arc; +use crate::base::{CFIndexConvertible, TCFType}; -use base::{CFIndexConvertible, TCFType}; - - -declare_TCFType!{ +declare_TCFType! { /// A byte buffer. CFData, CFDataRef } @@ -28,20 +26,22 @@ impl_TCFType!(CFData, CFDataRef, CFDataGetTypeID); impl_CFTypeDescription!(CFData); impl CFData { - /// Creates a CFData around a copy `buffer` + /// Creates a [`CFData`] around a copy `buffer` pub fn from_buffer(buffer: &[u8]) -> CFData { unsafe { - let data_ref = CFDataCreate(kCFAllocatorDefault, - buffer.as_ptr(), - buffer.len().to_CFIndex()); + let data_ref = CFDataCreate( + kCFAllocatorDefault, + buffer.as_ptr(), + buffer.len().to_CFIndex(), + ); TCFType::wrap_under_create_rule(data_ref) } } - /// Creates a CFData referencing `buffer` without creating a copy + /// Creates a [`CFData`] referencing `buffer` without creating a copy pub fn from_arc + Sync + Send>(buffer: Arc) -> Self { - use std::os::raw::c_void; use crate::base::{CFAllocator, CFAllocatorContext}; + use std::os::raw::c_void; unsafe { let ptr = (*buffer).as_ref().as_ptr() as *const _; @@ -67,8 +67,12 @@ impl CFData { deallocate: Some(deallocate::), preferredSize: None, }); - let data_ref = - CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ptr, len, allocator.as_CFTypeRef()); + let data_ref = CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, + ptr, + len, + allocator.as_CFTypeRef(), + ); TCFType::wrap_under_create_rule(data_ref) } } @@ -76,18 +80,20 @@ impl CFData { /// Returns a pointer to the underlying bytes in this data. Note that this byte buffer is /// read-only. #[inline] - pub fn bytes<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_parts(CFDataGetBytePtr(self.0), self.len() as usize) - } + pub fn bytes(&self) -> &[u8] { + unsafe { slice::from_raw_parts(CFDataGetBytePtr(self.0), self.len() as usize) } } /// Returns the length of this byte buffer. #[inline] pub fn len(&self) -> CFIndex { - unsafe { - CFDataGetLength(self.0) - } + unsafe { CFDataGetLength(self.0) } + } + + /// Returns `true` if this byte buffer is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 } } @@ -133,7 +139,10 @@ mod test { } let dropped = Arc::new(AtomicBool::default()); - let l = Arc::new(VecWrapper {inner: vec![5], dropped: dropped.clone() }); + let l = Arc::new(VecWrapper { + inner: vec![5], + dropped: dropped.clone(), + }); let m = l.clone(); let dp = CFData::from_arc(l); drop(m); diff --git a/third_party/rust/core-foundation/src/date.rs b/third_party/rust/core-foundation/src/date.rs index 57ee7211e6..c27bad25d1 100644 --- a/third_party/rust/core-foundation/src/date.rs +++ b/third_party/rust/core-foundation/src/date.rs @@ -9,16 +9,15 @@ //! Core Foundation date objects. -pub use core_foundation_sys::date::*; use core_foundation_sys::base::kCFAllocatorDefault; +pub use core_foundation_sys::date::*; -use base::TCFType; +use crate::base::TCFType; #[cfg(feature = "with-chrono")] use chrono::NaiveDateTime; - -declare_TCFType!{ +declare_TCFType! { /// A date. CFDate, CFDateRef } @@ -42,16 +41,12 @@ impl CFDate { #[inline] pub fn abs_time(&self) -> CFAbsoluteTime { - unsafe { - CFDateGetAbsoluteTime(self.0) - } + unsafe { CFDateGetAbsoluteTime(self.0) } } #[cfg(feature = "with-chrono")] pub fn naive_utc(&self) -> NaiveDateTime { - let ts = unsafe { - self.abs_time() + kCFAbsoluteTimeIntervalSince1970 - }; + let ts = unsafe { self.abs_time() + kCFAbsoluteTimeIntervalSince1970 }; let (secs, nanos) = if ts.is_sign_positive() { (ts.trunc() as i64, ts.fract()) } else { @@ -65,9 +60,7 @@ impl CFDate { pub fn from_naive_utc(time: NaiveDateTime) -> CFDate { let secs = time.timestamp(); let nanos = time.timestamp_subsec_nanos(); - let ts = unsafe { - secs as f64 + (nanos as f64 / 1e9) - kCFAbsoluteTimeIntervalSince1970 - }; + let ts = unsafe { secs as f64 + (nanos as f64 / 1e9) - kCFAbsoluteTimeIntervalSince1970 }; CFDate::new(ts) } } @@ -86,7 +79,7 @@ mod test { let same_sign = a.is_sign_positive() == b.is_sign_positive(); let equal = ((a - b).abs() / f64::min(a.abs() + b.abs(), f64::MAX)) < f64::EPSILON; - (same_sign && equal) + same_sign && equal } #[test] @@ -119,9 +112,7 @@ mod test { fn date_chrono_conversion_negative() { use super::kCFAbsoluteTimeIntervalSince1970; - let ts = unsafe { - kCFAbsoluteTimeIntervalSince1970 - 420.0 - }; + let ts = unsafe { kCFAbsoluteTimeIntervalSince1970 - 420.0 }; let date = CFDate::new(ts); let datetime: NaiveDateTime = date.naive_utc(); let converted = CFDate::from_naive_utc(datetime); diff --git a/third_party/rust/core-foundation/src/dictionary.rs b/third_party/rust/core-foundation/src/dictionary.rs index efcbba1178..aad37f3c81 100644 --- a/third_party/rust/core-foundation/src/dictionary.rs +++ b/third_party/rust/core-foundation/src/dictionary.rs @@ -11,18 +11,22 @@ pub use core_foundation_sys::dictionary::*; -use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault}; +use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease, CFTypeRef}; +use std::marker::PhantomData; use std::mem; use std::os::raw::c_void; use std::ptr; -use std::marker::PhantomData; -use base::{ItemRef, FromVoid, ToVoid}; -use base::{CFIndexConvertible, TCFType}; -use ConcreteCFType; +use crate::base::{CFIndexConvertible, TCFType}; +use crate::base::{FromVoid, ItemRef, ToVoid}; +use crate::ConcreteCFType; // consume the type parameters with PhantomDatas -pub struct CFDictionary(CFDictionaryRef, PhantomData, PhantomData); +pub struct CFDictionary( + CFDictionaryRef, + PhantomData, + PhantomData, +); impl Drop for CFDictionary { fn drop(&mut self) { @@ -36,19 +40,25 @@ impl_CFTypeDescription!(CFDictionary); unsafe impl ConcreteCFType for CFDictionary<*const c_void, *const c_void> {} impl CFDictionary { - pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFDictionary where K: TCFType, V: TCFType { + pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFDictionary + where + K: TCFType, + V: TCFType, + { let (keys, values): (Vec, Vec) = pairs .iter() - .map(|&(ref key, ref value)| (key.as_CFTypeRef(), value.as_CFTypeRef())) + .map(|(key, value)| (key.as_CFTypeRef(), value.as_CFTypeRef())) .unzip(); unsafe { - let dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault, - keys.as_ptr(), - values.as_ptr(), - keys.len().to_CFIndex(), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + let dictionary_ref = CFDictionaryCreate( + kCFAllocatorDefault, + keys.as_ptr(), + values.as_ptr(), + keys.len().to_CFIndex(), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks, + ); TCFType::wrap_under_create_rule(dictionary_ref) } } @@ -76,9 +86,7 @@ impl CFDictionary { #[inline] pub fn len(&self) -> usize { - unsafe { - CFDictionaryGetCount(self.0) as usize - } + unsafe { CFDictionaryGetCount(self.0) as usize } } #[inline] @@ -87,12 +95,19 @@ impl CFDictionary { } #[inline] - pub fn contains_key(&self, key: &K) -> bool where K: ToVoid { + pub fn contains_key(&self, key: &K) -> bool + where + K: ToVoid, + { unsafe { CFDictionaryContainsKey(self.0, key.to_void()) != 0 } } #[inline] - pub fn find<'a, T: ToVoid>(&'a self, key: T) -> Option> where V: FromVoid, K: ToVoid { + pub fn find>(&self, key: T) -> Option> + where + V: FromVoid, + K: ToVoid, + { unsafe { let mut value: *const c_void = ptr::null(); if CFDictionaryGetValueIfPresent(self.0, key.to_void(), &mut value) != 0 { @@ -108,9 +123,14 @@ impl CFDictionary { /// Panics if the key is not present in the dictionary. Use `find` to get an `Option` instead /// of panicking. #[inline] - pub fn get<'a, T: ToVoid>(&'a self, key: T) -> ItemRef<'a, V> where V: FromVoid, K: ToVoid { + pub fn get>(&self, key: T) -> ItemRef<'_, V> + where + V: FromVoid, + K: ToVoid, + { let ptr = key.to_void(); - self.find(key).unwrap_or_else(|| panic!("No entry found for key {:p}", ptr)) + self.find(key) + .unwrap_or_else(|| panic!("No entry found for key {:p}", ptr)) } pub fn get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>) { @@ -129,7 +149,11 @@ impl CFDictionary { } // consume the type parameters with PhantomDatas -pub struct CFMutableDictionary(CFMutableDictionaryRef, PhantomData, PhantomData); +pub struct CFMutableDictionary( + CFMutableDictionaryRef, + PhantomData, + PhantomData, +); impl Drop for CFMutableDictionary { fn drop(&mut self) { @@ -147,24 +171,31 @@ impl CFMutableDictionary { pub fn with_capacity(capacity: isize) -> Self { unsafe { - let dictionary_ref = CFDictionaryCreateMutable(kCFAllocatorDefault, - capacity as _, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + let dictionary_ref = CFDictionaryCreateMutable( + kCFAllocatorDefault, + capacity as _, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks, + ); TCFType::wrap_under_create_rule(dictionary_ref) } } pub fn copy_with_capacity(&self, capacity: isize) -> Self { unsafe { - let dictionary_ref = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, capacity as _, self.0); + let dictionary_ref = + CFDictionaryCreateMutableCopy(kCFAllocatorDefault, capacity as _, self.0); TCFType::wrap_under_get_rule(dictionary_ref) } } - pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFMutableDictionary where K: ToVoid, V: ToVoid { + pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFMutableDictionary + where + K: ToVoid, + V: ToVoid, + { let mut result = Self::with_capacity(pairs.len() as _); - for &(ref key, ref value) in pairs { + for (key, value) in pairs { result.add(key, value); } result @@ -194,9 +225,7 @@ impl CFMutableDictionary { #[inline] pub fn len(&self) -> usize { - unsafe { - CFDictionaryGetCount(self.0) as usize - } + unsafe { CFDictionaryGetCount(self.0) as usize } } #[inline] @@ -206,13 +235,15 @@ impl CFMutableDictionary { #[inline] pub fn contains_key(&self, key: *const c_void) -> bool { - unsafe { - CFDictionaryContainsKey(self.0, key) != 0 - } + unsafe { CFDictionaryContainsKey(self.0, key) != 0 } } #[inline] - pub fn find<'a>(&'a self, key: &K) -> Option> where V: FromVoid, K: ToVoid { + pub fn find<'a>(&'a self, key: &K) -> Option> + where + V: FromVoid, + K: ToVoid, + { unsafe { let mut value: *const c_void = ptr::null(); if CFDictionaryGetValueIfPresent(self.0, key.to_void(), &mut value) != 0 { @@ -228,9 +259,14 @@ impl CFMutableDictionary { /// Panics if the key is not present in the dictionary. Use `find` to get an `Option` instead /// of panicking. #[inline] - pub fn get<'a>(&'a self, key: &K) -> ItemRef<'a, V> where V: FromVoid, K: ToVoid { + pub fn get<'a>(&'a self, key: &K) -> ItemRef<'a, V> + where + V: FromVoid, + K: ToVoid, + { let ptr = key.to_void(); - self.find(&key).unwrap_or_else(|| panic!("No entry found for key {:p}", ptr)) + self.find(key) + .unwrap_or_else(|| panic!("No entry found for key {:p}", ptr)) } pub fn get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>) { @@ -251,25 +287,40 @@ impl CFMutableDictionary { /// Adds the key-value pair to the dictionary if no such key already exist. #[inline] - pub fn add(&mut self, key: &K, value: &V) where K: ToVoid, V: ToVoid { + pub fn add(&mut self, key: &K, value: &V) + where + K: ToVoid, + V: ToVoid, + { unsafe { CFDictionaryAddValue(self.0, key.to_void(), value.to_void()) } } /// Sets the value of the key in the dictionary. #[inline] - pub fn set(&mut self, key: K, value: V) where K: ToVoid, V: ToVoid { + pub fn set(&mut self, key: K, value: V) + where + K: ToVoid, + V: ToVoid, + { unsafe { CFDictionarySetValue(self.0, key.to_void(), value.to_void()) } } /// Replaces the value of the key in the dictionary. #[inline] - pub fn replace(&mut self, key: K, value: V) where K: ToVoid, V: ToVoid { + pub fn replace(&mut self, key: K, value: V) + where + K: ToVoid, + V: ToVoid, + { unsafe { CFDictionaryReplaceValue(self.0, key.to_void(), value.to_void()) } } /// Removes the value of the key from the dictionary. #[inline] - pub fn remove(&mut self, key: K) where K: ToVoid { + pub fn remove(&mut self, key: K) + where + K: ToVoid, + { unsafe { CFDictionaryRemoveValue(self.0, key.to_void()) } } @@ -296,15 +347,13 @@ impl<'a, K, V> From<&'a CFDictionary> for CFMutableDictionary { } } - #[cfg(test)] pub mod test { use super::*; - use base::{CFType, TCFType}; - use boolean::CFBoolean; - use number::CFNumber; - use string::CFString; - + use crate::base::{CFType, TCFType}; + use crate::boolean::CFBoolean; + use crate::number::CFNumber; + use crate::string::CFString; #[test] fn dictionary() { @@ -322,8 +371,14 @@ pub mod test { ]); let (v1, v2) = d.get_keys_and_values(); - assert_eq!(v1, &[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()]); - assert_eq!(v2, &[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()]); + assert_eq!( + v1, + &[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()] + ); + assert_eq!( + v2, + &[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()] + ); } #[test] @@ -342,8 +397,14 @@ pub mod test { assert_eq!(d.len(), 3); let (v1, v2) = d.get_keys_and_values(); - assert_eq!(v1, &[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()]); - assert_eq!(v2, &[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()]); + assert_eq!( + v1, + &[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()] + ); + assert_eq!( + v2, + &[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()] + ); d.remove(baz); assert_eq!(d.len(), 2); @@ -358,12 +419,10 @@ pub mod test { #[test] fn dict_find_and_contains_key() { - let dict = CFDictionary::from_CFType_pairs(&[ - ( - CFString::from_static_string("hello"), - CFBoolean::true_value(), - ), - ]); + let dict = CFDictionary::from_CFType_pairs(&[( + CFString::from_static_string("hello"), + CFBoolean::true_value(), + )]); let key = CFString::from_static_string("hello"); let invalid_key = CFString::from_static_string("foobar"); @@ -377,17 +436,24 @@ pub mod test { #[test] fn convert_immutable_to_mutable_dict() { - let dict: CFDictionary = CFDictionary::from_CFType_pairs(&[ - (CFString::from_static_string("Foo"), CFBoolean::true_value()), - ]); + let dict: CFDictionary = CFDictionary::from_CFType_pairs(&[( + CFString::from_static_string("Foo"), + CFBoolean::true_value(), + )]); let mut mut_dict = CFMutableDictionary::from(&dict); assert_eq!(dict.retain_count(), 1); assert_eq!(mut_dict.retain_count(), 1); assert_eq!(mut_dict.len(), 1); - assert_eq!(*mut_dict.get(&CFString::from_static_string("Foo")), CFBoolean::true_value()); - - mut_dict.add(&CFString::from_static_string("Bar"), &CFBoolean::false_value()); + assert_eq!( + *mut_dict.get(&CFString::from_static_string("Foo")), + CFBoolean::true_value() + ); + + mut_dict.add( + &CFString::from_static_string("Bar"), + &CFBoolean::false_value(), + ); assert_eq!(dict.len(), 1); assert_eq!(mut_dict.len(), 2); } @@ -395,13 +461,19 @@ pub mod test { #[test] fn mutable_dictionary_as_immutable() { let mut mut_dict: CFMutableDictionary = CFMutableDictionary::new(); - mut_dict.add(&CFString::from_static_string("Bar"), &CFBoolean::false_value()); + mut_dict.add( + &CFString::from_static_string("Bar"), + &CFBoolean::false_value(), + ); assert_eq!(mut_dict.retain_count(), 1); let dict = mut_dict.to_immutable(); assert_eq!(mut_dict.retain_count(), 2); assert_eq!(dict.retain_count(), 2); - assert_eq!(*dict.get(&CFString::from_static_string("Bar")), CFBoolean::false_value()); + assert_eq!( + *dict.get(&CFString::from_static_string("Bar")), + CFBoolean::false_value() + ); mem::drop(dict); assert_eq!(mut_dict.retain_count(), 1); diff --git a/third_party/rust/core-foundation/src/error.rs b/third_party/rust/core-foundation/src/error.rs index f100171bc9..e5a2242596 100644 --- a/third_party/rust/core-foundation/src/error.rs +++ b/third_party/rust/core-foundation/src/error.rs @@ -14,11 +14,10 @@ pub use core_foundation_sys::error::*; use std::error::Error; use std::fmt; -use base::{CFIndex, TCFType}; -use string::CFString; +use crate::base::{CFIndex, TCFType}; +use crate::string::CFString; - -declare_TCFType!{ +declare_TCFType! { /// An error value. CFError, CFErrorRef } @@ -27,10 +26,10 @@ impl_TCFType!(CFError, CFErrorRef, CFErrorGetTypeID); impl fmt::Debug for CFError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("CFError") - .field("domain", &self.domain()) - .field("code", &self.code()) - .field("description", &self.description()) - .finish() + .field("domain", &self.domain()) + .field("code", &self.code()) + .field("description", &self.description()) + .finish() } } diff --git a/third_party/rust/core-foundation/src/filedescriptor.rs b/third_party/rust/core-foundation/src/filedescriptor.rs index e153c70b2f..876d1cec0a 100644 --- a/third_party/rust/core-foundation/src/filedescriptor.rs +++ b/third_party/rust/core-foundation/src/filedescriptor.rs @@ -9,33 +9,41 @@ pub use core_foundation_sys::filedescriptor::*; -use core_foundation_sys::base::{Boolean, CFIndex}; use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; +use core_foundation_sys::base::{Boolean, CFIndex}; -use base::TCFType; -use runloop::CFRunLoopSource; +use crate::base::TCFType; +use crate::runloop::CFRunLoopSource; use std::mem::MaybeUninit; use std::os::unix::io::{AsRawFd, RawFd}; use std::ptr; -declare_TCFType!{ +declare_TCFType! { CFFileDescriptor, CFFileDescriptorRef } -impl_TCFType!(CFFileDescriptor, CFFileDescriptorRef, CFFileDescriptorGetTypeID); +impl_TCFType!( + CFFileDescriptor, + CFFileDescriptorRef, + CFFileDescriptorGetTypeID +); impl CFFileDescriptor { - pub fn new(fd: RawFd, - closeOnInvalidate: bool, - callout: CFFileDescriptorCallBack, - context: Option<&CFFileDescriptorContext>) -> Option { + pub fn new( + fd: RawFd, + closeOnInvalidate: bool, + callout: CFFileDescriptorCallBack, + context: Option<&CFFileDescriptorContext>, + ) -> Option { let context = context.map_or(ptr::null(), |c| c as *const _); unsafe { - let fd_ref = CFFileDescriptorCreate(kCFAllocatorDefault, - fd, - closeOnInvalidate as Boolean, - callout, - context); + let fd_ref = CFFileDescriptorCreate( + kCFAllocatorDefault, + fd, + closeOnInvalidate as Boolean, + callout, + context, + ); if fd_ref.is_null() { None } else { @@ -53,36 +61,25 @@ impl CFFileDescriptor { } pub fn enable_callbacks(&self, callback_types: CFOptionFlags) { - unsafe { - CFFileDescriptorEnableCallBacks(self.0, callback_types) - } + unsafe { CFFileDescriptorEnableCallBacks(self.0, callback_types) } } pub fn disable_callbacks(&self, callback_types: CFOptionFlags) { - unsafe { - CFFileDescriptorDisableCallBacks(self.0, callback_types) - } + unsafe { CFFileDescriptorDisableCallBacks(self.0, callback_types) } } pub fn valid(&self) -> bool { - unsafe { - CFFileDescriptorIsValid(self.0) != 0 - } + unsafe { CFFileDescriptorIsValid(self.0) != 0 } } pub fn invalidate(&self) { - unsafe { - CFFileDescriptorInvalidate(self.0) - } + unsafe { CFFileDescriptorInvalidate(self.0) } } pub fn to_run_loop_source(&self, order: CFIndex) -> Option { unsafe { - let source_ref = CFFileDescriptorCreateRunLoopSource( - kCFAllocatorDefault, - self.0, - order - ); + let source_ref = + CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, self.0, order); if source_ref.is_null() { None } else { @@ -94,24 +91,21 @@ impl CFFileDescriptor { impl AsRawFd for CFFileDescriptor { fn as_raw_fd(&self) -> RawFd { - unsafe { - CFFileDescriptorGetNativeDescriptor(self.0) - } + unsafe { CFFileDescriptorGetNativeDescriptor(self.0) } } } - #[cfg(test)] mod test { extern crate libc; use super::*; + use crate::runloop::CFRunLoop; + use core_foundation_sys::base::CFOptionFlags; + use core_foundation_sys::runloop::kCFRunLoopDefaultMode; + use libc::O_RDWR; use std::ffi::CString; use std::os::raw::c_void; - use core_foundation_sys::base::{CFOptionFlags}; - use core_foundation_sys::runloop::{kCFRunLoopDefaultMode}; - use libc::O_RDWR; - use runloop::{CFRunLoop}; #[test] fn test_unconsumed() { @@ -129,14 +123,16 @@ mod test { assert_eq!(unsafe { libc::close(raw_fd) }, 0); } - extern "C" fn never_callback(_f: CFFileDescriptorRef, - _callback_types: CFOptionFlags, - _info_ptr: *mut c_void) { + extern "C" fn never_callback( + _f: CFFileDescriptorRef, + _callback_types: CFOptionFlags, + _info_ptr: *mut c_void, + ) { unreachable!(); } struct TestInfo { - value: CFOptionFlags + value: CFOptionFlags, } #[test] @@ -147,7 +143,7 @@ mod test { info: &mut info as *mut _ as *mut c_void, retain: None, release: None, - copyDescription: None + copyDescription: None, }; let path = CString::new("/dev/null").unwrap(); @@ -182,7 +178,11 @@ mod test { assert!(!cf_fd.valid()); } - extern "C" fn callback(_f: CFFileDescriptorRef, callback_types: CFOptionFlags, info_ptr: *mut c_void) { + extern "C" fn callback( + _f: CFFileDescriptorRef, + callback_types: CFOptionFlags, + info_ptr: *mut c_void, + ) { assert!(!info_ptr.is_null()); let info: *mut TestInfo = info_ptr as *mut TestInfo; diff --git a/third_party/rust/core-foundation/src/lib.rs b/third_party/rust/core-foundation/src/lib.rs index b935938996..767d45aad1 100644 --- a/third_party/rust/core-foundation/src/lib.rs +++ b/third_party/rust/core-foundation/src/lib.rs @@ -21,7 +21,7 @@ extern crate libc; #[cfg(feature = "with-chrono")] extern crate chrono; -use base::TCFType; +use crate::base::TCFType; pub unsafe trait ConcreteCFType: TCFType {} @@ -165,7 +165,6 @@ macro_rules! impl_TCFType { (@Phantom $x:ident) => { ::std::marker::PhantomData }; } - /// Implement `std::fmt::Debug` for the given type. /// /// This will invoke the implementation of `Debug` for [`CFType`] @@ -200,7 +199,14 @@ macro_rules! impl_CFComparison { #[inline] fn partial_cmp(&self, other: &$ty) -> Option<::std::cmp::Ordering> { unsafe { - Some($compare(self.as_concrete_TypeRef(), other.as_concrete_TypeRef(), ::std::ptr::null_mut()).into()) + Some( + $compare( + self.as_concrete_TypeRef(), + other.as_concrete_TypeRef(), + ::std::ptr::null_mut(), + ) + .into(), + ) } } } @@ -211,26 +217,26 @@ macro_rules! impl_CFComparison { self.partial_cmp(other).unwrap() } } - } + }; } pub mod array; pub mod attributed_string; pub mod base; pub mod boolean; +pub mod bundle; pub mod characterset; pub mod data; pub mod date; pub mod dictionary; pub mod error; pub mod filedescriptor; +pub mod mach_port; pub mod number; -pub mod set; -pub mod string; -pub mod url; -pub mod bundle; pub mod propertylist; pub mod runloop; +pub mod set; +pub mod string; pub mod timezone; +pub mod url; pub mod uuid; -pub mod mach_port; diff --git a/third_party/rust/core-foundation/src/mach_port.rs b/third_party/rust/core-foundation/src/mach_port.rs index 6112e3aae0..f01847fff1 100644 --- a/third_party/rust/core-foundation/src/mach_port.rs +++ b/third_party/rust/core-foundation/src/mach_port.rs @@ -1,9 +1,8 @@ -use base::TCFType; +use crate::base::TCFType; +use crate::runloop::CFRunLoopSource; use core_foundation_sys::base::kCFAllocatorDefault; -use runloop::CFRunLoopSource; pub use core_foundation_sys::mach_port::*; - declare_TCFType! { /// An immutable numeric value. CFMachPort, CFMachPortRef @@ -12,12 +11,10 @@ impl_TCFType!(CFMachPort, CFMachPortRef, CFMachPortGetTypeID); impl_CFTypeDescription!(CFMachPort); impl CFMachPort { - pub fn create_runloop_source( - &self, - order: CFIndex, - ) -> Result { + pub fn create_runloop_source(&self, order: CFIndex) -> Result { unsafe { - let runloop_source_ref = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.0, order); + let runloop_source_ref = + CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.0, order); if runloop_source_ref.is_null() { Err(()) } else { diff --git a/third_party/rust/core-foundation/src/number.rs b/third_party/rust/core-foundation/src/number.rs index a4b2affaa7..c3b6fab96c 100644 --- a/third_party/rust/core-foundation/src/number.rs +++ b/third_party/rust/core-foundation/src/number.rs @@ -13,10 +13,9 @@ use core_foundation_sys::base::kCFAllocatorDefault; pub use core_foundation_sys::number::*; use std::os::raw::c_void; -use base::TCFType; +use crate::base::TCFType; - -declare_TCFType!{ +declare_TCFType! { /// An immutable numeric value. CFNumber, CFNumberRef } @@ -25,13 +24,20 @@ impl_CFTypeDescription!(CFNumber); impl_CFComparison!(CFNumber, CFNumberCompare); impl CFNumber { - #[inline] pub fn to_i32(&self) -> Option { unsafe { let mut value: i32 = 0; - let ok = CFNumberGetValue(self.0, kCFNumberSInt32Type, &mut value as *mut i32 as *mut c_void); - if ok { Some(value) } else { None } + let ok = CFNumberGetValue( + self.0, + kCFNumberSInt32Type, + &mut value as *mut i32 as *mut c_void, + ); + if ok { + Some(value) + } else { + None + } } } @@ -39,8 +45,16 @@ impl CFNumber { pub fn to_i64(&self) -> Option { unsafe { let mut value: i64 = 0; - let ok = CFNumberGetValue(self.0, kCFNumberSInt64Type, &mut value as *mut i64 as *mut c_void); - if ok { Some(value) } else { None } + let ok = CFNumberGetValue( + self.0, + kCFNumberSInt64Type, + &mut value as *mut i64 as *mut c_void, + ); + if ok { + Some(value) + } else { + None + } } } @@ -48,8 +62,16 @@ impl CFNumber { pub fn to_f32(&self) -> Option { unsafe { let mut value: f32 = 0.0; - let ok = CFNumberGetValue(self.0, kCFNumberFloat32Type, &mut value as *mut f32 as *mut c_void); - if ok { Some(value) } else { None } + let ok = CFNumberGetValue( + self.0, + kCFNumberFloat32Type, + &mut value as *mut f32 as *mut c_void, + ); + if ok { + Some(value) + } else { + None + } } } @@ -57,8 +79,16 @@ impl CFNumber { pub fn to_f64(&self) -> Option { unsafe { let mut value: f64 = 0.0; - let ok = CFNumberGetValue(self.0, kCFNumberFloat64Type, &mut value as *mut f64 as *mut c_void); - if ok { Some(value) } else { None } + let ok = CFNumberGetValue( + self.0, + kCFNumberFloat64Type, + &mut value as *mut f64 as *mut c_void, + ); + if ok { + Some(value) + } else { + None + } } } } diff --git a/third_party/rust/core-foundation/src/propertylist.rs b/third_party/rust/core-foundation/src/propertylist.rs index e8fceac58d..de5d1d87ba 100644 --- a/third_party/rust/core-foundation/src/propertylist.rs +++ b/third_party/rust/core-foundation/src/propertylist.rs @@ -9,30 +9,34 @@ //! Core Foundation property lists -use std::ptr; use std::mem; use std::os::raw::c_void; +use std::ptr; -use error::CFError; -use data::CFData; -use base::{CFType, TCFType, TCFTypeRef}; +use crate::base::{CFType, TCFType, TCFTypeRef}; +use crate::data::CFData; +use crate::error::CFError; -pub use core_foundation_sys::propertylist::*; +use core_foundation_sys::base::{ + kCFAllocatorDefault, CFGetRetainCount, CFGetTypeID, CFIndex, CFRetain, CFShow, CFTypeID, +}; use core_foundation_sys::error::CFErrorRef; -use core_foundation_sys::base::{CFGetRetainCount, CFGetTypeID, CFIndex, CFRetain, - CFShow, CFTypeID, kCFAllocatorDefault}; +pub use core_foundation_sys::propertylist::*; -pub fn create_with_data(data: CFData, - options: CFPropertyListMutabilityOptions) - -> Result<(*const c_void, CFPropertyListFormat), CFError> { +pub fn create_with_data( + data: CFData, + options: CFPropertyListMutabilityOptions, +) -> Result<(*const c_void, CFPropertyListFormat), CFError> { unsafe { let mut error: CFErrorRef = ptr::null_mut(); let mut format: CFPropertyListFormat = 0; - let property_list = CFPropertyListCreateWithData(kCFAllocatorDefault, - data.as_concrete_TypeRef(), - options, - &mut format, - &mut error); + let property_list = CFPropertyListCreateWithData( + kCFAllocatorDefault, + data.as_concrete_TypeRef(), + options, + &mut format, + &mut error, + ); if property_list.is_null() { Err(TCFType::wrap_under_create_rule(error)) } else { @@ -41,14 +45,14 @@ pub fn create_with_data(data: CFData, } } -pub fn create_data(property_list: *const c_void, format: CFPropertyListFormat) -> Result { +pub fn create_data( + property_list: *const c_void, + format: CFPropertyListFormat, +) -> Result { unsafe { let mut error: CFErrorRef = ptr::null_mut(); - let data_ref = CFPropertyListCreateData(kCFAllocatorDefault, - property_list, - format, - 0, - &mut error); + let data_ref = + CFPropertyListCreateData(kCFAllocatorDefault, property_list, format, 0, &mut error); if data_ref.is_null() { Err(TCFType::wrap_under_create_rule(error)) } else { @@ -57,7 +61,6 @@ pub fn create_data(property_list: *const c_void, format: CFPropertyListFormat) - } } - /// Trait for all subclasses of [`CFPropertyList`]. /// /// [`CFPropertyList`]: struct.CFPropertyList.html @@ -84,16 +87,15 @@ pub trait CFPropertyListSubClass: TCFType { } } -impl CFPropertyListSubClass for ::data::CFData {} -impl CFPropertyListSubClass for ::string::CFString {} -impl CFPropertyListSubClass for ::array::CFArray {} -impl CFPropertyListSubClass for ::dictionary::CFDictionary {} -impl CFPropertyListSubClass for ::date::CFDate {} -impl CFPropertyListSubClass for ::boolean::CFBoolean {} -impl CFPropertyListSubClass for ::number::CFNumber {} - +impl CFPropertyListSubClass for crate::data::CFData {} +impl CFPropertyListSubClass for crate::string::CFString {} +impl CFPropertyListSubClass for crate::array::CFArray {} +impl CFPropertyListSubClass for crate::dictionary::CFDictionary {} +impl CFPropertyListSubClass for crate::date::CFDate {} +impl CFPropertyListSubClass for crate::boolean::CFBoolean {} +impl CFPropertyListSubClass for crate::number::CFNumber {} -declare_TCFType!{ +declare_TCFType! { /// A CFPropertyList struct. This is superclass to [`CFData`], [`CFString`], [`CFArray`], /// [`CFDictionary`], [`CFDate`], [`CFBoolean`], and [`CFNumber`]. /// @@ -161,8 +163,8 @@ impl CFPropertyList { unsafe { CFGetRetainCount(self.as_CFTypeRef()) } } - /// Returns the type ID of this object. Will be one of CFData, CFString, CFArray, CFDictionary, - /// CFDate, CFBoolean, or CFNumber. + /// Returns the type ID of this object. Will be one of `CFData`, `CFString`, `CFArray`, + /// `CFDictionary`, `CFDate`, `CFBoolean`, or `CFNumber`. #[inline] pub fn type_of(&self) -> CFTypeID { unsafe { CFGetTypeID(self.as_CFTypeRef()) } @@ -173,7 +175,7 @@ impl CFPropertyList { unsafe { CFShow(self.as_CFTypeRef()) } } - /// Returns true if this value is an instance of another type. + /// Returns `true` if this value is an instance of another type. #[inline] pub fn instance_of(&self) -> bool { self.type_of() == OtherCFType::type_id() @@ -244,33 +246,33 @@ impl CFPropertyList { } } - - #[cfg(test)] pub mod test { use super::*; - use string::CFString; - use boolean::CFBoolean; + use crate::boolean::CFBoolean; + use crate::string::CFString; #[test] fn test_property_list_serialization() { - use base::{TCFType, CFEqual}; - use boolean::CFBoolean; - use number::CFNumber; - use dictionary::CFDictionary; - use string::CFString; use super::*; + use crate::base::{CFEqual, TCFType}; + use crate::boolean::CFBoolean; + use crate::dictionary::CFDictionary; + use crate::number::CFNumber; + use crate::string::CFString; let bar = CFString::from_static_string("Bar"); let baz = CFString::from_static_string("Baz"); let boo = CFString::from_static_string("Boo"); let foo = CFString::from_static_string("Foo"); let tru = CFBoolean::true_value(); - let n42 = CFNumber::from(1i64<<33); + let n42 = CFNumber::from(1i64 << 33); - let dict1 = CFDictionary::from_CFType_pairs(&[(bar.as_CFType(), boo.as_CFType()), - (baz.as_CFType(), tru.as_CFType()), - (foo.as_CFType(), n42.as_CFType())]); + let dict1 = CFDictionary::from_CFType_pairs(&[ + (bar.as_CFType(), boo.as_CFType()), + (baz.as_CFType(), tru.as_CFType()), + (foo.as_CFType(), n42.as_CFType()), + ]); let data = create_data(dict1.as_CFTypeRef(), kCFPropertyListXMLFormat_v1_0).unwrap(); let (dict2, _) = create_with_data(data, kCFPropertyListImmutable).unwrap(); @@ -281,7 +283,7 @@ pub mod test { #[test] fn to_propertylist_retain_count() { - let string = CFString::from_static_string("Bar"); + let string = CFString::from_static_string("alongerstring"); assert_eq!(string.retain_count(), 1); let propertylist = string.to_CFPropertyList(); @@ -295,7 +297,10 @@ pub mod test { #[test] fn downcast_string() { let propertylist = CFString::from_static_string("Bar").to_CFPropertyList(); - assert_eq!(propertylist.downcast::().unwrap().to_string(), "Bar"); + assert_eq!( + propertylist.downcast::().unwrap().to_string(), + "Bar" + ); assert!(propertylist.downcast::().is_none()); } @@ -308,7 +313,7 @@ pub mod test { #[test] fn downcast_into_fail() { - let string = CFString::from_static_string("Bar"); + let string = CFString::from_static_string("alongerstring"); let propertylist = string.to_CFPropertyList(); assert_eq!(string.retain_count(), 2); @@ -318,12 +323,12 @@ pub mod test { #[test] fn downcast_into() { - let string = CFString::from_static_string("Bar"); + let string = CFString::from_static_string("alongerstring"); let propertylist = string.to_CFPropertyList(); assert_eq!(string.retain_count(), 2); let string2 = propertylist.downcast_into::().unwrap(); - assert_eq!(string2.to_string(), "Bar"); + assert_eq!(string2.to_string(), "alongerstring"); assert_eq!(string2.retain_count(), 2); } } diff --git a/third_party/rust/core-foundation/src/runloop.rs b/third_party/rust/core-foundation/src/runloop.rs index be06f4ec7f..304c0716df 100644 --- a/third_party/rust/core-foundation/src/runloop.rs +++ b/third_party/rust/core-foundation/src/runloop.rs @@ -9,23 +9,26 @@ #![allow(non_upper_case_globals)] -pub use core_foundation_sys::runloop::*; use core_foundation_sys::base::CFIndex; use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; +pub use core_foundation_sys::runloop::*; use core_foundation_sys::string::CFStringRef; -use base::{TCFType}; -use date::{CFAbsoluteTime, CFTimeInterval}; -use filedescriptor::CFFileDescriptor; -use string::{CFString}; +use crate::base::TCFType; +use crate::date::{CFAbsoluteTime, CFTimeInterval}; +use crate::filedescriptor::CFFileDescriptor; +use crate::string::CFString; pub type CFRunLoopMode = CFStringRef; - declare_TCFType!(CFRunLoop, CFRunLoopRef); impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); impl_CFTypeDescription!(CFRunLoop); +// https://github.com/servo/core-foundation-rs/issues/550 +unsafe impl Send for CFRunLoop {} +unsafe impl Sync for CFRunLoop {} + #[derive(Copy, Clone, Debug, PartialEq)] pub enum CFRunLoopRunResult { Finished = 1, @@ -92,9 +95,7 @@ impl CFRunLoop { } pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool { - unsafe { - CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 - } + unsafe { CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 } } pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { @@ -110,9 +111,7 @@ impl CFRunLoop { } pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool { - unsafe { - CFRunLoopContainsSource(self.0, source.0, mode) != 0 - } + unsafe { CFRunLoopContainsSource(self.0, source.0, mode) != 0 } } pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { @@ -128,9 +127,7 @@ impl CFRunLoop { } pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool { - unsafe { - CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 - } + unsafe { CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 } } pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { @@ -144,25 +141,41 @@ impl CFRunLoop { CFRunLoopRemoveObserver(self.0, observer.0, mode); } } - } - declare_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef); impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID); impl CFRunLoopTimer { - pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer { + pub fn new( + fireDate: CFAbsoluteTime, + interval: CFTimeInterval, + flags: CFOptionFlags, + order: CFIndex, + callout: CFRunLoopTimerCallBack, + context: *mut CFRunLoopTimerContext, + ) -> CFRunLoopTimer { unsafe { - let timer_ref = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, flags, order, callout, context); + let timer_ref = CFRunLoopTimerCreate( + kCFAllocatorDefault, + fireDate, + interval, + flags, + order, + callout, + context, + ); TCFType::wrap_under_create_rule(timer_ref) } } } - declare_TCFType!(CFRunLoopSource, CFRunLoopSourceRef); -impl_TCFType!(CFRunLoopSource, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); +impl_TCFType!( + CFRunLoopSource, + CFRunLoopSourceRef, + CFRunLoopSourceGetTypeID +); impl CFRunLoopSource { pub fn from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option { @@ -171,15 +184,23 @@ impl CFRunLoopSource { } declare_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef); -impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeID); +impl_TCFType!( + CFRunLoopObserver, + CFRunLoopObserverRef, + CFRunLoopObserverGetTypeID +); #[cfg(test)] mod test { use super::*; - use date::{CFDate, CFAbsoluteTime}; + use crate::base::Boolean; + use crate::date::{CFAbsoluteTime, CFDate}; use std::mem; use std::os::raw::c_void; + use std::ptr::null_mut; use std::sync::mpsc; + use std::thread::spawn; + use std::time::Duration; #[test] fn wait_200_milliseconds() { @@ -199,7 +220,8 @@ mod test { copyDescription: None, }; - let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); + let run_loop_timer = + CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); unsafe { run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode); } @@ -221,4 +243,62 @@ mod test { let _ = unsafe { (*info).elapsed_tx.send(elapsed) }; CFRunLoop::get_current().stop(); } + + extern "C" fn observe(_: CFRunLoopObserverRef, _: CFRunLoopActivity, context: *mut c_void) { + let tx: &mpsc::Sender = unsafe { &*(context as *const _) }; + let _ = tx.send(CFRunLoop::get_current()); + } + + extern "C" fn observe_timer_popped(_: CFRunLoopTimerRef, _: *mut c_void) { + panic!("timer popped unexpectedly"); + } + + #[test] + fn observe_runloop() { + let (tx, rx) = mpsc::channel(); + spawn(move || { + let mut context = CFRunLoopObserverContext { + version: 0, + info: &tx as *const _ as *mut c_void, + retain: None, + release: None, + copyDescription: None, + }; + + let observer = unsafe { + CFRunLoopObserver::wrap_under_create_rule(CFRunLoopObserverCreate( + kCFAllocatorDefault, + kCFRunLoopEntry, + false as Boolean, + 0, + observe, + &mut context, + )) + }; + + let runloop = CFRunLoop::get_current(); + runloop.add_observer(&observer, unsafe { kCFRunLoopDefaultMode }); + + let timer = CFRunLoopTimer::new( + CFDate::now().abs_time() + 1f64, + 0f64, + 0, + 0, + observe_timer_popped, + null_mut(), + ); + runloop.add_timer(&timer, unsafe { kCFRunLoopDefaultMode }); + + let result = unsafe { + CFRunLoop::run_in_mode(kCFRunLoopDefaultMode, Duration::from_secs(10), false) + }; + + assert_eq!(result, CFRunLoopRunResult::Stopped); + + drop(tx); + }); + + let runloop: CFRunLoop = rx.recv().unwrap(); + runloop.stop(); + } } diff --git a/third_party/rust/core-foundation/src/set.rs b/third_party/rust/core-foundation/src/set.rs index eb1d357a03..641202de8d 100644 --- a/third_party/rust/core-foundation/src/set.rs +++ b/third_party/rust/core-foundation/src/set.rs @@ -9,13 +9,13 @@ //! An immutable bag of elements. +use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease, CFTypeRef}; pub use core_foundation_sys::set::*; -use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault}; -use base::{CFIndexConvertible, TCFType}; +use crate::base::{CFIndexConvertible, TCFType}; -use std::os::raw::c_void; use std::marker::PhantomData; +use std::os::raw::c_void; /// An immutable bag of elements. pub struct CFSet(CFSetRef, PhantomData); @@ -31,23 +31,31 @@ impl_CFTypeDescription!(CFSet); impl CFSet { /// Creates a new set from a list of `CFType` instances. - pub fn from_slice(elems: &[T]) -> CFSet where T: TCFType { + pub fn from_slice(elems: &[T]) -> CFSet + where + T: TCFType, + { unsafe { let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); - let set_ref = CFSetCreate(kCFAllocatorDefault, - elems.as_ptr(), - elems.len().to_CFIndex(), - &kCFTypeSetCallBacks); + let set_ref = CFSetCreate( + kCFAllocatorDefault, + elems.as_ptr(), + elems.len().to_CFIndex(), + &kCFTypeSetCallBacks, + ); TCFType::wrap_under_create_rule(set_ref) } } } impl CFSet { - /// Get the number of elements in the CFSet + /// Get the number of elements in the `CFSet`. pub fn len(&self) -> usize { - unsafe { - CFSetGetCount(self.0) as usize - } + unsafe { CFSetGetCount(self.0) as usize } + } + + /// Returns `true` if the set contains no elements. + pub fn is_empty(&self) -> bool { + self.len() == 0 } } diff --git a/third_party/rust/core-foundation/src/string.rs b/third_party/rust/core-foundation/src/string.rs index 3f5994bc5a..3358bab552 100644 --- a/third_party/rust/core-foundation/src/string.rs +++ b/third_party/rust/core-foundation/src/string.rs @@ -11,18 +11,17 @@ pub use core_foundation_sys::string::*; -use base::{CFIndexConvertible, TCFType}; +use crate::base::{CFIndexConvertible, TCFType}; -use core_foundation_sys::base::{Boolean, CFIndex, CFRange}; use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull}; +use core_foundation_sys::base::{Boolean, CFIndex, CFRange}; use std::borrow::Cow; +use std::ffi::CStr; use std::fmt; -use std::str::{self, FromStr}; use std::ptr; -use std::ffi::CStr; - +use std::str::{self, FromStr}; -declare_TCFType!{ +declare_TCFType! { /// An immutable string in one of a variety of encodings. CFString, CFStringRef } @@ -31,7 +30,7 @@ impl_TCFType!(CFString, CFStringRef, CFStringGetTypeID); impl FromStr for CFString { type Err = (); - /// See also CFString::new for a variant of this which does not return a Result + /// See also [`CFString::new()`] for a variant of this which does not return a `Result`. #[inline] fn from_str(string: &str) -> Result { Ok(CFString::new(string)) @@ -58,27 +57,37 @@ impl<'a> From<&'a CFString> for Cow<'a, str> { // First, ask how big the buffer ought to be. let mut bytes_required: CFIndex = 0; - CFStringGetBytes(cf_str.0, - CFRange { location: 0, length: char_len }, - kCFStringEncodingUTF8, - 0, - false as Boolean, - ptr::null_mut(), - 0, - &mut bytes_required); + CFStringGetBytes( + cf_str.0, + CFRange { + location: 0, + length: char_len, + }, + kCFStringEncodingUTF8, + 0, + false as Boolean, + ptr::null_mut(), + 0, + &mut bytes_required, + ); // Then, allocate the buffer and actually copy. let mut buffer = vec![b'\x00'; bytes_required as usize]; let mut bytes_used: CFIndex = 0; - let chars_written = CFStringGetBytes(cf_str.0, - CFRange { location: 0, length: char_len }, - kCFStringEncodingUTF8, - 0, - false as Boolean, - buffer.as_mut_ptr(), - buffer.len().to_CFIndex(), - &mut bytes_used); + let chars_written = CFStringGetBytes( + cf_str.0, + CFRange { + location: 0, + length: char_len, + }, + kCFStringEncodingUTF8, + 0, + false as Boolean, + buffer.as_mut_ptr(), + buffer.len().to_CFIndex(), + &mut bytes_used, + ); assert_eq!(chars_written, char_len); // This is dangerous; we over-allocate and null-terminate the string (during @@ -102,17 +111,18 @@ impl fmt::Debug for CFString { } } - impl CFString { /// Creates a new `CFString` instance from a Rust string. #[inline] pub fn new(string: &str) -> CFString { unsafe { - let string_ref = CFStringCreateWithBytes(kCFAllocatorDefault, - string.as_ptr(), - string.len().to_CFIndex(), - kCFStringEncodingUTF8, - false as Boolean); + let string_ref = CFStringCreateWithBytes( + kCFAllocatorDefault, + string.as_ptr(), + string.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean, + ); CFString::wrap_under_create_rule(string_ref) } } @@ -122,12 +132,14 @@ impl CFString { #[inline] pub fn from_static_string(string: &'static str) -> CFString { unsafe { - let string_ref = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, - string.as_ptr(), - string.len().to_CFIndex(), - kCFStringEncodingUTF8, - false as Boolean, - kCFAllocatorNull); + let string_ref = CFStringCreateWithBytesNoCopy( + kCFAllocatorDefault, + string.as_ptr(), + string.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean, + kCFAllocatorNull, + ); TCFType::wrap_under_create_rule(string_ref) } } @@ -135,21 +147,21 @@ impl CFString { /// Returns the number of characters in the string. #[inline] pub fn char_len(&self) -> CFIndex { - unsafe { - CFStringGetLength(self.0) - } + unsafe { CFStringGetLength(self.0) } } } impl<'a> PartialEq<&'a str> for CFString { fn eq(&self, other: &&str) -> bool { unsafe { - let temp = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, - other.as_ptr(), - other.len().to_CFIndex(), - kCFStringEncodingUTF8, - false as Boolean, - kCFAllocatorNull); + let temp = CFStringCreateWithBytesNoCopy( + kCFAllocatorDefault, + other.as_ptr(), + other.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean, + kCFAllocatorNull, + ); self.eq(&CFString::wrap_under_create_rule(temp)) } } diff --git a/third_party/rust/core-foundation/src/timezone.rs b/third_party/rust/core-foundation/src/timezone.rs index a8bb2ed1d2..46123dcc22 100644 --- a/third_party/rust/core-foundation/src/timezone.rs +++ b/third_party/rust/core-foundation/src/timezone.rs @@ -9,18 +9,17 @@ //! Core Foundation time zone objects. -pub use core_foundation_sys::timezone::*; use core_foundation_sys::base::kCFAllocatorDefault; +pub use core_foundation_sys::timezone::*; -use base::TCFType; -use date::{CFDate, CFTimeInterval}; -use string::CFString; +use crate::base::TCFType; +use crate::date::{CFDate, CFTimeInterval}; +use crate::string::CFString; #[cfg(feature = "with-chrono")] use chrono::{FixedOffset, NaiveDateTime}; - -declare_TCFType!{ +declare_TCFType! { /// A time zone. CFTimeZone, CFTimeZoneRef } @@ -54,9 +53,7 @@ impl CFTimeZone { } pub fn seconds_from_gmt(&self, date: CFDate) -> CFTimeInterval { - unsafe { - CFTimeZoneGetSecondsFromGMT(self.0, date.abs_time()) - } + unsafe { CFTimeZoneGetSecondsFromGMT(self.0, date.abs_time()) } } #[cfg(feature = "with-chrono")] @@ -70,12 +67,10 @@ impl CFTimeZone { CFTimeZone::new(offset.local_minus_utc() as f64) } - /// The timezone database ID that identifies the time zone. E.g. "America/Los_Angeles" or - /// "Europe/Paris". + /// The timezone database ID that identifies the time zone. E.g. `"America/Los_Angeles" `or + /// `"Europe/Paris"`. pub fn name(&self) -> CFString { - unsafe { - CFString::wrap_under_get_rule(CFTimeZoneGetName(self.0)) - } + unsafe { CFString::wrap_under_get_rule(CFTimeZoneGetName(self.0)) } } } @@ -84,7 +79,7 @@ mod test { use super::CFTimeZone; #[cfg(feature = "with-chrono")] - use chrono::{NaiveDateTime, FixedOffset}; + use chrono::{FixedOffset, NaiveDateTime}; #[test] fn timezone_comparison() { diff --git a/third_party/rust/core-foundation/src/url.rs b/third_party/rust/core-foundation/src/url.rs index 064dd7b5e0..b929844385 100644 --- a/third_party/rust/core-foundation/src/url.rs +++ b/third_party/rust/core-foundation/src/url.rs @@ -11,21 +11,20 @@ pub use core_foundation_sys::url::*; -use base::{TCFType, CFIndex}; -use string::{CFString}; +use crate::base::{CFIndex, TCFType}; +use crate::string::CFString; use core_foundation_sys::base::{kCFAllocatorDefault, Boolean}; use std::fmt; -use std::ptr; use std::path::{Path, PathBuf}; +use std::ptr; use libc::{c_char, strlen, PATH_MAX}; -#[cfg(unix)] -use std::os::unix::ffi::OsStrExt; #[cfg(unix)] use std::ffi::OsStr; - +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; declare_TCFType!(CFURL, CFURLRef); impl_TCFType!(CFURL, CFURLRef, CFURLGetTypeID); @@ -35,7 +34,7 @@ impl fmt::Debug for CFURL { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.0)); - write!(f, "{}", string.to_string()) + write!(f, "{}", string) } } } @@ -58,7 +57,12 @@ impl CFURL { } unsafe { - let url_ref = CFURLCreateFromFileSystemRepresentation(ptr::null_mut(), path_bytes.as_ptr(), path_bytes.len() as CFIndex, isDirectory as u8); + let url_ref = CFURLCreateFromFileSystemRepresentation( + ptr::null_mut(), + path_bytes.as_ptr(), + path_bytes.len() as CFIndex, + isDirectory as u8, + ); if url_ref.is_null() { return None; } @@ -66,9 +70,18 @@ impl CFURL { } } - pub fn from_file_system_path(filePath: CFString, pathStyle: CFURLPathStyle, isDirectory: bool) -> CFURL { + pub fn from_file_system_path( + filePath: CFString, + pathStyle: CFURLPathStyle, + isDirectory: bool, + ) -> CFURL { unsafe { - let url_ref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath.as_concrete_TypeRef(), pathStyle, isDirectory as u8); + let url_ref = CFURLCreateWithFileSystemPath( + kCFAllocatorDefault, + filePath.as_concrete_TypeRef(), + pathStyle, + isDirectory as u8, + ); TCFType::wrap_under_create_rule(url_ref) } } @@ -78,7 +91,12 @@ impl CFURL { // implementing this on Windows is more complicated because of the different OsStr representation unsafe { let mut buf = [0u8; PATH_MAX as usize]; - let result = CFURLGetFileSystemRepresentation(self.0, true as Boolean, buf.as_mut_ptr(), buf.len() as CFIndex); + let result = CFURLGetFileSystemRepresentation( + self.0, + true as Boolean, + buf.as_mut_ptr(), + buf.len() as CFIndex, + ); if result == false as Boolean { return None; } @@ -89,21 +107,20 @@ impl CFURL { } pub fn get_string(&self) -> CFString { - unsafe { - TCFType::wrap_under_get_rule(CFURLGetString(self.0)) - } + unsafe { TCFType::wrap_under_get_rule(CFURLGetString(self.0)) } } pub fn get_file_system_path(&self, pathStyle: CFURLPathStyle) -> CFString { unsafe { - TCFType::wrap_under_create_rule(CFURLCopyFileSystemPath(self.as_concrete_TypeRef(), pathStyle)) + TCFType::wrap_under_create_rule(CFURLCopyFileSystemPath( + self.as_concrete_TypeRef(), + pathStyle, + )) } } pub fn absolute(&self) -> CFURL { - unsafe { - TCFType::wrap_under_create_rule(CFURLCopyAbsoluteURL(self.as_concrete_TypeRef())) - } + unsafe { TCFType::wrap_under_create_rule(CFURLCopyAbsoluteURL(self.as_concrete_TypeRef())) } } } @@ -138,18 +155,30 @@ fn absolute_file_url() { let cfstr_file = CFString::from_static_string(file); let cfurl_base = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); let cfurl_relative: CFURL = unsafe { - let url_ref = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, + let url_ref = CFURLCreateWithFileSystemPathRelativeToBase( + kCFAllocatorDefault, cfstr_file.as_concrete_TypeRef(), kCFURLPOSIXPathStyle, false as u8, - cfurl_base.as_concrete_TypeRef()); + cfurl_base.as_concrete_TypeRef(), + ); TCFType::wrap_under_create_rule(url_ref) }; let mut absolute_path = PathBuf::from(path); absolute_path.push(file); - assert_eq!(cfurl_relative.get_file_system_path(kCFURLPOSIXPathStyle).to_string(), file); - assert_eq!(cfurl_relative.absolute().get_file_system_path(kCFURLPOSIXPathStyle).to_string(), - absolute_path.to_str().unwrap()); + assert_eq!( + cfurl_relative + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + file + ); + assert_eq!( + cfurl_relative + .absolute() + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + absolute_path.to_str().unwrap() + ); } diff --git a/third_party/rust/core-foundation/src/uuid.rs b/third_party/rust/core-foundation/src/uuid.rs index 6be734dabc..834a6dd9d2 100644 --- a/third_party/rust/core-foundation/src/uuid.rs +++ b/third_party/rust/core-foundation/src/uuid.rs @@ -12,15 +12,14 @@ #[cfg(feature = "with-uuid")] extern crate uuid; -pub use core_foundation_sys::uuid::*; use core_foundation_sys::base::kCFAllocatorDefault; +pub use core_foundation_sys::uuid::*; -use base::TCFType; +use crate::base::TCFType; #[cfg(feature = "with-uuid")] use self::uuid::Uuid; - declare_TCFType! { /// A UUID. CFUUID, CFUUIDRef @@ -45,28 +44,12 @@ impl Default for CFUUID { } #[cfg(feature = "with-uuid")] -impl Into for CFUUID { - fn into(self) -> Uuid { - let b = unsafe { - CFUUIDGetUUIDBytes(self.0) - }; +impl From for Uuid { + fn from(val: CFUUID) -> Self { + let b = unsafe { CFUUIDGetUUIDBytes(val.0) }; let bytes = [ - b.byte0, - b.byte1, - b.byte2, - b.byte3, - b.byte4, - b.byte5, - b.byte6, - b.byte7, - b.byte8, - b.byte9, - b.byte10, - b.byte11, - b.byte12, - b.byte13, - b.byte14, - b.byte15, + b.byte0, b.byte1, b.byte2, b.byte3, b.byte4, b.byte5, b.byte6, b.byte7, b.byte8, + b.byte9, b.byte10, b.byte11, b.byte12, b.byte13, b.byte14, b.byte15, ]; Uuid::from_bytes(&bytes).unwrap() } @@ -101,7 +84,6 @@ impl From for CFUUID { } } - #[cfg(test)] #[cfg(feature = "with-uuid")] mod test { diff --git a/third_party/rust/core-graphics-types/.cargo-checksum.json b/third_party/rust/core-graphics-types/.cargo-checksum.json index cc00991ad2..69613fe009 100644 --- a/third_party/rust/core-graphics-types/.cargo-checksum.json +++ b/third_party/rust/core-graphics-types/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"cac07dfd7a2fcbb169a0c471a8a139ade8da91f92b7fbc198f3f2185d9c94d16","src/base.rs":"561db031cc746eab35a10fe72e10c314615b11e13cd48366fcdb2223196308a7","src/geometry.rs":"4ed03b07a4c5ba0f090689d31ef6eab8ec5b8f6eb7fb4e04fdf65e5ad8cd70ea","src/lib.rs":"31700ac9508fd32005bafd1c12a86a6803d198e9b1a71166a7391e642c091cd1"},"package":"2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33"} \ No newline at end of file +{"files":{"Cargo.toml":"a49bc6534c1e5be53c72f3016ff7f64509a5570868dc943178c75b541fa839da","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","src/base.rs":"7e4e9c23f874443d0095f82d2786dc65b6b6635cbe8b3514999be80445a92bc8","src/geometry.rs":"7eda026c3db65cac836531565f85120132ab1ec84f76467a68ff040b8dc437c4","src/lib.rs":"42baf24c75dc6627bd4ca8481c503febf54e7eafa50cce40804042ddc74881c8"},"package":"45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"} \ No newline at end of file diff --git a/third_party/rust/core-graphics-types/Cargo.toml b/third_party/rust/core-graphics-types/Cargo.toml index 365717dfb4..2c28237424 100644 --- a/third_party/rust/core-graphics-types/Cargo.toml +++ b/third_party/rust/core-graphics-types/Cargo.toml @@ -10,8 +10,9 @@ # See Cargo.toml.orig for the original contents. [package] +edition = "2018" name = "core-graphics-types" -version = "0.1.2" +version = "0.1.3" authors = ["The Servo Project Developers"] description = "Bindings for some fundamental Core Graphics types" homepage = "https://github.com/servo/core-foundation-rs" @@ -25,7 +26,12 @@ default-target = "x86_64-apple-darwin" version = "1.0" [dependencies.core-foundation] -version = "0.9" +version = "0.9.4" +default-features = false [dependencies.libc] version = "0.2" + +[features] +default = ["link"] +link = ["core-foundation/link"] diff --git a/third_party/rust/core-graphics-types/LICENSE-APACHE b/third_party/rust/core-graphics-types/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/core-graphics-types/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/core-graphics-types/LICENSE-MIT b/third_party/rust/core-graphics-types/LICENSE-MIT new file mode 100644 index 0000000000..807526f57f --- /dev/null +++ b/third_party/rust/core-graphics-types/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2012-2013 Mozilla Foundation + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/core-graphics-types/src/base.rs b/third_party/rust/core-graphics-types/src/base.rs index 03a85f1559..4d87233199 100644 --- a/third_party/rust/core-graphics-types/src/base.rs +++ b/third_party/rust/core-graphics-types/src/base.rs @@ -14,9 +14,7 @@ use libc; -#[cfg(any(target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64"))] +#[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "aarch64"))] pub type boolean_t = libc::c_int; #[cfg(target_arch = "x86_64")] pub type boolean_t = libc::c_uint; diff --git a/third_party/rust/core-graphics-types/src/geometry.rs b/third_party/rust/core-graphics-types/src/geometry.rs index 586075270c..b585afdcbd 100644 --- a/third_party/rust/core-graphics-types/src/geometry.rs +++ b/third_party/rust/core-graphics-types/src/geometry.rs @@ -7,14 +7,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use base::CGFloat; +use crate::base::CGFloat; use core_foundation::base::TCFType; use core_foundation::dictionary::CFDictionary; -pub const CG_ZERO_POINT: CGPoint = CGPoint { - x: 0.0, - y: 0.0, -}; +pub const CG_ZERO_POINT: CGPoint = CGPoint { x: 0.0, y: 0.0 }; pub const CG_ZERO_SIZE: CGSize = CGSize { width: 0.0, @@ -27,9 +24,12 @@ pub const CG_ZERO_RECT: CGRect = CGRect { }; pub const CG_AFFINE_TRANSFORM_IDENTITY: CGAffineTransform = CGAffineTransform { - a: 1.0, b: 0.0, - c: 0.0, d: 1.0, - tx: 0.0, ty: 0.0, + a: 1.0, + b: 0.0, + c: 0.0, + d: 1.0, + tx: 0.0, + ty: 0.0, }; #[repr(C)] @@ -42,17 +42,12 @@ pub struct CGSize { impl CGSize { #[inline] pub fn new(width: CGFloat, height: CGFloat) -> CGSize { - CGSize { - width: width, - height: height, - } + CGSize { width, height } } #[inline] pub fn apply_transform(&self, t: &CGAffineTransform) -> CGSize { - unsafe { - ffi::CGSizeApplyAffineTransform(*self, *t) - } + unsafe { ffi::CGSizeApplyAffineTransform(*self, *t) } } } @@ -66,17 +61,12 @@ pub struct CGPoint { impl CGPoint { #[inline] pub fn new(x: CGFloat, y: CGFloat) -> CGPoint { - CGPoint { - x: x, - y: y, - } + CGPoint { x, y } } #[inline] pub fn apply_transform(&self, t: &CGAffineTransform) -> CGPoint { - unsafe { - ffi::CGPointApplyAffineTransform(*self, *t) - } + unsafe { ffi::CGPointApplyAffineTransform(*self, *t) } } } @@ -84,7 +74,7 @@ impl CGPoint { #[derive(Clone, Copy, Debug, Default)] pub struct CGRect { pub origin: CGPoint, - pub size: CGSize + pub size: CGSize, } impl CGRect { @@ -98,9 +88,7 @@ impl CGRect { #[inline] pub fn inset(&self, size: &CGSize) -> CGRect { - unsafe { - ffi::CGRectInset(*self, size.width, size.height) - } + unsafe { ffi::CGRectInset(*self, size.width, size.height) } } #[inline] @@ -134,14 +122,12 @@ impl CGRect { #[inline] pub fn apply_transform(&self, t: &CGAffineTransform) -> CGRect { - unsafe { - ffi::CGRectApplyAffineTransform(*self, *t) - } + unsafe { ffi::CGRectApplyAffineTransform(*self, *t) } } #[inline] pub fn contains(&self, point: &CGPoint) -> bool { - unsafe { ffi::CGRectContainsPoint(*self,*point) == 1 } + unsafe { ffi::CGRectContainsPoint(*self, *point) == 1 } } } @@ -171,22 +157,22 @@ impl CGAffineTransform { #[inline] pub fn invert(&self) -> CGAffineTransform { - unsafe { - ffi::CGAffineTransformInvert(*self) - } + unsafe { ffi::CGAffineTransformInvert(*self) } } } mod ffi { - use base::{CGFloat, boolean_t}; - use geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; + use crate::base::{boolean_t, CGFloat}; + use crate::geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; use core_foundation::dictionary::CFDictionaryRef; - #[link(name = "CoreGraphics", kind = "framework")] - extern { + #[cfg_attr(feature = "link", link(name = "CoreGraphics", kind = "framework"))] + extern "C" { pub fn CGRectInset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect; - pub fn CGRectMakeWithDictionaryRepresentation(dict: CFDictionaryRef, - rect: *mut CGRect) -> boolean_t; + pub fn CGRectMakeWithDictionaryRepresentation( + dict: CFDictionaryRef, + rect: *mut CGRect, + ) -> boolean_t; pub fn CGRectIsEmpty(rect: CGRect) -> boolean_t; pub fn CGRectIntersectsRect(rect1: CGRect, rect2: CGRect) -> boolean_t; @@ -196,7 +182,6 @@ mod ffi { pub fn CGRectApplyAffineTransform(rect: CGRect, t: CGAffineTransform) -> CGRect; pub fn CGSizeApplyAffineTransform(size: CGSize, t: CGAffineTransform) -> CGSize; - pub fn CGRectContainsPoint(rect:CGRect, point: CGPoint) -> boolean_t; + pub fn CGRectContainsPoint(rect: CGRect, point: CGPoint) -> boolean_t; } } - diff --git a/third_party/rust/core-graphics-types/src/lib.rs b/third_party/rust/core-graphics-types/src/lib.rs index f34bf01207..94a4eb9797 100644 --- a/third_party/rust/core-graphics-types/src/lib.rs +++ b/third_party/rust/core-graphics-types/src/lib.rs @@ -7,8 +7,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate libc; extern crate core_foundation; +extern crate libc; pub mod base; pub mod geometry; diff --git a/third_party/rust/cssparser-macros/.cargo-checksum.json b/third_party/rust/cssparser-macros/.cargo-checksum.json index 7d765b8aa1..d6f57235d1 100644 --- a/third_party/rust/cssparser-macros/.cargo-checksum.json +++ b/third_party/rust/cssparser-macros/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"b3a51cde73d95cac878371677b7e3a847b8726b49ab61204682c691dc1b1b81c","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","lib.rs":"10e68d5a92a053ff498cb1caa8290e508f691e32b73222a5a4737ee9a4097ce2"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"d4a43ad31d5048cf19ee80ec38de90fa98b9b9902b97d61e4edc940246806295","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","lib.rs":"10e68d5a92a053ff498cb1caa8290e508f691e32b73222a5a4737ee9a4097ce2"},"package":"13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"} \ No newline at end of file diff --git a/third_party/rust/cssparser-macros/Cargo.toml b/third_party/rust/cssparser-macros/Cargo.toml index 0cafd289af..601ac6a3af 100644 --- a/third_party/rust/cssparser-macros/Cargo.toml +++ b/third_party/rust/cssparser-macros/Cargo.toml @@ -23,8 +23,8 @@ repository = "https://github.com/servo/rust-cssparser" path = "lib.rs" proc-macro = true -[dependencies] -quote = "1" +[dependencies.quote] +version = "1" [dependencies.syn] version = "2" diff --git a/third_party/rust/cssparser/.cargo-checksum.json b/third_party/rust/cssparser/.cargo-checksum.json index 2c42f1420e..c4e19e50be 100644 --- a/third_party/rust/cssparser/.cargo-checksum.json +++ b/third_party/rust/cssparser/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".github/workflows/main.yml":"9fb6be1c14d9107ac4613e660d111d469722839ddf8a59e781c54a3607676e9e","Cargo.toml":"2c12f0dd7e94af4ca4ae29a741d2de2447c705f83fec0ab601b3548d2b7c64f4","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"53a6805edd80f642473514cb93f1f4197e17a911d66a2dfcefc3dc5e82bac206","docs/.nojekyll":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","docs/404.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","docs/index.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","src/color.rs":"eedf03d8ba8ca54a744617fdd945c80cbae73f99b6dff06f43a39764a93a3ac5","src/cow_rc_str.rs":"4d172d3633ef55af815784fbaee03cbcf85796a380765a0af09bbb6ca5b6fbab","src/from_bytes.rs":"b1cf15c4e975523fef46b575598737a39f3c63e5ce0b2bfd6ec627c69c6ea54a","src/lib.rs":"13be989c091fb59ecab3e855e76e7c3468f465f63e7391303fa51f251441916a","src/macros.rs":"c6e06fd014ee8c6212c72928e8b474fb1cd13a0b604055e9943ed05179a0e63b","src/nth.rs":"2fc26915f0a36cb22ac45dd9a7ecbdc64c327b2ec135370258ec3db9f9985460","src/parser.rs":"51d86df7f788da4ee6bdef8e92474bf118ac26f8954f82a14d11f1f578b6998e","src/rules_and_declarations.rs":"180c797c75a1f7298c4e47dc819cd5f8c8d911d20492eac88f10d910fd5258d4","src/serializer.rs":"b3d59a3b72a67f7bcd0f949497445d756f584661424682d03a3a1030ed4862b1","src/size_of_tests.rs":"da0cbcaa304f7800e9122e2bce0a11d42a70b9012e646a723cb23ee74a6b858c","src/tests.rs":"aa67c41be76b2a944d4d6dd162c3e8a77be1f877e94ac62e8f065adb5407a669","src/tokenizer.rs":"1f690582d4cdba930a379e5808d54f4085e3c6b60345e55c1141df7e263c722a","src/unicode_range.rs":"20d96f06fbb73921e308cc340c9fe065e27f19843005689fb259007a6a372bcc"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"f93c7e90c8e06349e2c3faee56f48c9121ab0a1571db502143c8c50df75c98a4","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"95e81e8f22062ba196eb8229a749327c063620ccf31ce1dd01b7ea0529840280","docs/404.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","docs/index.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","src/color.rs":"5edc02f840f6837580e800c860e91c8ea28c77f0dd157bffdf648827c476d01c","src/cow_rc_str.rs":"9bb6f4ca76ec51bcf85ec3ff23b80c76a0113df0856a60f34fbcd43e869a19ad","src/from_bytes.rs":"b1cf15c4e975523fef46b575598737a39f3c63e5ce0b2bfd6ec627c69c6ea54a","src/lib.rs":"13be989c091fb59ecab3e855e76e7c3468f465f63e7391303fa51f251441916a","src/macros.rs":"64ad9e506e5cea52767a5177779ac4a1cbdac1b2188abaa1291e9feb8f1653bf","src/nth.rs":"972cc94275126e747c95621e8c5f56ce5d869924e60bb0dc990f4c98f3d74890","src/parser.rs":"beb4327ada3ae9f0f6cef29a88ef6d210b9942dc459369f7ffc4529a5f413f47","src/rules_and_declarations.rs":"4b16d61e017de50c81ac3aa7ff78eeb186af1e233bbd1e93b31c2c3aff944ddc","src/serializer.rs":"807ae7f49abd6a0a83172321ec95624de2266f6caa687b014c58e9f9660b629a","src/size_of_tests.rs":"da0cbcaa304f7800e9122e2bce0a11d42a70b9012e646a723cb23ee74a6b858c","src/tests.rs":"00c370284ff862faec40e580507593dad51bff608360f8562634fb6948eee2f0","src/tokenizer.rs":"99977cf09f2e8d1b45fe98a4db2eda89defd64cb99c948885c0cec2122951b41","src/unicode_range.rs":"db0217629bf70dafef5cc93a9615d54dd0f2a5bfd19d31e1d06bf4c7b006dd1e"},"package":"b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3"} \ No newline at end of file diff --git a/third_party/rust/cssparser/.github/workflows/main.yml b/third_party/rust/cssparser/.github/workflows/main.yml deleted file mode 100644 index 0d3c0229fb..0000000000 --- a/third_party/rust/cssparser/.github/workflows/main.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: CI - -on: - push: - branches: [master] - pull_request: - workflow_dispatch: - merge_group: - types: [checks_requested] - -jobs: - linux-ci: - name: Linux - runs-on: ubuntu-latest - strategy: - matrix: - toolchain: - - nightly - - beta - - stable - - 1.63.0 - features: - - - - --features dummy_match_byte - include: - - toolchain: nightly - features: --features bench - - toolchain: nightly - features: --features bench,dummy_match_byte - steps: - - uses: actions/checkout@v2 - - - name: Install toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.toolchain }} - override: true - components: ${{ matrix.toolchain == 'nightly' && 'miri,rust-src' || '' }} - - - name: Cargo build - run: cargo build ${{ matrix.features }} - - - name: Cargo doc - run: cargo doc ${{ matrix.features }} - - - name: Cargo test - run: cargo test ${{ matrix.features }} - - - name: macros build - run: cargo build - working-directory: macros - - - name: Color build - run: cargo build - working-directory: color - - - name: Color test - run: cargo test - working-directory: color - - - name: Cargo miri test - if: "matrix.toolchain == 'nightly'" - run: cargo miri test --features skip_long_tests ${{ matrix.features }} - - build_result: - name: Result - runs-on: ubuntu-latest - needs: - - "linux-ci" - - steps: - - name: Mark the job as successful - run: exit 0 - if: success() - - name: Mark the job as unsuccessful - run: exit 1 - if: "!success()" diff --git a/third_party/rust/cssparser/Cargo.toml b/third_party/rust/cssparser/Cargo.toml index 28312541ae..bceceea9d2 100644 --- a/third_party/rust/cssparser/Cargo.toml +++ b/third_party/rust/cssparser/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" rust-version = "1.63" name = "cssparser" -version = "0.33.0" +version = "0.34.0" authors = ["Simon Sapin "] exclude = [ "src/css-parsing-tests/**", @@ -30,36 +30,41 @@ keywords = [ license = "MPL-2.0" repository = "https://github.com/servo/rust-cssparser" -[dependencies] -dtoa-short = "0.3" -itoa = "1.0" -smallvec = "1.0" +[profile.profiling] +debug = 2 +inherits = "release" [dependencies.cssparser-macros] version = "0.6.1" -path = "./macros" + +[dependencies.dtoa-short] +version = "0.3" + +[dependencies.itoa] +version = "1.0" [dependencies.phf] -version = ">=0.8,<=0.11" +version = "0.11.2" features = ["macros"] [dependencies.serde] version = "1.0" +features = ["derive"] optional = true -[dev-dependencies] -difference = "2.0" -encoding_rs = "0.8" -serde_json = "1.0" +[dependencies.smallvec] +version = "1.0" + +[dev-dependencies.difference] +version = "2.0" + +[dev-dependencies.encoding_rs] +version = "0.8" + +[dev-dependencies.serde_json] +version = "1.0.25" [features] bench = [] dummy_match_byte = [] skip_long_tests = [] - -[workspace] -members = [ - ".", - "./macros", - "./color", -] diff --git a/third_party/rust/cssparser/README.md b/third_party/rust/cssparser/README.md index 84d47d9e04..d9ca4ada84 100644 --- a/third_party/rust/cssparser/README.md +++ b/third_party/rust/cssparser/README.md @@ -3,7 +3,7 @@ rust-cssparser [![Build Status](https://github.com/servo/rust-cssparser/actions/workflows/main.yml/badge.svg)](https://github.com/servo/rust-cssparser/actions) -[Documentation](https://docs.rs/cssparser/) +[Documentation](https://docs.rs/cssparser) Rust implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) @@ -53,5 +53,5 @@ Parsing CSS involves a series of steps: It does however provide some helper functions to parse [CSS colors](src/color.rs) and [An+B](src/nth.rs) (the argument to `:nth-child()` and related selectors. - See [Servo’s `style` crate](https://github.com/servo/servo/tree/master/components/style) + See [Servo’s `style` crate](https://github.com/servo/stylo/tree/main/style) for an example of a parser based on rust-cssparser. diff --git a/third_party/rust/cssparser/docs/.nojekyll b/third_party/rust/cssparser/docs/.nojekyll deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/third_party/rust/cssparser/src/color.rs b/third_party/rust/cssparser/src/color.rs index d5f9a5c0e6..978936e01a 100644 --- a/third_party/rust/cssparser/src/color.rs +++ b/third_party/rust/cssparser/src/color.rs @@ -14,9 +14,8 @@ /// The opaque alpha value of 1.0. pub const OPAQUE: f32 = 1.0; -use crate::ToCss; +use crate::{BasicParseError, Parser, ToCss, Token}; use std::fmt; -use std::str::FromStr; /// Clamp a 0..1 number to a 0..255 range to u8. /// @@ -76,7 +75,9 @@ pub fn serialize_color_alpha( /// A Predefined color space specified in: /// -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] pub enum PredefinedColorSpace { /// Srgb, @@ -97,36 +98,21 @@ pub enum PredefinedColorSpace { } impl PredefinedColorSpace { - /// Returns the string value of the predefined color space. - pub fn as_str(&self) -> &str { - match self { - PredefinedColorSpace::Srgb => "srgb", - PredefinedColorSpace::SrgbLinear => "srgb-linear", - PredefinedColorSpace::DisplayP3 => "display-p3", - PredefinedColorSpace::A98Rgb => "a98-rgb", - PredefinedColorSpace::ProphotoRgb => "prophoto-rgb", - PredefinedColorSpace::Rec2020 => "rec2020", - PredefinedColorSpace::XyzD50 => "xyz-d50", - PredefinedColorSpace::XyzD65 => "xyz-d65", - } - } -} - -impl FromStr for PredefinedColorSpace { - type Err = (); + /// Parse a PredefinedColorSpace from the given input. + pub fn parse<'i>(input: &mut Parser<'i, '_>) -> Result> { + let location = input.current_source_location(); - fn from_str(s: &str) -> Result { - Ok(match_ignore_ascii_case! { s, - "srgb" => PredefinedColorSpace::Srgb, - "srgb-linear" => PredefinedColorSpace::SrgbLinear, - "display-p3" => PredefinedColorSpace::DisplayP3, - "a98-rgb" => PredefinedColorSpace::A98Rgb, - "prophoto-rgb" => PredefinedColorSpace::ProphotoRgb, - "rec2020" => PredefinedColorSpace::Rec2020, - "xyz-d50" => PredefinedColorSpace::XyzD50, - "xyz" | "xyz-d65" => PredefinedColorSpace::XyzD65, - - _ => return Err(()), + let ident = input.expect_ident()?; + Ok(match_ignore_ascii_case! { ident, + "srgb" => Self::Srgb, + "srgb-linear" => Self::SrgbLinear, + "display-p3" => Self::DisplayP3, + "a98-rgb" => Self::A98Rgb, + "prophoto-rgb" => Self::ProphotoRgb, + "rec2020" => Self::Rec2020, + "xyz-d50" => Self::XyzD50, + "xyz" | "xyz-d65" => Self::XyzD65, + _ => return Err(location.new_basic_unexpected_token_error(Token::Ident(ident.clone()))), }) } } @@ -136,11 +122,21 @@ impl ToCss for PredefinedColorSpace { where W: fmt::Write, { - dest.write_str(self.as_str()) + dest.write_str(match self { + Self::Srgb => "srgb", + Self::SrgbLinear => "srgb-linear", + Self::DisplayP3 => "display-p3", + Self::A98Rgb => "a98-rgb", + Self::ProphotoRgb => "prophoto-rgb", + Self::Rec2020 => "rec2020", + Self::XyzD50 => "xyz-d50", + Self::XyzD65 => "xyz-d65", + }) } } /// Parse a color hash, without the leading '#' character. +#[allow(clippy::result_unit_err)] #[inline] pub fn parse_hash_color(value: &[u8]) -> Result<(u8, u8, u8, f32), ()> { Ok(match value.len() { @@ -328,6 +324,7 @@ ascii_case_insensitive_phf_map! { /// Returns the named color with the given name. /// +#[allow(clippy::result_unit_err)] #[inline] pub fn parse_named_color(ident: &str) -> Result<(u8, u8, u8), ()> { named_colors::get(ident).copied().ok_or(()) diff --git a/third_party/rust/cssparser/src/cow_rc_str.rs b/third_party/rust/cssparser/src/cow_rc_str.rs index ecf14a0a75..2650848111 100644 --- a/third_party/rust/cssparser/src/cow_rc_str.rs +++ b/third_party/rust/cssparser/src/cow_rc_str.rs @@ -4,7 +4,7 @@ use std::borrow::{Borrow, Cow}; use std::rc::Rc; -use std::{cmp, fmt, hash, marker, mem, ops, slice, str, ptr}; +use std::{cmp, fmt, hash, marker, mem, ops, ptr, slice, str}; /// A string that is either shared (heap-allocated and reference-counted) or borrowed. /// @@ -23,9 +23,9 @@ pub struct CowRcStr<'a> { phantom: marker::PhantomData>>, } -fn _static_assert_same_size<'a>() { +fn _static_assert_same_size() { // "Instantiate" the generic function without calling it. - let _ = mem::transmute::, Option>>; + let _ = mem::transmute::, Option>>; } impl<'a> From> for CowRcStr<'a> { diff --git a/third_party/rust/cssparser/src/macros.rs b/third_party/rust/cssparser/src/macros.rs index fc4b77a194..67d8365884 100644 --- a/third_party/rust/cssparser/src/macros.rs +++ b/third_party/rust/cssparser/src/macros.rs @@ -182,7 +182,7 @@ pub fn _cssparser_internal_to_lowercase<'a>( let input_bytes = unsafe { &*(input.as_bytes() as *const [u8] as *const [MaybeUninit]) }; - buffer.copy_from_slice(&*input_bytes); + buffer.copy_from_slice(input_bytes); // Same as above re layout, plus these bytes have been initialized: let buffer = unsafe { &mut *(buffer as *mut [MaybeUninit] as *mut [u8]) }; @@ -195,7 +195,7 @@ pub fn _cssparser_internal_to_lowercase<'a>( } Some( - match input.bytes().position(|byte| matches!(byte, b'A'..=b'Z')) { + match input.bytes().position(|byte| byte.is_ascii_uppercase()) { Some(first_uppercase) => make_ascii_lowercase(buffer, input, first_uppercase), // common case: input is already lower-case None => input, diff --git a/third_party/rust/cssparser/src/nth.rs b/third_party/rust/cssparser/src/nth.rs index 518de4d9b4..4fe5a6bc04 100644 --- a/third_party/rust/cssparser/src/nth.rs +++ b/third_party/rust/cssparser/src/nth.rs @@ -7,8 +7,8 @@ use super::{BasicParseError, Parser, ParserInput, Token}; /// Parse the *An+B* notation, as found in the `:nth-child()` selector. /// The input is typically the arguments of a function, /// in which case the caller needs to check if the arguments’ parser is exhausted. -/// Return `Ok((A, B))`, or `Err(())` for a syntax error. -pub fn parse_nth<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(i32, i32), BasicParseError<'i>> { +/// Return `Ok((A, B))`, or an `Err(..)` for a syntax error. +pub fn parse_nth<'i>(input: &mut Parser<'i, '_>) -> Result<(i32, i32), BasicParseError<'i>> { match *input.next()? { Token::Number { int_value: Some(b), .. @@ -22,7 +22,7 @@ pub fn parse_nth<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(i32, i32), Basic unit, "n" => Ok(parse_b(input, a)?), "n-" => Ok(parse_signless_b(input, a, -1)?), - _ => match parse_n_dash_digits(&*unit) { + _ => match parse_n_dash_digits(unit) { Ok(b) => Ok((a, b)), Err(()) => { let unit = unit.clone(); @@ -40,8 +40,8 @@ pub fn parse_nth<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(i32, i32), Basic "n-" => Ok(parse_signless_b(input, 1, -1)?), "-n-" => Ok(parse_signless_b(input, -1, -1)?), _ => { - let (slice, a) = if value.starts_with("-") { - (&value[1..], -1) + let (slice, a) = if let Some(stripped) = value.strip_prefix('-') { + (stripped, -1) } else { (&**value, 1) }; @@ -81,7 +81,7 @@ pub fn parse_nth<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(i32, i32), Basic } } -fn parse_b<'i, 't>(input: &mut Parser<'i, 't>, a: i32) -> Result<(i32, i32), BasicParseError<'i>> { +fn parse_b<'i>(input: &mut Parser<'i, '_>, a: i32) -> Result<(i32, i32), BasicParseError<'i>> { let start = input.state(); match input.next() { Ok(&Token::Delim('+')) => parse_signless_b(input, a, 1), @@ -98,8 +98,8 @@ fn parse_b<'i, 't>(input: &mut Parser<'i, 't>, a: i32) -> Result<(i32, i32), Bas } } -fn parse_signless_b<'i, 't>( - input: &mut Parser<'i, 't>, +fn parse_signless_b<'i>( + input: &mut Parser<'i, '_>, a: i32, b_sign: i32, ) -> Result<(i32, i32), BasicParseError<'i>> { @@ -118,7 +118,7 @@ fn parse_n_dash_digits(string: &str) -> Result { let bytes = string.as_bytes(); if bytes.len() >= 3 && bytes[..2].eq_ignore_ascii_case(b"n-") - && bytes[2..].iter().all(|&c| matches!(c, b'0'..=b'9')) + && bytes[2..].iter().all(|&c| c.is_ascii_digit()) { Ok(parse_number_saturate(&string[1..]).unwrap()) // Include the minus sign } else { diff --git a/third_party/rust/cssparser/src/parser.rs b/third_party/rust/cssparser/src/parser.rs index dd7777a2d8..dd35fc50ed 100644 --- a/third_party/rust/cssparser/src/parser.rs +++ b/third_party/rust/cssparser/src/parser.rs @@ -53,7 +53,7 @@ impl ParserState { /// /// Would need to scan the whole {} block to find a semicolon, only for parsing getting restarted /// as a qualified rule later. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ParseUntilErrorBehavior { /// Consume until we see the relevant delimiter or the end of the stream. Consume, @@ -116,18 +116,30 @@ impl<'i, T> From> for ParseError<'i, T> { impl SourceLocation { /// Create a new BasicParseError at this location for an unexpected token #[inline] - pub fn new_basic_unexpected_token_error<'i>(self, token: Token<'i>) -> BasicParseError<'i> { + pub fn new_basic_unexpected_token_error(self, token: Token<'_>) -> BasicParseError<'_> { + self.new_basic_error(BasicParseErrorKind::UnexpectedToken(token)) + } + + /// Create a new BasicParseError at this location + #[inline] + pub fn new_basic_error(self, kind: BasicParseErrorKind<'_>) -> BasicParseError<'_> { BasicParseError { - kind: BasicParseErrorKind::UnexpectedToken(token), + kind, location: self, } } /// Create a new ParseError at this location for an unexpected token #[inline] - pub fn new_unexpected_token_error<'i, E>(self, token: Token<'i>) -> ParseError<'i, E> { + pub fn new_unexpected_token_error(self, token: Token<'_>) -> ParseError<'_, E> { + self.new_error(BasicParseErrorKind::UnexpectedToken(token)) + } + + /// Create a new basic ParseError at the current location + #[inline] + pub fn new_error(self, kind: BasicParseErrorKind<'_>) -> ParseError<'_, E> { ParseError { - kind: ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(token)), + kind: ParseErrorKind::Basic(kind), location: self, } } @@ -450,19 +462,13 @@ impl<'i: 't, 't> Parser<'i, 't> { /// Create a new BasicParseError at the current location #[inline] pub fn new_basic_error(&self, kind: BasicParseErrorKind<'i>) -> BasicParseError<'i> { - BasicParseError { - kind, - location: self.current_source_location(), - } + self.current_source_location().new_basic_error(kind) } /// Create a new basic ParseError at the current location #[inline] pub fn new_error(&self, kind: BasicParseErrorKind<'i>) -> ParseError<'i, E> { - ParseError { - kind: ParseErrorKind::Basic(kind), - location: self.current_source_location(), - } + self.current_source_location().new_error(kind) } /// Create a new custom BasicParseError at the current location @@ -606,6 +612,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// See the `Parser::parse_nested_block` method to parse the content of functions or blocks. /// /// This only returns a closing token when it is unmatched (and therefore an error). + #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Result<&Token<'i>, BasicParseError<'i>> { self.skip_whitespace(); self.next_including_whitespace_and_comments() @@ -652,9 +659,8 @@ impl<'i: 't, 't> Parser<'i, 't> { let token = if using_cached_token { let cached_token = self.input.cached_token.as_ref().unwrap(); self.input.tokenizer.reset(&cached_token.end_state); - match cached_token.token { - Token::Function(ref name) => self.input.tokenizer.see_function(name), - _ => {} + if let Token::Function(ref name) = cached_token.token { + self.input.tokenizer.see_function(name) } &cached_token.token } else { @@ -678,7 +684,7 @@ impl<'i: 't, 't> Parser<'i, 't> { } /// Have the given closure parse something, then check the the input is exhausted. - /// The result is overridden to `Err(())` if some input remains. + /// The result is overridden to an `Err(..)` if some input remains. /// /// This can help tell e.g. `color: green;` from `color: green 4px;` #[inline] @@ -699,7 +705,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// /// Successful results are accumulated in a vector. /// - /// This method returns `Err(())` the first time that a closure call does, + /// This method returns an`Err(..)` the first time that a closure call does, /// or if a closure call leaves some input before the next comma or the end /// of the input. #[inline] @@ -748,7 +754,7 @@ impl<'i: 't, 't> Parser<'i, 't> { match self.parse_until_before(Delimiter::Comma, &mut parse_one) { Ok(v) => values.push(v), Err(e) if !ignore_errors => return Err(e), - Err(_) => {}, + Err(_) => {} } match self.next() { Err(_) => return Ok(values), @@ -768,7 +774,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// The given closure is called with a "delimited" parser /// that stops at the end of the block or function (at the matching closing token). /// - /// The result is overridden to `Err(())` if the closure leaves some input before that point. + /// The result is overridden to an `Err(..)` if the closure leaves some input before that point. #[inline] pub fn parse_nested_block(&mut self, parse: F) -> Result> where @@ -784,7 +790,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// that stops before the first character at this block/function nesting level /// that matches the given set of delimiters, or at the end of the input. /// - /// The result is overridden to `Err(())` if the closure leaves some input before that point. + /// The result is overridden to an `Err(..)` if the closure leaves some input before that point. #[inline] pub fn parse_until_before( &mut self, @@ -835,7 +841,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// expect_ident, but clone the CowRcStr #[inline] pub fn expect_ident_cloned(&mut self) -> Result, BasicParseError<'i>> { - self.expect_ident().map(|s| s.clone()) + self.expect_ident().cloned() } /// Parse a whose unescaped value is an ASCII-insensitive match for the given value. @@ -860,7 +866,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// expect_string, but clone the CowRcStr #[inline] pub fn expect_string_cloned(&mut self) -> Result, BasicParseError<'i>> { - self.expect_string().map(|s| s.clone()) + self.expect_string().cloned() } /// Parse either a or a , and return the unescaped value. @@ -879,7 +885,7 @@ impl<'i: 't, 't> Parser<'i, 't> { Token::UnquotedUrl(ref value) => Ok(value.clone()), Token::Function(ref name) if name.eq_ignore_ascii_case("url") => { self.parse_nested_block(|input| { - input.expect_string().map_err(Into::into).map(|s| s.clone()) + input.expect_string().map_err(Into::into).cloned() }) .map_err(ParseError::<()>::basic) } @@ -894,7 +900,7 @@ impl<'i: 't, 't> Parser<'i, 't> { Token::QuotedString(ref value) => Ok(value.clone()), Token::Function(ref name) if name.eq_ignore_ascii_case("url") => { self.parse_nested_block(|input| { - input.expect_string().map_err(Into::into).map(|s| s.clone()) + input.expect_string().map_err(Into::into).cloned() }) .map_err(ParseError::<()>::basic) } diff --git a/third_party/rust/cssparser/src/rules_and_declarations.rs b/third_party/rust/cssparser/src/rules_and_declarations.rs index fb33a7d0cd..48da02b5cc 100644 --- a/third_party/rust/cssparser/src/rules_and_declarations.rs +++ b/third_party/rust/cssparser/src/rules_and_declarations.rs @@ -4,9 +4,7 @@ // https://drafts.csswg.org/css-syntax/#parsing -use super::{ - BasicParseError, BasicParseErrorKind, Delimiter, Delimiters, ParseError, Parser, Token, -}; +use super::{BasicParseError, BasicParseErrorKind, Delimiter, ParseError, Parser, Token}; use crate::cow_rc_str::CowRcStr; use crate::parser::{parse_nested_block, parse_until_after, ParseUntilErrorBehavior, ParserState}; @@ -14,7 +12,7 @@ use crate::parser::{parse_nested_block, parse_until_after, ParseUntilErrorBehavi /// /// Typical usage is `input.try_parse(parse_important).is_ok()` /// at the end of a `DeclarationParser::parse_value` implementation. -pub fn parse_important<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), BasicParseError<'i>> { +pub fn parse_important<'i>(input: &mut Parser<'i, '_>) -> Result<(), BasicParseError<'i>> { input.expect_delim('!')?; input.expect_ident_matching("important") } @@ -34,7 +32,7 @@ pub trait DeclarationParser<'i> { /// /// Return the finished representation for the declaration /// as returned by `DeclarationListParser::next`, - /// or `Err(())` to ignore the entire declaration as invalid. + /// or an `Err(..)` to ignore the entire declaration as invalid. /// /// Declaration name matching should be case-insensitive in the ASCII range. /// This can be done with `std::ascii::Ascii::eq_ignore_ascii_case`, @@ -78,7 +76,7 @@ pub trait AtRuleParser<'i> { /// Parse the prelude of an at-rule with the given `name`. /// /// Return the representation of the prelude and the type of at-rule, - /// or `Err(())` to ignore the entire at-rule as invalid. + /// or an `Err(..)` to ignore the entire at-rule as invalid. /// /// The prelude is the part after the at-keyword /// and before the `;` semicolon or `{ /* ... */ }` block. @@ -106,6 +104,7 @@ pub trait AtRuleParser<'i> { /// This is only called when `parse_prelude` returned `WithoutBlock`, and /// either the `;` semicolon indeed follows the prelude, or parser is at /// the end of the input. + #[allow(clippy::result_unit_err)] fn rule_without_block( &mut self, prelude: Self::Prelude, @@ -122,7 +121,7 @@ pub trait AtRuleParser<'i> { /// /// Return the finished representation of the at-rule /// as returned by `RuleListParser::next` or `DeclarationListParser::next`, - /// or `Err(())` to ignore the entire at-rule as invalid. + /// or an `Err(..)` to ignore the entire at-rule as invalid. /// /// This is only called when `parse_prelude` returned `WithBlock`, and a block /// was indeed found following the prelude. @@ -161,7 +160,7 @@ pub trait QualifiedRuleParser<'i> { /// Parse the prelude of a qualified rule. For style rules, this is as Selector list. /// /// Return the representation of the prelude, - /// or `Err(())` to ignore the entire at-rule as invalid. + /// or an `Err(..)` to ignore the entire at-rule as invalid. /// /// The prelude is the part before the `{ /* ... */ }` block. /// @@ -180,7 +179,7 @@ pub trait QualifiedRuleParser<'i> { /// /// Return the finished representation of the qualified rule /// as returned by `RuleListParser::next`, - /// or `Err(())` to ignore the entire at-rule as invalid. + /// or an `Err(..)` to ignore the entire at-rule as invalid. fn parse_block<'t>( &mut self, prelude: Self::Prelude, @@ -253,10 +252,10 @@ where self.input.skip_whitespace(); let start = self.input.state(); match self.input.next_including_whitespace_and_comments().ok()? { - Token::CloseCurlyBracket | - Token::WhiteSpace(..) | - Token::Semicolon | - Token::Comment(..) => continue, + Token::CloseCurlyBracket + | Token::WhiteSpace(..) + | Token::Semicolon + | Token::Comment(..) => continue, Token::AtKeyword(ref name) => { let name = name.clone(); return Some(parse_at_rule(&start, name, self.input, &mut *self.parser)); @@ -292,9 +291,9 @@ where &start, self.input, &mut *self.parser, - Delimiter::Semicolon | Delimiter::CurlyBracketBlock, + /* nested = */ true, ) { - return Some(Ok(qual)) + return Some(Ok(qual)); } } @@ -303,12 +302,8 @@ where token => { let result = if self.parser.parse_qualified() { self.input.reset(&start); - let delimiters = if self.parser.parse_declarations() { - Delimiter::Semicolon | Delimiter::CurlyBracketBlock - } else { - Delimiter::CurlyBracketBlock - }; - parse_qualified_rule(&start, self.input, &mut *self.parser, delimiters) + let nested = self.parser.parse_declarations(); + parse_qualified_rule(&start, self.input, &mut *self.parser, nested) } else { let token = token.clone(); self.input.parse_until_after(Delimiter::Semicolon, |_| { @@ -353,7 +348,7 @@ where } } -/// `RuleListParser` is an iterator that yields `Ok(_)` for a rule or `Err(())` for an invalid one. +/// `RuleListParser` is an iterator that yields `Ok(_)` for a rule or an `Err(..)` for an invalid one. impl<'i, 't, 'a, R, P, E: 'i> Iterator for StyleSheetParser<'i, 't, 'a, P> where P: QualifiedRuleParser<'i, QualifiedRule = R, Error = E> @@ -367,7 +362,7 @@ where let start = self.input.state(); let at_keyword = match self.input.next_byte()? { b'@' => match self.input.next_including_whitespace_and_comments() { - Ok(&Token::AtKeyword(ref name)) => Some(name.clone()), + Ok(Token::AtKeyword(name)) => Some(name.clone()), _ => { self.input.reset(&start); None @@ -397,7 +392,7 @@ where &start, self.input, &mut *self.parser, - Delimiter::CurlyBracketBlock, + /* nested = */ false, ); return Some(result.map_err(|e| (e, self.input.slice_from(start.position())))); } @@ -450,7 +445,7 @@ where if let Some(name) = at_keyword { parse_at_rule(&start, name, input, parser).map_err(|e| e.0) } else { - parse_qualified_rule(&start, input, parser, Delimiter::CurlyBracketBlock) + parse_qualified_rule(&start, input, parser, /* nested = */ false) } }) } @@ -490,18 +485,54 @@ where } } +// If the first two non- values of rule’s prelude are an whose +// value starts with "--" followed by a , then... +fn looks_like_a_custom_property(input: &mut Parser) -> bool { + let ident = match input.expect_ident() { + Ok(i) => i, + Err(..) => return false, + }; + ident.starts_with("--") && input.expect_colon().is_ok() +} + +// https://drafts.csswg.org/css-syntax/#consume-a-qualified-rule fn parse_qualified_rule<'i, 't, P, E>( start: &ParserState, input: &mut Parser<'i, 't>, parser: &mut P, - delimiters: Delimiters, + nested: bool, ) -> Result<

>::QualifiedRule, ParseError<'i, E>> where P: QualifiedRuleParser<'i, Error = E>, { - let prelude = input.parse_until_before(delimiters, |input| parser.parse_prelude(input)); + input.skip_whitespace(); + let prelude = { + let state = input.state(); + if looks_like_a_custom_property(input) { + // If nested is true, consume the remnants of a bad declaration from input, with + // nested set to true, and return nothing. + // If nested is false, consume a block from input, and return nothing. + let delimiters = if nested { + Delimiter::Semicolon + } else { + Delimiter::CurlyBracketBlock + }; + let _: Result<(), ParseError<()>> = input.parse_until_after(delimiters, |_| Ok(())); + return Err(state + .source_location() + .new_error(BasicParseErrorKind::QualifiedRuleInvalid)); + } + let delimiters = if nested { + Delimiter::Semicolon | Delimiter::CurlyBracketBlock + } else { + Delimiter::CurlyBracketBlock + }; + input.reset(&state); + input.parse_until_before(delimiters, |input| parser.parse_prelude(input)) + }; + input.expect_curly_bracket_block()?; // Do this here so that we consume the `{` even if the prelude is `Err`. let prelude = prelude?; - parse_nested_block(input, |input| parser.parse_block(prelude, &start, input)) + parse_nested_block(input, |input| parser.parse_block(prelude, start, input)) } diff --git a/third_party/rust/cssparser/src/serializer.rs b/third_party/rust/cssparser/src/serializer.rs index 09c224022d..3c6e31cb84 100644 --- a/third_party/rust/cssparser/src/serializer.rs +++ b/third_party/rust/cssparser/src/serializer.rs @@ -3,8 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use crate::match_byte; -use dtoa_short::{self, Notation}; -use itoa; +use dtoa_short::Notation; use std::fmt::{self, Write}; use std::str; @@ -49,10 +48,9 @@ where dtoa_short::write(dest, value)? }; - if int_value.is_none() && value.fract() == 0. { - if !notation.decimal_point && !notation.scientific { - dest.write_str(".0")?; - } + if int_value.is_none() && value.fract() == 0. && !notation.decimal_point && !notation.scientific + { + dest.write_str(".0")?; } Ok(()) } @@ -63,10 +61,10 @@ impl<'a> ToCss for Token<'a> { W: fmt::Write, { match *self { - Token::Ident(ref value) => serialize_identifier(&**value, dest)?, + Token::Ident(ref value) => serialize_identifier(value, dest)?, Token::AtKeyword(ref value) => { dest.write_str("@")?; - serialize_identifier(&**value, dest)?; + serialize_identifier(value, dest)?; } Token::Hash(ref value) => { dest.write_str("#")?; @@ -74,12 +72,12 @@ impl<'a> ToCss for Token<'a> { } Token::IDHash(ref value) => { dest.write_str("#")?; - serialize_identifier(&**value, dest)?; + serialize_identifier(value, dest)?; } - Token::QuotedString(ref value) => serialize_string(&**value, dest)?, + Token::QuotedString(ref value) => serialize_string(value, dest)?, Token::UnquotedUrl(ref value) => { dest.write_str("url(")?; - serialize_unquoted_url(&**value, dest)?; + serialize_unquoted_url(value, dest)?; dest.write_str(")")?; } Token::Delim(value) => dest.write_char(value)?, @@ -134,7 +132,7 @@ impl<'a> ToCss for Token<'a> { Token::CDC => dest.write_str("-->")?, Token::Function(ref name) => { - serialize_identifier(&**name, dest)?; + serialize_identifier(name, dest)?; dest.write_str("(")?; } Token::ParenthesisBlock => dest.write_str("(")?, @@ -167,7 +165,7 @@ fn hex_escape(ascii_byte: u8, dest: &mut W) -> fmt::Result where W: fmt::Write, { - static HEX_DIGITS: &'static [u8; 16] = b"0123456789abcdef"; + static HEX_DIGITS: &[u8; 16] = b"0123456789abcdef"; let b3; let b4; let bytes = if ascii_byte > 0x0F { @@ -179,7 +177,7 @@ where b3 = [b'\\', HEX_DIGITS[ascii_byte as usize], b' ']; &b3[..] }; - dest.write_str(unsafe { str::from_utf8_unchecked(&bytes) }) + dest.write_str(unsafe { str::from_utf8_unchecked(bytes) }) } fn char_escape(ascii_byte: u8, dest: &mut W) -> fmt::Result @@ -199,9 +197,9 @@ where return Ok(()); } - if value.starts_with("--") { + if let Some(value) = value.strip_prefix("--") { dest.write_str("--")?; - serialize_name(&value[2..], dest) + serialize_name(value, dest) } else if value == "-" { dest.write_str("\\-") } else { @@ -240,7 +238,7 @@ where dest.write_str(&value[chunk_start..i])?; if let Some(escaped) = escaped { dest.write_str(escaped)?; - } else if (b >= b'\x01' && b <= b'\x1F') || b == b'\x7F' { + } else if (b'\x01'..=b'\x1F').contains(&b) || b == b'\x7F' { hex_escape(b, dest)?; } else { char_escape(b, dest)?; @@ -340,7 +338,7 @@ where macro_rules! impl_tocss_for_int { ($T: ty) => { - impl<'a> ToCss for $T { + impl ToCss for $T { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write, @@ -363,7 +361,7 @@ impl_tocss_for_int!(u64); macro_rules! impl_tocss_for_float { ($T: ty) => { - impl<'a> ToCss for $T { + impl ToCss for $T { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write, diff --git a/third_party/rust/cssparser/src/tests.rs b/third_party/rust/cssparser/src/tests.rs index f9dea19325..7389664de4 100644 --- a/third_party/rust/cssparser/src/tests.rs +++ b/third_party/rust/cssparser/src/tests.rs @@ -5,8 +5,7 @@ #[cfg(feature = "bench")] extern crate test; -use encoding_rs; -use serde_json::{self, json, Map, Value}; +use serde_json::{json, Map, Value}; #[cfg(feature = "bench")] use self::test::Bencher; @@ -25,25 +24,23 @@ macro_rules! JArray { } fn almost_equals(a: &Value, b: &Value) -> bool { - match (a, b) { - (&Value::Number(ref a), &Value::Number(ref b)) => { + let var_name = match (a, b) { + (Value::Number(a), Value::Number(b)) => { let a = a.as_f64().unwrap(); let b = b.as_f64().unwrap(); (a - b).abs() <= a.abs() * 1e-6 } (&Value::Bool(a), &Value::Bool(b)) => a == b, - (&Value::String(ref a), &Value::String(ref b)) => a == b, - (&Value::Array(ref a), &Value::Array(ref b)) => { - a.len() == b.len() - && a.iter() - .zip(b.iter()) - .all(|(ref a, ref b)| almost_equals(*a, *b)) + (Value::String(a), Value::String(b)) => a == b, + (Value::Array(a), Value::Array(b)) => { + a.len() == b.len() && a.iter().zip(b.iter()).all(|(a, b)| almost_equals(a, b)) } (&Value::Object(_), &Value::Object(_)) => panic!("Not implemented"), (&Value::Null, &Value::Null) => true, _ => false, - } + }; + var_name } fn normalize(json: &mut Value) { @@ -77,7 +74,7 @@ fn assert_json_eq(results: Value, mut expected: Value, message: &str) { } } -fn run_raw_json_tests ()>(json_data: &str, run: F) { +fn run_raw_json_tests(json_data: &str, run: F) { let items = match serde_json::from_str(json_data) { Ok(Value::Array(items)) => items, other => panic!("Invalid JSON: {:?}", other), @@ -242,7 +239,7 @@ fn stylesheet_from_bytes() { fn get_string<'a>(map: &'a Map, key: &str) -> Option<&'a str> { match map.get(key) { - Some(&Value::String(ref s)) => Some(s), + Some(Value::String(s)) => Some(s), Some(&Value::Null) => None, None => None, _ => panic!("Unexpected JSON"), @@ -393,7 +390,7 @@ fn unicode_range() { if input.is_exhausted() { Ok(result) } else { - while let Ok(_) = input.next() {} + while input.next().is_ok() {} Ok(None) } }); @@ -433,11 +430,9 @@ fn serializer(preserve_comments: bool) { preserve_comments: bool, ) { while let Ok(token) = if preserve_comments { - input - .next_including_whitespace_and_comments() - .map(|t| t.clone()) + input.next_including_whitespace_and_comments().cloned() } else { - input.next_including_whitespace().map(|t| t.clone()) + input.next_including_whitespace().cloned() } { let token_type = token.serialization_type(); if !preserve_comments && previous_token.needs_separator_when_before(token_type) @@ -593,8 +588,6 @@ fn line_numbers() { #[test] fn overflow() { - use std::iter::repeat; - let css = r" 2147483646 2147483647 @@ -619,7 +612,7 @@ fn overflow() { -3.402824e+38 " - .replace("{309 zeros}", &repeat('0').take(309).collect::()); + .replace("{309 zeros}", &"0".repeat(309)); let mut input = ParserInput::new(&css); let mut input = Parser::new(&mut input); @@ -637,15 +630,13 @@ fn overflow() { assert_eq!(input.expect_integer(), Ok(-2147483648)); assert_eq!(input.expect_integer(), Ok(-2147483648)); - assert_eq!(input.expect_number(), Ok(3.30282347e+38)); + assert_eq!(input.expect_number(), Ok(3.302_823_5e38)); assert_eq!(input.expect_number(), Ok(f32::MAX)); assert_eq!(input.expect_number(), Ok(f32::INFINITY)); - assert!(f32::MAX != f32::INFINITY); - assert_eq!(input.expect_number(), Ok(-3.30282347e+38)); + assert_eq!(input.expect_number(), Ok(-3.302_823_5e38)); assert_eq!(input.expect_number(), Ok(f32::MIN)); assert_eq!(input.expect_number(), Ok(f32::NEG_INFINITY)); - assert!(f32::MIN != f32::NEG_INFINITY); } #[test] @@ -784,7 +775,7 @@ where impl<'a> ToJson for CowRcStr<'a> { fn to_json(&self) -> Value { - let s: &str = &*self; + let s: &str = self; s.to_json() } } @@ -847,7 +838,7 @@ fn no_stack_overflow_multiple_nested_blocks() { } let mut input = ParserInput::new(&input); let mut input = Parser::new(&mut input); - while let Ok(..) = input.next() {} + while input.next().is_ok() {} } impl<'i> DeclarationParser<'i> for JsonParser { @@ -863,18 +854,16 @@ impl<'i> DeclarationParser<'i> for JsonParser { let mut important = false; loop { let start = input.state(); - if let Ok(mut token) = input.next_including_whitespace().map(|t| t.clone()) { + if let Ok(mut token) = input.next_including_whitespace().cloned() { // Hack to deal with css-parsing-tests assuming that // `!important` in the middle of a declaration value is OK. // This can never happen per spec // (even CSS Variables forbid top-level `!`) if token == Token::Delim('!') { input.reset(&start); - if parse_important(input).is_ok() { - if input.is_exhausted() { - important = true; - break; - } + if parse_important(input).is_ok() && input.is_exhausted() { + important = true; + break; } input.reset(&start); token = input.next_including_whitespace().unwrap().clone(); @@ -905,7 +894,7 @@ impl<'i> AtRuleParser<'i> for JsonParser { ]; match_ignore_ascii_case! { &*name, "charset" => { - Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone()).into())) + Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone()))) }, _ => Ok(prelude), } @@ -968,7 +957,7 @@ impl<'i> RuleBodyItemParser<'i, Value, ()> for JsonParser { fn component_values_to_json(input: &mut Parser) -> Vec { let mut values = vec![]; - while let Ok(token) = input.next_including_whitespace().map(|t| t.clone()) { + while let Ok(token) = input.next_including_whitespace().cloned() { values.push(one_component_value_to_json(token, input)); } values @@ -978,9 +967,9 @@ fn one_component_value_to_json(token: Token, input: &mut Parser) -> Value { fn numeric(value: f32, int_value: Option, has_sign: bool) -> Vec { vec![ Token::Number { - value: value, - int_value: int_value, - has_sign: has_sign, + value, + int_value, + has_sign, } .to_css_string() .to_json(), @@ -1137,7 +1126,7 @@ fn parse_until_before_stops_at_delimiter_or_end_of_input() { let ox = ix.next(); let oy = iy.next(); assert_eq!(ox, oy); - if let Err(_) = ox { + if ox.is_err() { break; } } @@ -1223,7 +1212,7 @@ fn parse_sourcemapping_comments() { for test in tests { let mut input = ParserInput::new(test.0); let mut parser = Parser::new(&mut input); - while let Ok(_) = parser.next_including_whitespace() {} + while parser.next_including_whitespace().is_ok() {} assert_eq!(parser.current_source_map_url(), test.1); } } @@ -1247,7 +1236,7 @@ fn parse_sourceurl_comments() { for test in tests { let mut input = ParserInput::new(test.0); let mut parser = Parser::new(&mut input); - while let Ok(_) = parser.next_including_whitespace() {} + while parser.next_including_whitespace().is_ok() {} assert_eq!(parser.current_source_url(), test.1); } } @@ -1321,7 +1310,8 @@ fn utf16_columns() { break; } Err(_) => { - assert!(false); + // should this be an explicit panic instead? + unreachable!(); } Ok(_) => {} }; diff --git a/third_party/rust/cssparser/src/tokenizer.rs b/third_party/rust/cssparser/src/tokenizer.rs index a3b700632d..ea173a5e45 100644 --- a/third_party/rust/cssparser/src/tokenizer.rs +++ b/third_party/rust/cssparser/src/tokenizer.rs @@ -255,10 +255,10 @@ impl<'a> Tokenizer<'a> { #[inline] pub fn see_function(&mut self, name: &str) { - if self.var_or_env_functions == SeenStatus::LookingForThem { - if name.eq_ignore_ascii_case("var") || name.eq_ignore_ascii_case("env") { - self.var_or_env_functions = SeenStatus::SeenAtLeastOne; - } + if self.var_or_env_functions == SeenStatus::LookingForThem + && (name.eq_ignore_ascii_case("var") || name.eq_ignore_ascii_case("env")) + { + self.var_or_env_functions = SeenStatus::SeenAtLeastOne; } } @@ -322,10 +322,12 @@ impl<'a> Tokenizer<'a> { pub fn current_source_line(&self) -> &'a str { let current = self.position(); - let start = self.slice(SourcePosition(0)..current) + let start = self + .slice(SourcePosition(0)..current) .rfind(|c| matches!(c, '\r' | '\n' | '\x0C')) .map_or(0, |start| start + 1); - let end = self.slice(current..SourcePosition(self.input.len())) + let end = self + .slice(current..SourcePosition(self.input.len())) .find(|c| matches!(c, '\r' | '\n' | '\x0C')) .map_or(self.input.len(), |end| current.0 + end); self.slice(SourcePosition(start)..SourcePosition(end)) @@ -424,7 +426,10 @@ impl<'a> Tokenizer<'a> { #[inline] fn next_char(&self) -> char { - unsafe { self.input.get_unchecked(self.position().0..) }.chars().next().unwrap() + unsafe { self.input.get_unchecked(self.position().0..) } + .chars() + .next() + .unwrap() } // Given that a newline has been seen, advance over the newline @@ -561,11 +566,11 @@ fn next_token<'a>(tokenizer: &mut Tokenizer<'a>) -> Result, ()> { b'#' => { tokenizer.advance(1); if is_ident_start(tokenizer) { IDHash(consume_name(tokenizer)) } - else if !tokenizer.is_eof() && match tokenizer.next_byte_unchecked() { + else if !tokenizer.is_eof() && + matches!(tokenizer.next_byte_unchecked(), b'0'..=b'9' | b'-') { // Any other valid case here already resulted in IDHash. - b'0'..=b'9' | b'-' => true, - _ => false, - } { Hash(consume_name(tokenizer)) } + Hash(consume_name(tokenizer)) + } else { Delim('#') } }, b'$' => { @@ -582,11 +587,11 @@ fn next_token<'a>(tokenizer: &mut Tokenizer<'a>) -> Result, ()> { b'+' => { if ( tokenizer.has_at_least(1) - && matches!(tokenizer.byte_at(1), b'0'..=b'9') + && tokenizer.byte_at(1).is_ascii_digit() ) || ( tokenizer.has_at_least(2) && tokenizer.byte_at(1) == b'.' - && matches!(tokenizer.byte_at(2), b'0'..=b'9') + && tokenizer.byte_at(2).is_ascii_digit() ) { consume_numeric(tokenizer) } else { @@ -598,11 +603,11 @@ fn next_token<'a>(tokenizer: &mut Tokenizer<'a>) -> Result, ()> { b'-' => { if ( tokenizer.has_at_least(1) - && matches!(tokenizer.byte_at(1), b'0'..=b'9') + && tokenizer.byte_at(1).is_ascii_digit() ) || ( tokenizer.has_at_least(2) && tokenizer.byte_at(1) == b'.' - && matches!(tokenizer.byte_at(2), b'0'..=b'9') + && tokenizer.byte_at(2).is_ascii_digit() ) { consume_numeric(tokenizer) } else if tokenizer.starts_with(b"-->") { @@ -617,8 +622,7 @@ fn next_token<'a>(tokenizer: &mut Tokenizer<'a>) -> Result, ()> { }, b'.' => { if tokenizer.has_at_least(1) - && matches!(tokenizer.byte_at(1), b'0'..=b'9' - ) { + && tokenizer.byte_at(1).is_ascii_digit() { consume_numeric(tokenizer) } else { tokenizer.advance(1); @@ -1001,7 +1005,7 @@ fn byte_to_hex_digit(b: u8) -> Option { } fn byte_to_decimal_digit(b: u8) -> Option { - if b >= b'0' && b <= b'9' { + if b.is_ascii_digit() { Some((b - b'0') as u32) } else { None @@ -1038,7 +1042,7 @@ fn consume_numeric<'a>(tokenizer: &mut Tokenizer<'a>) -> Token<'a> { let mut fractional_part: f64 = 0.; if tokenizer.has_at_least(1) && tokenizer.next_byte_unchecked() == b'.' - && matches!(tokenizer.byte_at(1), b'0'..=b'9') + && tokenizer.byte_at(1).is_ascii_digit() { is_integer = false; tokenizer.advance(1); // Consume '.' @@ -1055,32 +1059,32 @@ fn consume_numeric<'a>(tokenizer: &mut Tokenizer<'a>) -> Token<'a> { let mut value = sign * (integral_part + fractional_part); - if tokenizer.has_at_least(1) && matches!(tokenizer.next_byte_unchecked(), b'e' | b'E') { - if matches!(tokenizer.byte_at(1), b'0'..=b'9') + if tokenizer.has_at_least(1) + && matches!(tokenizer.next_byte_unchecked(), b'e' | b'E') + && (tokenizer.byte_at(1).is_ascii_digit() || (tokenizer.has_at_least(2) && matches!(tokenizer.byte_at(1), b'+' | b'-') - && matches!(tokenizer.byte_at(2), b'0'..=b'9')) - { - is_integer = false; + && tokenizer.byte_at(2).is_ascii_digit())) + { + is_integer = false; + tokenizer.advance(1); + let (has_sign, sign) = match tokenizer.next_byte_unchecked() { + b'-' => (true, -1.), + b'+' => (true, 1.), + _ => (false, 1.), + }; + if has_sign { tokenizer.advance(1); - let (has_sign, sign) = match tokenizer.next_byte_unchecked() { - b'-' => (true, -1.), - b'+' => (true, 1.), - _ => (false, 1.), - }; - if has_sign { - tokenizer.advance(1); - } - let mut exponent: f64 = 0.; - while let Some(digit) = byte_to_decimal_digit(tokenizer.next_byte_unchecked()) { - exponent = exponent * 10. + digit as f64; - tokenizer.advance(1); - if tokenizer.is_eof() { - break; - } + } + let mut exponent: f64 = 0.; + while let Some(digit) = byte_to_decimal_digit(tokenizer.next_byte_unchecked()) { + exponent = exponent * 10. + digit as f64; + tokenizer.advance(1); + if tokenizer.is_eof() { + break; } - value *= f64::powf(10., sign * exponent); } + value *= f64::powf(10., sign * exponent); } let int_value = if is_integer { @@ -1339,7 +1343,7 @@ fn consume_unquoted_url<'a>(tokenizer: &mut Tokenizer<'a>) -> Result, } // (value, number of digits up to 6) -fn consume_hex_digits<'a>(tokenizer: &mut Tokenizer<'a>) -> (u32, u32) { +fn consume_hex_digits(tokenizer: &mut Tokenizer<'_>) -> (u32, u32) { let mut value = 0; let mut digits = 0; while digits < 6 && !tokenizer.is_eof() { diff --git a/third_party/rust/cssparser/src/unicode_range.rs b/third_party/rust/cssparser/src/unicode_range.rs index b0a2017cbf..ce6bb3b5e7 100644 --- a/third_party/rust/cssparser/src/unicode_range.rs +++ b/third_party/rust/cssparser/src/unicode_range.rs @@ -24,7 +24,7 @@ pub struct UnicodeRange { impl UnicodeRange { /// https://drafts.csswg.org/css-syntax/#urange-syntax - pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { + pub fn parse<'i>(input: &mut Parser<'i, '_>) -> Result> { // = // u '+' '?'* | // u '?'* | @@ -57,7 +57,7 @@ impl UnicodeRange { } } -fn parse_tokens<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), BasicParseError<'i>> { +fn parse_tokens<'i>(input: &mut Parser<'i, '_>) -> Result<(), BasicParseError<'i>> { match input.next_including_whitespace()?.clone() { Token::Delim('+') => { match *input.next_including_whitespace()? { @@ -123,15 +123,13 @@ fn parse_concatenated(text: &[u8]) -> Result { start: first_hex_value, end: first_hex_value, }); - } else { - if let Some((&b'-', mut text)) = text.split_first() { - let (second_hex_value, hex_digit_count) = consume_hex(&mut text); - if hex_digit_count > 0 && hex_digit_count <= 6 && text.is_empty() { - return Ok(UnicodeRange { - start: first_hex_value, - end: second_hex_value, - }); - } + } else if let Some((&b'-', mut text)) = text.split_first() { + let (second_hex_value, hex_digit_count) = consume_hex(&mut text); + if hex_digit_count > 0 && hex_digit_count <= 6 && text.is_empty() { + return Ok(UnicodeRange { + start: first_hex_value, + end: second_hex_value, + }); } } Err(()) diff --git a/third_party/rust/cubeb-coreaudio/.cargo-checksum.json b/third_party/rust/cubeb-coreaudio/.cargo-checksum.json index fa6f229b4c..b0c27f353e 100644 --- a/third_party/rust/cubeb-coreaudio/.cargo-checksum.json +++ b/third_party/rust/cubeb-coreaudio/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"ac8f4cf5b7631b5c738d50c0cf78113bd395940b9e76593904bbaf2d02d16a70",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"0fb7c56c04e05dacffa5176f885cb8019ee6ab7f885479be501aba0eaac2148f","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"0007782a05a5330f739ad789c19c82562c82e32386b0447000fc72c0d48405bc","build-audiounit-rust-in-cubeb.sh":"d228a05985dcd02ec1ecac66a2b64dae5a530804a25a7054ccc95905aedfb7ef","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"90c2542fa3ff8a35fed894fae3a1aa0157117b7f0e28df14b8e6f7b1f1f43797","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"bae82f66dd47a060b6fdcc238520084aec1079d5b1b1d66d103baa1ffaa8773d","src/backend/aggregate_device.rs":"db7d644358090b1d65ff2d53ad854369790ae4ad7dfa12b79888c0002c1b4950","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"a7622feaa41db1cd76fd35a85a022e44f4894e396a104a59008d5b8757d2ab4e","src/backend/mixer.rs":"ed299d3954e2a823060c870a8244673a7d4bca530830cb66b964d047a80ee3af","src/backend/mod.rs":"e52b79a17dbf7faa072ec87cc3e4201b907772104c3be777498275733b9c334e","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"770cf90f32b5ab2203476031c1fbc8379b713baa97bec36f7fd0d77fef1efd60","src/backend/tests/api.rs":"d72d7c0de8d12e880966948be4686bcf8c789f0ef19cb435c242fd72f2d252f9","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"babf50326fb38db24fe80f24f546e1b6ad04319ae8835bb372d893fc9b3038a2","src/backend/tests/device_property.rs":"73c25f579a995e8a59c9b7d391813afb75f739b5e2f825480cba04499a1d46e8","src/backend/tests/interfaces.rs":"654333cd6d6023e72ba392d98872d33bc55f8f052205a9f701aec72069449e24","src/backend/tests/manual.rs":"e550cc8bb7619bb80b68e49bf7f475c029e0f1b34323d1d30edcbe322cf4efc7","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"a7ebd579339c40ca64c0757cc9da6baec641e670f226e1b2ec5049894700bd7a","src/backend/tests/tone.rs":"b028c67777b6453a26190b6a49785dfe28556adcbe179cb10862ce0d47ee8509","src/backend/tests/utils.rs":"80d7e4ebc06b23c63a4d2867e0c80e0bfe05449fa55edd21e785ed2c089bf7d5","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null} \ No newline at end of file +{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"ac8f4cf5b7631b5c738d50c0cf78113bd395940b9e76593904bbaf2d02d16a70",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"a16b883e4fb41bdbbe5f68158040f181aeeffb4573ab0d493e9452f7c6f00541","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"0007782a05a5330f739ad789c19c82562c82e32386b0447000fc72c0d48405bc","build-audiounit-rust-in-cubeb.sh":"d228a05985dcd02ec1ecac66a2b64dae5a530804a25a7054ccc95905aedfb7ef","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"90c2542fa3ff8a35fed894fae3a1aa0157117b7f0e28df14b8e6f7b1f1f43797","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"bae82f66dd47a060b6fdcc238520084aec1079d5b1b1d66d103baa1ffaa8773d","src/backend/aggregate_device.rs":"db7d644358090b1d65ff2d53ad854369790ae4ad7dfa12b79888c0002c1b4950","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"a7622feaa41db1cd76fd35a85a022e44f4894e396a104a59008d5b8757d2ab4e","src/backend/mixer.rs":"c4d09291598cbffb2217b551770ec590f34b6dd6b461dd99b019d5bb70f0eef3","src/backend/mod.rs":"d75e116a58d63c6a7cb281d160066f48c8c449702dad58c762ad50d9512d7bd3","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"770cf90f32b5ab2203476031c1fbc8379b713baa97bec36f7fd0d77fef1efd60","src/backend/tests/api.rs":"773e88b506efccf0eacbf408d34dea1fb2c5a8500e7fe8a494a97f15f1ea41fc","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"babf50326fb38db24fe80f24f546e1b6ad04319ae8835bb372d893fc9b3038a2","src/backend/tests/device_property.rs":"73c25f579a995e8a59c9b7d391813afb75f739b5e2f825480cba04499a1d46e8","src/backend/tests/interfaces.rs":"654333cd6d6023e72ba392d98872d33bc55f8f052205a9f701aec72069449e24","src/backend/tests/manual.rs":"e550cc8bb7619bb80b68e49bf7f475c029e0f1b34323d1d30edcbe322cf4efc7","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"a7ebd579339c40ca64c0757cc9da6baec641e670f226e1b2ec5049894700bd7a","src/backend/tests/tone.rs":"b028c67777b6453a26190b6a49785dfe28556adcbe179cb10862ce0d47ee8509","src/backend/tests/utils.rs":"80d7e4ebc06b23c63a4d2867e0c80e0bfe05449fa55edd21e785ed2c089bf7d5","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cubeb-coreaudio/Cargo.toml b/third_party/rust/cubeb-coreaudio/Cargo.toml index 8a73548f57..02fb9832ac 100644 --- a/third_party/rust/cubeb-coreaudio/Cargo.toml +++ b/third_party/rust/cubeb-coreaudio/Cargo.toml @@ -27,7 +27,7 @@ crate-type = [ [dependencies] atomic = "0.4" -audio-mixer = "0.1" +audio-mixer = "0.2" bitflags = "2" cubeb-backend = "0.12.0" float-cmp = "0.6" @@ -43,3 +43,6 @@ path = "coreaudio-sys-utils" [dev-dependencies] itertools = "0.11" + +[features] +audio-dump = [] diff --git a/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs b/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs index a4f63926b1..8b80738736 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs @@ -5,7 +5,7 @@ use std::os::raw::{c_int, c_void}; extern crate audio_mixer; pub use self::audio_mixer::Channel; -const CHANNEL_OERDER: [audio_mixer::Channel; audio_mixer::Channel::count()] = [ +const CHANNEL_ORDER: [audio_mixer::Channel; audio_mixer::Channel::count()] = [ audio_mixer::Channel::FrontLeft, audio_mixer::Channel::FrontRight, audio_mixer::Channel::FrontCenter, @@ -25,6 +25,7 @@ const CHANNEL_OERDER: [audio_mixer::Channel; audio_mixer::Channel::count()] = [ audio_mixer::Channel::TopBackCenter, audio_mixer::Channel::TopBackRight, audio_mixer::Channel::Silence, + audio_mixer::Channel::Discrete, ]; pub fn get_channel_order(channel_layout: ChannelLayout) -> Vec { @@ -33,7 +34,7 @@ pub fn get_channel_order(channel_layout: ChannelLayout) -> Vec>= 1; channel_index += 1; @@ -44,14 +45,14 @@ pub fn get_channel_order(channel_layout: ChannelLayout) -> Vec Vec { assert_ne!(channel_count, 0); let mut channels = Vec::with_capacity(channel_count); - for channel in CHANNEL_OERDER.iter().take(channel_count) { + for channel in CHANNEL_ORDER.iter().take(channel_count) { channels.push(*channel); } - if channel_count > CHANNEL_OERDER.len() { + if channel_count > CHANNEL_ORDER.len() { channels.extend(vec![ audio_mixer::Channel::Silence; - channel_count - CHANNEL_OERDER.len() + channel_count - CHANNEL_ORDER.len() ]); } @@ -214,7 +215,7 @@ impl Mixer { if output_channels.is_empty() || out_channel_count != output_channels.len() || all_silence == output_channels - || Self::non_silent_duplicate_channel_present(&output_channels) + || Self::duplicate_channel_present(&output_channels) { cubeb_log!("Use invalid layout. Apply default layout instead"); output_channels = get_default_channel_order(out_channel_count); @@ -261,10 +262,10 @@ impl Mixer { ) } - fn non_silent_duplicate_channel_present(channels: &[audio_mixer::Channel]) -> bool { + fn duplicate_channel_present(channels: &[audio_mixer::Channel]) -> bool { let mut bitmap: u32 = 0; for channel in channels { - if channel != &Channel::Silence { + if channel != &Channel::Silence && channel != &Channel::Discrete { if (bitmap & channel.bitmask()) != 0 { return true; } @@ -456,14 +457,14 @@ fn test_get_channel_order() { #[test] fn test_get_default_channel_order() { - for len in 1..CHANNEL_OERDER.len() + 10 { + for len in 1..CHANNEL_ORDER.len() + 10 { let channels = get_default_channel_order(len); - if len <= CHANNEL_OERDER.len() { - assert_eq!(channels, &CHANNEL_OERDER[..len]); + if len <= CHANNEL_ORDER.len() { + assert_eq!(channels, &CHANNEL_ORDER[..len]); } else { - let silences = vec![audio_mixer::Channel::Silence; len - CHANNEL_OERDER.len()]; - assert_eq!(channels[..CHANNEL_OERDER.len()], CHANNEL_OERDER); - assert_eq!(&channels[CHANNEL_OERDER.len()..], silences.as_slice()); + let silences = vec![audio_mixer::Channel::Silence; len - CHANNEL_ORDER.len()]; + assert_eq!(channels[..CHANNEL_ORDER.len()], CHANNEL_ORDER); + assert_eq!(&channels[CHANNEL_ORDER.len()..], silences.as_slice()); } } } @@ -478,7 +479,7 @@ fn test_non_silent_duplicate_channels() { Channel::Silence, Channel::FrontRight, ]; - assert!(Mixer::non_silent_duplicate_channel_present(&duplicate)); + assert!(Mixer::duplicate_channel_present(&duplicate)); let non_duplicate = [ Channel::FrontLeft, @@ -488,5 +489,25 @@ fn test_non_silent_duplicate_channels() { Channel::Silence, Channel::Silence, ]; - assert!(!Mixer::non_silent_duplicate_channel_present(&non_duplicate)); + assert!(!Mixer::duplicate_channel_present(&non_duplicate)); + + let duplicate = [ + Channel::FrontLeft, + Channel::Discrete, + Channel::FrontRight, + Channel::FrontCenter, + Channel::Discrete, + Channel::FrontRight, + ]; + assert!(Mixer::duplicate_channel_present(&duplicate)); + + let non_duplicate = [ + Channel::FrontLeft, + Channel::Discrete, + Channel::FrontRight, + Channel::FrontCenter, + Channel::Discrete, + Channel::Discrete, + ]; + assert!(!Mixer::duplicate_channel_present(&non_duplicate)); } diff --git a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs index e6be028a2e..855c119b63 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs @@ -33,6 +33,8 @@ use self::mixer::*; use self::resampler::*; use self::utils::*; use backend::ringbuf::RingBuffer; +#[cfg(feature = "audio_dump")] +use cubeb_backend::ffi::cubeb_audio_dump_stream_t; use cubeb_backend::{ ffi, ChannelLayout, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, Error, InputProcessingParams, Ops, Result, SampleFormat, State, Stream, StreamOps, @@ -114,6 +116,16 @@ lazy_static! { }; } +#[cfg(feature = "audio_dump")] +fn dump_audio(stream: cubeb_audio_dump_stream_t, audio_samples: *mut c_void, count: u32) { + unsafe { + let rv = ffi::cubeb_audio_dump_write(stream, audio_samples, count); + if rv != 0 { + cubeb_alog!("Error dumping audio data"); + } + } +} + fn make_sized_audio_channel_layout(sz: usize) -> AutoRelease { assert!(sz >= mem::size_of::()); assert_eq!( @@ -194,7 +206,12 @@ impl From for mixer::Channel { sys::kAudioChannelLabel_TopBackLeft => mixer::Channel::TopBackLeft, sys::kAudioChannelLabel_TopBackCenter => mixer::Channel::TopBackCenter, sys::kAudioChannelLabel_TopBackRight => mixer::Channel::TopBackRight, - _ => mixer::Channel::Silence, + sys::kAudioChannelLabel_Unknown => mixer::Channel::Discrete, + sys::kAudioChannelLabel_Unused => mixer::Channel::Silence, + v => { + eprintln!("Warning: channel label value {} isn't handled", v); + mixer::Channel::Silence + } } } } @@ -551,6 +568,16 @@ extern "C" fn audiounit_input_callback( ErrorHandle::Reinit } else { assert_eq!(status, NO_ERR); + + #[cfg(feature = "audio_dump")] + { + dump_audio( + stm.core_stream_data.audio_dump_input, + input_buffer_list.mBuffers[0].mData, + input_frames * stm.core_stream_data.input_dev_desc.mChannelsPerFrame, + ); + } + input_buffer_manager .push_data(input_buffer_list.mBuffers[0].mData, input_frames as usize); ErrorHandle::Return(status) @@ -708,6 +735,14 @@ extern "C" fn audiounit_output_callback( if stm.stopped.load(Ordering::SeqCst) { cubeb_alog!("({:p}) output stopped.", stm as *const AudioUnitStream); audiounit_make_silent(&buffers[0]); + #[cfg(feature = "audio_dump")] + { + dump_audio( + stm.core_stream_data.audio_dump_output, + buffers[0].mData, + output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame, + ); + } return NO_ERR; } @@ -718,12 +753,20 @@ extern "C" fn audiounit_output_callback( cubeb_alog!("({:p}) output drained.", stm as *const AudioUnitStream); stm.notify_state_changed(State::Drained); let queue = stm.queue.clone(); + audiounit_make_silent(&buffers[0]); + #[cfg(feature = "audio_dump")] + { + dump_audio( + stm.core_stream_data.audio_dump_output, + buffers[0].mData, + output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame, + ); + } // Use a new thread, through the queue, to avoid deadlock when calling // AudioOutputUnitStop method from inside render callback queue.run_async(move || { stm.core_stream_data.stop_audiounits(); }); - audiounit_make_silent(&buffers[0]); return NO_ERR; } @@ -846,12 +889,21 @@ extern "C" fn audiounit_output_callback( stm.stopped.store(true, Ordering::SeqCst); stm.notify_state_changed(State::Error); let queue = stm.queue.clone(); + audiounit_make_silent(&buffers[0]); + + #[cfg(feature = "audio_dump")] + { + dump_audio( + stm.core_stream_data.audio_dump_output, + buffers[0].mData, + output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame, + ); + } // Use a new thread, through the queue, to avoid deadlock when calling // AudioOutputUnitStop method from inside render callback queue.run_async(move || { stm.core_stream_data.stop_audiounits(); }); - audiounit_make_silent(&buffers[0]); return NO_ERR; } @@ -898,6 +950,15 @@ extern "C" fn audiounit_output_callback( buffers[0].mDataByteSize as usize, ); } + + #[cfg(feature = "audio_dump")] + { + dump_audio( + stm.core_stream_data.audio_dump_output, + buffers[0].mData, + output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame, + ); + } NO_ERR } @@ -3010,6 +3071,14 @@ struct CoreStreamData<'ctx> { output_alive_listener: Option, output_source_listener: Option, input_logging: Option, + #[cfg(feature = "audio_dump")] + audio_dump_session: ffi::cubeb_audio_dump_session_t, + #[cfg(feature = "audio_dump")] + audio_dump_session_running: bool, + #[cfg(feature = "audio_dump")] + audio_dump_input: ffi::cubeb_audio_dump_stream_t, + #[cfg(feature = "audio_dump")] + audio_dump_output: ffi::cubeb_audio_dump_stream_t, } impl<'ctx> Default for CoreStreamData<'ctx> { @@ -3050,6 +3119,14 @@ impl<'ctx> Default for CoreStreamData<'ctx> { output_alive_listener: None, output_source_listener: None, input_logging: None, + #[cfg(feature = "audio_dump")] + audio_dump_session: ptr::null_mut(), + #[cfg(feature = "audio_dump")] + audio_dump_session_running: false, + #[cfg(feature = "audio_dump")] + audio_dump_input: ptr::null_mut(), + #[cfg(feature = "audio_dump")] + audio_dump_output: ptr::null_mut(), } } } @@ -3097,6 +3174,14 @@ impl<'ctx> CoreStreamData<'ctx> { output_alive_listener: None, output_source_listener: None, input_logging: None, + #[cfg(feature = "audio_dump")] + audio_dump_session: ptr::null_mut(), + #[cfg(feature = "audio_dump")] + audio_dump_session_running: false, + #[cfg(feature = "audio_dump")] + audio_dump_input: ptr::null_mut(), + #[cfg(feature = "audio_dump")] + audio_dump_output: ptr::null_mut(), } } @@ -3454,6 +3539,11 @@ impl<'ctx> CoreStreamData<'ctx> { assert!(!self.stm_ptr.is_null()); let stream = unsafe { &(*self.stm_ptr) }; + #[cfg(feature = "audio_dump")] + unsafe { + ffi::cubeb_audio_dump_init(&mut self.audio_dump_session); + } + // Configure I/O stream if self.has_input() { assert!(!self.input_unit.is_null()); @@ -3543,6 +3633,26 @@ impl<'ctx> CoreStreamData<'ctx> { e })?; + #[cfg(feature = "audio_dump")] + { + let name = format!("input-{:p}.wav", self.stm_ptr); + let cname = CString::new(name).expect("OK"); + let rv = unsafe { + ffi::cubeb_audio_dump_stream_init( + self.audio_dump_session, + &mut self.audio_dump_input, + *params.as_ptr(), + cname.as_ptr(), + ) + }; + if rv == 0 { + assert_ne!(self.audio_dump_input, ptr::null_mut(),); + cubeb_log!("Successfully inited audio dump for input"); + } else { + cubeb_log!("Failed to init audio dump for input"); + } + } + assert_eq!(self.input_dev_desc.mSampleRate, input_hw_desc.mSampleRate); // Use latency to set buffer size @@ -3739,6 +3849,26 @@ impl<'ctx> CoreStreamData<'ctx> { e })?; + #[cfg(feature = "audio_dump")] + { + let name = format!("output-{:p}.wav", self.stm_ptr); + let cname = CString::new(name).expect("OK"); + let rv = unsafe { + ffi::cubeb_audio_dump_stream_init( + self.audio_dump_session, + &mut self.audio_dump_output, + *params.as_ptr(), + cname.as_ptr(), + ) + }; + if rv == 0 { + assert_ne!(self.audio_dump_output, ptr::null_mut(),); + cubeb_log!("Successfully inited audio dump for output"); + } else { + cubeb_log!("Failed to init audio dump for output"); + } + } + let device_layout = self .get_output_channel_layout() .map_err(|e| { @@ -3908,6 +4038,12 @@ impl<'ctx> CoreStreamData<'ctx> { self.input_logging = Some(InputCallbackLogger::new()); } + #[cfg(feature = "audio_dump")] + { + unsafe { ffi::cubeb_audio_dump_start(self.audio_dump_session) }; + self.audio_dump_session_running = true; + } + if !self.input_unit.is_null() { let r = audio_unit_initialize(self.input_unit); if r != NO_ERR { @@ -4081,6 +4217,36 @@ impl<'ctx> CoreStreamData<'ctx> { // Return the VPIO unit if present. self.voiceprocessing_unit_handle = None; + #[cfg(feature = "audio_dump")] + { + if !self.audio_dump_session.is_null() { + unsafe { + ffi::cubeb_audio_dump_stop(self.audio_dump_session); + if !self.audio_dump_input.is_null() { + let rv = ffi::cubeb_audio_dump_stream_shutdown( + self.audio_dump_session, + self.audio_dump_input, + ); + if rv != 0 { + cubeb_log!("Failed to shutdown audio dump for input"); + } + } + if !self.audio_dump_output.is_null() { + let rv = ffi::cubeb_audio_dump_stream_shutdown( + self.audio_dump_session, + self.audio_dump_output, + ); + if rv != 0 { + cubeb_log!("Failed to shutdown audio dump for output"); + } + } + ffi::cubeb_audio_dump_shutdown(self.audio_dump_session); + self.audio_dump_session = ptr::null_mut(); + self.audio_dump_session_running = false; + } + } + } + self.resampler.destroy(); self.mixer = None; self.aggregate_device = None; diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs index 5ce2374a3e..ea08a5ef45 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs @@ -376,7 +376,6 @@ fn test_get_default_device_id_with_inout_type() { #[test] fn test_convert_channel_layout() { let pairs = [ - (vec![kAudioObjectUnknown], vec![mixer::Channel::Silence]), ( vec![kAudioChannelLabel_Mono], vec![mixer::Channel::FrontCenter], @@ -398,7 +397,7 @@ fn test_convert_channel_layout() { vec![ mixer::Channel::FrontLeft, mixer::Channel::FrontRight, - mixer::Channel::Silence, + mixer::Channel::Discrete, ], ), ( diff --git a/third_party/rust/d3d12/.cargo-checksum.json b/third_party/rust/d3d12/.cargo-checksum.json index 8b27c96861..34bfd8a003 100644 --- a/third_party/rust/d3d12/.cargo-checksum.json +++ b/third_party/rust/d3d12/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"45fa76b0e5bc51721887147000e9e78a5934cb04d1ad628e501ef2082763d353","Cargo.toml":"a3135c67216ba021525ebc8d18dc3de5d779f1a1ddde5f25f4439acabd45824a","README.md":"76cee3209f773a62535de6c9724b53f158406359f35b4d48b17ac3747b6c102e","src/com.rs":"cfd6556a7abf38cba57559038f9f2cf86274418448fb2745436c251a99575e05","src/command_allocator.rs":"ef01059a661749470f3772d188fe0fab0f002e1d154facdab4b9b2932f4b2d93","src/command_list.rs":"8723f3b755b721e0dbb234bd604956c1b7922a2368231197495daa3fa6548e63","src/debug.rs":"aa33b98f7c3e71cba75fc42c6ca9af72d96b45122422c16e48525e24590c57bf","src/descriptor.rs":"fea0b820de1566b54d17d8d0c67e6f5a2126eda19526397eb710ff7d6db9db9e","src/device.rs":"c1dd479aabd22bced0d407523d60629ad1da439fb47ad89fe7b48bae1c4b23e5","src/dxgi.rs":"1516186845b91bf3df813a29b4a0e00a85ca5649fb7a2755da43fba984c41a42","src/heap.rs":"dae2380684896c97e97ed022929f79ce2cc4f5418a3ec34883086f7c88f423d0","src/lib.rs":"612e2f471b84502d219da3fb86ee13f3cbd6faf17d77407bab6c84e51ec424d0","src/pso.rs":"ff819c321536695e34a3be9a6051cf3e57765049a4a2035db6ab27add5a7978a","src/query.rs":"ff61a2b76a108afc1f082724bb9b07ac8b52afbe97356e0fcf6df0ff7e53e07d","src/queue.rs":"bd32813d0b8a3bedf3223b69ade9f9c799a138a9e27d970f86435d9ce32d1557","src/resource.rs":"8989cdb7c3ee0687c826047f39f85148459d9219754f20a970bf8aaa09b96e27","src/sync.rs":"5c287fb7498242a397eb1f08887be9cff9b48dc7cb13af5792cce5f7182b55f8"},"package":null} \ No newline at end of file +{"files":{"CHANGELOG.md":"45fa76b0e5bc51721887147000e9e78a5934cb04d1ad628e501ef2082763d353","Cargo.toml":"9938addd7ce2c7785a9ca11eb0049271317f9b05fdf0d7330d4a80f0e07ab500","README.md":"76cee3209f773a62535de6c9724b53f158406359f35b4d48b17ac3747b6c102e","src/com.rs":"cfd6556a7abf38cba57559038f9f2cf86274418448fb2745436c251a99575e05","src/command_allocator.rs":"ef01059a661749470f3772d188fe0fab0f002e1d154facdab4b9b2932f4b2d93","src/command_list.rs":"8723f3b755b721e0dbb234bd604956c1b7922a2368231197495daa3fa6548e63","src/debug.rs":"aa33b98f7c3e71cba75fc42c6ca9af72d96b45122422c16e48525e24590c57bf","src/descriptor.rs":"fea0b820de1566b54d17d8d0c67e6f5a2126eda19526397eb710ff7d6db9db9e","src/device.rs":"c1dd479aabd22bced0d407523d60629ad1da439fb47ad89fe7b48bae1c4b23e5","src/dxgi.rs":"1516186845b91bf3df813a29b4a0e00a85ca5649fb7a2755da43fba984c41a42","src/heap.rs":"dae2380684896c97e97ed022929f79ce2cc4f5418a3ec34883086f7c88f423d0","src/lib.rs":"612e2f471b84502d219da3fb86ee13f3cbd6faf17d77407bab6c84e51ec424d0","src/pso.rs":"ff819c321536695e34a3be9a6051cf3e57765049a4a2035db6ab27add5a7978a","src/query.rs":"ff61a2b76a108afc1f082724bb9b07ac8b52afbe97356e0fcf6df0ff7e53e07d","src/queue.rs":"bd32813d0b8a3bedf3223b69ade9f9c799a138a9e27d970f86435d9ce32d1557","src/resource.rs":"8989cdb7c3ee0687c826047f39f85148459d9219754f20a970bf8aaa09b96e27","src/sync.rs":"5c287fb7498242a397eb1f08887be9cff9b48dc7cb13af5792cce5f7182b55f8"},"package":null} \ No newline at end of file diff --git a/third_party/rust/d3d12/Cargo.toml b/third_party/rust/d3d12/Cargo.toml index 1425e10b80..576d6e21bb 100644 --- a/third_party/rust/d3d12/Cargo.toml +++ b/third_party/rust/d3d12/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "d3d12" -version = "0.19.0" +version = "0.20.0" authors = ["gfx-rs developers"] description = "Low level D3D12 API wrapper" documentation = "https://docs.rs/d3d12" diff --git a/third_party/rust/encoding_rs/.cargo-checksum.json b/third_party/rust/encoding_rs/.cargo-checksum.json index a5e1f1ba25..d5e91dd7e2 100644 --- a/third_party/rust/encoding_rs/.cargo-checksum.json +++ b/third_party/rust/encoding_rs/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"ca1901f3e8532fb4cec894fd3664f0eaa898c0c4b961d1b992d1ed54eacf362a","COPYRIGHT":"11789f45bb180841cd362a5eee6789c68ddb573a11105e30768c308a6add0190","Cargo.toml":"42fa83322aa9fd6723b77d35d0cacb92cbb6e7f573ce11c55f5225292866f8f4","Ideas.md":"b7452893f500163868d8de52c09addaf91e1632454ed02e892c467ed7ec39dbd","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"3fa4ca83dcc9237839b1bdeb2e6d16bdfb5ec0c5ce42b24694d8bbf0dcbef72c","LICENSE-WHATWG":"838118388fe5c2e7f1dbbaeed13e1c7f3ebf88be91319c7c1d77c18e987d1a50","README.md":"d938e8ab0b9ab67e74a1a4f48f23fdce956d0ad3a3f6147ae7612a92763c88d5","ci/miri.sh":"43cb8d82f49e3bfe2d2274b6ccd6f0714a4188ccef0cecc040829883cfdbee25","doc/Big5.txt":"f73a2edc5cb6c2d140ba6e07f4542e1c4a234950378acde1df93480f0ca0be0b","doc/EUC-JP.txt":"ee2818b907d0137f40a9ab9fd525fc700a44dbdddb6cf0c157a656566bae4bf1","doc/EUC-KR.txt":"71d9e2ccf3b124e8bdfb433c8cf2773fd878077038d0cec3c7237a50f4a78a30","doc/GBK.txt":"c1b522b5a799884e5001da661f42c5a8f4d0acb9ef1d74b206f22b5f65365606","doc/IBM866.txt":"a5a433e804d0f83af785015179fbc1d9b0eaf1f7960efcd04093e136b51fbd0e","doc/ISO-2022-JP.txt":"af86684f5a8f0e2868d7b2c292860140c3d2e5527530ca091f1b28198e8e2fe6","doc/ISO-8859-10.txt":"6d3949ad7c81ca176895101ed81a1db7df1060d64e262880b94bd31bb344ab4d","doc/ISO-8859-13.txt":"3951dd89cf93f7729148091683cf8511f4529388b7dc8dcd0d62eaed55be93fa","doc/ISO-8859-14.txt":"3d330784a0374fd255a38b47949675cc7168c800530534b0a01cac6edc623adc","doc/ISO-8859-15.txt":"24b1084aab5127a85aab99153f86e24694d0a3615f53b5ce23683f97cf66c47a","doc/ISO-8859-16.txt":"ce0272559b92ba76d7a7e476f6424ae4a5cc72e75b183611b08392e44add4d25","doc/ISO-8859-2.txt":"18ceff88c13d1b5ba455a3919b1e3de489045c4c3d2dd7e8527c125c75d54aad","doc/ISO-8859-3.txt":"21798404c68f4f5db59223362f24999da96968c0628427321fccce7d2849a130","doc/ISO-8859-4.txt":"d27f6520c6c5bfbcc19176b71d081cdb3bccde1622bb3e420d5680e812632d53","doc/ISO-8859-5.txt":"a10ec8d6ea7a78ad15da7275f6cb1a3365118527e28f9af6d0d5830501303f3a","doc/ISO-8859-6.txt":"ccda8a2efc96115336bdd77776637b9712425e44fbcf745353b9057fbef144e7","doc/ISO-8859-7.txt":"17900fa1f27a445958f0a77d7d9056be375a6bd7ee4492aa680c7c1500bab85e","doc/ISO-8859-8-I.txt":"8357555646d54265a9b9ffa3e68b08d132312f1561c60108ff9b8b1167b6ecf2","doc/ISO-8859-8.txt":"72cd6f3afb7b4a9c16a66a362473315770b7755d72c86c870e52fc3eba86c8af","doc/KOI8-R.txt":"839cf19a38da994488004ed7814b1f6151640156a9a2af02bf2efca745fb5966","doc/KOI8-U.txt":"0cc76624ed1f024183e2298b7e019957da2c70c8ca06e0fc4e6f353f50a5054f","doc/Shift_JIS.txt":"34c49141818cb9ddbcf59cc858f78a79be8ad148d563f26415108ae1f148443f","doc/UTF-16BE.txt":"e2e280d8acbaa6d2a6b3569d60e17500a285f2baa0df3363dd85537cd5a1ef8f","doc/UTF-16LE.txt":"70bdc170e3fc5298ba68f10125fb5eeb8b077036cc96bb4416c4de396f6d76c1","doc/UTF-8.txt":"ea7bae742e613010ced002cf4b601a737d2203fad65e115611451bc4428f548a","doc/gb18030.txt":"dc71378a8f07a2d8659f69ee81fb8791fef56ba86f124b429978285237bb4a7b","doc/macintosh.txt":"57491e53866711b4672d9b9ff35380b9dac9e0d8e3d6c20bdd6140603687c023","doc/replacement.txt":"4b6c3bbd7999d9d4108a281594bd02d13607e334a95465afff8c2c08d395f0e4","doc/windows-1250.txt":"61296bb6a21cdab602300d32ecfba434cb82de5ac3bc88d58710d2f125e28d39","doc/windows-1251.txt":"7deea1c61dea1485c8ff02db2c7d578db7a9aab63ab1cfd02ec04b515864689e","doc/windows-1252.txt":"933ef3bdddfce5ee132b9f1a1aa8b47423d2587bbe475b19028d0a6d38e180b6","doc/windows-1253.txt":"1a38748b88e99071a5c7b3d5456ead4caedeabab50d50d658be105bc113714de","doc/windows-1254.txt":"f8372f86c6f8d642563cd6ddc025260553292a39423df1683a98670bd7bf2b47","doc/windows-1255.txt":"4e5852494730054e2da258a74e1b9d780abbcdd8ce22ebc218ca2efe9e90493d","doc/windows-1256.txt":"c0879c5172abedead302a406e8f60d9cd9598694a0ffa4fd288ffe4fef7b8ea1","doc/windows-1257.txt":"c28a0c9f964fcb2b46d21f537c402446501a2800670481d6abf9fd9e9018d523","doc/windows-1258.txt":"5019ae4d61805c79aacbf17c93793342dbb098d65a1837783bc3e2c6d6a23602","doc/windows-874.txt":"4ef0e4501c5feba8b17aee1818602ed44b36ca8475db771ce2fc16d392cabecc","doc/x-mac-cyrillic.txt":"58be154d8a888ca3d484b83b44f749823ef339ab27f14d90ca9a856f5050a8bd","doc/x-user-defined.txt":"f9cd07c4321bf5cfb0be4bdddd251072999b04a6cf7a6f5bc63709a84e2c1ffc","generate-encoding-data.py":"be989dd25c6b946e3e8745fdc8e8a80fcf24b3be99ad0b4b78153ba3f6ab6310","rustfmt.toml":"85c1a3b4382fd89e991cbb81b70fb52780472edc064c963943cdaaa56e0a2030","src/ascii.rs":"c44c002641adb5ebc4368707a8cc0a076d2f33e6a5c27b1b69988eb515f5653d","src/big5.rs":"ec6e2913011a38e9a3e825a1731f139a7ca1d5b264fefae51a3cc1a68a57cef9","src/data.rs":"8a617cc57032092d65850eb27e00de687c80aea3299e839a1f58b42d0b35abf3","src/euc_jp.rs":"32047f5b540188c4cb19c07165f846b9786a09f18e315ed3e9bda1293dae52aa","src/euc_kr.rs":"9b25afc72d9378700eecfac58d55ad1c5946d6cd0ccde2c29c08200ef2de6bb9","src/gb18030.rs":"808587168d73f0c80f8520f0ca9b161866ed2efeb17a05e85fdf3b8efe7ba28a","src/handles.rs":"cc83dc0754751d67f5688a65c5e0191cba02f6bacce81a0813a243cba55eef7a","src/iso_2022_jp.rs":"9bb485e82574f4b7d4b2364f0ff276acb6a0bc111758420a3b0ec5e04c196652","src/lib.rs":"1dc07b818e45846b16ddcaf0de46c8862dd7df8099123ec38b95c3f8ad9c91ec","src/macros.rs":"200997f8870de8bfd8cdc475e92115df42108c0df661e49d3d1cbc32056e1d99","src/mem.rs":"0bf34103e0ad1b842a13a082dee2b920b05cf4fb0f145c9ee7f608f4cb4a544f","src/replacement.rs":"7660b34a53f8c1ca2bdfa0e51e843ec28326950952ad8bc96569feb93ac62308","src/shift_jis.rs":"6951ae67e36b1a12fa3a30734957f444d8b1b4ae0e2bde52060b29bd0f16d9d9","src/simd_funcs.rs":"2612aba86e1d201096d7e47a859bc3444f85934cc82d8adc6d39a4304d9eecfc","src/single_byte.rs":"3c9e9c1f946ae622c725ba9421240c1faa9a05e95fa10dd4642a25cb276a1edc","src/test_data/big5_in.txt":"4c5a8691f8dc717311889c63894026d2fb62725a86c4208ca274a9cc8d42a503","src/test_data/big5_in_ref.txt":"99d399e17750cf9c7cf30bb253dbfe35b81c4fcbdead93cfa48b1429213473c7","src/test_data/big5_out.txt":"6193ca97c297aa20e09396038d18e938bb7ea331c26f0f2454097296723a0b13","src/test_data/big5_out_ref.txt":"36567691f557df144f6cc520015a87038dfa156f296fcf103b56ae9a718be1fc","src/test_data/euc_kr_in.txt":"c86a7224f3215fa0d04e685622a752fdc72763e8ae076230c7fd62de57ec4074","src/test_data/euc_kr_in_ref.txt":"1f419f4ca47d708b54c73c461545a022ae2e20498fdbf8005a483d752a204883","src/test_data/euc_kr_out.txt":"e7f32e026f70be1e1b58e0047baf7d3d2c520269c4f9b9992e158b4decb0a1a3","src/test_data/euc_kr_out_ref.txt":"c9907857980b20b8e9e3b584482ed6567a2be6185d72237b6322f0404944924e","src/test_data/gb18030_in.txt":"ab7231b2d3e9afacdbd7d7f3b9e5361a7ff9f7e1cfdb4f3bd905b9362b309e53","src/test_data/gb18030_in_ref.txt":"dc5069421adca2043c55f5012b55a76fdff651d22e6e699fd0978f8d5706815c","src/test_data/gb18030_out.txt":"f0208d527f5ca63de7d9a0323be8d5cf12d8a104b2943d92c2701f0c3364dac1","src/test_data/gb18030_out_ref.txt":"6819fe47627e4ea01027003fc514b9f21a1322e732d7f1fb92cc6c5455bc6c07","src/test_data/iso_2022_jp_in.txt":"cd24bbdcb1834e25db54646fbf4c41560a13dc7540f6be3dba4f5d97d44513af","src/test_data/iso_2022_jp_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/iso_2022_jp_out.txt":"9b6f015329dda6c3f9ee5ce6dbd6fa9c89acc21283e886836c78b8d833480c21","src/test_data/iso_2022_jp_out_ref.txt":"78cb260093a20116ad9a42f43b05d1848c5ab100b6b9a850749809e943884b35","src/test_data/jis0208_in.txt":"6df3030553ffb0a6615bb33dc8ea9dca6d9623a9028e2ffec754ce3c3da824cc","src/test_data/jis0208_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/jis0208_out.txt":"4ec24477e1675ce750733bdc3c5add1cd27b6bd4ce1f09289564646e9654e857","src/test_data/jis0208_out_ref.txt":"c3e1cef5032b2b1d93a406f31ff940c4e2dfe8859b8b17ca2761fee7a75a0e48","src/test_data/jis0212_in.txt":"c011f0dd72bd7c8cd922df9374ef8d2769a77190514c77f6c62b415852eeb9fe","src/test_data/jis0212_in_ref.txt":"7d9458b3d2f73e7092a7f505c08ce1d233dde18aa679fbcf9889256239cc9e06","src/test_data/shift_jis_in.txt":"02e389ccef0dd2122e63f503899402cb7f797912c2444cc80ab93131116c5524","src/test_data/shift_jis_in_ref.txt":"512f985950ca902e643c88682dba9708b7c38d3c5ec2925168ab00ac94ab19f9","src/test_data/shift_jis_out.txt":"5fbc44da7bf639bf6cfe0fa1fd3eba7102b88f81919c9ea991302712f69426fb","src/test_data/shift_jis_out_ref.txt":"466322c6fed8286c64582731755290c2296508efdd258826e6279686649b481f","src/test_labels_names.rs":"23a2e11b02b3b8d15fb5613a625e3edb2c61e70e3c581abfd638719a4088200d","src/testing.rs":"f59e671e95a98a56f6b573e8c6be4d71e670bf52f7e20eb1605d990aafa1894e","src/utf_16.rs":"c071a147fad38d750c2c247e141b76b929a48007b99f26b2922b9caecdaf2f25","src/utf_8.rs":"7b7d887b347f1aefa03246b028a36a72758a4ce76c28f3b45c19467851aa7839","src/variant.rs":"1fab5363588a1554a7169de8731ea9cded7ac63ea35caabdd1c27a8dde68c27b","src/x_user_defined.rs":"c9c010730dfb9f141d4fed19350c08a21af240913a54bb64f5ca89ff93b6b7d1"},"package":"7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"ca1901f3e8532fb4cec894fd3664f0eaa898c0c4b961d1b992d1ed54eacf362a","COPYRIGHT":"11789f45bb180841cd362a5eee6789c68ddb573a11105e30768c308a6add0190","Cargo.toml":"22a4d210c92dae9f32c6944ef340ee8fdd027f99c081577e8907123e2a93383e","Ideas.md":"b7452893f500163868d8de52c09addaf91e1632454ed02e892c467ed7ec39dbd","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"3fa4ca83dcc9237839b1bdeb2e6d16bdfb5ec0c5ce42b24694d8bbf0dcbef72c","LICENSE-WHATWG":"838118388fe5c2e7f1dbbaeed13e1c7f3ebf88be91319c7c1d77c18e987d1a50","README.md":"1d08aefcb92afa81b18154049c9abbcad4540a23f7172e9f9bbed5af33f1a087","ci/miri.sh":"43cb8d82f49e3bfe2d2274b6ccd6f0714a4188ccef0cecc040829883cfdbee25","doc/Big5.txt":"f73a2edc5cb6c2d140ba6e07f4542e1c4a234950378acde1df93480f0ca0be0b","doc/EUC-JP.txt":"ee2818b907d0137f40a9ab9fd525fc700a44dbdddb6cf0c157a656566bae4bf1","doc/EUC-KR.txt":"71d9e2ccf3b124e8bdfb433c8cf2773fd878077038d0cec3c7237a50f4a78a30","doc/GBK.txt":"c1b522b5a799884e5001da661f42c5a8f4d0acb9ef1d74b206f22b5f65365606","doc/IBM866.txt":"a5a433e804d0f83af785015179fbc1d9b0eaf1f7960efcd04093e136b51fbd0e","doc/ISO-2022-JP.txt":"af86684f5a8f0e2868d7b2c292860140c3d2e5527530ca091f1b28198e8e2fe6","doc/ISO-8859-10.txt":"6d3949ad7c81ca176895101ed81a1db7df1060d64e262880b94bd31bb344ab4d","doc/ISO-8859-13.txt":"3951dd89cf93f7729148091683cf8511f4529388b7dc8dcd0d62eaed55be93fa","doc/ISO-8859-14.txt":"3d330784a0374fd255a38b47949675cc7168c800530534b0a01cac6edc623adc","doc/ISO-8859-15.txt":"24b1084aab5127a85aab99153f86e24694d0a3615f53b5ce23683f97cf66c47a","doc/ISO-8859-16.txt":"ce0272559b92ba76d7a7e476f6424ae4a5cc72e75b183611b08392e44add4d25","doc/ISO-8859-2.txt":"18ceff88c13d1b5ba455a3919b1e3de489045c4c3d2dd7e8527c125c75d54aad","doc/ISO-8859-3.txt":"21798404c68f4f5db59223362f24999da96968c0628427321fccce7d2849a130","doc/ISO-8859-4.txt":"d27f6520c6c5bfbcc19176b71d081cdb3bccde1622bb3e420d5680e812632d53","doc/ISO-8859-5.txt":"a10ec8d6ea7a78ad15da7275f6cb1a3365118527e28f9af6d0d5830501303f3a","doc/ISO-8859-6.txt":"ccda8a2efc96115336bdd77776637b9712425e44fbcf745353b9057fbef144e7","doc/ISO-8859-7.txt":"17900fa1f27a445958f0a77d7d9056be375a6bd7ee4492aa680c7c1500bab85e","doc/ISO-8859-8-I.txt":"8357555646d54265a9b9ffa3e68b08d132312f1561c60108ff9b8b1167b6ecf2","doc/ISO-8859-8.txt":"72cd6f3afb7b4a9c16a66a362473315770b7755d72c86c870e52fc3eba86c8af","doc/KOI8-R.txt":"839cf19a38da994488004ed7814b1f6151640156a9a2af02bf2efca745fb5966","doc/KOI8-U.txt":"0cc76624ed1f024183e2298b7e019957da2c70c8ca06e0fc4e6f353f50a5054f","doc/Shift_JIS.txt":"34c49141818cb9ddbcf59cc858f78a79be8ad148d563f26415108ae1f148443f","doc/UTF-16BE.txt":"e2e280d8acbaa6d2a6b3569d60e17500a285f2baa0df3363dd85537cd5a1ef8f","doc/UTF-16LE.txt":"70bdc170e3fc5298ba68f10125fb5eeb8b077036cc96bb4416c4de396f6d76c1","doc/UTF-8.txt":"ea7bae742e613010ced002cf4b601a737d2203fad65e115611451bc4428f548a","doc/gb18030.txt":"dc71378a8f07a2d8659f69ee81fb8791fef56ba86f124b429978285237bb4a7b","doc/macintosh.txt":"57491e53866711b4672d9b9ff35380b9dac9e0d8e3d6c20bdd6140603687c023","doc/replacement.txt":"4b6c3bbd7999d9d4108a281594bd02d13607e334a95465afff8c2c08d395f0e4","doc/windows-1250.txt":"61296bb6a21cdab602300d32ecfba434cb82de5ac3bc88d58710d2f125e28d39","doc/windows-1251.txt":"7deea1c61dea1485c8ff02db2c7d578db7a9aab63ab1cfd02ec04b515864689e","doc/windows-1252.txt":"933ef3bdddfce5ee132b9f1a1aa8b47423d2587bbe475b19028d0a6d38e180b6","doc/windows-1253.txt":"1a38748b88e99071a5c7b3d5456ead4caedeabab50d50d658be105bc113714de","doc/windows-1254.txt":"f8372f86c6f8d642563cd6ddc025260553292a39423df1683a98670bd7bf2b47","doc/windows-1255.txt":"4e5852494730054e2da258a74e1b9d780abbcdd8ce22ebc218ca2efe9e90493d","doc/windows-1256.txt":"c0879c5172abedead302a406e8f60d9cd9598694a0ffa4fd288ffe4fef7b8ea1","doc/windows-1257.txt":"c28a0c9f964fcb2b46d21f537c402446501a2800670481d6abf9fd9e9018d523","doc/windows-1258.txt":"5019ae4d61805c79aacbf17c93793342dbb098d65a1837783bc3e2c6d6a23602","doc/windows-874.txt":"4ef0e4501c5feba8b17aee1818602ed44b36ca8475db771ce2fc16d392cabecc","doc/x-mac-cyrillic.txt":"58be154d8a888ca3d484b83b44f749823ef339ab27f14d90ca9a856f5050a8bd","doc/x-user-defined.txt":"f9cd07c4321bf5cfb0be4bdddd251072999b04a6cf7a6f5bc63709a84e2c1ffc","generate-encoding-data.py":"be989dd25c6b946e3e8745fdc8e8a80fcf24b3be99ad0b4b78153ba3f6ab6310","rustfmt.toml":"85c1a3b4382fd89e991cbb81b70fb52780472edc064c963943cdaaa56e0a2030","src/ascii.rs":"588e38b01e666d5e7462617ea7e90a108d608dec9e016f3d273ac0744af2e05d","src/big5.rs":"ec6e2913011a38e9a3e825a1731f139a7ca1d5b264fefae51a3cc1a68a57cef9","src/data.rs":"8a617cc57032092d65850eb27e00de687c80aea3299e839a1f58b42d0b35abf3","src/euc_jp.rs":"32047f5b540188c4cb19c07165f846b9786a09f18e315ed3e9bda1293dae52aa","src/euc_kr.rs":"9b25afc72d9378700eecfac58d55ad1c5946d6cd0ccde2c29c08200ef2de6bb9","src/gb18030.rs":"808587168d73f0c80f8520f0ca9b161866ed2efeb17a05e85fdf3b8efe7ba28a","src/handles.rs":"b08cef1f5785bb6a4822f2e844c6df1b046b737b7a075e4593eaa8c4208e9fe2","src/iso_2022_jp.rs":"9bb485e82574f4b7d4b2364f0ff276acb6a0bc111758420a3b0ec5e04c196652","src/lib.rs":"834f44b670ec48ee82c0e12223d1567313fdd9f88bca5f4b117c82c1828f559f","src/macros.rs":"200997f8870de8bfd8cdc475e92115df42108c0df661e49d3d1cbc32056e1d99","src/mem.rs":"948571137d3b151df8db4fb2c733e74ae595d055cdf0ad83abcab9341d6adabe","src/replacement.rs":"7660b34a53f8c1ca2bdfa0e51e843ec28326950952ad8bc96569feb93ac62308","src/shift_jis.rs":"6951ae67e36b1a12fa3a30734957f444d8b1b4ae0e2bde52060b29bd0f16d9d9","src/simd_funcs.rs":"05c6e77af74bfe73cd39a752067c11425d6b46e5da419910f54bf75a5c02a984","src/single_byte.rs":"3ad87116fb339434a4b58e8f2b15485f2b66b9f7814d708f16194ed08f6d6ccf","src/test_data/big5_in.txt":"4c5a8691f8dc717311889c63894026d2fb62725a86c4208ca274a9cc8d42a503","src/test_data/big5_in_ref.txt":"99d399e17750cf9c7cf30bb253dbfe35b81c4fcbdead93cfa48b1429213473c7","src/test_data/big5_out.txt":"6193ca97c297aa20e09396038d18e938bb7ea331c26f0f2454097296723a0b13","src/test_data/big5_out_ref.txt":"36567691f557df144f6cc520015a87038dfa156f296fcf103b56ae9a718be1fc","src/test_data/euc_kr_in.txt":"c86a7224f3215fa0d04e685622a752fdc72763e8ae076230c7fd62de57ec4074","src/test_data/euc_kr_in_ref.txt":"1f419f4ca47d708b54c73c461545a022ae2e20498fdbf8005a483d752a204883","src/test_data/euc_kr_out.txt":"e7f32e026f70be1e1b58e0047baf7d3d2c520269c4f9b9992e158b4decb0a1a3","src/test_data/euc_kr_out_ref.txt":"c9907857980b20b8e9e3b584482ed6567a2be6185d72237b6322f0404944924e","src/test_data/gb18030_in.txt":"ab7231b2d3e9afacdbd7d7f3b9e5361a7ff9f7e1cfdb4f3bd905b9362b309e53","src/test_data/gb18030_in_ref.txt":"dc5069421adca2043c55f5012b55a76fdff651d22e6e699fd0978f8d5706815c","src/test_data/gb18030_out.txt":"f0208d527f5ca63de7d9a0323be8d5cf12d8a104b2943d92c2701f0c3364dac1","src/test_data/gb18030_out_ref.txt":"6819fe47627e4ea01027003fc514b9f21a1322e732d7f1fb92cc6c5455bc6c07","src/test_data/iso_2022_jp_in.txt":"cd24bbdcb1834e25db54646fbf4c41560a13dc7540f6be3dba4f5d97d44513af","src/test_data/iso_2022_jp_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/iso_2022_jp_out.txt":"9b6f015329dda6c3f9ee5ce6dbd6fa9c89acc21283e886836c78b8d833480c21","src/test_data/iso_2022_jp_out_ref.txt":"78cb260093a20116ad9a42f43b05d1848c5ab100b6b9a850749809e943884b35","src/test_data/jis0208_in.txt":"6df3030553ffb0a6615bb33dc8ea9dca6d9623a9028e2ffec754ce3c3da824cc","src/test_data/jis0208_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/jis0208_out.txt":"4ec24477e1675ce750733bdc3c5add1cd27b6bd4ce1f09289564646e9654e857","src/test_data/jis0208_out_ref.txt":"c3e1cef5032b2b1d93a406f31ff940c4e2dfe8859b8b17ca2761fee7a75a0e48","src/test_data/jis0212_in.txt":"c011f0dd72bd7c8cd922df9374ef8d2769a77190514c77f6c62b415852eeb9fe","src/test_data/jis0212_in_ref.txt":"7d9458b3d2f73e7092a7f505c08ce1d233dde18aa679fbcf9889256239cc9e06","src/test_data/shift_jis_in.txt":"02e389ccef0dd2122e63f503899402cb7f797912c2444cc80ab93131116c5524","src/test_data/shift_jis_in_ref.txt":"512f985950ca902e643c88682dba9708b7c38d3c5ec2925168ab00ac94ab19f9","src/test_data/shift_jis_out.txt":"5fbc44da7bf639bf6cfe0fa1fd3eba7102b88f81919c9ea991302712f69426fb","src/test_data/shift_jis_out_ref.txt":"466322c6fed8286c64582731755290c2296508efdd258826e6279686649b481f","src/test_labels_names.rs":"23a2e11b02b3b8d15fb5613a625e3edb2c61e70e3c581abfd638719a4088200d","src/testing.rs":"f59e671e95a98a56f6b573e8c6be4d71e670bf52f7e20eb1605d990aafa1894e","src/utf_16.rs":"c071a147fad38d750c2c247e141b76b929a48007b99f26b2922b9caecdaf2f25","src/utf_8.rs":"7b7d887b347f1aefa03246b028a36a72758a4ce76c28f3b45c19467851aa7839","src/variant.rs":"1fab5363588a1554a7169de8731ea9cded7ac63ea35caabdd1c27a8dde68c27b","src/x_user_defined.rs":"9456ca46168ef86c98399a2536f577ef7be3cdde90c0c51392d8ac48519d3fae"},"package":"b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"} \ No newline at end of file diff --git a/third_party/rust/encoding_rs/Cargo.toml b/third_party/rust/encoding_rs/Cargo.toml index e9fd6c0af2..08bb61136b 100644 --- a/third_party/rust/encoding_rs/Cargo.toml +++ b/third_party/rust/encoding_rs/Cargo.toml @@ -11,8 +11,9 @@ [package] edition = "2018" +rust-version = "1.36" name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" authors = ["Henri Sivonen "] description = "A Gecko-oriented implementation of the Encoding Standard" homepage = "https://docs.rs/encoding_rs/" @@ -36,13 +37,13 @@ repository = "https://github.com/hsivonen/encoding_rs" [profile.release] lto = true +[dependencies.any_all_workaround] +version = "0.1.0" +optional = true + [dependencies.cfg-if] version = "1.0" -[dependencies.packed_simd] -version = "0.3.9" -optional = true - [dependencies.serde] version = "1.0" optional = true @@ -74,10 +75,4 @@ fast-legacy-encode = [ less-slow-big5-hanzi-encode = [] less-slow-gb-hanzi-encode = [] less-slow-kanji-encode = [] -simd-accel = [ - "packed_simd", - "packed_simd/into_bits", -] - -[badges.travis-ci] -repository = "hsivonen/encoding_rs" +simd-accel = ["any_all_workaround"] diff --git a/third_party/rust/encoding_rs/README.md b/third_party/rust/encoding_rs/README.md index c0b596c951..ed0e954630 100644 --- a/third_party/rust/encoding_rs/README.md +++ b/third_party/rust/encoding_rs/README.md @@ -167,13 +167,15 @@ There are currently these optional cargo features: ### `simd-accel` -Enables SIMD acceleration using the nightly-dependent `packed_simd` crate. +Enables SIMD acceleration using the nightly-dependent `portable_simd` standard +library feature. This is an opt-in feature, because enabling this feature _opts out_ of Rust's guarantees of future compilers compiling old code (aka. "stability story"). Currently, this has not been tested to be an improvement except for these -targets: +targets and enabling the `simd-accel` feature is expected to break the build +on other targets: * x86_64 * i686 @@ -185,22 +187,6 @@ above, and you are prepared _to have to revise your configuration when updating Rust_, you should enable this feature. Otherwise, please _do not_ enable this feature. -_Note!_ If you are compiling for a target that does not have 128-bit SIMD -enabled as part of the target definition and you are enabling 128-bit SIMD -using `-C target_feature`, you need to enable the `core_arch` Cargo feature -for `packed_simd` to compile a crates.io snapshot of `core_arch` instead of -using the standard-library copy of `core::arch`, because the `core::arch` -module of the pre-compiled standard library has been compiled with the -assumption that the CPU doesn't have 128-bit SIMD. At present this applies -mainly to 32-bit ARM targets whose first component does not include the -substring `neon`. - -The encoding_rs side of things has not been properly set up for POWER, -PowerPC, MIPS, etc., SIMD at this time, so even if you were to follow -the advice from the previous paragraph, you probably shouldn't use -the `simd-accel` option on the less mainstream architectures at this -time. - Used by Firefox. ### `serde` @@ -381,8 +367,9 @@ as semver-breaking, because this crate depends on `cfg-if`, which doesn't appear to treat MSRV changes as semver-breaking, so it would be useless for this crate to treat MSRV changes as semver-breaking. -As of 2021-02-04, MSRV appears to be Rust 1.36.0 for using the crate and +As of 2024-04-04, MSRV appears to be Rust 1.36.0 for using the crate and 1.42.0 for doc tests to pass without errors about the global allocator. +With the `simd-accel` feature, the MSRV is even higher. ## Compatibility with rust-encoding @@ -446,10 +433,17 @@ To regenerate the generated code: - [x] Add actually fast CJK encode options. - [ ] ~Investigate [Bob Steagall's lookup table acceleration for UTF-8](https://github.com/BobSteagall/CppNow2018/blob/master/FastConversionFromUTF-8/Fast%20Conversion%20From%20UTF-8%20with%20C%2B%2B%2C%20DFAs%2C%20and%20SSE%20Intrinsics%20-%20Bob%20Steagall%20-%20C%2B%2BNow%202018.pdf).~ - [x] Provide a build mode that works without `alloc` (with lesser API surface). -- [ ] Migrate to `std::simd` once it is stable and declare 1.0. +- [x] Migrate to `std::simd` ~once it is stable and declare 1.0.~ +- [ ] Migrate `unsafe` slice access by larger types than `u8`/`u16` to `align_to`. ## Release Notes +### 0.8.34 + +* Use the `portable_simd` nightly feature of the standard library instead of the `packed_simd` crate. Only affects the `simd-accel` optional nightly feature. +* Internal documentation improvements and minor code improvements around `unsafe`. +* Added `rust-version` to `Cargo.toml`. + ### 0.8.33 * Use `packed_simd` instead of `packed_simd_2` again now that updates are back under the `packed_simd` name. Only affects the `simd-accel` optional nightly feature. diff --git a/third_party/rust/encoding_rs/src/ascii.rs b/third_party/rust/encoding_rs/src/ascii.rs index 90644de7a4..80233f285e 100644 --- a/third_party/rust/encoding_rs/src/ascii.rs +++ b/third_party/rust/encoding_rs/src/ascii.rs @@ -51,6 +51,8 @@ cfg_if! { } } +// Safety invariants for masks: data & mask = 0 for valid ASCII or basic latin utf-16 + // `as` truncates, so works on 32-bit, too. #[allow(dead_code)] pub const ASCII_MASK: usize = 0x8080_8080_8080_8080u64 as usize; @@ -62,6 +64,9 @@ pub const BASIC_LATIN_MASK: usize = 0xFF80_FF80_FF80_FF80u64 as usize; #[allow(unused_macros)] macro_rules! ascii_naive { ($name:ident, $src_unit:ty, $dst_unit:ty) => { + /// Safety: src and dst must have len_unit elements and be aligned + /// Safety-usable invariant: will return Some() when it fails + /// to convert. The first value will be a u8 that is > 127. #[inline(always)] pub unsafe fn $name( src: *const $src_unit, @@ -71,10 +76,13 @@ macro_rules! ascii_naive { // Yes, manually omitting the bound check here matters // a lot for perf. for i in 0..len { + // Safety: len invariant used here let code_unit = *(src.add(i)); + // Safety: Upholds safety-usable invariant here if code_unit > 127 { return Some((code_unit, i)); } + // Safety: len invariant used here *(dst.add(i)) = code_unit as $dst_unit; } return None; @@ -85,9 +93,15 @@ macro_rules! ascii_naive { #[allow(unused_macros)] macro_rules! ascii_alu { ($name:ident, + // safety invariant: src/dst MUST be u8 $src_unit:ty, $dst_unit:ty, + // Safety invariant: stride_fn must consume and produce two usizes, and return the index of the first non-ascii when it fails $stride_fn:ident) => { + /// Safety: src and dst must have len elements, src is valid for read, dst is valid for + /// write + /// Safety-usable invariant: will return Some() when it fails + /// to convert. The first value will be a u8 that is > 127. #[cfg_attr(feature = "cargo-clippy", allow(never_loop, cast_ptr_alignment))] #[inline(always)] pub unsafe fn $name( @@ -98,6 +112,7 @@ macro_rules! ascii_alu { let mut offset = 0usize; // This loop is only broken out of as a `goto` forward loop { + // Safety: until_alignment becomes the number of bytes we need to munch until we are aligned to usize let mut until_alignment = { // Check if the other unit aligns if we move the narrower unit // to alignment. @@ -106,6 +121,7 @@ macro_rules! ascii_alu { let src_alignment = (src as usize) & ALU_ALIGNMENT_MASK; let dst_alignment = (dst as usize) & ALU_ALIGNMENT_MASK; if src_alignment != dst_alignment { + // Safety: bails early and ends up in the naïve branch where usize-alignment doesn't matter break; } (ALU_ALIGNMENT - src_alignment) & ALU_ALIGNMENT_MASK @@ -134,25 +150,40 @@ macro_rules! ascii_alu { // x86_64 should be using SSE2 in due course, keeping the move // to alignment here. It would be good to test on more ARM CPUs // and on real MIPS and POWER hardware. + // + // Safety: This is the naïve code once again, for `until_alignment` bytes while until_alignment != 0 { let code_unit = *(src.add(offset)); if code_unit > 127 { + // Safety: Upholds safety-usable invariant here return Some((code_unit, offset)); } *(dst.add(offset)) = code_unit as $dst_unit; + // Safety: offset is the number of bytes copied so far offset += 1; until_alignment -= 1; } let len_minus_stride = len - ALU_STRIDE_SIZE; loop { + // Safety: num_ascii is known to be a byte index of a non-ascii byte due to stride_fn's invariant if let Some(num_ascii) = $stride_fn( + // Safety: These are known to be valid and aligned since we have at + // least ALU_STRIDE_SIZE data in these buffers, and offset is the + // number of elements copied so far, which according to the + // until_alignment calculation above will cause both src and dst to be + // aligned to usize after this add src.add(offset) as *const usize, dst.add(offset) as *mut usize, ) { offset += num_ascii; + // Safety: Upholds safety-usable invariant here by indexing into non-ascii byte return Some((*(src.add(offset)), offset)); } + // Safety: offset continues to be the number of bytes copied so far, and + // maintains usize alignment for the next loop iteration offset += ALU_STRIDE_SIZE; + // Safety: This is `offset > len - stride. This loop will continue as long as + // `offset <= len - stride`, which means there are `stride` bytes to still be read. if offset > len_minus_stride { break; } @@ -160,11 +191,17 @@ macro_rules! ascii_alu { } break; } + + // Safety: This is the naïve code, same as ascii_naive, and has no requirements + // other than src/dst being valid for the the right lens while offset < len { + // Safety: len invariant used here let code_unit = *(src.add(offset)); if code_unit > 127 { + // Safety: Upholds safety-usable invariant here return Some((code_unit, offset)); } + // Safety: len invariant used here *(dst.add(offset)) = code_unit as $dst_unit; offset += 1; } @@ -176,9 +213,16 @@ macro_rules! ascii_alu { #[allow(unused_macros)] macro_rules! basic_latin_alu { ($name:ident, + // safety invariant: use u8 for src/dest for ascii, and u16 for basic_latin $src_unit:ty, $dst_unit:ty, + // safety invariant: stride function must munch ALU_STRIDE_SIZE*size(src_unit) bytes off of src and + // write ALU_STRIDE_SIZE*size(dst_unit) bytes to dst $stride_fn:ident) => { + /// Safety: src and dst must have len elements, src is valid for read, dst is valid for + /// write + /// Safety-usable invariant: will return Some() when it fails + /// to convert. The first value will be a u8 that is > 127. #[cfg_attr( feature = "cargo-clippy", allow(never_loop, cast_ptr_alignment, cast_lossless) @@ -192,6 +236,8 @@ macro_rules! basic_latin_alu { let mut offset = 0usize; // This loop is only broken out of as a `goto` forward loop { + // Safety: until_alignment becomes the number of bytes we need to munch from src/dest until we are aligned to usize + // We ensure basic-latin has the same alignment as ascii, starting with ascii since it is smaller. let mut until_alignment = { // Check if the other unit aligns if we move the narrower unit // to alignment. @@ -237,24 +283,37 @@ macro_rules! basic_latin_alu { // x86_64 should be using SSE2 in due course, keeping the move // to alignment here. It would be good to test on more ARM CPUs // and on real MIPS and POWER hardware. + // + // Safety: This is the naïve code once again, for `until_alignment` bytes while until_alignment != 0 { let code_unit = *(src.add(offset)); if code_unit > 127 { + // Safety: Upholds safety-usable invariant here return Some((code_unit, offset)); } *(dst.add(offset)) = code_unit as $dst_unit; + // Safety: offset is the number of bytes copied so far offset += 1; until_alignment -= 1; } let len_minus_stride = len - ALU_STRIDE_SIZE; loop { if !$stride_fn( + // Safety: These are known to be valid and aligned since we have at + // least ALU_STRIDE_SIZE data in these buffers, and offset is the + // number of elements copied so far, which according to the + // until_alignment calculation above will cause both src and dst to be + // aligned to usize after this add src.add(offset) as *const usize, dst.add(offset) as *mut usize, ) { break; } + // Safety: offset continues to be the number of bytes copied so far, and + // maintains usize alignment for the next loop iteration offset += ALU_STRIDE_SIZE; + // Safety: This is `offset > len - stride. This loop will continue as long as + // `offset <= len - stride`, which means there are `stride` bytes to still be read. if offset > len_minus_stride { break; } @@ -262,11 +321,15 @@ macro_rules! basic_latin_alu { } break; } + // Safety: This is the naïve code once again, for leftover bytes while offset < len { + // Safety: len invariant used here let code_unit = *(src.add(offset)); if code_unit > 127 { + // Safety: Upholds safety-usable invariant here return Some((code_unit, offset)); } + // Safety: len invariant used here *(dst.add(offset)) = code_unit as $dst_unit; offset += 1; } @@ -277,7 +340,11 @@ macro_rules! basic_latin_alu { #[allow(unused_macros)] macro_rules! latin1_alu { + // safety invariant: stride function must munch ALU_STRIDE_SIZE*size(src_unit) bytes off of src and + // write ALU_STRIDE_SIZE*size(dst_unit) bytes to dst ($name:ident, $src_unit:ty, $dst_unit:ty, $stride_fn:ident) => { + /// Safety: src and dst must have len elements, src is valid for read, dst is valid for + /// write #[cfg_attr( feature = "cargo-clippy", allow(never_loop, cast_ptr_alignment, cast_lossless) @@ -287,6 +354,8 @@ macro_rules! latin1_alu { let mut offset = 0usize; // This loop is only broken out of as a `goto` forward loop { + // Safety: until_alignment becomes the number of bytes we need to munch from src/dest until we are aligned to usize + // We ensure the UTF-16 side has the same alignment as the Latin-1 side, starting with Latin-1 since it is smaller. let mut until_alignment = { if ::core::mem::size_of::<$src_unit>() < ::core::mem::size_of::<$dst_unit>() { // unpack @@ -313,19 +382,30 @@ macro_rules! latin1_alu { } }; if until_alignment + ALU_STRIDE_SIZE <= len { + // Safety: This is the naïve code once again, for `until_alignment` bytes while until_alignment != 0 { let code_unit = *(src.add(offset)); *(dst.add(offset)) = code_unit as $dst_unit; + // Safety: offset is the number of bytes copied so far offset += 1; until_alignment -= 1; } let len_minus_stride = len - ALU_STRIDE_SIZE; loop { $stride_fn( + // Safety: These are known to be valid and aligned since we have at + // least ALU_STRIDE_SIZE data in these buffers, and offset is the + // number of elements copied so far, which according to the + // until_alignment calculation above will cause both src and dst to be + // aligned to usize after this add src.add(offset) as *const usize, dst.add(offset) as *mut usize, ); + // Safety: offset continues to be the number of bytes copied so far, and + // maintains usize alignment for the next loop iteration offset += ALU_STRIDE_SIZE; + // Safety: This is `offset > len - stride. This loop will continue as long as + // `offset <= len - stride`, which means there are `stride` bytes to still be read. if offset > len_minus_stride { break; } @@ -333,7 +413,9 @@ macro_rules! latin1_alu { } break; } + // Safety: This is the naïve code once again, for leftover bytes while offset < len { + // Safety: len invariant used here let code_unit = *(src.add(offset)); *(dst.add(offset)) = code_unit as $dst_unit; offset += 1; @@ -348,11 +430,19 @@ macro_rules! ascii_simd_check_align { $name:ident, $src_unit:ty, $dst_unit:ty, + // Safety: This function must require aligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_both_aligned:ident, + // Safety: This function must require aligned/unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_src_aligned:ident, + // Safety: This function must require unaligned/aligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_dst_aligned:ident, + // Safety: This function must require unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_neither_aligned:ident ) => { + /// Safety: src/dst must be valid for reads/writes of `len` elements of their units. + /// + /// Safety-usable invariant: will return Some() when it encounters non-ASCII, with the first element in the Some being + /// guaranteed to be non-ASCII (> 127), and the second being the offset where it is found #[inline(always)] pub unsafe fn $name( src: *const $src_unit, @@ -360,6 +450,7 @@ macro_rules! ascii_simd_check_align { len: usize, ) -> Option<($src_unit, usize)> { let mut offset = 0usize; + // Safety: if this check succeeds we're valid for reading/writing at least `SIMD_STRIDE_SIZE` elements. if SIMD_STRIDE_SIZE <= len { let len_minus_stride = len - SIMD_STRIDE_SIZE; // XXX Should we first process one stride unconditionally as unaligned to @@ -368,23 +459,29 @@ macro_rules! ascii_simd_check_align { // on Haswell, it would make sense to just use unaligned and not bother // checking. Need to benchmark older architectures before deciding. let dst_masked = (dst as usize) & SIMD_ALIGNMENT_MASK; + // Safety: checking whether src is aligned if ((src as usize) & SIMD_ALIGNMENT_MASK) == 0 { + // Safety: Checking whether dst is aligned if dst_masked == 0 { loop { + // Safety: We're valid to read/write SIMD_STRIDE_SIZE elements and have the appropriate alignments if !$stride_both_aligned(src.add(offset), dst.add(offset)) { break; } offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE` which means we always have at least `SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride { break; } } } else { loop { + // Safety: We're valid to read/write SIMD_STRIDE_SIZE elements and have the appropriate alignments if !$stride_src_aligned(src.add(offset), dst.add(offset)) { break; } offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE` which means we always have at least `SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride { break; } @@ -393,20 +490,24 @@ macro_rules! ascii_simd_check_align { } else { if dst_masked == 0 { loop { + // Safety: We're valid to read/write SIMD_STRIDE_SIZE elements and have the appropriate alignments if !$stride_dst_aligned(src.add(offset), dst.add(offset)) { break; } offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE` which means we always have at least `SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride { break; } } } else { loop { + // Safety: We're valid to read/write SIMD_STRIDE_SIZE elements and have the appropriate alignments if !$stride_neither_aligned(src.add(offset), dst.add(offset)) { break; } offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE` which means we always have at least `SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride { break; } @@ -415,8 +516,10 @@ macro_rules! ascii_simd_check_align { } } while offset < len { + // Safety: uses len invariant here and below let code_unit = *(src.add(offset)); if code_unit > 127 { + // Safety: upholds safety-usable invariant return Some((code_unit, offset)); } *(dst.add(offset)) = code_unit as $dst_unit; @@ -433,13 +536,21 @@ macro_rules! ascii_simd_check_align_unrolled { $name:ident, $src_unit:ty, $dst_unit:ty, + // Safety: This function must require aligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_both_aligned:ident, + // Safety: This function must require aligned/unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_src_aligned:ident, + // Safety: This function must require unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_neither_aligned:ident, + // Safety: This function must require aligned src/dest that are valid for reading/writing 2*SIMD_STRIDE_SIZE src_unit/dst_unit $double_stride_both_aligned:ident, + // Safety: This function must require aligned/unaligned src/dest that are valid for reading/writing 2*SIMD_STRIDE_SIZE src_unit/dst_unit $double_stride_src_aligned:ident ) => { - #[inline(always)] + /// Safety: src/dst must be valid for reads/writes of `len` elements of their units. + /// + /// Safety-usable invariant: will return Some() when it encounters non-ASCII, with the first element in the Some being + /// guaranteed to be non-ASCII (> 127), and the second being the offset where it is found #[inline(always)] pub unsafe fn $name( src: *const $src_unit, dst: *mut $dst_unit, @@ -450,8 +561,10 @@ macro_rules! ascii_simd_check_align_unrolled { // This loop is only broken out of as a goto forward without // actually looping 'outer: loop { + // Safety: if this check succeeds we're valid for reading/writing at least `SIMD_STRIDE_SIZE` elements. if SIMD_STRIDE_SIZE <= len { // First, process one unaligned + // Safety: this is safe to call since we're valid for this read/write if !$stride_neither_aligned(src, dst) { break 'outer; } @@ -461,37 +574,54 @@ macro_rules! ascii_simd_check_align_unrolled { // there will be enough more to justify more expense // in the case of non-ASCII. // Use aligned reads for the sake of old microachitectures. + // + // Safety: this correctly calculates the number of src_units that need to be read before the remaining list is aligned. + // This is less that SIMD_ALIGNMENT, which is also SIMD_STRIDE_SIZE (as documented) let until_alignment = ((SIMD_ALIGNMENT - ((src.add(offset) as usize) & SIMD_ALIGNMENT_MASK)) & SIMD_ALIGNMENT_MASK) / unit_size; - // This addition won't overflow, because even in the 32-bit PAE case the + // Safety: This addition won't overflow, because even in the 32-bit PAE case the // address space holds enough code that the slice length can't be that // close to address space size. // offset now equals SIMD_STRIDE_SIZE, hence times 3 below. + // + // Safety: if this check succeeds we're valid for reading/writing at least `2 * SIMD_STRIDE_SIZE` elements plus `until_alignment`. + // The extra SIMD_STRIDE_SIZE in the condition is because `offset` is already `SIMD_STRIDE_SIZE`. if until_alignment + (SIMD_STRIDE_SIZE * 3) <= len { if until_alignment != 0 { + // Safety: this is safe to call since we're valid for this read/write (and more), and don't care about alignment + // This will copy over bytes that get decoded twice since it's not incrementing `offset` by SIMD_STRIDE_SIZE. This is fine. if !$stride_neither_aligned(src.add(offset), dst.add(offset)) { break; } offset += until_alignment; } + // Safety: At this point we're valid for reading/writing 2*SIMD_STRIDE_SIZE elements + // Safety: Now `offset` is aligned for `src` let len_minus_stride_times_two = len - (SIMD_STRIDE_SIZE * 2); + // Safety: This is whether dst is aligned let dst_masked = (dst.add(offset) as usize) & SIMD_ALIGNMENT_MASK; if dst_masked == 0 { loop { + // Safety: both are aligned, we can call the aligned function. We're valid for reading/writing double stride from the initial condition + // and the loop break condition below if let Some(advance) = $double_stride_both_aligned(src.add(offset), dst.add(offset)) { offset += advance; let code_unit = *(src.add(offset)); + // Safety: uses safety-usable invariant on ascii_to_ascii_simd_double_stride to return + // guaranteed non-ascii return Some((code_unit, offset)); } offset += SIMD_STRIDE_SIZE * 2; + // Safety: This is `offset > len - 2 * SIMD_STRIDE_SIZE` which means we always have at least `2 * SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride_times_two { break; } } + // Safety: We're valid for reading/writing one more, and can still assume alignment if offset + SIMD_STRIDE_SIZE <= len { if !$stride_both_aligned(src.add(offset), dst.add(offset)) { break 'outer; @@ -500,18 +630,25 @@ macro_rules! ascii_simd_check_align_unrolled { } } else { loop { + // Safety: only src is aligned here. We're valid for reading/writing double stride from the initial condition + // and the loop break condition below if let Some(advance) = $double_stride_src_aligned(src.add(offset), dst.add(offset)) { offset += advance; let code_unit = *(src.add(offset)); + // Safety: uses safety-usable invariant on ascii_to_ascii_simd_double_stride to return + // guaranteed non-ascii return Some((code_unit, offset)); } offset += SIMD_STRIDE_SIZE * 2; + // Safety: This is `offset > len - 2 * SIMD_STRIDE_SIZE` which means we always have at least `2 * SIMD_STRIDE_SIZE` elements to munch next time. + if offset > len_minus_stride_times_two { break; } } + // Safety: We're valid for reading/writing one more, and can still assume alignment if offset + SIMD_STRIDE_SIZE <= len { if !$stride_src_aligned(src.add(offset), dst.add(offset)) { break 'outer; @@ -522,11 +659,13 @@ macro_rules! ascii_simd_check_align_unrolled { } else { // At most two iterations, so unroll if offset + SIMD_STRIDE_SIZE <= len { + // Safety: The check above ensures we're allowed to read/write this, and we don't use alignment if !$stride_neither_aligned(src.add(offset), dst.add(offset)) { break; } offset += SIMD_STRIDE_SIZE; if offset + SIMD_STRIDE_SIZE <= len { + // Safety: The check above ensures we're allowed to read/write this, and we don't use alignment if !$stride_neither_aligned(src.add(offset), dst.add(offset)) { break; } @@ -538,8 +677,10 @@ macro_rules! ascii_simd_check_align_unrolled { break 'outer; } while offset < len { + // Safety: relies straightforwardly on the `len` invariant let code_unit = *(src.add(offset)); if code_unit > 127 { + // Safety-usable invariant upheld here return Some((code_unit, offset)); } *(dst.add(offset)) = code_unit as $dst_unit; @@ -556,30 +697,45 @@ macro_rules! latin1_simd_check_align { $name:ident, $src_unit:ty, $dst_unit:ty, + // Safety: This function must require aligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_both_aligned:ident, + // Safety: This function must require aligned/unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_src_aligned:ident, + // Safety: This function must require unaligned/aligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_dst_aligned:ident, + // Safety: This function must require unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_neither_aligned:ident + ) => { + /// Safety: src/dst must be valid for reads/writes of `len` elements of their units. #[inline(always)] pub unsafe fn $name(src: *const $src_unit, dst: *mut $dst_unit, len: usize) { let mut offset = 0usize; + // Safety: if this check succeeds we're valid for reading/writing at least `SIMD_STRIDE_SIZE` elements. if SIMD_STRIDE_SIZE <= len { let len_minus_stride = len - SIMD_STRIDE_SIZE; + // Whether dst is aligned let dst_masked = (dst as usize) & SIMD_ALIGNMENT_MASK; + // Whether src is aligned if ((src as usize) & SIMD_ALIGNMENT_MASK) == 0 { if dst_masked == 0 { loop { + // Safety: Both were aligned, we can use the aligned function $stride_both_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE`, which means in the next iteration we're valid for + // reading/writing at least SIMD_STRIDE_SIZE elements. if offset > len_minus_stride { break; } } } else { loop { + // Safety: src was aligned, dst was not $stride_src_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE`, which means in the next iteration we're valid for + // reading/writing at least SIMD_STRIDE_SIZE elements. if offset > len_minus_stride { break; } @@ -588,16 +744,22 @@ macro_rules! latin1_simd_check_align { } else { if dst_masked == 0 { loop { + // Safety: src was aligned, dst was not $stride_dst_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE`, which means in the next iteration we're valid for + // reading/writing at least SIMD_STRIDE_SIZE elements. if offset > len_minus_stride { break; } } } else { loop { + // Safety: Neither were aligned $stride_neither_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE`, which means in the next iteration we're valid for + // reading/writing at least SIMD_STRIDE_SIZE elements. if offset > len_minus_stride { break; } @@ -606,6 +768,7 @@ macro_rules! latin1_simd_check_align { } } while offset < len { + // Safety: relies straightforwardly on the `len` invariant let code_unit = *(src.add(offset)); *(dst.add(offset)) = code_unit as $dst_unit; offset += 1; @@ -620,56 +783,74 @@ macro_rules! latin1_simd_check_align_unrolled { $name:ident, $src_unit:ty, $dst_unit:ty, + // Safety: This function must require aligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_both_aligned:ident, + // Safety: This function must require aligned/unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_src_aligned:ident, + // Safety: This function must require unaligned/aligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_dst_aligned:ident, + // Safety: This function must require unaligned src/dest that are valid for reading/writing SIMD_STRIDE_SIZE src_unit/dst_unit $stride_neither_aligned:ident ) => { + /// Safety: src/dst must be valid for reads/writes of `len` elements of their units. #[inline(always)] pub unsafe fn $name(src: *const $src_unit, dst: *mut $dst_unit, len: usize) { let unit_size = ::core::mem::size_of::<$src_unit>(); let mut offset = 0usize; + // Safety: if this check succeeds we're valid for reading/writing at least `SIMD_STRIDE_SIZE` elements. if SIMD_STRIDE_SIZE <= len { + // Safety: this correctly calculates the number of src_units that need to be read before the remaining list is aligned. + // This is by definition less than SIMD_STRIDE_SIZE. let mut until_alignment = ((SIMD_STRIDE_SIZE - ((src as usize) & SIMD_ALIGNMENT_MASK)) & SIMD_ALIGNMENT_MASK) / unit_size; while until_alignment != 0 { + // Safety: This is a straightforward copy, since until_alignment is < SIMD_STRIDE_SIZE < len, this is in-bounds *(dst.add(offset)) = *(src.add(offset)) as $dst_unit; offset += 1; until_alignment -= 1; } + // Safety: here offset will be `until_alignment`, i.e. enough to align `src`. let len_minus_stride = len - SIMD_STRIDE_SIZE; + // Safety: if this check succeeds we're valid for reading/writing at least `2 * SIMD_STRIDE_SIZE` elements. if offset + SIMD_STRIDE_SIZE * 2 <= len { let len_minus_stride_times_two = len_minus_stride - SIMD_STRIDE_SIZE; + // Safety: at this point src is known to be aligned at offset, dst is not. if (dst.add(offset) as usize) & SIMD_ALIGNMENT_MASK == 0 { loop { + // Safety: We checked alignment of dst above, we can use the alignment functions. We're allowed to read/write 2*SIMD_STRIDE_SIZE elements, which we do. $stride_both_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; $stride_both_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - 2 * SIMD_STRIDE_SIZE` which means we always have at least `2 * SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride_times_two { break; } } } else { loop { + // Safety: we ensured alignment of src already. $stride_src_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; $stride_src_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - 2 * SIMD_STRIDE_SIZE` which means we always have at least `2 * SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride_times_two { break; } } } } + // Safety: This is `offset > len - SIMD_STRIDE_SIZE` which means we are valid to munch SIMD_STRIDE_SIZE more elements, which we do if offset < len_minus_stride { $stride_src_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; } } while offset < len { + // Safety: uses len invariant here and below let code_unit = *(src.add(offset)); // On x86_64, this loop autovectorizes but in the pack // case there are instructions whose purpose is to make sure @@ -693,7 +874,12 @@ macro_rules! latin1_simd_check_align_unrolled { #[allow(unused_macros)] macro_rules! ascii_simd_unalign { + // Safety: stride_neither_aligned must be a function that requires src/dest be valid for unaligned reads/writes for SIMD_STRIDE_SIZE elements of type src_unit/dest_unit ($name:ident, $src_unit:ty, $dst_unit:ty, $stride_neither_aligned:ident) => { + /// Safety: src and dst must be valid for reads/writes of len elements of type src_unit/dst_unit + /// + /// Safety-usable invariant: will return Some() when it encounters non-ASCII, with the first element in the Some being + /// guaranteed to be non-ASCII (> 127), and the second being the offset where it is found #[inline(always)] pub unsafe fn $name( src: *const $src_unit, @@ -701,21 +887,26 @@ macro_rules! ascii_simd_unalign { len: usize, ) -> Option<($src_unit, usize)> { let mut offset = 0usize; + // Safety: if this check succeeds we're valid for reading/writing at least `stride` elements. if SIMD_STRIDE_SIZE <= len { let len_minus_stride = len - SIMD_STRIDE_SIZE; loop { + // Safety: We know we're valid for `stride` reads/writes, so we can call this function. We don't need alignment. if !$stride_neither_aligned(src.add(offset), dst.add(offset)) { break; } offset += SIMD_STRIDE_SIZE; + // This is `offset > len - stride` which means we always have at least `stride` elements to munch next time. if offset > len_minus_stride { break; } } } while offset < len { + // Safety: Uses len invariant here and below let code_unit = *(src.add(offset)); if code_unit > 127 { + // Safety-usable invariant upheld here return Some((code_unit, offset)); } *(dst.add(offset)) = code_unit as $dst_unit; @@ -728,21 +919,27 @@ macro_rules! ascii_simd_unalign { #[allow(unused_macros)] macro_rules! latin1_simd_unalign { + // Safety: stride_neither_aligned must be a function that requires src/dest be valid for unaligned reads/writes for SIMD_STRIDE_SIZE elements of type src_unit/dest_unit ($name:ident, $src_unit:ty, $dst_unit:ty, $stride_neither_aligned:ident) => { + /// Safety: src and dst must be valid for unaligned reads/writes of len elements of type src_unit/dst_unit #[inline(always)] pub unsafe fn $name(src: *const $src_unit, dst: *mut $dst_unit, len: usize) { let mut offset = 0usize; + // Safety: if this check succeeds we're valid for reading/writing at least `stride` elements. if SIMD_STRIDE_SIZE <= len { let len_minus_stride = len - SIMD_STRIDE_SIZE; loop { + // Safety: We know we're valid for `stride` reads/writes, so we can call this function. We don't need alignment. $stride_neither_aligned(src.add(offset), dst.add(offset)); offset += SIMD_STRIDE_SIZE; + // This is `offset > len - stride` which means we always have at least `stride` elements to munch next time. if offset > len_minus_stride { break; } } } while offset < len { + // Safety: Uses len invariant here let code_unit = *(src.add(offset)); *(dst.add(offset)) = code_unit as $dst_unit; offset += 1; @@ -753,7 +950,11 @@ macro_rules! latin1_simd_unalign { #[allow(unused_macros)] macro_rules! ascii_to_ascii_simd_stride { + // Safety: load/store must be valid for 16 bytes of read/write, which may be unaligned. (candidates: `(load|store)(16|8)_(unaligned|aligned)` functions) ($name:ident, $load:ident, $store:ident) => { + /// Safety: src and dst must be valid for 16 bytes of read/write according to + /// the $load/$store fn, which may allow for unaligned reads/writes or require + /// alignment to either 16x8 or u8x16. #[inline(always)] pub unsafe fn $name(src: *const u8, dst: *mut u8) -> bool { let simd = $load(src); @@ -768,19 +969,32 @@ macro_rules! ascii_to_ascii_simd_stride { #[allow(unused_macros)] macro_rules! ascii_to_ascii_simd_double_stride { + // Safety: store must be valid for 32 bytes of write, which may be unaligned (candidates: `store(8|16)_(aligned|unaligned)`) ($name:ident, $store:ident) => { + /// Safety: src must be valid for 32 bytes of aligned u8x16 read + /// dst must be valid for 32 bytes of unaligned write according to + /// the $store fn, which may allow for unaligned writes or require + /// alignment to either 16x8 or u8x16. + /// + /// Safety-usable invariant: Returns Some(index) if the element at `index` is invalid ASCII #[inline(always)] pub unsafe fn $name(src: *const u8, dst: *mut u8) -> Option { let first = load16_aligned(src); let second = load16_aligned(src.add(SIMD_STRIDE_SIZE)); $store(dst, first); if unlikely(!simd_is_ascii(first | second)) { + // Safety: mask_ascii produces a mask of all the high bits. let mask_first = mask_ascii(first); if mask_first != 0 { + // Safety: on little endian systems this will be the number of ascii bytes + // before the first non-ascii, i.e. valid for indexing src + // TODO SAFETY: What about big-endian systems? return Some(mask_first.trailing_zeros() as usize); } $store(dst.add(SIMD_STRIDE_SIZE), second); let mask_second = mask_ascii(second); + // Safety: on little endian systems this will be the number of ascii bytes + // before the first non-ascii, i.e. valid for indexing src return Some(SIMD_STRIDE_SIZE + mask_second.trailing_zeros() as usize); } $store(dst.add(SIMD_STRIDE_SIZE), second); @@ -791,7 +1005,11 @@ macro_rules! ascii_to_ascii_simd_double_stride { #[allow(unused_macros)] macro_rules! ascii_to_basic_latin_simd_stride { + // Safety: load/store must be valid for 16 bytes of read/write, which may be unaligned. (candidates: `(load|store)(16|8)_(unaligned|aligned)` functions) ($name:ident, $load:ident, $store:ident) => { + /// Safety: src and dst must be valid for 16/32 bytes of read/write according to + /// the $load/$store fn, which may allow for unaligned reads/writes or require + /// alignment to either 16x8 or u8x16. #[inline(always)] pub unsafe fn $name(src: *const u8, dst: *mut u16) -> bool { let simd = $load(src); @@ -808,13 +1026,18 @@ macro_rules! ascii_to_basic_latin_simd_stride { #[allow(unused_macros)] macro_rules! ascii_to_basic_latin_simd_double_stride { + // Safety: store must be valid for 16 bytes of write, which may be unaligned ($name:ident, $store:ident) => { + /// Safety: src must be valid for 2*SIMD_STRIDE_SIZE bytes of aligned reads, + /// aligned to either 16x8 or u8x16. + /// dst must be valid for 2*SIMD_STRIDE_SIZE bytes of aligned or unaligned reads #[inline(always)] pub unsafe fn $name(src: *const u8, dst: *mut u16) -> Option { let first = load16_aligned(src); let second = load16_aligned(src.add(SIMD_STRIDE_SIZE)); let (a, b) = simd_unpack(first); $store(dst, a); + // Safety: divide by 2 since it's a u16 pointer $store(dst.add(SIMD_STRIDE_SIZE / 2), b); if unlikely(!simd_is_ascii(first | second)) { let mask_first = mask_ascii(first); @@ -837,7 +1060,11 @@ macro_rules! ascii_to_basic_latin_simd_double_stride { #[allow(unused_macros)] macro_rules! unpack_simd_stride { + // Safety: load/store must be valid for 16 bytes of read/write, which may be unaligned. (candidates: `(load|store)(16|8)_(unaligned|aligned)` functions) ($name:ident, $load:ident, $store:ident) => { + /// Safety: src and dst must be valid for 16 bytes of read/write according to + /// the $load/$store fn, which may allow for unaligned reads/writes or require + /// alignment to either 16x8 or u8x16. #[inline(always)] pub unsafe fn $name(src: *const u8, dst: *mut u16) { let simd = $load(src); @@ -850,7 +1077,11 @@ macro_rules! unpack_simd_stride { #[allow(unused_macros)] macro_rules! basic_latin_to_ascii_simd_stride { + // Safety: load/store must be valid for 16 bytes of read/write, which may be unaligned. (candidates: `(load|store)(16|8)_(unaligned|aligned)` functions) ($name:ident, $load:ident, $store:ident) => { + /// Safety: src and dst must be valid for 32/16 bytes of read/write according to + /// the $load/$store fn, which may allow for unaligned reads/writes or require + /// alignment to either 16x8 or u8x16. #[inline(always)] pub unsafe fn $name(src: *const u16, dst: *mut u8) -> bool { let first = $load(src); @@ -867,7 +1098,11 @@ macro_rules! basic_latin_to_ascii_simd_stride { #[allow(unused_macros)] macro_rules! pack_simd_stride { + // Safety: load/store must be valid for 16 bytes of read/write, which may be unaligned. (candidates: `(load|store)(16|8)_(unaligned|aligned)` functions) ($name:ident, $load:ident, $store:ident) => { + /// Safety: src and dst must be valid for 32/16 bytes of read/write according to + /// the $load/$store fn, which may allow for unaligned reads/writes or require + /// alignment to either 16x8 or u8x16. #[inline(always)] pub unsafe fn $name(src: *const u16, dst: *mut u8) { let first = $load(src); @@ -893,6 +1128,8 @@ cfg_if! { pub const ALU_ALIGNMENT_MASK: usize = 7; + // Safety for stride macros: We stick to the load8_aligned/etc family of functions. We consistently produce + // neither_unaligned variants using only unaligned inputs. ascii_to_ascii_simd_stride!(ascii_to_ascii_stride_neither_aligned, load16_unaligned, store16_unaligned); ascii_to_basic_latin_simd_stride!(ascii_to_basic_latin_stride_neither_aligned, load16_unaligned, store8_unaligned); @@ -901,6 +1138,8 @@ cfg_if! { basic_latin_to_ascii_simd_stride!(basic_latin_to_ascii_stride_neither_aligned, load8_unaligned, store16_unaligned); pack_simd_stride!(pack_stride_neither_aligned, load8_unaligned, store16_unaligned); + // Safety for conversion macros: We use the unalign macro with unalign functions above. All stride functions were produced + // by stride macros that universally munch a single SIMD_STRIDE_SIZE worth of elements. ascii_simd_unalign!(ascii_to_ascii, u8, u8, ascii_to_ascii_stride_neither_aligned); ascii_simd_unalign!(ascii_to_basic_latin, u8, u16, ascii_to_basic_latin_stride_neither_aligned); ascii_simd_unalign!(basic_latin_to_ascii, u16, u8, basic_latin_to_ascii_stride_neither_aligned); @@ -919,6 +1158,9 @@ cfg_if! { pub const SIMD_ALIGNMENT_MASK: usize = 15; + // Safety for stride macros: We stick to the load8_aligned/etc family of functions. We consistently name + // aligned/unaligned functions according to src/dst being aligned/unaligned + ascii_to_ascii_simd_stride!(ascii_to_ascii_stride_both_aligned, load16_aligned, store16_aligned); ascii_to_ascii_simd_stride!(ascii_to_ascii_stride_src_aligned, load16_aligned, store16_unaligned); ascii_to_ascii_simd_stride!(ascii_to_ascii_stride_dst_aligned, load16_unaligned, store16_aligned); @@ -944,6 +1186,9 @@ cfg_if! { pack_simd_stride!(pack_stride_dst_aligned, load8_unaligned, store16_aligned); pack_simd_stride!(pack_stride_neither_aligned, load8_unaligned, store16_unaligned); + // Safety for conversion macros: We use the correct pattern of both/src/dst/neither here. All stride functions were produced + // by stride macros that universally munch a single SIMD_STRIDE_SIZE worth of elements. + ascii_simd_check_align!(ascii_to_ascii, u8, u8, ascii_to_ascii_stride_both_aligned, ascii_to_ascii_stride_src_aligned, ascii_to_ascii_stride_dst_aligned, ascii_to_ascii_stride_neither_aligned); ascii_simd_check_align!(ascii_to_basic_latin, u8, u16, ascii_to_basic_latin_stride_both_aligned, ascii_to_basic_latin_stride_src_aligned, ascii_to_basic_latin_stride_dst_aligned, ascii_to_basic_latin_stride_neither_aligned); ascii_simd_check_align!(basic_latin_to_ascii, u16, u8, basic_latin_to_ascii_stride_both_aligned, basic_latin_to_ascii_stride_src_aligned, basic_latin_to_ascii_stride_dst_aligned, basic_latin_to_ascii_stride_neither_aligned); @@ -958,12 +1203,16 @@ cfg_if! { pub const SIMD_STRIDE_SIZE: usize = 16; + /// Safety-usable invariant: This should be identical to SIMD_STRIDE_SIZE (used by ascii_simd_check_align_unrolled) pub const SIMD_ALIGNMENT: usize = 16; pub const MAX_STRIDE_SIZE: usize = 16; pub const SIMD_ALIGNMENT_MASK: usize = 15; + // Safety for stride macros: We stick to the load8_aligned/etc family of functions. We consistently name + // aligned/unaligned functions according to src/dst being aligned/unaligned + ascii_to_ascii_simd_double_stride!(ascii_to_ascii_simd_double_stride_both_aligned, store16_aligned); ascii_to_ascii_simd_double_stride!(ascii_to_ascii_simd_double_stride_src_aligned, store16_unaligned); @@ -989,6 +1238,9 @@ cfg_if! { pack_simd_stride!(pack_stride_both_aligned, load8_aligned, store16_aligned); pack_simd_stride!(pack_stride_src_aligned, load8_aligned, store16_unaligned); + // Safety for conversion macros: We use the correct pattern of both/src/dst/neither/double_both/double_src here. All stride functions were produced + // by stride macros that universally munch a single SIMD_STRIDE_SIZE worth of elements. + ascii_simd_check_align_unrolled!(ascii_to_ascii, u8, u8, ascii_to_ascii_stride_both_aligned, ascii_to_ascii_stride_src_aligned, ascii_to_ascii_stride_neither_aligned, ascii_to_ascii_simd_double_stride_both_aligned, ascii_to_ascii_simd_double_stride_src_aligned); ascii_simd_check_align_unrolled!(ascii_to_basic_latin, u8, u16, ascii_to_basic_latin_stride_both_aligned, ascii_to_basic_latin_stride_src_aligned, ascii_to_basic_latin_stride_neither_aligned, ascii_to_basic_latin_simd_double_stride_both_aligned, ascii_to_basic_latin_simd_double_stride_src_aligned); @@ -998,14 +1250,21 @@ cfg_if! { } else if #[cfg(all(target_endian = "little", target_pointer_width = "64"))] { // Aligned ALU word, little-endian, 64-bit + /// Safety invariant: this is the amount of bytes consumed by + /// unpack_alu. This will be twice the pointer width, as it consumes two usizes. + /// This is also the number of bytes produced by pack_alu. + /// This is also the number of u16 code units produced/consumed by unpack_alu/pack_alu respectively. pub const ALU_STRIDE_SIZE: usize = 16; pub const MAX_STRIDE_SIZE: usize = 16; + // Safety invariant: this is the pointer width in bytes pub const ALU_ALIGNMENT: usize = 8; + // Safety invariant: this is a mask for getting the bits of a pointer not aligned to ALU_ALIGNMENT pub const ALU_ALIGNMENT_MASK: usize = 7; + /// Safety: dst must point to valid space for writing four `usize`s #[inline(always)] unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) { let first = ((0x0000_0000_FF00_0000usize & word) << 24) | @@ -1024,12 +1283,14 @@ cfg_if! { ((0x00FF_0000_0000_0000usize & second_word) >> 16) | ((0x0000_FF00_0000_0000usize & second_word) >> 24) | ((0x0000_00FF_0000_0000usize & second_word) >> 32); + // Safety: fn invariant used here *dst = first; *(dst.add(1)) = second; *(dst.add(2)) = third; *(dst.add(3)) = fourth; } + /// Safety: dst must point to valid space for writing two `usize`s #[inline(always)] unsafe fn pack_alu(first: usize, second: usize, third: usize, fourth: usize, dst: *mut usize) { let word = ((0x00FF_0000_0000_0000usize & second) << 8) | @@ -1048,20 +1309,28 @@ cfg_if! { ((0x0000_00FF_0000_0000usize & third) >> 16) | ((0x0000_0000_00FF_0000usize & third) >> 8) | (0x0000_0000_0000_00FFusize & third); + // Safety: fn invariant used here *dst = word; *(dst.add(1)) = second_word; } } else if #[cfg(all(target_endian = "little", target_pointer_width = "32"))] { // Aligned ALU word, little-endian, 32-bit + /// Safety invariant: this is the amount of bytes consumed by + /// unpack_alu. This will be twice the pointer width, as it consumes two usizes. + /// This is also the number of bytes produced by pack_alu. + /// This is also the number of u16 code units produced/consumed by unpack_alu/pack_alu respectively. pub const ALU_STRIDE_SIZE: usize = 8; pub const MAX_STRIDE_SIZE: usize = 8; + // Safety invariant: this is the pointer width in bytes pub const ALU_ALIGNMENT: usize = 4; + // Safety invariant: this is a mask for getting the bits of a pointer not aligned to ALU_ALIGNMENT pub const ALU_ALIGNMENT_MASK: usize = 3; + /// Safety: dst must point to valid space for writing four `usize`s #[inline(always)] unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) { let first = ((0x0000_FF00usize & word) << 8) | @@ -1072,12 +1341,14 @@ cfg_if! { (0x0000_00FFusize & second_word); let fourth = ((0xFF00_0000usize & second_word) >> 8) | ((0x00FF_0000usize & second_word) >> 16); + // Safety: fn invariant used here *dst = first; *(dst.add(1)) = second; *(dst.add(2)) = third; *(dst.add(3)) = fourth; } + /// Safety: dst must point to valid space for writing two `usize`s #[inline(always)] unsafe fn pack_alu(first: usize, second: usize, third: usize, fourth: usize, dst: *mut usize) { let word = ((0x00FF_0000usize & second) << 8) | @@ -1088,20 +1359,28 @@ cfg_if! { ((0x0000_00FFusize & fourth) << 16) | ((0x00FF_0000usize & third) >> 8) | (0x0000_00FFusize & third); + // Safety: fn invariant used here *dst = word; *(dst.add(1)) = second_word; } } else if #[cfg(all(target_endian = "big", target_pointer_width = "64"))] { // Aligned ALU word, big-endian, 64-bit + /// Safety invariant: this is the amount of bytes consumed by + /// unpack_alu. This will be twice the pointer width, as it consumes two usizes. + /// This is also the number of bytes produced by pack_alu. + /// This is also the number of u16 code units produced/consumed by unpack_alu/pack_alu respectively. pub const ALU_STRIDE_SIZE: usize = 16; pub const MAX_STRIDE_SIZE: usize = 16; + // Safety invariant: this is the pointer width in bytes pub const ALU_ALIGNMENT: usize = 8; + // Safety invariant: this is a mask for getting the bits of a pointer not aligned to ALU_ALIGNMENT pub const ALU_ALIGNMENT_MASK: usize = 7; + /// Safety: dst must point to valid space for writing four `usize`s #[inline(always)] unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) { let first = ((0xFF00_0000_0000_0000usize & word) >> 8) | @@ -1120,12 +1399,14 @@ cfg_if! { ((0x0000_0000_00FF_0000usize & second_word) << 16) | ((0x0000_0000_0000_FF00usize & second_word) << 8) | (0x0000_0000_0000_00FFusize & second_word); + // Safety: fn invariant used here *dst = first; *(dst.add(1)) = second; *(dst.add(2)) = third; *(dst.add(3)) = fourth; } + /// Safety: dst must point to valid space for writing two `usize`s #[inline(always)] unsafe fn pack_alu(first: usize, second: usize, third: usize, fourth: usize, dst: *mut usize) { let word = ((0x00FF0000_00000000usize & first) << 8) | @@ -1144,20 +1425,28 @@ cfg_if! { ((0x000000FF_00000000usize & fourth) >> 16) | ((0x00000000_00FF0000usize & fourth) >> 8) | (0x00000000_000000FFusize & fourth); + // Safety: fn invariant used here *dst = word; *(dst.add(1)) = second_word; } } else if #[cfg(all(target_endian = "big", target_pointer_width = "32"))] { // Aligned ALU word, big-endian, 32-bit + /// Safety invariant: this is the amount of bytes consumed by + /// unpack_alu. This will be twice the pointer width, as it consumes two usizes. + /// This is also the number of bytes produced by pack_alu. + /// This is also the number of u16 code units produced/consumed by unpack_alu/pack_alu respectively. pub const ALU_STRIDE_SIZE: usize = 8; pub const MAX_STRIDE_SIZE: usize = 8; + // Safety invariant: this is the pointer width in bytes pub const ALU_ALIGNMENT: usize = 4; + // Safety invariant: this is a mask for getting the bits of a pointer not aligned to ALU_ALIGNMENT pub const ALU_ALIGNMENT_MASK: usize = 3; + /// Safety: dst must point to valid space for writing four `usize`s #[inline(always)] unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) { let first = ((0xFF00_0000usize & word) >> 8) | @@ -1168,12 +1457,14 @@ cfg_if! { ((0x00FF_0000usize & second_word) >> 16); let fourth = ((0x0000_FF00usize & second_word) << 8) | (0x0000_00FFusize & second_word); + // Safety: fn invariant used here *dst = first; *(dst.add(1)) = second; *(dst.add(2)) = third; *(dst.add(3)) = fourth; } + /// Safety: dst must point to valid space for writing two `usize`s #[inline(always)] unsafe fn pack_alu(first: usize, second: usize, third: usize, fourth: usize, dst: *mut usize) { let word = ((0x00FF_0000usize & first) << 8) | @@ -1184,6 +1475,7 @@ cfg_if! { ((0x0000_00FFusize & third) << 16) | ((0x00FF_0000usize & fourth) >> 8) | (0x0000_00FFusize & fourth); + // Safety: fn invariant used here *dst = word; *(dst.add(1)) = second_word; } @@ -1195,6 +1487,8 @@ cfg_if! { } cfg_if! { + // Safety-usable invariant: this counts the zeroes from the "first byte" of utf-8 data packed into a usize + // with the target endianness if #[cfg(target_endian = "little")] { #[allow(dead_code)] #[inline(always)] @@ -1212,19 +1506,24 @@ cfg_if! { cfg_if! { if #[cfg(all(feature = "simd-accel", target_endian = "little", target_arch = "disabled"))] { + /// Safety-usable invariant: Will return the value and position of the first non-ASCII byte in the slice in a Some if found. + /// In other words, the first element of the Some is always `> 127` #[inline(always)] pub fn validate_ascii(slice: &[u8]) -> Option<(u8, usize)> { let src = slice.as_ptr(); let len = slice.len(); let mut offset = 0usize; + // Safety: if this check succeeds we're valid for reading/writing at least `stride` elements. if SIMD_STRIDE_SIZE <= len { let len_minus_stride = len - SIMD_STRIDE_SIZE; loop { + // Safety: src at offset is valid for a `SIMD_STRIDE_SIZE` read let simd = unsafe { load16_unaligned(src.add(offset)) }; if !simd_is_ascii(simd) { break; } offset += SIMD_STRIDE_SIZE; + // This is `offset > len - SIMD_STRIDE_SIZE` which means we always have at least `SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride { break; } @@ -1233,6 +1532,7 @@ cfg_if! { while offset < len { let code_unit = slice[offset]; if code_unit > 127 { + // Safety: Safety-usable invariant upheld here return Some((code_unit, offset)); } offset += 1; @@ -1240,13 +1540,17 @@ cfg_if! { None } } else if #[cfg(all(feature = "simd-accel", target_feature = "sse2"))] { + /// Safety-usable invariant: will return Some() when it encounters non-ASCII, with the first element in the Some being + /// guaranteed to be non-ASCII (> 127), and the second being the offset where it is found #[inline(always)] pub fn validate_ascii(slice: &[u8]) -> Option<(u8, usize)> { let src = slice.as_ptr(); let len = slice.len(); let mut offset = 0usize; + // Safety: if this check succeeds we're valid for reading at least `stride` elements. if SIMD_STRIDE_SIZE <= len { // First, process one unaligned vector + // Safety: src is valid for a `SIMD_STRIDE_SIZE` read let simd = unsafe { load16_unaligned(src) }; let mask = mask_ascii(simd); if mask != 0 { @@ -1255,18 +1559,26 @@ cfg_if! { return Some((non_ascii, offset)); } offset = SIMD_STRIDE_SIZE; + // Safety: Now that offset has changed we don't yet know how much it is valid for // We have now seen 16 ASCII bytes. Let's guess that // there will be enough more to justify more expense // in the case of non-ASCII. // Use aligned reads for the sake of old microachitectures. + // Safety: this correctly calculates the number of src_units that need to be read before the remaining list is aligned. + // This is by definition less than SIMD_ALIGNMENT, which is defined to be equal to SIMD_STRIDE_SIZE. let until_alignment = unsafe { (SIMD_ALIGNMENT - ((src.add(offset) as usize) & SIMD_ALIGNMENT_MASK)) & SIMD_ALIGNMENT_MASK }; // This addition won't overflow, because even in the 32-bit PAE case the // address space holds enough code that the slice length can't be that // close to address space size. // offset now equals SIMD_STRIDE_SIZE, hence times 3 below. + // + // Safety: if this check succeeds we're valid for reading at least `2 * SIMD_STRIDE_SIZE` elements plus `until_alignment`. + // The extra SIMD_STRIDE_SIZE in the condition is because `offset` is already `SIMD_STRIDE_SIZE`. if until_alignment + (SIMD_STRIDE_SIZE * 3) <= len { if until_alignment != 0 { + // Safety: this is safe to call since we're valid for this read (and more), and don't care about alignment + // This will copy over bytes that get decoded twice since it's not incrementing `offset` by SIMD_STRIDE_SIZE. This is fine. let simd = unsafe { load16_unaligned(src.add(offset)) }; let mask = mask_ascii(simd); if mask != 0 { @@ -1276,53 +1588,78 @@ cfg_if! { } offset += until_alignment; } + // Safety: At this point we're valid for reading 2*SIMD_STRIDE_SIZE elements + // Safety: Now `offset` is aligned for `src` let len_minus_stride_times_two = len - (SIMD_STRIDE_SIZE * 2); loop { + // Safety: We were valid for this read, and were aligned. let first = unsafe { load16_aligned(src.add(offset)) }; let second = unsafe { load16_aligned(src.add(offset + SIMD_STRIDE_SIZE)) }; if !simd_is_ascii(first | second) { + // Safety: mask_ascii produces a mask of all the high bits. let mask_first = mask_ascii(first); if mask_first != 0 { + // Safety: on little endian systems this will be the number of ascii bytes + // before the first non-ascii, i.e. valid for indexing src + // TODO SAFETY: What about big-endian systems? offset += mask_first.trailing_zeros() as usize; } else { let mask_second = mask_ascii(second); + // Safety: on little endian systems this will be the number of ascii bytes + // before the first non-ascii, i.e. valid for indexing src offset += SIMD_STRIDE_SIZE + mask_second.trailing_zeros() as usize; } + // Safety: We know this is non-ASCII, and can uphold the safety-usable invariant here let non_ascii = unsafe { *src.add(offset) }; + return Some((non_ascii, offset)); } offset += SIMD_STRIDE_SIZE * 2; + // Safety: This is `offset > len - 2 * SIMD_STRIDE_SIZE` which means we always have at least `2 * SIMD_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride_times_two { break; } } + // Safety: if this check succeeds we're valid for reading at least `SIMD_STRIDE_SIZE` if offset + SIMD_STRIDE_SIZE <= len { - let simd = unsafe { load16_aligned(src.add(offset)) }; - let mask = mask_ascii(simd); + // Safety: We were valid for this read, and were aligned. + let simd = unsafe { load16_aligned(src.add(offset)) }; + // Safety: mask_ascii produces a mask of all the high bits. + let mask = mask_ascii(simd); if mask != 0 { + // Safety: on little endian systems this will be the number of ascii bytes + // before the first non-ascii, i.e. valid for indexing src offset += mask.trailing_zeros() as usize; let non_ascii = unsafe { *src.add(offset) }; + // Safety: We know this is non-ASCII, and can uphold the safety-usable invariant here return Some((non_ascii, offset)); } offset += SIMD_STRIDE_SIZE; } } else { + // Safety: this is the unaligned branch // At most two iterations, so unroll + // Safety: if this check succeeds we're valid for reading at least `SIMD_STRIDE_SIZE` if offset + SIMD_STRIDE_SIZE <= len { + // Safety: We're valid for this read but must use an unaligned read let simd = unsafe { load16_unaligned(src.add(offset)) }; let mask = mask_ascii(simd); if mask != 0 { offset += mask.trailing_zeros() as usize; let non_ascii = unsafe { *src.add(offset) }; + // Safety-usable invariant upheld here (same as above) return Some((non_ascii, offset)); } offset += SIMD_STRIDE_SIZE; + // Safety: if this check succeeds we're valid for reading at least `SIMD_STRIDE_SIZE` if offset + SIMD_STRIDE_SIZE <= len { + // Safety: We're valid for this read but must use an unaligned read let simd = unsafe { load16_unaligned(src.add(offset)) }; let mask = mask_ascii(simd); if mask != 0 { offset += mask.trailing_zeros() as usize; let non_ascii = unsafe { *src.add(offset) }; + // Safety-usable invariant upheld here (same as above) return Some((non_ascii, offset)); } offset += SIMD_STRIDE_SIZE; @@ -1331,8 +1668,10 @@ cfg_if! { } } while offset < len { + // Safety: relies straightforwardly on the `len` invariant let code_unit = unsafe { *(src.add(offset)) }; if code_unit > 127 { + // Safety-usable invariant upheld here return Some((code_unit, offset)); } offset += 1; @@ -1340,31 +1679,40 @@ cfg_if! { None } } else { + // Safety-usable invariant: returns byte index of first non-ascii byte #[inline(always)] fn find_non_ascii(word: usize, second_word: usize) -> Option { let word_masked = word & ASCII_MASK; let second_masked = second_word & ASCII_MASK; if (word_masked | second_masked) == 0 { + // Both are ascii, invariant upheld return None; } if word_masked != 0 { let zeros = count_zeros(word_masked); - // `zeros` now contains 7 (for the seven bits of non-ASCII) + // `zeros` now contains 0 to 7 (for the seven bits of masked ASCII in little endian, + // or up to 7 bits of non-ASCII in big endian if the first byte is non-ASCII) // plus 8 times the number of ASCII in text order before the // non-ASCII byte in the little-endian case or 8 times the number of ASCII in // text order before the non-ASCII byte in the big-endian case. let num_ascii = (zeros >> 3) as usize; + // Safety-usable invariant upheld here return Some(num_ascii); } let zeros = count_zeros(second_masked); - // `zeros` now contains 7 (for the seven bits of non-ASCII) + // `zeros` now contains 0 to 7 (for the seven bits of masked ASCII in little endian, + // or up to 7 bits of non-ASCII in big endian if the first byte is non-ASCII) // plus 8 times the number of ASCII in text order before the // non-ASCII byte in the little-endian case or 8 times the number of ASCII in // text order before the non-ASCII byte in the big-endian case. let num_ascii = (zeros >> 3) as usize; + // Safety-usable invariant upheld here Some(ALU_ALIGNMENT + num_ascii) } + /// Safety: `src` must be valid for the reads of two `usize`s + /// + /// Safety-usable invariant: will return byte index of first non-ascii byte #[inline(always)] unsafe fn validate_ascii_stride(src: *const usize) -> Option { let word = *src; @@ -1372,6 +1720,8 @@ cfg_if! { find_non_ascii(word, second_word) } + /// Safety-usable invariant: will return Some() when it encounters non-ASCII, with the first element in the Some being + /// guaranteed to be non-ASCII (> 127), and the second being the offset where it is found #[cfg_attr(feature = "cargo-clippy", allow(cast_ptr_alignment))] #[inline(always)] pub fn validate_ascii(slice: &[u8]) -> Option<(u8, usize)> { @@ -1379,23 +1729,30 @@ cfg_if! { let len = slice.len(); let mut offset = 0usize; let mut until_alignment = (ALU_ALIGNMENT - ((src as usize) & ALU_ALIGNMENT_MASK)) & ALU_ALIGNMENT_MASK; + // Safety: If this check fails we're valid to read `until_alignment + ALU_STRIDE_SIZE` elements if until_alignment + ALU_STRIDE_SIZE <= len { while until_alignment != 0 { let code_unit = slice[offset]; if code_unit > 127 { + // Safety-usable invairant upheld here return Some((code_unit, offset)); } offset += 1; until_alignment -= 1; } + // Safety: At this point we have read until_alignment elements and + // are valid for `ALU_STRIDE_SIZE` more. let len_minus_stride = len - ALU_STRIDE_SIZE; loop { + // Safety: we were valid for this read let ptr = unsafe { src.add(offset) as *const usize }; if let Some(num_ascii) = unsafe { validate_ascii_stride(ptr) } { offset += num_ascii; + // Safety-usable invairant upheld here using the invariant from validate_ascii_stride() return Some((unsafe { *(src.add(offset)) }, offset)); } offset += ALU_STRIDE_SIZE; + // Safety: This is `offset > ALU_STRIDE_SIZE` which means we always have at least `2 * ALU_STRIDE_SIZE` elements to munch next time. if offset > len_minus_stride { break; } @@ -1404,6 +1761,7 @@ cfg_if! { while offset < len { let code_unit = slice[offset]; if code_unit > 127 { + // Safety-usable invairant upheld here return Some((code_unit, offset)); } offset += 1; @@ -1428,36 +1786,47 @@ cfg_if! { pub const ALU_ALIGNMENT_MASK: usize = 3; } else { + // Safety: src points to two valid `usize`s, dst points to four valid `usize`s #[inline(always)] unsafe fn unpack_latin1_stride_alu(src: *const usize, dst: *mut usize) { + // Safety: src safety invariant used here let word = *src; let second_word = *(src.add(1)); + // Safety: dst safety invariant passed down unpack_alu(word, second_word, dst); } + // Safety: src points to four valid `usize`s, dst points to two valid `usize`s #[inline(always)] unsafe fn pack_latin1_stride_alu(src: *const usize, dst: *mut usize) { + // Safety: src safety invariant used here let first = *src; let second = *(src.add(1)); let third = *(src.add(2)); let fourth = *(src.add(3)); + // Safety: dst safety invariant passed down pack_alu(first, second, third, fourth, dst); } + // Safety: src points to two valid `usize`s, dst points to four valid `usize`s #[inline(always)] unsafe fn ascii_to_basic_latin_stride_alu(src: *const usize, dst: *mut usize) -> bool { + // Safety: src safety invariant used here let word = *src; let second_word = *(src.add(1)); // Check if the words contains non-ASCII if (word & ASCII_MASK) | (second_word & ASCII_MASK) != 0 { return false; } + // Safety: dst safety invariant passed down unpack_alu(word, second_word, dst); true } + // Safety: src points four valid `usize`s, dst points to two valid `usize`s #[inline(always)] unsafe fn basic_latin_to_ascii_stride_alu(src: *const usize, dst: *mut usize) -> bool { + // Safety: src safety invariant used here let first = *src; let second = *(src.add(1)); let third = *(src.add(2)); @@ -1465,16 +1834,22 @@ cfg_if! { if (first & BASIC_LATIN_MASK) | (second & BASIC_LATIN_MASK) | (third & BASIC_LATIN_MASK) | (fourth & BASIC_LATIN_MASK) != 0 { return false; } + // Safety: dst safety invariant passed down pack_alu(first, second, third, fourth, dst); true } + // Safety: src, dst both point to two valid `usize`s each + // Safety-usable invariant: Will return byte index of first non-ascii byte. #[inline(always)] unsafe fn ascii_to_ascii_stride(src: *const usize, dst: *mut usize) -> Option { + // Safety: src safety invariant used here let word = *src; let second_word = *(src.add(1)); + // Safety: src safety invariant used here *dst = word; *(dst.add(1)) = second_word; + // Relies on safety-usable invariant here find_non_ascii(word, second_word) } @@ -1482,6 +1857,7 @@ cfg_if! { basic_latin_alu!(basic_latin_to_ascii, u16, u8, basic_latin_to_ascii_stride_alu); latin1_alu!(unpack_latin1, u8, u16, unpack_latin1_stride_alu); latin1_alu!(pack_latin1, u16, u8, pack_latin1_stride_alu); + // Safety invariant upheld: ascii_to_ascii_stride will return byte index of first non-ascii if found ascii_alu!(ascii_to_ascii, u8, u8, ascii_to_ascii_stride); } } diff --git a/third_party/rust/encoding_rs/src/handles.rs b/third_party/rust/encoding_rs/src/handles.rs index b5404c01d9..f44a834672 100644 --- a/third_party/rust/encoding_rs/src/handles.rs +++ b/third_party/rust/encoding_rs/src/handles.rs @@ -34,7 +34,7 @@ use crate::simd_funcs::*; all(target_endian = "little", target_feature = "neon") ) ))] -use packed_simd::u16x8; +use core::simd::u16x8; use super::DecoderResult; use super::EncoderResult; @@ -90,19 +90,23 @@ impl Endian for LittleEndian { #[derive(Debug, Copy, Clone)] struct UnalignedU16Slice { + // Safety invariant: ptr must be valid for reading 2*len bytes ptr: *const u8, len: usize, } impl UnalignedU16Slice { + /// Safety: ptr must be valid for reading 2*len bytes #[inline(always)] pub unsafe fn new(ptr: *const u8, len: usize) -> UnalignedU16Slice { + // Safety: field invariant passed up to caller here UnalignedU16Slice { ptr, len } } #[inline(always)] pub fn trim_last(&mut self) { assert!(self.len > 0); + // Safety: invariant upheld here: a slice is still valid with a shorter len self.len -= 1; } @@ -113,7 +117,9 @@ impl UnalignedU16Slice { assert!(i < self.len); unsafe { let mut u: MaybeUninit = MaybeUninit::uninit(); + // Safety: i is at most len - 1, which works here ::core::ptr::copy_nonoverlapping(self.ptr.add(i * 2), u.as_mut_ptr() as *mut u8, 2); + // Safety: valid read above lets us do this u.assume_init() } } @@ -121,8 +127,13 @@ impl UnalignedU16Slice { #[cfg(feature = "simd-accel")] #[inline(always)] pub fn simd_at(&self, i: usize) -> u16x8 { + // Safety: i/len are on the scale of u16s, each one corresponds to 2 u8s assert!(i + SIMD_STRIDE_SIZE / 2 <= self.len); let byte_index = i * 2; + // Safety: load16_unaligned needs SIMD_STRIDE_SIZE=16 u8 elements to read, + // or 16/2 = 8 u16 elements to read. + // We have checked that we have at least that many above. + unsafe { to_u16_lanes(load16_unaligned(self.ptr.add(byte_index))) } } @@ -136,6 +147,7 @@ impl UnalignedU16Slice { // XXX the return value should be restricted not to // outlive self. assert!(from <= self.len); + // Safety: This upholds the same invariant: `from` is in bounds and we're returning a shorter slice unsafe { UnalignedU16Slice::new(self.ptr.add(from * 2), self.len - from) } } @@ -144,6 +156,8 @@ impl UnalignedU16Slice { pub fn copy_bmp_to(&self, other: &mut [u16]) -> Option<(u16, usize)> { assert!(self.len <= other.len()); let mut offset = 0; + // Safety: SIMD_STRIDE_SIZE is measured in bytes, whereas len is in u16s. We check we can + // munch SIMD_STRIDE_SIZE / 2 u16s which means we can write SIMD_STRIDE_SIZE u8s if SIMD_STRIDE_SIZE / 2 <= self.len { let len_minus_stride = self.len - SIMD_STRIDE_SIZE / 2; loop { @@ -151,6 +165,7 @@ impl UnalignedU16Slice { if E::OPPOSITE_ENDIAN { simd = simd_byte_swap(simd); } + // Safety: we have enough space on the other side to write this unsafe { store8_unaligned(other.as_mut_ptr().add(offset), simd); } @@ -158,6 +173,7 @@ impl UnalignedU16Slice { break; } offset += SIMD_STRIDE_SIZE / 2; + // Safety: This ensures we still have space for writing SIMD_STRIDE_SIZE u8s if offset > len_minus_stride { break; } @@ -236,6 +252,7 @@ fn copy_unaligned_basic_latin_to_ascii( ) -> CopyAsciiResult { let len = ::core::cmp::min(src.len(), dst.len()); let mut offset = 0; + // Safety: This check ensures we are able to read/write at least SIMD_STRIDE_SIZE elements if SIMD_STRIDE_SIZE <= len { let len_minus_stride = len - SIMD_STRIDE_SIZE; loop { @@ -249,10 +266,13 @@ fn copy_unaligned_basic_latin_to_ascii( break; } let packed = simd_pack(first, second); + // Safety: We are able to write SIMD_STRIDE_SIZE elements in this iteration unsafe { store16_unaligned(dst.as_mut_ptr().add(offset), packed); } offset += SIMD_STRIDE_SIZE; + // Safety: This is `offset > len - SIMD_STRIDE_SIZE`, which ensures that we can write at least SIMD_STRIDE_SIZE elements + // in the next iteration if offset > len_minus_stride { break; } @@ -637,7 +657,7 @@ impl<'a> Utf16Destination<'a> { self.write_code_unit((0xDC00 + (astral & 0x3FF)) as u16); } #[inline(always)] - pub fn write_surrogate_pair(&mut self, high: u16, low: u16) { + fn write_surrogate_pair(&mut self, high: u16, low: u16) { self.write_code_unit(high); self.write_code_unit(low); } @@ -646,6 +666,7 @@ impl<'a> Utf16Destination<'a> { self.write_bmp_excl_ascii(combined); self.write_bmp_excl_ascii(combining); } + // Safety-usable invariant: CopyAsciiResult::GoOn will only contain bytes >=0x80 #[inline(always)] pub fn copy_ascii_from_check_space_bmp<'b>( &'b mut self, @@ -659,6 +680,8 @@ impl<'a> Utf16Destination<'a> { } else { (DecoderResult::InputEmpty, src_remaining.len()) }; + // Safety: This function is documented as needing valid pointers for src/dest and len, which + // is true since we've passed the minumum length of the two match unsafe { ascii_to_basic_latin(src_remaining.as_ptr(), dst_remaining.as_mut_ptr(), length) } { @@ -667,16 +690,20 @@ impl<'a> Utf16Destination<'a> { self.pos += length; return CopyAsciiResult::Stop((pending, source.pos, self.pos)); } + // Safety: the function is documented as returning bytes >=0x80 in the Some Some((non_ascii, consumed)) => { source.pos += consumed; self.pos += consumed; source.pos += 1; // +1 for non_ascii + // Safety: non-ascii bubbled out here non_ascii } } }; + // Safety: non-ascii returned here CopyAsciiResult::GoOn((non_ascii_ret, Utf16BmpHandle::new(self))) } + // Safety-usable invariant: CopyAsciiResult::GoOn will only contain bytes >=0x80 #[inline(always)] pub fn copy_ascii_from_check_space_astral<'b>( &'b mut self, @@ -691,6 +718,8 @@ impl<'a> Utf16Destination<'a> { } else { (DecoderResult::InputEmpty, src_remaining.len()) }; + // Safety: This function is documented as needing valid pointers for src/dest and len, which + // is true since we've passed the minumum length of the two match unsafe { ascii_to_basic_latin(src_remaining.as_ptr(), dst_remaining.as_mut_ptr(), length) } { @@ -699,11 +728,13 @@ impl<'a> Utf16Destination<'a> { self.pos += length; return CopyAsciiResult::Stop((pending, source.pos, self.pos)); } + // Safety: the function is documented as returning bytes >=0x80 in the Some Some((non_ascii, consumed)) => { source.pos += consumed; self.pos += consumed; if self.pos + 1 < dst_len { source.pos += 1; // +1 for non_ascii + // Safety: non-ascii bubbled out here non_ascii } else { return CopyAsciiResult::Stop(( @@ -715,6 +746,7 @@ impl<'a> Utf16Destination<'a> { } } }; + // Safety: non-ascii returned here CopyAsciiResult::GoOn((non_ascii_ret, Utf16AstralHandle::new(self))) } #[inline(always)] diff --git a/third_party/rust/encoding_rs/src/lib.rs b/third_party/rust/encoding_rs/src/lib.rs index 6cc920ef88..1faf02e6bd 100644 --- a/third_party/rust/encoding_rs/src/lib.rs +++ b/third_party/rust/encoding_rs/src/lib.rs @@ -689,7 +689,7 @@ //! for discussion about the UTF-16 family. #![no_std] -#![cfg_attr(feature = "simd-accel", feature(core_intrinsics))] +#![cfg_attr(feature = "simd-accel", feature(core_intrinsics, portable_simd))] #[cfg(feature = "alloc")] #[cfg_attr(test, macro_use)] @@ -699,17 +699,6 @@ extern crate core; #[macro_use] extern crate cfg_if; -#[cfg(all( - feature = "simd-accel", - any( - target_feature = "sse2", - all(target_endian = "little", target_arch = "aarch64"), - all(target_endian = "little", target_feature = "neon") - ) -))] -#[macro_use(shuffle)] -extern crate packed_simd; - #[cfg(feature = "serde")] extern crate serde; diff --git a/third_party/rust/encoding_rs/src/mem.rs b/third_party/rust/encoding_rs/src/mem.rs index ba8d9e3f4c..0f9f3c1977 100644 --- a/third_party/rust/encoding_rs/src/mem.rs +++ b/third_party/rust/encoding_rs/src/mem.rs @@ -116,6 +116,11 @@ macro_rules! by_unit_check_alu { } let len_minus_stride = len - ALU_ALIGNMENT / unit_size; if offset + (4 * (ALU_ALIGNMENT / unit_size)) <= len { + // Safety: the above check lets us perform 4 consecutive reads of + // length ALU_ALIGNMENT / unit_size. ALU_ALIGNMENT is the size of usize, and unit_size + // is the size of the `src` pointer, so this is equal to performing four usize reads. + // + // This invariant is upheld on all loop iterations let len_minus_unroll = len - (4 * (ALU_ALIGNMENT / unit_size)); loop { let unroll_accu = unsafe { *(src.add(offset) as *const usize) } @@ -134,12 +139,14 @@ macro_rules! by_unit_check_alu { return false; } offset += 4 * (ALU_ALIGNMENT / unit_size); + // Safety: this check lets us continue to perform the 4 reads earlier if offset > len_minus_unroll { break; } } } while offset <= len_minus_stride { + // Safety: the above check lets us perform one usize read. accu |= unsafe { *(src.add(offset) as *const usize) }; offset += ALU_ALIGNMENT / unit_size; } @@ -189,6 +196,11 @@ macro_rules! by_unit_check_simd { } let len_minus_stride = len - SIMD_STRIDE_SIZE / unit_size; if offset + (4 * (SIMD_STRIDE_SIZE / unit_size)) <= len { + // Safety: the above check lets us perform 4 consecutive reads of + // length SIMD_STRIDE_SIZE / unit_size. SIMD_STRIDE_SIZE is the size of $simd_ty, and unit_size + // is the size of the `src` pointer, so this is equal to performing four $simd_ty reads. + // + // This invariant is upheld on all loop iterations let len_minus_unroll = len - (4 * (SIMD_STRIDE_SIZE / unit_size)); loop { let unroll_accu = unsafe { *(src.add(offset) as *const $simd_ty) } @@ -208,6 +220,7 @@ macro_rules! by_unit_check_simd { return false; } offset += 4 * (SIMD_STRIDE_SIZE / unit_size); + // Safety: this check lets us continue to perform the 4 reads earlier if offset > len_minus_unroll { break; } @@ -215,6 +228,7 @@ macro_rules! by_unit_check_simd { } let mut simd_accu = $splat; while offset <= len_minus_stride { + // Safety: the above check lets us perform one $simd_ty read. simd_accu = simd_accu | unsafe { *(src.add(offset) as *const $simd_ty) }; offset += SIMD_STRIDE_SIZE / unit_size; } @@ -234,8 +248,8 @@ macro_rules! by_unit_check_simd { cfg_if! { if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))] { use crate::simd_funcs::*; - use packed_simd::u8x16; - use packed_simd::u16x8; + use core::simd::u8x16; + use core::simd::u16x8; const SIMD_ALIGNMENT: usize = 16; diff --git a/third_party/rust/encoding_rs/src/simd_funcs.rs b/third_party/rust/encoding_rs/src/simd_funcs.rs index 96feeab5a6..5ae00e62e0 100644 --- a/third_party/rust/encoding_rs/src/simd_funcs.rs +++ b/third_party/rust/encoding_rs/src/simd_funcs.rs @@ -7,55 +7,74 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use packed_simd::u16x8; -use packed_simd::u8x16; -use packed_simd::IntoBits; +use any_all_workaround::all_mask16x8; +use any_all_workaround::all_mask8x16; +use any_all_workaround::any_mask16x8; +use any_all_workaround::any_mask8x16; +use core::simd::cmp::SimdPartialEq; +use core::simd::cmp::SimdPartialOrd; +use core::simd::mask16x8; +use core::simd::mask8x16; +use core::simd::simd_swizzle; +use core::simd::u16x8; +use core::simd::u8x16; +use core::simd::ToBytes; // TODO: Migrate unaligned access to stdlib code if/when the RFC // https://github.com/rust-lang/rfcs/pull/1725 is implemented. +/// Safety invariant: ptr must be valid for an unaligned read of 16 bytes #[inline(always)] pub unsafe fn load16_unaligned(ptr: *const u8) -> u8x16 { - let mut simd = ::core::mem::uninitialized(); - ::core::ptr::copy_nonoverlapping(ptr, &mut simd as *mut u8x16 as *mut u8, 16); - simd + let mut simd = ::core::mem::MaybeUninit::::uninit(); + ::core::ptr::copy_nonoverlapping(ptr, simd.as_mut_ptr() as *mut u8, 16); + // Safety: copied 16 bytes of initialized memory into this, it is now initialized + simd.assume_init() } +/// Safety invariant: ptr must be valid for an aligned-for-u8x16 read of 16 bytes #[allow(dead_code)] #[inline(always)] pub unsafe fn load16_aligned(ptr: *const u8) -> u8x16 { *(ptr as *const u8x16) } +/// Safety invariant: ptr must be valid for an unaligned store of 16 bytes #[inline(always)] pub unsafe fn store16_unaligned(ptr: *mut u8, s: u8x16) { ::core::ptr::copy_nonoverlapping(&s as *const u8x16 as *const u8, ptr, 16); } +/// Safety invariant: ptr must be valid for an aligned-for-u8x16 store of 16 bytes #[allow(dead_code)] #[inline(always)] pub unsafe fn store16_aligned(ptr: *mut u8, s: u8x16) { *(ptr as *mut u8x16) = s; } +/// Safety invariant: ptr must be valid for an unaligned read of 16 bytes #[inline(always)] pub unsafe fn load8_unaligned(ptr: *const u16) -> u16x8 { - let mut simd = ::core::mem::uninitialized(); - ::core::ptr::copy_nonoverlapping(ptr as *const u8, &mut simd as *mut u16x8 as *mut u8, 16); - simd + let mut simd = ::core::mem::MaybeUninit::::uninit(); + ::core::ptr::copy_nonoverlapping(ptr as *const u8, simd.as_mut_ptr() as *mut u8, 16); + // Safety: copied 16 bytes of initialized memory into this, it is now initialized + simd.assume_init() } +/// Safety invariant: ptr must be valid for an aligned-for-u16x8 read of 16 bytes #[allow(dead_code)] #[inline(always)] pub unsafe fn load8_aligned(ptr: *const u16) -> u16x8 { *(ptr as *const u16x8) } +/// Safety invariant: ptr must be valid for an unaligned store of 16 bytes #[inline(always)] pub unsafe fn store8_unaligned(ptr: *mut u16, s: u16x8) { ::core::ptr::copy_nonoverlapping(&s as *const u16x8 as *const u8, ptr as *mut u8, 16); } +/// Safety invariant: ptr must be valid for an aligned-for-u16x8 store of 16 bytes #[allow(dead_code)] #[inline(always)] pub unsafe fn store8_aligned(ptr: *mut u16, s: u16x8) { @@ -100,7 +119,7 @@ pub fn simd_byte_swap(s: u16x8) -> u16x8 { #[inline(always)] pub fn to_u16_lanes(s: u8x16) -> u16x8 { - s.into_bits() + u16x8::from_ne_bytes(s) } cfg_if! { @@ -108,10 +127,11 @@ cfg_if! { // Expose low-level mask instead of higher-level conclusion, // because the non-ASCII case would perform less well otherwise. + // Safety-usable invariant: This returned value is whether each high bit is set #[inline(always)] pub fn mask_ascii(s: u8x16) -> i32 { unsafe { - _mm_movemask_epi8(s.into_bits()) + _mm_movemask_epi8(s.into()) } } @@ -125,14 +145,16 @@ cfg_if! { #[inline(always)] pub fn simd_is_ascii(s: u8x16) -> bool { unsafe { - _mm_movemask_epi8(s.into_bits()) == 0 + // Safety: We have cfg()d the correct platform + _mm_movemask_epi8(s.into()) == 0 } } } else if #[cfg(target_arch = "aarch64")]{ #[inline(always)] pub fn simd_is_ascii(s: u8x16) -> bool { unsafe { - vmaxvq_u8(s.into_bits()) < 0x80 + // Safety: We have cfg()d the correct platform + vmaxvq_u8(s.into()) < 0x80 } } } else { @@ -141,7 +163,7 @@ cfg_if! { // This optimizes better on ARM than // the lt formulation. let highest_ascii = u8x16::splat(0x7F); - !s.gt(highest_ascii).any() + !any_mask8x16(s.simd_gt(highest_ascii)) } } } @@ -154,20 +176,21 @@ cfg_if! { return true; } let above_str_latin1 = u8x16::splat(0xC4); - s.lt(above_str_latin1).all() + s.simd_lt(above_str_latin1).all() } } else if #[cfg(target_arch = "aarch64")]{ #[inline(always)] pub fn simd_is_str_latin1(s: u8x16) -> bool { unsafe { - vmaxvq_u8(s.into_bits()) < 0xC4 + // Safety: We have cfg()d the correct platform + vmaxvq_u8(s.into()) < 0xC4 } } } else { #[inline(always)] pub fn simd_is_str_latin1(s: u8x16) -> bool { let above_str_latin1 = u8x16::splat(0xC4); - s.lt(above_str_latin1).all() + all_mask8x16(s.simd_lt(above_str_latin1)) } } } @@ -177,21 +200,23 @@ cfg_if! { #[inline(always)] pub fn simd_is_basic_latin(s: u16x8) -> bool { unsafe { - vmaxvq_u16(s.into_bits()) < 0x80 + // Safety: We have cfg()d the correct platform + vmaxvq_u16(s.into()) < 0x80 } } #[inline(always)] pub fn simd_is_latin1(s: u16x8) -> bool { unsafe { - vmaxvq_u16(s.into_bits()) < 0x100 + // Safety: We have cfg()d the correct platform + vmaxvq_u16(s.into()) < 0x100 } } } else { #[inline(always)] pub fn simd_is_basic_latin(s: u16x8) -> bool { let above_ascii = u16x8::splat(0x80); - s.lt(above_ascii).all() + all_mask16x8(s.simd_lt(above_ascii)) } #[inline(always)] @@ -200,7 +225,7 @@ cfg_if! { // seems faster in this case while the above // function is better the other way round... let highest_latin1 = u16x8::splat(0xFF); - !s.gt(highest_latin1).any() + !any_mask16x8(s.simd_gt(highest_latin1)) } } } @@ -209,7 +234,7 @@ cfg_if! { pub fn contains_surrogates(s: u16x8) -> bool { let mask = u16x8::splat(0xF800); let surrogate_bits = u16x8::splat(0xD800); - (s & mask).eq(surrogate_bits).any() + any_mask16x8((s & mask).simd_eq(surrogate_bits)) } cfg_if! { @@ -217,7 +242,8 @@ cfg_if! { macro_rules! aarch64_return_false_if_below_hebrew { ($s:ident) => ({ unsafe { - if vmaxvq_u16($s.into_bits()) < 0x0590 { + // Safety: We have cfg()d the correct platform + if vmaxvq_u16($s.into()) < 0x0590 { return false; } } @@ -234,7 +260,7 @@ cfg_if! { macro_rules! non_aarch64_return_false_if_all { ($s:ident) => ({ - if $s.all() { + if all_mask16x8($s) { return false; } }) @@ -245,7 +271,7 @@ cfg_if! { macro_rules! in_range16x8 { ($s:ident, $start:expr, $end:expr) => {{ // SIMD sub is wrapping - ($s - u16x8::splat($start)).lt(u16x8::splat($end - $start)) + ($s - u16x8::splat($start)).simd_lt(u16x8::splat($end - $start)) }}; } @@ -259,43 +285,44 @@ pub fn is_u16x8_bidi(s: u16x8) -> bool { aarch64_return_false_if_below_hebrew!(s); - let below_hebrew = s.lt(u16x8::splat(0x0590)); + let below_hebrew = s.simd_lt(u16x8::splat(0x0590)); non_aarch64_return_false_if_all!(below_hebrew); - if (below_hebrew | in_range16x8!(s, 0x0900, 0x200F) | in_range16x8!(s, 0x2068, 0xD802)).all() { + if all_mask16x8( + below_hebrew | in_range16x8!(s, 0x0900, 0x200F) | in_range16x8!(s, 0x2068, 0xD802), + ) { return false; } // Quick refutation failed. Let's do the full check. - (in_range16x8!(s, 0x0590, 0x0900) - | in_range16x8!(s, 0xFB1D, 0xFE00) - | in_range16x8!(s, 0xFE70, 0xFEFF) - | in_range16x8!(s, 0xD802, 0xD804) - | in_range16x8!(s, 0xD83A, 0xD83C) - | s.eq(u16x8::splat(0x200F)) - | s.eq(u16x8::splat(0x202B)) - | s.eq(u16x8::splat(0x202E)) - | s.eq(u16x8::splat(0x2067))) - .any() + any_mask16x8( + (in_range16x8!(s, 0x0590, 0x0900) + | in_range16x8!(s, 0xFB1D, 0xFE00) + | in_range16x8!(s, 0xFE70, 0xFEFF) + | in_range16x8!(s, 0xD802, 0xD804) + | in_range16x8!(s, 0xD83A, 0xD83C) + | s.simd_eq(u16x8::splat(0x200F)) + | s.simd_eq(u16x8::splat(0x202B)) + | s.simd_eq(u16x8::splat(0x202E)) + | s.simd_eq(u16x8::splat(0x2067))), + ) } #[inline(always)] pub fn simd_unpack(s: u8x16) -> (u16x8, u16x8) { - unsafe { - let first: u8x16 = shuffle!( - s, - u8x16::splat(0), - [0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23] - ); - let second: u8x16 = shuffle!( - s, - u8x16::splat(0), - [8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31] - ); - (first.into_bits(), second.into_bits()) - } + let first: u8x16 = simd_swizzle!( + s, + u8x16::splat(0), + [0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23] + ); + let second: u8x16 = simd_swizzle!( + s, + u8x16::splat(0), + [8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31] + ); + (u16x8::from_ne_bytes(first), u16x8::from_ne_bytes(second)) } cfg_if! { @@ -303,21 +330,20 @@ cfg_if! { #[inline(always)] pub fn simd_pack(a: u16x8, b: u16x8) -> u8x16 { unsafe { - _mm_packus_epi16(a.into_bits(), b.into_bits()).into_bits() + // Safety: We have cfg()d the correct platform + _mm_packus_epi16(a.into(), b.into()).into() } } } else { #[inline(always)] pub fn simd_pack(a: u16x8, b: u16x8) -> u8x16 { - unsafe { - let first: u8x16 = a.into_bits(); - let second: u8x16 = b.into_bits(); - shuffle!( - first, - second, - [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30] - ) - } + let first: u8x16 = a.to_ne_bytes(); + let second: u8x16 = b.to_ne_bytes(); + simd_swizzle!( + first, + second, + [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30] + ) } } } diff --git a/third_party/rust/encoding_rs/src/single_byte.rs b/third_party/rust/encoding_rs/src/single_byte.rs index b3b6089d31..b7a4bf23da 100644 --- a/third_party/rust/encoding_rs/src/single_byte.rs +++ b/third_party/rust/encoding_rs/src/single_byte.rs @@ -53,6 +53,9 @@ impl SingleByteDecoder { // statically omit the bound check when accessing // `[u16; 128]` with an index // `non_ascii as usize - 0x80usize`. + // + // Safety: `non_ascii` is a u8 byte >=0x80, from the invariants + // on Utf8Destination::copy_ascii_from_check_space_bmp() let mapped = unsafe { *(self.table.get_unchecked(non_ascii as usize - 0x80usize)) }; // let mapped = self.table[non_ascii as usize - 0x80usize]; @@ -151,9 +154,12 @@ impl SingleByteDecoder { } else { (DecoderResult::InputEmpty, src.len()) }; + // Safety invariant: converted <= length. Quite often we have `converted < length` + // which will be separately marked. let mut converted = 0usize; 'outermost: loop { match unsafe { + // Safety: length is the minimum length, `src/dst + x` will always be valid for reads/writes of `len - x` ascii_to_basic_latin( src.as_ptr().add(converted), dst.as_mut_ptr().add(converted), @@ -164,6 +170,12 @@ impl SingleByteDecoder { return (pending, length, length); } Some((mut non_ascii, consumed)) => { + // Safety invariant: `converted <= length` upheld, since this can only consume + // up to `length - converted` bytes. + // + // Furthermore, in this context, + // we can assume `converted < length` since this branch is only ever hit when + // ascii_to_basic_latin fails to consume the entire slice converted += consumed; 'middle: loop { // `converted` doesn't count the reading of `non_ascii` yet. @@ -172,6 +184,9 @@ impl SingleByteDecoder { // statically omit the bound check when accessing // `[u16; 128]` with an index // `non_ascii as usize - 0x80usize`. + // + // Safety: We can rely on `non_ascii` being between `0x80` and `0xFF` due to + // the invariants of `ascii_to_basic_latin()`, and our table has enough space for that. let mapped = unsafe { *(self.table.get_unchecked(non_ascii as usize - 0x80usize)) }; // let mapped = self.table[non_ascii as usize - 0x80usize]; @@ -183,9 +198,10 @@ impl SingleByteDecoder { ); } unsafe { - // The bound check has already been performed + // Safety: As mentioned above, `converted < length` *(dst.get_unchecked_mut(converted)) = mapped; } + // Safety: `converted <= length` upheld, since `converted < length` before this converted += 1; // Next, handle ASCII punctuation and non-ASCII without // going back to ASCII acceleration. Non-ASCII scripts @@ -198,7 +214,10 @@ impl SingleByteDecoder { if converted == length { return (pending, length, length); } + // Safety: We are back to `converted < length` because of the == above + // and can perform this check. let mut b = unsafe { *(src.get_unchecked(converted)) }; + // Safety: `converted < length` is upheld for this loop 'innermost: loop { if b > 127 { non_ascii = b; @@ -208,15 +227,20 @@ impl SingleByteDecoder { // byte unconditionally instead of trying to unread it // to make it part of the next SIMD stride. unsafe { + // Safety: `converted < length` is true for this loop *(dst.get_unchecked_mut(converted)) = u16::from(b); } + // Safety: We are now at `converted <= length`. We should *not* `continue` + // the loop without reverifying converted += 1; if b < 60 { // We've got punctuation if converted == length { return (pending, length, length); } + // Safety: we're back to `converted <= length` because of the == above b = unsafe { *(src.get_unchecked(converted)) }; + // Safety: The loop continues as `converted < length` continue 'innermost; } // We've got markup or ASCII text @@ -234,6 +258,8 @@ impl SingleByteDecoder { loop { if let Some((non_ascii, offset)) = validate_ascii(bytes) { total += offset; + // Safety: We can rely on `non_ascii` being between `0x80` and `0xFF` due to + // the invariants of `ascii_to_basic_latin()`, and our table has enough space for that. let mapped = unsafe { *(self.table.get_unchecked(non_ascii as usize - 0x80usize)) }; if mapped != u16::from(non_ascii) { return total; @@ -384,9 +410,12 @@ impl SingleByteEncoder { } else { (EncoderResult::InputEmpty, src.len()) }; + // Safety invariant: converted <= length. Quite often we have `converted < length` + // which will be separately marked. let mut converted = 0usize; 'outermost: loop { match unsafe { + // Safety: length is the minimum length, `src/dst + x` will always be valid for reads/writes of `len - x` basic_latin_to_ascii( src.as_ptr().add(converted), dst.as_mut_ptr().add(converted), @@ -397,15 +426,23 @@ impl SingleByteEncoder { return (pending, length, length); } Some((mut non_ascii, consumed)) => { + // Safety invariant: `converted <= length` upheld, since this can only consume + // up to `length - converted` bytes. + // + // Furthermore, in this context, + // we can assume `converted < length` since this branch is only ever hit when + // ascii_to_basic_latin fails to consume the entire slice converted += consumed; 'middle: loop { // `converted` doesn't count the reading of `non_ascii` yet. match self.encode_u16(non_ascii) { Some(byte) => { unsafe { + // Safety: we're allowed this access since `converted < length` *(dst.get_unchecked_mut(converted)) = byte; } converted += 1; + // `converted <= length` now } None => { // At this point, we need to know if we @@ -421,6 +458,8 @@ impl SingleByteEncoder { converted, ); } + // Safety: convered < length from outside the match, and `converted + 1 != length`, + // So `converted + 1 < length` as well. We're in bounds let second = u32::from(unsafe { *src.get_unchecked(converted + 1) }); if second & 0xFC00u32 != 0xDC00u32 { @@ -432,6 +471,18 @@ impl SingleByteEncoder { } // The next code unit is a low surrogate. let astral: char = unsafe { + // Safety: We can rely on non_ascii being 0xD800-0xDBFF since the high bits are 0xD800 + // Then, (non_ascii << 10 - 0xD800 << 10) becomes between (0 to 0x3FF) << 10, which is between + // 0x400 to 0xffc00. Adding the 0x10000 gives a range of 0x10400 to 0x10fc00. Subtracting the 0xDC00 + // gives 0x2800 to 0x102000 + // The second term is between 0xDC00 and 0xDFFF from the check above. This gives a maximum + // possible range of (0x10400 + 0xDC00) to (0x102000 + 0xDFFF) which is 0x1E000 to 0x10ffff. + // This is in range. + // + // From a Unicode principles perspective this can also be verified as we have checked that `non_ascii` is a high surrogate + // (0xD800..=0xDBFF), and that `second` is a low surrogate (`0xDC00..=0xDFFF`), and we are applying reverse of the UTC16 transformation + // algorithm , by applying the high surrogate - 0xD800 to the + // high ten bits, and the low surrogate - 0xDc00 to the low ten bits, and then adding 0x10000 ::core::char::from_u32_unchecked( (u32::from(non_ascii) << 10) + second - (((0xD800u32 << 10) - 0x1_0000u32) + 0xDC00u32), @@ -456,6 +507,7 @@ impl SingleByteEncoder { converted + 1, // +1 `for non_ascii` converted, ); + // Safety: This branch diverges, so no need to uphold invariants on `converted` } } // Next, handle ASCII punctuation and non-ASCII without @@ -469,8 +521,12 @@ impl SingleByteEncoder { if converted == length { return (pending, length, length); } + // Safety: we're back to `converted < length` due to the == above and can perform + // the unchecked read let mut unit = unsafe { *(src.get_unchecked(converted)) }; 'innermost: loop { + // Safety: This loop always begins with `converted < length`, see + // the invariant outside and the comment on the continue below if unit > 127 { non_ascii = unit; continue 'middle; @@ -479,19 +535,25 @@ impl SingleByteEncoder { // byte unconditionally instead of trying to unread it // to make it part of the next SIMD stride. unsafe { + // Safety: Can rely on converted < length *(dst.get_unchecked_mut(converted)) = unit as u8; } converted += 1; + // `converted <= length` here if unit < 60 { // We've got punctuation if converted == length { return (pending, length, length); } + // Safety: `converted < length` due to the == above. The read is safe. unit = unsafe { *(src.get_unchecked(converted)) }; + // Safety: This only happens if `converted < length`, maintaining it continue 'innermost; } // We've got markup or ASCII text continue 'outermost; + // Safety: All other routes to here diverge so the continue is the only + // way to run the innermost loop. } } } diff --git a/third_party/rust/encoding_rs/src/x_user_defined.rs b/third_party/rust/encoding_rs/src/x_user_defined.rs index 103c9afba9..7af7d5e3d6 100644 --- a/third_party/rust/encoding_rs/src/x_user_defined.rs +++ b/third_party/rust/encoding_rs/src/x_user_defined.rs @@ -14,12 +14,13 @@ use crate::variant::*; cfg_if! { if #[cfg(feature = "simd-accel")] { use simd_funcs::*; - use packed_simd::u16x8; + use core::simd::u16x8; + use core::simd::cmp::SimdPartialOrd; #[inline(always)] fn shift_upper(unpacked: u16x8) -> u16x8 { let highest_ascii = u16x8::splat(0x7F); - unpacked + unpacked.gt(highest_ascii).select(u16x8::splat(0xF700), u16x8::splat(0)) } + unpacked + unpacked.simd_gt(highest_ascii).select(u16x8::splat(0xF700), u16x8::splat(0)) } } else { } } @@ -116,10 +117,15 @@ impl UserDefinedDecoder { let simd_iterations = length >> 4; let src_ptr = src.as_ptr(); let dst_ptr = dst.as_mut_ptr(); + // Safety: This is `for i in 0..length / 16` for i in 0..simd_iterations { + // Safety: This is in bounds: length is the minumum valid length for both src/dst + // and i ranges to length/16, so multiplying by 16 will always be `< length` and can do + // a 16 byte read let input = unsafe { load16_unaligned(src_ptr.add(i * 16)) }; let (first, second) = simd_unpack(input); unsafe { + // Safety: same as above, but this is two consecutive 8-byte reads store8_unaligned(dst_ptr.add(i * 16), shift_upper(first)); store8_unaligned(dst_ptr.add((i * 16) + 8), shift_upper(second)); } diff --git a/third_party/rust/equivalent/.cargo-checksum.json b/third_party/rust/equivalent/.cargo-checksum.json new file mode 100644 index 0000000000..18cb3e7d9a --- /dev/null +++ b/third_party/rust/equivalent/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"87d7f4d5b05a14966f11c5e40940ca2687a3ae8e751bb15d7f537ae95310ab7b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349","README.md":"bbcbb8419f9bb01a51d3d5e808fe35651d423014992a72be3e7acd518485f190","src/lib.rs":"1dd84363f561b30b1da713486c6b583900353e62c569d7ba1dd84eb2c04f1a14"},"package":"5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"} \ No newline at end of file diff --git a/third_party/rust/equivalent/Cargo.toml b/third_party/rust/equivalent/Cargo.toml new file mode 100644 index 0000000000..925d53e883 --- /dev/null +++ b/third_party/rust/equivalent/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +rust-version = "1.6" +name = "equivalent" +version = "1.0.1" +description = "Traits for key comparison in maps." +readme = "README.md" +keywords = [ + "hashmap", + "no_std", +] +categories = [ + "data-structures", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/cuviper/equivalent" diff --git a/third_party/rust/equivalent/LICENSE-APACHE b/third_party/rust/equivalent/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/equivalent/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/equivalent/LICENSE-MIT b/third_party/rust/equivalent/LICENSE-MIT new file mode 100644 index 0000000000..5ac40dae7f --- /dev/null +++ b/third_party/rust/equivalent/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016--2023 + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/equivalent/README.md b/third_party/rust/equivalent/README.md new file mode 100644 index 0000000000..8ff7e24c8c --- /dev/null +++ b/third_party/rust/equivalent/README.md @@ -0,0 +1,25 @@ +# Equivalent + +[![crates.io](https://img.shields.io/crates/v/equivalent.svg)](https://crates.io/crates/equivalent) +[![docs](https://docs.rs/equivalent/badge.svg)](https://docs.rs/equivalent) + +`Equivalent` and `Comparable` are Rust traits for key comparison in maps. + +These may be used in the implementation of maps where the lookup type `Q` +may be different than the stored key type `K`. + +* `Q: Equivalent` checks for equality, similar to the `HashMap` + constraint `K: Borrow, Q: Eq`. +* `Q: Comparable` checks the ordering, similar to the `BTreeMap` + constraint `K: Borrow, Q: Ord`. + +These traits are not used by the maps in the standard library, but they may +add more flexibility in third-party map implementations, especially in +situations where a strict `K: Borrow` relationship is not available. + +## License + +Equivalent is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). See [LICENSE-APACHE](LICENSE-APACHE) and +[LICENSE-MIT](LICENSE-MIT) for details. Opening a pull request is +assumed to signal agreement with these licensing terms. diff --git a/third_party/rust/equivalent/src/lib.rs b/third_party/rust/equivalent/src/lib.rs new file mode 100644 index 0000000000..09ba58dff3 --- /dev/null +++ b/third_party/rust/equivalent/src/lib.rs @@ -0,0 +1,113 @@ +//! [`Equivalent`] and [`Comparable`] are traits for key comparison in maps. +//! +//! These may be used in the implementation of maps where the lookup type `Q` +//! may be different than the stored key type `K`. +//! +//! * `Q: Equivalent` checks for equality, similar to the `HashMap` +//! constraint `K: Borrow, Q: Eq`. +//! * `Q: Comparable` checks the ordering, similar to the `BTreeMap` +//! constraint `K: Borrow, Q: Ord`. +//! +//! These traits are not used by the maps in the standard library, but they may +//! add more flexibility in third-party map implementations, especially in +//! situations where a strict `K: Borrow` relationship is not available. +//! +//! # Examples +//! +//! ``` +//! use equivalent::*; +//! use std::cmp::Ordering; +//! +//! pub struct Pair(pub A, pub B); +//! +//! impl<'a, A: ?Sized, B: ?Sized, C, D> Equivalent<(C, D)> for Pair<&'a A, &'a B> +//! where +//! A: Equivalent, +//! B: Equivalent, +//! { +//! fn equivalent(&self, key: &(C, D)) -> bool { +//! self.0.equivalent(&key.0) && self.1.equivalent(&key.1) +//! } +//! } +//! +//! impl<'a, A: ?Sized, B: ?Sized, C, D> Comparable<(C, D)> for Pair<&'a A, &'a B> +//! where +//! A: Comparable, +//! B: Comparable, +//! { +//! fn compare(&self, key: &(C, D)) -> Ordering { +//! match self.0.compare(&key.0) { +//! Ordering::Equal => self.1.compare(&key.1), +//! not_equal => not_equal, +//! } +//! } +//! } +//! +//! fn main() { +//! let key = (String::from("foo"), String::from("bar")); +//! let q1 = Pair("foo", "bar"); +//! let q2 = Pair("boo", "bar"); +//! let q3 = Pair("foo", "baz"); +//! +//! assert!(q1.equivalent(&key)); +//! assert!(!q2.equivalent(&key)); +//! assert!(!q3.equivalent(&key)); +//! +//! assert_eq!(q1.compare(&key), Ordering::Equal); +//! assert_eq!(q2.compare(&key), Ordering::Less); +//! assert_eq!(q3.compare(&key), Ordering::Greater); +//! } +//! ``` + +#![no_std] + +use core::borrow::Borrow; +use core::cmp::Ordering; + +/// Key equivalence trait. +/// +/// This trait allows hash table lookup to be customized. It has one blanket +/// implementation that uses the regular solution with `Borrow` and `Eq`, just +/// like `HashMap` does, so that you can pass `&str` to lookup into a map with +/// `String` keys and so on. +/// +/// # Contract +/// +/// The implementor **must** hash like `K`, if it is hashable. +pub trait Equivalent { + /// Compare self to `key` and return `true` if they are equal. + fn equivalent(&self, key: &K) -> bool; +} + +impl Equivalent for Q +where + Q: Eq, + K: Borrow, +{ + #[inline] + fn equivalent(&self, key: &K) -> bool { + PartialEq::eq(self, key.borrow()) + } +} + +/// Key ordering trait. +/// +/// This trait allows ordered map lookup to be customized. It has one blanket +/// implementation that uses the regular solution with `Borrow` and `Ord`, just +/// like `BTreeMap` does, so that you can pass `&str` to lookup into a map with +/// `String` keys and so on. +pub trait Comparable: Equivalent { + /// Compare self to `key` and return their ordering. + fn compare(&self, key: &K) -> Ordering; +} + +impl Comparable for Q +where + Q: Ord, + K: Borrow, +{ + #[inline] + fn compare(&self, key: &K) -> Ordering { + Ord::cmp(self, key.borrow()) + } +} diff --git a/third_party/rust/fallible_collections/.cargo-checksum.json b/third_party/rust/fallible_collections/.cargo-checksum.json index 7e41b87cf9..f09beee0e5 100644 --- a/third_party/rust/fallible_collections/.cargo-checksum.json +++ b/third_party/rust/fallible_collections/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"8ecacb7ad2f59391ae3247157c01c6d6508095f53ba466c3e3b554891b3e941f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"5b817b980bb39f4bee82913daf9d1ef39d1cb9e790b85ab000f735a962ce596d","src/arc.rs":"3cf237ae0acb5b058a57b633170f079024455271e9420e5a9244bafbdeb90b1c","src/boxed.rs":"1f19ad48ab3a1f41cca3756f3fdbc22e97f50a9121511222afcfe1859faf50fa","src/btree.rs":"b83820fc2a00e2e34127b3037abde8b945f0ca2785f3def725787e6813c3d3e0","src/btree/map.rs":"557ce3ff2d02c425adcb2b4ac53b6b6607c25c535aee8ffa4f12bf773fbcd763","src/btree/node.rs":"d943949b8938b5888245d6560efd386c6ae78d23fc3a7a0cc5b06f4da8f4c1c1","src/btree/search.rs":"ae78f73f3e56ea277b0a02cc39454447b75e12a6c817ecfee00065b3ddbfff67","src/btree/set.rs":"607f0db0b189c39b41824fbbf6fd8d9c5fdf85cc40f4437b13152e7b86d2979f","src/format.rs":"5142970f6ac1fe66f667ee2565af786802e93e6728ec3a1b82ffaa9f6a6b5bce","src/hashmap.rs":"1b9bf03fd2f2d9412ea2dad6963e1d37d51662e7091424bfcdc44a502f4e64bc","src/lib.rs":"652532126fdc2a81a927d23e4e4ad810911ee5d398f35f82650b5b4ec9fc5576","src/rc.rs":"f327a0adcfd2b1e225913ae716deb96777ca562985ac64e3b83550111f809864","src/try_clone.rs":"725130e0ddacde1ff7c976de62fbe45d01c67412af395aa41cac4bcfb85f6a5f","src/vec.rs":"27369a12a66deff0fe3fc57eae0f3a639e98b968d92e10eff9d4b7af8354a9d4"},"package":"3f57ccc32870366ae684be48b32a1a2e196f98a42a9b4361fe77e13fd4a34755"} \ No newline at end of file +{"files":{"Cargo.toml":"050bb460a70e6ddd572fdf118e5d52ae8dc1c7801af6475ef2ab9dfd34d963ab","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"63b0c7dac05e6dfba32dcd4cb8e671bb8b72525f67a6b17fa5b8f10fd2cab047","src/arc.rs":"fda02f28d359193cbc0ec988b7c8149e9212c1951dff9cba6041a9ebd7fa3f17","src/boxed.rs":"8d7b3afc19e27ca51a843490d346319807cfdcc268355272c3164756fd63c242","src/btree.rs":"b83820fc2a00e2e34127b3037abde8b945f0ca2785f3def725787e6813c3d3e0","src/btree/map.rs":"557ce3ff2d02c425adcb2b4ac53b6b6607c25c535aee8ffa4f12bf773fbcd763","src/btree/node.rs":"49feca8742513b1c29d2f949c1eb1b178b538097ae94ba9dc31b8323a6423ea6","src/btree/search.rs":"ae78f73f3e56ea277b0a02cc39454447b75e12a6c817ecfee00065b3ddbfff67","src/btree/set.rs":"607f0db0b189c39b41824fbbf6fd8d9c5fdf85cc40f4437b13152e7b86d2979f","src/format.rs":"5142970f6ac1fe66f667ee2565af786802e93e6728ec3a1b82ffaa9f6a6b5bce","src/hashmap.rs":"1b9bf03fd2f2d9412ea2dad6963e1d37d51662e7091424bfcdc44a502f4e64bc","src/lib.rs":"71c5dc986ad58a4515604a73a4b7f4d8b6f43d2831993ee8612c99978ff2bb42","src/rc.rs":"f327a0adcfd2b1e225913ae716deb96777ca562985ac64e3b83550111f809864","src/try_clone.rs":"725130e0ddacde1ff7c976de62fbe45d01c67412af395aa41cac4bcfb85f6a5f","src/try_reserve_error.rs":"5e8db6a538225e66fec5d9d3a4314939b5b0428180676eb55ab928875e4feefd","src/vec.rs":"4268ae1de90750c21503fc84bdbf46cd6ccf76e33ae7f7daf8050fb29b839db1"},"package":"a88c69768c0a15262df21899142bc6df9b9b823546d4b4b9a7bc2d6c448ec6fd"} \ No newline at end of file diff --git a/third_party/rust/fallible_collections/Cargo.toml b/third_party/rust/fallible_collections/Cargo.toml index 27a8221a17..6f6f316693 100644 --- a/third_party/rust/fallible_collections/Cargo.toml +++ b/third_party/rust/fallible_collections/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "fallible_collections" -version = "0.4.6" +version = "0.4.9" authors = ["vcombey "] description = "a crate which adds fallible allocation api to std collections" readme = "README.md" @@ -24,9 +24,12 @@ license = "MIT/Apache-2.0" repository = "https://github.com/vcombey/fallible_collections.git" [dependencies.hashbrown] -version = "0.12.1" +version = "0.13" +optional = true [features] +default = ["hashmap"] +hashmap = ["hashbrown"] rust_1_57 = [] std = [] std_io = ["std"] diff --git a/third_party/rust/fallible_collections/README.md b/third_party/rust/fallible_collections/README.md index b34825903d..623eedd5c7 100644 --- a/third_party/rust/fallible_collections/README.md +++ b/third_party/rust/fallible_collections/README.md @@ -17,7 +17,8 @@ It is recommended to look there for the newest released version, as well as link At the point of the last update of this README, the latest published version could be used like this: Add the following dependency to your Cargo manifest... -Add feature std and rust_1_57 to use the stabilized try_reserve api and the std HashMap type. +Add feature std and rust_1_57 to use the stabilized try_reserve api and the std HashMap type. Obviously, you cannot combine it with the 'unstable' feature. +Add integration tests that can be run with the tiny_integration_tester command. ```toml [dependencies] diff --git a/third_party/rust/fallible_collections/src/arc.rs b/third_party/rust/fallible_collections/src/arc.rs index 282b8e5555..26a6ec9407 100644 --- a/third_party/rust/fallible_collections/src/arc.rs +++ b/third_party/rust/fallible_collections/src/arc.rs @@ -1,15 +1,20 @@ //! Implement a Fallible Arc +#[cfg(any(not(feature = "unstable"), feature = "rust_1_57"))] use super::FallibleBox; use super::TryClone; - use crate::TryReserveError; + +#[cfg(any(not(feature = "unstable"), feature = "rust_1_57"))] use alloc::boxed::Box; use alloc::sync::Arc; /// trait to implement Fallible Arc -#[deprecated( - since = "0.3.1", - note = "⚠️️️this function is not completely fallible, it can panic !, see [issue](https://github.com/vcombey/fallible_collections/issues/13). help wanted" +#[cfg_attr( + any(not(feature = "unstable"), feature = "rust_1_57"), + deprecated( + since = "0.3.1", + note = "⚠️️️this function is not completely fallible, it can panic !, see [issue](https://github.com/vcombey/fallible_collections/issues/13). help wanted" + ) )] pub trait FallibleArc { /// try creating a new Arc, returning a Result, @@ -22,10 +27,24 @@ pub trait FallibleArc { #[allow(deprecated)] impl FallibleArc for Arc { fn try_new(t: T) -> Result { - // doesn't work as the inner variable of arc are also stocked in the box - - let b = as FallibleBox>::try_new(t)?; - Ok(Arc::from(b)) + #[cfg(any(not(feature = "unstable"), feature = "rust_1_57"))] + { + // doesn't work as the inner variable of arc are also stocked in the box + let b = as FallibleBox>::try_new(t)?; + Ok(Arc::from(b)) + } + #[cfg(all(feature = "unstable", not(feature = "rust_1_57")))] + { + use alloc::alloc::Layout; + use alloc::collections::TryReserveErrorKind; + Arc::try_new(t).map_err(|_e| { + TryReserveErrorKind::AllocError { + layout: Layout::new::>(), // This is bullshit + non_exhaustive: (), + } + .into() + }) + } } } diff --git a/third_party/rust/fallible_collections/src/boxed.rs b/third_party/rust/fallible_collections/src/boxed.rs index 6040754716..6680c713f4 100644 --- a/third_party/rust/fallible_collections/src/boxed.rs +++ b/third_party/rust/fallible_collections/src/boxed.rs @@ -64,19 +64,22 @@ impl Deref for TryBox { } fn alloc(layout: Layout) -> Result, TryReserveError> { - #[cfg(feature = "unstable")] // requires allocator_api + #[cfg(all(feature = "unstable", not(feature = "rust_1_57")))] // requires allocator_api { + use alloc::collections::TryReserveErrorKind; use core::alloc::Allocator; alloc::alloc::Global .allocate(layout) - .map_err(|_e| TryReserveError::AllocError { - layout, - #[cfg(not(feature = "rust_1_57"))] - non_exhaustive: (), + .map_err(|_e| { + TryReserveErrorKind::AllocError { + layout, + non_exhaustive: (), + } + .into() }) .map(|v| v.cast()) } - #[cfg(not(feature = "unstable"))] + #[cfg(any(not(feature = "unstable"), feature = "rust_1_57"))] { match layout.size() { 0 => { diff --git a/third_party/rust/fallible_collections/src/btree/node.rs b/third_party/rust/fallible_collections/src/btree/node.rs index 249aeb6598..bed459dcfe 100644 --- a/third_party/rust/fallible_collections/src/btree/node.rs +++ b/third_party/rust/fallible_collections/src/btree/node.rs @@ -670,8 +670,8 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { let idx = self.len(); unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); + ptr::write(self.keys_mut().as_mut_ptr().add(idx), key); + ptr::write(self.vals_mut().as_mut_ptr().add(idx), val); (*self.as_leaf_mut()).len += 1; } @@ -703,11 +703,14 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { let idx = self.len(); unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); + ptr::write(self.keys_mut().as_mut_ptr().add(idx), key); + ptr::write(self.vals_mut().as_mut_ptr().add(idx), val); self.as_internal_mut() .edges - .get_unchecked_mut(idx + 1) + .as_mut_ptr() + .add(idx + 1) + .as_mut() + .unwrap() .write(edge.node); (*self.as_leaf_mut()).len += 1; @@ -1002,7 +1005,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge (*self.node.as_leaf_mut()).len += 1; - self.node.vals_mut().get_unchecked_mut(self.idx) + self.node.vals_mut().as_mut_ptr().add(self.idx) } } @@ -1156,8 +1159,8 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> let (keys, vals) = self.node.into_slices_mut(); unsafe { ( - keys.get_unchecked_mut(self.idx), - vals.get_unchecked_mut(self.idx), + keys.as_mut_ptr().add(self.idx).as_mut().unwrap(), + vals.as_mut_ptr().add(self.idx).as_mut().unwrap(), ) } } @@ -1168,8 +1171,8 @@ impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker unsafe { let (keys, vals) = self.node.reborrow_mut().into_slices_mut(); ( - keys.get_unchecked_mut(self.idx), - vals.get_unchecked_mut(self.idx), + keys.as_mut_ptr().add(self.idx).as_mut().unwrap(), + vals.as_mut_ptr().add(self.idx).as_mut().unwrap(), ) } } @@ -1338,7 +1341,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: unsafe { ptr::write( - left_node.keys_mut().get_unchecked_mut(left_len), + left_node.keys_mut().as_mut_ptr().add(left_len), slice_remove(self.node.keys_mut(), self.idx), ); ptr::copy_nonoverlapping( @@ -1347,7 +1350,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: right_len, ); ptr::write( - left_node.vals_mut().get_unchecked_mut(left_len), + left_node.vals_mut().as_mut_ptr().add(left_len), slice_remove(self.node.vals_mut(), self.idx), ); ptr::copy_nonoverlapping( @@ -1662,7 +1665,7 @@ unsafe fn slice_insert(slice: &mut [T], idx: usize, val: T) { slice.as_mut_ptr().add(idx + 1), slice.len() - idx, ); - ptr::write(slice.get_unchecked_mut(idx), val); + ptr::write(slice.as_mut_ptr().add(idx), val); } unsafe fn slice_remove(slice: &mut [T], idx: usize) -> T { diff --git a/third_party/rust/fallible_collections/src/lib.rs b/third_party/rust/fallible_collections/src/lib.rs index 45dcd48d17..9f525d71b7 100644 --- a/third_party/rust/fallible_collections/src/lib.rs +++ b/third_party/rust/fallible_collections/src/lib.rs @@ -22,16 +22,22 @@ //! can't return a Result to indicate allocation failure. #![cfg_attr(not(test), no_std)] -#![cfg_attr(all(feature = "unstable", not(feature = "rust_1_57")), feature(try_reserve))] +#![cfg_attr(feature = "unstable", feature(try_reserve_kind))] #![cfg_attr(feature = "unstable", feature(min_specialization))] #![cfg_attr(feature = "unstable", feature(allocator_api))] #![cfg_attr(feature = "unstable", feature(dropck_eyepatch))] #![cfg_attr(feature = "unstable", feature(ptr_internals))] #![cfg_attr(feature = "unstable", feature(core_intrinsics))] -#![cfg_attr(all(feature = "unstable", not(feature = "rust_1_57")), feature(maybe_uninit_ref))] #![cfg_attr(feature = "unstable", feature(maybe_uninit_slice))] -#![cfg_attr(feature = "unstable", feature(maybe_uninit_extra))] #![cfg_attr(feature = "unstable", feature(maybe_uninit_uninit_array))] + +#[cfg(all(feature = "unstable", feature = "rust_1_57"))] +compile_error!( + "The use of the 'unstable' feature combined with the \ +'rust_1_57' feature, which is related to the partial stabilization \ +of the allocator API since rustc version 1.57, does not make sense!" +); + extern crate alloc; #[cfg(feature = "std")] extern crate std; @@ -47,18 +53,16 @@ pub mod arc; pub use arc::*; #[cfg(feature = "unstable")] pub mod btree; -#[cfg(not(feature = "unstable"))] +#[cfg(all(feature = "hashmap", not(feature = "unstable")))] pub mod hashmap; -#[cfg(not(feature = "unstable"))] +#[cfg(all(feature = "hashmap", not(feature = "unstable")))] pub use hashmap::*; #[macro_use] pub mod format; pub mod try_clone; -#[cfg(all(feature = "unstable", not(feature = "rust_1_57")))] -pub use alloc::collections::TryReserveError; -#[cfg(not(all(feature = "unstable", not(feature = "rust_1_57"))))] -pub use hashbrown::TryReserveError; +pub mod try_reserve_error; +pub use try_reserve_error::TryReserveError; #[cfg(feature = "std_io")] pub use vec::std_io::*; @@ -81,7 +85,7 @@ pub trait TryClone { } #[cfg(feature = "rust_1_57")] -fn make_try_reserve_error(len: usize, additional: usize, elem_size: usize, align: usize) -> hashbrown::TryReserveError { +fn make_try_reserve_error(len: usize, additional: usize, elem_size: usize, align: usize) -> TryReserveError { if let Some(size) = len.checked_add(additional).and_then(|l| l.checked_mul(elem_size)) { if let Ok(layout) = alloc::alloc::Layout::from_size_align(size, align) { return TryReserveError::AllocError { layout } diff --git a/third_party/rust/fallible_collections/src/try_reserve_error.rs b/third_party/rust/fallible_collections/src/try_reserve_error.rs new file mode 100644 index 0000000000..ec3a998f2e --- /dev/null +++ b/third_party/rust/fallible_collections/src/try_reserve_error.rs @@ -0,0 +1,19 @@ +#[cfg(all(feature = "unstable", not(feature = "rust_1_57")))] +pub use alloc::collections::TryReserveError; +#[cfg(all(feature = "hashmap", not(all(feature = "unstable", not(feature = "rust_1_57")))))] +pub use hashbrown::TryReserveError; + +/// The error type for `try_reserve` methods. +#[cfg(all(not(feature = "hashmap"), not(all(feature = "unstable", not(feature = "rust_1_57")))))] +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TryReserveError { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + + /// The memory allocator returned an error + AllocError { + /// The layout of the allocation request that failed. + layout: alloc::alloc::Layout, + }, +} \ No newline at end of file diff --git a/third_party/rust/fallible_collections/src/vec.rs b/third_party/rust/fallible_collections/src/vec.rs index 6197b5b5d6..d4ed4df74c 100644 --- a/third_party/rust/fallible_collections/src/vec.rs +++ b/third_party/rust/fallible_collections/src/vec.rs @@ -515,7 +515,7 @@ impl FallibleVec for Vec { self.try_reserve(additional) } - #[cfg(not(feature = "rust_1_57"))] + #[cfg(all(not(feature = "unstable"), not(feature = "rust_1_57")))] { vec_try_reserve(self, additional) } @@ -624,7 +624,7 @@ impl FallibleVec for Vec { let mut iterator = other.iter(); while let Some(element) = iterator.next() { unsafe { - core::ptr::write(self.get_unchecked_mut(len), element.try_clone()?); + core::ptr::write(self.as_mut_ptr().add(len), element.try_clone()?); // NB can't overflow since we would have had to alloc the address space len += 1; self.set_len(len); diff --git a/third_party/rust/getrandom/.cargo-checksum.json b/third_party/rust/getrandom/.cargo-checksum.json index fc46f728c8..cdbd3bb230 100644 --- a/third_party/rust/getrandom/.cargo-checksum.json +++ b/third_party/rust/getrandom/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"fe1a0dc50ac5c7bdd60591f6d1027072c68dcf142131945f782169c74b9e8188","Cargo.toml":"5506345251dee6e156a3d0072d2b3b6bc6894d8cf91adb85fefe211741e7c7f9","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"e5858de17fc28ec7a3a62cbefedd301ace8a85291d0aad5cb416824d1b5abadd","SECURITY.md":"816ea79f8c7937888ab5a972a1efb270c4bada028b448953a195359fe11d526e","benches/buffer.rs":"242f56eaeecd1d0a0f6f9419d1bf312b8d211215355022bd4aef5e5e0f53e2a5","src/3ds.rs":"e41b653723740ed89fa68f495b64125786e8dec002e3556d164c5795db62ea50","src/apple-other.rs":"3ff0abc72786a2ac063cdc5df4d18cc53dc493cd68fcb33734cf40cfdbb8f644","src/bsd_arandom.rs":"cfa0627a6b4d1f37065d415972ab813bf1c9f43979d2ff9440c92a53868123aa","src/custom.rs":"a256bd6e7e9bb560803f23a36bd437859ea8a9d8ec92608930b94b33e7314c64","src/dragonfly.rs":"047008e742a7a8050e61ed9626b9f4146dfaa0675e11d6f3680eb8af498d9a6d","src/emscripten.rs":"e0b3b44b52f54454ec3e0a9e7c5222003369d9d1575cc0652e3e7cbe1b3b6da7","src/error.rs":"ff09a7e02d7aff3e45eca6bbef6c686cc46f3c2371a0897a856e4dec4b942e46","src/error_impls.rs":"9c34832ebb99cd5e31bc5c8ffc5beb5b3fa6f7ff0226aaa1cdf8e10e6d64b324","src/espidf.rs":"915ca14cbf9299de51a3c67f34fdd252461d6545f33a7232dfb7fa247ccc0209","src/fuchsia.rs":"d307b15db9f2d67b43050ae6027779a6eb2b8a69e1e89931b55b767aa2622250","src/hermit.rs":"18fdd7917c73f8b16aa82b18003948d32f9b314da10e16ef9cd2fa077b17af00","src/hurd.rs":"1053908c4eaeae9e44078c9509aa80268caa1d66642b7c6a9a80f5b9f0e63fb0","src/js.rs":"c4cd60bcfe63f8affe947773197e288536ab205a73001059f39fc2e5688e98b6","src/lib.rs":"178b4b1dae3a41721f365ea5a4eda3f5b936b310afa4431935968e96edac3120","src/linux_android.rs":"e5f9e579bbde254fcab8f6b79b893d6b74054e023b21c56a3b2b21d8f4b4d825","src/macos.rs":"8f51e095906e751b68e837bfc63cc02b243e1698b66353566ccba507c81ddad3","src/openbsd.rs":"f6fd0aa74f704335a7e0532bf5e61a7ca90b0cbc398a9c01a0fd891b6fabca0c","src/rdrand.rs":"846ac7b8380a05a50e0592dca57338beb1634c0efc878d6d1e9421be3469a744","src/solaris_illumos.rs":"7209c8b1172fc4df5ad8a79f165556b403cdd90b9eb5f7f7f9ec97bf06f4d8d7","src/solid.rs":"58919109faf06e6d546f75f785d78d6c055e1f95110d1791d9191d1e404f1e20","src/use_file.rs":"ecfc1011b4a9c962ae9b4b75ca5149a4ee83cb0951a80224ce5417046ce11717","src/util.rs":"580fb7c4e41eb6007def8626e019829c22a63980fa4da68a1adef687c57953a2","src/util_libc.rs":"48c1fe251958c6c57b7c93d83f3648d97034feeee0d5cda0cbe7bc0ee0a73fca","src/vita.rs":"ecfa9d347ad5c480ba8ff80a9de968ae060ffb435f1e95777ee413642e62e50a","src/vxworks.rs":"984726b6dd9638a38ceda83124683419b9d69a9041ad9117a470eaec5b386ce4","src/wasi.rs":"229a58af3f13a629571fb83a0c11ef0ed696ba7a44ee2e811c9f348a19b2fb69","src/windows.rs":"dd3d833979fb6b96c04b84dbf8461d5fc819bde93ad9dc26bd0f6c282656c733","tests/common/mod.rs":"b9a36043d71963ba43a9e2899ba8eea80ff9f3284d243d9b9b9f941afa4f4aa4","tests/custom.rs":"1e944ae523b62dba53fe3daf1b964a2498c8fdd21dfa7afe53781bff2fcf276e","tests/normal.rs":"9e1c4b1e468a09ed0225370dfb6608f8b8135e0fabb09bbc1a718105164aade6","tests/rdrand.rs":"156676b57f1e6bd4d66d85b8a999f1cf7a8fb749a10b8b2b4dbbcf803e8c4cd3"},"package":"fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"} \ No newline at end of file +{"files":{"CHANGELOG.md":"d77ff9f599c3e313723df758f861e23f3caa696d0b8595af2975c2cc5be0f254","Cargo.toml":"822356b05121dcc6f3ec20d99814a93c9511e2bb3612266214e2e94fe844e9c3","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"42fa16951ce7f24b5a467a40e5b449a1d41e662f97ca779864f053f39e097737","README.md":"543f0efa922ff55d3cdc1c96a188dff669f57a2ff3b7dfa0c95368b8e646b5dd","SECURITY.md":"816ea79f8c7937888ab5a972a1efb270c4bada028b448953a195359fe11d526e","benches/buffer.rs":"242f56eaeecd1d0a0f6f9419d1bf312b8d211215355022bd4aef5e5e0f53e2a5","src/3ds.rs":"dae5b84328b063a3750a67e5086db530b905a661b152181f0d6b4d63e72b70e2","src/apple-other.rs":"75f2c3319068e06ec27135d516953ab645cc7c45033f045cba44136236ef5601","src/bsd_arandom.rs":"2ace9473afc3df95594884d87d8f484cf141c9d01f2c22ece2bb1118b73d51bb","src/custom.rs":"ae5dc94bc12a4a284762e99891b013c509942b1a802ea559e04e572ed44479dc","src/dragonfly.rs":"4cffb7af2b62d515f28790b906f0293b44af1d75b23c87fa9e50d5ef99bfa02c","src/emscripten.rs":"e0b3b44b52f54454ec3e0a9e7c5222003369d9d1575cc0652e3e7cbe1b3b6da7","src/error.rs":"ab5b82ddb8304e8ad75d905d7dc5ba8deec92096930e81e87d7a28f3da382dee","src/error_impls.rs":"4c068e81d876237a7e0a0e91519896bd670c2f999ca729f7fb970caf888cab46","src/espidf.rs":"50f70136fe46f9fe9a728aa7881cdc8144f430620168cf42519c2666a8edc11f","src/fuchsia.rs":"535ed84250cfe8f176494eba226d1c1df9687b5c30cf52d5949f56a591947656","src/hermit.rs":"c9d9d5c78e0e435c2678ef43d1296aef885fd62957d6b454d758ca475cd4e544","src/hurd.rs":"c0f807d7cc4ae6a5e0b1800bbd76639270503596c8f3cade2e59bf62e0bc7a89","src/js.rs":"4306b7a49441e0da2a0737f92f56d3258ddcd1566ec3aea4a4f4a865bbf0ff87","src/lazy.rs":"21764d7cffe5177a331ec37758cc550c6e3be8c5f6fdfb7606053dafbe6a994b","src/lib.rs":"085e7246d863322ef2031b8c6ac40245c77ce3cb0cc71ac5e0c102d188080780","src/linux_android.rs":"92c71e68adcb9bc4ee39e6b2db730e06af1e0c8db0389712b5ea8a1d86991277","src/linux_android_with_fallback.rs":"620577d889d92916aeed62ac0e4f711725fddb7e7bb331f02474160104354e8e","src/macos.rs":"6e4f8377c7ad3c5dea1816a7bac22a3bb5ba85260aee71d027e32cd6602cb2dd","src/openbsd.rs":"f22ffe151d1797785c32e165459e15a34643f8a441c12da736e8a22d7103db6e","src/rdrand.rs":"ffbe1bfb8f5b30a95f462fa85db07e251f63248c6c0daf3b5f586034cedfa976","src/solaris_illumos.rs":"2f0d03956d042249aed1c2f02fc9ad389ab4dcd1dfe5c5e7c189830545497259","src/solid.rs":"a5a6e4b2b43400548b36035b9a513e70ec17809d521757e7228d2214352d24ed","src/use_file.rs":"1d7cf9370697ae69d29792d0a50ae972b093676536eb0529d9a801efbecbb096","src/util.rs":"e2c1b86ea97ca5c61d562182890cbe24c7eaa37ff8945c17fcfa665b767da1b0","src/util_libc.rs":"9321ac241c1e2088e7a73d3323a79076f5d9253cf2f077ea7083be86ee313469","src/vita.rs":"97dc7ddd706c0c64273cc5b2a6c9cab47c221921908809a9f9a8b72a1753ce90","src/vxworks.rs":"3c132cd52df3a8cf903f430ce90d3432c4b4bb99bf069f5546dee43f4f10a555","src/wasi.rs":"45b95d98766cfdc0495cfe5da6c3b63e99dda34c334deee779cf146a29350344","src/windows.rs":"7e3e73fb29a7e2748d32344d1bb9327603c6d78eb0fc5e62f50c6fa93b648c60","tests/common/mod.rs":"b9a36043d71963ba43a9e2899ba8eea80ff9f3284d243d9b9b9f941afa4f4aa4","tests/custom.rs":"1e944ae523b62dba53fe3daf1b964a2498c8fdd21dfa7afe53781bff2fcf276e","tests/normal.rs":"9e1c4b1e468a09ed0225370dfb6608f8b8135e0fabb09bbc1a718105164aade6","tests/rdrand.rs":"fcf3f78e3078e1b262d0efae8f3c4a730f3fbf68df656fceb78e22ee4cc98990"},"package":"94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"} \ No newline at end of file diff --git a/third_party/rust/getrandom/CHANGELOG.md b/third_party/rust/getrandom/CHANGELOG.md index 7b1f46aabc..fb9d94b7dd 100644 --- a/third_party/rust/getrandom/CHANGELOG.md +++ b/third_party/rust/getrandom/CHANGELOG.md @@ -4,6 +4,42 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.14] - 2024-04-08 +### Fixed +- Enable `/dev/urandom` fallback for MUSL-based Linux targets [#408] + +[#408]: https://github.com/rust-random/getrandom/pull/408 + +## [0.2.13] - 2024-04-06 +### Added +- `linux_disable_fallback` crate feature to disable `/dev/urandom`-based fallback on Linux and + Android targets. Enabling this feature bumps minimum supported Linux kernel version to 3.17 and + Android API level to 23 (Marshmallow). [#396] + +### Changed +- Disable `/dev/urandom` fallback for Linux targets outside of the following `target_arch`es: + `aarch64`, `arm`, `powerpc`, `powerpc64`, `s390x`, `x86`, `x86_64` [#396] +- Do not catch `EPERM` error code on Android while checking availability of + the `getrandom` syscall [#396] + +[#396]: https://github.com/rust-random/getrandom/pull/396 + +## [0.2.12] - 2024-01-09 +### Fixed +- Custom backend for targets without atomics [#385] + +### Changed +- Improve robustness of the Hermit backend and `sys_fill_exact` [#386] +- Raise minimum supported Apple OS versions to macOS 10.12 and iOS 10 [#388] + +### Added +- Document platform support policy [#387] + +[#385]: https://github.com/rust-random/getrandom/pull/385 +[#386]: https://github.com/rust-random/getrandom/pull/386 +[#387]: https://github.com/rust-random/getrandom/pull/387 +[#388]: https://github.com/rust-random/getrandom/pull/388 + ## [0.2.11] - 2023-11-08 ### Added - GNU/Hurd support [#370] @@ -403,6 +439,9 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. +[0.2.14]: https://github.com/rust-random/getrandom/compare/v0.2.13...v0.2.14 +[0.2.13]: https://github.com/rust-random/getrandom/compare/v0.2.12...v0.2.13 +[0.2.12]: https://github.com/rust-random/getrandom/compare/v0.2.11...v0.2.12 [0.2.11]: https://github.com/rust-random/getrandom/compare/v0.2.10...v0.2.11 [0.2.10]: https://github.com/rust-random/getrandom/compare/v0.2.9...v0.2.10 [0.2.9]: https://github.com/rust-random/getrandom/compare/v0.2.8...v0.2.9 diff --git a/third_party/rust/getrandom/Cargo.toml b/third_party/rust/getrandom/Cargo.toml index a4c3946b73..1cb474ef6b 100644 --- a/third_party/rust/getrandom/Cargo.toml +++ b/third_party/rust/getrandom/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "getrandom" -version = "0.2.11" +version = "0.2.14" authors = ["The Rand Project Developers"] exclude = [".*"] description = "A small cross-platform library for retrieving random data from system source" @@ -63,6 +63,7 @@ js = [ "wasm-bindgen", "js-sys", ] +linux_disable_fallback = [] rdrand = [] rustc-dep-of-std = [ "compiler_builtins", diff --git a/third_party/rust/getrandom/LICENSE-MIT b/third_party/rust/getrandom/LICENSE-MIT index d93b5baf34..8ca28a1a09 100644 --- a/third_party/rust/getrandom/LICENSE-MIT +++ b/third_party/rust/getrandom/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright 2018 Developers of the Rand project +Copyright (c) 2018-2024 The rust-random Project Developers Copyright (c) 2014 The Rust Project Developers Permission is hereby granted, free of charge, to any diff --git a/third_party/rust/getrandom/README.md b/third_party/rust/getrandom/README.md index c43ad42eb8..b4b5a2b566 100644 --- a/third_party/rust/getrandom/README.md +++ b/third_party/rust/getrandom/README.md @@ -54,11 +54,28 @@ crate features, WASM support and Custom RNGs see the This crate requires Rust 1.36.0 or later. -# License +## Platform Support + +This crate generally supports the same operating system and platform versions that the Rust standard library does. +Additional targets may be supported using pluggable custom implementations. + +This means that as Rust drops support for old versions of operating systems (such as old Linux kernel versions, Android API levels, etc) +in stable releases, `getrandom` may create new patch releases (`0.N.x`) that remove support for outdated platform versions. + +## License The `getrandom` library is distributed under either of - * [Apache License, Version 2.0](LICENSE-APACHE) - * [MIT license](LICENSE-MIT) + * [Apache License, Version 2.0][LICENSE-APACHE] + * [MIT license][LICENSE-MIT] at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[LICENSE-APACHE]: https://github.com/rust-random/getrandom/blob/master/LICENSE-APACHE +[LICENSE-MIT]: https://github.com/rust-random/getrandom/blob/master/LICENSE-MIT diff --git a/third_party/rust/getrandom/src/3ds.rs b/third_party/rust/getrandom/src/3ds.rs index 87a32a1e80..a5aae77d10 100644 --- a/third_party/rust/getrandom/src/3ds.rs +++ b/third_party/rust/getrandom/src/3ds.rs @@ -1,11 +1,3 @@ -// Copyright 2021 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for Nintendo 3DS use crate::util_libc::sys_fill_exact; use crate::Error; diff --git a/third_party/rust/getrandom/src/apple-other.rs b/third_party/rust/getrandom/src/apple-other.rs index 8f904859ca..167d8cf0fa 100644 --- a/third_party/rust/getrandom/src/apple-other.rs +++ b/third_party/rust/getrandom/src/apple-other.rs @@ -1,24 +1,21 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for iOS +//! Implementation for iOS, tvOS, and watchOS where `getentropy` is unavailable. use crate::Error; -use core::{ffi::c_void, mem::MaybeUninit, ptr::null}; +use core::{ffi::c_void, mem::MaybeUninit}; -#[link(name = "Security", kind = "framework")] +// libsystem contains the libc of Darwin, and every binary ends up linked against it either way. This +// makes it a more lightweight choice compared to `Security.framework`. extern "C" { - fn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> i32; + // This RNG uses a thread-local CSPRNG to provide data, which is seeded by the operating system's root CSPRNG. + // Its the best option after `getentropy` on modern Darwin-based platforms that also avoids the + // high startup costs and linking of Security.framework. + // + // While its just an implementation detail, `Security.framework` just calls into this anyway. + fn CCRandomGenerateBytes(bytes: *mut c_void, size: usize) -> i32; } pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // Apple's documentation guarantees kSecRandomDefault is a synonym for NULL. - let ret = unsafe { SecRandomCopyBytes(null(), dest.len(), dest.as_mut_ptr() as *mut u8) }; - // errSecSuccess (from SecBase.h) is always zero. + let ret = unsafe { CCRandomGenerateBytes(dest.as_mut_ptr() as *mut c_void, dest.len()) }; + // kCCSuccess (from CommonCryptoError.h) is always zero. if ret != 0 { Err(Error::IOS_SEC_RANDOM) } else { diff --git a/third_party/rust/getrandom/src/bsd_arandom.rs b/third_party/rust/getrandom/src/bsd_arandom.rs index 5314c48f19..6e133d8957 100644 --- a/third_party/rust/getrandom/src/bsd_arandom.rs +++ b/third_party/rust/getrandom/src/bsd_arandom.rs @@ -1,11 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for FreeBSD and NetBSD use crate::{ util_libc::{sys_fill_exact, Weak}, diff --git a/third_party/rust/getrandom/src/custom.rs b/third_party/rust/getrandom/src/custom.rs index 66e4256fad..79be7fc26e 100644 --- a/third_party/rust/getrandom/src/custom.rs +++ b/third_party/rust/getrandom/src/custom.rs @@ -1,11 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! An implementation which calls out to an externally defined function. use crate::{util::uninit_slice_fill_zero, Error}; use core::{mem::MaybeUninit, num::NonZeroU32}; @@ -73,7 +65,6 @@ use core::{mem::MaybeUninit, num::NonZeroU32}; /// [top-level documentation](index.html#custom-implementations) this /// registration only has an effect on unsupported targets. #[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "custom")))] macro_rules! register_custom_getrandom { ($path:path) => { // TODO(MSRV 1.37): change to unnamed block diff --git a/third_party/rust/getrandom/src/dragonfly.rs b/third_party/rust/getrandom/src/dragonfly.rs index d3ef00aa9c..ac4794cdd9 100644 --- a/third_party/rust/getrandom/src/dragonfly.rs +++ b/third_party/rust/getrandom/src/dragonfly.rs @@ -1,11 +1,3 @@ -// Copyright 2021 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for DragonFly BSD use crate::{ use_file, diff --git a/third_party/rust/getrandom/src/error.rs b/third_party/rust/getrandom/src/error.rs index ab39a3c33a..13c81c7aff 100644 --- a/third_party/rust/getrandom/src/error.rs +++ b/third_party/rust/getrandom/src/error.rs @@ -1,10 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. use core::{fmt, num::NonZeroU32}; /// A small and `no_std` compatible error type @@ -35,7 +28,11 @@ impl Error { pub const UNSUPPORTED: Error = internal_error(0); /// The platform-specific `errno` returned a non-positive value. pub const ERRNO_NOT_POSITIVE: Error = internal_error(1); - /// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed. + /// Encountered an unexpected situation which should not happen in practice. + pub const UNEXPECTED: Error = internal_error(2); + /// Call to [`CCRandomGenerateBytes`](https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html) failed + /// on iOS, tvOS, or waatchOS. + // TODO: Update this constant name in the next breaking release. pub const IOS_SEC_RANDOM: Error = internal_error(3); /// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed. pub const WINDOWS_RTL_GEN_RANDOM: Error = internal_error(4); @@ -164,6 +161,7 @@ fn internal_desc(error: Error) -> Option<&'static str> { match error { Error::UNSUPPORTED => Some("getrandom: this target is not supported"), Error::ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"), + Error::UNEXPECTED => Some("unexpected situation"), Error::IOS_SEC_RANDOM => Some("SecRandomCopyBytes: iOS Security framework failure"), Error::WINDOWS_RTL_GEN_RANDOM => Some("RtlGenRandom: Windows system function failure"), Error::FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"), diff --git a/third_party/rust/getrandom/src/error_impls.rs b/third_party/rust/getrandom/src/error_impls.rs index 61f46d2279..2c326012c8 100644 --- a/third_party/rust/getrandom/src/error_impls.rs +++ b/third_party/rust/getrandom/src/error_impls.rs @@ -1,15 +1,6 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -#![cfg_attr(docsrs, doc(cfg(feature = "std")))] extern crate std; use crate::Error; -use core::convert::From; use std::io; impl From for io::Error { diff --git a/third_party/rust/getrandom/src/espidf.rs b/third_party/rust/getrandom/src/espidf.rs index d074dc4cec..7da5ca88ea 100644 --- a/third_party/rust/getrandom/src/espidf.rs +++ b/third_party/rust/getrandom/src/espidf.rs @@ -1,11 +1,3 @@ -// Copyright 2021 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for ESP-IDF use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; diff --git a/third_party/rust/getrandom/src/fuchsia.rs b/third_party/rust/getrandom/src/fuchsia.rs index 5a135f3430..11970685c0 100644 --- a/third_party/rust/getrandom/src/fuchsia.rs +++ b/third_party/rust/getrandom/src/fuchsia.rs @@ -1,11 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for Fuchsia Zircon use crate::Error; use core::mem::MaybeUninit; diff --git a/third_party/rust/getrandom/src/hermit.rs b/third_party/rust/getrandom/src/hermit.rs index 570b03d9a5..c4f619417e 100644 --- a/third_party/rust/getrandom/src/hermit.rs +++ b/third_party/rust/getrandom/src/hermit.rs @@ -1,5 +1,11 @@ +//! Implementation for Hermit use crate::Error; -use core::{cmp::min, mem::MaybeUninit, num::NonZeroU32}; +use core::{mem::MaybeUninit, num::NonZeroU32}; + +/// Minimum return value which we should get from syscalls in practice, +/// because Hermit uses positive `i32`s for error codes: +/// https://github.com/hermitcore/libhermit-rs/blob/main/src/errno.rs +const MIN_RET_CODE: isize = -(i32::MAX as isize); extern "C" { fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize; @@ -8,14 +14,16 @@ extern "C" { pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { while !dest.is_empty() { let res = unsafe { sys_read_entropy(dest.as_mut_ptr() as *mut u8, dest.len(), 0) }; - if res < 0 { - // SAFETY: all Hermit error codes use i32 under the hood: - // https://github.com/hermitcore/libhermit-rs/blob/master/src/errno.rs - let code = unsafe { NonZeroU32::new_unchecked((-res) as u32) }; - return Err(code.into()); + // Positive `isize`s can be safely casted to `usize` + if res > 0 && (res as usize) <= dest.len() { + dest = &mut dest[res as usize..]; + } else { + let err = match res { + MIN_RET_CODE..=-1 => NonZeroU32::new(-res as u32).unwrap().into(), + _ => Error::UNEXPECTED, + }; + return Err(err); } - let len = min(res as usize, dest.len()); - dest = &mut dest[len..]; } Ok(()) } diff --git a/third_party/rust/getrandom/src/hurd.rs b/third_party/rust/getrandom/src/hurd.rs index 842b9bc481..472a7d86b2 100644 --- a/third_party/rust/getrandom/src/hurd.rs +++ b/third_party/rust/getrandom/src/hurd.rs @@ -1,11 +1,3 @@ -// Copyright 2021 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for GNU/Hurd use crate::util_libc::sys_fill_exact; use crate::Error; diff --git a/third_party/rust/getrandom/src/js.rs b/third_party/rust/getrandom/src/js.rs index d031282261..e5428f50d1 100644 --- a/third_party/rust/getrandom/src/js.rs +++ b/third_party/rust/getrandom/src/js.rs @@ -1,10 +1,4 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. +//! Implementation for WASM based on Web and Node.js use crate::Error; extern crate std; diff --git a/third_party/rust/getrandom/src/lazy.rs b/third_party/rust/getrandom/src/lazy.rs new file mode 100644 index 0000000000..100ce1eaf5 --- /dev/null +++ b/third_party/rust/getrandom/src/lazy.rs @@ -0,0 +1,56 @@ +use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + +// This structure represents a lazily initialized static usize value. Useful +// when it is preferable to just rerun initialization instead of locking. +// unsync_init will invoke an init() function until it succeeds, then return the +// cached value for future calls. +// +// unsync_init supports init() "failing". If the init() method returns UNINIT, +// that value will be returned as normal, but will not be cached. +// +// Users should only depend on the _value_ returned by init() functions. +// Specifically, for the following init() function: +// fn init() -> usize { +// a(); +// let v = b(); +// c(); +// v +// } +// the effects of c() or writes to shared memory will not necessarily be +// observed and additional synchronization methods may be needed. +pub(crate) struct LazyUsize(AtomicUsize); + +impl LazyUsize { + pub const fn new() -> Self { + Self(AtomicUsize::new(Self::UNINIT)) + } + + // The initialization is not completed. + pub const UNINIT: usize = usize::max_value(); + + // Runs the init() function at most once, returning the value of some run of + // init(). Multiple callers can run their init() functions in parallel. + // init() should always return the same value, if it succeeds. + pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { + // Relaxed ordering is fine, as we only have a single atomic variable. + let mut val = self.0.load(Relaxed); + if val == Self::UNINIT { + val = init(); + self.0.store(val, Relaxed); + } + val + } +} + +// Identical to LazyUsize except with bool instead of usize. +pub(crate) struct LazyBool(LazyUsize); + +impl LazyBool { + pub const fn new() -> Self { + Self(LazyUsize::new()) + } + + pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { + self.0.unsync_init(|| init() as usize) != 0 + } +} diff --git a/third_party/rust/getrandom/src/lib.rs b/third_party/rust/getrandom/src/lib.rs index 10cc227377..b3b3d0e24b 100644 --- a/third_party/rust/getrandom/src/lib.rs +++ b/third_party/rust/getrandom/src/lib.rs @@ -1,11 +1,3 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Interface to the operating system's random number generator. //! //! # Supported targets @@ -14,8 +6,8 @@ //! | ----------------- | ------------------ | -------------- //! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` //! | Windows | `*‑windows‑*` | [`BCryptGenRandom`] -//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] if available, otherwise [`/dev/urandom`][4] (identical to `/dev/random`) -//! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`SecRandomCopyBytes`] +//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] +//! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`CCRandomGenerateBytes`] //! | FreeBSD | `*‑freebsd` | [`getrandom`][5] if available, otherwise [`kern.arandom`][6] //! | OpenBSD | `*‑openbsd` | [`getentropy`][7] //! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] @@ -55,6 +47,21 @@ //! This prevents a crate from overriding a secure source of randomness //! (either accidentally or intentionally). //! +//! ## `/dev/urandom` fallback on Linux and Android +//! +//! On Linux targets the fallback is present only if either `target_env` is `musl`, +//! or `target_arch` is one of the following: `aarch64`, `arm`, `powerpc`, `powerpc64`, +//! `s390x`, `x86`, `x86_64`. Other supported targets [require][platform-support] +//! kernel versions which support `getrandom` system call, so fallback is not needed. +//! +//! On Android targets the fallback is present only for the following `target_arch`es: +//! `aarch64`, `arm`, `x86`, `x86_64`. Other `target_arch`es (e.g. RISC-V) require +//! sufficiently high API levels. +//! +//! The fallback can be disabled by enabling the `linux_disable_fallback` crate feature. +//! Note that doing so will bump minimum supported Linux kernel version to 3.17 and +//! Android API level to 23 (Marshmallow). +//! //! ### RDRAND on x86 //! //! *If the `rdrand` Cargo feature is enabled*, `getrandom` will fallback to using @@ -106,6 +113,16 @@ //! ``` //! This crate will then use the provided `webcrypto` implementation. //! +//! ### Platform Support +//! This crate generally supports the same operating system and platform versions +//! that the Rust standard library does. Additional targets may be supported using +//! pluggable custom implementations. +//! +//! This means that as Rust drops support for old versions of operating systems +//! (such as old Linux kernel versions, Android API levels, etc) in stable releases, +//! `getrandom` may create new patch releases (`0.N.x`) that remove support for +//! outdated platform versions. +//! //! ### Custom implementations //! //! The [`register_custom_getrandom!`] macro allows a user to mark their own @@ -151,8 +168,8 @@ //! on every call to `getrandom`, hence after the first successful call one //! can be reasonably confident that no errors will occur. //! -//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html -//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html +//! [1]: https://manned.org/getrandom.2 +//! [2]: https://manned.org/urandom.4 //! [3]: https://www.unix.com/man-page/mojave/2/getentropy/ //! [4]: https://www.unix.com/man-page/mojave/4/urandom/ //! [5]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable @@ -172,7 +189,7 @@ //! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom //! [`Crypto.getRandomValues`]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues //! [`RDRAND`]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide -//! [`SecRandomCopyBytes`]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc +//! [`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html //! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw //! [`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size //! [`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t @@ -183,15 +200,16 @@ //! [CommonJS modules]: https://nodejs.org/api/modules.html //! [ES modules]: https://nodejs.org/api/esm.html //! [`sys_read_entropy`]: https://github.com/hermit-os/kernel/blob/315f58ff5efc81d9bf0618af85a59963ff55f8b1/src/syscalls/entropy.rs#L47-L55 +//! [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://docs.rs/getrandom/0.2.11" + html_root_url = "https://docs.rs/getrandom/0.2.14" )] #![no_std] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #[macro_use] extern crate cfg_if; @@ -221,9 +239,52 @@ cfg_if! { if #[cfg(any(target_os = "haiku", target_os = "redox", target_os = "nto", target_os = "aix"))] { mod util_libc; #[path = "use_file.rs"] mod imp; - } else if #[cfg(any(target_os = "android", target_os = "linux"))] { + } else if #[cfg(all( + not(feature = "linux_disable_fallback"), + any( + // Rust supports Android API level 19 (KitKat) [0] and the next upgrade targets + // level 21 (Lollipop) [1], while `getrandom(2)` was added only in + // level 23 (Marshmallow). Note that it applies only to the "old" `target_arch`es, + // RISC-V Android targets sufficiently new API level, same will apply for potential + // new Android `target_arch`es. + // [0]: https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html + // [1]: https://github.com/rust-lang/rust/pull/120593 + all( + target_os = "android", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "x86", + target_arch = "x86_64", + ), + ), + // Only on these `target_arch`es Rust supports Linux kernel versions (3.2+) + // that precede the version (3.17) in which `getrandom(2)` was added: + // https://doc.rust-lang.org/stable/rustc/platform-support.html + all( + target_os = "linux", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + target_arch = "x86", + target_arch = "x86_64", + // Minimum supported Linux kernel version for MUSL targets + // is not specified explicitly (as of Rust 1.77) and they + // are used in practice to target pre-3.17 kernels. + target_env = "musl", + ), + ) + ), + ))] { mod util_libc; mod use_file; + mod lazy; + #[path = "linux_android_with_fallback.rs"] mod imp; + } else if #[cfg(any(target_os = "android", target_os = "linux"))] { + mod util_libc; #[path = "linux_android.rs"] mod imp; } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] { mod util_libc; @@ -242,7 +303,6 @@ cfg_if! { #[path = "apple-other.rs"] mod imp; } else if #[cfg(target_os = "macos")] { mod util_libc; - mod use_file; #[path = "macos.rs"] mod imp; } else if #[cfg(target_os = "openbsd")] { mod util_libc; @@ -272,9 +332,11 @@ cfg_if! { mod util_libc; #[path = "emscripten.rs"] mod imp; } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] { + mod lazy; #[path = "rdrand.rs"] mod imp; } else if #[cfg(all(feature = "rdrand", any(target_arch = "x86_64", target_arch = "x86")))] { + mod lazy; #[path = "rdrand.rs"] mod imp; } else if #[cfg(all(feature = "js", any(target_arch = "wasm32", target_arch = "wasm64"), diff --git a/third_party/rust/getrandom/src/linux_android.rs b/third_party/rust/getrandom/src/linux_android.rs index e81f1e1533..93a649452f 100644 --- a/third_party/rust/getrandom/src/linux_android.rs +++ b/third_party/rust/getrandom/src/linux_android.rs @@ -1,48 +1,7 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for Linux / Android -use crate::{ - util::LazyBool, - util_libc::{last_os_error, sys_fill_exact}, - {use_file, Error}, -}; +//! Implementation for Linux / Android without `/dev/urandom` fallback +use crate::{util_libc, Error}; use core::mem::MaybeUninit; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // getrandom(2) was introduced in Linux 3.17 - static HAS_GETRANDOM: LazyBool = LazyBool::new(); - if HAS_GETRANDOM.unsync_init(is_getrandom_available) { - sys_fill_exact(dest, |buf| unsafe { - getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0) - }) - } else { - use_file::getrandom_inner(dest) - } -} - -fn is_getrandom_available() -> bool { - let res = unsafe { getrandom(core::ptr::null_mut(), 0, libc::GRND_NONBLOCK) }; - if res < 0 { - match last_os_error().raw_os_error() { - Some(libc::ENOSYS) => false, // No kernel support - Some(libc::EPERM) => false, // Blocked by seccomp - _ => true, - } - } else { - true - } -} - -unsafe fn getrandom( - buf: *mut libc::c_void, - buflen: libc::size_t, - flags: libc::c_uint, -) -> libc::ssize_t { - libc::syscall(libc::SYS_getrandom, buf, buflen, flags) as libc::ssize_t + util_libc::sys_fill_exact(dest, util_libc::getrandom_syscall) } diff --git a/third_party/rust/getrandom/src/linux_android_with_fallback.rs b/third_party/rust/getrandom/src/linux_android_with_fallback.rs new file mode 100644 index 0000000000..0f5ea8a992 --- /dev/null +++ b/third_party/rust/getrandom/src/linux_android_with_fallback.rs @@ -0,0 +1,33 @@ +//! Implementation for Linux / Android with `/dev/urandom` fallback +use crate::{ + lazy::LazyBool, + util_libc::{getrandom_syscall, last_os_error, sys_fill_exact}, + {use_file, Error}, +}; +use core::mem::MaybeUninit; + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + // getrandom(2) was introduced in Linux 3.17 + static HAS_GETRANDOM: LazyBool = LazyBool::new(); + if HAS_GETRANDOM.unsync_init(is_getrandom_available) { + sys_fill_exact(dest, getrandom_syscall) + } else { + use_file::getrandom_inner(dest) + } +} + +fn is_getrandom_available() -> bool { + if getrandom_syscall(&mut []) < 0 { + match last_os_error().raw_os_error() { + Some(libc::ENOSYS) => false, // No kernel support + // The fallback on EPERM is intentionally not done on Android since this workaround + // seems to be needed only for specific Linux-based products that aren't based + // on Android. See https://github.com/rust-random/getrandom/issues/229. + #[cfg(target_os = "linux")] + Some(libc::EPERM) => false, // Blocked by seccomp + _ => true, + } + } else { + true + } +} diff --git a/third_party/rust/getrandom/src/macos.rs b/third_party/rust/getrandom/src/macos.rs index 312f9b27f0..44af76b03c 100644 --- a/third_party/rust/getrandom/src/macos.rs +++ b/third_party/rust/getrandom/src/macos.rs @@ -1,36 +1,18 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for macOS -use crate::{ - use_file, - util_libc::{last_os_error, Weak}, - Error, -}; -use core::mem::{self, MaybeUninit}; +use crate::{util_libc::last_os_error, Error}; +use core::mem::MaybeUninit; -type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; +extern "C" { + // Supported as of macOS 10.12+. + fn getentropy(buf: *mut u8, size: libc::size_t) -> libc::c_int; +} pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // getentropy(2) was added in 10.12, Rust supports 10.7+ - static GETENTROPY: Weak = unsafe { Weak::new("getentropy\0") }; - if let Some(fptr) = GETENTROPY.ptr() { - let func: GetEntropyFn = unsafe { mem::transmute(fptr) }; - for chunk in dest.chunks_mut(256) { - let ret = unsafe { func(chunk.as_mut_ptr() as *mut u8, chunk.len()) }; - if ret != 0 { - return Err(last_os_error()); - } + for chunk in dest.chunks_mut(256) { + let ret = unsafe { getentropy(chunk.as_mut_ptr() as *mut u8, chunk.len()) }; + if ret != 0 { + return Err(last_os_error()); } - Ok(()) - } else { - // We fallback to reading from /dev/random instead of SecRandomCopyBytes - // to avoid high startup costs and linking the Security framework. - use_file::getrandom_inner(dest) } + Ok(()) } diff --git a/third_party/rust/getrandom/src/openbsd.rs b/third_party/rust/getrandom/src/openbsd.rs index 7a76f61d5b..f4d64daf6f 100644 --- a/third_party/rust/getrandom/src/openbsd.rs +++ b/third_party/rust/getrandom/src/openbsd.rs @@ -1,11 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for OpenBSD use crate::{util_libc::last_os_error, Error}; use core::mem::MaybeUninit; diff --git a/third_party/rust/getrandom/src/rdrand.rs b/third_party/rust/getrandom/src/rdrand.rs index 69f6a5d13e..f527c8c643 100644 --- a/third_party/rust/getrandom/src/rdrand.rs +++ b/third_party/rust/getrandom/src/rdrand.rs @@ -1,14 +1,5 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -use crate::{ - util::{slice_as_uninit, LazyBool}, - Error, -}; +//! RDRAND backend for x86(-64) targets +use crate::{lazy::LazyBool, util::slice_as_uninit, Error}; use core::mem::{size_of, MaybeUninit}; cfg_if! { diff --git a/third_party/rust/getrandom/src/solaris_illumos.rs b/third_party/rust/getrandom/src/solaris_illumos.rs index 501c610d77..fbc239433f 100644 --- a/third_party/rust/getrandom/src/solaris_illumos.rs +++ b/third_party/rust/getrandom/src/solaris_illumos.rs @@ -1,11 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for the Solaris family //! //! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. diff --git a/third_party/rust/getrandom/src/solid.rs b/third_party/rust/getrandom/src/solid.rs index aeccc4e2bd..cae8caf667 100644 --- a/third_party/rust/getrandom/src/solid.rs +++ b/third_party/rust/getrandom/src/solid.rs @@ -1,11 +1,3 @@ -// Copyright 2021 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for SOLID use crate::Error; use core::{mem::MaybeUninit, num::NonZeroU32}; diff --git a/third_party/rust/getrandom/src/use_file.rs b/third_party/rust/getrandom/src/use_file.rs index a6ef0d2350..333325b5a9 100644 --- a/third_party/rust/getrandom/src/use_file.rs +++ b/third_party/rust/getrandom/src/use_file.rs @@ -1,14 +1,5 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementations that just need to read from a file use crate::{ - util::LazyUsize, util_libc::{open_readonly, sys_fill_exact}, Error, }; @@ -21,7 +12,7 @@ use core::{ // We prefer using /dev/urandom and only use /dev/random if the OS // documentation indicates that /dev/urandom is insecure. // On Solaris/Illumos, see src/solaris_illumos.rs -// On Dragonfly, Haiku, macOS, and QNX Neutrino the devices are identical. +// On Dragonfly, Haiku, and QNX Neutrino the devices are identical. #[cfg(any(target_os = "solaris", target_os = "illumos"))] const FILE_PATH: &str = "/dev/random\0"; #[cfg(any( @@ -31,10 +22,10 @@ const FILE_PATH: &str = "/dev/random\0"; target_os = "redox", target_os = "dragonfly", target_os = "haiku", - target_os = "macos", target_os = "nto", ))] const FILE_PATH: &str = "/dev/urandom\0"; +const FD_UNINIT: usize = usize::max_value(); pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let fd = get_rng_fd()?; @@ -47,10 +38,10 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // bytes. The file will be opened exactly once. All subsequent calls will // return the same file descriptor. This file descriptor is never closed. fn get_rng_fd() -> Result { - static FD: AtomicUsize = AtomicUsize::new(LazyUsize::UNINIT); + static FD: AtomicUsize = AtomicUsize::new(FD_UNINIT); fn get_fd() -> Option { match FD.load(Relaxed) { - LazyUsize::UNINIT => None, + FD_UNINIT => None, val => Some(val as libc::c_int), } } @@ -75,8 +66,8 @@ fn get_rng_fd() -> Result { wait_until_rng_ready()?; let fd = unsafe { open_readonly(FILE_PATH)? }; - // The fd always fits in a usize without conflicting with UNINIT. - debug_assert!(fd >= 0 && (fd as usize) < LazyUsize::UNINIT); + // The fd always fits in a usize without conflicting with FD_UNINIT. + debug_assert!(fd >= 0 && (fd as usize) < FD_UNINIT); FD.store(fd as usize, Relaxed); Ok(fd) diff --git a/third_party/rust/getrandom/src/util.rs b/third_party/rust/getrandom/src/util.rs index 3162afad35..1c4e70ba4e 100644 --- a/third_party/rust/getrandom/src/util.rs +++ b/third_party/rust/getrandom/src/util.rs @@ -1,71 +1,5 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. #![allow(dead_code)] -use core::{ - mem::MaybeUninit, - ptr, - sync::atomic::{AtomicUsize, Ordering::Relaxed}, -}; - -// This structure represents a lazily initialized static usize value. Useful -// when it is preferable to just rerun initialization instead of locking. -// Both unsync_init and sync_init will invoke an init() function until it -// succeeds, then return the cached value for future calls. -// -// Both methods support init() "failing". If the init() method returns UNINIT, -// that value will be returned as normal, but will not be cached. -// -// Users should only depend on the _value_ returned by init() functions. -// Specifically, for the following init() function: -// fn init() -> usize { -// a(); -// let v = b(); -// c(); -// v -// } -// the effects of c() or writes to shared memory will not necessarily be -// observed and additional synchronization methods with be needed. -pub struct LazyUsize(AtomicUsize); - -impl LazyUsize { - pub const fn new() -> Self { - Self(AtomicUsize::new(Self::UNINIT)) - } - - // The initialization is not completed. - pub const UNINIT: usize = usize::max_value(); - - // Runs the init() function at least once, returning the value of some run - // of init(). Multiple callers can run their init() functions in parallel. - // init() should always return the same value, if it succeeds. - pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { - // Relaxed ordering is fine, as we only have a single atomic variable. - let mut val = self.0.load(Relaxed); - if val == Self::UNINIT { - val = init(); - self.0.store(val, Relaxed); - } - val - } -} - -// Identical to LazyUsize except with bool instead of usize. -pub struct LazyBool(LazyUsize); - -impl LazyBool { - pub const fn new() -> Self { - Self(LazyUsize::new()) - } - - pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { - self.0.unsync_init(|| init() as usize) != 0 - } -} +use core::{mem::MaybeUninit, ptr}; /// Polyfill for `maybe_uninit_slice` feature's /// `MaybeUninit::slice_assume_init_mut`. Every element of `slice` must have diff --git a/third_party/rust/getrandom/src/util_libc.rs b/third_party/rust/getrandom/src/util_libc.rs index 99bee3824b..e86ef77624 100644 --- a/third_party/rust/getrandom/src/util_libc.rs +++ b/third_party/rust/getrandom/src/util_libc.rs @@ -1,14 +1,6 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. #![allow(dead_code)] use crate::Error; use core::{ - cmp::min, mem::MaybeUninit, num::NonZeroU32, ptr::NonNull, @@ -70,17 +62,19 @@ pub fn sys_fill_exact( ) -> Result<(), Error> { while !buf.is_empty() { let res = sys_fill(buf); - if res < 0 { - let err = last_os_error(); - // We should try again if the call was interrupted. - if err.raw_os_error() != Some(libc::EINTR) { - return Err(err); + match res { + res if res > 0 => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?, + -1 => { + let err = last_os_error(); + // We should try again if the call was interrupted. + if err.raw_os_error() != Some(libc::EINTR) { + return Err(err); + } } - } else { - // We don't check for EOF (ret = 0) as the data we are reading + // Negative return codes not equal to -1 should be impossible. + // EOF (ret = 0) should be impossible, as the data we are reading // should be an infinite stream of random bytes. - let len = min(res as usize, buf.len()); - buf = &mut buf[len..]; + _ => return Err(Error::UNEXPECTED), } } Ok(()) @@ -157,3 +151,16 @@ pub unsafe fn open_readonly(path: &str) -> Result { } } } + +/// Thin wrapper around the `getrandom()` Linux system call +#[cfg(any(target_os = "android", target_os = "linux"))] +pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { + unsafe { + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr() as *mut libc::c_void, + buf.len(), + 0, + ) as libc::ssize_t + } +} diff --git a/third_party/rust/getrandom/src/vita.rs b/third_party/rust/getrandom/src/vita.rs index 4f19b9cb08..20a9878245 100644 --- a/third_party/rust/getrandom/src/vita.rs +++ b/third_party/rust/getrandom/src/vita.rs @@ -1,11 +1,3 @@ -// Copyright 2021 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for PS Vita use crate::{util_libc::last_os_error, Error}; use core::mem::MaybeUninit; diff --git a/third_party/rust/getrandom/src/vxworks.rs b/third_party/rust/getrandom/src/vxworks.rs index 9b2090fb0a..7ca9d6bfdd 100644 --- a/third_party/rust/getrandom/src/vxworks.rs +++ b/third_party/rust/getrandom/src/vxworks.rs @@ -1,11 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for VxWorks use crate::{util_libc::last_os_error, Error}; use core::{ diff --git a/third_party/rust/getrandom/src/wasi.rs b/third_party/rust/getrandom/src/wasi.rs index 9276ee74f8..d6c8a912c9 100644 --- a/third_party/rust/getrandom/src/wasi.rs +++ b/third_party/rust/getrandom/src/wasi.rs @@ -1,11 +1,3 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Implementation for WASI use crate::Error; use core::{ diff --git a/third_party/rust/getrandom/src/windows.rs b/third_party/rust/getrandom/src/windows.rs index 92d70429e4..2d1c48351c 100644 --- a/third_party/rust/getrandom/src/windows.rs +++ b/third_party/rust/getrandom/src/windows.rs @@ -1,11 +1,4 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - +//! Implementation for Windows use crate::Error; use core::{ffi::c_void, mem::MaybeUninit, num::NonZeroU32, ptr}; diff --git a/third_party/rust/getrandom/tests/rdrand.rs b/third_party/rust/getrandom/tests/rdrand.rs index 25678683f3..a355c31ee8 100644 --- a/third_party/rust/getrandom/tests/rdrand.rs +++ b/third_party/rust/getrandom/tests/rdrand.rs @@ -6,6 +6,8 @@ use getrandom::Error; #[macro_use] extern crate cfg_if; +#[path = "../src/lazy.rs"] +mod lazy; #[path = "../src/rdrand.rs"] mod rdrand; #[path = "../src/util.rs"] diff --git a/third_party/rust/glean-core/.cargo-checksum.json b/third_party/rust/glean-core/.cargo-checksum.json index 663b3141c3..e9033c86e8 100644 --- a/third_party/rust/glean-core/.cargo-checksum.json +++ b/third_party/rust/glean-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c590a29d01f2ccad65fdbed80578177ae3c02522d6c6c60eef9644d71f04a0e3","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"026495898699b54608eb4ec16074ffafc57920d80ccb59961c501a1ea28c9985","build.rs":"4857bea99c6b8c08db8818efa9d3738716f52d3acb68159323957ae52892a3eb","src/common_metric_data.rs":"864990a1e5770d5d5fdebcd2c36b58c3442334030fb60f53811395b56baac94b","src/core/mod.rs":"9880520967e9da0b475d280c17cd70debf9a1d15912018cbba775e5fde0ff588","src/core_metrics.rs":"a877e42e0f8b932adb52a5681ad76fd977808cb48c7eeb29b1e4bbe804f1ea96","src/coverage.rs":"49613fd310bd24d779472720975fbe6c97ec370a95eb55f10afa43f67539c942","src/database/mod.rs":"b3684bb6a11e0aa2a51306a53feddbc89bc21879d4930d5e9995869950af3413","src/debug.rs":"d0dfc0932a0953bbbe029f723bf2613c8d691f34b017e858030c46b02a46a17d","src/dispatcher/global.rs":"f69cd81a90a37c306d4e0ce8177ea5a3ae2ffda5b431ae46b9a22c9e38891271","src/dispatcher/mod.rs":"391310269947452d7e0de24c848c183110c60149d75e345ba6d5d146f222dace","src/error.rs":"b93c7d3e243b21bb9eafc95f17860aba1a942b2f2b0a7f43307690f05fece516","src/error_recording.rs":"1aba34e9d3c741755055f5b76415114b25b146b0aa90049c3457cfe12066deda","src/event_database/mod.rs":"78633293e1f3c9e9d51705615a7a4b603d7f85567bfdc2b0bad35ccda6a12d44","src/fd_logger.rs":"0c9def6fa53db1a2ab93c85795f8a7df57797bcfd3978146923e151752e291a6","src/glean.udl":"0fcf72a8e3304d98e896dd3dfd9787208776c2b21b59f1c241029978ee37a925","src/glean_metrics.rs":"9414fb1453d19f6832df33e4c6ef7383d62203e47026bf5bc9552b083101ddd1","src/histogram/exponential.rs":"58bb1770bae45770d92995515d328eb50a7e78726224f779446ae7d1632a6a3e","src/histogram/functional.rs":"1a63a305b48bcef7bc38136b40d916df4bb8f098dc602514ada54a9b091f6951","src/histogram/linear.rs":"4342a1733175d7f97b2b41adb18100537c206100c9fccb5bd13bd782c9cb3c9a","src/histogram/mod.rs":"bbb9535a633b5a85b6b11c6e4eed3314ab797950355a9bb8ccf3a22000f1e093","src/internal_metrics.rs":"263779535963a804c8c7fa6f8e284ac8ec7f415ceeadbb6a8f913a1e7073ae18","src/internal_pings.rs":"0e3b8ce673cf92bd085fd4f07aa43876c97472dbd921a2d0dc0f10c9fe6b1c6b","src/lib.rs":"fb50a72a7221358c5daa1a8c0e59c92d5d358adc10b1ba9b831d2f07c07d90e2","src/lib_unit_tests.rs":"76d1997f7608b735cc4e905cfa94f79dd71a4a2ed1eccaa89d3d72ccd8d348e2","src/metrics/boolean.rs":"2b9ef57e3582c9bd8b2cca8ab94c962a4871ecc00e837b913c9b0349ba9dff08","src/metrics/counter.rs":"b4a52a8167fb0edd6354f952525e59f3eadb4261de3483374f03c94449d30b92","src/metrics/custom_distribution.rs":"e1f2edfefb67da4bf369bab3d3047f4ff6539a1fea0eee81c78d96626e5b4bb0","src/metrics/datetime.rs":"e4405762fc71718299fa1b208e3d5fda654bd1b82fe908c884c284e3530de2ec","src/metrics/denominator.rs":"95e8442f90bad97f80fc74b146782f215344b52c5f3825ae0a8baffdc001a714","src/metrics/event.rs":"cd52e200d313e2e6f31707419d4a7fe1cab34916ee145f8136440d6da34aaad4","src/metrics/experiment.rs":"5f9278cca4e133eb8df33bbfe36d1fe0ef3eade8c09f1b46db3c4d0790515412","src/metrics/labeled.rs":"8d6e76a07064d132cd617c7901f2bc11ff6ba31e3483ba3b96354a4a3736b58d","src/metrics/memory_distribution.rs":"7f6ca51acb470df277ff14427c0e7bb07d921c0a0087d0cc56aebe038d198ccc","src/metrics/memory_unit.rs":"ee32e020cb303dd631457374048a3ed53a2e7cbacc29c54d17d836fb15507538","src/metrics/metrics_enabled_config.rs":"c45f2cd48b36f8706e0e1d402d6fc375f5bab50f7d0840e0fbbbeacb6f2732af","src/metrics/mod.rs":"8f8958b8cedfe01df6c97ec26b63f14fd7516f9de7ba62984062db96b5708720","src/metrics/numerator.rs":"937dfd583b797ac798a525cedca95c5a36262356760a89670d8113983c263154","src/metrics/object.rs":"89ce5190ed681b26b74a06a4ecaf9f96c36f96be1276f1fdb40f4406648e08c1","src/metrics/ping.rs":"86dc577422075c759edb998acbd890c239569d72b30a994e7777d6d0f7676c5a","src/metrics/quantity.rs":"aa13a8f8cf8e5e0281668fbbafc2998411df2a499479423558fd91b9bd7f8702","src/metrics/rate.rs":"603cc45c149c7a27c93b6a80146bf43f8ce70d9655f905bb5be6bc2c15bcb22b","src/metrics/recorded_experiment.rs":"33958abee79d8b55dec4cb5d20742640423713010f76314075cefde18b5c118a","src/metrics/string.rs":"0906b4d5ec1ec10b7a56fd6eb39dc30500531658df2c8bc3f55c9579e15c88db","src/metrics/string_list.rs":"ed53a095184c3e8224d0511809b5d7601ba3166505a39b0570f24ebeb0a5b97c","src/metrics/text.rs":"757f6919124d74e0512faa5bb9751a729b6bbc63ebe4d16ca81e9087f5595eaf","src/metrics/time_unit.rs":"4704703e19e799933aec3f39e3d3a125058756d7c7ba04f8729885c7843df447","src/metrics/timespan.rs":"1ad5233c7522cab70b4c095fb24cace66ace9741731f97bc001ede071f10d1ef","src/metrics/timing_distribution.rs":"261f971d012e80e93180caea69da549498597d47771264c9bb0667a9573f47ed","src/metrics/url.rs":"589ae1f8047367ad8c19b57a48ca8130d5f36cf3ce5954124150f0eb89c620ea","src/metrics/uuid.rs":"cacffd95ab30ed327ec2fa5feaf1359e667706746401f1e2c1195ad9553c4b54","src/ping/mod.rs":"fcadd52d2d536c9ace01f8a3812c3fb3c39b8094915db1b3656839fb87f771b5","src/scheduler.rs":"129863e31205404a3d1708627a62583324c347d143f976216f769893ec541ea0","src/storage/mod.rs":"91f02556f113799e0d88d732ab342bda443f43461369e8b41c424c074d742591","src/system.rs":"e3d1b54e1d39cafe6f4dc7ff5021b08c879733f909951b0e1332b3efa9ed97bd","src/traits/boolean.rs":"be0e130f8043215705becc956d45b126c340568f1b24a396c0af9b4334a41ced","src/traits/counter.rs":"c686d26e131d854cd7a7df83c900ca7c17a03c663a30cf58ab48c7259476ce85","src/traits/custom_distribution.rs":"0bd1d425e4c059cca6af2dfb13c78e5e4c6c07fb46c7e31489ad0c5959854833","src/traits/datetime.rs":"636ac1456b1b042e38cf5ae6193c5b232ea0b80df62f583a2097891baef9641b","src/traits/event.rs":"a02235aae630aba7a45a3166b756927252b397af3ecdfab7236931e62725ac49","src/traits/labeled.rs":"c633c68e70a44e73f8aff88aaab1029c0faded3cad08d822590ed8838f24b4fd","src/traits/memory_distribution.rs":"55bb8f45e948319fbba9d28a50d8742da134b066a42e480887db7c7e435f4096","src/traits/mod.rs":"d14b69d0946848c1f92cc8977cbc3fc9338ff1b53b7acc31ea0fe2f1122beecb","src/traits/numerator.rs":"6e4f236bdc448f1bde7a8c249dcd086204c2c69990d3f444e746290929226ed3","src/traits/object.rs":"c03bad670ec7affbc578247f9e1904e898c1870b9bf25750c5094113f995623f","src/traits/ping.rs":"8831c106c03afeb458b0b028fa1ce61f056ebf8e82bc0a171a1bff255d920748","src/traits/quantity.rs":"6ffe25c913bef4315573d747308c182de740b2a4e02ba22cd21d0c33ba521f31","src/traits/rate.rs":"f000790440e0f389f0b160526a9a9a266e58d1405915ae56ac550f482858222c","src/traits/string.rs":"0c3c88382ff2e8eba89c7cfe129c4b84e31140af717819533c14919541ad790c","src/traits/string_list.rs":"14e56b62c2c2be1dd8013f12001f235b084abd2a0d5aa2f7932843877af49ac0","src/traits/text.rs":"8af7d3a0c87cfd8c6d33d6ad47532b431055bbdd395f9110da5630222c23cf93","src/traits/timespan.rs":"52be325a9c061916f34c5b638a07a93b4a14aa89fe365783103d2e06b998f547","src/traits/timing_distribution.rs":"00ebdef647a7a208c01d13ba7b3996750e36de98d1f63859b609c80c8df25b6f","src/traits/url.rs":"c27f7add23214ff051078b65b88120b620560d2841a1056c7214d5237e86b9e4","src/traits/uuid.rs":"81322e71c7e847bacaf827a2cd58f6193bdc208355524207f7f38db039da6aa8","src/upload/directory.rs":"e42c62f27ace5c6504cc7703a4c1d9ffd0e6ac7c4fba7d7dee231430fb67f8f8","src/upload/mod.rs":"6151a6d3b4fccb3df7ef03207e2f77bf34dbf04b3b705e2af55dd02a731f99f8","src/upload/policy.rs":"c250957a37783e74af8002cd80ba06ef9780a389fb0f61b8b665b79688f0a360","src/upload/request.rs":"5891364d4254aafdb43751f476b0b908b681544793ac98802fe103de321ec326","src/upload/result.rs":"7efbbe50e8d36beb3f23e7bfd172d22e1c003472d2dd8055b06f6050c36437c5","src/util.rs":"ee7500434d9758a320dd410f18d7e18da956591e19d2555db87eef9623e4b916","tests/boolean.rs":"76d6014ff108cb6514d9bceb1b2b14749a55b09921f4595a5e30f1bd3546e9f0","tests/common/mod.rs":"c5bf5a9f3660ae1a1c1dbb659ab6be60438c58bc7c459f2f96dca467d05d4ab3","tests/counter.rs":"3663a3f5ec5c0bd2b758a9920cd20cc619a12566b445e4421ec7c98232bf5a32","tests/custom_distribution.rs":"41c593a0b4561e21f29d1a5b948de964a866253c58ca76ffefebe370fca150e0","tests/datetime.rs":"ec3c9760e70bb2cbc61ab23281c891bc1ec493c5c545466c29fd13e4f05c2c96","tests/event.rs":"0fbec0e8929c99603b79c62a1f57f8cabe614451fdafb6eb9d47f22116303245","tests/labeled.rs":"e9ea6dba17059d68114efce0c23373be9ceed922bf5e638a2158a6422c75a1c1","tests/memory_distribution.rs":"a5a7aa955e60823ea29a6f4bc96c61e41f1e41f08958aa4854668cf8fe04cde6","tests/object.rs":"8c35676e04f6ccf54a28764700915e753fc0355bfa5d7804d72caba66fd564cd","tests/ping.rs":"eb9f6be1aba21acc5dc670622bf622976718a706df1cc2095efa56a8e8b3fe1a","tests/ping_maker.rs":"7ad1f76a1eda2dabf0422fff74d9c2c1a39b9d1d315a4dbe6057dff44efcfae0","tests/quantity.rs":"55e7dca346fd1d27f0974b78ca3fb12427cb5da2ee637afc08a54f360f947361","tests/rate.rs":"1de571b9f0ee9a9006cbc8a31f91352d3ff1190b50840f0f668b470a7cd2a3a5","tests/storage.rs":"f0c8312bd789d7bda502cd45f35fef6b8591652bd194d07da4d81935ebe69b48","tests/string.rs":"7ece988a4b8efe6932ccb90bfe2f3c8aaea983777e99d7de6028bf6a29459ee6","tests/string_list.rs":"77188a2b90663c3f8dac5da89a6cb6b1d16a9f8c66ccd032d02966dfd14a3486","tests/text.rs":"1d43f6b90a43124311cacf0a6ee16f9e1e9263bcd11fee8b996d6efd81633638","tests/timespan.rs":"d50d75c7d75da3a878d67331cb0df8ae5e6a099ffab474361f71a408e02528d7","tests/timing_distribution.rs":"20860a7baccdcee6aed40c9cc8202b94f3b2e61164fbaf8f2af96b0f404a895a","tests/uuid.rs":"052ad26a6927c56272219340211cf4a059d200f14287b482fe8621d7bce3cc54","uniffi.toml":"6ddc98b686b0925a81abd9d1c769e5c98ac29771b210a1c535931a46dec9a8e3"},"package":"ea06a592b1395e0a16a5f4d6872f009ca7c98acc5127a8119088f1b435b5aaae"} \ No newline at end of file +{"files":{"Cargo.toml":"76031a9e743406219c98ef0c831e573b693c0db01ae7702a80917ce4816424df","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"026495898699b54608eb4ec16074ffafc57920d80ccb59961c501a1ea28c9985","build.rs":"4857bea99c6b8c08db8818efa9d3738716f52d3acb68159323957ae52892a3eb","src/common_metric_data.rs":"02dd1628fed6587621c089952dd0cb80bed3c352cdacfb33be7e218ad1d847e9","src/core/mod.rs":"a6a919646309d94b6d8b729cd717d5b6f2925095b88f5d11b4222cfd38998b40","src/core_metrics.rs":"a877e42e0f8b932adb52a5681ad76fd977808cb48c7eeb29b1e4bbe804f1ea96","src/coverage.rs":"49613fd310bd24d779472720975fbe6c97ec370a95eb55f10afa43f67539c942","src/database/mod.rs":"fb3caafb1e9dd08bd2559e56c5e0713d742795599d604a01b58b92db207e2842","src/debug.rs":"d0dfc0932a0953bbbe029f723bf2613c8d691f34b017e858030c46b02a46a17d","src/dispatcher/global.rs":"f69cd81a90a37c306d4e0ce8177ea5a3ae2ffda5b431ae46b9a22c9e38891271","src/dispatcher/mod.rs":"391310269947452d7e0de24c848c183110c60149d75e345ba6d5d146f222dace","src/error.rs":"b93c7d3e243b21bb9eafc95f17860aba1a942b2f2b0a7f43307690f05fece516","src/error_recording.rs":"1aba34e9d3c741755055f5b76415114b25b146b0aa90049c3457cfe12066deda","src/event_database/mod.rs":"78633293e1f3c9e9d51705615a7a4b603d7f85567bfdc2b0bad35ccda6a12d44","src/fd_logger.rs":"0c9def6fa53db1a2ab93c85795f8a7df57797bcfd3978146923e151752e291a6","src/glean.udl":"ebc09d8b03eed846a79c9ddb6bc81dc57ca9c28586886805bbc0fb2d64a8e225","src/glean_metrics.rs":"9414fb1453d19f6832df33e4c6ef7383d62203e47026bf5bc9552b083101ddd1","src/histogram/exponential.rs":"58bb1770bae45770d92995515d328eb50a7e78726224f779446ae7d1632a6a3e","src/histogram/functional.rs":"1a63a305b48bcef7bc38136b40d916df4bb8f098dc602514ada54a9b091f6951","src/histogram/linear.rs":"4342a1733175d7f97b2b41adb18100537c206100c9fccb5bd13bd782c9cb3c9a","src/histogram/mod.rs":"bbb9535a633b5a85b6b11c6e4eed3314ab797950355a9bb8ccf3a22000f1e093","src/internal_metrics.rs":"263779535963a804c8c7fa6f8e284ac8ec7f415ceeadbb6a8f913a1e7073ae18","src/internal_pings.rs":"c54339cb2530eec7717a3f6dd81ce98adf5da5d615bcf0a071fd90f415016866","src/lib.rs":"0fab5462a6b2a86244cfd7b3cdf99996b4b410f34ee9f0f8e16758fafdcfa389","src/lib_unit_tests.rs":"6180628e46d3dbcd8dbd5e7f3cdbc12a3987c0b3a9d6638ab1341f3f3d666db7","src/metrics/boolean.rs":"2b9ef57e3582c9bd8b2cca8ab94c962a4871ecc00e837b913c9b0349ba9dff08","src/metrics/counter.rs":"b4a52a8167fb0edd6354f952525e59f3eadb4261de3483374f03c94449d30b92","src/metrics/custom_distribution.rs":"e1f2edfefb67da4bf369bab3d3047f4ff6539a1fea0eee81c78d96626e5b4bb0","src/metrics/datetime.rs":"e4405762fc71718299fa1b208e3d5fda654bd1b82fe908c884c284e3530de2ec","src/metrics/denominator.rs":"95e8442f90bad97f80fc74b146782f215344b52c5f3825ae0a8baffdc001a714","src/metrics/event.rs":"cd52e200d313e2e6f31707419d4a7fe1cab34916ee145f8136440d6da34aaad4","src/metrics/experiment.rs":"5f9278cca4e133eb8df33bbfe36d1fe0ef3eade8c09f1b46db3c4d0790515412","src/metrics/labeled.rs":"8d6e76a07064d132cd617c7901f2bc11ff6ba31e3483ba3b96354a4a3736b58d","src/metrics/memory_distribution.rs":"7f6ca51acb470df277ff14427c0e7bb07d921c0a0087d0cc56aebe038d198ccc","src/metrics/memory_unit.rs":"ee32e020cb303dd631457374048a3ed53a2e7cbacc29c54d17d836fb15507538","src/metrics/mod.rs":"cc99e7b27a5cecc974475790e1bd4cce86813b881e3c1d858aa446c9fe5183f8","src/metrics/numerator.rs":"937dfd583b797ac798a525cedca95c5a36262356760a89670d8113983c263154","src/metrics/object.rs":"2a1f1cc31973b576e55ba464b35c41b9420f62471eebba51273bca6856459538","src/metrics/ping.rs":"ac4cdda5cc94ddf2a2206188abcfa3517de4500ba3eadd976758fb9cffcb3624","src/metrics/quantity.rs":"aa13a8f8cf8e5e0281668fbbafc2998411df2a499479423558fd91b9bd7f8702","src/metrics/rate.rs":"603cc45c149c7a27c93b6a80146bf43f8ce70d9655f905bb5be6bc2c15bcb22b","src/metrics/recorded_experiment.rs":"33958abee79d8b55dec4cb5d20742640423713010f76314075cefde18b5c118a","src/metrics/remote_settings_config.rs":"3565514a0444cb322e1f7944417167233d727a195c837bd7aee5eae88d5f0766","src/metrics/string.rs":"0906b4d5ec1ec10b7a56fd6eb39dc30500531658df2c8bc3f55c9579e15c88db","src/metrics/string_list.rs":"ed53a095184c3e8224d0511809b5d7601ba3166505a39b0570f24ebeb0a5b97c","src/metrics/text.rs":"757f6919124d74e0512faa5bb9751a729b6bbc63ebe4d16ca81e9087f5595eaf","src/metrics/time_unit.rs":"4704703e19e799933aec3f39e3d3a125058756d7c7ba04f8729885c7843df447","src/metrics/timespan.rs":"1ad5233c7522cab70b4c095fb24cace66ace9741731f97bc001ede071f10d1ef","src/metrics/timing_distribution.rs":"261f971d012e80e93180caea69da549498597d47771264c9bb0667a9573f47ed","src/metrics/url.rs":"589ae1f8047367ad8c19b57a48ca8130d5f36cf3ce5954124150f0eb89c620ea","src/metrics/uuid.rs":"cacffd95ab30ed327ec2fa5feaf1359e667706746401f1e2c1195ad9553c4b54","src/ping/mod.rs":"4c427ee29a7555c8577bd97fc4b85de4158f10062f73a5ee16b2a5d335b838b9","src/scheduler.rs":"129863e31205404a3d1708627a62583324c347d143f976216f769893ec541ea0","src/storage/mod.rs":"91f02556f113799e0d88d732ab342bda443f43461369e8b41c424c074d742591","src/system.rs":"e3d1b54e1d39cafe6f4dc7ff5021b08c879733f909951b0e1332b3efa9ed97bd","src/traits/boolean.rs":"be0e130f8043215705becc956d45b126c340568f1b24a396c0af9b4334a41ced","src/traits/counter.rs":"c686d26e131d854cd7a7df83c900ca7c17a03c663a30cf58ab48c7259476ce85","src/traits/custom_distribution.rs":"0bd1d425e4c059cca6af2dfb13c78e5e4c6c07fb46c7e31489ad0c5959854833","src/traits/datetime.rs":"636ac1456b1b042e38cf5ae6193c5b232ea0b80df62f583a2097891baef9641b","src/traits/event.rs":"a02235aae630aba7a45a3166b756927252b397af3ecdfab7236931e62725ac49","src/traits/labeled.rs":"c633c68e70a44e73f8aff88aaab1029c0faded3cad08d822590ed8838f24b4fd","src/traits/memory_distribution.rs":"55bb8f45e948319fbba9d28a50d8742da134b066a42e480887db7c7e435f4096","src/traits/mod.rs":"d14b69d0946848c1f92cc8977cbc3fc9338ff1b53b7acc31ea0fe2f1122beecb","src/traits/numerator.rs":"6e4f236bdc448f1bde7a8c249dcd086204c2c69990d3f444e746290929226ed3","src/traits/object.rs":"c03bad670ec7affbc578247f9e1904e898c1870b9bf25750c5094113f995623f","src/traits/ping.rs":"8831c106c03afeb458b0b028fa1ce61f056ebf8e82bc0a171a1bff255d920748","src/traits/quantity.rs":"6ffe25c913bef4315573d747308c182de740b2a4e02ba22cd21d0c33ba521f31","src/traits/rate.rs":"f000790440e0f389f0b160526a9a9a266e58d1405915ae56ac550f482858222c","src/traits/string.rs":"0c3c88382ff2e8eba89c7cfe129c4b84e31140af717819533c14919541ad790c","src/traits/string_list.rs":"14e56b62c2c2be1dd8013f12001f235b084abd2a0d5aa2f7932843877af49ac0","src/traits/text.rs":"8af7d3a0c87cfd8c6d33d6ad47532b431055bbdd395f9110da5630222c23cf93","src/traits/timespan.rs":"52be325a9c061916f34c5b638a07a93b4a14aa89fe365783103d2e06b998f547","src/traits/timing_distribution.rs":"00ebdef647a7a208c01d13ba7b3996750e36de98d1f63859b609c80c8df25b6f","src/traits/url.rs":"c27f7add23214ff051078b65b88120b620560d2841a1056c7214d5237e86b9e4","src/traits/uuid.rs":"81322e71c7e847bacaf827a2cd58f6193bdc208355524207f7f38db039da6aa8","src/upload/directory.rs":"5545042c1d1f37ebb08445b88c0fa8b97aad145e81e34051fad3da2a94b1b52d","src/upload/mod.rs":"7b65a31ed8b12c4a7e708edb9bbf48ab6a4c99422b4bb1f50891cde07f5e6a3c","src/upload/policy.rs":"c250957a37783e74af8002cd80ba06ef9780a389fb0f61b8b665b79688f0a360","src/upload/request.rs":"5891364d4254aafdb43751f476b0b908b681544793ac98802fe103de321ec326","src/upload/result.rs":"7efbbe50e8d36beb3f23e7bfd172d22e1c003472d2dd8055b06f6050c36437c5","src/util.rs":"ee7500434d9758a320dd410f18d7e18da956591e19d2555db87eef9623e4b916","tests/boolean.rs":"76d6014ff108cb6514d9bceb1b2b14749a55b09921f4595a5e30f1bd3546e9f0","tests/common/mod.rs":"c5bf5a9f3660ae1a1c1dbb659ab6be60438c58bc7c459f2f96dca467d05d4ab3","tests/counter.rs":"3663a3f5ec5c0bd2b758a9920cd20cc619a12566b445e4421ec7c98232bf5a32","tests/custom_distribution.rs":"41c593a0b4561e21f29d1a5b948de964a866253c58ca76ffefebe370fca150e0","tests/datetime.rs":"ec3c9760e70bb2cbc61ab23281c891bc1ec493c5c545466c29fd13e4f05c2c96","tests/event.rs":"3cfe41e67d300683f690a672cc82ca2f29658c870ba78b824f9e1e3d3556a2b5","tests/labeled.rs":"e9ea6dba17059d68114efce0c23373be9ceed922bf5e638a2158a6422c75a1c1","tests/memory_distribution.rs":"a5a7aa955e60823ea29a6f4bc96c61e41f1e41f08958aa4854668cf8fe04cde6","tests/object.rs":"8c35676e04f6ccf54a28764700915e753fc0355bfa5d7804d72caba66fd564cd","tests/ping.rs":"6dd56b6ca2206b687fc5e67e8c603872a5b60c5847c6ecb0c8f789fdd94b2c09","tests/ping_maker.rs":"48d25109154033ccf6783f2e9bfc30d2ec26876e0092d648c40062fb67cc9925","tests/quantity.rs":"55e7dca346fd1d27f0974b78ca3fb12427cb5da2ee637afc08a54f360f947361","tests/rate.rs":"1de571b9f0ee9a9006cbc8a31f91352d3ff1190b50840f0f668b470a7cd2a3a5","tests/storage.rs":"f0c8312bd789d7bda502cd45f35fef6b8591652bd194d07da4d81935ebe69b48","tests/string.rs":"7ece988a4b8efe6932ccb90bfe2f3c8aaea983777e99d7de6028bf6a29459ee6","tests/string_list.rs":"77188a2b90663c3f8dac5da89a6cb6b1d16a9f8c66ccd032d02966dfd14a3486","tests/text.rs":"1d43f6b90a43124311cacf0a6ee16f9e1e9263bcd11fee8b996d6efd81633638","tests/timespan.rs":"d50d75c7d75da3a878d67331cb0df8ae5e6a099ffab474361f71a408e02528d7","tests/timing_distribution.rs":"20860a7baccdcee6aed40c9cc8202b94f3b2e61164fbaf8f2af96b0f404a895a","tests/uuid.rs":"052ad26a6927c56272219340211cf4a059d200f14287b482fe8621d7bce3cc54","uniffi.toml":"6ddc98b686b0925a81abd9d1c769e5c98ac29771b210a1c535931a46dec9a8e3"},"package":"86db1cca10118079e9ae34681a6f762f6c51150971552e98f0dfec1d7a556c21"} \ No newline at end of file diff --git a/third_party/rust/glean-core/Cargo.toml b/third_party/rust/glean-core/Cargo.toml index 932b16a4a7..fba18dd4d8 100644 --- a/third_party/rust/glean-core/Cargo.toml +++ b/third_party/rust/glean-core/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.66" name = "glean-core" -version = "59.0.0" +version = "60.0.1" authors = [ "Jan-Erik Rediger ", "The Glean Team ", @@ -35,7 +35,7 @@ license = "MPL-2.0" repository = "https://github.com/mozilla/glean" [package.metadata.glean] -glean-parser = "13.0.0" +glean-parser = "14.0.1" [dependencies.bincode] version = "1.2.1" diff --git a/third_party/rust/glean-core/src/common_metric_data.rs b/third_party/rust/glean-core/src/common_metric_data.rs index 9bda9bb462..f5058d995f 100644 --- a/third_party/rust/glean-core/src/common_metric_data.rs +++ b/third_party/rust/glean-core/src/common_metric_data.rs @@ -90,9 +90,10 @@ impl Clone for CommonMetricDataInternal { impl From for CommonMetricDataInternal { fn from(input_data: CommonMetricData) -> Self { + let disabled = input_data.disabled; Self { - inner: input_data.clone(), - disabled: AtomicU8::new(u8::from(input_data.disabled)), + inner: input_data, + disabled: AtomicU8::new(u8::from(disabled)), } } } diff --git a/third_party/rust/glean-core/src/core/mod.rs b/third_party/rust/glean-core/src/core/mod.rs index f69f0c3868..9b8cfe531b 100644 --- a/third_party/rust/glean-core/src/core/mod.rs +++ b/third_party/rust/glean-core/src/core/mod.rs @@ -16,7 +16,7 @@ use crate::event_database::EventDatabase; use crate::internal_metrics::{AdditionalMetrics, CoreMetrics, DatabaseMetrics}; use crate::internal_pings::InternalPings; use crate::metrics::{ - self, ExperimentMetric, Metric, MetricType, MetricsEnabledConfig, PingType, RecordedExperiment, + self, ExperimentMetric, Metric, MetricType, PingType, RecordedExperiment, RemoteSettingsConfig, }; use crate::ping::PingMaker; use crate::storage::{StorageManager, INTERNAL_STORAGE}; @@ -123,7 +123,7 @@ where /// enable_internal_pings: true, /// }; /// let mut glean = Glean::new(cfg).unwrap(); -/// let ping = PingType::new("sample", true, false, true, true, vec![]); +/// let ping = PingType::new("sample", true, false, true, true, true, vec![], vec![]); /// glean.register_ping_type(&ping); /// /// let call_counter: CounterMetric = CounterMetric::new(CommonMetricData { @@ -162,7 +162,7 @@ pub struct Glean { pub(crate) app_build: String, pub(crate) schedule_metrics_pings: bool, pub(crate) remote_settings_epoch: AtomicU8, - pub(crate) remote_settings_metrics_config: Arc>, + pub(crate) remote_settings_config: Arc>, pub(crate) with_timestamps: bool, } @@ -222,7 +222,7 @@ impl Glean { // Subprocess doesn't use "metrics" pings so has no need for a scheduler. schedule_metrics_pings: false, remote_settings_epoch: AtomicU8::new(0), - remote_settings_metrics_config: Arc::new(Mutex::new(MetricsEnabledConfig::new())), + remote_settings_config: Arc::new(Mutex::new(RemoteSettingsConfig::new())), with_timestamps: cfg.enable_event_timestamps, }; @@ -758,19 +758,26 @@ impl Glean { .get_value(self, None) } - /// Set configuration to override the default metric enabled/disabled state, typically from a + /// Set configuration to override the default state, typically initiated from a /// remote_settings experiment or rollout /// /// # Arguments /// - /// * `json` - The stringified JSON representation of a `MetricsEnabledConfig` object - pub fn set_metrics_enabled_config(&self, cfg: MetricsEnabledConfig) { - // Set the current MetricsEnabledConfig, keeping the lock until the epoch is + /// * `cfg` - The stringified JSON representation of a `RemoteSettingsConfig` object + pub fn apply_server_knobs_config(&self, cfg: RemoteSettingsConfig) { + // Set the current RemoteSettingsConfig, keeping the lock until the epoch is // updated to prevent against reading a "new" config but an "old" epoch - let mut metric_config = self.remote_settings_metrics_config.lock().unwrap(); + let mut remote_settings_config = self.remote_settings_config.lock().unwrap(); - // Merge the exising configuration with the supplied one - metric_config.metrics_enabled.extend(cfg.metrics_enabled); + // Merge the exising metrics configuration with the supplied one + remote_settings_config + .metrics_enabled + .extend(cfg.metrics_enabled); + + // Merge the exising ping configuration with the supplied one + remote_settings_config + .pings_enabled + .extend(cfg.pings_enabled); // Update remote_settings epoch self.remote_settings_epoch.fetch_add(1, Ordering::SeqCst); diff --git a/third_party/rust/glean-core/src/database/mod.rs b/third_party/rust/glean-core/src/database/mod.rs index 0dbf0220bc..75a068b42e 100644 --- a/third_party/rust/glean-core/src/database/mod.rs +++ b/third_party/rust/glean-core/src/database/mod.rs @@ -9,6 +9,8 @@ use std::io; use std::num::NonZeroU64; use std::path::Path; use std::str; +#[cfg(target_os = "android")] +use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::RwLock; use crate::ErrorKind; @@ -167,6 +169,13 @@ use crate::Glean; use crate::Lifetime; use crate::Result; +/// The number of writes we accept writes to the ping-lifetime in-memory map +/// before data is flushed to disk. +/// +/// Only considered if `delay_ping_lifetime_io` is set to `true`. +#[cfg(target_os = "android")] +const PING_LIFETIME_THRESHOLD: usize = 1000; + pub struct Database { /// Handle to the database environment. rkv: Rkv, @@ -184,6 +193,14 @@ pub struct Database { /// so as to persist them to disk using rkv in bulk on demand. ping_lifetime_data: Option>>, + /// A count of how many database writes have been done since the last ping-lifetime flush. + /// + /// A ping-lifetime flush is automatically done after `PING_LIFETIME_THRESHOLD` writes. + /// + /// Only relevant if `delay_ping_lifetime_io` is set to `true`, + #[cfg(target_os = "android")] + ping_lifetime_count: AtomicUsize, + /// Initial file size when opening the database. file_size: Option, @@ -263,6 +280,8 @@ impl Database { ping_store, application_store, ping_lifetime_data, + #[cfg(target_os = "android")] + ping_lifetime_count: AtomicUsize::new(0), file_size, rkv_load_state, }; @@ -528,6 +547,9 @@ impl Database { .write() .expect("Can't read ping lifetime data"); data.insert(final_key, metric.clone()); + + // flush ping lifetime + self.persist_ping_lifetime_data_if_full(&data)?; return Ok(()); } } @@ -609,6 +631,9 @@ impl Database { entry.insert(transform(Some(old_value))); } } + + // flush ping lifetime + self.persist_ping_lifetime_data_if_full(&data)?; return Ok(()); } } @@ -802,6 +827,10 @@ impl Database { .read() .expect("Can't read ping lifetime data"); + // We can reset the write-counter. Current data has been persisted. + #[cfg(target_os = "android")] + self.ping_lifetime_count.store(0, Ordering::Release); + self.write_with_store(Lifetime::Ping, |mut writer, store| { for (key, value) in data.iter() { let encoded = @@ -817,6 +846,42 @@ impl Database { } Ok(()) } + + pub fn persist_ping_lifetime_data_if_full( + &self, + data: &BTreeMap, + ) -> Result<()> { + #[cfg(target_os = "android")] + { + self.ping_lifetime_count.fetch_add(1, Ordering::Release); + + let write_count = self.ping_lifetime_count.load(Ordering::Relaxed); + if write_count < PING_LIFETIME_THRESHOLD { + return Ok(()); + } + + self.ping_lifetime_count.store(0, Ordering::Release); + let write_result = self.write_with_store(Lifetime::Ping, |mut writer, store| { + for (key, value) in data.iter() { + let encoded = + bincode::serialize(&value).expect("IMPOSSIBLE: Serializing metric failed"); + // There is no need for `get_storage_key` here because + // the key is already formatted from when it was saved + // to ping_lifetime_data. + store.put(&mut writer, key, &rkv::Value::Blob(&encoded))?; + } + writer.commit()?; + Ok(()) + }); + + return write_result; + } + #[cfg(not(target_os = "android"))] + { + _ = data; // suppress unused_variables warning. + Ok(()) + } + } } #[cfg(test)] diff --git a/third_party/rust/glean-core/src/glean.udl b/third_party/rust/glean-core/src/glean.udl index dc71fea594..b107a36f28 100644 --- a/third_party/rust/glean-core/src/glean.udl +++ b/third_party/rust/glean-core/src/glean.udl @@ -47,12 +47,14 @@ namespace glean { void glean_unregister_event_listener(string tag); // Server Knobs API - void glean_set_metrics_enabled_config(string json); + void glean_apply_server_knobs_config(string json); boolean glean_set_debug_view_tag(string tag); boolean glean_set_source_tags(sequence tags); void glean_set_log_pings(boolean value); + void glean_persist_ping_lifetime_data(); + void glean_handle_client_active(); void glean_handle_client_inactive(); @@ -292,7 +294,7 @@ enum ErrorType { }; interface PingType { - constructor(string name, boolean include_client_id, boolean send_if_empty, boolean precise_timestamps, boolean include_info_sections, sequence reason_codes); + constructor(string name, boolean include_client_id, boolean send_if_empty, boolean precise_timestamps, boolean include_info_sections, boolean enabled, sequence schedules_pings, sequence reason_codes); void submit(optional string? reason = null); }; @@ -640,3 +642,19 @@ interface TextMetric { i32 test_get_num_recorded_errors(ErrorType error); }; + +// JSON data encoded into a string +[Custom] +typedef string JsonValue; + +interface ObjectMetric { + constructor(CommonMetricData meta); + + void set_string(string object); + + JsonValue? test_get_value(optional string? ping_name = null); + + i32 test_get_num_recorded_errors(ErrorType error); + + void record_schema_error(); +}; diff --git a/third_party/rust/glean-core/src/internal_pings.rs b/third_party/rust/glean-core/src/internal_pings.rs index 1cf32feb60..4fe15352b2 100644 --- a/third_party/rust/glean-core/src/internal_pings.rs +++ b/third_party/rust/glean-core/src/internal_pings.rs @@ -21,25 +21,28 @@ pub struct InternalPings { impl InternalPings { pub fn new(enabled: bool) -> InternalPings { InternalPings { - baseline: PingType::new_internal( + baseline: PingType::new( "baseline", true, true, true, true, + enabled, + vec![], vec![ "active".to_string(), "dirty_startup".to_string(), "inactive".to_string(), ], - enabled, ), - metrics: PingType::new_internal( + metrics: PingType::new( "metrics", true, false, true, true, + enabled, + vec![], vec![ "overdue".to_string(), "reschedule".to_string(), @@ -47,20 +50,20 @@ impl InternalPings { "tomorrow".to_string(), "upgrade".to_string(), ], - enabled, ), - events: PingType::new_internal( + events: PingType::new( "events", true, false, true, true, + enabled, + vec![], vec![ "startup".to_string(), "inactive".to_string(), "max_capacity".to_string(), ], - enabled, ), deletion_request: PingType::new( "deletion-request", @@ -68,6 +71,8 @@ impl InternalPings { true, true, true, + true, // The deletion-request should not be disabled + vec![], vec!["at_init".to_string(), "set_upload_enabled".to_string()], ), } diff --git a/third_party/rust/glean-core/src/lib.rs b/third_party/rust/glean-core/src/lib.rs index af68fde264..c79fa1e226 100644 --- a/third_party/rust/glean-core/src/lib.rs +++ b/third_party/rust/glean-core/src/lib.rs @@ -28,7 +28,7 @@ use log::LevelFilter; use once_cell::sync::{Lazy, OnceCell}; use uuid::Uuid; -use metrics::MetricsEnabledConfig; +use metrics::RemoteSettingsConfig; mod common_metric_data; mod core; @@ -68,9 +68,9 @@ pub use crate::metrics::labeled::{ pub use crate::metrics::{ BooleanMetric, CounterMetric, CustomDistributionMetric, Datetime, DatetimeMetric, DenominatorMetric, DistributionData, EventMetric, MemoryDistributionMetric, MemoryUnit, - NumeratorMetric, PingType, QuantityMetric, Rate, RateMetric, RecordedEvent, RecordedExperiment, - StringListMetric, StringMetric, TextMetric, TimeUnit, TimerId, TimespanMetric, - TimingDistributionMetric, UrlMetric, UuidMetric, + NumeratorMetric, ObjectMetric, PingType, QuantityMetric, Rate, RateMetric, RecordedEvent, + RecordedExperiment, StringListMetric, StringMetric, TextMetric, TimeUnit, TimerId, + TimespanMetric, TimingDistributionMetric, UrlMetric, UuidMetric, }; pub use crate::upload::{PingRequest, PingUploadTask, UploadResult, UploadTaskAction}; @@ -693,7 +693,7 @@ pub fn shutdown() { /// Only has effect when Glean is configured with `delay_ping_lifetime_io: true`. /// If Glean hasn't been initialized this will dispatch and return Ok(()), /// otherwise it will block until the persist is done and return its Result. -pub fn persist_ping_lifetime_data() { +pub fn glean_persist_ping_lifetime_data() { // This is async, we can't get the Error back to the caller. crate::launch_with_glean(|glean| { let _ = glean.persist_ping_lifetime_data(); @@ -910,17 +910,17 @@ pub fn glean_test_get_experimentation_id() -> Option { /// Sets a remote configuration to override metrics' default enabled/disabled /// state /// -/// See [`core::Glean::set_metrics_enabled_config`]. -pub fn glean_set_metrics_enabled_config(json: String) { +/// See [`core::Glean::apply_server_knobs_config`]. +pub fn glean_apply_server_knobs_config(json: String) { // An empty config means it is not set, // so we avoid logging an error about it. if json.is_empty() { return; } - match MetricsEnabledConfig::try_from(json) { + match RemoteSettingsConfig::try_from(json) { Ok(cfg) => launch_with_glean(|glean| { - glean.set_metrics_enabled_config(cfg); + glean.apply_server_knobs_config(cfg); }), Err(e) => { log::error!("Error setting metrics feature config: {:?}", e); @@ -1125,8 +1125,14 @@ pub fn glean_test_destroy_glean(clear_stores: bool, data_path: Option) { // Only useful if Glean initialization finished successfully // and set up the storage. - let has_storage = - core::with_opt_glean(|glean| glean.storage_opt().is_some()).unwrap_or(false); + let has_storage = core::with_opt_glean(|glean| { + // We need to flush the ping lifetime data before a full shutdown. + glean + .storage_opt() + .map(|storage| storage.persist_ping_lifetime_data()) + .is_some() + }) + .unwrap_or(false); if has_storage { uploader_shutdown(); } @@ -1229,6 +1235,20 @@ mod ffi { obj.into_owned() } } + + type JsonValue = serde_json::Value; + + impl UniffiCustomTypeConverter for JsonValue { + type Builtin = String; + + fn into_custom(val: Self::Builtin) -> uniffi::Result { + Ok(serde_json::from_str(&val)?) + } + + fn from_custom(obj: Self) -> Self::Builtin { + serde_json::to_string(&obj).unwrap() + } + } } pub use ffi::*; diff --git a/third_party/rust/glean-core/src/lib_unit_tests.rs b/third_party/rust/glean-core/src/lib_unit_tests.rs index 14d3b98417..b74397317f 100644 --- a/third_party/rust/glean-core/src/lib_unit_tests.rs +++ b/third_party/rust/glean-core/src/lib_unit_tests.rs @@ -890,16 +890,17 @@ fn test_set_remote_metric_configuration() { ); // 2. Set a configuration to disable the metrics - let mut metrics_enabled_config = json!( + let mut remote_settings_config = json!( { - "category.string_metric": false, - "category.labeled_string_metric": false, + "metrics_enabled": { + "category.string_metric": false, + "category.labeled_string_metric": false, + } } ) .to_string(); - glean.set_metrics_enabled_config( - MetricsEnabledConfig::try_from(metrics_enabled_config).unwrap(), - ); + glean + .apply_server_knobs_config(RemoteSettingsConfig::try_from(remote_settings_config).unwrap()); // 3. Since the metrics were disabled, setting a new value will be ignored metric.set_sync(&glean, "VALUE_AFTER_DISABLED"); @@ -921,15 +922,16 @@ fn test_set_remote_metric_configuration() { ); // 4. Set a new configuration where one metric is enabled - metrics_enabled_config = json!( + remote_settings_config = json!( { - "category.string_metric": true, + "metrics_enabled": { + "category.string_metric": true, + } } ) .to_string(); - glean.set_metrics_enabled_config( - MetricsEnabledConfig::try_from(metrics_enabled_config).unwrap(), - ); + glean + .apply_server_knobs_config(RemoteSettingsConfig::try_from(remote_settings_config).unwrap()); // 5. Since the first metric is enabled, setting a new value should work // on it but not the second metric @@ -954,15 +956,16 @@ fn test_set_remote_metric_configuration() { // 6. Set a new configuration where the second metric is enabled. This // should be merged with the existing configuration and then both // metrics should be enabled at that point. - metrics_enabled_config = json!( + remote_settings_config = json!( { - "category.labeled_string_metric": true, + "metrics_enabled": { + "category.labeled_string_metric": true, + } } ) .to_string(); - glean.set_metrics_enabled_config( - MetricsEnabledConfig::try_from(metrics_enabled_config).unwrap(), - ); + glean + .apply_server_knobs_config(RemoteSettingsConfig::try_from(remote_settings_config).unwrap()); // 7. Now both metrics are enabled, setting a new value should work for // both metrics with the merged configurations @@ -992,15 +995,16 @@ fn test_remote_settings_epoch() { assert_eq!(0u8, current_epoch, "Current epoch must start at 0"); // 2. Set a configuration which will trigger incrementing the epoch - let metrics_enabled_config = json!( + let remote_settings_config = json!( { - "category.string_metric": false + "metrics_enabled": { + "category.string_metric": false + } } ) .to_string(); - glean.set_metrics_enabled_config( - MetricsEnabledConfig::try_from(metrics_enabled_config).unwrap(), - ); + glean + .apply_server_knobs_config(RemoteSettingsConfig::try_from(remote_settings_config).unwrap()); // 3. Ensure the epoch updated current_epoch = glean.remote_settings_epoch.load(Ordering::Acquire); @@ -1026,15 +1030,16 @@ fn test_remote_settings_epoch_updates_in_metric() { ); // 2. Set a configuration to disable the `category.string_metric` - let metrics_enabled_config = json!( + let remote_settings_config = json!( { - "category.string_metric": false + "metrics_enabled": { + "category.string_metric": false + } } ) .to_string(); - glean.set_metrics_enabled_config( - MetricsEnabledConfig::try_from(metrics_enabled_config).unwrap(), - ); + glean + .apply_server_knobs_config(RemoteSettingsConfig::try_from(remote_settings_config).unwrap()); // 3. Ensure the epoch was updated let current_epoch = glean.remote_settings_epoch.load(Ordering::Acquire); @@ -1168,7 +1173,16 @@ fn disabled_pings_are_not_submitted() { let dir = tempfile::tempdir().unwrap(); let (mut glean, _t) = new_glean(Some(dir)); - let ping = PingType::new_internal("custom-disabled", true, false, true, true, vec![], false); + let ping = PingType::new_internal( + "custom-disabled", + true, + false, + true, + true, + false, + vec![], + vec![], + ); glean.register_ping_type(&ping); // We need to store a metric as an empty ping is not stored. @@ -1203,3 +1217,53 @@ fn internal_pings_can_be_disabled() { let submitted = glean.internal_pings.baseline.submit_sync(&glean, None); assert!(!submitted); } + +#[test] +fn pings_are_controllable_from_remote_settings_config() { + let _ = env_logger::builder().is_test(true).try_init(); + + let dir = tempfile::tempdir().unwrap(); + let (mut glean, _t) = new_glean(Some(dir)); + + let disabled_ping = PingType::new( + "custom-disabled", + true, + true, + true, + true, + false, + vec![], + vec![], + ); + glean.register_ping_type(&disabled_ping); + let enabled_ping = PingType::new( + "custom-enabled", + true, + true, + true, + true, + true, + vec![], + vec![], + ); + glean.register_ping_type(&enabled_ping); + + assert!(!disabled_ping.submit_sync(&glean, None)); + assert!(enabled_ping.submit_sync(&glean, None)); + + // Now, create a configuration to switch the enabled state of the two pings + let remote_settings_config = json!( + { + "pings_enabled": { + "custom-disabled": true, + "custom-enabled": false + } + } + ) + .to_string(); + glean + .apply_server_knobs_config(RemoteSettingsConfig::try_from(remote_settings_config).unwrap()); + + assert!(disabled_ping.submit_sync(&glean, None)); + assert!(!enabled_ping.submit_sync(&glean, None)); +} diff --git a/third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs b/third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs deleted file mode 100644 index b36cbc150a..0000000000 --- a/third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs +++ /dev/null @@ -1,46 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -use std::collections::HashMap; - -use serde::{Deserialize, Serialize}; - -/// Represents a list of metrics and an associated boolean property -/// indicating if the metric is enabledfrom the remote-settings -/// configuration store. The expected format of this data is stringified JSON -/// in the following format: -/// ```json -/// { -/// "category.metric_name": true -/// } -/// ``` -#[derive(Serialize, Deserialize, Debug, Clone, Default)] -pub struct MetricsEnabledConfig { - /// This is a `HashMap` consisting of base_identifiers as keys - /// and bool values representing an override for the `disabled` - /// property of the metric, only inverted to reduce confusion. - /// If a particular metric has a value of `true` here, it means - /// the default of the metric will be overriden and set to the - /// enabled state. - #[serde(flatten)] - pub metrics_enabled: HashMap, -} - -impl MetricsEnabledConfig { - /// Creates a new MetricsEnabledConfig - pub fn new() -> Self { - Default::default() - } -} - -impl TryFrom for MetricsEnabledConfig { - type Error = crate::ErrorKind; - - fn try_from(json: String) -> Result { - match serde_json::from_str(json.as_str()) { - Ok(config) => Ok(config), - Err(e) => Err(crate::ErrorKind::Json(e)), - } - } -} diff --git a/third_party/rust/glean-core/src/metrics/mod.rs b/third_party/rust/glean-core/src/metrics/mod.rs index 92001efd2a..9234fff2d1 100644 --- a/third_party/rust/glean-core/src/metrics/mod.rs +++ b/third_party/rust/glean-core/src/metrics/mod.rs @@ -22,13 +22,13 @@ mod experiment; pub(crate) mod labeled; mod memory_distribution; mod memory_unit; -mod metrics_enabled_config; mod numerator; mod object; mod ping; mod quantity; mod rate; mod recorded_experiment; +mod remote_settings_config; mod string; mod string_list; mod text; @@ -72,7 +72,7 @@ pub use self::uuid::UuidMetric; pub use crate::histogram::HistogramType; pub use recorded_experiment::RecordedExperiment; -pub use self::metrics_enabled_config::MetricsEnabledConfig; +pub use self::remote_settings_config::RemoteSettingsConfig; /// A snapshot of all buckets and the accumulated sum of a distribution. // @@ -180,7 +180,7 @@ pub trait MetricType { // Technically nothing prevents multiple calls to should_record() to run in parallel, // meaning both are reading self.meta().disabled and later writing it. In between it can - // also read remote_settings_metrics_config, which also could be modified in between those 2 reads. + // also read remote_settings_config, which also could be modified in between those 2 reads. // This means we could write the wrong remote_settings_epoch | current_disabled value. All in all // at worst we would see that metric enabled/disabled wrongly once. // But since everything is tunneled through the dispatcher, this should never ever happen. @@ -200,11 +200,7 @@ pub trait MetricType { } // The epoch's didn't match so we need to look up the disabled flag // by the base_identifier from the in-memory HashMap - let metrics_enabled = &glean - .remote_settings_metrics_config - .lock() - .unwrap() - .metrics_enabled; + let remote_settings_config = &glean.remote_settings_config.lock().unwrap(); // Get the value from the remote configuration if it is there, otherwise return the default value. let current_disabled = { let base_id = self.meta().base_identifier(); @@ -215,8 +211,13 @@ pub trait MetricType { // NOTE: The `!` preceding the `*is_enabled` is important for inverting the logic since the // underlying property in the metrics.yaml is `disabled` and the outward API is treating it as // if it were `enabled` to make it easier to understand. - if let Some(is_enabled) = metrics_enabled.get(identifier) { - u8::from(!*is_enabled) + + if !remote_settings_config.metrics_enabled.is_empty() { + if let Some(is_enabled) = remote_settings_config.metrics_enabled.get(identifier) { + u8::from(!*is_enabled) + } else { + u8::from(self.meta().inner.disabled) + } } else { u8::from(self.meta().inner.disabled) } diff --git a/third_party/rust/glean-core/src/metrics/object.rs b/third_party/rust/glean-core/src/metrics/object.rs index 6071e2b33a..58c8a04c73 100644 --- a/third_party/rust/glean-core/src/metrics/object.rs +++ b/third_party/rust/glean-core/src/metrics/object.rs @@ -48,6 +48,10 @@ impl ObjectMetric { /// * `value` - the value to set. #[doc(hidden)] pub fn set_sync(&self, glean: &Glean, value: JsonValue) { + if !self.should_record(glean) { + return; + } + let value = Metric::Object(serde_json::to_string(&value).unwrap()); glean.storage().record(glean, &self.meta, &value) } @@ -65,6 +69,31 @@ impl ObjectMetric { crate::launch_with_glean(move |glean| metric.set_sync(glean, value)) } + /// Sets to the specified structure. + /// + /// Parses the passed JSON string. + /// If it can't be parsed into a valid object it records an invalid value error. + /// + /// Note: This does not check the structure. This needs to be done by the wrapper. + /// + /// # Arguments + /// + /// * `object` - JSON representation of the object to set. + pub fn set_string(&self, object: String) { + let metric = self.clone(); + crate::launch_with_glean(move |glean| { + let object = match serde_json::from_str(&object) { + Ok(object) => object, + Err(_) => { + let msg = "Value did not match predefined schema"; + record_error(glean, &metric.meta, ErrorType::InvalidValue, msg, None); + return; + } + }; + metric.set_sync(glean, object) + }) + } + /// Record an `InvalidValue` error for this metric. /// /// Only to be used by the RLB. diff --git a/third_party/rust/glean-core/src/metrics/ping.rs b/third_party/rust/glean-core/src/metrics/ping.rs index 5defab7a71..1c5b93c165 100644 --- a/third_party/rust/glean-core/src/metrics/ping.rs +++ b/third_party/rust/glean-core/src/metrics/ping.rs @@ -29,13 +29,12 @@ struct InnerPing { pub precise_timestamps: bool, /// Whether to include the {client|ping}_info sections on assembly. pub include_info_sections: bool, + /// Whether this ping is enabled. + pub enabled: bool, + /// Other pings that should be scheduled when this ping is sent. + pub schedules_pings: Vec, /// The "reason" codes that this ping can send pub reason_codes: Vec, - - /// Whether this ping is enabled. - /// Note: Data for disabled pings is still recorded. - /// It will not be cleared out on submit. - enabled: bool, } impl fmt::Debug for PingType { @@ -46,6 +45,8 @@ impl fmt::Debug for PingType { .field("send_if_empty", &self.0.send_if_empty) .field("precise_timestamps", &self.0.precise_timestamps) .field("include_info_sections", &self.0.include_info_sections) + .field("enabled", &self.0.enabled) + .field("schedules_pings", &self.0.schedules_pings) .field("reason_codes", &self.0.reason_codes) .finish() } @@ -64,13 +65,20 @@ impl PingType { /// * `name` - The name of the ping. /// * `include_client_id` - Whether to include the client ID in the assembled ping when submitting. /// * `send_if_empty` - Whether the ping should be sent empty or not. + /// * `precise_timestamps` - Whether the ping should use precise timestamps for the start and end time. + /// * `include_info_sections` - Whether the ping should include the client/ping_info sections. + /// * `enabled` - Whether or not this ping is enabled. Note: Data that would be sent on a disabled + /// ping will still be collected but is discarded rather than being submitted. /// * `reason_codes` - The valid reason codes for this ping. + #[allow(clippy::too_many_arguments)] pub fn new>( name: A, include_client_id: bool, send_if_empty: bool, precise_timestamps: bool, include_info_sections: bool, + enabled: bool, + schedules_pings: Vec, reason_codes: Vec, ) -> Self { Self::new_internal( @@ -79,19 +87,22 @@ impl PingType { send_if_empty, precise_timestamps, include_info_sections, + enabled, + schedules_pings, reason_codes, - true, ) } + #[allow(clippy::too_many_arguments)] pub(crate) fn new_internal>( name: A, include_client_id: bool, send_if_empty: bool, precise_timestamps: bool, include_info_sections: bool, - reason_codes: Vec, enabled: bool, + schedules_pings: Vec, + reason_codes: Vec, ) -> Self { let this = Self(Arc::new(InnerPing { name: name.into(), @@ -99,8 +110,9 @@ impl PingType { send_if_empty, precise_timestamps, include_info_sections, - reason_codes, enabled, + schedules_pings, + reason_codes, })); // Register this ping. @@ -130,6 +142,22 @@ impl PingType { self.0.include_info_sections } + pub(crate) fn enabled(&self, glean: &Glean) -> bool { + let remote_settings_config = &glean.remote_settings_config.lock().unwrap(); + + if !remote_settings_config.pings_enabled.is_empty() { + if let Some(remote_enabled) = remote_settings_config.pings_enabled.get(self.name()) { + return *remote_enabled; + } + } + + self.0.enabled + } + + pub(crate) fn schedules_pings(&self) -> &[String] { + &self.0.schedules_pings + } + /// Submits the ping for eventual uploading. /// /// The ping content is assembled as soon as possible, but upload is not @@ -166,11 +194,6 @@ impl PingType { /// Whether the ping was succesfully assembled and queued. #[doc(hidden)] pub fn submit_sync(&self, glean: &Glean, reason: Option<&str>) -> bool { - if !self.0.enabled { - log::info!("Ping disabled: not submitting '{}' ping.", self.0.name); - return false; - } - if !glean.is_upload_enabled() { log::info!("Glean disabled: not submitting any pings."); return false; @@ -208,6 +231,15 @@ impl PingType { false } Some(ping) => { + if !self.enabled(glean) { + log::info!( + "The ping '{}' is disabled and will be discarded and not submitted", + ping.name + ); + + return false; + } + // This metric is recorded *after* the ping is collected (since // that is the only way to know *if* it will be submitted). The // implication of this is that the count for a metrics ping will @@ -219,7 +251,10 @@ impl PingType { .add_sync(glean, 1); if let Err(e) = ping_maker.store_ping(glean.get_data_path(), &ping) { - log::warn!("IO error while writing ping to file: {}. Enqueuing upload of what we have in memory.", e); + log::warn!( + "IO error while writing ping to file: {}. Enqueuing upload of what we have in memory.", + e + ); glean.additional_metrics.io_errors.add_sync(glean, 1); // `serde_json::to_string` only fails if serialization of the content // fails or it contains maps with non-string keys. @@ -248,6 +283,17 @@ impl PingType { ping.name ); + if !ping.schedules_pings.is_empty() { + log::info!( + "The ping '{}' is being used to schedule other pings: {:?}", + ping.name, + ping.schedules_pings + ); + for scheduled_ping_name in &ping.schedules_pings { + glean.submit_ping_by_name(scheduled_ping_name, reason); + } + } + true } } diff --git a/third_party/rust/glean-core/src/metrics/remote_settings_config.rs b/third_party/rust/glean-core/src/metrics/remote_settings_config.rs new file mode 100644 index 0000000000..e7a560e81c --- /dev/null +++ b/third_party/rust/glean-core/src/metrics/remote_settings_config.rs @@ -0,0 +1,52 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +/// Represents a list of metrics and an associated boolean property +/// indicating if the metric is enabledfrom the remote-settings +/// configuration store. The expected format of this data is stringified JSON +/// in the following format: +/// ```json +/// { +/// "category.metric_name": true +/// } +/// ``` +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RemoteSettingsConfig { + /// This is a `HashMap` consisting of base_identifiers as keys + /// and bool values representing an override for the `disabled` + /// property of the metric, only inverted to reduce confusion. + /// If a particular metric has a value of `true` here, it means + /// the default of the metric will be overriden and set to the + /// enabled state. + #[serde(default)] + pub metrics_enabled: HashMap, + + /// This is a `HashMap` consisting of ping names as keys and + /// boolean values representing on override for the default + /// enabled state of the ping of the same name. + #[serde(default)] + pub pings_enabled: HashMap, +} + +impl RemoteSettingsConfig { + /// Creates a new RemoteSettingsConfig + pub fn new() -> Self { + Default::default() + } +} + +impl TryFrom for RemoteSettingsConfig { + type Error = crate::ErrorKind; + + fn try_from(json: String) -> Result { + match serde_json::from_str(json.as_str()) { + Ok(config) => Ok(config), + Err(e) => Err(crate::ErrorKind::Json(e)), + } + } +} diff --git a/third_party/rust/glean-core/src/ping/mod.rs b/third_party/rust/glean-core/src/ping/mod.rs index d1a67ae360..8af4cd27f4 100644 --- a/third_party/rust/glean-core/src/ping/mod.rs +++ b/third_party/rust/glean-core/src/ping/mod.rs @@ -32,6 +32,8 @@ pub struct Ping<'a> { pub headers: HeaderMap, /// Whether the content contains {client|ping}_info sections. pub includes_info_sections: bool, + /// Other pings that should be scheduled when this ping is sent. + pub schedules_pings: Vec, } /// Collect a ping's data, assemble it into its full payload and store it on disk. @@ -314,6 +316,7 @@ impl PingMaker { url_path, headers: self.get_headers(glean), includes_info_sections: ping.include_info_sections(), + schedules_pings: ping.schedules_pings().to_vec(), }) } diff --git a/third_party/rust/glean-core/src/upload/directory.rs b/third_party/rust/glean-core/src/upload/directory.rs index 91a4d061d1..b083fa8f1f 100644 --- a/third_party/rust/glean-core/src/upload/directory.rs +++ b/third_party/rust/glean-core/src/upload/directory.rs @@ -337,7 +337,7 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, true, true, true, vec![]); + let ping_type = PingType::new("test", true, true, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); // Submit the ping to populate the pending_pings directory @@ -364,7 +364,7 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, true, true, true, vec![]); + let ping_type = PingType::new("test", true, true, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); // Submit the ping to populate the pending_pings directory @@ -400,7 +400,7 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, true, true, true, vec![]); + let ping_type = PingType::new("test", true, true, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); // Submit the ping to populate the pending_pings directory diff --git a/third_party/rust/glean-core/src/upload/mod.rs b/third_party/rust/glean-core/src/upload/mod.rs index f217137f00..83b06cca65 100644 --- a/third_party/rust/glean-core/src/upload/mod.rs +++ b/third_party/rust/glean-core/src/upload/mod.rs @@ -1031,6 +1031,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1070,6 +1072,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1107,6 +1111,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1144,6 +1150,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1181,6 +1189,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1220,6 +1230,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1335,6 +1347,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1408,6 +1422,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1465,6 +1481,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1543,6 +1561,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1622,6 +1642,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); @@ -1703,6 +1725,8 @@ mod test { /* send_if_empty */ true, true, true, + true, + vec![], vec![], ); glean.register_ping_type(&ping_type); diff --git a/third_party/rust/glean-core/tests/event.rs b/third_party/rust/glean-core/tests/event.rs index 48120956d7..20bf943113 100644 --- a/third_party/rust/glean-core/tests/event.rs +++ b/third_party/rust/glean-core/tests/event.rs @@ -167,6 +167,8 @@ fn test_sending_of_event_ping_when_it_fills_up() { false, true, true, + true, + vec![], vec!["max_capacity".to_string()], )); } @@ -452,6 +454,8 @@ fn event_storage_trimming() { false, true, true, + true, + vec![], vec![], )); diff --git a/third_party/rust/glean-core/tests/ping.rs b/third_party/rust/glean-core/tests/ping.rs index 17944b4c24..42f93e08c7 100644 --- a/third_party/rust/glean-core/tests/ping.rs +++ b/third_party/rust/glean-core/tests/ping.rs @@ -15,7 +15,7 @@ use glean_core::Lifetime; fn write_ping_to_disk() { let (mut glean, _temp) = new_glean(None); - let ping = PingType::new("metrics", true, false, true, true, vec![]); + let ping = PingType::new("metrics", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&ping); // We need to store a metric as an empty ping is not stored. @@ -36,7 +36,7 @@ fn write_ping_to_disk() { fn disabling_upload_clears_pending_pings() { let (mut glean, _t) = new_glean(None); - let ping = PingType::new("metrics", true, false, true, true, vec![]); + let ping = PingType::new("metrics", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&ping); // We need to store a metric as an empty ping is not stored. @@ -105,9 +105,18 @@ fn deletion_request_only_when_toggled_from_on_to_off() { fn empty_pings_with_flag_are_sent() { let (mut glean, _t) = new_glean(None); - let ping1 = PingType::new("custom-ping1", true, true, true, true, vec![]); + let ping1 = PingType::new("custom-ping1", true, true, true, true, true, vec![], vec![]); glean.register_ping_type(&ping1); - let ping2 = PingType::new("custom-ping2", true, false, true, true, vec![]); + let ping2 = PingType::new( + "custom-ping2", + true, + false, + true, + true, + true, + vec![], + vec![], + ); glean.register_ping_type(&ping2); // No data is stored in either of the custom pings @@ -139,10 +148,10 @@ fn test_pings_submitted_metric() { None, ); - let metrics_ping = PingType::new("metrics", true, false, true, true, vec![]); + let metrics_ping = PingType::new("metrics", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&metrics_ping); - let baseline_ping = PingType::new("baseline", true, false, true, true, vec![]); + let baseline_ping = PingType::new("baseline", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&baseline_ping); // We need to store a metric as an empty ping is not stored. @@ -218,7 +227,7 @@ fn test_pings_submitted_metric() { fn events_ping_with_metric_but_no_events_is_not_sent() { let (mut glean, _t) = new_glean(None); - let events_ping = PingType::new("events", true, true, true, true, vec![]); + let events_ping = PingType::new("events", true, true, true, true, true, vec![], vec![]); glean.register_ping_type(&events_ping); let counter = CounterMetric::new(CommonMetricData { name: "counter".into(), @@ -247,3 +256,26 @@ fn events_ping_with_metric_but_no_events_is_not_sent() { assert!(events_ping.submit_sync(&glean, None)); assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len()); } + +#[test] +fn test_scheduled_pings_are_sent() { + let (mut glean, _t) = new_glean(None); + + let piggyback_ping = PingType::new("piggyback", true, true, true, true, true, vec![], vec![]); + glean.register_ping_type(&piggyback_ping); + + let trigger_ping = PingType::new( + "trigger", + true, + true, + true, + true, + true, + vec!["piggyback".into()], + vec![], + ); + glean.register_ping_type(&trigger_ping); + + assert!(trigger_ping.submit_sync(&glean, None)); + assert_eq!(2, get_queued_pings(glean.get_data_path()).unwrap().len()); +} diff --git a/third_party/rust/glean-core/tests/ping_maker.rs b/third_party/rust/glean-core/tests/ping_maker.rs index f716dc4692..ac2dcbee11 100644 --- a/third_party/rust/glean-core/tests/ping_maker.rs +++ b/third_party/rust/glean-core/tests/ping_maker.rs @@ -13,7 +13,7 @@ fn set_up_basic_ping() -> (Glean, PingMaker, PingType, tempfile::TempDir) { let (tempdir, _) = tempdir(); let (mut glean, t) = new_glean(Some(tempdir)); let ping_maker = PingMaker::new(); - let ping_type = PingType::new("store1", true, false, true, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); // Record something, so the ping will have data @@ -95,7 +95,7 @@ fn test_metrics_must_report_experimentation_id() { }) .unwrap(); let ping_maker = PingMaker::new(); - let ping_type = PingType::new("store1", true, false, true, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); // Record something, so the ping will have data @@ -149,7 +149,7 @@ fn experimentation_id_is_removed_if_send_if_empty_is_false() { .unwrap(); let ping_maker = PingMaker::new(); - let unknown_ping_type = PingType::new("unknown", true, false, true, true, vec![]); + let unknown_ping_type = PingType::new("unknown", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&unknown_ping_type); assert!(ping_maker @@ -165,7 +165,7 @@ fn collect_must_report_none_when_no_data_is_stored() { let (mut glean, ping_maker, ping_type, _t) = set_up_basic_ping(); - let unknown_ping_type = PingType::new("unknown", true, false, true, true, vec![]); + let unknown_ping_type = PingType::new("unknown", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); assert!(ping_maker @@ -189,7 +189,8 @@ fn seq_number_must_be_sequential() { for i in 0..=1 { for ping_name in ["store1", "store2"].iter() { - let ping_type = PingType::new(*ping_name, true, false, true, true, vec![]); + let ping_type = + PingType::new(*ping_name, true, false, true, true, true, vec![], vec![]); let ping = ping_maker .collect(&glean, &ping_type, None, "", "") .unwrap(); @@ -202,7 +203,7 @@ fn seq_number_must_be_sequential() { // Test that ping sequence numbers increase independently. { - let ping_type = PingType::new("store1", true, false, true, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, true, vec![], vec![]); // 3rd ping of store1 let ping = ping_maker @@ -220,7 +221,7 @@ fn seq_number_must_be_sequential() { } { - let ping_type = PingType::new("store2", true, false, true, true, vec![]); + let ping_type = PingType::new("store2", true, false, true, true, true, vec![], vec![]); // 3rd ping of store2 let ping = ping_maker @@ -231,7 +232,7 @@ fn seq_number_must_be_sequential() { } { - let ping_type = PingType::new("store1", true, false, true, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, true, vec![], vec![]); // 5th ping of store1 let ping = ping_maker @@ -246,7 +247,7 @@ fn seq_number_must_be_sequential() { fn clear_pending_pings() { let (mut glean, _t) = new_glean(None); let ping_maker = PingMaker::new(); - let ping_type = PingType::new("store1", true, false, true, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); // Record something, so the ping will have data @@ -274,7 +275,7 @@ fn no_pings_submitted_if_upload_disabled() { // Regression test, bug 1603571 let (mut glean, _t) = new_glean(None); - let ping_type = PingType::new("store1", true, true, true, true, vec![]); + let ping_type = PingType::new("store1", true, true, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); assert!(ping_type.submit_sync(&glean, None)); @@ -292,7 +293,7 @@ fn no_pings_submitted_if_upload_disabled() { fn metadata_is_correctly_added_when_necessary() { let (mut glean, _t) = new_glean(None); glean.set_debug_view_tag("valid-tag"); - let ping_type = PingType::new("store1", true, true, true, true, vec![]); + let ping_type = PingType::new("store1", true, true, true, true, true, vec![], vec![]); glean.register_ping_type(&ping_type); assert!(ping_type.submit_sync(&glean, None)); diff --git a/third_party/rust/glean/.cargo-checksum.json b/third_party/rust/glean/.cargo-checksum.json index 7cb5c7390c..76c4772b8e 100644 --- a/third_party/rust/glean/.cargo-checksum.json +++ b/third_party/rust/glean/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"af0535de86b60e3e08cadcdb9e61ce4a699c168608d7e9e2ebb92d949e7f31ef","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5627cc81e6187ab6c2b4dff061af16d559edcab64ba786bac39daa69c703c595","src/common_test.rs":"de47b53dcca37985c0a2b8c02daecbf32309aa54f5a4dd9290719c2c1fd0fa55","src/configuration.rs":"27075b12236021c54d0c99427bcbd417933ca02545275604d3c13f32ca25af13","src/core_metrics.rs":"fef8fb4e5fa57c179836c6eb2cf59278fe3b8b036dbe57b0ff02971b4acd822f","src/lib.rs":"d4010f265de330081467673df05bbd45efbdfeef28823f7dc11a903b11fb8976","src/net/http_uploader.rs":"01ad5bd91384411a12c74434cd1c5cd585078cb34faba4615c70bdb669a9bccb","src/net/mod.rs":"f47b96bb878f1a6c771cedbaeaeefb270bc87fb1d1bbbed1b282dddca16216ed","src/private/event.rs":"d7c70c02648584c19c73af89e5180d3c6153c911f2c6830f7d1599b18d6150eb","src/private/mod.rs":"3565eb569d2b96f938f130abe0fc3ee3f55e7e03fd6501e309d3ef6af72ef6ee","src/private/object.rs":"3f70363a196aea46cc163af025a53e48c117c6208babc4bce772bb4c337cced8","src/private/ping.rs":"a6262a3453c77cbf30766c19b535a1bf66a37b2a316e8f87baee03025255c33e","src/system.rs":"6eae5b41c15eba9cad6dbd116abe3519ee3e1fe034e79bdd692b029829a8c384","src/test.rs":"6388b9e8bf96e0fb56ad71b7a5b5630d209ae62f1a65c62e878cbc1757ddd585","tests/common/mod.rs":"08fb9483d9b6ed9fe873b4395245166ae8a15263be750c7a8e298c41d9604745","tests/init_fails.rs":"906bbf0faa613976623e0cf782bd86545b49d76afaab182af7634690b747ebf7","tests/never_init.rs":"19bad996e22f7d6958cc1a650528530aa7d1aeb4a8ab42229a90bbc0315c8ed1","tests/no_time_to_init.rs":"06c81148c27d383cb708c0c80a2e806024c9955337d7adfba8c53aaeade9be67","tests/overflowing_preinit.rs":"7ad4b2274dd9240b53430859a4eb1d2597cf508a5a678333f3d3abbadd2ed4a7","tests/persist_ping_lifetime.rs":"81415dc1d74743f02269f0d0dfa524003147056853f080276972e64a0b761d3c","tests/persist_ping_lifetime_nopanic.rs":"18379d3ffbf4a2c8c684c04ff7a0660b86dfbbb447db2d24dfed6073cb7ddf8f","tests/schema.rs":"9615eded31a2582c8f04c729d551c0c81a57029ba62a19184221c2e1cd39baf0","tests/simple.rs":"1b8b227249ae9d3cc281db07ed779bc75252c7849b1c48b4ac3d765228d65b20","tests/test-shutdown-blocking.sh":"9b16a01c190c7062474dd92182298a3d9a27928c8fa990340fdd798e6cdb7ab2","tests/test-thread-crashing.sh":"ff1bc8e5d7e4ba3a10d0d38bef222db8bfba469e7d30e45b1053d177a4084f09","tests/upload_timing.rs":"3024b7999a0c23f2c3d7e59725b5455522e4e9fdf63e3265b93fea4cec18725f"},"package":"0ceede8fb9c90ba1b77fb8290d3ae7b62bfcb422ad1d6e46bae1c8af3f22f12d"} \ No newline at end of file +{"files":{"Cargo.toml":"f6e4a46a08d708810f6f0fc0461c4ebc246d5d656b2ed3a1bff4bdd774911c84","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5627cc81e6187ab6c2b4dff061af16d559edcab64ba786bac39daa69c703c595","src/common_test.rs":"de47b53dcca37985c0a2b8c02daecbf32309aa54f5a4dd9290719c2c1fd0fa55","src/configuration.rs":"27075b12236021c54d0c99427bcbd417933ca02545275604d3c13f32ca25af13","src/core_metrics.rs":"fef8fb4e5fa57c179836c6eb2cf59278fe3b8b036dbe57b0ff02971b4acd822f","src/lib.rs":"21d670de3713a20a7a741f8ff6d6bde4329be44beeca037e32f22cce53a1bea2","src/net/http_uploader.rs":"01ad5bd91384411a12c74434cd1c5cd585078cb34faba4615c70bdb669a9bccb","src/net/mod.rs":"f47b96bb878f1a6c771cedbaeaeefb270bc87fb1d1bbbed1b282dddca16216ed","src/private/event.rs":"d7c70c02648584c19c73af89e5180d3c6153c911f2c6830f7d1599b18d6150eb","src/private/mod.rs":"3565eb569d2b96f938f130abe0fc3ee3f55e7e03fd6501e309d3ef6af72ef6ee","src/private/object.rs":"3f70363a196aea46cc163af025a53e48c117c6208babc4bce772bb4c337cced8","src/private/ping.rs":"31d33d7f661a7a17ccb69351328700b4d7b80024d1e128f406c3534f9d163475","src/system.rs":"6eae5b41c15eba9cad6dbd116abe3519ee3e1fe034e79bdd692b029829a8c384","src/test.rs":"39dd7468dcdaf17593b8b07970ced25c07cbd76853aaef2532fdcad0281a21d3","tests/common/mod.rs":"08fb9483d9b6ed9fe873b4395245166ae8a15263be750c7a8e298c41d9604745","tests/init_fails.rs":"46d7064bba9386c3065635434e17ac9212c6c2236b3cd12bd985fc3229e659a3","tests/never_init.rs":"7a6e8a011fbd945f2544f204367eeceff3f6039c99d98799477e3b2352ae6227","tests/no_time_to_init.rs":"4a5bdddc2f8226d2ad17038229e8767a6dd195977af49527fbb84a9f6b0154bb","tests/overflowing_preinit.rs":"7ad4b2274dd9240b53430859a4eb1d2597cf508a5a678333f3d3abbadd2ed4a7","tests/persist_ping_lifetime.rs":"81415dc1d74743f02269f0d0dfa524003147056853f080276972e64a0b761d3c","tests/persist_ping_lifetime_nopanic.rs":"18379d3ffbf4a2c8c684c04ff7a0660b86dfbbb447db2d24dfed6073cb7ddf8f","tests/schema.rs":"dde65bce8a715ca3bd9c54b2466d831dd5e0d559e0773fe7657827f22a66bb44","tests/simple.rs":"1835b5df6f76ff894b45805bd54eaab23ca2d9d2b0694ec64af3aa6132baf30e","tests/test-shutdown-blocking.sh":"a44d8d4bbe2ee3ede9e48121150ae7a5386025160c5cef2181ca142232c5fb27","tests/test-thread-crashing.sh":"8d5ed070754e09fbe55183bb2792ae6e234a95770e39397caf05e4ec4d6015db","tests/upload_timing.rs":"6a97aa355d808123af0914ffecf1da0ecb2cc441c95c63c600b14f97ce0d45a0"},"package":"188984f86678ca6ef88beb79cb743128549946858523d516466d6e94d05fc911"} \ No newline at end of file diff --git a/third_party/rust/glean/Cargo.toml b/third_party/rust/glean/Cargo.toml index edcc84d5d6..db7aa95f21 100644 --- a/third_party/rust/glean/Cargo.toml +++ b/third_party/rust/glean/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.66" name = "glean" -version = "59.0.0" +version = "60.0.1" authors = [ "Jan-Erik Rediger ", "The Glean Team ", @@ -35,7 +35,7 @@ license = "MPL-2.0" repository = "https://github.com/mozilla/glean" [dependencies.glean-core] -version = "59.0.0" +version = "=60.0.1" [dependencies.inherent] version = "1" diff --git a/third_party/rust/glean/src/lib.rs b/third_party/rust/glean/src/lib.rs index 81899d42ee..7f7f2c48be 100644 --- a/third_party/rust/glean/src/lib.rs +++ b/third_party/rust/glean/src/lib.rs @@ -23,7 +23,7 @@ //! let cfg = ConfigurationBuilder::new(true, "/tmp/data", "org.mozilla.glean_core.example").build(); //! glean::initialize(cfg, ClientInfoMetrics::unknown()); //! -//! let prototype_ping = PingType::new("prototype", true, true, true, true, vec!()); +//! let prototype_ping = PingType::new("prototype", true, true, true, true, true, vec!(), vec!()); //! //! prototype_ping.submit(None); //! ``` @@ -187,9 +187,9 @@ pub fn test_get_experimentation_id() -> Option { /// Set the remote configuration values for the metrics' disabled property /// -/// See [`glean_core::Glean::set_metrics_enabled_config`]. -pub fn glean_set_metrics_enabled_config(json: String) { - glean_core::glean_set_metrics_enabled_config(json) +/// See [`glean_core::Glean::glean_apply_server_knobs_config`]. +pub fn glean_apply_server_knobs_config(json: String) { + glean_core::glean_apply_server_knobs_config(json) } /// Performs the collection/cleanup operations required by becoming active. @@ -293,7 +293,7 @@ pub fn get_timestamp_ms() -> u64 { /// If Glean hasn't been initialized this will dispatch and return Ok(()), /// otherwise it will block until the persist is done and return its Result. pub fn persist_ping_lifetime_data() { - glean_core::persist_ping_lifetime_data(); + glean_core::glean_persist_ping_lifetime_data(); } #[cfg(test)] diff --git a/third_party/rust/glean/src/private/ping.rs b/third_party/rust/glean/src/private/ping.rs index 6c126992bc..b54eec91a6 100644 --- a/third_party/rust/glean/src/private/ping.rs +++ b/third_party/rust/glean/src/private/ping.rs @@ -27,13 +27,22 @@ impl PingType { /// * `name` - The name of the ping. /// * `include_client_id` - Whether to include the client ID in the assembled ping when. /// * `send_if_empty` - Whether the ping should be sent empty or not. + /// * `precise_timestamps` - Whether the ping should use precise timestamps for the start and end time. + /// * `include_info_sections` - Whether the ping should include the client/ping_info sections. + /// * `enabled` - Whether or not this ping is enabled. Note: Data that would be sent on a disabled + /// ping will still be collected and is discarded instead of being submitted. + /// * `schedules_pings` - A list of pings which are triggered for submission when this ping is + /// submitted. /// * `reason_codes` - The valid reason codes for this ping. + #[allow(clippy::too_many_arguments)] pub fn new>( name: A, include_client_id: bool, send_if_empty: bool, precise_timestamps: bool, include_info_sections: bool, + enabled: bool, + schedules_pings: Vec, reason_codes: Vec, ) -> Self { let inner = glean_core::metrics::PingType::new( @@ -42,6 +51,8 @@ impl PingType { send_if_empty, precise_timestamps, include_info_sections, + enabled, + schedules_pings, reason_codes, ); diff --git a/third_party/rust/glean/src/test.rs b/third_party/rust/glean/src/test.rs index 16d6d05447..c547cabccd 100644 --- a/third_party/rust/glean/src/test.rs +++ b/third_party/rust/glean/src/test.rs @@ -49,7 +49,8 @@ fn send_a_ping() { // Define a new ping and submit it. const PING_NAME: &str = "test-ping"; - let custom_ping = private::PingType::new(PING_NAME, true, true, true, true, vec![]); + let custom_ping = + private::PingType::new(PING_NAME, true, true, true, true, true, vec![], vec![]); custom_ping.submit(None); // Wait for the ping to arrive. @@ -90,7 +91,8 @@ fn send_a_ping_without_info_sections() { // Define a new ping and submit it. const PING_NAME: &str = "noinfo-ping"; - let custom_ping = private::PingType::new(PING_NAME, true, true, true, false, vec![]); + let custom_ping = + private::PingType::new(PING_NAME, true, true, true, false, true, vec![], vec![]); custom_ping.submit(None); // Wait for the ping to arrive. @@ -594,7 +596,7 @@ fn ping_collection_must_happen_after_concurrently_scheduled_metrics_recordings() ); let ping_name = "custom_ping_1"; - let ping = private::PingType::new(ping_name, true, false, true, true, vec![]); + let ping = private::PingType::new(ping_name, true, false, true, true, true, vec![], vec![]); let metric = private::StringMetric::new(CommonMetricData { name: "string_metric".into(), category: "telemetry".into(), @@ -1097,7 +1099,16 @@ fn flipping_upload_enabled_respects_order_of_events() { .build(); // We create a ping and a metric before we initialize Glean - let sample_ping = PingType::new("sample-ping-1", true, false, true, true, vec![]); + let sample_ping = PingType::new( + "sample-ping-1", + true, + false, + true, + true, + true, + vec![], + vec![], + ); let metric = private::StringMetric::new(CommonMetricData { name: "string_metric".into(), category: "telemetry".into(), @@ -1141,7 +1152,7 @@ fn registering_pings_before_init_must_work() { } // Create a custom ping and attempt its registration. - let sample_ping = PingType::new("pre-register", true, true, true, true, vec![]); + let sample_ping = PingType::new("pre-register", true, true, true, true, true, vec![], vec![]); // Create a custom configuration to use a fake uploader. let dir = tempfile::tempdir().unwrap(); @@ -1193,7 +1204,7 @@ fn test_a_ping_before_submission() { let _t = new_glean(Some(cfg), true); // Create a custom ping and register it. - let sample_ping = PingType::new("custom1", true, true, true, true, vec![]); + let sample_ping = PingType::new("custom1", true, true, true, true, true, vec![], vec![]); let metric = CounterMetric::new(CommonMetricData { name: "counter_metric".into(), @@ -1310,7 +1321,8 @@ fn signaling_done() { // Define a new ping and submit it. const PING_NAME: &str = "test-ping"; - let custom_ping = private::PingType::new(PING_NAME, true, true, true, true, vec![]); + let custom_ping = + private::PingType::new(PING_NAME, true, true, true, true, true, vec![], vec![]); custom_ping.submit(None); custom_ping.submit(None); @@ -1381,7 +1393,8 @@ fn configure_ping_throttling() { // Define a new ping. const PING_NAME: &str = "test-ping"; - let custom_ping = private::PingType::new(PING_NAME, true, true, true, true, vec![]); + let custom_ping = + private::PingType::new(PING_NAME, true, true, true, true, true, vec![], vec![]); // Submit and receive it `pings_per_interval` times. for _ in 0..pings_per_interval { diff --git a/third_party/rust/glean/tests/init_fails.rs b/third_party/rust/glean/tests/init_fails.rs index a0c23ca277..2ae4a91f02 100644 --- a/third_party/rust/glean/tests/init_fails.rs +++ b/third_party/rust/glean/tests/init_fails.rs @@ -42,8 +42,9 @@ mod pings { use once_cell::sync::Lazy; #[allow(non_upper_case_globals)] - pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); + pub static validation: Lazy = Lazy::new(|| { + glean::private::PingType::new("validation", true, true, true, true, true, vec![], vec![]) + }); } /// Test scenario: Glean initialization fails. diff --git a/third_party/rust/glean/tests/never_init.rs b/third_party/rust/glean/tests/never_init.rs index 0d0d3768ff..a991ce467e 100644 --- a/third_party/rust/glean/tests/never_init.rs +++ b/third_party/rust/glean/tests/never_init.rs @@ -38,8 +38,9 @@ mod pings { use once_cell::sync::Lazy; #[allow(non_upper_case_globals)] - pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); + pub static validation: Lazy = Lazy::new(|| { + glean::private::PingType::new("validation", true, true, true, true, true, vec![], vec![]) + }); } /// Test scenario: Glean is never initialized. diff --git a/third_party/rust/glean/tests/no_time_to_init.rs b/third_party/rust/glean/tests/no_time_to_init.rs index c312b397af..c14129c168 100644 --- a/third_party/rust/glean/tests/no_time_to_init.rs +++ b/third_party/rust/glean/tests/no_time_to_init.rs @@ -40,8 +40,9 @@ mod pings { use once_cell::sync::Lazy; #[allow(non_upper_case_globals)] - pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); + pub static validation: Lazy = Lazy::new(|| { + glean::private::PingType::new("validation", true, true, true, true, true, vec![], vec![]) + }); } /// Test scenario: Glean initialization fails. diff --git a/third_party/rust/glean/tests/schema.rs b/third_party/rust/glean/tests/schema.rs index 59132cd82a..2909ab1dd3 100644 --- a/third_party/rust/glean/tests/schema.rs +++ b/third_party/rust/glean/tests/schema.rs @@ -170,7 +170,8 @@ fn validate_against_schema() { text_metric.set("loooooong text".repeat(100)); // Define a new ping and submit it. - let custom_ping = glean::private::PingType::new(PING_NAME, true, true, true, true, vec![]); + let custom_ping = + glean::private::PingType::new(PING_NAME, true, true, true, true, true, vec![], vec![]); custom_ping.submit(None); // Wait for the ping to arrive. diff --git a/third_party/rust/glean/tests/simple.rs b/third_party/rust/glean/tests/simple.rs index 3baa4df14e..d5c6a5244c 100644 --- a/third_party/rust/glean/tests/simple.rs +++ b/third_party/rust/glean/tests/simple.rs @@ -40,8 +40,9 @@ mod pings { use once_cell::sync::Lazy; #[allow(non_upper_case_globals)] - pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); + pub static validation: Lazy = Lazy::new(|| { + glean::private::PingType::new("validation", true, true, true, true, true, vec![], vec![]) + }); } /// Test scenario: A clean run diff --git a/third_party/rust/glean/tests/test-shutdown-blocking.sh b/third_party/rust/glean/tests/test-shutdown-blocking.sh index 2f5d82acf0..8591aa005a 100755 --- a/third_party/rust/glean/tests/test-shutdown-blocking.sh +++ b/third_party/rust/glean/tests/test-shutdown-blocking.sh @@ -17,7 +17,7 @@ trap cleanup INT ABRT TERM EXIT tmp="${TMPDIR:-/tmp}" datapath=$(mktemp -d "${tmp}/glean_long_running.XXXX") -cargo run --example long-running -- "$datapath" +cargo run -p glean --example long-running -- "$datapath" count=$(ls -1q "$datapath/pending_pings" | wc -l) if [[ "$count" -eq 0 ]]; then diff --git a/third_party/rust/glean/tests/test-thread-crashing.sh b/third_party/rust/glean/tests/test-thread-crashing.sh index 1657467a33..67a0f4099c 100755 --- a/third_party/rust/glean/tests/test-thread-crashing.sh +++ b/third_party/rust/glean/tests/test-thread-crashing.sh @@ -19,7 +19,7 @@ datapath=$(mktemp -d "${tmp}/glean_long_running.XXXX") RUSTFLAGS="-C panic=abort" \ RUST_LOG=debug \ -cargo run --example crashing-threads -- "$datapath" +cargo run -p glean --example crashing-threads -- "$datapath" ret=$? count=$(ls -1q "$datapath/pending_pings" | wc -l) diff --git a/third_party/rust/glean/tests/upload_timing.rs b/third_party/rust/glean/tests/upload_timing.rs index ba0eee3402..49007cf8dc 100644 --- a/third_party/rust/glean/tests/upload_timing.rs +++ b/third_party/rust/glean/tests/upload_timing.rs @@ -96,8 +96,9 @@ mod pings { use once_cell::sync::Lazy; #[allow(non_upper_case_globals)] - pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); + pub static validation: Lazy = Lazy::new(|| { + glean::private::PingType::new("validation", true, true, true, true, true, vec![], vec![]) + }); } // Define a fake uploader that sleeps. diff --git a/third_party/rust/gpu-descriptor-types/.cargo-checksum.json b/third_party/rust/gpu-descriptor-types/.cargo-checksum.json index ff289fd42a..9a414739ec 100644 --- a/third_party/rust/gpu-descriptor-types/.cargo-checksum.json +++ b/third_party/rust/gpu-descriptor-types/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"5e3f9842253279ef626cd67111b942c5ef8d011efb39cc00b8f3469f8b4bede9","src/device.rs":"ecb6aaefd8af7ac51eed42a01ebbe7a98f44f62ea3b8d193e11a6889d4cd01bb","src/lib.rs":"bcf06593c390a3999f300333f63ae69542613157d316b3246faf69eded07d896","src/types.rs":"65f8e4006280713668f96279ce96c2d21fc75b5fb0fe4240dc650dfe71f92b27"},"package":"363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126"} \ No newline at end of file +{"files":{"Cargo.toml":"54164c8c1352852cce6f2330030365868815deb9bd717b8d493071790cd72d7b","src/device.rs":"0f9957fee64c4db767a2abb2e88d34ebbf48ed6062121e081e0116e14190b4fa","src/lib.rs":"0ca3f2a281ba43466fb4d29c05b35c9059806d6114cd929b85afc0c41ea9d3ac","src/types.rs":"d38b838827edf226f6bc82e8f0718d90d6e2376d027c118a6d397260996a12bd"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gpu-descriptor-types/Cargo.toml b/third_party/rust/gpu-descriptor-types/Cargo.toml index 18871bb18b..f63ba9b7b6 100644 --- a/third_party/rust/gpu-descriptor-types/Cargo.toml +++ b/third_party/rust/gpu-descriptor-types/Cargo.toml @@ -3,24 +3,29 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "gpu-descriptor-types" -version = "0.1.1" +version = "0.2.0" authors = ["Zakarum "] description = "Core types of gpu-descriptor crate" homepage = "https://github.com/zakarumych/gpu-descriptor" -documentation = "https://docs.rs/gpu-descriptor-types/0.1.0" -keywords = ["gpu", "vulkan", "allocation", "no-std"] +documentation = "https://docs.rs/gpu-descriptor-types" +keywords = [ + "gpu", + "vulkan", + "allocation", + "no-std", +] license = "MIT OR Apache-2.0" repository = "https://github.com/zakarumych/gpu-descriptor" + [dependencies.bitflags] -version = "1.2" +version = "2.4" default-features = false diff --git a/third_party/rust/gpu-descriptor-types/src/device.rs b/third_party/rust/gpu-descriptor-types/src/device.rs index b10511f863..a73a58a79c 100644 --- a/third_party/rust/gpu-descriptor-types/src/device.rs +++ b/third_party/rust/gpu-descriptor-types/src/device.rs @@ -1,53 +1,75 @@ -use crate::types::{DescriptorPoolCreateFlags, DescriptorTotalCount}; - -/// Memory exhausted error. -#[derive(Debug)] -pub enum CreatePoolError { - /// Device memory exhausted. - OutOfDeviceMemory, - - /// Host memory exhausted. - OutOfHostMemory, - - /// A descriptor pool creation has failed due to fragmentation. - Fragmentation, -} - -/// Memory exhausted error. -#[derive(Debug)] -pub enum DeviceAllocationError { - /// Device memory exhausted. - OutOfDeviceMemory, - - /// Host memory exhausted. - OutOfHostMemory, - - /// Failed to allocate memory from pool. - OutOfPoolMemory, - - /// Pool allocation failed due to fragmentation of pool's memory. - FragmentedPool, -} - -/// Abstract device that can create pools of type `P` and allocate sets `S` with layout `L`. -pub trait DescriptorDevice { - unsafe fn create_descriptor_pool( - &self, - descriptor_count: &DescriptorTotalCount, - max_sets: u32, - flags: DescriptorPoolCreateFlags, - ) -> Result; - - unsafe fn destroy_descriptor_pool(&self, pool: P); - - unsafe fn alloc_descriptor_sets<'a>( - &self, - pool: &mut P, - layouts: impl ExactSizeIterator, - sets: &mut impl Extend, - ) -> Result<(), DeviceAllocationError> - where - L: 'a; - - unsafe fn dealloc_descriptor_sets<'a>(&self, pool: &mut P, sets: impl Iterator); -} +use crate::types::{DescriptorPoolCreateFlags, DescriptorTotalCount}; + +/// Memory exhausted error. +#[derive(Debug)] +pub enum CreatePoolError { + /// Device memory exhausted. + OutOfDeviceMemory, + + /// Host memory exhausted. + OutOfHostMemory, + + /// A descriptor pool creation has failed due to fragmentation. + Fragmentation, +} + +/// Memory exhausted error. +#[derive(Debug)] +pub enum DeviceAllocationError { + /// Device memory exhausted. + OutOfDeviceMemory, + + /// Host memory exhausted. + OutOfHostMemory, + + /// Failed to allocate memory from pool. + OutOfPoolMemory, + + /// Pool allocation failed due to fragmentation of pool's memory. + FragmentedPool, +} + +/// Abstract device that can create pools of type `P` and allocate sets `S` with layout `L`. +pub trait DescriptorDevice { + /// Creates a new descriptor pool. + /// + /// # Safety + /// + /// Actually safe. + /// TODO: Remove `unsafe` with next breaking change. + unsafe fn create_descriptor_pool( + &self, + descriptor_count: &DescriptorTotalCount, + max_sets: u32, + flags: DescriptorPoolCreateFlags, + ) -> Result; + + /// Destroys descriptor pool. + /// + /// # Safety + /// + /// Pool must be created from this device. + /// All descriptor sets allocated from this pool become invalid. + unsafe fn destroy_descriptor_pool(&self, pool: P); + + /// Allocates descriptor sets. + /// + /// # Safety + /// + /// Pool must be created from this device. + unsafe fn alloc_descriptor_sets<'a>( + &self, + pool: &mut P, + layouts: impl ExactSizeIterator, + sets: &mut impl Extend, + ) -> Result<(), DeviceAllocationError> + where + L: 'a; + + /// Deallocates descriptor sets. + /// + /// # Safety + /// + /// Sets must be allocated from specified pool and not deallocated before. + unsafe fn dealloc_descriptor_sets(&self, pool: &mut P, sets: impl Iterator); +} diff --git a/third_party/rust/gpu-descriptor-types/src/lib.rs b/third_party/rust/gpu-descriptor-types/src/lib.rs index 37c0d861c6..2af448c654 100644 --- a/third_party/rust/gpu-descriptor-types/src/lib.rs +++ b/third_party/rust/gpu-descriptor-types/src/lib.rs @@ -1,6 +1,6 @@ -#![no_std] - -mod device; -mod types; - -pub use self::{device::*, types::*}; +#![no_std] + +mod device; +mod types; + +pub use self::{device::*, types::*}; diff --git a/third_party/rust/gpu-descriptor-types/src/types.rs b/third_party/rust/gpu-descriptor-types/src/types.rs index f65ffc74ae..73b28dcea5 100644 --- a/third_party/rust/gpu-descriptor-types/src/types.rs +++ b/third_party/rust/gpu-descriptor-types/src/types.rs @@ -1,33 +1,53 @@ -bitflags::bitflags! { - /// Flags to augment descriptor pool creation. - /// - /// Match corresponding bits in Vulkan. - pub struct DescriptorPoolCreateFlags: u32 { - /// Allows freeing individial sets. - const FREE_DESCRIPTOR_SET = 0x1; - - /// Allows allocating sets with layout created with matching backend-specific flag. - const UPDATE_AFTER_BIND = 0x2; - } -} - -/// Number of descriptors of each type. -/// -/// For `InlineUniformBlock` this value is number of bytes instead. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] -pub struct DescriptorTotalCount { - pub sampler: u32, - pub combined_image_sampler: u32, - pub sampled_image: u32, - pub storage_image: u32, - pub uniform_texel_buffer: u32, - pub storage_texel_buffer: u32, - pub uniform_buffer: u32, - pub storage_buffer: u32, - pub uniform_buffer_dynamic: u32, - pub storage_buffer_dynamic: u32, - pub input_attachment: u32, - pub acceleration_structure: u32, - pub inline_uniform_block_bytes: u32, - pub inline_uniform_block_bindings: u32, -} +bitflags::bitflags! { + /// Flags to augment descriptor pool creation. + /// + /// Match corresponding bits in Vulkan. + #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] + pub struct DescriptorPoolCreateFlags: u32 { + /// Allows freeing individual sets. + const FREE_DESCRIPTOR_SET = 0x1; + + /// Allows allocating sets with layout created with matching backend-specific flag. + const UPDATE_AFTER_BIND = 0x2; + } +} + +/// Number of descriptors of each type. +/// +/// For `InlineUniformBlock` this value is number of bytes instead. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +pub struct DescriptorTotalCount { + pub sampler: u32, + pub combined_image_sampler: u32, + pub sampled_image: u32, + pub storage_image: u32, + pub uniform_texel_buffer: u32, + pub storage_texel_buffer: u32, + pub uniform_buffer: u32, + pub storage_buffer: u32, + pub uniform_buffer_dynamic: u32, + pub storage_buffer_dynamic: u32, + pub input_attachment: u32, + pub acceleration_structure: u32, + pub inline_uniform_block_bytes: u32, + pub inline_uniform_block_bindings: u32, +} + +impl DescriptorTotalCount { + pub fn total(&self) -> u32 { + self.sampler + + self.combined_image_sampler + + self.sampled_image + + self.storage_image + + self.uniform_texel_buffer + + self.storage_texel_buffer + + self.uniform_buffer + + self.storage_buffer + + self.uniform_buffer_dynamic + + self.storage_buffer_dynamic + + self.input_attachment + + self.acceleration_structure + + self.inline_uniform_block_bytes + + self.inline_uniform_block_bindings + } +} diff --git a/third_party/rust/gpu-descriptor/.cargo-checksum.json b/third_party/rust/gpu-descriptor/.cargo-checksum.json index b2cdaf5c8d..f4fb18bc58 100644 --- a/third_party/rust/gpu-descriptor/.cargo-checksum.json +++ b/third_party/rust/gpu-descriptor/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"dfdf8bb8e5a78a8b8feff5d924bd3757fd1299fa015802314a89883036f20c80","src/allocator.rs":"d46bee4586b88a3a5988e59b3112da379a49688d7f12bd2716cebb9fa6076a7a","src/lib.rs":"6fb74a08ad9975e561f4fca7bd391f0cbd96a7cab79b17df7d979021099b50f9"},"package":"0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a"} \ No newline at end of file +{"files":{"Cargo.toml":"0bd7a40cb614fe568b076fd5edd6d6e51791b6d1e0a174ae67a16d56618357e1","src/allocator.rs":"38d173f9b6ca608dee9a7898b6e2ad7e75d199284c99291da0112e4b6e908409","src/lib.rs":"6fb74a08ad9975e561f4fca7bd391f0cbd96a7cab79b17df7d979021099b50f9"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gpu-descriptor/Cargo.toml b/third_party/rust/gpu-descriptor/Cargo.toml index 1f8ff2851c..7524894008 100644 --- a/third_party/rust/gpu-descriptor/Cargo.toml +++ b/third_party/rust/gpu-descriptor/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "gpu-descriptor" -version = "0.2.3" +version = "0.3.0" authors = ["Zakarum "] description = "Implementation agnostic descriptor allocator for Vulkan like APIs" homepage = "https://github.com/zakarumych/gpu-descriptor" @@ -27,14 +27,20 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/zakarumych/gpu-descriptor" [dependencies.bitflags] -version = "1.2" +version = "2.4" default-features = false [dependencies.gpu-descriptor-types] -version = "0.1" +version = "0.2" +path = "../types" [dependencies.hashbrown] -version = "0.12" +version = "0.14" +features = [ + "ahash", + "raw", +] +default-features = false [dependencies.serde] version = "1.0" diff --git a/third_party/rust/gpu-descriptor/src/allocator.rs b/third_party/rust/gpu-descriptor/src/allocator.rs index 077a8860ce..96fc073a48 100644 --- a/third_party/rust/gpu-descriptor/src/allocator.rs +++ b/third_party/rust/gpu-descriptor/src/allocator.rs @@ -13,6 +13,7 @@ use { bitflags::bitflags! { /// Flags to augment descriptor set allocation. + #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct DescriptorSetLayoutCreateFlags: u32 { /// Specified that descriptor set must be allocated from\ /// pool with `DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`. @@ -107,7 +108,7 @@ struct DescriptorPool

{ struct DescriptorBucket

{ offset: u64, pools: VecDeque>, - total: u64, + total: u32, update_after_bind: bool, size: DescriptorTotalCount, } @@ -158,7 +159,7 @@ impl

DescriptorBucket

{ fn new_pool_size(&self, minimal_set_count: u32) -> (DescriptorTotalCount, u32) { let mut max_sets = MIN_SETS // at least MIN_SETS .max(minimal_set_count) // at least enough for allocation - .max(self.total.min(MAX_SETS as u64) as u32) // at least as much as was allocated so far capped to MAX_SETS + .max(self.total.min(MAX_SETS)) // at least as much as was allocated so far capped to MAX_SETS .checked_next_power_of_two() // rounded up to nearest 2^N .unwrap_or(i32::MAX as u32); @@ -259,7 +260,7 @@ impl

DescriptorBucket

{ count -= allocate; pool.available -= allocate; pool.allocated += allocate; - self.total += u64::from(allocate); + self.total += allocate; if count == 0 { return Ok(()); @@ -328,7 +329,7 @@ impl

DescriptorBucket

{ allocated: allocate, available: max_sets - allocate, }); - self.total += allocate as u64; + self.total += allocate; } Ok(()) @@ -356,7 +357,7 @@ impl

DescriptorBucket

{ pool.available += count; pool.allocated -= count; - self.total -= u64::from(count); + self.total -= count; #[cfg(feature = "tracing")] tracing::trace!("Freed {} from descriptor bucket", count); @@ -395,10 +396,11 @@ impl

DescriptorBucket

{ #[derive(Debug)] pub struct DescriptorAllocator { buckets: HashMap<(DescriptorTotalCount, bool), DescriptorBucket

(&self, pred: P) -> usize + where + P: FnMut(&K, &V) -> bool, + { + self.as_slice().partition_point(pred) } /// Reverses the order of the map’s key-value pairs in place. @@ -770,9 +980,28 @@ where pub fn reverse(&mut self) { self.core.reverse() } -} -impl IndexMap { + /// Returns a slice of all the key-value pairs in the map. + /// + /// Computes in **O(1)** time. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.as_entries()) + } + + /// Returns a mutable slice of all the key-value pairs in the map. + /// + /// Computes in **O(1)** time. + pub fn as_mut_slice(&mut self) -> &mut Slice { + Slice::from_mut_slice(self.as_entries_mut()) + } + + /// Converts into a boxed slice of all the key-value pairs in the map. + /// + /// Note that this will drop the inner hash table and any excess capacity. + pub fn into_boxed_slice(self) -> Box> { + Slice::from_boxed(self.into_entries().into_boxed_slice()) + } + /// Get a key-value pair by index /// /// Valid indices are *0 <= index < self.len()* @@ -787,8 +1016,42 @@ impl IndexMap { /// Valid indices are *0 <= index < self.len()* /// /// Computes in **O(1)** time. - pub fn get_index_mut(&mut self, index: usize) -> Option<(&mut K, &mut V)> { - self.as_entries_mut().get_mut(index).map(Bucket::muts) + pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { + self.as_entries_mut().get_mut(index).map(Bucket::ref_mut) + } + + /// Get an entry in the map by index for in-place manipulation. + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + pub fn get_index_entry(&mut self, index: usize) -> Option> { + if index >= self.len() { + return None; + } + Some(IndexedEntry::new(&mut self.core, index)) + } + + /// Returns a slice of key-value pairs in the given range of indices. + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + pub fn get_range>(&self, range: R) -> Option<&Slice> { + let entries = self.as_entries(); + let range = try_simplify_range(range, entries.len())?; + entries.get(range).map(Slice::from_slice) + } + + /// Returns a mutable slice of key-value pairs in the given range of indices. + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + pub fn get_range_mut>(&mut self, range: R) -> Option<&mut Slice> { + let entries = self.as_entries_mut(); + let range = try_simplify_range(range, entries.len())?; + entries.get_mut(range).map(Slice::from_mut_slice) } /// Get the first key-value pair @@ -823,7 +1086,7 @@ impl IndexMap { /// /// Valid indices are *0 <= index < self.len()* /// - /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs /// the position of what used to be the last element!** /// @@ -836,7 +1099,7 @@ impl IndexMap { /// /// Valid indices are *0 <= index < self.len()* /// - /// Like `Vec::remove`, the pair is removed by shifting all of the + /// Like [`Vec::remove`], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// @@ -861,386 +1124,14 @@ impl IndexMap { /// Swaps the position of two key-value pairs in the map. /// /// ***Panics*** if `a` or `b` are out of bounds. + /// + /// Computes in **O(1)** time (average). pub fn swap_indices(&mut self, a: usize, b: usize) { self.core.swap_indices(a, b) } } -/// An iterator over the keys of a `IndexMap`. -/// -/// This `struct` is created by the [`keys`] method on [`IndexMap`]. See its -/// documentation for more. -/// -/// [`keys`]: struct.IndexMap.html#method.keys -/// [`IndexMap`]: struct.IndexMap.html -pub struct Keys<'a, K, V> { - iter: SliceIter<'a, Bucket>, -} - -impl<'a, K, V> Iterator for Keys<'a, K, V> { - type Item = &'a K; - - iterator_methods!(Bucket::key_ref); -} - -impl DoubleEndedIterator for Keys<'_, K, V> { - double_ended_iterator_methods!(Bucket::key_ref); -} - -impl ExactSizeIterator for Keys<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for Keys<'_, K, V> {} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl Clone for Keys<'_, K, V> { - fn clone(&self) -> Self { - Keys { - iter: self.iter.clone(), - } - } -} - -impl fmt::Debug for Keys<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// An owning iterator over the keys of a `IndexMap`. -/// -/// This `struct` is created by the [`into_keys`] method on [`IndexMap`]. -/// See its documentation for more. -/// -/// [`IndexMap`]: struct.IndexMap.html -/// [`into_keys`]: struct.IndexMap.html#method.into_keys -pub struct IntoKeys { - iter: vec::IntoIter>, -} - -impl Iterator for IntoKeys { - type Item = K; - - iterator_methods!(Bucket::key); -} - -impl DoubleEndedIterator for IntoKeys { - double_ended_iterator_methods!(Bucket::key); -} - -impl ExactSizeIterator for IntoKeys { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for IntoKeys {} - -impl fmt::Debug for IntoKeys { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::key_ref); - f.debug_list().entries(iter).finish() - } -} - -/// An iterator over the values of a `IndexMap`. -/// -/// This `struct` is created by the [`values`] method on [`IndexMap`]. See its -/// documentation for more. -/// -/// [`values`]: struct.IndexMap.html#method.values -/// [`IndexMap`]: struct.IndexMap.html -pub struct Values<'a, K, V> { - iter: SliceIter<'a, Bucket>, -} - -impl<'a, K, V> Iterator for Values<'a, K, V> { - type Item = &'a V; - - iterator_methods!(Bucket::value_ref); -} - -impl DoubleEndedIterator for Values<'_, K, V> { - double_ended_iterator_methods!(Bucket::value_ref); -} - -impl ExactSizeIterator for Values<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for Values<'_, K, V> {} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl Clone for Values<'_, K, V> { - fn clone(&self) -> Self { - Values { - iter: self.iter.clone(), - } - } -} - -impl fmt::Debug for Values<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A mutable iterator over the values of a `IndexMap`. -/// -/// This `struct` is created by the [`values_mut`] method on [`IndexMap`]. See its -/// documentation for more. -/// -/// [`values_mut`]: struct.IndexMap.html#method.values_mut -/// [`IndexMap`]: struct.IndexMap.html -pub struct ValuesMut<'a, K, V> { - iter: SliceIterMut<'a, Bucket>, -} - -impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { - type Item = &'a mut V; - - iterator_methods!(Bucket::value_mut); -} - -impl DoubleEndedIterator for ValuesMut<'_, K, V> { - double_ended_iterator_methods!(Bucket::value_mut); -} - -impl ExactSizeIterator for ValuesMut<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for ValuesMut<'_, K, V> {} - -impl fmt::Debug for ValuesMut<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::value_ref); - f.debug_list().entries(iter).finish() - } -} - -/// An owning iterator over the values of a `IndexMap`. -/// -/// This `struct` is created by the [`into_values`] method on [`IndexMap`]. -/// See its documentation for more. -/// -/// [`IndexMap`]: struct.IndexMap.html -/// [`into_values`]: struct.IndexMap.html#method.into_values -pub struct IntoValues { - iter: vec::IntoIter>, -} - -impl Iterator for IntoValues { - type Item = V; - - iterator_methods!(Bucket::value); -} - -impl DoubleEndedIterator for IntoValues { - double_ended_iterator_methods!(Bucket::value); -} - -impl ExactSizeIterator for IntoValues { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for IntoValues {} - -impl fmt::Debug for IntoValues { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::value_ref); - f.debug_list().entries(iter).finish() - } -} - -/// An iterator over the entries of a `IndexMap`. -/// -/// This `struct` is created by the [`iter`] method on [`IndexMap`]. See its -/// documentation for more. -/// -/// [`iter`]: struct.IndexMap.html#method.iter -/// [`IndexMap`]: struct.IndexMap.html -pub struct Iter<'a, K, V> { - iter: SliceIter<'a, Bucket>, -} - -impl<'a, K, V> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - iterator_methods!(Bucket::refs); -} - -impl DoubleEndedIterator for Iter<'_, K, V> { - double_ended_iterator_methods!(Bucket::refs); -} - -impl ExactSizeIterator for Iter<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for Iter<'_, K, V> {} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl Clone for Iter<'_, K, V> { - fn clone(&self) -> Self { - Iter { - iter: self.iter.clone(), - } - } -} - -impl fmt::Debug for Iter<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A mutable iterator over the entries of a `IndexMap`. -/// -/// This `struct` is created by the [`iter_mut`] method on [`IndexMap`]. See its -/// documentation for more. -/// -/// [`iter_mut`]: struct.IndexMap.html#method.iter_mut -/// [`IndexMap`]: struct.IndexMap.html -pub struct IterMut<'a, K, V> { - iter: SliceIterMut<'a, Bucket>, -} - -impl<'a, K, V> Iterator for IterMut<'a, K, V> { - type Item = (&'a K, &'a mut V); - - iterator_methods!(Bucket::ref_mut); -} - -impl DoubleEndedIterator for IterMut<'_, K, V> { - double_ended_iterator_methods!(Bucket::ref_mut); -} - -impl ExactSizeIterator for IterMut<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for IterMut<'_, K, V> {} - -impl fmt::Debug for IterMut<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::refs); - f.debug_list().entries(iter).finish() - } -} - -/// An owning iterator over the entries of a `IndexMap`. -/// -/// This `struct` is created by the [`into_iter`] method on [`IndexMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`into_iter`]: struct.IndexMap.html#method.into_iter -/// [`IndexMap`]: struct.IndexMap.html -pub struct IntoIter { - iter: vec::IntoIter>, -} - -impl Iterator for IntoIter { - type Item = (K, V); - - iterator_methods!(Bucket::key_value); -} - -impl DoubleEndedIterator for IntoIter { - double_ended_iterator_methods!(Bucket::key_value); -} - -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for IntoIter {} - -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::refs); - f.debug_list().entries(iter).finish() - } -} - -/// A draining iterator over the entries of a `IndexMap`. -/// -/// This `struct` is created by the [`drain`] method on [`IndexMap`]. See its -/// documentation for more. -/// -/// [`drain`]: struct.IndexMap.html#method.drain -/// [`IndexMap`]: struct.IndexMap.html -pub struct Drain<'a, K, V> { - pub(crate) iter: vec::Drain<'a, Bucket>, -} - -impl Iterator for Drain<'_, K, V> { - type Item = (K, V); - - iterator_methods!(Bucket::key_value); -} - -impl DoubleEndedIterator for Drain<'_, K, V> { - double_ended_iterator_methods!(Bucket::key_value); -} - -impl ExactSizeIterator for Drain<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for Drain<'_, K, V> {} - -impl fmt::Debug for Drain<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::refs); - f.debug_list().entries(iter).finish() - } -} - -impl<'a, K, V, S> IntoIterator for &'a IndexMap { - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a mut IndexMap { - type Item = (&'a K, &'a mut V); - type IntoIter = IterMut<'a, K, V>; - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - -impl IntoIterator for IndexMap { - type Item = (K, V); - type IntoIter = IntoIter; - fn into_iter(self) -> Self::IntoIter { - IntoIter { - iter: self.into_entries().into_iter(), - } - } -} - -/// Access `IndexMap` values corresponding to a key. +/// Access [`IndexMap`] values corresponding to a key. /// /// # Examples /// @@ -1265,7 +1156,6 @@ impl IntoIterator for IndexMap { impl Index<&Q> for IndexMap where Q: Hash + Equivalent, - K: Hash + Eq, S: BuildHasher, { type Output = V; @@ -1278,7 +1168,7 @@ where } } -/// Access `IndexMap` values corresponding to a key. +/// Access [`IndexMap`] values corresponding to a key. /// /// Mutable indexing allows changing / updating values of key-value /// pairs that are already present. @@ -1310,7 +1200,6 @@ where impl IndexMut<&Q> for IndexMap where Q: Hash + Equivalent, - K: Hash + Eq, S: BuildHasher, { /// Returns a mutable reference to the value corresponding to the supplied `key`. @@ -1321,7 +1210,11 @@ where } } -/// Access `IndexMap` values at indexed positions. +/// Access [`IndexMap`] values at indexed positions. +/// +/// See [`Index for Keys`][keys] to access a map's keys instead. +/// +/// [keys]: Keys#impl-Index-for-Keys<'a,+K,+V> /// /// # Examples /// @@ -1362,12 +1255,12 @@ impl Index for IndexMap { } } -/// Access `IndexMap` values at indexed positions. +/// Access [`IndexMap`] values at indexed positions. /// /// Mutable indexing allows changing / updating indexed values /// that are already present. /// -/// You can **not** insert new values with index syntax, use `.insert()`. +/// You can **not** insert new values with index syntax -- use [`.insert()`][IndexMap::insert]. /// /// # Examples /// @@ -1411,7 +1304,7 @@ where /// iterable. /// /// `from_iter` uses the same logic as `extend`. See - /// [`extend`](#method.extend) for more details. + /// [`extend`][IndexMap::extend] for more details. fn from_iter>(iterable: I) -> Self { let iter = iterable.into_iter(); let (low, _) = iter.size_hint(); @@ -1421,7 +1314,8 @@ where } } -#[cfg(has_std)] +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl From<[(K, V); N]> for IndexMap where K: Hash + Eq, @@ -1447,7 +1341,7 @@ where { /// Extend the map with all key-value pairs in the iterable. /// - /// This is equivalent to calling [`insert`](#method.insert) for each of + /// This is equivalent to calling [`insert`][IndexMap::insert] for each of /// them in order, which means that for keys that already existed /// in the map, their value is updated but it keeps the existing order. /// @@ -1491,7 +1385,7 @@ impl Default for IndexMap where S: Default, { - /// Return an empty `IndexMap` + /// Return an empty [`IndexMap`] fn default() -> Self { Self::with_capacity_and_hasher(0, S::default()) } @@ -1521,427 +1415,3 @@ where S: BuildHasher, { } - -#[cfg(test)] -mod tests { - use super::*; - use std::string::String; - - #[test] - fn it_works() { - let mut map = IndexMap::new(); - assert_eq!(map.is_empty(), true); - map.insert(1, ()); - map.insert(1, ()); - assert_eq!(map.len(), 1); - assert!(map.get(&1).is_some()); - assert_eq!(map.is_empty(), false); - } - - #[test] - fn new() { - let map = IndexMap::::new(); - println!("{:?}", map); - assert_eq!(map.capacity(), 0); - assert_eq!(map.len(), 0); - assert_eq!(map.is_empty(), true); - } - - #[test] - fn insert() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5]; - let not_present = [1, 3, 6, 9, 10]; - let mut map = IndexMap::with_capacity(insert.len()); - - for (i, &elt) in insert.iter().enumerate() { - assert_eq!(map.len(), i); - map.insert(elt, elt); - assert_eq!(map.len(), i + 1); - assert_eq!(map.get(&elt), Some(&elt)); - assert_eq!(map[&elt], elt); - } - println!("{:?}", map); - - for &elt in ¬_present { - assert!(map.get(&elt).is_none()); - } - } - - #[test] - fn insert_full() { - let insert = vec![9, 2, 7, 1, 4, 6, 13]; - let present = vec![1, 6, 2]; - let mut map = IndexMap::with_capacity(insert.len()); - - for (i, &elt) in insert.iter().enumerate() { - assert_eq!(map.len(), i); - let (index, existing) = map.insert_full(elt, elt); - assert_eq!(existing, None); - assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); - assert_eq!(map.len(), i + 1); - } - - let len = map.len(); - for &elt in &present { - let (index, existing) = map.insert_full(elt, elt); - assert_eq!(existing, Some(elt)); - assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); - assert_eq!(map.len(), len); - } - } - - #[test] - fn insert_2() { - let mut map = IndexMap::with_capacity(16); - - let mut keys = vec![]; - keys.extend(0..16); - keys.extend(if cfg!(miri) { 32..64 } else { 128..267 }); - - for &i in &keys { - let old_map = map.clone(); - map.insert(i, ()); - for key in old_map.keys() { - if map.get(key).is_none() { - println!("old_map: {:?}", old_map); - println!("map: {:?}", map); - panic!("did not find {} in map", key); - } - } - } - - for &i in &keys { - assert!(map.get(&i).is_some(), "did not find {}", i); - } - } - - #[test] - fn insert_order() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; - let mut map = IndexMap::new(); - - for &elt in &insert { - map.insert(elt, ()); - } - - assert_eq!(map.keys().count(), map.len()); - assert_eq!(map.keys().count(), insert.len()); - for (a, b) in insert.iter().zip(map.keys()) { - assert_eq!(a, b); - } - for (i, k) in (0..insert.len()).zip(map.keys()) { - assert_eq!(map.get_index(i).unwrap().0, k); - } - } - - #[test] - fn grow() { - let insert = [0, 4, 2, 12, 8, 7, 11]; - let not_present = [1, 3, 6, 9, 10]; - let mut map = IndexMap::with_capacity(insert.len()); - - for (i, &elt) in insert.iter().enumerate() { - assert_eq!(map.len(), i); - map.insert(elt, elt); - assert_eq!(map.len(), i + 1); - assert_eq!(map.get(&elt), Some(&elt)); - assert_eq!(map[&elt], elt); - } - - println!("{:?}", map); - for &elt in &insert { - map.insert(elt * 10, elt); - } - for &elt in &insert { - map.insert(elt * 100, elt); - } - for (i, &elt) in insert.iter().cycle().enumerate().take(100) { - map.insert(elt * 100 + i as i32, elt); - } - println!("{:?}", map); - for &elt in ¬_present { - assert!(map.get(&elt).is_none()); - } - } - - #[test] - fn reserve() { - let mut map = IndexMap::::new(); - assert_eq!(map.capacity(), 0); - map.reserve(100); - let capacity = map.capacity(); - assert!(capacity >= 100); - for i in 0..capacity { - assert_eq!(map.len(), i); - map.insert(i, i * i); - assert_eq!(map.len(), i + 1); - assert_eq!(map.capacity(), capacity); - assert_eq!(map.get(&i), Some(&(i * i))); - } - map.insert(capacity, std::usize::MAX); - assert_eq!(map.len(), capacity + 1); - assert!(map.capacity() > capacity); - assert_eq!(map.get(&capacity), Some(&std::usize::MAX)); - } - - #[test] - fn shrink_to_fit() { - let mut map = IndexMap::::new(); - assert_eq!(map.capacity(), 0); - for i in 0..100 { - assert_eq!(map.len(), i); - map.insert(i, i * i); - assert_eq!(map.len(), i + 1); - assert!(map.capacity() >= i + 1); - assert_eq!(map.get(&i), Some(&(i * i))); - map.shrink_to_fit(); - assert_eq!(map.len(), i + 1); - assert_eq!(map.capacity(), i + 1); - assert_eq!(map.get(&i), Some(&(i * i))); - } - } - - #[test] - fn remove() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; - let mut map = IndexMap::new(); - - for &elt in &insert { - map.insert(elt, elt); - } - - assert_eq!(map.keys().count(), map.len()); - assert_eq!(map.keys().count(), insert.len()); - for (a, b) in insert.iter().zip(map.keys()) { - assert_eq!(a, b); - } - - let remove_fail = [99, 77]; - let remove = [4, 12, 8, 7]; - - for &key in &remove_fail { - assert!(map.swap_remove_full(&key).is_none()); - } - println!("{:?}", map); - for &key in &remove { - //println!("{:?}", map); - let index = map.get_full(&key).unwrap().0; - assert_eq!(map.swap_remove_full(&key), Some((index, key, key))); - } - println!("{:?}", map); - - for key in &insert { - assert_eq!(map.get(key).is_some(), !remove.contains(key)); - } - assert_eq!(map.len(), insert.len() - remove.len()); - assert_eq!(map.keys().count(), insert.len() - remove.len()); - } - - #[test] - fn remove_to_empty() { - let mut map = indexmap! { 0 => 0, 4 => 4, 5 => 5 }; - map.swap_remove(&5).unwrap(); - map.swap_remove(&4).unwrap(); - map.swap_remove(&0).unwrap(); - assert!(map.is_empty()); - } - - #[test] - fn swap_remove_index() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; - let mut map = IndexMap::new(); - - for &elt in &insert { - map.insert(elt, elt * 2); - } - - let mut vector = insert.to_vec(); - let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; - - // check that the same swap remove sequence on vec and map - // have the same result. - for &rm in remove_sequence { - let out_vec = vector.swap_remove(rm); - let (out_map, _) = map.swap_remove_index(rm).unwrap(); - assert_eq!(out_vec, out_map); - } - assert_eq!(vector.len(), map.len()); - for (a, b) in vector.iter().zip(map.keys()) { - assert_eq!(a, b); - } - } - - #[test] - fn partial_eq_and_eq() { - let mut map_a = IndexMap::new(); - map_a.insert(1, "1"); - map_a.insert(2, "2"); - let mut map_b = map_a.clone(); - assert_eq!(map_a, map_b); - map_b.swap_remove(&1); - assert_ne!(map_a, map_b); - - let map_c: IndexMap<_, String> = map_b.into_iter().map(|(k, v)| (k, v.into())).collect(); - assert_ne!(map_a, map_c); - assert_ne!(map_c, map_a); - } - - #[test] - fn extend() { - let mut map = IndexMap::new(); - map.extend(vec![(&1, &2), (&3, &4)]); - map.extend(vec![(5, 6)]); - assert_eq!( - map.into_iter().collect::>(), - vec![(1, 2), (3, 4), (5, 6)] - ); - } - - #[test] - fn entry() { - let mut map = IndexMap::new(); - - map.insert(1, "1"); - map.insert(2, "2"); - { - let e = map.entry(3); - assert_eq!(e.index(), 2); - let e = e.or_insert("3"); - assert_eq!(e, &"3"); - } - - let e = map.entry(2); - assert_eq!(e.index(), 1); - assert_eq!(e.key(), &2); - match e { - Entry::Occupied(ref e) => assert_eq!(e.get(), &"2"), - Entry::Vacant(_) => panic!(), - } - assert_eq!(e.or_insert("4"), &"2"); - } - - #[test] - fn entry_and_modify() { - let mut map = IndexMap::new(); - - map.insert(1, "1"); - map.entry(1).and_modify(|x| *x = "2"); - assert_eq!(Some(&"2"), map.get(&1)); - - map.entry(2).and_modify(|x| *x = "doesn't exist"); - assert_eq!(None, map.get(&2)); - } - - #[test] - fn entry_or_default() { - let mut map = IndexMap::new(); - - #[derive(Debug, PartialEq)] - enum TestEnum { - DefaultValue, - NonDefaultValue, - } - - impl Default for TestEnum { - fn default() -> Self { - TestEnum::DefaultValue - } - } - - map.insert(1, TestEnum::NonDefaultValue); - assert_eq!(&mut TestEnum::NonDefaultValue, map.entry(1).or_default()); - - assert_eq!(&mut TestEnum::DefaultValue, map.entry(2).or_default()); - } - - #[test] - fn occupied_entry_key() { - // These keys match hash and equality, but their addresses are distinct. - let (k1, k2) = (&mut 1, &mut 1); - let k1_ptr = k1 as *const i32; - let k2_ptr = k2 as *const i32; - assert_ne!(k1_ptr, k2_ptr); - - let mut map = IndexMap::new(); - map.insert(k1, "value"); - match map.entry(k2) { - Entry::Occupied(ref e) => { - // `OccupiedEntry::key` should reference the key in the map, - // not the key that was used to find the entry. - let ptr = *e.key() as *const i32; - assert_eq!(ptr, k1_ptr); - assert_ne!(ptr, k2_ptr); - } - Entry::Vacant(_) => panic!(), - } - } - - #[test] - fn keys() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: IndexMap<_, _> = vec.into_iter().collect(); - let keys: Vec<_> = map.keys().copied().collect(); - assert_eq!(keys.len(), 3); - assert!(keys.contains(&1)); - assert!(keys.contains(&2)); - assert!(keys.contains(&3)); - } - - #[test] - fn into_keys() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: IndexMap<_, _> = vec.into_iter().collect(); - let keys: Vec = map.into_keys().collect(); - assert_eq!(keys.len(), 3); - assert!(keys.contains(&1)); - assert!(keys.contains(&2)); - assert!(keys.contains(&3)); - } - - #[test] - fn values() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: IndexMap<_, _> = vec.into_iter().collect(); - let values: Vec<_> = map.values().copied().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&'a')); - assert!(values.contains(&'b')); - assert!(values.contains(&'c')); - } - - #[test] - fn values_mut() { - let vec = vec![(1, 1), (2, 2), (3, 3)]; - let mut map: IndexMap<_, _> = vec.into_iter().collect(); - for value in map.values_mut() { - *value *= 2 - } - let values: Vec<_> = map.values().copied().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&2)); - assert!(values.contains(&4)); - assert!(values.contains(&6)); - } - - #[test] - fn into_values() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: IndexMap<_, _> = vec.into_iter().collect(); - let values: Vec = map.into_values().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&'a')); - assert!(values.contains(&'b')); - assert!(values.contains(&'c')); - } - - #[test] - #[cfg(has_std)] - fn from_array() { - let map = IndexMap::from([(1, 2), (3, 4)]); - let mut expected = IndexMap::new(); - expected.insert(1, 2); - expected.insert(3, 4); - - assert_eq!(map, expected) - } -} diff --git a/third_party/rust/indexmap/src/map/core.rs b/third_party/rust/indexmap/src/map/core.rs index ea7aaae62e..16e87c7c6a 100644 --- a/third_party/rust/indexmap/src/map/core.rs +++ b/third_party/rust/indexmap/src/map/core.rs @@ -7,19 +7,22 @@ //! //! However, we should probably not let this show in the public API or docs. +mod entry; mod raw; +pub mod raw_entry_v1; + use hashbrown::raw::RawTable; -use crate::vec::{Drain, Vec}; -use core::cmp; -use core::fmt; -use core::mem::replace; +use crate::vec::{self, Vec}; +use crate::TryReserveError; +use core::mem; use core::ops::RangeBounds; -use crate::equivalent::Equivalent; use crate::util::simplify_range; -use crate::{Bucket, Entries, HashValue}; +use crate::{Bucket, Entries, Equivalent, HashValue}; + +pub use entry::{Entry, IndexedEntry, OccupiedEntry, VacantEntry}; /// Core of the map that does not depend on S pub(crate) struct IndexMapCore { @@ -62,29 +65,30 @@ where V: Clone, { fn clone(&self) -> Self { - let indices = self.indices.clone(); - let mut entries = Vec::with_capacity(indices.capacity()); - entries.clone_from(&self.entries); - IndexMapCore { indices, entries } + let mut new = Self::new(); + new.clone_from(self); + new } fn clone_from(&mut self, other: &Self) { let hasher = get_hash(&other.entries); self.indices.clone_from_with_hasher(&other.indices, hasher); if self.entries.capacity() < other.entries.len() { - // If we must resize, match the indices capacity - self.reserve_entries(); + // If we must resize, match the indices capacity. + let additional = other.entries.len() - self.entries.len(); + self.reserve_entries(additional); } self.entries.clone_from(&other.entries); } } -impl fmt::Debug for IndexMapCore +#[cfg(feature = "test_debug")] +impl core::fmt::Debug for IndexMapCore where - K: fmt::Debug, - V: fmt::Debug, + K: core::fmt::Debug, + V: core::fmt::Debug, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("IndexMapCore") .field("indices", &raw::DebugIndices(&self.indices)) .field("entries", &self.entries) @@ -120,6 +124,9 @@ impl Entries for IndexMapCore { } impl IndexMapCore { + /// The maximum capacity before the `entries` allocation would exceed `isize::MAX`. + const MAX_ENTRIES_CAPACITY: usize = (isize::MAX as usize) / mem::size_of::>(); + #[inline] pub(crate) const fn new() -> Self { IndexMapCore { @@ -143,7 +150,7 @@ impl IndexMapCore { #[inline] pub(crate) fn capacity(&self) -> usize { - cmp::min(self.indices.capacity(), self.entries.capacity()) + Ord::min(self.indices.capacity(), self.entries.capacity()) } pub(crate) fn clear(&mut self) { @@ -158,7 +165,7 @@ impl IndexMapCore { } } - pub(crate) fn drain(&mut self, range: R) -> Drain<'_, Bucket> + pub(crate) fn drain(&mut self, range: R) -> vec::Drain<'_, Bucket> where R: RangeBounds, { @@ -190,18 +197,92 @@ impl IndexMapCore { Self { indices, entries } } + pub(crate) fn split_splice(&mut self, range: R) -> (Self, vec::IntoIter>) + where + R: RangeBounds, + { + let range = simplify_range(range, self.len()); + self.erase_indices(range.start, self.entries.len()); + let entries = self.entries.split_off(range.end); + let drained = self.entries.split_off(range.start); + + let mut indices = RawTable::with_capacity(entries.len()); + raw::insert_bulk_no_grow(&mut indices, &entries); + (Self { indices, entries }, drained.into_iter()) + } + + /// Append from another map without checking whether items already exist. + pub(crate) fn append_unchecked(&mut self, other: &mut Self) { + self.reserve(other.len()); + raw::insert_bulk_no_grow(&mut self.indices, &other.entries); + self.entries.append(&mut other.entries); + other.indices.clear(); + } + /// Reserve capacity for `additional` more key-value pairs. pub(crate) fn reserve(&mut self, additional: usize) { self.indices.reserve(additional, get_hash(&self.entries)); - self.reserve_entries(); + // Only grow entries if necessary, since we also round up capacity. + if additional > self.entries.capacity() - self.entries.len() { + self.reserve_entries(additional); + } + } + + /// Reserve entries capacity, rounded up to match the indices + fn reserve_entries(&mut self, additional: usize) { + // Use a soft-limit on the maximum capacity, but if the caller explicitly + // requested more, do it and let them have the resulting panic. + let new_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY); + let try_add = new_capacity - self.entries.len(); + if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() { + return; + } + self.entries.reserve_exact(additional); } - /// Reserve entries capacity to match the indices - fn reserve_entries(&mut self) { - let additional = self.indices.capacity() - self.entries.len(); + /// Reserve capacity for `additional` more key-value pairs, without over-allocating. + pub(crate) fn reserve_exact(&mut self, additional: usize) { + self.indices.reserve(additional, get_hash(&self.entries)); self.entries.reserve_exact(additional); } + /// Try to reserve capacity for `additional` more key-value pairs. + pub(crate) fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.indices + .try_reserve(additional, get_hash(&self.entries)) + .map_err(TryReserveError::from_hashbrown)?; + // Only grow entries if necessary, since we also round up capacity. + if additional > self.entries.capacity() - self.entries.len() { + self.try_reserve_entries(additional) + } else { + Ok(()) + } + } + + /// Try to reserve entries capacity, rounded up to match the indices + fn try_reserve_entries(&mut self, additional: usize) -> Result<(), TryReserveError> { + // Use a soft-limit on the maximum capacity, but if the caller explicitly + // requested more, do it and let them have the resulting error. + let new_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY); + let try_add = new_capacity - self.entries.len(); + if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() { + return Ok(()); + } + self.entries + .try_reserve_exact(additional) + .map_err(TryReserveError::from_alloc) + } + + /// Try to reserve capacity for `additional` more key-value pairs, without over-allocating. + pub(crate) fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.indices + .try_reserve(additional, get_hash(&self.entries)) + .map_err(TryReserveError::from_hashbrown)?; + self.entries + .try_reserve_exact(additional) + .map_err(TryReserveError::from_alloc) + } + /// Shrink the capacity of the map with a lower bound pub(crate) fn shrink_to(&mut self, min_capacity: usize) { self.indices @@ -220,18 +301,25 @@ impl IndexMapCore { } } - /// Append a key-value pair, *without* checking whether it already exists, - /// and return the pair's new index. - fn push(&mut self, hash: HashValue, key: K, value: V) -> usize { - let i = self.entries.len(); - self.indices.insert(hash.get(), i, get_hash(&self.entries)); - if i == self.entries.capacity() { + /// Append a key-value pair to `entries`, *without* checking whether it already exists. + fn push_entry(&mut self, hash: HashValue, key: K, value: V) { + if self.entries.len() == self.entries.capacity() { // Reserve our own capacity synced to the indices, // rather than letting `Vec::push` just double it. - self.reserve_entries(); + self.reserve_entries(1); } self.entries.push(Bucket { hash, key, value }); - i + } + + /// Insert a key-value pair in `entries` at a particular index, + /// *without* checking whether it already exists. + fn insert_entry(&mut self, index: usize, hash: HashValue, key: K, value: V) { + if self.entries.len() == self.entries.capacity() { + // Reserve our own capacity synced to the indices, + // rather than letting `Vec::insert` just double it. + self.reserve_entries(1); + } + self.entries.insert(index, Bucket { hash, key, value }); } /// Return the index in `entries` where an equivalent key can be found @@ -247,12 +335,66 @@ impl IndexMapCore { where K: Eq, { - match self.get_index_of(hash, &key) { - Some(i) => (i, Some(replace(&mut self.entries[i].value, value))), - None => (self.push(hash, key, value), None), + match self.find_or_insert(hash, &key) { + Ok(i) => (i, Some(mem::replace(&mut self.entries[i].value, value))), + Err(i) => { + debug_assert_eq!(i, self.entries.len()); + self.push_entry(hash, key, value); + (i, None) + } + } + } + + /// Same as `insert_full`, except it also replaces the key + pub(crate) fn replace_full( + &mut self, + hash: HashValue, + key: K, + value: V, + ) -> (usize, Option<(K, V)>) + where + K: Eq, + { + match self.find_or_insert(hash, &key) { + Ok(i) => { + let entry = &mut self.entries[i]; + let kv = ( + mem::replace(&mut entry.key, key), + mem::replace(&mut entry.value, value), + ); + (i, Some(kv)) + } + Err(i) => { + debug_assert_eq!(i, self.entries.len()); + self.push_entry(hash, key, value); + (i, None) + } } } + fn insert_unique(&mut self, hash: HashValue, key: K, value: V) -> usize { + let i = self.indices.len(); + self.indices.insert(hash.get(), i, get_hash(&self.entries)); + debug_assert_eq!(i, self.entries.len()); + self.push_entry(hash, key, value); + i + } + + fn shift_insert_unique(&mut self, index: usize, hash: HashValue, key: K, value: V) { + let end = self.indices.len(); + assert!(index <= end); + // Increment others first so we don't have duplicate indices. + self.increment_indices(index, end); + let entries = &*self.entries; + self.indices.insert(hash.get(), index, move |&i| { + // Adjust for the incremented indices to find hashes. + debug_assert_ne!(i, index); + let i = if i < index { i } else { i - 1 }; + entries[i].hash.get() + }); + self.insert_entry(index, hash, key, value); + } + /// Remove an entry by shifting all entries that follow it pub(crate) fn shift_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> where @@ -339,7 +481,7 @@ impl IndexMapCore { pub(super) fn move_index(&mut self, from: usize, to: usize) { let from_hash = self.entries[from].hash; if from != to { - // Use a sentinal index so other indices don't collide. + // Use a sentinel index so other indices don't collide. update_index(&mut self.indices, from_hash, from, usize::MAX); // Update all other indices and rotate the entry positions. @@ -351,11 +493,31 @@ impl IndexMapCore { self.entries[to..=from].rotate_right(1); } - // Change the sentinal index to its final position. + // Change the sentinel index to its final position. update_index(&mut self.indices, from_hash, usize::MAX, to); } } + pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { + // If they're equal and in-bounds, there's nothing to do. + if a == b && a < self.entries.len() { + return; + } + + // We'll get a "nice" bounds-check from indexing `self.entries`, + // and then we expect to find it in the table as well. + let [ref_a, ref_b] = self + .indices + .get_many_mut( + [self.entries[a].hash.get(), self.entries[b].hash.get()], + move |i, &x| if i == 0 { x == a } else { x == b }, + ) + .expect("indices not found"); + + mem::swap(ref_a, ref_b); + self.entries.swap(a, b); + } + /// Remove an entry by swapping it with the last pub(crate) fn swap_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> where @@ -447,25 +609,9 @@ impl IndexMapCore { where F: FnMut(&mut K, &mut V) -> bool, { - // FIXME: This could use Vec::retain_mut with MSRV 1.61. - // Like Vec::retain in self.entries, but with mutable K and V. - // We swap-shift all the items we want to keep, truncate the rest, - // then rebuild the raw hash table with the new indexes. - let len = self.entries.len(); - let mut n_deleted = 0; - for i in 0..len { - let will_keep = { - let entry = &mut self.entries[i]; - keep(&mut entry.key, &mut entry.value) - }; - if !will_keep { - n_deleted += 1; - } else if n_deleted > 0 { - self.entries.swap(i - n_deleted, i); - } - } - if n_deleted > 0 { - self.entries.truncate(len - n_deleted); + self.entries + .retain_mut(|entry| keep(&mut entry.key, &mut entry.value)); + if self.entries.len() < self.indices.len() { self.rebuild_hash_table(); } } @@ -487,214 +633,10 @@ impl IndexMapCore { } } -/// Entry for an existing key-value pair or a vacant location to -/// insert one. -pub enum Entry<'a, K, V> { - /// Existing slot with equivalent key. - Occupied(OccupiedEntry<'a, K, V>), - /// Vacant slot (no equivalent key in the map). - Vacant(VacantEntry<'a, K, V>), -} - -impl<'a, K, V> Entry<'a, K, V> { - /// Inserts the given default value in the entry if it is vacant and returns a mutable - /// reference to it. Otherwise a mutable reference to an already existent value is returned. - /// - /// Computes in **O(1)** time (amortized average). - pub fn or_insert(self, default: V) -> &'a mut V { - match self { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => entry.insert(default), - } - } - - /// Inserts the result of the `call` function in the entry if it is vacant and returns a mutable - /// reference to it. Otherwise a mutable reference to an already existent value is returned. - /// - /// Computes in **O(1)** time (amortized average). - pub fn or_insert_with(self, call: F) -> &'a mut V - where - F: FnOnce() -> V, - { - match self { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => entry.insert(call()), - } - } - - /// Inserts the result of the `call` function with a reference to the entry's key if it is - /// vacant, and returns a mutable reference to the new value. Otherwise a mutable reference to - /// an already existent value is returned. - /// - /// Computes in **O(1)** time (amortized average). - pub fn or_insert_with_key(self, call: F) -> &'a mut V - where - F: FnOnce(&K) -> V, - { - match self { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => { - let value = call(&entry.key); - entry.insert(value) - } - } - } - - /// Gets a reference to the entry's key, either within the map if occupied, - /// or else the new key that was used to find the entry. - pub fn key(&self) -> &K { - match *self { - Entry::Occupied(ref entry) => entry.key(), - Entry::Vacant(ref entry) => entry.key(), - } - } - - /// Return the index where the key-value pair exists or will be inserted. - pub fn index(&self) -> usize { - match *self { - Entry::Occupied(ref entry) => entry.index(), - Entry::Vacant(ref entry) => entry.index(), - } - } - - /// Modifies the entry if it is occupied. - pub fn and_modify(self, f: F) -> Self - where - F: FnOnce(&mut V), - { - match self { - Entry::Occupied(mut o) => { - f(o.get_mut()); - Entry::Occupied(o) - } - x => x, - } - } - - /// Inserts a default-constructed value in the entry if it is vacant and returns a mutable - /// reference to it. Otherwise a mutable reference to an already existent value is returned. - /// - /// Computes in **O(1)** time (amortized average). - pub fn or_default(self) -> &'a mut V - where - V: Default, - { - match self { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => entry.insert(V::default()), - } - } -} - -impl fmt::Debug for Entry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Entry::Vacant(ref v) => f.debug_tuple(stringify!(Entry)).field(v).finish(), - Entry::Occupied(ref o) => f.debug_tuple(stringify!(Entry)).field(o).finish(), - } - } -} - -pub use self::raw::OccupiedEntry; - -// Extra methods that don't threaten the unsafe encapsulation. -impl OccupiedEntry<'_, K, V> { - /// Sets the value of the entry to `value`, and returns the entry's old value. - pub fn insert(&mut self, value: V) -> V { - replace(self.get_mut(), value) - } - - /// Remove the key, value pair stored in the map for this entry, and return the value. - /// - /// **NOTE:** This is equivalent to `.swap_remove()`. - pub fn remove(self) -> V { - self.swap_remove() - } - - /// Remove the key, value pair stored in the map for this entry, and return the value. - /// - /// Like `Vec::swap_remove`, the pair is removed by swapping it with the - /// last element of the map and popping it off. **This perturbs - /// the position of what used to be the last element!** - /// - /// Computes in **O(1)** time (average). - pub fn swap_remove(self) -> V { - self.swap_remove_entry().1 - } - - /// Remove the key, value pair stored in the map for this entry, and return the value. - /// - /// Like `Vec::remove`, the pair is removed by shifting all of the - /// elements that follow it, preserving their relative order. - /// **This perturbs the index of all of those elements!** - /// - /// Computes in **O(n)** time (average). - pub fn shift_remove(self) -> V { - self.shift_remove_entry().1 - } - - /// Remove and return the key, value pair stored in the map for this entry - /// - /// **NOTE:** This is equivalent to `.swap_remove_entry()`. - pub fn remove_entry(self) -> (K, V) { - self.swap_remove_entry() - } -} - -impl fmt::Debug for OccupiedEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct(stringify!(OccupiedEntry)) - .field("key", self.key()) - .field("value", self.get()) - .finish() - } -} - -/// A view into a vacant entry in a `IndexMap`. -/// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html -pub struct VacantEntry<'a, K, V> { - map: &'a mut IndexMapCore, - hash: HashValue, - key: K, -} - -impl<'a, K, V> VacantEntry<'a, K, V> { - /// Gets a reference to the key that was used to find the entry. - pub fn key(&self) -> &K { - &self.key - } - - /// Takes ownership of the key, leaving the entry vacant. - pub fn into_key(self) -> K { - self.key - } - - /// Return the index where the key-value pair will be inserted. - pub fn index(&self) -> usize { - self.map.len() - } - - /// Inserts the entry's key and the given value into the map, and returns a mutable reference - /// to the value. - pub fn insert(self, value: V) -> &'a mut V { - let i = self.map.push(self.hash, self.key, value); - &mut self.map.entries[i].value - } -} - -impl fmt::Debug for VacantEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple(stringify!(VacantEntry)) - .field(self.key()) - .finish() - } -} - #[test] fn assert_send_sync() { fn assert_send_sync() {} assert_send_sync::>(); assert_send_sync::>(); + assert_send_sync::>(); } diff --git a/third_party/rust/indexmap/src/map/core/entry.rs b/third_party/rust/indexmap/src/map/core/entry.rs new file mode 100644 index 0000000000..6c31070788 --- /dev/null +++ b/third_party/rust/indexmap/src/map/core/entry.rs @@ -0,0 +1,481 @@ +use super::raw::RawTableEntry; +use super::IndexMapCore; +use crate::HashValue; +use core::{fmt, mem}; + +impl IndexMapCore { + pub(crate) fn entry(&mut self, hash: HashValue, key: K) -> Entry<'_, K, V> + where + K: Eq, + { + match self.raw_entry(hash, |k| *k == key) { + Ok(raw) => Entry::Occupied(OccupiedEntry { raw }), + Err(map) => Entry::Vacant(VacantEntry { map, hash, key }), + } + } +} + +/// Entry for an existing key-value pair in an [`IndexMap`][crate::IndexMap] +/// or a vacant location to insert one. +pub enum Entry<'a, K, V> { + /// Existing slot with equivalent key. + Occupied(OccupiedEntry<'a, K, V>), + /// Vacant slot (no equivalent key in the map). + Vacant(VacantEntry<'a, K, V>), +} + +impl<'a, K, V> Entry<'a, K, V> { + /// Return the index where the key-value pair exists or will be inserted. + pub fn index(&self) -> usize { + match *self { + Entry::Occupied(ref entry) => entry.index(), + Entry::Vacant(ref entry) => entry.index(), + } + } + + /// Inserts the given default value in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Inserts the result of the `call` function in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert_with(self, call: F) -> &'a mut V + where + F: FnOnce() -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(call()), + } + } + + /// Inserts the result of the `call` function with a reference to the entry's key if it is + /// vacant, and returns a mutable reference to the new value. Otherwise a mutable reference to + /// an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert_with_key(self, call: F) -> &'a mut V + where + F: FnOnce(&K) -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = call(&entry.key); + entry.insert(value) + } + } + } + + /// Gets a reference to the entry's key, either within the map if occupied, + /// or else the new key that was used to find the entry. + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Modifies the entry if it is occupied. + pub fn and_modify(mut self, f: F) -> Self + where + F: FnOnce(&mut V), + { + if let Entry::Occupied(entry) = &mut self { + f(entry.get_mut()); + } + self + } + + /// Inserts a default-constructed value in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_default(self) -> &'a mut V + where + V: Default, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(V::default()), + } + } +} + +impl fmt::Debug for Entry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut tuple = f.debug_tuple("Entry"); + match self { + Entry::Vacant(v) => tuple.field(v), + Entry::Occupied(o) => tuple.field(o), + }; + tuple.finish() + } +} + +/// A view into an occupied entry in an [`IndexMap`][crate::IndexMap]. +/// It is part of the [`Entry`] enum. +pub struct OccupiedEntry<'a, K, V> { + raw: RawTableEntry<'a, K, V>, +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + /// Return the index of the key-value pair + #[inline] + pub fn index(&self) -> usize { + self.raw.index() + } + + /// Gets a reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn key(&self) -> &K { + &self.raw.bucket().key + } + + /// Gets a reference to the entry's value in the map. + pub fn get(&self) -> &V { + &self.raw.bucket().value + } + + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// [`Entry`] value, see [`into_mut`][Self::into_mut]. + pub fn get_mut(&mut self) -> &mut V { + &mut self.raw.bucket_mut().value + } + + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut V { + &mut self.raw.into_bucket().value + } + + /// Sets the value of the entry to `value`, and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// **NOTE:** This is equivalent to [`.swap_remove()`][Self::swap_remove], replacing this + /// entry's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the keys in the map, use + /// [`.shift_remove()`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the map order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(self) -> V { + self.swap_remove() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with + /// the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(self) -> V { + self.swap_remove_entry().1 + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(self) -> V { + self.shift_remove_entry().1 + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// **NOTE:** This is equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry], + /// replacing this entry's position with the last element, and it is deprecated in favor of + /// calling that explicitly. If you need to preserve the relative order of the keys in the map, + /// use [`.shift_remove_entry()`][Self::shift_remove_entry] instead. + #[deprecated(note = "`remove_entry` disrupts the map order -- \ + use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")] + pub fn remove_entry(self) -> (K, V) { + self.swap_remove_entry() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with + /// the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(self) -> (K, V) { + let (map, index) = self.raw.remove_index(); + map.swap_remove_finish(index) + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(self) -> (K, V) { + let (map, index) = self.raw.remove_index(); + map.shift_remove_finish(index) + } + + /// Moves the position of the entry to a new index + /// by shifting all other entries in-between. + /// + /// This is equivalent to [`IndexMap::move_index`][`crate::IndexMap::move_index`] + /// coming `from` the current [`.index()`][Self::index]. + /// + /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. + /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. + /// + /// ***Panics*** if `to` is out of bounds. + /// + /// Computes in **O(n)** time (average). + pub fn move_index(self, to: usize) { + let (map, index) = self.raw.into_inner(); + map.move_index(index, to); + } + + /// Swaps the position of entry with another. + /// + /// This is equivalent to [`IndexMap::swap_indices`][`crate::IndexMap::swap_indices`] + /// with the current [`.index()`][Self::index] as one of the two being swapped. + /// + /// ***Panics*** if the `other` index is out of bounds. + /// + /// Computes in **O(1)** time (average). + pub fn swap_indices(self, other: usize) { + let (map, index) = self.raw.into_inner(); + map.swap_indices(index, other) + } +} + +impl fmt::Debug for OccupiedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in an [`IndexMap`][crate::IndexMap]. +/// It is part of the [`Entry`] enum. +pub struct VacantEntry<'a, K, V> { + map: &'a mut IndexMapCore, + hash: HashValue, + key: K, +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + /// Return the index where a key-value pair may be inserted. + pub fn index(&self) -> usize { + self.map.indices.len() + } + + /// Gets a reference to the key that was used to find the entry. + pub fn key(&self) -> &K { + &self.key + } + + /// Takes ownership of the key, leaving the entry vacant. + pub fn into_key(self) -> K { + self.key + } + + /// Inserts the entry's key and the given value into the map, and returns a mutable reference + /// to the value. + pub fn insert(self, value: V) -> &'a mut V { + let Self { map, hash, key } = self; + let i = map.insert_unique(hash, key, value); + &mut map.entries[i].value + } + + /// Inserts the entry's key and the given value into the map at its ordered + /// position among sorted keys, and returns the new index and a mutable + /// reference to the value. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted(self, value: V) -> (usize, &'a mut V) + where + K: Ord, + { + let slice = crate::map::Slice::from_slice(&self.map.entries); + let i = slice.binary_search_keys(&self.key).unwrap_err(); + (i, self.shift_insert(i, value)) + } + + /// Inserts the entry's key and the given value into the map at the given index, + /// shifting others to the right, and returns a mutable reference to the value. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + pub fn shift_insert(self, index: usize, value: V) -> &'a mut V { + let Self { map, hash, key } = self; + map.shift_insert_unique(index, hash, key, value); + &mut map.entries[index].value + } +} + +impl fmt::Debug for VacantEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into an occupied entry in an [`IndexMap`][crate::IndexMap] obtained by index. +/// +/// This `struct` is created from the [`get_index_entry`][crate::IndexMap::get_index_entry] method. +pub struct IndexedEntry<'a, K, V> { + map: &'a mut IndexMapCore, + // We have a mutable reference to the map, which keeps the index + // valid and pointing to the correct entry. + index: usize, +} + +impl<'a, K, V> IndexedEntry<'a, K, V> { + pub(crate) fn new(map: &'a mut IndexMapCore, index: usize) -> Self { + Self { map, index } + } + + /// Return the index of the key-value pair + #[inline] + pub fn index(&self) -> usize { + self.index + } + + /// Gets a reference to the entry's key in the map. + pub fn key(&self) -> &K { + &self.map.entries[self.index].key + } + + /// Gets a reference to the entry's value in the map. + pub fn get(&self) -> &V { + &self.map.entries[self.index].value + } + + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// `IndexedEntry` value, see [`into_mut`][Self::into_mut]. + pub fn get_mut(&mut self) -> &mut V { + &mut self.map.entries[self.index].value + } + + /// Sets the value of the entry to `value`, and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut V { + &mut self.map.entries[self.index].value + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with + /// the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(self) -> (K, V) { + self.map.swap_remove_index(self.index).unwrap() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(self) -> (K, V) { + self.map.shift_remove_index(self.index).unwrap() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with + /// the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(self) -> V { + self.swap_remove_entry().1 + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(self) -> V { + self.shift_remove_entry().1 + } + + /// Moves the position of the entry to a new index + /// by shifting all other entries in-between. + /// + /// This is equivalent to [`IndexMap::move_index`][`crate::IndexMap::move_index`] + /// coming `from` the current [`.index()`][Self::index]. + /// + /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. + /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. + /// + /// ***Panics*** if `to` is out of bounds. + /// + /// Computes in **O(n)** time (average). + pub fn move_index(self, to: usize) { + self.map.move_index(self.index, to); + } + + /// Swaps the position of entry with another. + /// + /// This is equivalent to [`IndexMap::swap_indices`][`crate::IndexMap::swap_indices`] + /// with the current [`.index()`][Self::index] as one of the two being swapped. + /// + /// ***Panics*** if the `other` index is out of bounds. + /// + /// Computes in **O(1)** time (average). + pub fn swap_indices(self, other: usize) { + self.map.swap_indices(self.index, other) + } +} + +impl fmt::Debug for IndexedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IndexedEntry") + .field("index", &self.index) + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} diff --git a/third_party/rust/indexmap/src/map/core/raw.rs b/third_party/rust/indexmap/src/map/core/raw.rs index bf1672d52a..451994339a 100644 --- a/third_party/rust/indexmap/src/map/core/raw.rs +++ b/third_party/rust/indexmap/src/map/core/raw.rs @@ -2,9 +2,7 @@ //! This module encapsulates the `unsafe` access to `hashbrown::raw::RawTable`, //! mostly in dealing with its bucket "pointers". -use super::{equivalent, Bucket, Entry, HashValue, IndexMapCore, VacantEntry}; -use core::fmt; -use core::mem::replace; +use super::{equivalent, get_hash, Bucket, HashValue, IndexMapCore}; use hashbrown::raw::RawTable; type RawBucket = hashbrown::raw::Bucket; @@ -22,11 +20,14 @@ pub(super) fn insert_bulk_no_grow(indices: &mut RawTable, entries: } } +#[cfg(feature = "test_debug")] pub(super) struct DebugIndices<'a>(pub &'a RawTable); -impl fmt::Debug for DebugIndices<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + +#[cfg(feature = "test_debug")] +impl core::fmt::Debug for DebugIndices<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { // SAFETY: we're not letting any of the buckets escape this function - let indices = unsafe { self.0.iter().map(|raw_bucket| raw_bucket.read()) }; + let indices = unsafe { self.0.iter().map(|raw_bucket| *raw_bucket.as_ref()) }; f.debug_list().entries(indices).finish() } } @@ -38,34 +39,57 @@ impl IndexMapCore { unsafe { let offset = end - start; for bucket in self.indices.iter() { - let i = bucket.read(); - if i >= end { - bucket.write(i - offset); - } else if i >= start { + let i = bucket.as_mut(); + if *i >= end { + *i -= offset; + } else if *i >= start { self.indices.erase(bucket); } } } } - pub(crate) fn entry(&mut self, hash: HashValue, key: K) -> Entry<'_, K, V> + /// Search for a key in the table and return `Ok(entry_index)` if found. + /// Otherwise, insert the key and return `Err(new_index)`. + /// + /// Note that hashbrown may resize the table to reserve space for insertion, + /// even before checking if it's already present, so this is somewhat biased + /// towards new items. + pub(crate) fn find_or_insert(&mut self, hash: HashValue, key: &K) -> Result where K: Eq, { - let eq = equivalent(&key, &self.entries); + let hash = hash.get(); + let eq = equivalent(key, &self.entries); + let hasher = get_hash(&self.entries); + // SAFETY: We're not mutating between find and read/insert. + unsafe { + match self.indices.find_or_find_insert_slot(hash, eq, hasher) { + Ok(raw_bucket) => Ok(*raw_bucket.as_ref()), + Err(slot) => { + let index = self.indices.len(); + self.indices.insert_in_slot(hash, slot, index); + Err(index) + } + } + } + } + + pub(super) fn raw_entry( + &mut self, + hash: HashValue, + mut is_match: impl FnMut(&K) -> bool, + ) -> Result, &mut Self> { + let entries = &*self.entries; + let eq = move |&i: &usize| is_match(&entries[i].key); match self.indices.find(hash.get(), eq) { // SAFETY: The entry is created with a live raw bucket, at the same time // we have a &mut reference to the map, so it can not be modified further. - Some(raw_bucket) => Entry::Occupied(OccupiedEntry { + Some(raw_bucket) => Ok(RawTableEntry { map: self, raw_bucket, - key, - }), - None => Entry::Vacant(VacantEntry { - map: self, - hash, - key, }), + None => Err(self), } } @@ -74,118 +98,56 @@ impl IndexMapCore { // only the item references that are appropriately bound to `&mut self`. unsafe { self.indices.iter().map(|bucket| bucket.as_mut()) } } - - /// Return the raw bucket for the given index - fn find_index(&self, index: usize) -> RawBucket { - // We'll get a "nice" bounds-check from indexing `self.entries`, - // and then we expect to find it in the table as well. - let hash = self.entries[index].hash.get(); - self.indices - .find(hash, move |&i| i == index) - .expect("index not found") - } - - pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { - // SAFETY: Can't take two `get_mut` references from one table, so we - // must use raw buckets to do the swap. This is still safe because we - // are locally sure they won't dangle, and we write them individually. - unsafe { - let raw_bucket_a = self.find_index(a); - let raw_bucket_b = self.find_index(b); - raw_bucket_a.write(b); - raw_bucket_b.write(a); - } - self.entries.swap(a, b); - } } -/// A view into an occupied entry in a `IndexMap`. -/// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html +/// A view into an occupied raw entry in an `IndexMap`. // SAFETY: The lifetime of the map reference also constrains the raw bucket, // which is essentially a raw pointer into the map indices. -pub struct OccupiedEntry<'a, K, V> { +pub(super) struct RawTableEntry<'a, K, V> { map: &'a mut IndexMapCore, raw_bucket: RawBucket, - key: K, } // `hashbrown::raw::Bucket` is only `Send`, not `Sync`. // SAFETY: `&self` only accesses the bucket to read it. -unsafe impl Sync for OccupiedEntry<'_, K, V> {} - -// The parent module also adds methods that don't threaten the unsafe encapsulation. -impl<'a, K, V> OccupiedEntry<'a, K, V> { - /// Gets a reference to the entry's key in the map. - /// - /// Note that this is not the key that was used to find the entry. There may be an observable - /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like - /// extra fields or the memory address of an allocation. - pub fn key(&self) -> &K { - &self.map.entries[self.index()].key - } +unsafe impl Sync for RawTableEntry<'_, K, V> {} - /// Gets a reference to the entry's value in the map. - pub fn get(&self) -> &V { - &self.map.entries[self.index()].value +impl<'a, K, V> RawTableEntry<'a, K, V> { + /// Return the index of the key-value pair + #[inline] + pub(super) fn index(&self) -> usize { + // SAFETY: we have `&mut map` keeping the bucket stable + unsafe { *self.raw_bucket.as_ref() } } - /// Gets a mutable reference to the entry's value in the map. - /// - /// If you need a reference which may outlive the destruction of the - /// `Entry` value, see `into_mut`. - pub fn get_mut(&mut self) -> &mut V { - let index = self.index(); - &mut self.map.entries[index].value + #[inline] + pub(super) fn bucket(&self) -> &Bucket { + &self.map.entries[self.index()] } - /// Put the new key in the occupied entry's key slot - pub(crate) fn replace_key(self) -> K { + #[inline] + pub(super) fn bucket_mut(&mut self) -> &mut Bucket { let index = self.index(); - let old_key = &mut self.map.entries[index].key; - replace(old_key, self.key) + &mut self.map.entries[index] } - /// Return the index of the key-value pair #[inline] - pub fn index(&self) -> usize { - // SAFETY: we have &mut map keep keeping the bucket stable - unsafe { self.raw_bucket.read() } - } - - /// Converts into a mutable reference to the entry's value in the map, - /// with a lifetime bound to the map itself. - pub fn into_mut(self) -> &'a mut V { + pub(super) fn into_bucket(self) -> &'a mut Bucket { let index = self.index(); - &mut self.map.entries[index].value + &mut self.map.entries[index] } - /// Remove and return the key, value pair stored in the map for this entry - /// - /// Like `Vec::swap_remove`, the pair is removed by swapping it with the - /// last element of the map and popping it off. **This perturbs - /// the position of what used to be the last element!** - /// - /// Computes in **O(1)** time (average). - pub fn swap_remove_entry(self) -> (K, V) { + /// Remove the index from indices, leaving the actual entries to the caller. + pub(super) fn remove_index(self) -> (&'a mut IndexMapCore, usize) { // SAFETY: This is safe because it can only happen once (self is consumed) // and map.indices have not been modified since entry construction - let index = unsafe { self.map.indices.remove(self.raw_bucket) }; - self.map.swap_remove_finish(index) + let (index, _slot) = unsafe { self.map.indices.remove(self.raw_bucket) }; + (self.map, index) } - /// Remove and return the key, value pair stored in the map for this entry - /// - /// Like `Vec::remove`, the pair is removed by shifting all of the - /// elements that follow it, preserving their relative order. - /// **This perturbs the index of all of those elements!** - /// - /// Computes in **O(n)** time (average). - pub fn shift_remove_entry(self) -> (K, V) { - // SAFETY: This is safe because it can only happen once (self is consumed) - // and map.indices have not been modified since entry construction - let index = unsafe { self.map.indices.remove(self.raw_bucket) }; - self.map.shift_remove_finish(index) + /// Take no action, just return the index and the original map reference. + pub(super) fn into_inner(self) -> (&'a mut IndexMapCore, usize) { + let index = self.index(); + (self.map, index) } } diff --git a/third_party/rust/indexmap/src/map/core/raw_entry_v1.rs b/third_party/rust/indexmap/src/map/core/raw_entry_v1.rs new file mode 100644 index 0000000000..87e532d557 --- /dev/null +++ b/third_party/rust/indexmap/src/map/core/raw_entry_v1.rs @@ -0,0 +1,652 @@ +//! Opt-in access to the experimental raw entry API. +//! +//! This module is designed to mimic the raw entry API of [`HashMap`][std::collections::hash_map], +//! matching its unstable state as of Rust 1.75. See the tracking issue +//! [rust#56167](https://github.com/rust-lang/rust/issues/56167) for more details. +//! +//! The trait [`RawEntryApiV1`] and the `_v1` suffix on its methods are meant to insulate this for +//! the future, in case later breaking changes are needed. If the standard library stabilizes its +//! `hash_raw_entry` feature (or some replacement), matching *inherent* methods will be added to +//! `IndexMap` without such an opt-in trait. + +use super::raw::RawTableEntry; +use super::IndexMapCore; +use crate::{Equivalent, HashValue, IndexMap}; +use core::fmt; +use core::hash::{BuildHasher, Hash, Hasher}; +use core::marker::PhantomData; +use core::mem; + +/// Opt-in access to the experimental raw entry API. +/// +/// See the [`raw_entry_v1`][self] module documentation for more information. +pub trait RawEntryApiV1: private::Sealed { + /// Creates a raw immutable entry builder for the [`IndexMap`]. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. + /// + /// This is useful for + /// * Hash memoization + /// * Using a search key that doesn't work with the [`Equivalent`] trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Unless you are in such a situation, higher-level and more foolproof APIs like + /// [`get`][IndexMap::get] should be preferred. + /// + /// Immutable raw entries have very limited use; you might instead want + /// [`raw_entry_mut_v1`][Self::raw_entry_mut_v1]. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use indexmap::map::{IndexMap, RawEntryApiV1}; + /// + /// let mut map = IndexMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// for k in ["a", "b", "c", "d", "e", "f"] { + /// let hash = compute_hash(map.hasher(), k); + /// let i = map.get_index_of(k); + /// let v = map.get(k); + /// let kv = map.get_key_value(k); + /// let ikv = map.get_full(k); + /// + /// println!("Key: {} and value: {:?}", k, v); + /// + /// assert_eq!(map.raw_entry_v1().from_key(k), kv); + /// assert_eq!(map.raw_entry_v1().from_hash(hash, |q| *q == k), kv); + /// assert_eq!(map.raw_entry_v1().from_key_hashed_nocheck(hash, k), kv); + /// assert_eq!(map.raw_entry_v1().from_hash_full(hash, |q| *q == k), ikv); + /// assert_eq!(map.raw_entry_v1().index_from_hash(hash, |q| *q == k), i); + /// } + /// ``` + fn raw_entry_v1(&self) -> RawEntryBuilder<'_, K, V, S>; + + /// Creates a raw entry builder for the [`IndexMap`]. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. After this, insertions into a vacant entry + /// still require an owned key to be provided. + /// + /// Raw entries are useful for such exotic situations as: + /// + /// * Hash memoization + /// * Deferring the creation of an owned key until it is known to be required + /// * Using a search key that doesn't work with the [`Equivalent`] trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Because raw entries provide much more low-level control, it's much easier + /// to put the `IndexMap` into an inconsistent state which, while memory-safe, + /// will cause the map to produce seemingly random results. Higher-level and more + /// foolproof APIs like [`entry`][IndexMap::entry] should be preferred when possible. + /// + /// Raw entries give mutable access to the keys. This must not be used + /// to modify how the key would compare or hash, as the map will not re-evaluate + /// where the key should go, meaning the keys may become "lost" if their + /// location does not reflect their state. For instance, if you change a key + /// so that the map now contains keys which compare equal, search may start + /// acting erratically, with two keys randomly masking each other. Implementations + /// are free to assume this doesn't happen (within the limits of memory-safety). + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use indexmap::map::{IndexMap, RawEntryApiV1}; + /// use indexmap::map::raw_entry_v1::RawEntryMut; + /// + /// let mut map = IndexMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// // Existing key (insert and update) + /// match map.raw_entry_mut_v1().from_key("a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(mut view) => { + /// assert_eq!(view.index(), 0); + /// assert_eq!(view.get(), &100); + /// let v = view.get_mut(); + /// let new_v = (*v) * 10; + /// *v = new_v; + /// assert_eq!(view.insert(1111), 1000); + /// } + /// } + /// + /// assert_eq!(map["a"], 1111); + /// assert_eq!(map.len(), 3); + /// + /// // Existing key (take) + /// let hash = compute_hash(map.hasher(), "c"); + /// match map.raw_entry_mut_v1().from_key_hashed_nocheck(hash, "c") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.index(), 2); + /// assert_eq!(view.shift_remove_entry(), ("c", 300)); + /// } + /// } + /// assert_eq!(map.raw_entry_v1().from_key("c"), None); + /// assert_eq!(map.len(), 2); + /// + /// // Nonexistent key (insert and update) + /// let key = "d"; + /// let hash = compute_hash(map.hasher(), key); + /// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(view) => { + /// assert_eq!(view.index(), 2); + /// let (k, value) = view.insert("d", 4000); + /// assert_eq!((*k, *value), ("d", 4000)); + /// *value = 40000; + /// } + /// } + /// assert_eq!(map["d"], 40000); + /// assert_eq!(map.len(), 3); + /// + /// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.index(), 2); + /// assert_eq!(view.swap_remove_entry(), ("d", 40000)); + /// } + /// } + /// assert_eq!(map.get("d"), None); + /// assert_eq!(map.len(), 2); + /// ``` + fn raw_entry_mut_v1(&mut self) -> RawEntryBuilderMut<'_, K, V, S>; +} + +impl RawEntryApiV1 for IndexMap { + fn raw_entry_v1(&self) -> RawEntryBuilder<'_, K, V, S> { + RawEntryBuilder { map: self } + } + + fn raw_entry_mut_v1(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { + RawEntryBuilderMut { map: self } + } +} + +/// A builder for computing where in an [`IndexMap`] a key-value pair would be stored. +/// +/// This `struct` is created by the [`IndexMap::raw_entry_v1`] method, provided by the +/// [`RawEntryApiV1`] trait. See its documentation for more. +pub struct RawEntryBuilder<'a, K, V, S> { + map: &'a IndexMap, +} + +impl fmt::Debug for RawEntryBuilder<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> { + /// Access an entry by key. + pub fn from_key(self, key: &Q) -> Option<(&'a K, &'a V)> + where + S: BuildHasher, + Q: ?Sized + Hash + Equivalent, + { + self.map.get_key_value(key) + } + + /// Access an entry by a key and its hash. + pub fn from_key_hashed_nocheck(self, hash: u64, key: &Q) -> Option<(&'a K, &'a V)> + where + Q: ?Sized + Equivalent, + { + let hash = HashValue(hash as usize); + let i = self.map.core.get_index_of(hash, key)?; + self.map.get_index(i) + } + + /// Access an entry by hash. + pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + let map = self.map; + let i = self.index_from_hash(hash, is_match)?; + map.get_index(i) + } + + /// Access an entry by hash, including its index. + pub fn from_hash_full(self, hash: u64, is_match: F) -> Option<(usize, &'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + let map = self.map; + let i = self.index_from_hash(hash, is_match)?; + let (key, value) = map.get_index(i)?; + Some((i, key, value)) + } + + /// Access the index of an entry by hash. + pub fn index_from_hash(self, hash: u64, mut is_match: F) -> Option + where + F: FnMut(&K) -> bool, + { + let hash = HashValue(hash as usize); + let entries = &*self.map.core.entries; + let eq = move |&i: &usize| is_match(&entries[i].key); + self.map.core.indices.get(hash.get(), eq).copied() + } +} + +/// A builder for computing where in an [`IndexMap`] a key-value pair would be stored. +/// +/// This `struct` is created by the [`IndexMap::raw_entry_mut_v1`] method, provided by the +/// [`RawEntryApiV1`] trait. See its documentation for more. +pub struct RawEntryBuilderMut<'a, K, V, S> { + map: &'a mut IndexMap, +} + +impl fmt::Debug for RawEntryBuilderMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilderMut").finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> { + /// Access an entry by key. + pub fn from_key(self, key: &Q) -> RawEntryMut<'a, K, V, S> + where + S: BuildHasher, + Q: ?Sized + Hash + Equivalent, + { + let hash = self.map.hash(key); + self.from_key_hashed_nocheck(hash.get(), key) + } + + /// Access an entry by a key and its hash. + pub fn from_key_hashed_nocheck(self, hash: u64, key: &Q) -> RawEntryMut<'a, K, V, S> + where + Q: ?Sized + Equivalent, + { + self.from_hash(hash, |k| Q::equivalent(key, k)) + } + + /// Access an entry by hash. + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> + where + F: FnMut(&K) -> bool, + { + let hash = HashValue(hash as usize); + match self.map.core.raw_entry(hash, is_match) { + Ok(raw) => RawEntryMut::Occupied(RawOccupiedEntryMut { + raw, + hash_builder: PhantomData, + }), + Err(map) => RawEntryMut::Vacant(RawVacantEntryMut { + map, + hash_builder: &self.map.hash_builder, + }), + } + } +} + +/// Raw entry for an existing key-value pair or a vacant location to +/// insert one. +pub enum RawEntryMut<'a, K, V, S> { + /// Existing slot with equivalent key. + Occupied(RawOccupiedEntryMut<'a, K, V, S>), + /// Vacant slot (no equivalent key in the map). + Vacant(RawVacantEntryMut<'a, K, V, S>), +} + +impl fmt::Debug for RawEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut tuple = f.debug_tuple("RawEntryMut"); + match self { + Self::Vacant(v) => tuple.field(v), + Self::Occupied(o) => tuple.field(o), + }; + tuple.finish() + } +} + +impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { + /// Return the index where the key-value pair exists or may be inserted. + #[inline] + pub fn index(&self) -> usize { + match self { + Self::Occupied(entry) => entry.index(), + Self::Vacant(entry) => entry.index(), + } + } + + /// Inserts the given default key and value in the entry if it is vacant and returns mutable + /// references to them. Otherwise mutable references to an already existent pair are returned. + pub fn or_insert(self, default_key: K, default_value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + match self { + Self::Occupied(entry) => entry.into_key_value_mut(), + Self::Vacant(entry) => entry.insert(default_key, default_value), + } + } + + /// Inserts the result of the `call` function in the entry if it is vacant and returns mutable + /// references to them. Otherwise mutable references to an already existent pair are returned. + pub fn or_insert_with(self, call: F) -> (&'a mut K, &'a mut V) + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, + { + match self { + Self::Occupied(entry) => entry.into_key_value_mut(), + Self::Vacant(entry) => { + let (key, value) = call(); + entry.insert(key, value) + } + } + } + + /// Modifies the entry if it is occupied. + pub fn and_modify(mut self, f: F) -> Self + where + F: FnOnce(&mut K, &mut V), + { + if let Self::Occupied(entry) = &mut self { + let (k, v) = entry.get_key_value_mut(); + f(k, v); + } + self + } +} + +/// A raw view into an occupied entry in an [`IndexMap`]. +/// It is part of the [`RawEntryMut`] enum. +pub struct RawOccupiedEntryMut<'a, K, V, S> { + raw: RawTableEntry<'a, K, V>, + hash_builder: PhantomData<&'a S>, +} + +impl fmt::Debug for RawOccupiedEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawOccupiedEntryMut") + .field("key", self.key()) + .field("value", self.get()) + .finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { + /// Return the index of the key-value pair + #[inline] + pub fn index(&self) -> usize { + self.raw.index() + } + + /// Gets a reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn key(&self) -> &K { + &self.raw.bucket().key + } + + /// Gets a mutable reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn key_mut(&mut self) -> &mut K { + &mut self.raw.bucket_mut().key + } + + /// Converts into a mutable reference to the entry's key in the map, + /// with a lifetime bound to the map itself. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn into_key(self) -> &'a mut K { + &mut self.raw.into_bucket().key + } + + /// Gets a reference to the entry's value in the map. + pub fn get(&self) -> &V { + &self.raw.bucket().value + } + + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// [`RawEntryMut`] value, see [`into_mut`][Self::into_mut]. + pub fn get_mut(&mut self) -> &mut V { + &mut self.raw.bucket_mut().value + } + + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut V { + &mut self.raw.into_bucket().value + } + + /// Gets a reference to the entry's key and value in the map. + pub fn get_key_value(&self) -> (&K, &V) { + self.raw.bucket().refs() + } + + /// Gets a reference to the entry's key and value in the map. + pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { + self.raw.bucket_mut().muts() + } + + /// Converts into a mutable reference to the entry's key and value in the map, + /// with a lifetime bound to the map itself. + pub fn into_key_value_mut(self) -> (&'a mut K, &'a mut V) { + self.raw.into_bucket().muts() + } + + /// Sets the value of the entry, and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Sets the key of the entry, and returns the entry's old key. + pub fn insert_key(&mut self, key: K) -> K { + mem::replace(self.key_mut(), key) + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// **NOTE:** This is equivalent to [`.swap_remove()`][Self::swap_remove], replacing this + /// entry's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the keys in the map, use + /// [`.shift_remove()`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the map order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(self) -> V { + self.swap_remove() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with + /// the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(self) -> V { + self.swap_remove_entry().1 + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(self) -> V { + self.shift_remove_entry().1 + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// **NOTE:** This is equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry], + /// replacing this entry's position with the last element, and it is deprecated in favor of + /// calling that explicitly. If you need to preserve the relative order of the keys in the map, + /// use [`.shift_remove_entry()`][Self::shift_remove_entry] instead. + #[deprecated(note = "`remove_entry` disrupts the map order -- \ + use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")] + pub fn remove_entry(self) -> (K, V) { + self.swap_remove_entry() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with + /// the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(self) -> (K, V) { + let (map, index) = self.raw.remove_index(); + map.swap_remove_finish(index) + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(self) -> (K, V) { + let (map, index) = self.raw.remove_index(); + map.shift_remove_finish(index) + } + + /// Moves the position of the entry to a new index + /// by shifting all other entries in-between. + /// + /// This is equivalent to [`IndexMap::move_index`] + /// coming `from` the current [`.index()`][Self::index]. + /// + /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. + /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. + /// + /// ***Panics*** if `to` is out of bounds. + /// + /// Computes in **O(n)** time (average). + pub fn move_index(self, to: usize) { + let (map, index) = self.raw.into_inner(); + map.move_index(index, to); + } + + /// Swaps the position of entry with another. + /// + /// This is equivalent to [`IndexMap::swap_indices`] + /// with the current [`.index()`][Self::index] as one of the two being swapped. + /// + /// ***Panics*** if the `other` index is out of bounds. + /// + /// Computes in **O(1)** time (average). + pub fn swap_indices(self, other: usize) { + let (map, index) = self.raw.into_inner(); + map.swap_indices(index, other) + } +} + +/// A view into a vacant raw entry in an [`IndexMap`]. +/// It is part of the [`RawEntryMut`] enum. +pub struct RawVacantEntryMut<'a, K, V, S> { + map: &'a mut IndexMapCore, + hash_builder: &'a S, +} + +impl fmt::Debug for RawVacantEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { + /// Return the index where a key-value pair may be inserted. + pub fn index(&self) -> usize { + self.map.indices.len() + } + + /// Inserts the given key and value into the map, + /// and returns mutable references to them. + pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let mut h = self.hash_builder.build_hasher(); + key.hash(&mut h); + self.insert_hashed_nocheck(h.finish(), key, value) + } + + /// Inserts the given key and value into the map with the provided hash, + /// and returns mutable references to them. + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) { + let hash = HashValue(hash as usize); + let i = self.map.insert_unique(hash, key, value); + self.map.entries[i].muts() + } + + /// Inserts the given key and value into the map at the given index, + /// shifting others to the right, and returns mutable references to them. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + pub fn shift_insert(self, index: usize, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let mut h = self.hash_builder.build_hasher(); + key.hash(&mut h); + self.shift_insert_hashed_nocheck(index, h.finish(), key, value) + } + + /// Inserts the given key and value into the map with the provided hash + /// at the given index, and returns mutable references to them. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + pub fn shift_insert_hashed_nocheck( + self, + index: usize, + hash: u64, + key: K, + value: V, + ) -> (&'a mut K, &'a mut V) { + let hash = HashValue(hash as usize); + self.map.shift_insert_unique(index, hash, key, value); + self.map.entries[index].muts() + } +} + +mod private { + pub trait Sealed {} + + impl Sealed for super::IndexMap {} +} diff --git a/third_party/rust/indexmap/src/map/iter.rs b/third_party/rust/indexmap/src/map/iter.rs new file mode 100644 index 0000000000..1ec3703cfb --- /dev/null +++ b/third_party/rust/indexmap/src/map/iter.rs @@ -0,0 +1,713 @@ +use super::core::IndexMapCore; +use super::{Bucket, Entries, IndexMap, Slice}; + +use alloc::vec::{self, Vec}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::FusedIterator; +use core::ops::{Index, RangeBounds}; +use core::slice; + +impl<'a, K, V, S> IntoIterator for &'a IndexMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, K, V, S> IntoIterator for &'a mut IndexMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl IntoIterator for IndexMap { + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +/// An iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::iter`] method. +/// See its documentation for more. +pub struct Iter<'a, K, V> { + iter: slice::Iter<'a, Bucket>, +} + +impl<'a, K, V> Iter<'a, K, V> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &'a Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + iterator_methods!(Bucket::refs); +} + +impl DoubleEndedIterator for Iter<'_, K, V> { + double_ended_iterator_methods!(Bucket::refs); +} + +impl ExactSizeIterator for Iter<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Iter<'_, K, V> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// A mutable iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::iter_mut`] method. +/// See its documentation for more. +pub struct IterMut<'a, K, V> { + iter: slice::IterMut<'a, Bucket>, +} + +impl<'a, K, V> IterMut<'a, K, V> { + pub(super) fn new(entries: &'a mut [Bucket]) -> Self { + Self { + iter: entries.iter_mut(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } + + /// Returns a mutable slice of the remaining entries in the iterator. + /// + /// To avoid creating `&mut` references that alias, this is forced to consume the iterator. + pub fn into_slice(self) -> &'a mut Slice { + Slice::from_mut_slice(self.iter.into_slice()) + } +} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + iterator_methods!(Bucket::ref_mut); +} + +impl DoubleEndedIterator for IterMut<'_, K, V> { + double_ended_iterator_methods!(Bucket::ref_mut); +} + +impl ExactSizeIterator for IterMut<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IterMut<'_, K, V> {} + +impl fmt::Debug for IterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IterMut<'_, K, V> { + fn default() -> Self { + Self { + iter: [].iter_mut(), + } + } +} + +/// An owning iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::into_iter`] method +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +pub struct IntoIter { + iter: vec::IntoIter>, +} + +impl IntoIter { + pub(super) fn new(entries: Vec>) -> Self { + Self { + iter: entries.into_iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } + + /// Returns a mutable slice of the remaining entries in the iterator. + pub fn as_mut_slice(&mut self) -> &mut Slice { + Slice::from_mut_slice(self.iter.as_mut_slice()) + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + iterator_methods!(Bucket::key_value); +} + +impl DoubleEndedIterator for IntoIter { + double_ended_iterator_methods!(Bucket::key_value); +} + +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoIter { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// A draining iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::drain`] method. +/// See its documentation for more. +pub struct Drain<'a, K, V> { + iter: vec::Drain<'a, Bucket>, +} + +impl<'a, K, V> Drain<'a, K, V> { + pub(super) fn new(iter: vec::Drain<'a, Bucket>) -> Self { + Self { iter } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl Iterator for Drain<'_, K, V> { + type Item = (K, V); + + iterator_methods!(Bucket::key_value); +} + +impl DoubleEndedIterator for Drain<'_, K, V> { + double_ended_iterator_methods!(Bucket::key_value); +} + +impl ExactSizeIterator for Drain<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Drain<'_, K, V> {} + +impl fmt::Debug for Drain<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +/// An iterator over the keys of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::keys`] method. +/// See its documentation for more. +pub struct Keys<'a, K, V> { + iter: slice::Iter<'a, Bucket>, +} + +impl<'a, K, V> Keys<'a, K, V> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + iterator_methods!(Bucket::key_ref); +} + +impl DoubleEndedIterator for Keys<'_, K, V> { + double_ended_iterator_methods!(Bucket::key_ref); +} + +impl ExactSizeIterator for Keys<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Keys<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + fn clone(&self) -> Self { + Keys { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Keys<'_, K, V> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// Access [`IndexMap`] keys at indexed positions. +/// +/// While [`Index for IndexMap`][values] accesses a map's values, +/// indexing through [`IndexMap::keys`] offers an alternative to access a map's +/// keys instead. +/// +/// [values]: IndexMap#impl-Index-for-IndexMap +/// +/// Since `Keys` is also an iterator, consuming items from the iterator will +/// offset the effective indexes. Similarly, if `Keys` is obtained from +/// [`Slice::keys`], indexes will be interpreted relative to the position of +/// that slice. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_uppercase()); +/// } +/// +/// assert_eq!(map[0], "LOREM"); +/// assert_eq!(map.keys()[0], "lorem"); +/// assert_eq!(map[1], "IPSUM"); +/// assert_eq!(map.keys()[1], "ipsum"); +/// +/// map.reverse(); +/// assert_eq!(map.keys()[0], "amet"); +/// assert_eq!(map.keys()[1], "sit"); +/// +/// map.sort_keys(); +/// assert_eq!(map.keys()[0], "amet"); +/// assert_eq!(map.keys()[1], "dolor"); +/// +/// // Advancing the iterator will offset the indexing +/// let mut keys = map.keys(); +/// assert_eq!(keys[0], "amet"); +/// assert_eq!(keys.next().map(|s| &**s), Some("amet")); +/// assert_eq!(keys[0], "dolor"); +/// assert_eq!(keys[1], "ipsum"); +/// +/// // Slices may have an offset as well +/// let slice = &map[2..]; +/// assert_eq!(slice[0], "IPSUM"); +/// assert_eq!(slice.keys()[0], "ipsum"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// println!("{:?}", map.keys()[10]); // panics! +/// ``` +impl<'a, K, V> Index for Keys<'a, K, V> { + type Output = K; + + /// Returns a reference to the key at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index(&self, index: usize) -> &K { + &self.iter.as_slice()[index].key + } +} + +/// An owning iterator over the keys of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::into_keys`] method. +/// See its documentation for more. +pub struct IntoKeys { + iter: vec::IntoIter>, +} + +impl IntoKeys { + pub(super) fn new(entries: Vec>) -> Self { + Self { + iter: entries.into_iter(), + } + } +} + +impl Iterator for IntoKeys { + type Item = K; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for IntoKeys { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for IntoKeys { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoKeys {} + +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoKeys { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// An iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::values`] method. +/// See its documentation for more. +pub struct Values<'a, K, V> { + iter: slice::Iter<'a, Bucket>, +} + +impl<'a, K, V> Values<'a, K, V> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } +} + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + iterator_methods!(Bucket::value_ref); +} + +impl DoubleEndedIterator for Values<'_, K, V> { + double_ended_iterator_methods!(Bucket::value_ref); +} + +impl ExactSizeIterator for Values<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Values<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + fn clone(&self) -> Self { + Values { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Values<'_, K, V> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// A mutable iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::values_mut`] method. +/// See its documentation for more. +pub struct ValuesMut<'a, K, V> { + iter: slice::IterMut<'a, Bucket>, +} + +impl<'a, K, V> ValuesMut<'a, K, V> { + pub(super) fn new(entries: &'a mut [Bucket]) -> Self { + Self { + iter: entries.iter_mut(), + } + } +} + +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + iterator_methods!(Bucket::value_mut); +} + +impl DoubleEndedIterator for ValuesMut<'_, K, V> { + double_ended_iterator_methods!(Bucket::value_mut); +} + +impl ExactSizeIterator for ValuesMut<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for ValuesMut<'_, K, V> {} + +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for ValuesMut<'_, K, V> { + fn default() -> Self { + Self { + iter: [].iter_mut(), + } + } +} + +/// An owning iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::into_values`] method. +/// See its documentation for more. +pub struct IntoValues { + iter: vec::IntoIter>, +} + +impl IntoValues { + pub(super) fn new(entries: Vec>) -> Self { + Self { + iter: entries.into_iter(), + } + } +} + +impl Iterator for IntoValues { + type Item = V; + + iterator_methods!(Bucket::value); +} + +impl DoubleEndedIterator for IntoValues { + double_ended_iterator_methods!(Bucket::value); +} + +impl ExactSizeIterator for IntoValues { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoValues {} + +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoValues { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// A splicing iterator for `IndexMap`. +/// +/// This `struct` is created by [`IndexMap::splice()`]. +/// See its documentation for more. +pub struct Splice<'a, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + map: &'a mut IndexMap, + tail: IndexMapCore, + drain: vec::IntoIter>, + replace_with: I, +} + +impl<'a, I, K, V, S> Splice<'a, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + pub(super) fn new(map: &'a mut IndexMap, range: R, replace_with: I) -> Self + where + R: RangeBounds, + { + let (tail, drain) = map.core.split_splice(range); + Self { + map, + tail, + drain, + replace_with, + } + } +} + +impl Drop for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + fn drop(&mut self) { + // Finish draining unconsumed items. We don't strictly *have* to do this + // manually, since we already split it into separate memory, but it will + // match the drop order of `vec::Splice` items this way. + let _ = self.drain.nth(usize::MAX); + + // Now insert all the new items. If a key matches an existing entry, it + // keeps the original position and only replaces the value, like `insert`. + while let Some((key, value)) = self.replace_with.next() { + // Since the tail is disjoint, we can try to update it first, + // or else insert (update or append) the primary map. + let hash = self.map.hash(&key); + if let Some(i) = self.tail.get_index_of(hash, &key) { + self.tail.as_entries_mut()[i].value = value; + } else { + self.map.core.insert_full(hash, key, value); + } + } + + // Finally, re-append the tail + self.map.core.append_unchecked(&mut self.tail); + } +} + +impl Iterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + type Item = (K, V); + + fn next(&mut self) -> Option { + self.drain.next().map(Bucket::key_value) + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +impl DoubleEndedIterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.drain.next_back().map(Bucket::key_value) + } +} + +impl ExactSizeIterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + fn len(&self) -> usize { + self.drain.len() + } +} + +impl FusedIterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ +} + +impl<'a, I, K, V, S> fmt::Debug for Splice<'a, I, K, V, S> +where + I: fmt::Debug + Iterator, + K: fmt::Debug + Hash + Eq, + V: fmt::Debug, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Follow `vec::Splice` in only printing the drain and replacement + f.debug_struct("Splice") + .field("drain", &self.drain) + .field("replace_with", &self.replace_with) + .finish() + } +} diff --git a/third_party/rust/indexmap/src/map/mutable.rs b/third_party/rust/indexmap/src/map/mutable.rs new file mode 100644 index 0000000000..7df325948f --- /dev/null +++ b/third_party/rust/indexmap/src/map/mutable.rs @@ -0,0 +1,87 @@ +use core::hash::{BuildHasher, Hash}; + +use super::{Bucket, Entries, Equivalent, IndexMap}; + +/// Opt-in mutable access to [`IndexMap`] keys. +/// +/// These methods expose `&mut K`, mutable references to the key as it is stored +/// in the map. +/// You are allowed to modify the keys in the map **if the modification +/// does not change the key’s hash and equality**. +/// +/// If keys are modified erroneously, you can no longer look them up. +/// This is sound (memory safe) but a logical error hazard (just like +/// implementing `PartialEq`, `Eq`, or `Hash` incorrectly would be). +/// +/// `use` this trait to enable its methods for `IndexMap`. +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +pub trait MutableKeys: private::Sealed { + type Key; + type Value; + + /// Return item index, mutable reference to key and value + /// + /// Computes in **O(1)** time (average). + fn get_full_mut2(&mut self, key: &Q) -> Option<(usize, &mut Self::Key, &mut Self::Value)> + where + Q: ?Sized + Hash + Equivalent; + + /// Return mutable reference to key and value at an index. + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + fn get_index_mut2(&mut self, index: usize) -> Option<(&mut Self::Key, &mut Self::Value)>; + + /// Scan through each key-value pair in the map and keep those where the + /// closure `keep` returns `true`. + /// + /// The elements are visited in order, and remaining elements keep their + /// order. + /// + /// Computes in **O(n)** time (average). + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut Self::Key, &mut Self::Value) -> bool; +} + +/// Opt-in mutable access to [`IndexMap`] keys. +/// +/// See [`MutableKeys`] for more information. +impl MutableKeys for IndexMap +where + S: BuildHasher, +{ + type Key = K; + type Value = V; + + fn get_full_mut2(&mut self, key: &Q) -> Option<(usize, &mut K, &mut V)> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some((i, &mut entry.key, &mut entry.value)) + } else { + None + } + } + + fn get_index_mut2(&mut self, index: usize) -> Option<(&mut K, &mut V)> { + self.as_entries_mut().get_mut(index).map(Bucket::muts) + } + + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut K, &mut V) -> bool, + { + self.core.retain_in_order(keep); + } +} + +mod private { + pub trait Sealed {} + + impl Sealed for super::IndexMap {} +} diff --git a/third_party/rust/indexmap/src/map/serde_seq.rs b/third_party/rust/indexmap/src/map/serde_seq.rs new file mode 100644 index 0000000000..602ae7dc74 --- /dev/null +++ b/third_party/rust/indexmap/src/map/serde_seq.rs @@ -0,0 +1,138 @@ +//! Functions to serialize and deserialize an [`IndexMap`] as an ordered sequence. +//! +//! The default `serde` implementation serializes `IndexMap` as a normal map, +//! but there is no guarantee that serialization formats will preserve the order +//! of the key-value pairs. This module serializes `IndexMap` as a sequence of +//! `(key, value)` elements instead, in order. +//! +//! This module may be used in a field attribute for derived implementations: +//! +//! ``` +//! # use indexmap::IndexMap; +//! # use serde_derive::{Deserialize, Serialize}; +//! #[derive(Deserialize, Serialize)] +//! struct Data { +//! #[serde(with = "indexmap::map::serde_seq")] +//! map: IndexMap, +//! // ... +//! } +//! ``` + +use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; +use serde::ser::{Serialize, Serializer}; + +use core::fmt::{self, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; + +use crate::map::Slice as MapSlice; +use crate::serde::cautious_capacity; +use crate::set::Slice as SetSlice; +use crate::IndexMap; + +/// Serializes a [`map::Slice`][MapSlice] as an ordered sequence. +/// +/// This behaves like [`crate::map::serde_seq`] for `IndexMap`, serializing a sequence +/// of `(key, value)` pairs, rather than as a map that might not preserve order. +impl Serialize for MapSlice +where + K: Serialize, + V: Serialize, +{ + fn serialize(&self, serializer: T) -> Result + where + T: Serializer, + { + serializer.collect_seq(self) + } +} + +/// Serializes a [`set::Slice`][SetSlice] as an ordered sequence. +impl Serialize for SetSlice +where + T: Serialize, +{ + fn serialize(&self, serializer: Se) -> Result + where + Se: Serializer, + { + serializer.collect_seq(self) + } +} + +/// Serializes an [`IndexMap`] as an ordered sequence. +/// +/// This function may be used in a field attribute for deriving [`Serialize`]: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde_derive::Serialize; +/// #[derive(Serialize)] +/// struct Data { +/// #[serde(serialize_with = "indexmap::map::serde_seq::serialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +pub fn serialize(map: &IndexMap, serializer: T) -> Result +where + K: Serialize, + V: Serialize, + T: Serializer, +{ + serializer.collect_seq(map) +} + +/// Visitor to deserialize a *sequenced* `IndexMap` +struct SeqVisitor(PhantomData<(K, V, S)>); + +impl<'de, K, V, S> Visitor<'de> for SeqVisitor +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + type Value = IndexMap; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a sequenced map") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = cautious_capacity::(seq.size_hint()); + let mut map = IndexMap::with_capacity_and_hasher(capacity, S::default()); + + while let Some((key, value)) = seq.next_element()? { + map.insert(key, value); + } + + Ok(map) + } +} + +/// Deserializes an [`IndexMap`] from an ordered sequence. +/// +/// This function may be used in a field attribute for deriving [`Deserialize`]: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde_derive::Deserialize; +/// #[derive(Deserialize)] +/// struct Data { +/// #[serde(deserialize_with = "indexmap::map::serde_seq::deserialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +pub fn deserialize<'de, D, K, V, S>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + deserializer.deserialize_seq(SeqVisitor(PhantomData)) +} diff --git a/third_party/rust/indexmap/src/map/slice.rs b/third_party/rust/indexmap/src/map/slice.rs new file mode 100644 index 0000000000..b2f00f4807 --- /dev/null +++ b/third_party/rust/indexmap/src/map/slice.rs @@ -0,0 +1,539 @@ +use super::{ + Bucket, Entries, IndexMap, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, + ValuesMut, +}; +use crate::util::try_simplify_range; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ops::{self, Bound, Index, IndexMut, RangeBounds}; + +/// A dynamically-sized slice of key-value pairs in an [`IndexMap`]. +/// +/// This supports indexed operations much like a `[(K, V)]` slice, +/// but not any hashed operations on the map keys. +/// +/// Unlike `IndexMap`, `Slice` does consider the order for [`PartialEq`] +/// and [`Eq`], and it also implements [`PartialOrd`], [`Ord`], and [`Hash`]. +#[repr(transparent)] +pub struct Slice { + pub(crate) entries: [Bucket], +} + +// SAFETY: `Slice` is a transparent wrapper around `[Bucket]`, +// and reference lifetimes are bound together in function signatures. +#[allow(unsafe_code)] +impl Slice { + pub(super) const fn from_slice(entries: &[Bucket]) -> &Self { + unsafe { &*(entries as *const [Bucket] as *const Self) } + } + + pub(super) fn from_mut_slice(entries: &mut [Bucket]) -> &mut Self { + unsafe { &mut *(entries as *mut [Bucket] as *mut Self) } + } + + pub(super) fn from_boxed(entries: Box<[Bucket]>) -> Box { + unsafe { Box::from_raw(Box::into_raw(entries) as *mut Self) } + } + + fn into_boxed(self: Box) -> Box<[Bucket]> { + unsafe { Box::from_raw(Box::into_raw(self) as *mut [Bucket]) } + } +} + +impl Slice { + pub(crate) fn into_entries(self: Box) -> Vec> { + self.into_boxed().into_vec() + } + + /// Returns an empty slice. + pub const fn new<'a>() -> &'a Self { + Self::from_slice(&[]) + } + + /// Returns an empty mutable slice. + pub fn new_mut<'a>() -> &'a mut Self { + Self::from_mut_slice(&mut []) + } + + /// Return the number of key-value pairs in the map slice. + #[inline] + pub const fn len(&self) -> usize { + self.entries.len() + } + + /// Returns true if the map slice contains no elements. + #[inline] + pub const fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + /// Get a key-value pair by index. + /// + /// Valid indices are *0 <= index < self.len()* + pub fn get_index(&self, index: usize) -> Option<(&K, &V)> { + self.entries.get(index).map(Bucket::refs) + } + + /// Get a key-value pair by index, with mutable access to the value. + /// + /// Valid indices are *0 <= index < self.len()* + pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { + self.entries.get_mut(index).map(Bucket::ref_mut) + } + + /// Returns a slice of key-value pairs in the given range of indices. + /// + /// Valid indices are *0 <= index < self.len()* + pub fn get_range>(&self, range: R) -> Option<&Self> { + let range = try_simplify_range(range, self.entries.len())?; + self.entries.get(range).map(Slice::from_slice) + } + + /// Returns a mutable slice of key-value pairs in the given range of indices. + /// + /// Valid indices are *0 <= index < self.len()* + pub fn get_range_mut>(&mut self, range: R) -> Option<&mut Self> { + let range = try_simplify_range(range, self.entries.len())?; + self.entries.get_mut(range).map(Slice::from_mut_slice) + } + + /// Get the first key-value pair. + pub fn first(&self) -> Option<(&K, &V)> { + self.entries.first().map(Bucket::refs) + } + + /// Get the first key-value pair, with mutable access to the value. + pub fn first_mut(&mut self) -> Option<(&K, &mut V)> { + self.entries.first_mut().map(Bucket::ref_mut) + } + + /// Get the last key-value pair. + pub fn last(&self) -> Option<(&K, &V)> { + self.entries.last().map(Bucket::refs) + } + + /// Get the last key-value pair, with mutable access to the value. + pub fn last_mut(&mut self) -> Option<(&K, &mut V)> { + self.entries.last_mut().map(Bucket::ref_mut) + } + + /// Divides one slice into two at an index. + /// + /// ***Panics*** if `index > len`. + pub fn split_at(&self, index: usize) -> (&Self, &Self) { + let (first, second) = self.entries.split_at(index); + (Self::from_slice(first), Self::from_slice(second)) + } + + /// Divides one mutable slice into two at an index. + /// + /// ***Panics*** if `index > len`. + pub fn split_at_mut(&mut self, index: usize) -> (&mut Self, &mut Self) { + let (first, second) = self.entries.split_at_mut(index); + (Self::from_mut_slice(first), Self::from_mut_slice(second)) + } + + /// Returns the first key-value pair and the rest of the slice, + /// or `None` if it is empty. + pub fn split_first(&self) -> Option<((&K, &V), &Self)> { + if let [first, rest @ ..] = &self.entries { + Some((first.refs(), Self::from_slice(rest))) + } else { + None + } + } + + /// Returns the first key-value pair and the rest of the slice, + /// with mutable access to the value, or `None` if it is empty. + pub fn split_first_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> { + if let [first, rest @ ..] = &mut self.entries { + Some((first.ref_mut(), Self::from_mut_slice(rest))) + } else { + None + } + } + + /// Returns the last key-value pair and the rest of the slice, + /// or `None` if it is empty. + pub fn split_last(&self) -> Option<((&K, &V), &Self)> { + if let [rest @ .., last] = &self.entries { + Some((last.refs(), Self::from_slice(rest))) + } else { + None + } + } + + /// Returns the last key-value pair and the rest of the slice, + /// with mutable access to the value, or `None` if it is empty. + pub fn split_last_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> { + if let [rest @ .., last] = &mut self.entries { + Some((last.ref_mut(), Self::from_mut_slice(rest))) + } else { + None + } + } + + /// Return an iterator over the key-value pairs of the map slice. + pub fn iter(&self) -> Iter<'_, K, V> { + Iter::new(&self.entries) + } + + /// Return an iterator over the key-value pairs of the map slice. + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut::new(&mut self.entries) + } + + /// Return an iterator over the keys of the map slice. + pub fn keys(&self) -> Keys<'_, K, V> { + Keys::new(&self.entries) + } + + /// Return an owning iterator over the keys of the map slice. + pub fn into_keys(self: Box) -> IntoKeys { + IntoKeys::new(self.into_entries()) + } + + /// Return an iterator over the values of the map slice. + pub fn values(&self) -> Values<'_, K, V> { + Values::new(&self.entries) + } + + /// Return an iterator over mutable references to the the values of the map slice. + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut::new(&mut self.entries) + } + + /// Return an owning iterator over the values of the map slice. + pub fn into_values(self: Box) -> IntoValues { + IntoValues::new(self.into_entries()) + } + + /// Search over a sorted map for a key. + /// + /// Returns the position where that key is present, or the position where it can be inserted to + /// maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the key up in + /// the map this is a slice from using [`IndexMap::get_index_of`], but this can also position + /// missing keys. + pub fn binary_search_keys(&self, x: &K) -> Result + where + K: Ord, + { + self.binary_search_by(|p, _| p.cmp(x)) + } + + /// Search over a sorted map with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> Ordering, + { + self.entries.binary_search_by(move |a| f(&a.key, &a.value)) + } + + /// Search over a sorted map with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> B, + B: Ord, + { + self.binary_search_by(|k, v| f(k, v).cmp(b)) + } + + /// Returns the index of the partition point of a sorted map according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point

(&self, mut pred: P) -> usize + where + P: FnMut(&K, &V) -> bool, + { + self.entries + .partition_point(move |a| pred(&a.key, &a.value)) + } +} + +impl<'a, K, V> IntoIterator for &'a Slice { + type IntoIter = Iter<'a, K, V>; + type Item = (&'a K, &'a V); + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, K, V> IntoIterator for &'a mut Slice { + type IntoIter = IterMut<'a, K, V>; + type Item = (&'a K, &'a mut V); + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl IntoIterator for Box> { + type IntoIter = IntoIter; + type Item = (K, V); + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +impl Default for &'_ Slice { + fn default() -> Self { + Slice::from_slice(&[]) + } +} + +impl Default for &'_ mut Slice { + fn default() -> Self { + Slice::from_mut_slice(&mut []) + } +} + +impl Default for Box> { + fn default() -> Self { + Slice::from_boxed(Box::default()) + } +} + +impl Clone for Box> { + fn clone(&self) -> Self { + Slice::from_boxed(self.entries.to_vec().into_boxed_slice()) + } +} + +impl From<&Slice> for Box> { + fn from(slice: &Slice) -> Self { + Slice::from_boxed(Box::from(&slice.entries)) + } +} + +impl fmt::Debug for Slice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +impl PartialEq for Slice { + fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.iter().eq(other) + } +} + +impl Eq for Slice {} + +impl PartialOrd for Slice { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +impl Ord for Slice { + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +impl Hash for Slice { + fn hash(&self, state: &mut H) { + self.len().hash(state); + for (key, value) in self { + key.hash(state); + value.hash(state); + } + } +} + +impl Index for Slice { + type Output = V; + + fn index(&self, index: usize) -> &V { + &self.entries[index].value + } +} + +impl IndexMut for Slice { + fn index_mut(&mut self, index: usize) -> &mut V { + &mut self.entries[index].value + } +} + +// We can't have `impl> Index` because that conflicts +// both upstream with `Index` and downstream with `Index<&Q>`. +// Instead, we repeat the implementations for all the core range types. +macro_rules! impl_index { + ($($range:ty),*) => {$( + impl Index<$range> for IndexMap { + type Output = Slice; + + fn index(&self, range: $range) -> &Self::Output { + Slice::from_slice(&self.as_entries()[range]) + } + } + + impl IndexMut<$range> for IndexMap { + fn index_mut(&mut self, range: $range) -> &mut Self::Output { + Slice::from_mut_slice(&mut self.as_entries_mut()[range]) + } + } + + impl Index<$range> for Slice { + type Output = Slice; + + fn index(&self, range: $range) -> &Self { + Self::from_slice(&self.entries[range]) + } + } + + impl IndexMut<$range> for Slice { + fn index_mut(&mut self, range: $range) -> &mut Self { + Self::from_mut_slice(&mut self.entries[range]) + } + } + )*} +} +impl_index!( + ops::Range, + ops::RangeFrom, + ops::RangeFull, + ops::RangeInclusive, + ops::RangeTo, + ops::RangeToInclusive, + (Bound, Bound) +); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn slice_index() { + fn check( + vec_slice: &[(i32, i32)], + map_slice: &Slice, + sub_slice: &Slice, + ) { + assert_eq!(map_slice as *const _, sub_slice as *const _); + itertools::assert_equal( + vec_slice.iter().copied(), + map_slice.iter().map(|(&k, &v)| (k, v)), + ); + itertools::assert_equal(vec_slice.iter().map(|(k, _)| k), map_slice.keys()); + itertools::assert_equal(vec_slice.iter().map(|(_, v)| v), map_slice.values()); + } + + let vec: Vec<(i32, i32)> = (0..10).map(|i| (i, i * i)).collect(); + let map: IndexMap = vec.iter().cloned().collect(); + let slice = map.as_slice(); + + // RangeFull + check(&vec[..], &map[..], &slice[..]); + + for i in 0usize..10 { + // Index + assert_eq!(vec[i].1, map[i]); + assert_eq!(vec[i].1, slice[i]); + assert_eq!(map[&(i as i32)], map[i]); + assert_eq!(map[&(i as i32)], slice[i]); + + // RangeFrom + check(&vec[i..], &map[i..], &slice[i..]); + + // RangeTo + check(&vec[..i], &map[..i], &slice[..i]); + + // RangeToInclusive + check(&vec[..=i], &map[..=i], &slice[..=i]); + + // (Bound, Bound) + let bounds = (Bound::Excluded(i), Bound::Unbounded); + check(&vec[i + 1..], &map[bounds], &slice[bounds]); + + for j in i..=10 { + // Range + check(&vec[i..j], &map[i..j], &slice[i..j]); + } + + for j in i..10 { + // RangeInclusive + check(&vec[i..=j], &map[i..=j], &slice[i..=j]); + } + } + } + + #[test] + fn slice_index_mut() { + fn check_mut( + vec_slice: &[(i32, i32)], + map_slice: &mut Slice, + sub_slice: &mut Slice, + ) { + assert_eq!(map_slice, sub_slice); + itertools::assert_equal( + vec_slice.iter().copied(), + map_slice.iter_mut().map(|(&k, &mut v)| (k, v)), + ); + itertools::assert_equal( + vec_slice.iter().map(|&(_, v)| v), + map_slice.values_mut().map(|&mut v| v), + ); + } + + let vec: Vec<(i32, i32)> = (0..10).map(|i| (i, i * i)).collect(); + let mut map: IndexMap = vec.iter().cloned().collect(); + let mut map2 = map.clone(); + let slice = map2.as_mut_slice(); + + // RangeFull + check_mut(&vec[..], &mut map[..], &mut slice[..]); + + for i in 0usize..10 { + // IndexMut + assert_eq!(&mut map[i], &mut slice[i]); + + // RangeFrom + check_mut(&vec[i..], &mut map[i..], &mut slice[i..]); + + // RangeTo + check_mut(&vec[..i], &mut map[..i], &mut slice[..i]); + + // RangeToInclusive + check_mut(&vec[..=i], &mut map[..=i], &mut slice[..=i]); + + // (Bound, Bound) + let bounds = (Bound::Excluded(i), Bound::Unbounded); + check_mut(&vec[i + 1..], &mut map[bounds], &mut slice[bounds]); + + for j in i..=10 { + // Range + check_mut(&vec[i..j], &mut map[i..j], &mut slice[i..j]); + } + + for j in i..10 { + // RangeInclusive + check_mut(&vec[i..=j], &mut map[i..=j], &mut slice[i..=j]); + } + } + } +} diff --git a/third_party/rust/indexmap/src/map/tests.rs b/third_party/rust/indexmap/src/map/tests.rs new file mode 100644 index 0000000000..bba78ff54c --- /dev/null +++ b/third_party/rust/indexmap/src/map/tests.rs @@ -0,0 +1,727 @@ +use super::*; +use std::string::String; + +#[test] +fn it_works() { + let mut map = IndexMap::new(); + assert_eq!(map.is_empty(), true); + map.insert(1, ()); + map.insert(1, ()); + assert_eq!(map.len(), 1); + assert!(map.get(&1).is_some()); + assert_eq!(map.is_empty(), false); +} + +#[test] +fn new() { + let map = IndexMap::::new(); + println!("{:?}", map); + assert_eq!(map.capacity(), 0); + assert_eq!(map.len(), 0); + assert_eq!(map.is_empty(), true); +} + +#[test] +fn insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(map.len(), i); + map.insert(elt, elt); + assert_eq!(map.len(), i + 1); + assert_eq!(map.get(&elt), Some(&elt)); + assert_eq!(map[&elt], elt); + } + println!("{:?}", map); + + for &elt in ¬_present { + assert!(map.get(&elt).is_none()); + } +} + +#[test] +fn insert_full() { + let insert = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(map.len(), i); + let (index, existing) = map.insert_full(elt, elt); + assert_eq!(existing, None); + assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); + assert_eq!(map.len(), i + 1); + } + + let len = map.len(); + for &elt in &present { + let (index, existing) = map.insert_full(elt, elt); + assert_eq!(existing, Some(elt)); + assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); + assert_eq!(map.len(), len); + } +} + +#[test] +fn insert_2() { + let mut map = IndexMap::with_capacity(16); + + let mut keys = vec![]; + keys.extend(0..16); + keys.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &keys { + let old_map = map.clone(); + map.insert(i, ()); + for key in old_map.keys() { + if map.get(key).is_none() { + println!("old_map: {:?}", old_map); + println!("map: {:?}", map); + panic!("did not find {} in map", key); + } + } + } + + for &i in &keys { + assert!(map.get(&i).is_some(), "did not find {}", i); + } +} + +#[test] +fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, ()); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().zip(map.keys()) { + assert_eq!(a, b); + } + for (i, k) in (0..insert.len()).zip(map.keys()) { + assert_eq!(map.get_index(i).unwrap().0, k); + } +} + +#[test] +fn shift_insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.shift_insert(0, elt, ()); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().rev().zip(map.keys()) { + assert_eq!(a, b); + } + for (i, k) in (0..insert.len()).zip(map.keys()) { + assert_eq!(map.get_index(i).unwrap().0, k); + } + + // "insert" that moves an existing entry + map.shift_insert(0, insert[0], ()); + assert_eq!(map.keys().count(), insert.len()); + assert_eq!(insert[0], map.keys()[0]); + for (a, b) in insert[1..].iter().rev().zip(map.keys().skip(1)) { + assert_eq!(a, b); + } +} + +#[test] +fn grow() { + let insert = [0, 4, 2, 12, 8, 7, 11]; + let not_present = [1, 3, 6, 9, 10]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(map.len(), i); + map.insert(elt, elt); + assert_eq!(map.len(), i + 1); + assert_eq!(map.get(&elt), Some(&elt)); + assert_eq!(map[&elt], elt); + } + + println!("{:?}", map); + for &elt in &insert { + map.insert(elt * 10, elt); + } + for &elt in &insert { + map.insert(elt * 100, elt); + } + for (i, &elt) in insert.iter().cycle().enumerate().take(100) { + map.insert(elt * 100 + i as i32, elt); + } + println!("{:?}", map); + for &elt in ¬_present { + assert!(map.get(&elt).is_none()); + } +} + +#[test] +fn reserve() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + map.reserve(100); + let capacity = map.capacity(); + assert!(capacity >= 100); + for i in 0..capacity { + assert_eq!(map.len(), i); + map.insert(i, i * i); + assert_eq!(map.len(), i + 1); + assert_eq!(map.capacity(), capacity); + assert_eq!(map.get(&i), Some(&(i * i))); + } + map.insert(capacity, std::usize::MAX); + assert_eq!(map.len(), capacity + 1); + assert!(map.capacity() > capacity); + assert_eq!(map.get(&capacity), Some(&std::usize::MAX)); +} + +#[test] +fn try_reserve() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + assert_eq!(map.try_reserve(100), Ok(())); + assert!(map.capacity() >= 100); + assert!(map.try_reserve(usize::MAX).is_err()); +} + +#[test] +fn shrink_to_fit() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + for i in 0..100 { + assert_eq!(map.len(), i); + map.insert(i, i * i); + assert_eq!(map.len(), i + 1); + assert!(map.capacity() >= i + 1); + assert_eq!(map.get(&i), Some(&(i * i))); + map.shrink_to_fit(); + assert_eq!(map.len(), i + 1); + assert_eq!(map.capacity(), i + 1); + assert_eq!(map.get(&i), Some(&(i * i))); + } +} + +#[test] +fn remove() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, elt); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().zip(map.keys()) { + assert_eq!(a, b); + } + + let remove_fail = [99, 77]; + let remove = [4, 12, 8, 7]; + + for &key in &remove_fail { + assert!(map.swap_remove_full(&key).is_none()); + } + println!("{:?}", map); + for &key in &remove { + //println!("{:?}", map); + let index = map.get_full(&key).unwrap().0; + assert_eq!(map.swap_remove_full(&key), Some((index, key, key))); + } + println!("{:?}", map); + + for key in &insert { + assert_eq!(map.get(key).is_some(), !remove.contains(key)); + } + assert_eq!(map.len(), insert.len() - remove.len()); + assert_eq!(map.keys().count(), insert.len() - remove.len()); +} + +#[test] +fn remove_to_empty() { + let mut map = indexmap! { 0 => 0, 4 => 4, 5 => 5 }; + map.swap_remove(&5).unwrap(); + map.swap_remove(&4).unwrap(); + map.swap_remove(&0).unwrap(); + assert!(map.is_empty()); +} + +#[test] +fn swap_remove_index() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, elt * 2); + } + + let mut vector = insert.to_vec(); + let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; + + // check that the same swap remove sequence on vec and map + // have the same result. + for &rm in remove_sequence { + let out_vec = vector.swap_remove(rm); + let (out_map, _) = map.swap_remove_index(rm).unwrap(); + assert_eq!(out_vec, out_map); + } + assert_eq!(vector.len(), map.len()); + for (a, b) in vector.iter().zip(map.keys()) { + assert_eq!(a, b); + } +} + +#[test] +fn partial_eq_and_eq() { + let mut map_a = IndexMap::new(); + map_a.insert(1, "1"); + map_a.insert(2, "2"); + let mut map_b = map_a.clone(); + assert_eq!(map_a, map_b); + map_b.swap_remove(&1); + assert_ne!(map_a, map_b); + + let map_c: IndexMap<_, String> = map_b.into_iter().map(|(k, v)| (k, v.into())).collect(); + assert_ne!(map_a, map_c); + assert_ne!(map_c, map_a); +} + +#[test] +fn extend() { + let mut map = IndexMap::new(); + map.extend(vec![(&1, &2), (&3, &4)]); + map.extend(vec![(5, 6)]); + assert_eq!( + map.into_iter().collect::>(), + vec![(1, 2), (3, 4), (5, 6)] + ); +} + +#[test] +fn entry() { + let mut map = IndexMap::new(); + + map.insert(1, "1"); + map.insert(2, "2"); + { + let e = map.entry(3); + assert_eq!(e.index(), 2); + let e = e.or_insert("3"); + assert_eq!(e, &"3"); + } + + let e = map.entry(2); + assert_eq!(e.index(), 1); + assert_eq!(e.key(), &2); + match e { + Entry::Occupied(ref e) => assert_eq!(e.get(), &"2"), + Entry::Vacant(_) => panic!(), + } + assert_eq!(e.or_insert("4"), &"2"); +} + +#[test] +fn entry_and_modify() { + let mut map = IndexMap::new(); + + map.insert(1, "1"); + map.entry(1).and_modify(|x| *x = "2"); + assert_eq!(Some(&"2"), map.get(&1)); + + map.entry(2).and_modify(|x| *x = "doesn't exist"); + assert_eq!(None, map.get(&2)); +} + +#[test] +fn entry_or_default() { + let mut map = IndexMap::new(); + + #[derive(Debug, PartialEq)] + enum TestEnum { + DefaultValue, + NonDefaultValue, + } + + impl Default for TestEnum { + fn default() -> Self { + TestEnum::DefaultValue + } + } + + map.insert(1, TestEnum::NonDefaultValue); + assert_eq!(&mut TestEnum::NonDefaultValue, map.entry(1).or_default()); + + assert_eq!(&mut TestEnum::DefaultValue, map.entry(2).or_default()); +} + +#[test] +fn occupied_entry_key() { + // These keys match hash and equality, but their addresses are distinct. + let (k1, k2) = (&mut 1, &mut 1); + let k1_ptr = k1 as *const i32; + let k2_ptr = k2 as *const i32; + assert_ne!(k1_ptr, k2_ptr); + + let mut map = IndexMap::new(); + map.insert(k1, "value"); + match map.entry(k2) { + Entry::Occupied(ref e) => { + // `OccupiedEntry::key` should reference the key in the map, + // not the key that was used to find the entry. + let ptr = *e.key() as *const i32; + assert_eq!(ptr, k1_ptr); + assert_ne!(ptr, k2_ptr); + } + Entry::Vacant(_) => panic!(), + } +} + +#[test] +fn get_index_entry() { + let mut map = IndexMap::new(); + + assert!(map.get_index_entry(0).is_none()); + + map.insert(0, "0"); + map.insert(1, "1"); + map.insert(2, "2"); + map.insert(3, "3"); + + assert!(map.get_index_entry(4).is_none()); + + { + let e = map.get_index_entry(1).unwrap(); + assert_eq!(*e.key(), 1); + assert_eq!(*e.get(), "1"); + assert_eq!(e.swap_remove(), "1"); + } + + { + let mut e = map.get_index_entry(1).unwrap(); + assert_eq!(*e.key(), 3); + assert_eq!(*e.get(), "3"); + assert_eq!(e.insert("4"), "3"); + } + + assert_eq!(*map.get(&3).unwrap(), "4"); +} + +#[test] +fn keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let keys: Vec = map.into_keys().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +fn values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: IndexMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value *= 2 + } + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); +} + +#[test] +fn into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let values: Vec = map.into_values().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +#[cfg(feature = "std")] +fn from_array() { + let map = IndexMap::from([(1, 2), (3, 4)]); + let mut expected = IndexMap::new(); + expected.insert(1, 2); + expected.insert(3, 4); + + assert_eq!(map, expected) +} + +#[test] +fn iter_default() { + struct K; + struct V; + fn assert_default() + where + T: Default + Iterator, + { + assert!(T::default().next().is_none()); + } + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); +} + +#[test] +fn test_binary_search_by() { + // adapted from std's test for binary_search + let b: IndexMap<_, i32> = [] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(0)); + + let b: IndexMap<_, i32> = [4] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&3)), Err(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&4)), Ok(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(1)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Ok(4)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&9)), Err(6)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Ok(5)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Err(5)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&0)), Err(0)); + + let b: IndexMap<_, i32> = [1, 3, 3, 3, 7] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&0)), Err(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&1)), Ok(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&2)), Err(1)); + assert!(match b.binary_search_by(|_, x| x.cmp(&3)) { + Ok(1..=3) => true, + _ => false, + }); + assert!(match b.binary_search_by(|_, x| x.cmp(&3)) { + Ok(1..=3) => true, + _ => false, + }); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&4)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Ok(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Err(5)); +} + +#[test] +fn test_binary_search_by_key() { + // adapted from std's test for binary_search + let b: IndexMap<_, i32> = [] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(0)); + + let b: IndexMap<_, i32> = [4] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&3, |_, &x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&4, |_, &x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(1)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Ok(4)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&9, |_, &x| x), Err(6)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Ok(5)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Err(5)); + assert_eq!(b.binary_search_by_key(&0, |_, &x| x), Err(0)); + + let b: IndexMap<_, i32> = [1, 3, 3, 3, 7] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&0, |_, &x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&1, |_, &x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&2, |_, &x| x), Err(1)); + assert!(match b.binary_search_by_key(&3, |_, &x| x) { + Ok(1..=3) => true, + _ => false, + }); + assert!(match b.binary_search_by_key(&3, |_, &x| x) { + Ok(1..=3) => true, + _ => false, + }); + assert_eq!(b.binary_search_by_key(&4, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Ok(4)); + assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Err(5)); +} + +#[test] +fn test_partition_point() { + // adapted from std's test for partition_point + let b: IndexMap<_, i32> = [] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 5), 0); + + let b: IndexMap<_, i32> = [4] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 3), 0); + assert_eq!(b.partition_point(|_, &x| x < 4), 0); + assert_eq!(b.partition_point(|_, &x| x < 5), 1); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 5), 3); + assert_eq!(b.partition_point(|_, &x| x < 6), 3); + assert_eq!(b.partition_point(|_, &x| x < 7), 4); + assert_eq!(b.partition_point(|_, &x| x < 8), 4); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 9), 6); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 6), 3); + assert_eq!(b.partition_point(|_, &x| x < 5), 3); + assert_eq!(b.partition_point(|_, &x| x < 8), 5); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 7), 5); + assert_eq!(b.partition_point(|_, &x| x < 0), 0); + + let b: IndexMap<_, i32> = [1, 3, 3, 3, 7] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 0), 0); + assert_eq!(b.partition_point(|_, &x| x < 1), 0); + assert_eq!(b.partition_point(|_, &x| x < 2), 1); + assert_eq!(b.partition_point(|_, &x| x < 3), 1); + assert_eq!(b.partition_point(|_, &x| x < 4), 4); + assert_eq!(b.partition_point(|_, &x| x < 5), 4); + assert_eq!(b.partition_point(|_, &x| x < 6), 4); + assert_eq!(b.partition_point(|_, &x| x < 7), 4); + assert_eq!(b.partition_point(|_, &x| x < 8), 5); +} diff --git a/third_party/rust/indexmap/src/mutable_keys.rs b/third_party/rust/indexmap/src/mutable_keys.rs deleted file mode 100644 index 35a90c4723..0000000000 --- a/third_party/rust/indexmap/src/mutable_keys.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::hash::{BuildHasher, Hash}; - -use super::{Equivalent, IndexMap}; - -pub struct PrivateMarker {} - -/// Opt-in mutable access to keys. -/// -/// These methods expose `&mut K`, mutable references to the key as it is stored -/// in the map. -/// You are allowed to modify the keys in the hashmap **if the modification -/// does not change the key’s hash and equality**. -/// -/// If keys are modified erroneously, you can no longer look them up. -/// This is sound (memory safe) but a logical error hazard (just like -/// implementing PartialEq, Eq, or Hash incorrectly would be). -/// -/// `use` this trait to enable its methods for `IndexMap`. -pub trait MutableKeys { - type Key; - type Value; - - /// Return item index, mutable reference to key and value - fn get_full_mut2( - &mut self, - key: &Q, - ) -> Option<(usize, &mut Self::Key, &mut Self::Value)> - where - Q: Hash + Equivalent; - - /// Scan through each key-value pair in the map and keep those where the - /// closure `keep` returns `true`. - /// - /// The elements are visited in order, and remaining elements keep their - /// order. - /// - /// Computes in **O(n)** time (average). - fn retain2(&mut self, keep: F) - where - F: FnMut(&mut Self::Key, &mut Self::Value) -> bool; - - /// This method is not useful in itself – it is there to “seal” the trait - /// for external implementation, so that we can add methods without - /// causing breaking changes. - fn __private_marker(&self) -> PrivateMarker; -} - -/// Opt-in mutable access to keys. -/// -/// See [`MutableKeys`](trait.MutableKeys.html) for more information. -impl MutableKeys for IndexMap -where - K: Eq + Hash, - S: BuildHasher, -{ - type Key = K; - type Value = V; - fn get_full_mut2(&mut self, key: &Q) -> Option<(usize, &mut K, &mut V)> - where - Q: Hash + Equivalent, - { - self.get_full_mut2_impl(key) - } - - fn retain2(&mut self, keep: F) - where - F: FnMut(&mut K, &mut V) -> bool, - { - self.retain_mut(keep) - } - - fn __private_marker(&self) -> PrivateMarker { - PrivateMarker {} - } -} diff --git a/third_party/rust/indexmap/src/rayon/map.rs b/third_party/rust/indexmap/src/rayon/map.rs index 8819f13ed7..8236cf70f0 100644 --- a/third_party/rust/indexmap/src/rayon/map.rs +++ b/third_party/rust/indexmap/src/rayon/map.rs @@ -1,25 +1,24 @@ -//! Parallel iterator types for `IndexMap` with [rayon](https://docs.rs/rayon/1.0/rayon). +//! Parallel iterator types for [`IndexMap`] with [`rayon`][::rayon]. //! //! You will rarely need to interact with this module directly unless you need to name one of the //! iterator types. -//! -//! Requires crate feature `"rayon"` use super::collect; use rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; use rayon::prelude::*; use crate::vec::Vec; +use alloc::boxed::Box; use core::cmp::Ordering; use core::fmt; use core::hash::{BuildHasher, Hash}; use core::ops::RangeBounds; +use crate::map::Slice; use crate::Bucket; use crate::Entries; use crate::IndexMap; -/// Requires crate feature `"rayon"`. impl IntoParallelIterator for IndexMap where K: Send, @@ -35,13 +34,25 @@ where } } -/// A parallel owning iterator over the entries of a `IndexMap`. -/// -/// This `struct` is created by the [`into_par_iter`] method on [`IndexMap`] -/// (provided by rayon's `IntoParallelIterator` trait). See its documentation for more. +impl IntoParallelIterator for Box> +where + K: Send, + V: Send, +{ + type Item = (K, V); + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +/// A parallel owning iterator over the entries of an [`IndexMap`]. /// -/// [`into_par_iter`]: ../struct.IndexMap.html#method.into_par_iter -/// [`IndexMap`]: ../struct.IndexMap.html +/// This `struct` is created by the [`IndexMap::into_par_iter`] method +/// (provided by rayon's [`IntoParallelIterator`] trait). See its documentation for more. pub struct IntoParIter { entries: Vec>, } @@ -63,7 +74,6 @@ impl IndexedParallelIterator for IntoParIter { indexed_parallel_iterator_methods!(Bucket::key_value); } -/// Requires crate feature `"rayon"`. impl<'a, K, V, S> IntoParallelIterator for &'a IndexMap where K: Sync, @@ -79,13 +89,27 @@ where } } -/// A parallel iterator over the entries of a `IndexMap`. +impl<'a, K, V> IntoParallelIterator for &'a Slice +where + K: Sync, + V: Sync, +{ + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: &self.entries, + } + } +} + +/// A parallel iterator over the entries of an [`IndexMap`]. /// -/// This `struct` is created by the [`par_iter`] method on [`IndexMap`] -/// (provided by rayon's `IntoParallelRefIterator` trait). See its documentation for more. +/// This `struct` is created by the [`IndexMap::par_iter`] method +/// (provided by rayon's [`IntoParallelRefIterator`] trait). See its documentation for more. /// -/// [`par_iter`]: ../struct.IndexMap.html#method.par_iter -/// [`IndexMap`]: ../struct.IndexMap.html +/// [`IndexMap::par_iter`]: ../struct.IndexMap.html#method.par_iter pub struct ParIter<'a, K, V> { entries: &'a [Bucket], } @@ -113,7 +137,6 @@ impl IndexedParallelIterator for ParIter<'_, K, V> { indexed_parallel_iterator_methods!(Bucket::refs); } -/// Requires crate feature `"rayon"`. impl<'a, K, V, S> IntoParallelIterator for &'a mut IndexMap where K: Sync + Send, @@ -129,13 +152,27 @@ where } } -/// A parallel mutable iterator over the entries of a `IndexMap`. +impl<'a, K, V> IntoParallelIterator for &'a mut Slice +where + K: Sync + Send, + V: Send, +{ + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + entries: &mut self.entries, + } + } +} + +/// A parallel mutable iterator over the entries of an [`IndexMap`]. /// -/// This `struct` is created by the [`par_iter_mut`] method on [`IndexMap`] -/// (provided by rayon's `IntoParallelRefMutIterator` trait). See its documentation for more. +/// This `struct` is created by the [`IndexMap::par_iter_mut`] method +/// (provided by rayon's [`IntoParallelRefMutIterator`] trait). See its documentation for more. /// -/// [`par_iter_mut`]: ../struct.IndexMap.html#method.par_iter_mut -/// [`IndexMap`]: ../struct.IndexMap.html +/// [`IndexMap::par_iter_mut`]: ../struct.IndexMap.html#method.par_iter_mut pub struct ParIterMut<'a, K, V> { entries: &'a mut [Bucket], } @@ -157,7 +194,6 @@ impl IndexedParallelIterator for ParIterMut<'_, K, V> { indexed_parallel_iterator_methods!(Bucket::ref_mut); } -/// Requires crate feature `"rayon"`. impl<'a, K, V, S> ParallelDrainRange for &'a mut IndexMap where K: Send, @@ -173,13 +209,12 @@ where } } -/// A parallel draining iterator over the entries of a `IndexMap`. +/// A parallel draining iterator over the entries of an [`IndexMap`]. /// -/// This `struct` is created by the [`par_drain`] method on [`IndexMap`] -/// (provided by rayon's `ParallelDrainRange` trait). See its documentation for more. +/// This `struct` is created by the [`IndexMap::par_drain`] method +/// (provided by rayon's [`ParallelDrainRange`] trait). See its documentation for more. /// -/// [`par_drain`]: ../struct.IndexMap.html#method.par_drain -/// [`IndexMap`]: ../struct.IndexMap.html +/// [`IndexMap::par_drain`]: ../struct.IndexMap.html#method.par_drain pub struct ParDrain<'a, K: Send, V: Send> { entries: rayon::vec::Drain<'a, Bucket>, } @@ -225,6 +260,37 @@ where } } +/// Parallel iterator methods and other parallel methods. +/// +/// The following methods **require crate feature `"rayon"`**. +/// +/// See also the `IntoParallelIterator` implementations. +impl Slice +where + K: Sync, + V: Sync, +{ + /// Return a parallel iterator over the keys of the map slice. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the slice is still preserved for operations like `reduce` and `collect`. + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + entries: &self.entries, + } + } + + /// Return a parallel iterator over the values of the map slice. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the slice is still preserved for operations like `reduce` and `collect`. + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + entries: &self.entries, + } + } +} + impl IndexMap where K: Hash + Eq + Sync, @@ -246,13 +312,10 @@ where } } -/// A parallel iterator over the keys of a `IndexMap`. +/// A parallel iterator over the keys of an [`IndexMap`]. /// -/// This `struct` is created by the [`par_keys`] method on [`IndexMap`]. See its -/// documentation for more. -/// -/// [`par_keys`]: ../struct.IndexMap.html#method.par_keys -/// [`IndexMap`]: ../struct.IndexMap.html +/// This `struct` is created by the [`IndexMap::par_keys`] method. +/// See its documentation for more. pub struct ParKeys<'a, K, V> { entries: &'a [Bucket], } @@ -280,13 +343,10 @@ impl IndexedParallelIterator for ParKeys<'_, K, V> { indexed_parallel_iterator_methods!(Bucket::key_ref); } -/// A parallel iterator over the values of a `IndexMap`. -/// -/// This `struct` is created by the [`par_values`] method on [`IndexMap`]. See its -/// documentation for more. +/// A parallel iterator over the values of an [`IndexMap`]. /// -/// [`par_values`]: ../struct.IndexMap.html#method.par_values -/// [`IndexMap`]: ../struct.IndexMap.html +/// This `struct` is created by the [`IndexMap::par_values`] method. +/// See its documentation for more. pub struct ParValues<'a, K, V> { entries: &'a [Bucket], } @@ -314,7 +374,6 @@ impl IndexedParallelIterator for ParValues<'_, K, V> { indexed_parallel_iterator_methods!(Bucket::value_ref); } -/// Requires crate feature `"rayon"`. impl IndexMap where K: Send, @@ -331,11 +390,26 @@ where } } +impl Slice +where + K: Send, + V: Send, +{ + /// Return a parallel iterator over mutable references to the the values of the map slice. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the slice is still preserved for operations like `reduce` and `collect`. + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + entries: &mut self.entries, + } + } +} + impl IndexMap where - K: Hash + Eq + Send, + K: Send, V: Send, - S: BuildHasher, { /// Sort the map’s key-value pairs in parallel, by the default ordering of the keys. pub fn par_sort_keys(&mut self) @@ -406,15 +480,24 @@ where entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); IntoParIter { entries } } + + /// Sort the map’s key-value pairs in place and in parallel, using a sort-key extraction + /// function. + pub fn par_sort_by_cached_key(&mut self, sort_key: F) + where + T: Ord + Send, + F: Fn(&K, &V) -> T + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_by_cached_key(move |a| sort_key(&a.key, &a.value)); + }); + } } -/// A parallel mutable iterator over the values of a `IndexMap`. -/// -/// This `struct` is created by the [`par_values_mut`] method on [`IndexMap`]. See its -/// documentation for more. +/// A parallel mutable iterator over the values of an [`IndexMap`]. /// -/// [`par_values_mut`]: ../struct.IndexMap.html#method.par_values_mut -/// [`IndexMap`]: ../struct.IndexMap.html +/// This `struct` is created by the [`IndexMap::par_values_mut`] method. +/// See its documentation for more. pub struct ParValuesMut<'a, K, V> { entries: &'a mut [Bucket], } @@ -436,7 +519,6 @@ impl IndexedParallelIterator for ParValuesMut<'_, K, V> { indexed_parallel_iterator_methods!(Bucket::value_mut); } -/// Requires crate feature `"rayon"`. impl FromParallelIterator<(K, V)> for IndexMap where K: Eq + Hash + Send, @@ -457,7 +539,6 @@ where } } -/// Requires crate feature `"rayon"`. impl ParallelExtend<(K, V)> for IndexMap where K: Eq + Hash + Send, @@ -474,7 +555,6 @@ where } } -/// Requires crate feature `"rayon"`. impl<'a, K: 'a, V: 'a, S> ParallelExtend<(&'a K, &'a V)> for IndexMap where K: Copy + Eq + Hash + Send + Sync, diff --git a/third_party/rust/indexmap/src/rayon/mod.rs b/third_party/rust/indexmap/src/rayon/mod.rs index ebb1ac2d1e..1d21569c18 100644 --- a/third_party/rust/indexmap/src/rayon/mod.rs +++ b/third_party/rust/indexmap/src/rayon/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "rayon")))] + use rayon::prelude::*; use alloc::collections::LinkedList; diff --git a/third_party/rust/indexmap/src/rayon/set.rs b/third_party/rust/indexmap/src/rayon/set.rs index 6749dc0d7f..3904234b20 100644 --- a/third_party/rust/indexmap/src/rayon/set.rs +++ b/third_party/rust/indexmap/src/rayon/set.rs @@ -1,26 +1,25 @@ -//! Parallel iterator types for `IndexSet` with [rayon](https://docs.rs/rayon/1.0/rayon). +//! Parallel iterator types for [`IndexSet`] with [rayon][::rayon]. //! //! You will rarely need to interact with this module directly unless you need to name one of the //! iterator types. -//! -//! Requires crate feature `"rayon"`. use super::collect; use rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; use rayon::prelude::*; use crate::vec::Vec; +use alloc::boxed::Box; use core::cmp::Ordering; use core::fmt; use core::hash::{BuildHasher, Hash}; use core::ops::RangeBounds; +use crate::set::Slice; use crate::Entries; use crate::IndexSet; type Bucket = crate::Bucket; -/// Requires crate feature `"rayon"`. impl IntoParallelIterator for IndexSet where T: Send, @@ -35,13 +34,24 @@ where } } -/// A parallel owning iterator over the items of a `IndexSet`. -/// -/// This `struct` is created by the [`into_par_iter`] method on [`IndexSet`] -/// (provided by rayon's `IntoParallelIterator` trait). See its documentation for more. +impl IntoParallelIterator for Box> +where + T: Send, +{ + type Item = T; + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +/// A parallel owning iterator over the items of an [`IndexSet`]. /// -/// [`IndexSet`]: ../struct.IndexSet.html -/// [`into_par_iter`]: ../struct.IndexSet.html#method.into_par_iter +/// This `struct` is created by the [`IndexSet::into_par_iter`] method +/// (provided by rayon's [`IntoParallelIterator`] trait). See its documentation for more. pub struct IntoParIter { entries: Vec>, } @@ -63,7 +73,6 @@ impl IndexedParallelIterator for IntoParIter { indexed_parallel_iterator_methods!(Bucket::key); } -/// Requires crate feature `"rayon"`. impl<'a, T, S> IntoParallelIterator for &'a IndexSet where T: Sync, @@ -78,13 +87,26 @@ where } } -/// A parallel iterator over the items of a `IndexSet`. +impl<'a, T> IntoParallelIterator for &'a Slice +where + T: Sync, +{ + type Item = &'a T; + type Iter = ParIter<'a, T>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: &self.entries, + } + } +} + +/// A parallel iterator over the items of an [`IndexSet`]. /// -/// This `struct` is created by the [`par_iter`] method on [`IndexSet`] -/// (provided by rayon's `IntoParallelRefIterator` trait). See its documentation for more. +/// This `struct` is created by the [`IndexSet::par_iter`] method +/// (provided by rayon's [`IntoParallelRefIterator`] trait). See its documentation for more. /// -/// [`IndexSet`]: ../struct.IndexSet.html -/// [`par_iter`]: ../struct.IndexSet.html#method.par_iter +/// [`IndexSet::par_iter`]: ../struct.IndexSet.html#method.par_iter pub struct ParIter<'a, T> { entries: &'a [Bucket], } @@ -112,7 +134,6 @@ impl IndexedParallelIterator for ParIter<'_, T> { indexed_parallel_iterator_methods!(Bucket::key_ref); } -/// Requires crate feature `"rayon"`. impl<'a, T, S> ParallelDrainRange for &'a mut IndexSet where T: Send, @@ -127,13 +148,12 @@ where } } -/// A parallel draining iterator over the items of a `IndexSet`. +/// A parallel draining iterator over the items of an [`IndexSet`]. /// -/// This `struct` is created by the [`par_drain`] method on [`IndexSet`] -/// (provided by rayon's `ParallelDrainRange` trait). See its documentation for more. +/// This `struct` is created by the [`IndexSet::par_drain`] method +/// (provided by rayon's [`ParallelDrainRange`] trait). See its documentation for more. /// -/// [`par_drain`]: ../struct.IndexSet.html#method.par_drain -/// [`IndexSet`]: ../struct.IndexSet.html +/// [`IndexSet::par_drain`]: ../struct.IndexSet.html#method.par_drain pub struct ParDrain<'a, T: Send> { entries: rayon::vec::Drain<'a, Bucket>, } @@ -269,13 +289,10 @@ where } } -/// A parallel iterator producing elements in the difference of `IndexSet`s. +/// A parallel iterator producing elements in the difference of [`IndexSet`]s. /// -/// This `struct` is created by the [`par_difference`] method on [`IndexSet`]. +/// This `struct` is created by the [`IndexSet::par_difference`] method. /// See its documentation for more. -/// -/// [`IndexSet`]: ../struct.IndexSet.html -/// [`par_difference`]: ../struct.IndexSet.html#method.par_difference pub struct ParDifference<'a, T, S1, S2> { set1: &'a IndexSet, set2: &'a IndexSet, @@ -320,13 +337,10 @@ where } } -/// A parallel iterator producing elements in the intersection of `IndexSet`s. +/// A parallel iterator producing elements in the intersection of [`IndexSet`]s. /// -/// This `struct` is created by the [`par_intersection`] method on [`IndexSet`]. +/// This `struct` is created by the [`IndexSet::par_intersection`] method. /// See its documentation for more. -/// -/// [`IndexSet`]: ../struct.IndexSet.html -/// [`par_intersection`]: ../struct.IndexSet.html#method.par_intersection pub struct ParIntersection<'a, T, S1, S2> { set1: &'a IndexSet, set2: &'a IndexSet, @@ -371,13 +385,10 @@ where } } -/// A parallel iterator producing elements in the symmetric difference of `IndexSet`s. -/// -/// This `struct` is created by the [`par_symmetric_difference`] method on -/// [`IndexSet`]. See its documentation for more. +/// A parallel iterator producing elements in the symmetric difference of [`IndexSet`]s. /// -/// [`IndexSet`]: ../struct.IndexSet.html -/// [`par_symmetric_difference`]: ../struct.IndexSet.html#method.par_symmetric_difference +/// This `struct` is created by the [`IndexSet::par_symmetric_difference`] method. +/// See its documentation for more. pub struct ParSymmetricDifference<'a, T, S1, S2> { set1: &'a IndexSet, set2: &'a IndexSet, @@ -422,13 +433,10 @@ where } } -/// A parallel iterator producing elements in the union of `IndexSet`s. +/// A parallel iterator producing elements in the union of [`IndexSet`]s. /// -/// This `struct` is created by the [`par_union`] method on [`IndexSet`]. +/// This `struct` is created by the [`IndexSet::par_union`] method. /// See its documentation for more. -/// -/// [`IndexSet`]: ../struct.IndexSet.html -/// [`par_union`]: ../struct.IndexSet.html#method.par_union pub struct ParUnion<'a, T, S1, S2> { set1: &'a IndexSet, set2: &'a IndexSet, @@ -476,8 +484,7 @@ where /// The following methods **require crate feature `"rayon"`**. impl IndexSet where - T: Hash + Eq + Send, - S: BuildHasher + Send, + T: Send, { /// Sort the set’s values in parallel by their default ordering. pub fn par_sort(&mut self) @@ -540,9 +547,19 @@ where entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &b.key)); IntoParIter { entries } } + + /// Sort the set’s values in place and in parallel, using a key extraction function. + pub fn par_sort_by_cached_key(&mut self, sort_key: F) + where + K: Ord + Send, + F: Fn(&T) -> K + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_by_cached_key(move |a| sort_key(&a.key)); + }); + } } -/// Requires crate feature `"rayon"`. impl FromParallelIterator for IndexSet where T: Eq + Hash + Send, @@ -562,7 +579,6 @@ where } } -/// Requires crate feature `"rayon"`. impl ParallelExtend for IndexSet where T: Eq + Hash + Send, @@ -578,7 +594,6 @@ where } } -/// Requires crate feature `"rayon"`. impl<'a, T: 'a, S> ParallelExtend<&'a T> for IndexSet where T: Copy + Eq + Hash + Send + Sync, diff --git a/third_party/rust/indexmap/src/serde.rs b/third_party/rust/indexmap/src/serde.rs index c6dd6d5ea0..25546d531b 100644 --- a/third_party/rust/indexmap/src/serde.rs +++ b/third_party/rust/indexmap/src/serde.rs @@ -1,3 +1,5 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "serde")))] + use serde::de::value::{MapDeserializer, SeqDeserializer}; use serde::de::{ Deserialize, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor, @@ -7,15 +9,30 @@ use serde::ser::{Serialize, Serializer}; use core::fmt::{self, Formatter}; use core::hash::{BuildHasher, Hash}; use core::marker::PhantomData; +use core::{cmp, mem}; + +use crate::{Bucket, IndexMap, IndexSet}; + +/// Limit our preallocated capacity from a deserializer `size_hint()`. +/// +/// We do account for the `Bucket` overhead from its saved `hash` field, but we don't count the +/// `RawTable` allocation or the fact that its raw capacity will be rounded up to a power of two. +/// The "max" is an arbitrary choice anyway, not something that needs precise adherence. +/// +/// This is based on the internal `serde::de::size_hint::cautious(hint)` function. +pub(crate) fn cautious_capacity(hint: Option) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + + cmp::min( + hint.unwrap_or(0), + MAX_PREALLOC_BYTES / mem::size_of::>(), + ) +} -use crate::IndexMap; - -/// Requires crate feature `"serde"` or `"serde-1"` impl Serialize for IndexMap where - K: Serialize + Hash + Eq, + K: Serialize, V: Serialize, - S: BuildHasher, { fn serialize(&self, serializer: T) -> Result where @@ -43,8 +60,8 @@ where where A: MapAccess<'de>, { - let mut values = - IndexMap::with_capacity_and_hasher(map.size_hint().unwrap_or(0), S::default()); + let capacity = cautious_capacity::(map.size_hint()); + let mut values = IndexMap::with_capacity_and_hasher(capacity, S::default()); while let Some((key, value)) = map.next_entry()? { values.insert(key, value); @@ -54,7 +71,6 @@ where } } -/// Requires crate feature `"serde"` or `"serde-1"` impl<'de, K, V, S> Deserialize<'de> for IndexMap where K: Deserialize<'de> + Eq + Hash, @@ -83,13 +99,9 @@ where } } -use crate::IndexSet; - -/// Requires crate feature `"serde"` or `"serde-1"` impl Serialize for IndexSet where - T: Serialize + Hash + Eq, - S: BuildHasher, + T: Serialize, { fn serialize(&self, serializer: Se) -> Result where @@ -116,8 +128,8 @@ where where A: SeqAccess<'de>, { - let mut values = - IndexSet::with_capacity_and_hasher(seq.size_hint().unwrap_or(0), S::default()); + let capacity = cautious_capacity::(seq.size_hint()); + let mut values = IndexSet::with_capacity_and_hasher(capacity, S::default()); while let Some(value) = seq.next_element()? { values.insert(value); @@ -127,7 +139,6 @@ where } } -/// Requires crate feature `"serde"` or `"serde-1"` impl<'de, T, S> Deserialize<'de> for IndexSet where T: Deserialize<'de> + Eq + Hash, diff --git a/third_party/rust/indexmap/src/serde_seq.rs b/third_party/rust/indexmap/src/serde_seq.rs deleted file mode 100644 index d326a02e37..0000000000 --- a/third_party/rust/indexmap/src/serde_seq.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Functions to serialize and deserialize an `IndexMap` as an ordered sequence. -//! -//! The default `serde` implementation serializes `IndexMap` as a normal map, -//! but there is no guarantee that serialization formats will preserve the order -//! of the key-value pairs. This module serializes `IndexMap` as a sequence of -//! `(key, value)` elements instead, in order. -//! -//! This module may be used in a field attribute for derived implementations: -//! -//! ``` -//! # use indexmap::IndexMap; -//! # use serde_derive::{Deserialize, Serialize}; -//! #[derive(Deserialize, Serialize)] -//! struct Data { -//! #[serde(with = "indexmap::serde_seq")] -//! map: IndexMap, -//! // ... -//! } -//! ``` -//! -//! Requires crate feature `"serde"` or `"serde-1"` - -use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; -use serde::ser::{Serialize, Serializer}; - -use core::fmt::{self, Formatter}; -use core::hash::{BuildHasher, Hash}; -use core::marker::PhantomData; - -use crate::IndexMap; - -/// Serializes an `IndexMap` as an ordered sequence. -/// -/// This function may be used in a field attribute for deriving `Serialize`: -/// -/// ``` -/// # use indexmap::IndexMap; -/// # use serde_derive::Serialize; -/// #[derive(Serialize)] -/// struct Data { -/// #[serde(serialize_with = "indexmap::serde_seq::serialize")] -/// map: IndexMap, -/// // ... -/// } -/// ``` -/// -/// Requires crate feature `"serde"` or `"serde-1"` -pub fn serialize(map: &IndexMap, serializer: T) -> Result -where - K: Serialize + Hash + Eq, - V: Serialize, - S: BuildHasher, - T: Serializer, -{ - serializer.collect_seq(map) -} - -/// Visitor to deserialize a *sequenced* `IndexMap` -struct SeqVisitor(PhantomData<(K, V, S)>); - -impl<'de, K, V, S> Visitor<'de> for SeqVisitor -where - K: Deserialize<'de> + Eq + Hash, - V: Deserialize<'de>, - S: Default + BuildHasher, -{ - type Value = IndexMap; - - fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { - write!(formatter, "a sequenced map") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let capacity = seq.size_hint().unwrap_or(0); - let mut map = IndexMap::with_capacity_and_hasher(capacity, S::default()); - - while let Some((key, value)) = seq.next_element()? { - map.insert(key, value); - } - - Ok(map) - } -} - -/// Deserializes an `IndexMap` from an ordered sequence. -/// -/// This function may be used in a field attribute for deriving `Deserialize`: -/// -/// ``` -/// # use indexmap::IndexMap; -/// # use serde_derive::Deserialize; -/// #[derive(Deserialize)] -/// struct Data { -/// #[serde(deserialize_with = "indexmap::serde_seq::deserialize")] -/// map: IndexMap, -/// // ... -/// } -/// ``` -/// -/// Requires crate feature `"serde"` or `"serde-1"` -pub fn deserialize<'de, D, K, V, S>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, - K: Deserialize<'de> + Eq + Hash, - V: Deserialize<'de>, - S: Default + BuildHasher, -{ - deserializer.deserialize_seq(SeqVisitor(PhantomData)) -} diff --git a/third_party/rust/indexmap/src/set.rs b/third_party/rust/indexmap/src/set.rs index 3728947426..b5bd05f1bc 100644 --- a/third_party/rust/indexmap/src/set.rs +++ b/third_party/rust/indexmap/src/set.rs @@ -1,18 +1,32 @@ -//! A hash set implemented using `IndexMap` +//! A hash set implemented using [`IndexMap`] + +mod iter; +mod mutable; +mod slice; + +#[cfg(test)] +mod tests; + +pub use self::iter::{ + Difference, Drain, Intersection, IntoIter, Iter, Splice, SymmetricDifference, Union, +}; +pub use self::mutable::MutableValues; +pub use self::slice::Slice; #[cfg(feature = "rayon")] pub use crate::rayon::set as rayon; +use crate::TryReserveError; -#[cfg(has_std)] +#[cfg(feature = "std")] use std::collections::hash_map::RandomState; -use crate::vec::{self, Vec}; +use crate::util::try_simplify_range; +use alloc::boxed::Box; +use alloc::vec::Vec; use core::cmp::Ordering; use core::fmt; use core::hash::{BuildHasher, Hash}; -use core::iter::{Chain, FusedIterator}; use core::ops::{BitAnd, BitOr, BitXor, Index, RangeBounds, Sub}; -use core::slice; use super::{Entries, Equivalent, IndexMap}; @@ -21,8 +35,9 @@ type Bucket = super::Bucket; /// A hash set where the iteration order of the values is independent of their /// hash values. /// -/// The interface is closely compatible with the standard `HashSet`, but also -/// has additional features. +/// The interface is closely compatible with the standard +/// [`HashSet`][std::collections::HashSet], +/// but also has additional features. /// /// # Order /// @@ -33,11 +48,12 @@ type Bucket = super::Bucket; /// already present. /// /// All iterators traverse the set *in order*. Set operation iterators like -/// `union` produce a concatenated order, as do their matching "bitwise" +/// [`IndexSet::union`] produce a concatenated order, as do their matching "bitwise" /// operators. See their documentation for specifics. /// /// The insertion order is preserved, with **notable exceptions** like the -/// `.remove()` or `.swap_remove()` methods. Methods such as `.sort_by()` of +/// [`.remove()`][Self::remove] or [`.swap_remove()`][Self::swap_remove] methods. +/// Methods such as [`.sort_by()`][Self::sort_by] of /// course result in a new order, depending on the sorting order. /// /// # Indices @@ -46,6 +62,11 @@ type Bucket = super::Bucket; /// `0..self.len()`. For example, the method `.get_full` looks up the index for /// a value, and the method `.get_index` looks up the value by index. /// +/// # Complexity +/// +/// Internally, `IndexSet` just holds an [`IndexMap`](IndexMap). Thus the complexity +/// of the two are the same for most methods. +/// /// # Examples /// /// ``` @@ -59,11 +80,11 @@ type Bucket = super::Bucket; /// assert!(letters.contains(&'u')); /// assert!(!letters.contains(&'y')); /// ``` -#[cfg(has_std)] +#[cfg(feature = "std")] pub struct IndexSet { pub(crate) map: IndexMap, } -#[cfg(not(has_std))] +#[cfg(not(feature = "std"))] pub struct IndexSet { pub(crate) map: IndexMap, } @@ -114,17 +135,20 @@ impl fmt::Debug for IndexSet where T: fmt::Debug, { + #[cfg(not(feature = "test_debug"))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if cfg!(not(feature = "test_debug")) { - f.debug_set().entries(self.iter()).finish() - } else { - // Let the inner `IndexMap` print all of its details - f.debug_struct("IndexSet").field("map", &self.map).finish() - } + f.debug_set().entries(self.iter()).finish() + } + + #[cfg(feature = "test_debug")] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Let the inner `IndexMap` print all of its details + f.debug_struct("IndexSet").field("map", &self.map).finish() } } -#[cfg(has_std)] +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl IndexSet { /// Create a new set. (Does not allocate.) pub fn new() -> Self { @@ -165,6 +189,11 @@ impl IndexSet { } } + /// Return the number of elements the set can hold without reallocating. + /// + /// This number is a lower bound; the set might be able to hold more, + /// but is guaranteed to be able to hold at least this many. + /// /// Computes in **O(1)** time. pub fn capacity(&self) -> usize { self.map.capacity() @@ -191,9 +220,7 @@ impl IndexSet { /// Return an iterator over the values of the set, in their order pub fn iter(&self) -> Iter<'_, T> { - Iter { - iter: self.map.as_entries().iter(), - } + Iter::new(self.as_entries()) } /// Remove all elements in the set, while preserving its capacity. @@ -213,7 +240,7 @@ impl IndexSet { /// Clears the `IndexSet` in the given index range, returning those values /// as a drain iterator. /// - /// The range may be any type that implements `RangeBounds`, + /// The range may be any type that implements [`RangeBounds`], /// including all of the `std::ops::Range*` types, or even a tuple pair of /// `Bound` start and end values. To drain the set entirely, use `RangeFull` /// like `set.drain(..)`. @@ -227,9 +254,7 @@ impl IndexSet { where R: RangeBounds, { - Drain { - iter: self.map.drain(range).iter, - } + Drain::new(self.map.core.drain(range)) } /// Splits the collection into two at the given index. @@ -247,13 +272,7 @@ impl IndexSet { map: self.map.split_off(at), } } -} -impl IndexSet -where - T: Hash + Eq, - S: BuildHasher, -{ /// Reserve capacity for `additional` more values. /// /// Computes in **O(n)** time. @@ -261,6 +280,37 @@ where self.map.reserve(additional); } + /// Reserve capacity for `additional` more values, without over-allocating. + /// + /// Unlike `reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn reserve_exact(&mut self, additional: usize) { + self.map.reserve_exact(additional); + } + + /// Try to reserve capacity for `additional` more values. + /// + /// Computes in **O(n)** time. + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve(additional) + } + + /// Try to reserve capacity for `additional` more values, without over-allocating. + /// + /// Unlike `try_reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve_exact(additional) + } + /// Shrink the capacity of the set as much as possible. /// /// Computes in **O(n)** time. @@ -274,7 +324,13 @@ where pub fn shrink_to(&mut self, min_capacity: usize) { self.map.shrink_to(min_capacity); } +} +impl IndexSet +where + T: Hash + Eq, + S: BuildHasher, +{ /// Insert the value into the set. /// /// If an equivalent item already exists in the set, it returns @@ -297,15 +353,69 @@ where /// /// Computes in **O(1)** time (amortized average). pub fn insert_full(&mut self, value: T) -> (usize, bool) { - use super::map::Entry::*; - - match self.map.entry(value) { - Occupied(e) => (e.index(), false), - Vacant(e) => { - let index = e.index(); - e.insert(()); - (index, true) - } + let (index, existing) = self.map.insert_full(value, ()); + (index, existing.is_none()) + } + + /// Insert the value into the set at its ordered position among sorted values. + /// + /// This is equivalent to finding the position with + /// [`binary_search`][Self::binary_search], and if needed calling + /// [`shift_insert`][Self::shift_insert] for a new value. + /// + /// If the sorted item is found in the set, it returns the index of that + /// existing item and `false`, without any change. Otherwise, it inserts the + /// new item and returns its sorted index and `true`. + /// + /// If the existing items are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the value + /// is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). Instead of repeating calls to + /// `insert_sorted`, it may be faster to call batched [`insert`][Self::insert] + /// or [`extend`][Self::extend] and only call [`sort`][Self::sort] or + /// [`sort_unstable`][Self::sort_unstable] once. + pub fn insert_sorted(&mut self, value: T) -> (usize, bool) + where + T: Ord, + { + let (index, existing) = self.map.insert_sorted(value, ()); + (index, existing.is_none()) + } + + /// Insert the value into the set at the given index. + /// + /// If an equivalent item already exists in the set, it returns + /// `false` leaving the original value in the set, but moving it to + /// the new position in the set. Otherwise, it inserts the new + /// item at the given index and returns `true`. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + pub fn shift_insert(&mut self, index: usize, value: T) -> bool { + self.map.shift_insert(index, value, ()).is_none() + } + + /// Adds a value to the set, replacing the existing value, if any, that is + /// equal to the given one, without altering its insertion order. Returns + /// the replaced value. + /// + /// Computes in **O(1)** time (average). + pub fn replace(&mut self, value: T) -> Option { + self.replace_full(value).1 + } + + /// Adds a value to the set, replacing the existing value, if any, that is + /// equal to the given one, without altering its insertion order. Returns + /// the index of the item and its replaced value. + /// + /// Computes in **O(1)** time (average). + pub fn replace_full(&mut self, value: T) -> (usize, Option) { + let hash = self.map.hash(&value); + match self.map.core.replace_full(hash, value, ()) { + (i, Some((replaced, ()))) => (i, Some(replaced)), + (i, None) => (i, None), } } @@ -316,10 +426,7 @@ where where S2: BuildHasher, { - Difference { - iter: self.iter(), - other, - } + Difference::new(self, other) } /// Return an iterator over the values that are in `self` or `other`, @@ -334,9 +441,7 @@ where where S2: BuildHasher, { - SymmetricDifference { - iter: self.difference(other).chain(other.difference(self)), - } + SymmetricDifference::new(self, other) } /// Return an iterator over the values that are in both `self` and `other`. @@ -346,10 +451,7 @@ where where S2: BuildHasher, { - Intersection { - iter: self.iter(), - other, - } + Intersection::new(self, other) } /// Return an iterator over all values that are in `self` or `other`. @@ -360,17 +462,57 @@ where where S2: BuildHasher, { - Union { - iter: self.iter().chain(other.difference(self)), - } + Union::new(self, other) + } + + /// Creates a splicing iterator that replaces the specified range in the set + /// with the given `replace_with` iterator and yields the removed items. + /// `replace_with` does not need to be the same length as `range`. + /// + /// The `range` is removed even if the iterator is not consumed until the + /// end. It is unspecified how many elements are removed from the set if the + /// `Splice` value is leaked. + /// + /// The input iterator `replace_with` is only consumed when the `Splice` + /// value is dropped. If a value from the iterator matches an existing entry + /// in the set (outside of `range`), then the original will be unchanged. + /// Otherwise, the new value will be inserted in the replaced `range`. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the set. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let mut set = IndexSet::from([0, 1, 2, 3, 4]); + /// let new = [5, 4, 3, 2, 1]; + /// let removed: Vec<_> = set.splice(2..4, new).collect(); + /// + /// // 1 and 4 kept their positions, while 5, 3, and 2 were newly inserted. + /// assert!(set.into_iter().eq([0, 1, 5, 3, 2, 4])); + /// assert_eq!(removed, &[2, 3]); + /// ``` + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, T, S> + where + R: RangeBounds, + I: IntoIterator, + { + Splice::new(self, range, replace_with.into_iter()) } +} +impl IndexSet +where + S: BuildHasher, +{ /// Return `true` if an equivalent to `value` exists in the set. /// /// Computes in **O(1)** time (average). - pub fn contains(&self, value: &Q) -> bool + pub fn contains(&self, value: &Q) -> bool where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.contains_key(value) } @@ -379,97 +521,74 @@ where /// else `None`. /// /// Computes in **O(1)** time (average). - pub fn get(&self, value: &Q) -> Option<&T> + pub fn get(&self, value: &Q) -> Option<&T> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.get_key_value(value).map(|(x, &())| x) } /// Return item index and value - pub fn get_full(&self, value: &Q) -> Option<(usize, &T)> + pub fn get_full(&self, value: &Q) -> Option<(usize, &T)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.get_full(value).map(|(i, x, &())| (i, x)) } /// Return item index, if it exists in the set - pub fn get_index_of(&self, value: &Q) -> Option + /// + /// Computes in **O(1)** time (average). + pub fn get_index_of(&self, value: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.get_index_of(value) } - /// Adds a value to the set, replacing the existing value, if any, that is - /// equal to the given one, without altering its insertion order. Returns - /// the replaced value. - /// - /// Computes in **O(1)** time (average). - pub fn replace(&mut self, value: T) -> Option { - self.replace_full(value).1 - } - - /// Adds a value to the set, replacing the existing value, if any, that is - /// equal to the given one, without altering its insertion order. Returns - /// the index of the item and its replaced value. - /// - /// Computes in **O(1)** time (average). - pub fn replace_full(&mut self, value: T) -> (usize, Option) { - use super::map::Entry::*; - - match self.map.entry(value) { - Vacant(e) => { - let index = e.index(); - e.insert(()); - (index, None) - } - Occupied(e) => (e.index(), Some(e.replace_key())), - } - } - /// Remove the value from the set, and return `true` if it was present. /// - /// **NOTE:** This is equivalent to `.swap_remove(value)`, if you want - /// to preserve the order of the values in the set, use `.shift_remove(value)`. - /// - /// Computes in **O(1)** time (average). - pub fn remove(&mut self, value: &Q) -> bool + /// **NOTE:** This is equivalent to [`.swap_remove(value)`][Self::swap_remove], replacing this + /// value's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the values in the set, use + /// [`.shift_remove(value)`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the set order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(&mut self, value: &Q) -> bool where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.swap_remove(value) } /// Remove the value from the set, and return `true` if it was present. /// - /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs /// the position of what used to be the last element!** /// /// Return `false` if `value` was not in the set. /// /// Computes in **O(1)** time (average). - pub fn swap_remove(&mut self, value: &Q) -> bool + pub fn swap_remove(&mut self, value: &Q) -> bool where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.swap_remove(value).is_some() } /// Remove the value from the set, and return `true` if it was present. /// - /// Like `Vec::remove`, the value is removed by shifting all of the + /// Like [`Vec::remove`], the value is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Return `false` if `value` was not in the set. /// /// Computes in **O(n)** time (average). - pub fn shift_remove(&mut self, value: &Q) -> bool + pub fn shift_remove(&mut self, value: &Q) -> bool where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.shift_remove(value).is_some() } @@ -477,14 +596,15 @@ where /// Removes and returns the value in the set, if any, that is equal to the /// given one. /// - /// **NOTE:** This is equivalent to `.swap_take(value)`, if you need to - /// preserve the order of the values in the set, use `.shift_take(value)` - /// instead. - /// - /// Computes in **O(1)** time (average). - pub fn take(&mut self, value: &Q) -> Option + /// **NOTE:** This is equivalent to [`.swap_take(value)`][Self::swap_take], replacing this + /// value's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the values in the set, use + /// [`.shift_take(value)`][Self::shift_take] instead. + #[deprecated(note = "`take` disrupts the set order -- \ + use `swap_take` or `shift_take` for explicit behavior.")] + pub fn take(&mut self, value: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.swap_take(value) } @@ -492,16 +612,16 @@ where /// Removes and returns the value in the set, if any, that is equal to the /// given one. /// - /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs /// the position of what used to be the last element!** /// /// Return `None` if `value` was not in the set. /// /// Computes in **O(1)** time (average). - pub fn swap_take(&mut self, value: &Q) -> Option + pub fn swap_take(&mut self, value: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.swap_remove_entry(value).map(|(x, ())| x) } @@ -509,48 +629,50 @@ where /// Removes and returns the value in the set, if any, that is equal to the /// given one. /// - /// Like `Vec::remove`, the value is removed by shifting all of the + /// Like [`Vec::remove`], the value is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Return `None` if `value` was not in the set. /// /// Computes in **O(n)** time (average). - pub fn shift_take(&mut self, value: &Q) -> Option + pub fn shift_take(&mut self, value: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.shift_remove_entry(value).map(|(x, ())| x) } /// Remove the value from the set return it and the index it had. /// - /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs /// the position of what used to be the last element!** /// /// Return `None` if `value` was not in the set. - pub fn swap_remove_full(&mut self, value: &Q) -> Option<(usize, T)> + pub fn swap_remove_full(&mut self, value: &Q) -> Option<(usize, T)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.swap_remove_full(value).map(|(i, x, ())| (i, x)) } /// Remove the value from the set return it and the index it had. /// - /// Like `Vec::remove`, the value is removed by shifting all of the + /// Like [`Vec::remove`], the value is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Return `None` if `value` was not in the set. - pub fn shift_remove_full(&mut self, value: &Q) -> Option<(usize, T)> + pub fn shift_remove_full(&mut self, value: &Q) -> Option<(usize, T)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.map.shift_remove_full(value).map(|(i, x, ())| (i, x)) } +} +impl IndexSet { /// Remove the last value /// /// This preserves the order of the remaining elements. @@ -576,6 +698,10 @@ where /// Sort the set’s values by their default ordering. /// + /// This is a stable sort -- but equivalent values should not normally coexist in + /// a set at all, so [`sort_unstable`][Self::sort_unstable] is preferred + /// because it is generally faster and doesn't allocate auxiliary memory. + /// /// See [`sort_by`](Self::sort_by) for details. pub fn sort(&mut self) where @@ -604,9 +730,7 @@ where { let mut entries = self.into_entries(); entries.sort_by(move |a, b| cmp(&a.key, &b.key)); - IntoIter { - iter: entries.into_iter(), - } + IntoIter::new(entries) } /// Sort the set's values by their default ordering. @@ -619,7 +743,7 @@ where self.map.sort_unstable_keys() } - /// Sort the set's values in place using the comparison funtion `cmp`. + /// Sort the set's values in place using the comparison function `cmp`. /// /// Computes in **O(n log n)** time. The sort is unstable. pub fn sort_unstable_by(&mut self, mut cmp: F) @@ -637,9 +761,82 @@ where { let mut entries = self.into_entries(); entries.sort_unstable_by(move |a, b| cmp(&a.key, &b.key)); - IntoIter { - iter: entries.into_iter(), - } + IntoIter::new(entries) + } + + /// Sort the set’s values in place using a key extraction function. + /// + /// During sorting, the function is called at most once per entry, by using temporary storage + /// to remember the results of its evaluation. The order of calls to the function is + /// unspecified and may change between versions of `indexmap` or the standard library. + /// + /// Computes in **O(m n + n log n + c)** time () and **O(n)** space, where the function is + /// **O(m)**, *n* is the length of the map, and *c* the capacity. The sort is stable. + pub fn sort_by_cached_key(&mut self, mut sort_key: F) + where + K: Ord, + F: FnMut(&T) -> K, + { + self.with_entries(move |entries| { + entries.sort_by_cached_key(move |a| sort_key(&a.key)); + }); + } + + /// Search over a sorted set for a value. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the value up + /// using [`get_index_of`][IndexSet::get_index_of], but this can also position missing values. + pub fn binary_search(&self, x: &T) -> Result + where + T: Ord, + { + self.as_slice().binary_search(x) + } + + /// Search over a sorted set with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + where + F: FnMut(&'a T) -> Ordering, + { + self.as_slice().binary_search_by(f) + } + + /// Search over a sorted set with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + where + F: FnMut(&'a T) -> B, + B: Ord, + { + self.as_slice().binary_search_by_key(b, f) + } + + /// Returns the index of the partition point of a sorted set according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point

(&self, pred: P) -> usize + where + P: FnMut(&T) -> bool, + { + self.as_slice().partition_point(pred) } /// Reverses the order of the set’s values in place. @@ -648,9 +845,21 @@ where pub fn reverse(&mut self) { self.map.reverse() } -} -impl IndexSet { + /// Returns a slice of all the values in the set. + /// + /// Computes in **O(1)** time. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.as_entries()) + } + + /// Converts into a boxed slice of all the values in the set. + /// + /// Note that this will drop the inner hash table and any excess capacity. + pub fn into_boxed_slice(self) -> Box> { + Slice::from_boxed(self.into_entries().into_boxed_slice()) + } + /// Get a value by index /// /// Valid indices are *0 <= index < self.len()* @@ -660,6 +869,17 @@ impl IndexSet { self.as_entries().get(index).map(Bucket::key_ref) } + /// Returns a slice of values in the given range of indices. + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + pub fn get_range>(&self, range: R) -> Option<&Slice> { + let entries = self.as_entries(); + let range = try_simplify_range(range, entries.len())?; + entries.get(range).map(Slice::from_slice) + } + /// Get the first value /// /// Computes in **O(1)** time. @@ -678,7 +898,7 @@ impl IndexSet { /// /// Valid indices are *0 <= index < self.len()* /// - /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs /// the position of what used to be the last element!** /// @@ -691,7 +911,7 @@ impl IndexSet { /// /// Valid indices are *0 <= index < self.len()* /// - /// Like `Vec::remove`, the value is removed by shifting all of the + /// Like [`Vec::remove`], the value is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// @@ -716,12 +936,14 @@ impl IndexSet { /// Swaps the position of two values in the set. /// /// ***Panics*** if `a` or `b` are out of bounds. + /// + /// Computes in **O(1)** time (average). pub fn swap_indices(&mut self, a: usize, b: usize) { self.map.swap_indices(a, b) } } -/// Access `IndexSet` values at indexed positions. +/// Access [`IndexSet`] values at indexed positions. /// /// # Examples /// @@ -761,141 +983,6 @@ impl Index for IndexSet { } } -/// An owning iterator over the items of a `IndexSet`. -/// -/// This `struct` is created by the [`into_iter`] method on [`IndexSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`IndexSet`]: struct.IndexSet.html -/// [`into_iter`]: struct.IndexSet.html#method.into_iter -pub struct IntoIter { - iter: vec::IntoIter>, -} - -impl Iterator for IntoIter { - type Item = T; - - iterator_methods!(Bucket::key); -} - -impl DoubleEndedIterator for IntoIter { - double_ended_iterator_methods!(Bucket::key); -} - -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for IntoIter {} - -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::key_ref); - f.debug_list().entries(iter).finish() - } -} - -/// An iterator over the items of a `IndexSet`. -/// -/// This `struct` is created by the [`iter`] method on [`IndexSet`]. -/// See its documentation for more. -/// -/// [`IndexSet`]: struct.IndexSet.html -/// [`iter`]: struct.IndexSet.html#method.iter -pub struct Iter<'a, T> { - iter: slice::Iter<'a, Bucket>, -} - -impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; - - iterator_methods!(Bucket::key_ref); -} - -impl DoubleEndedIterator for Iter<'_, T> { - double_ended_iterator_methods!(Bucket::key_ref); -} - -impl ExactSizeIterator for Iter<'_, T> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for Iter<'_, T> {} - -impl Clone for Iter<'_, T> { - fn clone(&self) -> Self { - Iter { - iter: self.iter.clone(), - } - } -} - -impl fmt::Debug for Iter<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A draining iterator over the items of a `IndexSet`. -/// -/// This `struct` is created by the [`drain`] method on [`IndexSet`]. -/// See its documentation for more. -/// -/// [`IndexSet`]: struct.IndexSet.html -/// [`drain`]: struct.IndexSet.html#method.drain -pub struct Drain<'a, T> { - iter: vec::Drain<'a, Bucket>, -} - -impl Iterator for Drain<'_, T> { - type Item = T; - - iterator_methods!(Bucket::key); -} - -impl DoubleEndedIterator for Drain<'_, T> { - double_ended_iterator_methods!(Bucket::key); -} - -impl ExactSizeIterator for Drain<'_, T> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl FusedIterator for Drain<'_, T> {} - -impl fmt::Debug for Drain<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.iter.as_slice().iter().map(Bucket::key_ref); - f.debug_list().entries(iter).finish() - } -} - -impl<'a, T, S> IntoIterator for &'a IndexSet { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl IntoIterator for IndexSet { - type Item = T; - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { - iter: self.into_entries().into_iter(), - } - } -} - impl FromIterator for IndexSet where T: Hash + Eq, @@ -909,7 +996,8 @@ where } } -#[cfg(has_std)] +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl From<[T; N]> for IndexSet where T: Eq + Hash, @@ -954,7 +1042,7 @@ impl Default for IndexSet where S: Default, { - /// Return an empty `IndexSet` + /// Return an empty [`IndexSet`] fn default() -> Self { IndexSet { map: IndexMap::default(), @@ -1014,315 +1102,11 @@ where } } -/// A lazy iterator producing elements in the difference of `IndexSet`s. -/// -/// This `struct` is created by the [`difference`] method on [`IndexSet`]. -/// See its documentation for more. -/// -/// [`IndexSet`]: struct.IndexSet.html -/// [`difference`]: struct.IndexSet.html#method.difference -pub struct Difference<'a, T, S> { - iter: Iter<'a, T>, - other: &'a IndexSet, -} - -impl<'a, T, S> Iterator for Difference<'a, T, S> +impl BitAnd<&IndexSet> for &IndexSet where - T: Eq + Hash, - S: BuildHasher, -{ - type Item = &'a T; - - fn next(&mut self) -> Option { - while let Some(item) = self.iter.next() { - if !self.other.contains(item) { - return Some(item); - } - } - None - } - - fn size_hint(&self) -> (usize, Option) { - (0, self.iter.size_hint().1) - } -} - -impl DoubleEndedIterator for Difference<'_, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - fn next_back(&mut self) -> Option { - while let Some(item) = self.iter.next_back() { - if !self.other.contains(item) { - return Some(item); - } - } - None - } -} - -impl FusedIterator for Difference<'_, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ -} - -impl Clone for Difference<'_, T, S> { - fn clone(&self) -> Self { - Difference { - iter: self.iter.clone(), - ..*self - } - } -} - -impl fmt::Debug for Difference<'_, T, S> -where - T: fmt::Debug + Eq + Hash, - S: BuildHasher, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A lazy iterator producing elements in the intersection of `IndexSet`s. -/// -/// This `struct` is created by the [`intersection`] method on [`IndexSet`]. -/// See its documentation for more. -/// -/// [`IndexSet`]: struct.IndexSet.html -/// [`intersection`]: struct.IndexSet.html#method.intersection -pub struct Intersection<'a, T, S> { - iter: Iter<'a, T>, - other: &'a IndexSet, -} - -impl<'a, T, S> Iterator for Intersection<'a, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - type Item = &'a T; - - fn next(&mut self) -> Option { - while let Some(item) = self.iter.next() { - if self.other.contains(item) { - return Some(item); - } - } - None - } - - fn size_hint(&self) -> (usize, Option) { - (0, self.iter.size_hint().1) - } -} - -impl DoubleEndedIterator for Intersection<'_, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - fn next_back(&mut self) -> Option { - while let Some(item) = self.iter.next_back() { - if self.other.contains(item) { - return Some(item); - } - } - None - } -} - -impl FusedIterator for Intersection<'_, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ -} - -impl Clone for Intersection<'_, T, S> { - fn clone(&self) -> Self { - Intersection { - iter: self.iter.clone(), - ..*self - } - } -} - -impl fmt::Debug for Intersection<'_, T, S> -where - T: fmt::Debug + Eq + Hash, - S: BuildHasher, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A lazy iterator producing elements in the symmetric difference of `IndexSet`s. -/// -/// This `struct` is created by the [`symmetric_difference`] method on -/// [`IndexSet`]. See its documentation for more. -/// -/// [`IndexSet`]: struct.IndexSet.html -/// [`symmetric_difference`]: struct.IndexSet.html#method.symmetric_difference -pub struct SymmetricDifference<'a, T, S1, S2> { - iter: Chain, Difference<'a, T, S1>>, -} - -impl<'a, T, S1, S2> Iterator for SymmetricDifference<'a, T, S1, S2> -where - T: Eq + Hash, - S1: BuildHasher, - S2: BuildHasher, -{ - type Item = &'a T; - - fn next(&mut self) -> Option { - self.iter.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.iter.fold(init, f) - } -} - -impl DoubleEndedIterator for SymmetricDifference<'_, T, S1, S2> -where - T: Eq + Hash, - S1: BuildHasher, - S2: BuildHasher, -{ - fn next_back(&mut self) -> Option { - self.iter.next_back() - } - - fn rfold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.iter.rfold(init, f) - } -} - -impl FusedIterator for SymmetricDifference<'_, T, S1, S2> -where - T: Eq + Hash, - S1: BuildHasher, - S2: BuildHasher, -{ -} - -impl Clone for SymmetricDifference<'_, T, S1, S2> { - fn clone(&self) -> Self { - SymmetricDifference { - iter: self.iter.clone(), - } - } -} - -impl fmt::Debug for SymmetricDifference<'_, T, S1, S2> -where - T: fmt::Debug + Eq + Hash, - S1: BuildHasher, - S2: BuildHasher, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A lazy iterator producing elements in the union of `IndexSet`s. -/// -/// This `struct` is created by the [`union`] method on [`IndexSet`]. -/// See its documentation for more. -/// -/// [`IndexSet`]: struct.IndexSet.html -/// [`union`]: struct.IndexSet.html#method.union -pub struct Union<'a, T, S> { - iter: Chain, Difference<'a, T, S>>, -} - -impl<'a, T, S> Iterator for Union<'a, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - type Item = &'a T; - - fn next(&mut self) -> Option { - self.iter.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.iter.fold(init, f) - } -} - -impl DoubleEndedIterator for Union<'_, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - fn next_back(&mut self) -> Option { - self.iter.next_back() - } - - fn rfold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.iter.rfold(init, f) - } -} - -impl FusedIterator for Union<'_, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ -} - -impl Clone for Union<'_, T, S> { - fn clone(&self) -> Self { - Union { - iter: self.iter.clone(), - } - } -} - -impl fmt::Debug for Union<'_, T, S> -where - T: fmt::Debug + Eq + Hash, - S: BuildHasher, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl BitAnd<&IndexSet> for &IndexSet -where - T: Eq + Hash + Clone, - S1: BuildHasher + Default, - S2: BuildHasher, + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, { type Output = IndexSet; @@ -1383,530 +1167,3 @@ where self.difference(other).cloned().collect() } } - -#[cfg(test)] -mod tests { - use super::*; - use std::string::String; - - #[test] - fn it_works() { - let mut set = IndexSet::new(); - assert_eq!(set.is_empty(), true); - set.insert(1); - set.insert(1); - assert_eq!(set.len(), 1); - assert!(set.get(&1).is_some()); - assert_eq!(set.is_empty(), false); - } - - #[test] - fn new() { - let set = IndexSet::::new(); - println!("{:?}", set); - assert_eq!(set.capacity(), 0); - assert_eq!(set.len(), 0); - assert_eq!(set.is_empty(), true); - } - - #[test] - fn insert() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5]; - let not_present = [1, 3, 6, 9, 10]; - let mut set = IndexSet::with_capacity(insert.len()); - - for (i, &elt) in insert.iter().enumerate() { - assert_eq!(set.len(), i); - set.insert(elt); - assert_eq!(set.len(), i + 1); - assert_eq!(set.get(&elt), Some(&elt)); - } - println!("{:?}", set); - - for &elt in ¬_present { - assert!(set.get(&elt).is_none()); - } - } - - #[test] - fn insert_full() { - let insert = vec![9, 2, 7, 1, 4, 6, 13]; - let present = vec![1, 6, 2]; - let mut set = IndexSet::with_capacity(insert.len()); - - for (i, &elt) in insert.iter().enumerate() { - assert_eq!(set.len(), i); - let (index, success) = set.insert_full(elt); - assert!(success); - assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); - assert_eq!(set.len(), i + 1); - } - - let len = set.len(); - for &elt in &present { - let (index, success) = set.insert_full(elt); - assert!(!success); - assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); - assert_eq!(set.len(), len); - } - } - - #[test] - fn insert_2() { - let mut set = IndexSet::with_capacity(16); - - let mut values = vec![]; - values.extend(0..16); - values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); - - for &i in &values { - let old_set = set.clone(); - set.insert(i); - for value in old_set.iter() { - if set.get(value).is_none() { - println!("old_set: {:?}", old_set); - println!("set: {:?}", set); - panic!("did not find {} in set", value); - } - } - } - - for &i in &values { - assert!(set.get(&i).is_some(), "did not find {}", i); - } - } - - #[test] - fn insert_dup() { - let mut elements = vec![0, 2, 4, 6, 8]; - let mut set: IndexSet = elements.drain(..).collect(); - { - let (i, v) = set.get_full(&0).unwrap(); - assert_eq!(set.len(), 5); - assert_eq!(i, 0); - assert_eq!(*v, 0); - } - { - let inserted = set.insert(0); - let (i, v) = set.get_full(&0).unwrap(); - assert_eq!(set.len(), 5); - assert_eq!(inserted, false); - assert_eq!(i, 0); - assert_eq!(*v, 0); - } - } - - #[test] - fn insert_order() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; - let mut set = IndexSet::new(); - - for &elt in &insert { - set.insert(elt); - } - - assert_eq!(set.iter().count(), set.len()); - assert_eq!(set.iter().count(), insert.len()); - for (a, b) in insert.iter().zip(set.iter()) { - assert_eq!(a, b); - } - for (i, v) in (0..insert.len()).zip(set.iter()) { - assert_eq!(set.get_index(i).unwrap(), v); - } - } - - #[test] - fn replace() { - let replace = [0, 4, 2, 12, 8, 7, 11, 5]; - let not_present = [1, 3, 6, 9, 10]; - let mut set = IndexSet::with_capacity(replace.len()); - - for (i, &elt) in replace.iter().enumerate() { - assert_eq!(set.len(), i); - set.replace(elt); - assert_eq!(set.len(), i + 1); - assert_eq!(set.get(&elt), Some(&elt)); - } - println!("{:?}", set); - - for &elt in ¬_present { - assert!(set.get(&elt).is_none()); - } - } - - #[test] - fn replace_full() { - let replace = vec![9, 2, 7, 1, 4, 6, 13]; - let present = vec![1, 6, 2]; - let mut set = IndexSet::with_capacity(replace.len()); - - for (i, &elt) in replace.iter().enumerate() { - assert_eq!(set.len(), i); - let (index, replaced) = set.replace_full(elt); - assert!(replaced.is_none()); - assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); - assert_eq!(set.len(), i + 1); - } - - let len = set.len(); - for &elt in &present { - let (index, replaced) = set.replace_full(elt); - assert_eq!(Some(elt), replaced); - assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); - assert_eq!(set.len(), len); - } - } - - #[test] - fn replace_2() { - let mut set = IndexSet::with_capacity(16); - - let mut values = vec![]; - values.extend(0..16); - values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); - - for &i in &values { - let old_set = set.clone(); - set.replace(i); - for value in old_set.iter() { - if set.get(value).is_none() { - println!("old_set: {:?}", old_set); - println!("set: {:?}", set); - panic!("did not find {} in set", value); - } - } - } - - for &i in &values { - assert!(set.get(&i).is_some(), "did not find {}", i); - } - } - - #[test] - fn replace_dup() { - let mut elements = vec![0, 2, 4, 6, 8]; - let mut set: IndexSet = elements.drain(..).collect(); - { - let (i, v) = set.get_full(&0).unwrap(); - assert_eq!(set.len(), 5); - assert_eq!(i, 0); - assert_eq!(*v, 0); - } - { - let replaced = set.replace(0); - let (i, v) = set.get_full(&0).unwrap(); - assert_eq!(set.len(), 5); - assert_eq!(replaced, Some(0)); - assert_eq!(i, 0); - assert_eq!(*v, 0); - } - } - - #[test] - fn replace_order() { - let replace = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; - let mut set = IndexSet::new(); - - for &elt in &replace { - set.replace(elt); - } - - assert_eq!(set.iter().count(), set.len()); - assert_eq!(set.iter().count(), replace.len()); - for (a, b) in replace.iter().zip(set.iter()) { - assert_eq!(a, b); - } - for (i, v) in (0..replace.len()).zip(set.iter()) { - assert_eq!(set.get_index(i).unwrap(), v); - } - } - - #[test] - fn grow() { - let insert = [0, 4, 2, 12, 8, 7, 11]; - let not_present = [1, 3, 6, 9, 10]; - let mut set = IndexSet::with_capacity(insert.len()); - - for (i, &elt) in insert.iter().enumerate() { - assert_eq!(set.len(), i); - set.insert(elt); - assert_eq!(set.len(), i + 1); - assert_eq!(set.get(&elt), Some(&elt)); - } - - println!("{:?}", set); - for &elt in &insert { - set.insert(elt * 10); - } - for &elt in &insert { - set.insert(elt * 100); - } - for (i, &elt) in insert.iter().cycle().enumerate().take(100) { - set.insert(elt * 100 + i as i32); - } - println!("{:?}", set); - for &elt in ¬_present { - assert!(set.get(&elt).is_none()); - } - } - - #[test] - fn reserve() { - let mut set = IndexSet::::new(); - assert_eq!(set.capacity(), 0); - set.reserve(100); - let capacity = set.capacity(); - assert!(capacity >= 100); - for i in 0..capacity { - assert_eq!(set.len(), i); - set.insert(i); - assert_eq!(set.len(), i + 1); - assert_eq!(set.capacity(), capacity); - assert_eq!(set.get(&i), Some(&i)); - } - set.insert(capacity); - assert_eq!(set.len(), capacity + 1); - assert!(set.capacity() > capacity); - assert_eq!(set.get(&capacity), Some(&capacity)); - } - - #[test] - fn shrink_to_fit() { - let mut set = IndexSet::::new(); - assert_eq!(set.capacity(), 0); - for i in 0..100 { - assert_eq!(set.len(), i); - set.insert(i); - assert_eq!(set.len(), i + 1); - assert!(set.capacity() >= i + 1); - assert_eq!(set.get(&i), Some(&i)); - set.shrink_to_fit(); - assert_eq!(set.len(), i + 1); - assert_eq!(set.capacity(), i + 1); - assert_eq!(set.get(&i), Some(&i)); - } - } - - #[test] - fn remove() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; - let mut set = IndexSet::new(); - - for &elt in &insert { - set.insert(elt); - } - - assert_eq!(set.iter().count(), set.len()); - assert_eq!(set.iter().count(), insert.len()); - for (a, b) in insert.iter().zip(set.iter()) { - assert_eq!(a, b); - } - - let remove_fail = [99, 77]; - let remove = [4, 12, 8, 7]; - - for &value in &remove_fail { - assert!(set.swap_remove_full(&value).is_none()); - } - println!("{:?}", set); - for &value in &remove { - //println!("{:?}", set); - let index = set.get_full(&value).unwrap().0; - assert_eq!(set.swap_remove_full(&value), Some((index, value))); - } - println!("{:?}", set); - - for value in &insert { - assert_eq!(set.get(value).is_some(), !remove.contains(value)); - } - assert_eq!(set.len(), insert.len() - remove.len()); - assert_eq!(set.iter().count(), insert.len() - remove.len()); - } - - #[test] - fn swap_remove_index() { - let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; - let mut set = IndexSet::new(); - - for &elt in &insert { - set.insert(elt); - } - - let mut vector = insert.to_vec(); - let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; - - // check that the same swap remove sequence on vec and set - // have the same result. - for &rm in remove_sequence { - let out_vec = vector.swap_remove(rm); - let out_set = set.swap_remove_index(rm).unwrap(); - assert_eq!(out_vec, out_set); - } - assert_eq!(vector.len(), set.len()); - for (a, b) in vector.iter().zip(set.iter()) { - assert_eq!(a, b); - } - } - - #[test] - fn partial_eq_and_eq() { - let mut set_a = IndexSet::new(); - set_a.insert(1); - set_a.insert(2); - let mut set_b = set_a.clone(); - assert_eq!(set_a, set_b); - set_b.swap_remove(&1); - assert_ne!(set_a, set_b); - - let set_c: IndexSet<_> = set_b.into_iter().collect(); - assert_ne!(set_a, set_c); - assert_ne!(set_c, set_a); - } - - #[test] - fn extend() { - let mut set = IndexSet::new(); - set.extend(vec![&1, &2, &3, &4]); - set.extend(vec![5, 6]); - assert_eq!(set.into_iter().collect::>(), vec![1, 2, 3, 4, 5, 6]); - } - - #[test] - fn comparisons() { - let set_a: IndexSet<_> = (0..3).collect(); - let set_b: IndexSet<_> = (3..6).collect(); - let set_c: IndexSet<_> = (0..6).collect(); - let set_d: IndexSet<_> = (3..9).collect(); - - assert!(!set_a.is_disjoint(&set_a)); - assert!(set_a.is_subset(&set_a)); - assert!(set_a.is_superset(&set_a)); - - assert!(set_a.is_disjoint(&set_b)); - assert!(set_b.is_disjoint(&set_a)); - assert!(!set_a.is_subset(&set_b)); - assert!(!set_b.is_subset(&set_a)); - assert!(!set_a.is_superset(&set_b)); - assert!(!set_b.is_superset(&set_a)); - - assert!(!set_a.is_disjoint(&set_c)); - assert!(!set_c.is_disjoint(&set_a)); - assert!(set_a.is_subset(&set_c)); - assert!(!set_c.is_subset(&set_a)); - assert!(!set_a.is_superset(&set_c)); - assert!(set_c.is_superset(&set_a)); - - assert!(!set_c.is_disjoint(&set_d)); - assert!(!set_d.is_disjoint(&set_c)); - assert!(!set_c.is_subset(&set_d)); - assert!(!set_d.is_subset(&set_c)); - assert!(!set_c.is_superset(&set_d)); - assert!(!set_d.is_superset(&set_c)); - } - - #[test] - fn iter_comparisons() { - use std::iter::empty; - - fn check<'a, I1, I2>(iter1: I1, iter2: I2) - where - I1: Iterator, - I2: Iterator, - { - assert!(iter1.copied().eq(iter2)); - } - - let set_a: IndexSet<_> = (0..3).collect(); - let set_b: IndexSet<_> = (3..6).collect(); - let set_c: IndexSet<_> = (0..6).collect(); - let set_d: IndexSet<_> = (3..9).rev().collect(); - - check(set_a.difference(&set_a), empty()); - check(set_a.symmetric_difference(&set_a), empty()); - check(set_a.intersection(&set_a), 0..3); - check(set_a.union(&set_a), 0..3); - - check(set_a.difference(&set_b), 0..3); - check(set_b.difference(&set_a), 3..6); - check(set_a.symmetric_difference(&set_b), 0..6); - check(set_b.symmetric_difference(&set_a), (3..6).chain(0..3)); - check(set_a.intersection(&set_b), empty()); - check(set_b.intersection(&set_a), empty()); - check(set_a.union(&set_b), 0..6); - check(set_b.union(&set_a), (3..6).chain(0..3)); - - check(set_a.difference(&set_c), empty()); - check(set_c.difference(&set_a), 3..6); - check(set_a.symmetric_difference(&set_c), 3..6); - check(set_c.symmetric_difference(&set_a), 3..6); - check(set_a.intersection(&set_c), 0..3); - check(set_c.intersection(&set_a), 0..3); - check(set_a.union(&set_c), 0..6); - check(set_c.union(&set_a), 0..6); - - check(set_c.difference(&set_d), 0..3); - check(set_d.difference(&set_c), (6..9).rev()); - check( - set_c.symmetric_difference(&set_d), - (0..3).chain((6..9).rev()), - ); - check(set_d.symmetric_difference(&set_c), (6..9).rev().chain(0..3)); - check(set_c.intersection(&set_d), 3..6); - check(set_d.intersection(&set_c), (3..6).rev()); - check(set_c.union(&set_d), (0..6).chain((6..9).rev())); - check(set_d.union(&set_c), (3..9).rev().chain(0..3)); - } - - #[test] - fn ops() { - let empty = IndexSet::::new(); - let set_a: IndexSet<_> = (0..3).collect(); - let set_b: IndexSet<_> = (3..6).collect(); - let set_c: IndexSet<_> = (0..6).collect(); - let set_d: IndexSet<_> = (3..9).rev().collect(); - - #[allow(clippy::eq_op)] - { - assert_eq!(&set_a & &set_a, set_a); - assert_eq!(&set_a | &set_a, set_a); - assert_eq!(&set_a ^ &set_a, empty); - assert_eq!(&set_a - &set_a, empty); - } - - assert_eq!(&set_a & &set_b, empty); - assert_eq!(&set_b & &set_a, empty); - assert_eq!(&set_a | &set_b, set_c); - assert_eq!(&set_b | &set_a, set_c); - assert_eq!(&set_a ^ &set_b, set_c); - assert_eq!(&set_b ^ &set_a, set_c); - assert_eq!(&set_a - &set_b, set_a); - assert_eq!(&set_b - &set_a, set_b); - - assert_eq!(&set_a & &set_c, set_a); - assert_eq!(&set_c & &set_a, set_a); - assert_eq!(&set_a | &set_c, set_c); - assert_eq!(&set_c | &set_a, set_c); - assert_eq!(&set_a ^ &set_c, set_b); - assert_eq!(&set_c ^ &set_a, set_b); - assert_eq!(&set_a - &set_c, empty); - assert_eq!(&set_c - &set_a, set_b); - - assert_eq!(&set_c & &set_d, set_b); - assert_eq!(&set_d & &set_c, set_b); - assert_eq!(&set_c | &set_d, &set_a | &set_d); - assert_eq!(&set_d | &set_c, &set_a | &set_d); - assert_eq!(&set_c ^ &set_d, &set_a | &(&set_d - &set_b)); - assert_eq!(&set_d ^ &set_c, &set_a | &(&set_d - &set_b)); - assert_eq!(&set_c - &set_d, set_a); - assert_eq!(&set_d - &set_c, &set_d - &set_b); - } - - #[test] - #[cfg(has_std)] - fn from_array() { - let set1 = IndexSet::from([1, 2, 3, 4]); - let set2: IndexSet<_> = [1, 2, 3, 4].into(); - - assert_eq!(set1, set2); - } -} diff --git a/third_party/rust/indexmap/src/set/iter.rs b/third_party/rust/indexmap/src/set/iter.rs new file mode 100644 index 0000000000..3f8033c2db --- /dev/null +++ b/third_party/rust/indexmap/src/set/iter.rs @@ -0,0 +1,626 @@ +use super::{Bucket, Entries, IndexSet, Slice}; + +use alloc::vec::{self, Vec}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FusedIterator}; +use core::ops::RangeBounds; +use core::slice::Iter as SliceIter; + +impl<'a, T, S> IntoIterator for &'a IndexSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for IndexSet { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +/// An iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::iter`] method. +/// See its documentation for more. +pub struct Iter<'a, T> { + iter: SliceIter<'a, Bucket>, +} + +impl<'a, T> Iter<'a, T> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &'a Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + iterator_methods!(Bucket::key_ref); +} + +impl DoubleEndedIterator for Iter<'_, T> { + double_ended_iterator_methods!(Bucket::key_ref); +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Iter<'_, T> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// An owning iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::into_iter`] method +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +pub struct IntoIter { + iter: vec::IntoIter>, +} + +impl IntoIter { + pub(super) fn new(entries: Vec>) -> Self { + Self { + iter: entries.into_iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl Iterator for IntoIter { + type Item = T; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for IntoIter { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoIter { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// A draining iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::drain`] method. +/// See its documentation for more. +pub struct Drain<'a, T> { + iter: vec::Drain<'a, Bucket>, +} + +impl<'a, T> Drain<'a, T> { + pub(super) fn new(iter: vec::Drain<'a, Bucket>) -> Self { + Self { iter } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl Iterator for Drain<'_, T> { + type Item = T; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for Drain<'_, T> { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for Drain<'_, T> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Drain<'_, T> {} + +impl fmt::Debug for Drain<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +/// A lazy iterator producing elements in the difference of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::difference`] method. +/// See its documentation for more. +pub struct Difference<'a, T, S> { + iter: Iter<'a, T>, + other: &'a IndexSet, +} + +impl<'a, T, S> Difference<'a, T, S> { + pub(super) fn new(set: &'a IndexSet, other: &'a IndexSet) -> Self { + Self { + iter: set.iter(), + other, + } + } +} + +impl<'a, T, S> Iterator for Difference<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + while let Some(item) = self.iter.next() { + if !self.other.contains(item) { + return Some(item); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} + +impl DoubleEndedIterator for Difference<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + while let Some(item) = self.iter.next_back() { + if !self.other.contains(item) { + return Some(item); + } + } + None + } +} + +impl FusedIterator for Difference<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Difference<'_, T, S> { + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl fmt::Debug for Difference<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the intersection of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::intersection`] method. +/// See its documentation for more. +pub struct Intersection<'a, T, S> { + iter: Iter<'a, T>, + other: &'a IndexSet, +} + +impl<'a, T, S> Intersection<'a, T, S> { + pub(super) fn new(set: &'a IndexSet, other: &'a IndexSet) -> Self { + Self { + iter: set.iter(), + other, + } + } +} + +impl<'a, T, S> Iterator for Intersection<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + while let Some(item) = self.iter.next() { + if self.other.contains(item) { + return Some(item); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} + +impl DoubleEndedIterator for Intersection<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + while let Some(item) = self.iter.next_back() { + if self.other.contains(item) { + return Some(item); + } + } + None + } +} + +impl FusedIterator for Intersection<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Intersection<'_, T, S> { + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl fmt::Debug for Intersection<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the symmetric difference of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::symmetric_difference`] method. +/// See its documentation for more. +pub struct SymmetricDifference<'a, T, S1, S2> { + iter: Chain, Difference<'a, T, S1>>, +} + +impl<'a, T, S1, S2> SymmetricDifference<'a, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + pub(super) fn new(set1: &'a IndexSet, set2: &'a IndexSet) -> Self { + let diff1 = set1.difference(set2); + let diff2 = set2.difference(set1); + Self { + iter: diff1.chain(diff2), + } + } +} + +impl<'a, T, S1, S2> Iterator for SymmetricDifference<'a, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl DoubleEndedIterator for SymmetricDifference<'_, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.iter.next_back() + } + + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.rfold(init, f) + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ +} + +impl Clone for SymmetricDifference<'_, T, S1, S2> { + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for SymmetricDifference<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the union of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::union`] method. +/// See its documentation for more. +pub struct Union<'a, T, S> { + iter: Chain, Difference<'a, T, S>>, +} + +impl<'a, T, S> Union<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + pub(super) fn new(set1: &'a IndexSet, set2: &'a IndexSet) -> Self + where + S2: BuildHasher, + { + Self { + iter: set1.iter().chain(set2.difference(set1)), + } + } +} + +impl<'a, T, S> Iterator for Union<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl DoubleEndedIterator for Union<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.iter.next_back() + } + + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.rfold(init, f) + } +} + +impl FusedIterator for Union<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Union<'_, T, S> { + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Union<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A splicing iterator for `IndexSet`. +/// +/// This `struct` is created by [`IndexSet::splice()`]. +/// See its documentation for more. +pub struct Splice<'a, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + iter: crate::map::Splice<'a, UnitValue, T, (), S>, +} + +impl<'a, I, T, S> Splice<'a, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + pub(super) fn new(set: &'a mut IndexSet, range: R, replace_with: I) -> Self + where + R: RangeBounds, + { + Self { + iter: set.map.splice(range, UnitValue(replace_with)), + } + } +} + +impl Iterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + type Item = T; + + fn next(&mut self) -> Option { + Some(self.iter.next()?.0) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl DoubleEndedIterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + Some(self.iter.next_back()?.0) + } +} + +impl ExactSizeIterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ +} + +struct UnitValue(I); + +impl Iterator for UnitValue { + type Item = (I::Item, ()); + + fn next(&mut self) -> Option { + self.0.next().map(|x| (x, ())) + } +} + +impl<'a, I, T, S> fmt::Debug for Splice<'a, I, T, S> +where + I: fmt::Debug + Iterator, + T: fmt::Debug + Hash + Eq, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.iter, f) + } +} + +impl fmt::Debug for UnitValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} diff --git a/third_party/rust/indexmap/src/set/mutable.rs b/third_party/rust/indexmap/src/set/mutable.rs new file mode 100644 index 0000000000..20eaa11221 --- /dev/null +++ b/third_party/rust/indexmap/src/set/mutable.rs @@ -0,0 +1,86 @@ +use core::hash::{BuildHasher, Hash}; + +use super::{Equivalent, IndexSet}; +use crate::map::MutableKeys; + +/// Opt-in mutable access to [`IndexSet`] values. +/// +/// These methods expose `&mut T`, mutable references to the value as it is stored +/// in the set. +/// You are allowed to modify the values in the set **if the modification +/// does not change the value’s hash and equality**. +/// +/// If values are modified erroneously, you can no longer look them up. +/// This is sound (memory safe) but a logical error hazard (just like +/// implementing `PartialEq`, `Eq`, or `Hash` incorrectly would be). +/// +/// `use` this trait to enable its methods for `IndexSet`. +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +pub trait MutableValues: private::Sealed { + type Value; + + /// Return item index and mutable reference to the value + /// + /// Computes in **O(1)** time (average). + fn get_full_mut2(&mut self, value: &Q) -> Option<(usize, &mut Self::Value)> + where + Q: ?Sized + Hash + Equivalent; + + /// Return mutable reference to the value at an index. + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + fn get_index_mut2(&mut self, index: usize) -> Option<&mut Self::Value>; + + /// Scan through each value in the set and keep those where the + /// closure `keep` returns `true`. + /// + /// The values are visited in order, and remaining values keep their order. + /// + /// Computes in **O(n)** time (average). + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut Self::Value) -> bool; +} + +/// Opt-in mutable access to [`IndexSet`] values. +/// +/// See [`MutableValues`] for more information. +impl MutableValues for IndexSet +where + S: BuildHasher, +{ + type Value = T; + + fn get_full_mut2(&mut self, value: &Q) -> Option<(usize, &mut T)> + where + Q: ?Sized + Hash + Equivalent, + { + match self.map.get_full_mut2(value) { + Some((index, value, ())) => Some((index, value)), + None => None, + } + } + + fn get_index_mut2(&mut self, index: usize) -> Option<&mut T> { + match self.map.get_index_mut2(index) { + Some((value, ())) => Some(value), + None => None, + } + } + + fn retain2(&mut self, mut keep: F) + where + F: FnMut(&mut T) -> bool, + { + self.map.retain2(move |value, ()| keep(value)); + } +} + +mod private { + pub trait Sealed {} + + impl Sealed for super::IndexSet {} +} diff --git a/third_party/rust/indexmap/src/set/slice.rs b/third_party/rust/indexmap/src/set/slice.rs new file mode 100644 index 0000000000..9fc208c706 --- /dev/null +++ b/third_party/rust/indexmap/src/set/slice.rs @@ -0,0 +1,340 @@ +use super::{Bucket, Entries, IndexSet, IntoIter, Iter}; +use crate::util::try_simplify_range; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ops::{self, Bound, Index, RangeBounds}; + +/// A dynamically-sized slice of values in an [`IndexSet`]. +/// +/// This supports indexed operations much like a `[T]` slice, +/// but not any hashed operations on the values. +/// +/// Unlike `IndexSet`, `Slice` does consider the order for [`PartialEq`] +/// and [`Eq`], and it also implements [`PartialOrd`], [`Ord`], and [`Hash`]. +#[repr(transparent)] +pub struct Slice { + pub(crate) entries: [Bucket], +} + +// SAFETY: `Slice` is a transparent wrapper around `[Bucket]`, +// and reference lifetimes are bound together in function signatures. +#[allow(unsafe_code)] +impl Slice { + pub(super) const fn from_slice(entries: &[Bucket]) -> &Self { + unsafe { &*(entries as *const [Bucket] as *const Self) } + } + + pub(super) fn from_boxed(entries: Box<[Bucket]>) -> Box { + unsafe { Box::from_raw(Box::into_raw(entries) as *mut Self) } + } + + fn into_boxed(self: Box) -> Box<[Bucket]> { + unsafe { Box::from_raw(Box::into_raw(self) as *mut [Bucket]) } + } +} + +impl Slice { + pub(crate) fn into_entries(self: Box) -> Vec> { + self.into_boxed().into_vec() + } + + /// Returns an empty slice. + pub const fn new<'a>() -> &'a Self { + Self::from_slice(&[]) + } + + /// Return the number of elements in the set slice. + pub const fn len(&self) -> usize { + self.entries.len() + } + + /// Returns true if the set slice contains no elements. + pub const fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + /// Get a value by index. + /// + /// Valid indices are *0 <= index < self.len()* + pub fn get_index(&self, index: usize) -> Option<&T> { + self.entries.get(index).map(Bucket::key_ref) + } + + /// Returns a slice of values in the given range of indices. + /// + /// Valid indices are *0 <= index < self.len()* + pub fn get_range>(&self, range: R) -> Option<&Self> { + let range = try_simplify_range(range, self.entries.len())?; + self.entries.get(range).map(Self::from_slice) + } + + /// Get the first value. + pub fn first(&self) -> Option<&T> { + self.entries.first().map(Bucket::key_ref) + } + + /// Get the last value. + pub fn last(&self) -> Option<&T> { + self.entries.last().map(Bucket::key_ref) + } + + /// Divides one slice into two at an index. + /// + /// ***Panics*** if `index > len`. + pub fn split_at(&self, index: usize) -> (&Self, &Self) { + let (first, second) = self.entries.split_at(index); + (Self::from_slice(first), Self::from_slice(second)) + } + + /// Returns the first value and the rest of the slice, + /// or `None` if it is empty. + pub fn split_first(&self) -> Option<(&T, &Self)> { + if let [first, rest @ ..] = &self.entries { + Some((&first.key, Self::from_slice(rest))) + } else { + None + } + } + + /// Returns the last value and the rest of the slice, + /// or `None` if it is empty. + pub fn split_last(&self) -> Option<(&T, &Self)> { + if let [rest @ .., last] = &self.entries { + Some((&last.key, Self::from_slice(rest))) + } else { + None + } + } + + /// Return an iterator over the values of the set slice. + pub fn iter(&self) -> Iter<'_, T> { + Iter::new(&self.entries) + } + + /// Search over a sorted set for a value. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the value up in + /// the set this is a slice from using [`IndexSet::get_index_of`], but this can also position + /// missing values. + pub fn binary_search(&self, x: &T) -> Result + where + T: Ord, + { + self.binary_search_by(|p| p.cmp(x)) + } + + /// Search over a sorted set with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: FnMut(&'a T) -> Ordering, + { + self.entries.binary_search_by(move |a| f(&a.key)) + } + + /// Search over a sorted set with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: FnMut(&'a T) -> B, + B: Ord, + { + self.binary_search_by(|k| f(k).cmp(b)) + } + + /// Returns the index of the partition point of a sorted set according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point

(&self, mut pred: P) -> usize + where + P: FnMut(&T) -> bool, + { + self.entries.partition_point(move |a| pred(&a.key)) + } +} + +impl<'a, T> IntoIterator for &'a Slice { + type IntoIter = Iter<'a, T>; + type Item = &'a T; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for Box> { + type IntoIter = IntoIter; + type Item = T; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +impl Default for &'_ Slice { + fn default() -> Self { + Slice::from_slice(&[]) + } +} + +impl Default for Box> { + fn default() -> Self { + Slice::from_boxed(Box::default()) + } +} + +impl Clone for Box> { + fn clone(&self) -> Self { + Slice::from_boxed(self.entries.to_vec().into_boxed_slice()) + } +} + +impl From<&Slice> for Box> { + fn from(slice: &Slice) -> Self { + Slice::from_boxed(Box::from(&slice.entries)) + } +} + +impl fmt::Debug for Slice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +impl PartialEq for Slice { + fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.iter().eq(other) + } +} + +impl Eq for Slice {} + +impl PartialOrd for Slice { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +impl Ord for Slice { + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +impl Hash for Slice { + fn hash(&self, state: &mut H) { + self.len().hash(state); + for value in self { + value.hash(state); + } + } +} + +impl Index for Slice { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.entries[index].key + } +} + +// We can't have `impl> Index` because that conflicts with `Index`. +// Instead, we repeat the implementations for all the core range types. +macro_rules! impl_index { + ($($range:ty),*) => {$( + impl Index<$range> for IndexSet { + type Output = Slice; + + fn index(&self, range: $range) -> &Self::Output { + Slice::from_slice(&self.as_entries()[range]) + } + } + + impl Index<$range> for Slice { + type Output = Self; + + fn index(&self, range: $range) -> &Self::Output { + Slice::from_slice(&self.entries[range]) + } + } + )*} +} +impl_index!( + ops::Range, + ops::RangeFrom, + ops::RangeFull, + ops::RangeInclusive, + ops::RangeTo, + ops::RangeToInclusive, + (Bound, Bound) +); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn slice_index() { + fn check(vec_slice: &[i32], set_slice: &Slice, sub_slice: &Slice) { + assert_eq!(set_slice as *const _, sub_slice as *const _); + itertools::assert_equal(vec_slice, set_slice); + } + + let vec: Vec = (0..10).map(|i| i * i).collect(); + let set: IndexSet = vec.iter().cloned().collect(); + let slice = set.as_slice(); + + // RangeFull + check(&vec[..], &set[..], &slice[..]); + + for i in 0usize..10 { + // Index + assert_eq!(vec[i], set[i]); + assert_eq!(vec[i], slice[i]); + + // RangeFrom + check(&vec[i..], &set[i..], &slice[i..]); + + // RangeTo + check(&vec[..i], &set[..i], &slice[..i]); + + // RangeToInclusive + check(&vec[..=i], &set[..=i], &slice[..=i]); + + // (Bound, Bound) + let bounds = (Bound::Excluded(i), Bound::Unbounded); + check(&vec[i + 1..], &set[bounds], &slice[bounds]); + + for j in i..=10 { + // Range + check(&vec[i..j], &set[i..j], &slice[i..j]); + } + + for j in i..10 { + // RangeInclusive + check(&vec[i..=j], &set[i..=j], &slice[i..=j]); + } + } + } +} diff --git a/third_party/rust/indexmap/src/set/tests.rs b/third_party/rust/indexmap/src/set/tests.rs new file mode 100644 index 0000000000..35a076e8de --- /dev/null +++ b/third_party/rust/indexmap/src/set/tests.rs @@ -0,0 +1,723 @@ +use super::*; +use std::string::String; + +#[test] +fn it_works() { + let mut set = IndexSet::new(); + assert_eq!(set.is_empty(), true); + set.insert(1); + set.insert(1); + assert_eq!(set.len(), 1); + assert!(set.get(&1).is_some()); + assert_eq!(set.is_empty(), false); +} + +#[test] +fn new() { + let set = IndexSet::::new(); + println!("{:?}", set); + assert_eq!(set.capacity(), 0); + assert_eq!(set.len(), 0); + assert_eq!(set.is_empty(), true); +} + +#[test] +fn insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(set.len(), i); + set.insert(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + println!("{:?}", set); + + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } +} + +#[test] +fn insert_full() { + let insert = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(set.len(), i); + let (index, success) = set.insert_full(elt); + assert!(success); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), i + 1); + } + + let len = set.len(); + for &elt in &present { + let (index, success) = set.insert_full(elt); + assert!(!success); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), len); + } +} + +#[test] +fn insert_2() { + let mut set = IndexSet::with_capacity(16); + + let mut values = vec![]; + values.extend(0..16); + values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &values { + let old_set = set.clone(); + set.insert(i); + for value in old_set.iter() { + if set.get(value).is_none() { + println!("old_set: {:?}", old_set); + println!("set: {:?}", set); + panic!("did not find {} in set", value); + } + } + } + + for &i in &values { + assert!(set.get(&i).is_some(), "did not find {}", i); + } +} + +#[test] +fn insert_dup() { + let mut elements = vec![0, 2, 4, 6, 8]; + let mut set: IndexSet = elements.drain(..).collect(); + { + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + { + let inserted = set.insert(0); + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(inserted, false); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } +} + +#[test] +fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..insert.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } +} + +#[test] +fn shift_insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.shift_insert(0, elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().rev().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..insert.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } + + // "insert" that moves an existing entry + set.shift_insert(0, insert[0]); + assert_eq!(set.iter().count(), insert.len()); + assert_eq!(insert[0], set[0]); + for (a, b) in insert[1..].iter().rev().zip(set.iter().skip(1)) { + assert_eq!(a, b); + } +} + +#[test] +fn replace() { + let replace = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(replace.len()); + + for (i, &elt) in replace.iter().enumerate() { + assert_eq!(set.len(), i); + set.replace(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + println!("{:?}", set); + + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } +} + +#[test] +fn replace_full() { + let replace = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut set = IndexSet::with_capacity(replace.len()); + + for (i, &elt) in replace.iter().enumerate() { + assert_eq!(set.len(), i); + let (index, replaced) = set.replace_full(elt); + assert!(replaced.is_none()); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), i + 1); + } + + let len = set.len(); + for &elt in &present { + let (index, replaced) = set.replace_full(elt); + assert_eq!(Some(elt), replaced); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), len); + } +} + +#[test] +fn replace_2() { + let mut set = IndexSet::with_capacity(16); + + let mut values = vec![]; + values.extend(0..16); + values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &values { + let old_set = set.clone(); + set.replace(i); + for value in old_set.iter() { + if set.get(value).is_none() { + println!("old_set: {:?}", old_set); + println!("set: {:?}", set); + panic!("did not find {} in set", value); + } + } + } + + for &i in &values { + assert!(set.get(&i).is_some(), "did not find {}", i); + } +} + +#[test] +fn replace_dup() { + let mut elements = vec![0, 2, 4, 6, 8]; + let mut set: IndexSet = elements.drain(..).collect(); + { + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + { + let replaced = set.replace(0); + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(replaced, Some(0)); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } +} + +#[test] +fn replace_order() { + let replace = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &replace { + set.replace(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), replace.len()); + for (a, b) in replace.iter().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..replace.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } +} + +#[test] +fn replace_change() { + // Check pointers to make sure it really changes + let mut set = indexset!(vec![42]); + let old_ptr = set[0].as_ptr(); + let new = set[0].clone(); + let new_ptr = new.as_ptr(); + assert_ne!(old_ptr, new_ptr); + let replaced = set.replace(new).unwrap(); + assert_eq!(replaced.as_ptr(), old_ptr); +} + +#[test] +fn grow() { + let insert = [0, 4, 2, 12, 8, 7, 11]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(set.len(), i); + set.insert(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + + println!("{:?}", set); + for &elt in &insert { + set.insert(elt * 10); + } + for &elt in &insert { + set.insert(elt * 100); + } + for (i, &elt) in insert.iter().cycle().enumerate().take(100) { + set.insert(elt * 100 + i as i32); + } + println!("{:?}", set); + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } +} + +#[test] +fn reserve() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + set.reserve(100); + let capacity = set.capacity(); + assert!(capacity >= 100); + for i in 0..capacity { + assert_eq!(set.len(), i); + set.insert(i); + assert_eq!(set.len(), i + 1); + assert_eq!(set.capacity(), capacity); + assert_eq!(set.get(&i), Some(&i)); + } + set.insert(capacity); + assert_eq!(set.len(), capacity + 1); + assert!(set.capacity() > capacity); + assert_eq!(set.get(&capacity), Some(&capacity)); +} + +#[test] +fn try_reserve() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + assert_eq!(set.try_reserve(100), Ok(())); + assert!(set.capacity() >= 100); + assert!(set.try_reserve(usize::MAX).is_err()); +} + +#[test] +fn shrink_to_fit() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + for i in 0..100 { + assert_eq!(set.len(), i); + set.insert(i); + assert_eq!(set.len(), i + 1); + assert!(set.capacity() >= i + 1); + assert_eq!(set.get(&i), Some(&i)); + set.shrink_to_fit(); + assert_eq!(set.len(), i + 1); + assert_eq!(set.capacity(), i + 1); + assert_eq!(set.get(&i), Some(&i)); + } +} + +#[test] +fn remove() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().zip(set.iter()) { + assert_eq!(a, b); + } + + let remove_fail = [99, 77]; + let remove = [4, 12, 8, 7]; + + for &value in &remove_fail { + assert!(set.swap_remove_full(&value).is_none()); + } + println!("{:?}", set); + for &value in &remove { + //println!("{:?}", set); + let index = set.get_full(&value).unwrap().0; + assert_eq!(set.swap_remove_full(&value), Some((index, value))); + } + println!("{:?}", set); + + for value in &insert { + assert_eq!(set.get(value).is_some(), !remove.contains(value)); + } + assert_eq!(set.len(), insert.len() - remove.len()); + assert_eq!(set.iter().count(), insert.len() - remove.len()); +} + +#[test] +fn swap_remove_index() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + let mut vector = insert.to_vec(); + let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; + + // check that the same swap remove sequence on vec and set + // have the same result. + for &rm in remove_sequence { + let out_vec = vector.swap_remove(rm); + let out_set = set.swap_remove_index(rm).unwrap(); + assert_eq!(out_vec, out_set); + } + assert_eq!(vector.len(), set.len()); + for (a, b) in vector.iter().zip(set.iter()) { + assert_eq!(a, b); + } +} + +#[test] +fn partial_eq_and_eq() { + let mut set_a = IndexSet::new(); + set_a.insert(1); + set_a.insert(2); + let mut set_b = set_a.clone(); + assert_eq!(set_a, set_b); + set_b.swap_remove(&1); + assert_ne!(set_a, set_b); + + let set_c: IndexSet<_> = set_b.into_iter().collect(); + assert_ne!(set_a, set_c); + assert_ne!(set_c, set_a); +} + +#[test] +fn extend() { + let mut set = IndexSet::new(); + set.extend(vec![&1, &2, &3, &4]); + set.extend(vec![5, 6]); + assert_eq!(set.into_iter().collect::>(), vec![1, 2, 3, 4, 5, 6]); +} + +#[test] +fn comparisons() { + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).collect(); + + assert!(!set_a.is_disjoint(&set_a)); + assert!(set_a.is_subset(&set_a)); + assert!(set_a.is_superset(&set_a)); + + assert!(set_a.is_disjoint(&set_b)); + assert!(set_b.is_disjoint(&set_a)); + assert!(!set_a.is_subset(&set_b)); + assert!(!set_b.is_subset(&set_a)); + assert!(!set_a.is_superset(&set_b)); + assert!(!set_b.is_superset(&set_a)); + + assert!(!set_a.is_disjoint(&set_c)); + assert!(!set_c.is_disjoint(&set_a)); + assert!(set_a.is_subset(&set_c)); + assert!(!set_c.is_subset(&set_a)); + assert!(!set_a.is_superset(&set_c)); + assert!(set_c.is_superset(&set_a)); + + assert!(!set_c.is_disjoint(&set_d)); + assert!(!set_d.is_disjoint(&set_c)); + assert!(!set_c.is_subset(&set_d)); + assert!(!set_d.is_subset(&set_c)); + assert!(!set_c.is_superset(&set_d)); + assert!(!set_d.is_superset(&set_c)); +} + +#[test] +fn iter_comparisons() { + use std::iter::empty; + + fn check<'a, I1, I2>(iter1: I1, iter2: I2) + where + I1: Iterator, + I2: Iterator, + { + assert!(iter1.copied().eq(iter2)); + } + + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + check(set_a.difference(&set_a), empty()); + check(set_a.symmetric_difference(&set_a), empty()); + check(set_a.intersection(&set_a), 0..3); + check(set_a.union(&set_a), 0..3); + + check(set_a.difference(&set_b), 0..3); + check(set_b.difference(&set_a), 3..6); + check(set_a.symmetric_difference(&set_b), 0..6); + check(set_b.symmetric_difference(&set_a), (3..6).chain(0..3)); + check(set_a.intersection(&set_b), empty()); + check(set_b.intersection(&set_a), empty()); + check(set_a.union(&set_b), 0..6); + check(set_b.union(&set_a), (3..6).chain(0..3)); + + check(set_a.difference(&set_c), empty()); + check(set_c.difference(&set_a), 3..6); + check(set_a.symmetric_difference(&set_c), 3..6); + check(set_c.symmetric_difference(&set_a), 3..6); + check(set_a.intersection(&set_c), 0..3); + check(set_c.intersection(&set_a), 0..3); + check(set_a.union(&set_c), 0..6); + check(set_c.union(&set_a), 0..6); + + check(set_c.difference(&set_d), 0..3); + check(set_d.difference(&set_c), (6..9).rev()); + check( + set_c.symmetric_difference(&set_d), + (0..3).chain((6..9).rev()), + ); + check(set_d.symmetric_difference(&set_c), (6..9).rev().chain(0..3)); + check(set_c.intersection(&set_d), 3..6); + check(set_d.intersection(&set_c), (3..6).rev()); + check(set_c.union(&set_d), (0..6).chain((6..9).rev())); + check(set_d.union(&set_c), (3..9).rev().chain(0..3)); +} + +#[test] +fn ops() { + let empty = IndexSet::::new(); + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + #[allow(clippy::eq_op)] + { + assert_eq!(&set_a & &set_a, set_a); + assert_eq!(&set_a | &set_a, set_a); + assert_eq!(&set_a ^ &set_a, empty); + assert_eq!(&set_a - &set_a, empty); + } + + assert_eq!(&set_a & &set_b, empty); + assert_eq!(&set_b & &set_a, empty); + assert_eq!(&set_a | &set_b, set_c); + assert_eq!(&set_b | &set_a, set_c); + assert_eq!(&set_a ^ &set_b, set_c); + assert_eq!(&set_b ^ &set_a, set_c); + assert_eq!(&set_a - &set_b, set_a); + assert_eq!(&set_b - &set_a, set_b); + + assert_eq!(&set_a & &set_c, set_a); + assert_eq!(&set_c & &set_a, set_a); + assert_eq!(&set_a | &set_c, set_c); + assert_eq!(&set_c | &set_a, set_c); + assert_eq!(&set_a ^ &set_c, set_b); + assert_eq!(&set_c ^ &set_a, set_b); + assert_eq!(&set_a - &set_c, empty); + assert_eq!(&set_c - &set_a, set_b); + + assert_eq!(&set_c & &set_d, set_b); + assert_eq!(&set_d & &set_c, set_b); + assert_eq!(&set_c | &set_d, &set_a | &set_d); + assert_eq!(&set_d | &set_c, &set_a | &set_d); + assert_eq!(&set_c ^ &set_d, &set_a | &(&set_d - &set_b)); + assert_eq!(&set_d ^ &set_c, &set_a | &(&set_d - &set_b)); + assert_eq!(&set_c - &set_d, set_a); + assert_eq!(&set_d - &set_c, &set_d - &set_b); +} + +#[test] +#[cfg(feature = "std")] +fn from_array() { + let set1 = IndexSet::from([1, 2, 3, 4]); + let set2: IndexSet<_> = [1, 2, 3, 4].into(); + + assert_eq!(set1, set2); +} + +#[test] +fn iter_default() { + struct Item; + fn assert_default() + where + T: Default + Iterator, + { + assert!(T::default().next().is_none()); + } + assert_default::>(); + assert_default::>(); +} + +#[test] +fn test_binary_search_by() { + // adapted from std's test for binary_search + let b: IndexSet = [].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(0)); + + let b: IndexSet = [4].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&3)), Err(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&4)), Ok(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(1)); + + let b: IndexSet = [1, 2, 4, 6, 8, 9].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&7)), Err(4)); + assert_eq!(b.binary_search_by(|x| x.cmp(&8)), Ok(4)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&9)), Err(6)); + + let b: IndexSet = [1, 2, 4, 6, 7, 8, 9].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&8)), Ok(5)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8, 9].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&7)), Err(5)); + assert_eq!(b.binary_search_by(|x| x.cmp(&0)), Err(0)); + + let b: IndexSet = [1, 3, 3, 3, 7].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&0)), Err(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&1)), Ok(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&2)), Err(1)); + // diff from std as set merges the duplicate keys + assert!(match b.binary_search_by(|x| x.cmp(&3)) { + Ok(1..=2) => true, + _ => false, + }); + assert!(match b.binary_search_by(|x| x.cmp(&3)) { + Ok(1..=2) => true, + _ => false, + }); + assert_eq!(b.binary_search_by(|x| x.cmp(&4)), Err(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&6)), Err(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&7)), Ok(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&8)), Err(3)); +} + +#[test] +fn test_binary_search_by_key() { + // adapted from std's test for binary_search + let b: IndexSet = [].into(); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(0)); + + let b: IndexSet = [4].into(); + assert_eq!(b.binary_search_by_key(&3, |&x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&4, |&x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(1)); + + let b: IndexSet = [1, 2, 4, 6, 8, 9].into(); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&6, |&x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&7, |&x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&8, |&x| x), Ok(4)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8].into(); + assert_eq!(b.binary_search_by_key(&9, |&x| x), Err(6)); + + let b: IndexSet = [1, 2, 4, 6, 7, 8, 9].into(); + assert_eq!(b.binary_search_by_key(&6, |&x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&8, |&x| x), Ok(5)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8, 9].into(); + assert_eq!(b.binary_search_by_key(&7, |&x| x), Err(5)); + assert_eq!(b.binary_search_by_key(&0, |&x| x), Err(0)); + + let b: IndexSet = [1, 3, 3, 3, 7].into(); + assert_eq!(b.binary_search_by_key(&0, |&x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&1, |&x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&2, |&x| x), Err(1)); + // diff from std as set merges the duplicate keys + assert!(match b.binary_search_by_key(&3, |&x| x) { + Ok(1..=2) => true, + _ => false, + }); + assert!(match b.binary_search_by_key(&3, |&x| x) { + Ok(1..=2) => true, + _ => false, + }); + assert_eq!(b.binary_search_by_key(&4, |&x| x), Err(2)); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(2)); + assert_eq!(b.binary_search_by_key(&6, |&x| x), Err(2)); + assert_eq!(b.binary_search_by_key(&7, |&x| x), Ok(2)); + assert_eq!(b.binary_search_by_key(&8, |&x| x), Err(3)); +} + +#[test] +fn test_partition_point() { + // adapted from std's test for partition_point + let b: IndexSet = [].into(); + assert_eq!(b.partition_point(|&x| x < 5), 0); + + let b: IndexSet<_> = [4].into(); + assert_eq!(b.partition_point(|&x| x < 3), 0); + assert_eq!(b.partition_point(|&x| x < 4), 0); + assert_eq!(b.partition_point(|&x| x < 5), 1); + + let b: IndexSet<_> = [1, 2, 4, 6, 8, 9].into(); + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 4); + + let b: IndexSet<_> = [1, 2, 4, 5, 6, 8].into(); + assert_eq!(b.partition_point(|&x| x < 9), 6); + + let b: IndexSet<_> = [1, 2, 4, 6, 7, 8, 9].into(); + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 8), 5); + + let b: IndexSet<_> = [1, 2, 4, 5, 6, 8, 9].into(); + assert_eq!(b.partition_point(|&x| x < 7), 5); + assert_eq!(b.partition_point(|&x| x < 0), 0); + + let b: IndexSet<_> = [1, 3, 3, 3, 7].into(); + assert_eq!(b.partition_point(|&x| x < 0), 0); + assert_eq!(b.partition_point(|&x| x < 1), 0); + assert_eq!(b.partition_point(|&x| x < 2), 1); + assert_eq!(b.partition_point(|&x| x < 3), 1); + assert_eq!(b.partition_point(|&x| x < 4), 2); // diff from std as set merges the duplicate keys + assert_eq!(b.partition_point(|&x| x < 5), 2); + assert_eq!(b.partition_point(|&x| x < 6), 2); + assert_eq!(b.partition_point(|&x| x < 7), 2); + assert_eq!(b.partition_point(|&x| x < 8), 3); +} diff --git a/third_party/rust/indexmap/src/util.rs b/third_party/rust/indexmap/src/util.rs index a24dfafde7..377ff516f0 100644 --- a/third_party/rust/indexmap/src/util.rs +++ b/third_party/rust/indexmap/src/util.rs @@ -29,3 +29,25 @@ where } start..end } + +pub(crate) fn try_simplify_range(range: R, len: usize) -> Option> +where + R: RangeBounds, +{ + let start = match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(&i) if i <= len => i, + Bound::Excluded(&i) if i < len => i + 1, + _ => return None, + }; + let end = match range.end_bound() { + Bound::Unbounded => len, + Bound::Excluded(&i) if i <= len => i, + Bound::Included(&i) if i < len => i + 1, + _ => return None, + }; + if start > end { + return None; + } + Some(start..end) +} diff --git a/third_party/rust/indexmap/tests/quick.rs b/third_party/rust/indexmap/tests/quick.rs index e9d96acccb..56afee7239 100644 --- a/third_party/rust/indexmap/tests/quick.rs +++ b/third_party/rust/indexmap/tests/quick.rs @@ -19,8 +19,8 @@ use std::hash::Hash; use std::ops::Bound; use std::ops::Deref; -use indexmap::map::Entry as OEntry; -use std::collections::hash_map::Entry as HEntry; +use indexmap::map::Entry; +use std::collections::hash_map::Entry as StdEntry; fn set<'a, T: 'a, I>(iter: I) -> HashSet where @@ -113,6 +113,23 @@ quickcheck_limit! { true } + fn insert_sorted(insert: Vec<(u32, u32)>) -> bool { + let mut hmap = HashMap::new(); + let mut map = IndexMap::new(); + let mut map2 = IndexMap::new(); + for &(key, value) in &insert { + hmap.insert(key, value); + map.insert_sorted(key, value); + match map2.entry(key) { + Entry::Occupied(e) => *e.into_mut() = value, + Entry::Vacant(e) => { e.insert_sorted(value); } + } + } + itertools::assert_equal(hmap.iter().sorted(), &map); + itertools::assert_equal(&map, &map2); + true + } + fn pop(insert: Vec) -> bool { let mut map = IndexMap::new(); for &key in &insert { @@ -218,7 +235,7 @@ quickcheck_limit! { } // Use `u8` test indices so quickcheck is less likely to go out of bounds. - fn swap_indices(vec: Vec, a: u8, b: u8) -> TestResult { + fn set_swap_indices(vec: Vec, a: u8, b: u8) -> TestResult { let mut set = IndexSet::::from_iter(vec); let a = usize::from(a); let b = usize::from(b); @@ -240,8 +257,39 @@ quickcheck_limit! { TestResult::passed() } + fn map_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_swap_indices(vec, from, to, IndexMap::swap_indices) + } + + fn occupied_entry_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_swap_indices(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.entry(key) { + Entry::Occupied(entry) => entry.swap_indices(to), + _ => unreachable!(), + } + }) + } + + fn indexed_entry_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_swap_indices(vec, from, to, |map, from, to| { + map.get_index_entry(from).unwrap().swap_indices(to); + }) + } + + fn raw_occupied_entry_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + use indexmap::map::raw_entry_v1::{RawEntryApiV1, RawEntryMut}; + test_map_swap_indices(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.raw_entry_mut_v1().from_key(&key) { + RawEntryMut::Occupied(entry) => entry.swap_indices(to), + _ => unreachable!(), + } + }) + } + // Use `u8` test indices so quickcheck is less likely to go out of bounds. - fn move_index(vec: Vec, from: u8, to: u8) -> TestResult { + fn set_move_index(vec: Vec, from: u8, to: u8) -> TestResult { let mut set = IndexSet::::from_iter(vec); let from = usize::from(from); let to = usize::from(to); @@ -263,6 +311,138 @@ quickcheck_limit! { })); TestResult::passed() } + + fn map_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_move_index(vec, from, to, IndexMap::move_index) + } + + fn occupied_entry_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_move_index(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.entry(key) { + Entry::Occupied(entry) => entry.move_index(to), + _ => unreachable!(), + } + }) + } + + fn indexed_entry_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_move_index(vec, from, to, |map, from, to| { + map.get_index_entry(from).unwrap().move_index(to); + }) + } + + fn raw_occupied_entry_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + use indexmap::map::raw_entry_v1::{RawEntryApiV1, RawEntryMut}; + test_map_move_index(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.raw_entry_mut_v1().from_key(&key) { + RawEntryMut::Occupied(entry) => entry.move_index(to), + _ => unreachable!(), + } + }) + } + + fn occupied_entry_shift_insert(vec: Vec, i: u8) -> TestResult { + test_map_shift_insert(vec, i, |map, i, key| { + match map.entry(key) { + Entry::Vacant(entry) => entry.shift_insert(i, ()), + _ => unreachable!(), + }; + }) + } + + fn raw_occupied_entry_shift_insert(vec: Vec, i: u8) -> TestResult { + use indexmap::map::raw_entry_v1::{RawEntryApiV1, RawEntryMut}; + test_map_shift_insert(vec, i, |map, i, key| { + match map.raw_entry_mut_v1().from_key(&key) { + RawEntryMut::Vacant(entry) => entry.shift_insert(i, key, ()), + _ => unreachable!(), + }; + }) + } +} + +fn test_map_swap_indices(vec: Vec, a: u8, b: u8, swap_indices: F) -> TestResult +where + F: FnOnce(&mut IndexMap, usize, usize), +{ + let mut map = IndexMap::::from_iter(vec.into_iter().map(|k| (k, ()))); + let a = usize::from(a); + let b = usize::from(b); + + if a >= map.len() || b >= map.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(map.keys().copied()); + vec.swap(a, b); + + swap_indices(&mut map, a, b); + + // Check both iteration order and hash lookups + assert!(map.keys().eq(vec.iter())); + assert!(vec + .iter() + .enumerate() + .all(|(i, x)| { map.get_index_of(x) == Some(i) })); + TestResult::passed() +} + +fn test_map_move_index(vec: Vec, from: u8, to: u8, move_index: F) -> TestResult +where + F: FnOnce(&mut IndexMap, usize, usize), +{ + let mut map = IndexMap::::from_iter(vec.into_iter().map(|k| (k, ()))); + let from = usize::from(from); + let to = usize::from(to); + + if from >= map.len() || to >= map.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(map.keys().copied()); + let x = vec.remove(from); + vec.insert(to, x); + + move_index(&mut map, from, to); + + // Check both iteration order and hash lookups + assert!(map.keys().eq(vec.iter())); + assert!(vec + .iter() + .enumerate() + .all(|(i, x)| { map.get_index_of(x) == Some(i) })); + TestResult::passed() +} + +fn test_map_shift_insert(vec: Vec, i: u8, shift_insert: F) -> TestResult +where + F: FnOnce(&mut IndexMap, usize, u8), +{ + let mut map = IndexMap::::from_iter(vec.into_iter().map(|k| (k, ()))); + let i = usize::from(i); + if i >= map.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(map.keys().copied()); + let x = vec.pop().unwrap(); + vec.insert(i, x); + + let (last, ()) = map.pop().unwrap(); + assert_eq!(x, last); + map.shrink_to_fit(); // so we might have to grow and rehash the table + + shift_insert(&mut map, i, last); + + // Check both iteration order and hash lookups + assert!(map.keys().eq(vec.iter())); + assert!(vec + .iter() + .enumerate() + .all(|(i, x)| { map.get_index_of(x) == Some(i) })); + TestResult::passed() } use crate::Op::*; @@ -310,10 +490,10 @@ where b.remove(k); } RemoveEntry(ref k) => { - if let OEntry::Occupied(ent) = a.entry(k.clone()) { + if let Entry::Occupied(ent) = a.entry(k.clone()) { ent.swap_remove_entry(); } - if let HEntry::Occupied(ent) = b.entry(k.clone()) { + if let StdEntry::Occupied(ent) = b.entry(k.clone()) { ent.remove_entry(); } } @@ -452,6 +632,12 @@ quickcheck_limit! { assert_sorted_by_key(map, |t| t.1); } + fn sort_3(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + map.sort_by_cached_key(|&k, _| std::cmp::Reverse(k)); + assert_sorted_by_key(map, |t| std::cmp::Reverse(t.0)); + } + fn reverse(keyvals: Large>) -> () { let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); diff --git a/third_party/rust/interrupt-support/.cargo-checksum.json b/third_party/rust/interrupt-support/.cargo-checksum.json index 052b3da11a..89a260dc6e 100644 --- a/third_party/rust/interrupt-support/.cargo-checksum.json +++ b/third_party/rust/interrupt-support/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c2ca168a6ba35961681f351e010d21696d8779ddac06436338431bd39ed16ebb","README.md":"7f1418b4a7c138ba20bcaea077fe6cf0d6ffbaf6df6b90c80efc52aa0d0e2e9f","src/error.rs":"b83cbe8abd22a9d687508d236a2a77e28b3fc6c39673633e5820cc0e3fc86cba","src/interruptee.rs":"c56f9ac610d0b24a128a907266432287558c4b73f6c24b82674ca7894181d18f","src/lib.rs":"cf44a84310913be5264e1c4a3e004a9f7a6cd82d01a109bb6ac4d6002b5dd560","src/shutdown.rs":"b9dfdb717932301035001a0398967384f1b993e14505860415d023febbe82d63","src/sql.rs":"7e050313884a281e6b3fc7a4514374e08cb9e5f3c5aefb873be92e56f30af660"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"f31bc542c5a3e5dfe82a7c62fa4a0a3e5b56424b77eb7ad913aa322e5e070c60","README.md":"7f1418b4a7c138ba20bcaea077fe6cf0d6ffbaf6df6b90c80efc52aa0d0e2e9f","build.rs":"49840f26c73c5db19cb4e7f02930e49d7a19648168b83f2313ac1a0303c103df","src/error.rs":"b83cbe8abd22a9d687508d236a2a77e28b3fc6c39673633e5820cc0e3fc86cba","src/interrupt_support.udl":"5472e585280576de4fab587278e6e24cc26a7c74e0489aeef3c41671c768f662","src/interruptee.rs":"c56f9ac610d0b24a128a907266432287558c4b73f6c24b82674ca7894181d18f","src/lib.rs":"cf44a84310913be5264e1c4a3e004a9f7a6cd82d01a109bb6ac4d6002b5dd560","src/shutdown.rs":"881a358b053fdd01b56b59864547b6456625dea4ee311b2e0ed3762009516ce6","src/sql.rs":"ba04479f740a25310fd171a473b9870580ad9f02bb2f1109c0171694cad4c2cd"},"package":null} \ No newline at end of file diff --git a/third_party/rust/interrupt-support/Cargo.toml b/third_party/rust/interrupt-support/Cargo.toml index ced41d7c4e..78dfc448f9 100644 --- a/third_party/rust/interrupt-support/Cargo.toml +++ b/third_party/rust/interrupt-support/Cargo.toml @@ -20,6 +20,7 @@ license = "MPL-2.0" [dependencies] lazy_static = "1.4" parking_lot = ">=0.11,<=0.12" +uniffi = "0.27.1" [dependencies.rusqlite] version = "0.30.0" @@ -29,3 +30,7 @@ features = [ "bundled", "unlock_notify", ] + +[build-dependencies.uniffi] +version = "0.27.1" +features = ["build"] diff --git a/third_party/rust/interrupt-support/build.rs b/third_party/rust/interrupt-support/build.rs new file mode 100644 index 0000000000..20533b7a2f --- /dev/null +++ b/third_party/rust/interrupt-support/build.rs @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +fn main() { + uniffi::generate_scaffolding("./src/interrupt_support.udl").unwrap(); +} diff --git a/third_party/rust/interrupt-support/src/interrupt_support.udl b/third_party/rust/interrupt-support/src/interrupt_support.udl new file mode 100644 index 0000000000..06264fec0e --- /dev/null +++ b/third_party/rust/interrupt-support/src/interrupt_support.udl @@ -0,0 +1,5 @@ +namespace interrupt_support { + // Enter shutdown mode, causing all current and future interruptable operations to be interrupted. + void shutdown(); +}; + diff --git a/third_party/rust/interrupt-support/src/shutdown.rs b/third_party/rust/interrupt-support/src/shutdown.rs index 9c64df27e8..88a56029b8 100644 --- a/third_party/rust/interrupt-support/src/shutdown.rs +++ b/third_party/rust/interrupt-support/src/shutdown.rs @@ -12,13 +12,14 @@ License, v. 2.0. If a copy of the MPL was not distributed with this /// /// Here's how add shutdown support to a component: /// -/// - Use `SqlInterruptScope::new_with_shutdown_check()` to create a new -/// `SqlInterruptScope` /// - Database connections need to be wrapped in a type that: /// - Implements `AsRef`. /// - Gets wrapped in an `Arc<>`. This is needed so the shutdown code can get a weak reference to /// the instance. /// - Calls `register_interrupt()` on creation +/// - Use `SqlInterruptScope::begin_interrupt_scope()` before each operation. +/// This will return an error if shutdown mode is in effect. +/// The interrupt scope should be periodically checked to handle the operation being interrupted/shutdown after it started. /// /// See `PlacesDb::begin_interrupt_scope()` and `PlacesApi::new_connection()` for an example of /// how this works. diff --git a/third_party/rust/interrupt-support/src/sql.rs b/third_party/rust/interrupt-support/src/sql.rs index 6f361013fc..a9f10f8cf8 100644 --- a/third_party/rust/interrupt-support/src/sql.rs +++ b/third_party/rust/interrupt-support/src/sql.rs @@ -120,3 +120,10 @@ impl Interruptee for SqlInterruptScope { self.was_interrupted() } } + +// Needed to allow Weak to be passed to `interrupt::register_interrupt` +impl AsRef for SqlInterruptHandle { + fn as_ref(&self) -> &SqlInterruptHandle { + self + } +} diff --git a/third_party/rust/libc/.cargo-checksum.json b/third_party/rust/libc/.cargo-checksum.json index 2ff314778c..f2b650512a 100644 --- a/third_party/rust/libc/.cargo-checksum.json +++ b/third_party/rust/libc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"a93fcda0a76e1975fcfb0aa2ba00c9b1864f9ae6062704a294d81a3688898e10","Cargo.toml":"0d743c123c9c30b09413dce51344d4dfaf958e8eef3e1f4e7682931a8d781ec3","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"4da2919bb509f3f06163778478494f780ca6627cb79ccab5d2c828c8d88dc133","build.rs":"01bc1b8934bb80982a36f46c61508f32cb05c4deab15cb9afb5bf9da285d5c1b","rustfmt.toml":"eaa2ea84fc1ba0359b77680804903e07bb38d257ab11986b95b158e460f787b2","src/fixed_width_ints.rs":"7f986e5f5e68d25ef04d386fd2f640e8be8f15427a8d4a458ea01d26b8dca0ca","src/fuchsia/aarch64.rs":"893fcec48142d273063ffd814dca33fbec92205fd39ada97075f85201d803996","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"07410f511835da540e5bdc55f7384c71cd7836fe63bbca6be547de825f823c03","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/riscv64.rs":"617cd75e79e0e20f664db764a4dc2a396d9fd11a4d95371acd91ed4811293b11","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"2d04cfa0d55dc0a2e36fdc4a45819b9d3722af19bb1932778b44feb4c2f81036","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"9d7030ba3e21064a0f3a8e79927c70d5a95a0026be61be084f3ab021e243e503","src/macros.rs":"5f985b3de7b18833f866bf832b8ffb0430f0f70aa9a468b6a2c855c1bf9d33e4","src/psp.rs":"0a7d5121a8cc2903009f586c00e4ae2d6126d24eb90531dafaba6f59823aa6b2","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/solid/aarch64.rs":"a726e47f324adf73a4a0b67a2c183408d0cad105ae66acf36db37a42ab7f8707","src/solid/arm.rs":"e39a4f74ebbef3b97b8c95758ad741123d84ed3eb48d9cf4f1f4872097fc27fe","src/solid/mod.rs":"5f4151dca5132e4b4e4c23ab9737e12856dddbdc0ca3f7dbc004328ef3c8acde","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/teeos/mod.rs":"eb664b3e94bcd44d8c8147b56c2187139d01bf8402ee0bb81967a5a50a3e927f","src/unix/aix/mod.rs":"d4ed2a4eff43c60a251bba150868d0249bf79dd6fb835d5287c352577452712b","src/unix/aix/powerpc64.rs":"cf374d81139d45f9d77c6a764f640bfbf7e0a5903689652c8296f8e10d55169b","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"2546ad3eb6aecb95f916648bc63264117c92b4b4859532b34cb011e4c75a5a72","src/unix/bsd/apple/b64/aarch64/align.rs":"2eaf0f561a32bdcbf4e0477c8895d5e7bcb5cdebd5fef7b4df2ca8e38e144d94","src/unix/bsd/apple/b64/aarch64/mod.rs":"44c217a4f263afe7a97435de9323d20a96c37836f899ca0925306d4b7e073c27","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"f5e278a1af7fb358891d1c9be4eb7e815aaca0c5cb738d0c3604ba2208a856f7","src/unix/bsd/apple/b64/x86_64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/x86_64/mod.rs":"8c87c5855038aae5d433c8f5eb3b29b0a175879a0245342b3bfd83bdf4cfd936","src/unix/bsd/apple/long_array.rs":"3cf1f19b812e6d093c819dc65ce55b13491963e0780eda0d0bd1577603e81948","src/unix/bsd/apple/mod.rs":"1da404688e9d67171403f2486456aac9d36a2db31ee7ebc308f14d6277754eef","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"8295b8bb0dfd38d2cdb4d9192cdeeb534cc6c3b208170e64615fa3e0edb3e578","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"2777f94909a798df1b8030fb86d02e2118d0ac3e49e9a542df54a569ca5ae2f9","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"6c8e216385f53a4bf5f171749b57602fc34a4e4b160a44ca31c058cb0c8a2126","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"e243ae0e89623d4fa9f85afe14369cc5fd5f2028ea715773dbec722ba80dac1f","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"bef9fae288a4f29e941ea369be1cd20b170040e60665a4d49a4a9e79009b72d8","src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs":"2df36a7f122f6d6e5753cfb4d22e915cc80f6bc91c0161b3daae55a481bfd052","src/unix/bsd/freebsdlike/freebsd/freebsd13/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs":"88be47524b28b6635ccb1e85ea511bf17337be0af7e9baa740c341ac9e83a6f7","src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs":"2df36a7f122f6d6e5753cfb4d22e915cc80f6bc91c0161b3daae55a481bfd052","src/unix/bsd/freebsdlike/freebsd/freebsd14/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs":"6ddc6abf6d5ccaea0d8cccf521e8ca6457efcad3086af4155628d5d06d672346","src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs":"e7b5863e222d6cc416b6b0fbe71690fad909e899b4c4ae810bbca117e4fcb650","src/unix/bsd/freebsdlike/freebsd/freebsd15/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs":"93115c1a9faa43ebf58b7dee3582aed5a54291b284764e370e7f649b2e6a9565","src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs":"e7b5863e222d6cc416b6b0fbe71690fad909e899b4c4ae810bbca117e4fcb650","src/unix/bsd/freebsdlike/freebsd/mod.rs":"5669c341804bccf27eb03965f11bd640a762a9898a5baa18b5a319fb1d8abddf","src/unix/bsd/freebsdlike/freebsd/powerpc.rs":"9ca3f82f88974e6db5569f2d76a5a3749b248a31747a6c0da5820492bdfeca42","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/riscv64.rs":"fa4bed4c58cad24ba3395941c7fa6b11e089551a04714f9561078e400f5b2b62","src/unix/bsd/freebsdlike/freebsd/x86.rs":"6766e2ce85e187b306cd3b0b8d7e15b8f4042c5cff81d89b3af69ecc99c70ab0","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"51e4dd0c8ae247bb652feda5adad9333ea3bb30c750c3a3935e0b0e47d7803eb","src/unix/bsd/freebsdlike/mod.rs":"29f5ae7c8bcd64219e77f99ba9b26527299cf4908b20f7d1ec4f625b5194a44c","src/unix/bsd/mod.rs":"f5974098ef3d1a29774bc0bde27dc9c89c3880f9ed7b4d7ea334b595dc39ff94","src/unix/bsd/netbsdlike/mod.rs":"ea60540aa4edd4e43136749d5df497b1dc072b9912b6030dd1ab794a6d1c3c3c","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"057ee877db7193ba0dc10801b9a6563ac6dbdb78376d6851a84cb12b30841759","src/unix/bsd/netbsdlike/netbsd/arm.rs":"949b55e4dee1c8c511f4f061a6a57ac876a6c0eabfaf5cc20e9ab40d8f41b2e0","src/unix/bsd/netbsdlike/netbsd/mips.rs":"88be18ac43ba224c77e78e4179b6761debc5e6c30a258fac56263809c7af4fbc","src/unix/bsd/netbsdlike/netbsd/mod.rs":"b8d6f089fc8eb2cb59e45335a26c9ce871b846216c9859b553c6b91982f8de33","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/riscv64.rs":"1cbe2e5ed681cb1054b699da37daaf6c714267df7d332c90fc2a589b11579625","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"532b76199d6c71ff996eade9f906c55a72c9aff489595d25a21e21878cfd740b","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"dd91931d373b7ecaf6e2de25adadee10d16fa9b12c2cbacdff3eb291e1ba36af","src/unix/bsd/netbsdlike/openbsd/arm.rs":"01580d261bc6447bb327a0d982181b7bdabfa066cee65a30373d3ced729ad307","src/unix/bsd/netbsdlike/openbsd/mips64.rs":"8532a189ae10c7d668d9d4065da8b05d124e09bd39442c9f74a7f231c43eca48","src/unix/bsd/netbsdlike/openbsd/mod.rs":"7b93b5b24b3c72a79b2de19b47ac2f56b29d87e9fc8f4c721a63d1e87ec83fcc","src/unix/bsd/netbsdlike/openbsd/powerpc.rs":"01580d261bc6447bb327a0d982181b7bdabfa066cee65a30373d3ced729ad307","src/unix/bsd/netbsdlike/openbsd/powerpc64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/riscv64.rs":"1fe3332dc705a13e6242219970f5449d6d7a73e2e6c8537ab8e421d8a6f2e3ff","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"d31db31630289c85af3339dbe357998a21ca584cbae31607448fe2cf7675a4e1","src/unix/haiku/b32.rs":"a2efdbf7158a6da341e1db9176b0ab193ba88b449616239ed95dced11f54d87b","src/unix/haiku/b64.rs":"ff8115367d3d7d354f792d6176dfaaa26353f57056197b563bf4681f91ff7985","src/unix/haiku/mod.rs":"ad70cc42ed83ac38664941418b0b9bfe1ead7a0ff82b121ea8df65483e3b7e1c","src/unix/haiku/native.rs":"3bbf42c3e3e437e8b626be67c72b6adcec60646eb5dd4bf8471a603cbbb5e5a4","src/unix/haiku/x86_64.rs":"3ec3aeeb7ed208b8916f3e32d42bfd085ff5e16936a1a35d9a52789f043b7237","src/unix/hurd/align.rs":"03c79b2cd8270ebd0cf93cb475a8f1ff85b28175ea0de007ede17cad94a89b03","src/unix/hurd/b32.rs":"2ba90ed973f90366c36a6387833a3df42abfee9622d4a0352635937d4a89eaf4","src/unix/hurd/b64.rs":"d919b4aec9b3080ad24c125c57b2c8b2e483d72045f1554c429d14560355846f","src/unix/hurd/mod.rs":"6a2f0db80a3cd34b55ef82e357da4d453d5d190a2dd4501bfa5d0bb9bca0de4f","src/unix/hurd/no_align.rs":"03c79b2cd8270ebd0cf93cb475a8f1ff85b28175ea0de007ede17cad94a89b03","src/unix/linux_like/android/b32/arm.rs":"ce582de7e983a33d3bfad13075c53aac9016cee35f06ad8653ee9072c3ec2564","src/unix/linux_like/android/b32/mod.rs":"7c173e0375119bf06a3081652faede95e5bcd6858e7576b7533d037978737c8f","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"e6d107efbcd37b5b85dfa18f683300cbf768ffa0237997a9fa52b184a53323ac","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/int128.rs":"1735f6f5c56770d20dd426442f09724d9b2052b46a7cd82f23f3288a4a7276de","src/unix/linux_like/android/b64/aarch64/mod.rs":"10e963e29ff209703de6336c99cca96fd79789438d34c82a693eae56e8916c3c","src/unix/linux_like/android/b64/mod.rs":"71e4fcbe952bfa4a5f9022f3972e906917b38f729b9d8ef57cd5d179104894ac","src/unix/linux_like/android/b64/riscv64/align.rs":"0bf138f84e5327d8339bcd4adf071a6832b516445e597552c82bbd881095e3a8","src/unix/linux_like/android/b64/riscv64/mod.rs":"19d4bf2237c47127eba9144e0b82e995bc079315e719179a91813b0ae7b0e49d","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"4ec2de11a9b65c4325b7b991f0b99a414975e0e61ba8668caca5d921e9b314d1","src/unix/linux_like/android/mod.rs":"e7e87cb2aa2665a7113e3cbcad58c6b4c8a04c9989a6773895b5ecc806348258","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/lfs64.rs":"3776af30a758d765a88920ec4fde442ab89040da13d3b3625c7fbcb8a958559f","src/unix/linux_like/emscripten/mod.rs":"70d4591730a731ee32788a9d8d2de379592844ec36b7d1723514179605587713","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"bc5abcd38e2320171e0981e773c9c5fe3e0d5a66fdff049228f6a1acad80ef8b","src/unix/linux_like/linux/arch/generic/mod.rs":"ebb6a0a96bcbfbe3432bf67d88ea5d006ccb47f345dab33562bb052d110a6946","src/unix/linux_like/linux/arch/mips/mod.rs":"18dade308bf04717630fd6467b92c23560c83ac5274a8469569f260aa4671239","src/unix/linux_like/linux/arch/mod.rs":"5bd5361f8a6ab4e18bbba6da9f92c164ae252b15a0ed10064812544aa1fdf198","src/unix/linux_like/linux/arch/powerpc/mod.rs":"0bc2d2667a00eca81f4abeb6d613a90848a947f51224103f83268928b8197629","src/unix/linux_like/linux/arch/sparc/mod.rs":"5e6777863e74a9e2aa9dc487f1059783dd211babc2b32d6bf676f311e49c55d6","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"6ec0eb3ee93f7ae99fd714b4deabfb5e97fbcefd8c26f5a45fb8e7150899cdeb","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"f68ec59b6407f9d4e326f3e71a41ec21f19ecfc703edf9a93e496f661fed5506","src/unix/linux_like/linux/gnu/b32/csky/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/csky/mod.rs":"8729b68e433e94c2128e51a7db4fd555938e4be4dc64584c352b24a20d9c8e91","src/unix/linux_like/linux/gnu/b32/m68k/align.rs":"8faa92f77a9232c035418d45331774e64a9a841d99c91791570a203bf2b45bcb","src/unix/linux_like/linux/gnu/b32/m68k/mod.rs":"80956d3fef163ecf248828a6f38782dd8ae856d86b1bb5aac2de36032dbd8ea0","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"96e22350d5d132d917c743d6560464500652c67b52c3d0e8474494487df3365d","src/unix/linux_like/linux/gnu/b32/mod.rs":"b56625dd20dd48a8699034d349ef089c540c0ddcbf8a3481d598d101f8b40b78","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"20fc3cc4fe1ef6617b63b61b897f782ceb9c2842fc718f504a1840537229bf47","src/unix/linux_like/linux/gnu/b32/riscv32/align.rs":"d321491612be8d5c61b6ec2dc0111beb3a22e58803f99cd37543efe86621b119","src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs":"887288a0a1cfff319d0e15edcdc4fcb31fd643ff41715ec5244c8f2413624169","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"cc4342b949e4d796f304acd9dfe3f721a1c2f37fec16b42d3bb27dc94723af37","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"06d4db4ee8352f62a0a5ead0c4d6ea0a78feff522f19b9bc5772f6dd920ffd80","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"fdf1c72375a2167699157e0dd825422690bb6719f7bc69515a2e5846d0431d7c","src/unix/linux_like/linux/gnu/b64/aarch64/fallback.rs":"832e7487249c1c0bb6e9911ce3f7d32ca22378e42392ab83c56915cbc59d8be3","src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs":"bf4611b737813deef6787babf6c01698605f3b75482269b8546318667bc68e29","src/unix/linux_like/linux/gnu/b64/aarch64/int128.rs":"1735f6f5c56770d20dd426442f09724d9b2052b46a7cd82f23f3288a4a7276de","src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs":"11a950697fdda0258c6e37c6b13993348c8de4134105ed4faa79358e53175072","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"8202614484da36c388d2ffdd2554c56bb4f9db8e5bd621f8c36114cdcfeec644","src/unix/linux_like/linux/gnu/b64/loongarch64/align.rs":"060aa33cc737966c691aab8511c5c5729e551458ce18d0e284e0d45f39beeb60","src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs":"dc29dfdadd754ec355b82a7ca6636de7ed97f7ba98f132b71cb49f39d6bd8e3f","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"73532be4b5775acf9524c77feeefe1f6d1936ceffef908d01dd2586986520f2d","src/unix/linux_like/linux/gnu/b64/mod.rs":"6a160ef25439c4fecdb0e3bd0b818742263c791364da874d4febd3aa644ec8e2","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"a90c2641616c620e9d1fea87695ce046e14f9da2282bb93f761eeb4077c74741","src/unix/linux_like/linux/gnu/b64/riscv64/align.rs":"d321491612be8d5c61b6ec2dc0111beb3a22e58803f99cd37543efe86621b119","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"68a2a20fa4ef92cdf382d8095168eb88875b7aa8c9c47ee5f1e527393b6c16fa","src/unix/linux_like/linux/gnu/b64/s390x.rs":"1ea9e39432ce6bf68779d33546dacd7d39477a9f8fc3da4f4f339e4538cb74c3","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"bed381c44cec2a5b50125f7e548ab487d4c829006c971d152a611b7141760052","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"62e822478356db4a73b6bbd1b36d825b893939ab4b308ec11b0578bcc4b49769","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"332846e4a5920d7e6b05df0448a2333c5dd00fb27cb33654648f507ee89dbec5","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"38f74ce15d9662ce4818815a2b87be1618d5e45f190f7e4db84ff3285b4421fb","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"b20218a11364a6dec87f96d6c0d8b19e660697ab09ad5ee0e9b3a9dafedaaebb","src/unix/linux_like/linux/gnu/mod.rs":"583d04f92435da76fd3f87182ab67b5e6dd8c35a63b240d8c4555fb1ab70f3f8","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"e5000a0746c354b26e3c469ed7802a86a7bcca67446047c4e2d5526ea80c4d32","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"af10147d7c3661751750a58ffad089d5d18d180cd18303c653aef126c07ccd91","src/unix/linux_like/linux/musl/b32/hexagon.rs":"d079cab42529f7dab699334d43168c74ff4aa0282f11040a8b7d274b65767a7a","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"e44043766f7cd26de7ffa4232654afb6feb03e58dbd5890717970887bd003151","src/unix/linux_like/linux/musl/b32/mod.rs":"31677597fd9544c4b1ec1477628288f6273fabbc06e38f33da862ad55f019ce1","src/unix/linux_like/linux/musl/b32/powerpc.rs":"3dae56a4e7789bcc5314e419fea5e4b2495367b4f1a49d1c9477c60225d65eef","src/unix/linux_like/linux/musl/b32/riscv32/align.rs":"efd2accf33b87de7c7547903359a5da896edc33cd6c719552c7474b60d4a5d48","src/unix/linux_like/linux/musl/b32/riscv32/mod.rs":"3ee845d272f91a1908d5f421d7c353e1f14681bbdfef64410e408f4c14365a91","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"f2b53ae0034c833244b7cdb8c670349bf8272a03abf04152eba65cf62810484d","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"6ba32725d24d7d8e6aa111f3b57aafa318f83b606abe96561329151829821133","src/unix/linux_like/linux/musl/b64/aarch64/int128.rs":"1735f6f5c56770d20dd426442f09724d9b2052b46a7cd82f23f3288a4a7276de","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"45ce6897afcc960267bb7505702b639daf94dc69428a213bf1aefd367ca32adc","src/unix/linux_like/linux/musl/b64/mips64.rs":"a968ef9c54fa22293085f318c8472c1754482df92cc500568dc33bd807d71ea6","src/unix/linux_like/linux/musl/b64/mod.rs":"1a8391febf3e750185ffc5c69c9f9e411f4e8c53b5d994cb231df24480169686","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"140e579800a67315f4cb8a42b22aa8157eae34ffe626e77e421b43c53c23b34d","src/unix/linux_like/linux/musl/b64/riscv64/align.rs":"d321491612be8d5c61b6ec2dc0111beb3a22e58803f99cd37543efe86621b119","src/unix/linux_like/linux/musl/b64/riscv64/mod.rs":"c5944526d7e19cd43e9d14d119a1d98f8780db7ecbcc79e69d7b9348e596b520","src/unix/linux_like/linux/musl/b64/s390x.rs":"8557b3477ca8cefef7fce764a3c25441929a54e50ead4091f6f7823c427cd728","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"77309276ad7a42cbe59ca381f23590b7a143aded05555b34a5b307b808cbca6e","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"a91c4f18027c9958037f78ae48f6352d23cb4e6f2995b2cc8de7dce0e5759470","src/unix/linux_like/linux/musl/lfs64.rs":"3e4fb381f3a0756520bde0f1692d4fa45e4ae8133bf7d7c64b0e3fdd512f235f","src/unix/linux_like/linux/musl/mod.rs":"f0a23b77e5465c05a5dd95c3c6b7959c597010416226503ff3719796367ba98e","src/unix/linux_like/linux/no_align.rs":"62cdca0e011937aaf09a51ca86d9f0ee0fdb05f61ec3c058e6a5d5fa6357d784","src/unix/linux_like/linux/non_exhaustive.rs":"181a05bf94fdb911db83ce793b993bd6548a4115b306a7ef3c10f745a8fea3e9","src/unix/linux_like/linux/uclibc/align.rs":"9ed16138d8e439bd90930845a65eafa7ebd67366e6bf633936d44014f6e4c959","src/unix/linux_like/linux/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/uclibc/arm/mod.rs":"50288ff9e411ab0966da24838f2c2a5618021bc19c422a04f577b2979ef4081e","src/unix/linux_like/linux/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs":"d0c4434e2bf813372c418a8f516c706cdccc9f7be2f0921b2207b0afdb66fe81","src/unix/linux_like/linux/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs":"3f38ee6a4690b9d7594be20d216467a34d955f7653c2c8ce1e6147daeb53f1e0","src/unix/linux_like/linux/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/linux_like/linux/uclibc/mips/mod.rs":"a048fce1c2d9b1ad57305642e8ad05ca0f0c7e4753267a2e2d6b4fee5db3b072","src/unix/linux_like/linux/uclibc/mod.rs":"193a03fa4aa5345394e39d2115c9427e806c9f28b0fde685719119e1c90ca08a","src/unix/linux_like/linux/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/linux_like/linux/uclibc/x86_64/l4re.rs":"8485b9182b7c67f7344fab377e7cc2a72afefd9ab63837c860514abba9728d76","src/unix/linux_like/linux/uclibc/x86_64/mod.rs":"196d03affbefb85716937c15904831e731eb222ee906e05e42102d639a8152ea","src/unix/linux_like/linux/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/unix/linux_like/mod.rs":"86dbbd81484df25ad7c6a82d2d3b5eab2f8e7751853c1dd4308b7eee57b5fbca","src/unix/mod.rs":"923a32e8fd9e462eda4e90ae7ee501da1d12aaadc1bf2e9722f02581a5d3fc6c","src/unix/newlib/aarch64/mod.rs":"964c096288da836b53c0c71d7f3a97048d177da220a69314c5ce93ba330d72af","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"cf754f8b1197489fca01e881a4b4b146e814998e4b365f116fa1a102c00e6a4e","src/unix/newlib/espidf/mod.rs":"29969da41f0042197b21cfa7c0ad2244b4519ecab0fb7de3d0a7655b4f3937e1","src/unix/newlib/generic.rs":"5f0b5d07ddb5a5d60580f9561fdb05e9218d9751d4068c4aadad2ba6b950aabf","src/unix/newlib/horizon/mod.rs":"3a521d22bf932fc01c1d26d1f9bff20f11b1855b03c8236a8eb18310f6cab5a8","src/unix/newlib/mod.rs":"e5d5faf27a6336b9f1c02b8726427801d906a14dae766852b4e85c1a92df06c8","src/unix/newlib/no_align.rs":"e0743b2179495a9514bc3a4d1781e492878c4ec834ee0085d0891dd1712e82fb","src/unix/newlib/powerpc/mod.rs":"cc9e188711b9bf614323ad6c48e0d2e1a1ecc5d3bc64961ba451f29c6c22d2d8","src/unix/newlib/vita/mod.rs":"d849a01841744ea5e04635c8f69c9e2b44791320eb9d629b9d0fee0a4c5d502a","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/nto/aarch64.rs":"4709c9afdc8d583be876598e7c238499ee3e8da5bd2baa614d9c7dd414851555","src/unix/nto/mod.rs":"07268897fc8810f2fed22ab56f87757f71c73ba401abd848bccca6b183a13b02","src/unix/nto/neutrino.rs":"799bff4ab01a6424db6c5a2b76aa5679826d41495f9d13c63485bf13bc80026b","src/unix/nto/x86_64.rs":"a3e18e93c2999da1cd7a6f748a4b60c07aefb73d8ea2aafec19a84cfb040bc8e","src/unix/redox/mod.rs":"a9f54687307883beb4a410216dc8e36b85d72b0463bc6b1520bd91edf3947d23","src/unix/solarish/compat.rs":"00f1ee3faec9da69204e42f025f6735dd13d894071a154425dcc43ecbdd06e7f","src/unix/solarish/illumos.rs":"cd93c2d84722bbf9933a92842a8998eb0b2afc962f50bc2546ad127b82809fa7","src/unix/solarish/mod.rs":"10b2369edc027fcb2e41e5342f24946aa01ee1549a6d7f06b9a3956ff84518bc","src/unix/solarish/solaris.rs":"41b350a89ddf01cd12a10f93640f92be53be0b0d976021cdc08da17bf3e72edf","src/unix/solarish/x86.rs":"e86e806df0caed72765040eaa2f3c883198d1aa91508540adf9b7008c77f522e","src/unix/solarish/x86_64.rs":"ec2b01f194eb8a6a27133c57681da195a949e03098f3ea1e847227a9c09ef5fc","src/unix/solarish/x86_common.rs":"ac869d9c3c95645c22460468391eb1982023c3a8e02b9e06a72e3aef3d5f1eac","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"4105a2e6a6c9908fc1f2a770ede052bb0d6a5d9d49e32d815f557081efc49860","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"d4147353537d7556076ff1a1c4cb96cc2dae9416a5d176ba8a077ad55ab7ec18","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"3c8c7edb7cdf5d0c44af936db2a94869585c69dfabeef30571b4f4e38375767a","src/windows/mod.rs":"9fdc5e1c62c441abef7bc62a7343efb2041edc24db9ac0efc0f74df55b69e249","src/windows/msvc/mod.rs":"c068271e00fca6b62bc4bf44bcf142cfc38caeded9b6c4e01d1ceef3ccf986f4","src/xous.rs":"eb0675f25ba01f73072d2b70907fb8abb1148facefe5a20756c49250f3d65fae","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4"},"package":"13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"a93fcda0a76e1975fcfb0aa2ba00c9b1864f9ae6062704a294d81a3688898e10","Cargo.toml":"c7d137b327d60cad5b7bd3ef97ec93f57fdde1101b14250b56fe1a1d3afc98ef","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"4da2919bb509f3f06163778478494f780ca6627cb79ccab5d2c828c8d88dc133","build.rs":"01bc1b8934bb80982a36f46c61508f32cb05c4deab15cb9afb5bf9da285d5c1b","rustfmt.toml":"eaa2ea84fc1ba0359b77680804903e07bb38d257ab11986b95b158e460f787b2","src/fixed_width_ints.rs":"7f986e5f5e68d25ef04d386fd2f640e8be8f15427a8d4a458ea01d26b8dca0ca","src/fuchsia/aarch64.rs":"893fcec48142d273063ffd814dca33fbec92205fd39ada97075f85201d803996","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"07410f511835da540e5bdc55f7384c71cd7836fe63bbca6be547de825f823c03","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/riscv64.rs":"617cd75e79e0e20f664db764a4dc2a396d9fd11a4d95371acd91ed4811293b11","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"2d04cfa0d55dc0a2e36fdc4a45819b9d3722af19bb1932778b44feb4c2f81036","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"9d7030ba3e21064a0f3a8e79927c70d5a95a0026be61be084f3ab021e243e503","src/macros.rs":"5f985b3de7b18833f866bf832b8ffb0430f0f70aa9a468b6a2c855c1bf9d33e4","src/psp.rs":"0a7d5121a8cc2903009f586c00e4ae2d6126d24eb90531dafaba6f59823aa6b2","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/solid/aarch64.rs":"a726e47f324adf73a4a0b67a2c183408d0cad105ae66acf36db37a42ab7f8707","src/solid/arm.rs":"e39a4f74ebbef3b97b8c95758ad741123d84ed3eb48d9cf4f1f4872097fc27fe","src/solid/mod.rs":"5f4151dca5132e4b4e4c23ab9737e12856dddbdc0ca3f7dbc004328ef3c8acde","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/teeos/mod.rs":"eb664b3e94bcd44d8c8147b56c2187139d01bf8402ee0bb81967a5a50a3e927f","src/unix/aix/mod.rs":"d4ed2a4eff43c60a251bba150868d0249bf79dd6fb835d5287c352577452712b","src/unix/aix/powerpc64.rs":"cf374d81139d45f9d77c6a764f640bfbf7e0a5903689652c8296f8e10d55169b","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"2546ad3eb6aecb95f916648bc63264117c92b4b4859532b34cb011e4c75a5a72","src/unix/bsd/apple/b64/aarch64/align.rs":"2eaf0f561a32bdcbf4e0477c8895d5e7bcb5cdebd5fef7b4df2ca8e38e144d94","src/unix/bsd/apple/b64/aarch64/mod.rs":"44c217a4f263afe7a97435de9323d20a96c37836f899ca0925306d4b7e073c27","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"f5e278a1af7fb358891d1c9be4eb7e815aaca0c5cb738d0c3604ba2208a856f7","src/unix/bsd/apple/b64/x86_64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/x86_64/mod.rs":"8c87c5855038aae5d433c8f5eb3b29b0a175879a0245342b3bfd83bdf4cfd936","src/unix/bsd/apple/long_array.rs":"3cf1f19b812e6d093c819dc65ce55b13491963e0780eda0d0bd1577603e81948","src/unix/bsd/apple/mod.rs":"1da404688e9d67171403f2486456aac9d36a2db31ee7ebc308f14d6277754eef","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"8295b8bb0dfd38d2cdb4d9192cdeeb534cc6c3b208170e64615fa3e0edb3e578","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"2777f94909a798df1b8030fb86d02e2118d0ac3e49e9a542df54a569ca5ae2f9","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"6c8e216385f53a4bf5f171749b57602fc34a4e4b160a44ca31c058cb0c8a2126","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"e243ae0e89623d4fa9f85afe14369cc5fd5f2028ea715773dbec722ba80dac1f","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"bef9fae288a4f29e941ea369be1cd20b170040e60665a4d49a4a9e79009b72d8","src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs":"2df36a7f122f6d6e5753cfb4d22e915cc80f6bc91c0161b3daae55a481bfd052","src/unix/bsd/freebsdlike/freebsd/freebsd13/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs":"88be47524b28b6635ccb1e85ea511bf17337be0af7e9baa740c341ac9e83a6f7","src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs":"2df36a7f122f6d6e5753cfb4d22e915cc80f6bc91c0161b3daae55a481bfd052","src/unix/bsd/freebsdlike/freebsd/freebsd14/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs":"6ddc6abf6d5ccaea0d8cccf521e8ca6457efcad3086af4155628d5d06d672346","src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs":"e7b5863e222d6cc416b6b0fbe71690fad909e899b4c4ae810bbca117e4fcb650","src/unix/bsd/freebsdlike/freebsd/freebsd15/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs":"93115c1a9faa43ebf58b7dee3582aed5a54291b284764e370e7f649b2e6a9565","src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs":"e7b5863e222d6cc416b6b0fbe71690fad909e899b4c4ae810bbca117e4fcb650","src/unix/bsd/freebsdlike/freebsd/mod.rs":"5669c341804bccf27eb03965f11bd640a762a9898a5baa18b5a319fb1d8abddf","src/unix/bsd/freebsdlike/freebsd/powerpc.rs":"9ca3f82f88974e6db5569f2d76a5a3749b248a31747a6c0da5820492bdfeca42","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/riscv64.rs":"fa4bed4c58cad24ba3395941c7fa6b11e089551a04714f9561078e400f5b2b62","src/unix/bsd/freebsdlike/freebsd/x86.rs":"6766e2ce85e187b306cd3b0b8d7e15b8f4042c5cff81d89b3af69ecc99c70ab0","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"51e4dd0c8ae247bb652feda5adad9333ea3bb30c750c3a3935e0b0e47d7803eb","src/unix/bsd/freebsdlike/mod.rs":"29f5ae7c8bcd64219e77f99ba9b26527299cf4908b20f7d1ec4f625b5194a44c","src/unix/bsd/mod.rs":"f5974098ef3d1a29774bc0bde27dc9c89c3880f9ed7b4d7ea334b595dc39ff94","src/unix/bsd/netbsdlike/mod.rs":"ea60540aa4edd4e43136749d5df497b1dc072b9912b6030dd1ab794a6d1c3c3c","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"057ee877db7193ba0dc10801b9a6563ac6dbdb78376d6851a84cb12b30841759","src/unix/bsd/netbsdlike/netbsd/arm.rs":"949b55e4dee1c8c511f4f061a6a57ac876a6c0eabfaf5cc20e9ab40d8f41b2e0","src/unix/bsd/netbsdlike/netbsd/mips.rs":"88be18ac43ba224c77e78e4179b6761debc5e6c30a258fac56263809c7af4fbc","src/unix/bsd/netbsdlike/netbsd/mod.rs":"b8d6f089fc8eb2cb59e45335a26c9ce871b846216c9859b553c6b91982f8de33","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/riscv64.rs":"1cbe2e5ed681cb1054b699da37daaf6c714267df7d332c90fc2a589b11579625","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"532b76199d6c71ff996eade9f906c55a72c9aff489595d25a21e21878cfd740b","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"dd91931d373b7ecaf6e2de25adadee10d16fa9b12c2cbacdff3eb291e1ba36af","src/unix/bsd/netbsdlike/openbsd/arm.rs":"01580d261bc6447bb327a0d982181b7bdabfa066cee65a30373d3ced729ad307","src/unix/bsd/netbsdlike/openbsd/mips64.rs":"8532a189ae10c7d668d9d4065da8b05d124e09bd39442c9f74a7f231c43eca48","src/unix/bsd/netbsdlike/openbsd/mod.rs":"7b93b5b24b3c72a79b2de19b47ac2f56b29d87e9fc8f4c721a63d1e87ec83fcc","src/unix/bsd/netbsdlike/openbsd/powerpc.rs":"01580d261bc6447bb327a0d982181b7bdabfa066cee65a30373d3ced729ad307","src/unix/bsd/netbsdlike/openbsd/powerpc64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/riscv64.rs":"1fe3332dc705a13e6242219970f5449d6d7a73e2e6c8537ab8e421d8a6f2e3ff","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"d31db31630289c85af3339dbe357998a21ca584cbae31607448fe2cf7675a4e1","src/unix/haiku/b32.rs":"a2efdbf7158a6da341e1db9176b0ab193ba88b449616239ed95dced11f54d87b","src/unix/haiku/b64.rs":"ff8115367d3d7d354f792d6176dfaaa26353f57056197b563bf4681f91ff7985","src/unix/haiku/mod.rs":"ad70cc42ed83ac38664941418b0b9bfe1ead7a0ff82b121ea8df65483e3b7e1c","src/unix/haiku/native.rs":"3bbf42c3e3e437e8b626be67c72b6adcec60646eb5dd4bf8471a603cbbb5e5a4","src/unix/haiku/x86_64.rs":"3ec3aeeb7ed208b8916f3e32d42bfd085ff5e16936a1a35d9a52789f043b7237","src/unix/hurd/align.rs":"03c79b2cd8270ebd0cf93cb475a8f1ff85b28175ea0de007ede17cad94a89b03","src/unix/hurd/b32.rs":"2ba90ed973f90366c36a6387833a3df42abfee9622d4a0352635937d4a89eaf4","src/unix/hurd/b64.rs":"d919b4aec9b3080ad24c125c57b2c8b2e483d72045f1554c429d14560355846f","src/unix/hurd/mod.rs":"6a2f0db80a3cd34b55ef82e357da4d453d5d190a2dd4501bfa5d0bb9bca0de4f","src/unix/hurd/no_align.rs":"03c79b2cd8270ebd0cf93cb475a8f1ff85b28175ea0de007ede17cad94a89b03","src/unix/linux_like/android/b32/arm.rs":"ce582de7e983a33d3bfad13075c53aac9016cee35f06ad8653ee9072c3ec2564","src/unix/linux_like/android/b32/mod.rs":"7c173e0375119bf06a3081652faede95e5bcd6858e7576b7533d037978737c8f","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"e6d107efbcd37b5b85dfa18f683300cbf768ffa0237997a9fa52b184a53323ac","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/int128.rs":"1735f6f5c56770d20dd426442f09724d9b2052b46a7cd82f23f3288a4a7276de","src/unix/linux_like/android/b64/aarch64/mod.rs":"10e963e29ff209703de6336c99cca96fd79789438d34c82a693eae56e8916c3c","src/unix/linux_like/android/b64/mod.rs":"71e4fcbe952bfa4a5f9022f3972e906917b38f729b9d8ef57cd5d179104894ac","src/unix/linux_like/android/b64/riscv64/align.rs":"0bf138f84e5327d8339bcd4adf071a6832b516445e597552c82bbd881095e3a8","src/unix/linux_like/android/b64/riscv64/mod.rs":"19d4bf2237c47127eba9144e0b82e995bc079315e719179a91813b0ae7b0e49d","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"4ec2de11a9b65c4325b7b991f0b99a414975e0e61ba8668caca5d921e9b314d1","src/unix/linux_like/android/mod.rs":"5f923c89c8fd6a672d695ddd690aeac6a025c947f565acbd829c0e69d72ca049","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/lfs64.rs":"3776af30a758d765a88920ec4fde442ab89040da13d3b3625c7fbcb8a958559f","src/unix/linux_like/emscripten/mod.rs":"70d4591730a731ee32788a9d8d2de379592844ec36b7d1723514179605587713","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"bc5abcd38e2320171e0981e773c9c5fe3e0d5a66fdff049228f6a1acad80ef8b","src/unix/linux_like/linux/arch/generic/mod.rs":"feff53cb116f60c302121f9a5701adf1e2a16ff7d52a6de161fe58a28553f870","src/unix/linux_like/linux/arch/mips/mod.rs":"18dade308bf04717630fd6467b92c23560c83ac5274a8469569f260aa4671239","src/unix/linux_like/linux/arch/mod.rs":"5bd5361f8a6ab4e18bbba6da9f92c164ae252b15a0ed10064812544aa1fdf198","src/unix/linux_like/linux/arch/powerpc/mod.rs":"0bc2d2667a00eca81f4abeb6d613a90848a947f51224103f83268928b8197629","src/unix/linux_like/linux/arch/sparc/mod.rs":"5e6777863e74a9e2aa9dc487f1059783dd211babc2b32d6bf676f311e49c55d6","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"6ec0eb3ee93f7ae99fd714b4deabfb5e97fbcefd8c26f5a45fb8e7150899cdeb","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"f68ec59b6407f9d4e326f3e71a41ec21f19ecfc703edf9a93e496f661fed5506","src/unix/linux_like/linux/gnu/b32/csky/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/csky/mod.rs":"8729b68e433e94c2128e51a7db4fd555938e4be4dc64584c352b24a20d9c8e91","src/unix/linux_like/linux/gnu/b32/m68k/align.rs":"8faa92f77a9232c035418d45331774e64a9a841d99c91791570a203bf2b45bcb","src/unix/linux_like/linux/gnu/b32/m68k/mod.rs":"80956d3fef163ecf248828a6f38782dd8ae856d86b1bb5aac2de36032dbd8ea0","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"96e22350d5d132d917c743d6560464500652c67b52c3d0e8474494487df3365d","src/unix/linux_like/linux/gnu/b32/mod.rs":"b56625dd20dd48a8699034d349ef089c540c0ddcbf8a3481d598d101f8b40b78","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"20fc3cc4fe1ef6617b63b61b897f782ceb9c2842fc718f504a1840537229bf47","src/unix/linux_like/linux/gnu/b32/riscv32/align.rs":"d321491612be8d5c61b6ec2dc0111beb3a22e58803f99cd37543efe86621b119","src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs":"887288a0a1cfff319d0e15edcdc4fcb31fd643ff41715ec5244c8f2413624169","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"cc4342b949e4d796f304acd9dfe3f721a1c2f37fec16b42d3bb27dc94723af37","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"06d4db4ee8352f62a0a5ead0c4d6ea0a78feff522f19b9bc5772f6dd920ffd80","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"fdf1c72375a2167699157e0dd825422690bb6719f7bc69515a2e5846d0431d7c","src/unix/linux_like/linux/gnu/b64/aarch64/fallback.rs":"832e7487249c1c0bb6e9911ce3f7d32ca22378e42392ab83c56915cbc59d8be3","src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs":"bf4611b737813deef6787babf6c01698605f3b75482269b8546318667bc68e29","src/unix/linux_like/linux/gnu/b64/aarch64/int128.rs":"1735f6f5c56770d20dd426442f09724d9b2052b46a7cd82f23f3288a4a7276de","src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs":"11a950697fdda0258c6e37c6b13993348c8de4134105ed4faa79358e53175072","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"8202614484da36c388d2ffdd2554c56bb4f9db8e5bd621f8c36114cdcfeec644","src/unix/linux_like/linux/gnu/b64/loongarch64/align.rs":"060aa33cc737966c691aab8511c5c5729e551458ce18d0e284e0d45f39beeb60","src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs":"dc29dfdadd754ec355b82a7ca6636de7ed97f7ba98f132b71cb49f39d6bd8e3f","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"73532be4b5775acf9524c77feeefe1f6d1936ceffef908d01dd2586986520f2d","src/unix/linux_like/linux/gnu/b64/mod.rs":"6a160ef25439c4fecdb0e3bd0b818742263c791364da874d4febd3aa644ec8e2","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"a90c2641616c620e9d1fea87695ce046e14f9da2282bb93f761eeb4077c74741","src/unix/linux_like/linux/gnu/b64/riscv64/align.rs":"d321491612be8d5c61b6ec2dc0111beb3a22e58803f99cd37543efe86621b119","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"68a2a20fa4ef92cdf382d8095168eb88875b7aa8c9c47ee5f1e527393b6c16fa","src/unix/linux_like/linux/gnu/b64/s390x.rs":"1ea9e39432ce6bf68779d33546dacd7d39477a9f8fc3da4f4f339e4538cb74c3","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"bed381c44cec2a5b50125f7e548ab487d4c829006c971d152a611b7141760052","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"62e822478356db4a73b6bbd1b36d825b893939ab4b308ec11b0578bcc4b49769","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"332846e4a5920d7e6b05df0448a2333c5dd00fb27cb33654648f507ee89dbec5","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"38f74ce15d9662ce4818815a2b87be1618d5e45f190f7e4db84ff3285b4421fb","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"b20218a11364a6dec87f96d6c0d8b19e660697ab09ad5ee0e9b3a9dafedaaebb","src/unix/linux_like/linux/gnu/mod.rs":"583d04f92435da76fd3f87182ab67b5e6dd8c35a63b240d8c4555fb1ab70f3f8","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"099ae3b59e379cad0e57df710a81a3f8f208a5993051e6e0fcfb61595889ce18","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"af10147d7c3661751750a58ffad089d5d18d180cd18303c653aef126c07ccd91","src/unix/linux_like/linux/musl/b32/hexagon.rs":"d079cab42529f7dab699334d43168c74ff4aa0282f11040a8b7d274b65767a7a","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"e44043766f7cd26de7ffa4232654afb6feb03e58dbd5890717970887bd003151","src/unix/linux_like/linux/musl/b32/mod.rs":"31677597fd9544c4b1ec1477628288f6273fabbc06e38f33da862ad55f019ce1","src/unix/linux_like/linux/musl/b32/powerpc.rs":"3dae56a4e7789bcc5314e419fea5e4b2495367b4f1a49d1c9477c60225d65eef","src/unix/linux_like/linux/musl/b32/riscv32/align.rs":"efd2accf33b87de7c7547903359a5da896edc33cd6c719552c7474b60d4a5d48","src/unix/linux_like/linux/musl/b32/riscv32/mod.rs":"3ee845d272f91a1908d5f421d7c353e1f14681bbdfef64410e408f4c14365a91","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"f2b53ae0034c833244b7cdb8c670349bf8272a03abf04152eba65cf62810484d","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"6ba32725d24d7d8e6aa111f3b57aafa318f83b606abe96561329151829821133","src/unix/linux_like/linux/musl/b64/aarch64/int128.rs":"1735f6f5c56770d20dd426442f09724d9b2052b46a7cd82f23f3288a4a7276de","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"45ce6897afcc960267bb7505702b639daf94dc69428a213bf1aefd367ca32adc","src/unix/linux_like/linux/musl/b64/mips64.rs":"a968ef9c54fa22293085f318c8472c1754482df92cc500568dc33bd807d71ea6","src/unix/linux_like/linux/musl/b64/mod.rs":"1a8391febf3e750185ffc5c69c9f9e411f4e8c53b5d994cb231df24480169686","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"140e579800a67315f4cb8a42b22aa8157eae34ffe626e77e421b43c53c23b34d","src/unix/linux_like/linux/musl/b64/riscv64/align.rs":"d321491612be8d5c61b6ec2dc0111beb3a22e58803f99cd37543efe86621b119","src/unix/linux_like/linux/musl/b64/riscv64/mod.rs":"c5944526d7e19cd43e9d14d119a1d98f8780db7ecbcc79e69d7b9348e596b520","src/unix/linux_like/linux/musl/b64/s390x.rs":"8557b3477ca8cefef7fce764a3c25441929a54e50ead4091f6f7823c427cd728","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"77309276ad7a42cbe59ca381f23590b7a143aded05555b34a5b307b808cbca6e","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"a91c4f18027c9958037f78ae48f6352d23cb4e6f2995b2cc8de7dce0e5759470","src/unix/linux_like/linux/musl/lfs64.rs":"3e4fb381f3a0756520bde0f1692d4fa45e4ae8133bf7d7c64b0e3fdd512f235f","src/unix/linux_like/linux/musl/mod.rs":"f0a23b77e5465c05a5dd95c3c6b7959c597010416226503ff3719796367ba98e","src/unix/linux_like/linux/no_align.rs":"62cdca0e011937aaf09a51ca86d9f0ee0fdb05f61ec3c058e6a5d5fa6357d784","src/unix/linux_like/linux/non_exhaustive.rs":"181a05bf94fdb911db83ce793b993bd6548a4115b306a7ef3c10f745a8fea3e9","src/unix/linux_like/linux/uclibc/align.rs":"9ed16138d8e439bd90930845a65eafa7ebd67366e6bf633936d44014f6e4c959","src/unix/linux_like/linux/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/uclibc/arm/mod.rs":"50288ff9e411ab0966da24838f2c2a5618021bc19c422a04f577b2979ef4081e","src/unix/linux_like/linux/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs":"d0c4434e2bf813372c418a8f516c706cdccc9f7be2f0921b2207b0afdb66fe81","src/unix/linux_like/linux/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs":"3f38ee6a4690b9d7594be20d216467a34d955f7653c2c8ce1e6147daeb53f1e0","src/unix/linux_like/linux/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/linux_like/linux/uclibc/mips/mod.rs":"a048fce1c2d9b1ad57305642e8ad05ca0f0c7e4753267a2e2d6b4fee5db3b072","src/unix/linux_like/linux/uclibc/mod.rs":"193a03fa4aa5345394e39d2115c9427e806c9f28b0fde685719119e1c90ca08a","src/unix/linux_like/linux/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/linux_like/linux/uclibc/x86_64/l4re.rs":"8485b9182b7c67f7344fab377e7cc2a72afefd9ab63837c860514abba9728d76","src/unix/linux_like/linux/uclibc/x86_64/mod.rs":"196d03affbefb85716937c15904831e731eb222ee906e05e42102d639a8152ea","src/unix/linux_like/linux/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/unix/linux_like/mod.rs":"86dbbd81484df25ad7c6a82d2d3b5eab2f8e7751853c1dd4308b7eee57b5fbca","src/unix/mod.rs":"923a32e8fd9e462eda4e90ae7ee501da1d12aaadc1bf2e9722f02581a5d3fc6c","src/unix/newlib/aarch64/mod.rs":"964c096288da836b53c0c71d7f3a97048d177da220a69314c5ce93ba330d72af","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"cf754f8b1197489fca01e881a4b4b146e814998e4b365f116fa1a102c00e6a4e","src/unix/newlib/espidf/mod.rs":"29969da41f0042197b21cfa7c0ad2244b4519ecab0fb7de3d0a7655b4f3937e1","src/unix/newlib/generic.rs":"5f0b5d07ddb5a5d60580f9561fdb05e9218d9751d4068c4aadad2ba6b950aabf","src/unix/newlib/horizon/mod.rs":"3a521d22bf932fc01c1d26d1f9bff20f11b1855b03c8236a8eb18310f6cab5a8","src/unix/newlib/mod.rs":"e5d5faf27a6336b9f1c02b8726427801d906a14dae766852b4e85c1a92df06c8","src/unix/newlib/no_align.rs":"e0743b2179495a9514bc3a4d1781e492878c4ec834ee0085d0891dd1712e82fb","src/unix/newlib/powerpc/mod.rs":"cc9e188711b9bf614323ad6c48e0d2e1a1ecc5d3bc64961ba451f29c6c22d2d8","src/unix/newlib/vita/mod.rs":"ff1caf74bb0696fe15d60dbac598db4520cd538aa0f5989713d97d008eee6ad8","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/nto/aarch64.rs":"4709c9afdc8d583be876598e7c238499ee3e8da5bd2baa614d9c7dd414851555","src/unix/nto/mod.rs":"07268897fc8810f2fed22ab56f87757f71c73ba401abd848bccca6b183a13b02","src/unix/nto/neutrino.rs":"799bff4ab01a6424db6c5a2b76aa5679826d41495f9d13c63485bf13bc80026b","src/unix/nto/x86_64.rs":"a3e18e93c2999da1cd7a6f748a4b60c07aefb73d8ea2aafec19a84cfb040bc8e","src/unix/redox/mod.rs":"a9f54687307883beb4a410216dc8e36b85d72b0463bc6b1520bd91edf3947d23","src/unix/solarish/compat.rs":"00f1ee3faec9da69204e42f025f6735dd13d894071a154425dcc43ecbdd06e7f","src/unix/solarish/illumos.rs":"cd93c2d84722bbf9933a92842a8998eb0b2afc962f50bc2546ad127b82809fa7","src/unix/solarish/mod.rs":"10b2369edc027fcb2e41e5342f24946aa01ee1549a6d7f06b9a3956ff84518bc","src/unix/solarish/solaris.rs":"41b350a89ddf01cd12a10f93640f92be53be0b0d976021cdc08da17bf3e72edf","src/unix/solarish/x86.rs":"e86e806df0caed72765040eaa2f3c883198d1aa91508540adf9b7008c77f522e","src/unix/solarish/x86_64.rs":"ec2b01f194eb8a6a27133c57681da195a949e03098f3ea1e847227a9c09ef5fc","src/unix/solarish/x86_common.rs":"ac869d9c3c95645c22460468391eb1982023c3a8e02b9e06a72e3aef3d5f1eac","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"4105a2e6a6c9908fc1f2a770ede052bb0d6a5d9d49e32d815f557081efc49860","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"d4147353537d7556076ff1a1c4cb96cc2dae9416a5d176ba8a077ad55ab7ec18","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"3c8c7edb7cdf5d0c44af936db2a94869585c69dfabeef30571b4f4e38375767a","src/windows/mod.rs":"9fdc5e1c62c441abef7bc62a7343efb2041edc24db9ac0efc0f74df55b69e249","src/windows/msvc/mod.rs":"c068271e00fca6b62bc4bf44bcf142cfc38caeded9b6c4e01d1ceef3ccf986f4","src/xous.rs":"eb0675f25ba01f73072d2b70907fb8abb1148facefe5a20756c49250f3d65fae","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4"},"package":"9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"} \ No newline at end of file diff --git a/third_party/rust/libc/Cargo.toml b/third_party/rust/libc/Cargo.toml index 266fb56093..46ec3b4074 100644 --- a/third_party/rust/libc/Cargo.toml +++ b/third_party/rust/libc/Cargo.toml @@ -11,7 +11,7 @@ [package] name = "libc" -version = "0.2.152" +version = "0.2.153" authors = ["The Rust Project Developers"] build = "build.rs" exclude = [ diff --git a/third_party/rust/libc/src/unix/linux_like/android/mod.rs b/third_party/rust/libc/src/unix/linux_like/android/mod.rs index 94c4eace85..2c1c1e9b91 100644 --- a/third_party/rust/libc/src/unix/linux_like/android/mod.rs +++ b/third_party/rust/libc/src/unix/linux_like/android/mod.rs @@ -2275,6 +2275,8 @@ pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; pub const MFD_CLOEXEC: ::c_uint = 0x0001; pub const MFD_ALLOW_SEALING: ::c_uint = 0x0002; pub const MFD_HUGETLB: ::c_uint = 0x0004; +pub const MFD_NOEXEC_SEAL: ::c_uint = 0x0008; +pub const MFD_EXEC: ::c_uint = 0x0010; pub const MFD_HUGE_64KB: ::c_uint = 0x40000000; pub const MFD_HUGE_512KB: ::c_uint = 0x4c000000; pub const MFD_HUGE_1MB: ::c_uint = 0x50000000; @@ -3468,6 +3470,37 @@ pub const NET_DCCP: ::c_int = 20; pub const HUGETLB_FLAG_ENCODE_SHIFT: ::c_int = 26; pub const MAP_HUGE_SHIFT: ::c_int = HUGETLB_FLAG_ENCODE_SHIFT; +// include/linux/sched.h +pub const PF_VCPU: ::c_int = 0x00000001; +pub const PF_IDLE: ::c_int = 0x00000002; +pub const PF_EXITING: ::c_int = 0x00000004; +pub const PF_POSTCOREDUMP: ::c_int = 0x00000008; +pub const PF_IO_WORKER: ::c_int = 0x00000010; +pub const PF_WQ_WORKER: ::c_int = 0x00000020; +pub const PF_FORKNOEXEC: ::c_int = 0x00000040; +pub const PF_MCE_PROCESS: ::c_int = 0x00000080; +pub const PF_SUPERPRIV: ::c_int = 0x00000100; +pub const PF_DUMPCORE: ::c_int = 0x00000200; +pub const PF_SIGNALED: ::c_int = 0x00000400; +pub const PF_MEMALLOC: ::c_int = 0x00000800; +pub const PF_NPROC_EXCEEDED: ::c_int = 0x00001000; +pub const PF_USED_MATH: ::c_int = 0x00002000; +pub const PF_USER_WORKER: ::c_int = 0x00004000; +pub const PF_NOFREEZE: ::c_int = 0x00008000; + +pub const PF_KSWAPD: ::c_int = 0x00020000; +pub const PF_MEMALLOC_NOFS: ::c_int = 0x00040000; +pub const PF_MEMALLOC_NOIO: ::c_int = 0x00080000; +pub const PF_LOCAL_THROTTLE: ::c_int = 0x00100000; +pub const PF_KTHREAD: ::c_int = 0x00200000; +pub const PF_RANDOMIZE: ::c_int = 0x00400000; + +pub const PF_NO_SETAFFINITY: ::c_int = 0x04000000; +pub const PF_MCE_EARLY: ::c_int = 0x08000000; +pub const PF_MEMALLOC_PIN: ::c_int = 0x10000000; + +pub const PF_SUSPEND_TASK: ::c_int = 0x80000000; + // Most `*_SUPER_MAGIC` constants are defined at the `linux_like` level; the // following are only available on newer Linux versions than the versions // currently used in CI in some configurations, so we define them here. diff --git a/third_party/rust/libc/src/unix/linux_like/linux/arch/generic/mod.rs b/third_party/rust/libc/src/unix/linux_like/linux/arch/generic/mod.rs index b8e459631e..83f97fbd92 100644 --- a/third_party/rust/libc/src/unix/linux_like/linux/arch/generic/mod.rs +++ b/third_party/rust/libc/src/unix/linux_like/linux/arch/generic/mod.rs @@ -227,7 +227,11 @@ cfg_if! { pub const FS_IOC32_SETFLAGS: ::Ioctl = 0x40046602; pub const FS_IOC32_GETVERSION: ::Ioctl = 0x80047601; pub const FS_IOC32_SETVERSION: ::Ioctl = 0x40047602; - } else if #[cfg(any(target_arch = "x86_64", target_arch = "riscv64", target_arch = "aarch64", target_arch = "s390x"))] { + } else if #[cfg(any(target_arch = "x86_64", + target_arch = "riscv64", + target_arch = "aarch64", + target_arch = "s390x", + target_arch = "loongarch64"))] { pub const FS_IOC_GETFLAGS: ::Ioctl = 0x80086601; pub const FS_IOC_SETFLAGS: ::Ioctl = 0x40086602; pub const FS_IOC_GETVERSION: ::Ioctl = 0x80087601; diff --git a/third_party/rust/libc/src/unix/linux_like/linux/mod.rs b/third_party/rust/libc/src/unix/linux_like/linux/mod.rs index acb10c603f..cbb3f7bdf5 100644 --- a/third_party/rust/libc/src/unix/linux_like/linux/mod.rs +++ b/third_party/rust/libc/src/unix/linux_like/linux/mod.rs @@ -2433,6 +2433,8 @@ pub const CMSPAR: ::tcflag_t = 0o10000000000; pub const MFD_CLOEXEC: ::c_uint = 0x0001; pub const MFD_ALLOW_SEALING: ::c_uint = 0x0002; pub const MFD_HUGETLB: ::c_uint = 0x0004; +pub const MFD_NOEXEC_SEAL: ::c_uint = 0x0008; +pub const MFD_EXEC: ::c_uint = 0x0010; pub const MFD_HUGE_64KB: ::c_uint = 0x40000000; pub const MFD_HUGE_512KB: ::c_uint = 0x4c000000; pub const MFD_HUGE_1MB: ::c_uint = 0x50000000; diff --git a/third_party/rust/libc/src/unix/newlib/vita/mod.rs b/third_party/rust/libc/src/unix/newlib/vita/mod.rs index e80f061ea0..d4c6955f36 100644 --- a/third_party/rust/libc/src/unix/newlib/vita/mod.rs +++ b/third_party/rust/libc/src/unix/newlib/vita/mod.rs @@ -94,6 +94,8 @@ pub const SOCK_RAW: ::c_int = 3; pub const SOCK_RDM: ::c_int = 4; pub const SOCK_SEQPACKET: ::c_int = 5; +pub const SOMAXCONN: ::c_int = 128; + pub const FIONBIO: ::c_ulong = 1; pub const POLLIN: ::c_short = 0x0001; diff --git a/third_party/rust/libloading/.cargo-checksum.json b/third_party/rust/libloading/.cargo-checksum.json index 04164017dd..4874dbade8 100644 --- a/third_party/rust/libloading/.cargo-checksum.json +++ b/third_party/rust/libloading/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"30f23c025249e7779afd2a52fdaba7145dd75c2a3e5a0a23f3322261d6b94c59","LICENSE":"b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f","README.mkd":"973a5fa332a8f33abc73ffc0ed509f81c66dbd681d8f50969cac32cdfe16ecb2","src/changelog.rs":"a49ff30e81a245fdcef957a3fffed5a5a5b56825bc51f6ed26fe4c12f75d359c","src/error.rs":"156c53e299e8f1cd4694b277a5d92772a8a9e7ec4004bae067367f4c2502de8b","src/lib.rs":"2eebab93230a59cd87c7884e95c91b3a8736c0a76814dd040864b8c25f0d5f9e","src/os/mod.rs":"6c59ef8c1120953ae6b6c32f27766c643ca90d85075c49c3545d2fe1ed82cedd","src/os/unix/consts.rs":"1418cc26329d01ee6bc9c1144881873a66ac2183c1bf1d589904d569656c80f2","src/os/unix/mod.rs":"dff9590acbbb9a02baea9d2eb870515104c9d519b1896887f3bf1434db442929","src/os/windows/mod.rs":"b14478d7f9d4e8edc8afcbc7aa695ede1ccdd739a94242cb8dbb154fe04e4999","src/safe.rs":"b0dc1cb5c8e0216e365063b5e84218b2377bb7a62714fca9a6215a22a7bc58b8","src/test_helpers.rs":"201403e143e5b3204864124cd38067cf8813d5273dc1a9099288a9dc4bdd15b6","src/util.rs":"0b6dcfb9eafff2d87966460ef6b1b99980f888813037e787ed92deee602f8c2b","tests/constants.rs":"4778c062605ed22238c1bed16de4c076d0857282f090f36e6d985dafb7b4544d","tests/functions.rs":"0cbcc193f8aad71df626aefab9881a76f17c5a4b241855b602ce874018392db7","tests/library_filename.rs":"b1481f0bb374687c5f24e25113426d2a95f08a45fb8bc41a41e8702bd5a7b4bf","tests/markers.rs":"0ebc8f807b92e39452d35732988012cdca7ce96231c57eaac9c3f4217225ad39","tests/nagisa32.dll":"5c69b2bd9c8a6ad04165c221075fc9fade1dd66ca697399ace528a5a62328e36","tests/nagisa64.dll":"e20b95e3036f3289421abd100760874d4f455afd33c3b5b64fec56b191f7d477","tests/windows.rs":"35584a46658b305cd539712d3ba3c21fe7a130fd693aa1389e4886a67625d532"},"package":"b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"} \ No newline at end of file +{"files":{"Cargo.toml":"d97d9cdce69985cab52ba027b089854906d4cf653d581e9742530a536b4599fc","LICENSE":"b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f","README.mkd":"707e1cae9fa4b691ce5cb8a3976573158fc60b67cb89948f8f5d51c5908bd0a8","src/changelog.rs":"e7c18ebb9be9624b64bcca3f39d714084cbbaa2ffbc35bfc033967b81be1af66","src/error.rs":"488004e68022adba1002c95d1c8f568fdf1f7bc88aedb6a0f5e31a3dab6f8509","src/lib.rs":"0142a630bb27d1443a8a79d1d5559ea10e859d587442c596d2be7d837507afa0","src/os/mod.rs":"6c59ef8c1120953ae6b6c32f27766c643ca90d85075c49c3545d2fe1ed82cedd","src/os/unix/consts.rs":"a1f98372a58acc6d00a1df19550e0593ede60a53f2aa3ff26cf678cf1015594c","src/os/unix/mod.rs":"15e284c70b61c2728cdf312c2c8740d1671a53dbc7161d8ad5c8a909416644cc","src/os/windows/mod.rs":"8a8792569d43140d982edd6d401abb82023894eb02f2eeba321ee9887568cf3b","src/safe.rs":"b0dc1cb5c8e0216e365063b5e84218b2377bb7a62714fca9a6215a22a7bc58b8","src/test_helpers.rs":"201403e143e5b3204864124cd38067cf8813d5273dc1a9099288a9dc4bdd15b6","src/util.rs":"0b6dcfb9eafff2d87966460ef6b1b99980f888813037e787ed92deee602f8c2b","tests/constants.rs":"4778c062605ed22238c1bed16de4c076d0857282f090f36e6d985dafb7b4544d","tests/functions.rs":"c3d4770704de40e9592cfd109cf506e6b04f0738d8a1ee02ec858b4fa4632a2b","tests/library_filename.rs":"b1481f0bb374687c5f24e25113426d2a95f08a45fb8bc41a41e8702bd5a7b4bf","tests/markers.rs":"0ebc8f807b92e39452d35732988012cdca7ce96231c57eaac9c3f4217225ad39","tests/nagisa32.dll":"5c69b2bd9c8a6ad04165c221075fc9fade1dd66ca697399ace528a5a62328e36","tests/nagisa64.dll":"e20b95e3036f3289421abd100760874d4f455afd33c3b5b64fec56b191f7d477","tests/windows.rs":"35584a46658b305cd539712d3ba3c21fe7a130fd693aa1389e4886a67625d532"},"package":"0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"} \ No newline at end of file diff --git a/third_party/rust/libloading/Cargo.toml b/third_party/rust/libloading/Cargo.toml index 65168d5858..d5e55487b7 100644 --- a/third_party/rust/libloading/Cargo.toml +++ b/third_party/rust/libloading/Cargo.toml @@ -10,9 +10,9 @@ # See Cargo.toml.orig for the original contents. [package] -rust-version = "1.40.0" +rust-version = "1.56.0" name = "libloading" -version = "0.7.4" +version = "0.8.3" authors = ["Simonas Kazlauskas "] description = "Bindings around the platform's dynamic library loading primitives with greatly improved memory safety." documentation = "https://docs.rs/libloading/" @@ -43,9 +43,9 @@ version = "1.1" [target."cfg(unix)".dependencies.cfg-if] version = "1" -[target."cfg(windows)".dependencies.winapi] -version = "0.3" -features = [ - "errhandlingapi", - "libloaderapi", -] +[target."cfg(windows)".dependencies.windows-targets] +version = ">=0.48, <0.53" + +[target."cfg(windows)".dev-dependencies.windows-sys] +version = "0.52" +features = ["Win32_Foundation"] diff --git a/third_party/rust/libloading/README.mkd b/third_party/rust/libloading/README.mkd index 66abb30b6e..7ff55b04b2 100644 --- a/third_party/rust/libloading/README.mkd +++ b/third_party/rust/libloading/README.mkd @@ -1,8 +1,11 @@ # libloading -Bindings around the platform's dynamic library loading primitives with greatly improved memory safety. The most important safety guarantee of this library is the prevention of dangling `Symbol`s that may occur after a `Library` is unloaded. +Bindings around the platform's dynamic library loading primitives with greatly improved memory +safety. The most important safety guarantee of this library is the prevention of dangling `Symbol`s +that may occur after a `Library` is unloaded. -Using this library allows the loading of dynamic libraries, also known as shared libraries, as well as the use of the functions and static variables that these libraries may contain. +Using this library allows the loading of dynamic libraries, also known as shared libraries, as well +as the use of the functions and static variables that these libraries may contain. * [Documentation][docs] * [Changelog][changelog] diff --git a/third_party/rust/libloading/src/changelog.rs b/third_party/rust/libloading/src/changelog.rs index 162544f34f..58101aecf9 100644 --- a/third_party/rust/libloading/src/changelog.rs +++ b/third_party/rust/libloading/src/changelog.rs @@ -1,5 +1,50 @@ //! The change log. +/// Release 0.8.3 (2024-03-05) +/// +/// ## Non-breaking changes +/// +/// A `dev-dependency` on `windows-sys` that was unconditionally introduced in +/// [0.8.2](r0_8_2) has been made conditional. +pub mod r0_8_3 {} + +/// Release 0.8.2 (2024-03-01) +/// +/// ## (Potentially) breaking changes +/// +/// MSRV has been increased to 1.56.0. Since both rustc versions are ancient, this has been deemed +/// to not be breaking enough to warrant a semver-breaking release of libloading. If you're stick +/// with a version of rustc older than 1.56.0, lock `libloading` dependency to `0.8.1`. +/// +/// ## Non-breaking changes +/// +/// * The crate switches the dependency on `windows-sys` to a `windows-target` one for Windows +/// bindings. In order to enable this `libloading` defines any bindings necessary for its operation +/// internally, just like has been done for `unix` targets. This should result in leaner dependency +/// trees. +/// * `os::unix::with_dlerror` has been exposed for the users who need to invoke `dl*` family of +/// functions manually. +pub mod r0_8_2 {} + +/// Release 0.8.1 (2023-09-30) +/// +/// ## Non-breaking changes +/// +/// * Support for GNU Hurd. +pub mod r0_8_1 {} + +/// Release 0.8.0 (2023-04-11) +/// +/// ## (Potentially) breaking changes +/// +/// * `winapi` dependency has been replaced with `windows-sys`. +/// * As a result the MSRV has been increased to 1.48. +/// +/// ## Non-breaking changes +/// +/// * Support for the QNX Neutrino target has been added. +pub mod r0_8_0 {} + /// Release 0.7.4 (2022-11-07) /// /// This release has no functional changes. diff --git a/third_party/rust/libloading/src/error.rs b/third_party/rust/libloading/src/error.rs index bd70ec39ce..ff4891c901 100644 --- a/third_party/rust/libloading/src/error.rs +++ b/third_party/rust/libloading/src/error.rs @@ -1,4 +1,4 @@ -use std::ffi::CString; +use std::ffi::{CString, CStr}; /// A `dlerror` error. pub struct DlDescription(pub(crate) CString); @@ -9,6 +9,12 @@ impl std::fmt::Debug for DlDescription { } } +impl From<&CStr> for DlDescription { + fn from(value: &CStr) -> Self { + Self(value.into()) + } +} + /// A Windows API error. pub struct WindowsError(pub(crate) std::io::Error); diff --git a/third_party/rust/libloading/src/lib.rs b/third_party/rust/libloading/src/lib.rs index 6f0e4cb7f7..3ddf98a34b 100644 --- a/third_party/rust/libloading/src/lib.rs +++ b/third_party/rust/libloading/src/lib.rs @@ -16,7 +16,7 @@ //! //! ```toml //! [dependencies] -//! libloading = "0.7" +//! libloading = "0.8" //! ``` //! //! # Usage @@ -41,15 +41,13 @@ pub mod changelog; pub mod os; mod util; - mod error; -pub use self::error::Error; - #[cfg(any(unix, windows, libloading_docs))] mod safe; + +pub use self::error::Error; #[cfg(any(unix, windows, libloading_docs))] pub use self::safe::{Library, Symbol}; - use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::ffi::{OsStr, OsString}; diff --git a/third_party/rust/libloading/src/os/unix/consts.rs b/third_party/rust/libloading/src/os/unix/consts.rs index ea7a6a102d..ed3edaf829 100644 --- a/third_party/rust/libloading/src/os/unix/consts.rs +++ b/third_party/rust/libloading/src/os/unix/consts.rs @@ -82,6 +82,8 @@ mod posix { target_os = "fuchsia", target_os = "redox", + target_os = "nto", + target_os = "hurd", ))] { pub(super) const RTLD_LAZY: c_int = 1; } else { @@ -115,6 +117,8 @@ mod posix { target_os = "fuchsia", target_os = "redox", + target_os = "nto", + target_os = "hurd", ))] { pub(super) const RTLD_NOW: c_int = 2; } else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] { @@ -162,6 +166,8 @@ mod posix { target_os = "fuchsia", target_os = "redox", + target_os = "nto", + target_os = "hurd", ))] { pub(super) const RTLD_GLOBAL: c_int = 0x100; } else { @@ -172,7 +178,10 @@ mod posix { } cfg_if! { - if #[cfg(target_os = "netbsd")] { + if #[cfg(any( + target_os = "netbsd", + target_os = "nto", + ))] { pub(super) const RTLD_LOCAL: c_int = 0x200; } else if #[cfg(target_os = "aix")] { pub(super) const RTLD_LOCAL: c_int = 0x80000; @@ -200,6 +209,7 @@ mod posix { target_os = "fuchsia", target_os = "redox", + target_os = "hurd", ))] { pub(super) const RTLD_LOCAL: c_int = 0; } else { diff --git a/third_party/rust/libloading/src/os/unix/mod.rs b/third_party/rust/libloading/src/os/unix/mod.rs index df7efdad54..6347e02700 100644 --- a/third_party/rust/libloading/src/os/unix/mod.rs +++ b/third_party/rust/libloading/src/os/unix/mod.rs @@ -16,18 +16,33 @@ use util::{cstr_cow_from_bytes, ensure_compatible_types}; mod consts; -// dl* family of functions did not have enough thought put into it. -// -// Whole error handling scheme is done via setting and querying some global state, therefore it is -// not safe to use dynamic library loading in MT-capable environment at all. Only in POSIX 2008+TC1 -// a thread-local state was allowed for `dlerror`, making the dl* family of functions MT-safe. -// -// In practice (as of 2020-04-01) most of the widely used targets use a thread-local for error -// state and have been doing so for a long time. Regardless the comments in this function shall -// remain as a documentation for the future generations. -fn with_dlerror(wrap: fn(crate::error::DlDescription) -> crate::Error, closure: F) --> Result> -where F: FnOnce() -> Option { +/// Run code and handle errors reported by `dlerror`. +/// +/// This function first executes the `closure` function containing calls to the functions that +/// report their errors via `dlerror`. This closure may return either `None` or `Some(*)` to +/// further affect operation of this function. +/// +/// In case the `closure` returns `None`, `with_dlerror` inspects the `dlerror`. `dlerror` may +/// decide to not provide any error description, in which case `Err(None)` is returned to the +/// caller. Otherwise the `error` callback is invoked to allow inspection and conversion of the +/// error message. The conversion result is returned as `Err(Some(Error))`. +/// +/// If the operations that report their errors via `dlerror` were all successful, `closure` should +/// return `Some(T)` instead. In this case `dlerror` is not inspected at all. +/// +/// # Notes +/// +/// The whole `dlerror` handling scheme is done via setting and querying some global state. For +/// that reason it is not safe to use dynamic library loading in MT-capable environment at all. +/// Only in POSIX 2008+TC1 a thread-local state was allowed for `dlerror`, making the dl* family of +/// functions possibly MT-safe, depending on the implementation of `dlerror`. +/// +/// In practice (as of 2020-04-01) most of the widely used targets use a thread-local for error +/// state and have been doing so for a long time. +pub fn with_dlerror(closure: F, error: fn(&CStr) -> Error) -> Result> +where + F: FnOnce() -> Option, +{ // We used to guard all uses of dl* functions with our own mutex. This made them safe to use in // MT programs provided the only way a program used dl* was via this library. However, it also // had a number of downsides or cases where it failed to handle the problems. For instance, @@ -53,8 +68,8 @@ where F: FnOnce() -> Option { // or a bug in implementation of dl* family of functions. closure().ok_or_else(|| unsafe { // This code will only get executed if the `closure` returns `None`. - let error = dlerror(); - if error.is_null() { + let dlerror_str = dlerror(); + if dlerror_str.is_null() { // In non-dlsym case this may happen when there’re bugs in our bindings or there’s // non-libloading user of libdl; possibly in another thread. None @@ -64,8 +79,7 @@ where F: FnOnce() -> Option { // ownership over the message? // TODO: should do locale-aware conversion here. OTOH Rust doesn’t seem to work well in // any system that uses non-utf8 locale, so I doubt there’s a problem here. - let message = CStr::from_ptr(error).into(); - Some(wrap(crate::error::DlDescription(message))) + Some(error(CStr::from_ptr(dlerror_str))) // Since we do a copy of the error string above, maybe we should call dlerror again to // let libdl know it may free its copy of the string now? } @@ -74,7 +88,7 @@ where F: FnOnce() -> Option { /// A platform-specific counterpart of the cross-platform [`Library`](crate::Library). pub struct Library { - handle: *mut raw::c_void + handle: *mut raw::c_void, } unsafe impl Send for Library {} @@ -164,30 +178,38 @@ impl Library { /// termination routines contained within the library is safe as well. These routines may be /// executed when the library is unloaded. pub unsafe fn open

(filename: Option

, flags: raw::c_int) -> Result - where P: AsRef { + where + P: AsRef, + { let filename = match filename { None => None, Some(ref f) => Some(cstr_cow_from_bytes(f.as_ref().as_bytes())?), }; - with_dlerror(|desc| crate::Error::DlOpen { desc }, move || { - let result = dlopen(match filename { - None => ptr::null(), - Some(ref f) => f.as_ptr() - }, flags); - // ensure filename lives until dlopen completes - drop(filename); - if result.is_null() { - None - } else { - Some(Library { - handle: result - }) - } - }).map_err(|e| e.unwrap_or(crate::Error::DlOpenUnknown)) + with_dlerror( + move || { + let result = dlopen( + match filename { + None => ptr::null(), + Some(ref f) => f.as_ptr(), + }, + flags, + ); + // ensure filename lives until dlopen completes + drop(filename); + if result.is_null() { + None + } else { + Some(Library { handle: result }) + } + }, + |desc| crate::Error::DlOpen { desc: desc.into() }, + ) + .map_err(|e| e.unwrap_or(crate::Error::DlOpenUnknown)) } unsafe fn get_impl(&self, symbol: &[u8], on_null: F) -> Result, crate::Error> - where F: FnOnce() -> Result, crate::Error> + where + F: FnOnce() -> Result, crate::Error>, { ensure_compatible_types::()?; let symbol = cstr_cow_from_bytes(symbol)?; @@ -197,23 +219,26 @@ impl Library { // // We try to leave as little space as possible for this to occur, but we can’t exactly // fully prevent it. - match with_dlerror(|desc| crate::Error::DlSym { desc }, || { - dlerror(); - let symbol = dlsym(self.handle, symbol.as_ptr()); - if symbol.is_null() { - None - } else { - Some(Symbol { - pointer: symbol, - pd: marker::PhantomData - }) - } - }) { + let result = with_dlerror( + || { + dlerror(); + let symbol = dlsym(self.handle, symbol.as_ptr()); + if symbol.is_null() { + None + } else { + Some(Symbol { + pointer: symbol, + pd: marker::PhantomData, + }) + } + }, + |desc| crate::Error::DlSym { desc: desc.into() }, + ); + match result { Err(None) => on_null(), Err(Some(e)) => Err(e), - Ok(x) => Ok(x) + Ok(x) => Ok(x), } - } /// Get a pointer to a function or static variable by symbol name. @@ -284,10 +309,12 @@ impl Library { /// variables that work on e.g. Linux may have unintended behaviour on other targets. #[inline(always)] pub unsafe fn get_singlethreaded(&self, symbol: &[u8]) -> Result, crate::Error> { - self.get_impl(symbol, || Ok(Symbol { - pointer: ptr::null_mut(), - pd: marker::PhantomData - })) + self.get_impl(symbol, || { + Ok(Symbol { + pointer: ptr::null_mut(), + pd: marker::PhantomData, + }) + }) } /// Convert the `Library` to a raw handle. @@ -308,9 +335,7 @@ impl Library { /// pointer previously returned by `Library::into_raw` call. It must be valid to call `dlclose` /// with this pointer as an argument. pub unsafe fn from_raw(handle: *mut raw::c_void) -> Library { - Library { - handle - } + Library { handle } } /// Unload the library. @@ -324,13 +349,17 @@ impl Library { /// /// The underlying data structures may still get leaked if an error does occur. pub fn close(self) -> Result<(), crate::Error> { - let result = with_dlerror(|desc| crate::Error::DlClose { desc }, || { - if unsafe { dlclose(self.handle) } == 0 { - Some(()) - } else { - None - } - }).map_err(|e| e.unwrap_or(crate::Error::DlCloseUnknown)); + let result = with_dlerror( + || { + if unsafe { dlclose(self.handle) } == 0 { + Some(()) + } else { + None + } + }, + |desc| crate::Error::DlClose { desc: desc.into() }, + ) + .map_err(|e| e.unwrap_or(crate::Error::DlCloseUnknown)); // While the library is not free'd yet in case of an error, there is no reason to try // dropping it again, because all that will do is try calling `dlclose` again. only // this time it would ignore the return result, which we already seen failing… @@ -359,7 +388,7 @@ impl fmt::Debug for Library { /// `Symbol` does not outlive the `Library` it comes from. pub struct Symbol { pointer: *mut raw::c_void, - pd: marker::PhantomData + pd: marker::PhantomData, } impl Symbol { @@ -409,13 +438,18 @@ impl fmt::Debug for Symbol { if dladdr(self.pointer, info.as_mut_ptr()) != 0 { let info = info.assume_init(); if info.dli_sname.is_null() { - f.write_str(&format!("Symbol@{:p} from {:?}", - self.pointer, - CStr::from_ptr(info.dli_fname))) + f.write_str(&format!( + "Symbol@{:p} from {:?}", + self.pointer, + CStr::from_ptr(info.dli_fname) + )) } else { - f.write_str(&format!("Symbol {:?}@{:p} from {:?}", - CStr::from_ptr(info.dli_sname), self.pointer, - CStr::from_ptr(info.dli_fname))) + f.write_str(&format!( + "Symbol {:?}@{:p} from {:?}", + CStr::from_ptr(info.dli_sname), + self.pointer, + CStr::from_ptr(info.dli_fname) + )) } } else { f.write_str(&format!("Symbol@{:p}", self.pointer)) @@ -425,9 +459,9 @@ impl fmt::Debug for Symbol { } // Platform specific things -#[cfg_attr(any(target_os = "linux", target_os = "android"), link(name="dl"))] -#[cfg_attr(any(target_os = "freebsd", target_os = "dragonfly"), link(name="c"))] -extern { +#[cfg_attr(any(target_os = "linux", target_os = "android"), link(name = "dl"))] +#[cfg_attr(any(target_os = "freebsd", target_os = "dragonfly"), link(name = "c"))] +extern "C" { fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void; fn dlclose(handle: *mut raw::c_void) -> raw::c_int; fn dlsym(handle: *mut raw::c_void, symbol: *const raw::c_char) -> *mut raw::c_void; @@ -437,8 +471,8 @@ extern { #[repr(C)] struct DlInfo { - dli_fname: *const raw::c_char, - dli_fbase: *mut raw::c_void, - dli_sname: *const raw::c_char, - dli_saddr: *mut raw::c_void + dli_fname: *const raw::c_char, + dli_fbase: *mut raw::c_void, + dli_sname: *const raw::c_char, + dli_saddr: *mut raw::c_void, } diff --git a/third_party/rust/libloading/src/os/windows/mod.rs b/third_party/rust/libloading/src/os/windows/mod.rs index e3da940a29..172801e168 100644 --- a/third_party/rust/libloading/src/os/windows/mod.rs +++ b/third_party/rust/libloading/src/os/windows/mod.rs @@ -1,53 +1,18 @@ // A hack for docs.rs to build documentation that has both windows and linux documentation in the // same rustdoc build visible. #[cfg(all(libloading_docs, not(windows)))] -mod windows_imports { - pub(super) enum WORD {} - pub(super) struct DWORD; - pub(super) enum HMODULE {} - pub(super) enum FARPROC {} - - pub(super) mod consts { - use super::DWORD; - pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_AS_DATAFILE: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = DWORD; - pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = DWORD; - pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD; - } -} +mod windows_imports {} #[cfg(any(not(libloading_docs), windows))] mod windows_imports { - extern crate winapi; - pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC}; - pub(super) use self::winapi::shared::ntdef::WCHAR; - pub(super) use self::winapi::um::{errhandlingapi, libloaderapi}; + use super::{DWORD, BOOL, HANDLE, HMODULE, FARPROC}; pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt}; - pub(super) const SEM_FAILCE: DWORD = 1; - - pub(super) mod consts { - pub(crate) use super::winapi::um::libloaderapi::{ - LOAD_IGNORE_CODE_AUTHZ_LEVEL, - LOAD_LIBRARY_AS_DATAFILE, - LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, - LOAD_LIBRARY_AS_IMAGE_RESOURCE, - LOAD_LIBRARY_SEARCH_APPLICATION_DIR, - LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, - LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, - LOAD_LIBRARY_SEARCH_SYSTEM32, - LOAD_LIBRARY_SEARCH_USER_DIRS, - LOAD_WITH_ALTERED_SEARCH_PATH, - LOAD_LIBRARY_REQUIRE_SIGNED_TARGET, - LOAD_LIBRARY_SAFE_CURRENT_DIRS, - }; - } + windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> DWORD); + windows_targets::link!("kernel32.dll" "system" fn SetThreadErrorMode(new_mode: DWORD, old_mode: *mut DWORD) -> BOOL); + windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleExW(flags: u32, module_name: *const u16, module: *mut HMODULE) -> BOOL); + windows_targets::link!("kernel32.dll" "system" fn FreeLibrary(module: HMODULE) -> BOOL); + windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExW(filename: *const u16, file: HANDLE, flags: DWORD) -> HMODULE); + windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(module: HMODULE, filename: *mut u16, size: DWORD) -> DWORD); + windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(module: HMODULE, procname: *const u8) -> FARPROC); } use self::windows_imports::*; @@ -116,9 +81,9 @@ impl Library { /// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw pub fn this() -> Result { unsafe { - let mut handle: HMODULE = std::ptr::null_mut(); + let mut handle: HMODULE = 0; with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || { - let result = libloaderapi::GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle); + let result = GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle); if result == 0 { None } else { @@ -149,11 +114,11 @@ impl Library { let wide_filename: Vec = filename.as_ref().encode_wide().chain(Some(0)).collect(); let ret = unsafe { - let mut handle: HMODULE = std::ptr::null_mut(); + let mut handle: HMODULE = 0; with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || { // Make sure no winapi calls as a result of drop happen inside this closure, because // otherwise that might change the return value of the GetLastError. - let result = libloaderapi::GetModuleHandleExW(0, wide_filename.as_ptr(), &mut handle); + let result = GetModuleHandleExW(0, wide_filename.as_ptr(), &mut handle); if result == 0 { None } else { @@ -186,16 +151,15 @@ impl Library { /// Additionally, the callers of this function must also ensure that execution of the /// termination routines contained within the library is safe as well. These routines may be /// executed when the library is unloaded. - pub unsafe fn load_with_flags>(filename: P, flags: DWORD) -> Result { + pub unsafe fn load_with_flags>(filename: P, flags: LOAD_LIBRARY_FLAGS) -> Result { let wide_filename: Vec = filename.as_ref().encode_wide().chain(Some(0)).collect(); let _guard = ErrorModeGuard::new(); let ret = with_get_last_error(|source| crate::Error::LoadLibraryExW { source }, || { // Make sure no winapi calls as a result of drop happen inside this closure, because // otherwise that might change the return value of the GetLastError. - let handle = - libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags); - if handle.is_null() { + let handle = LoadLibraryExW(wide_filename.as_ptr(), 0, flags); + if handle == 0 { None } else { Some(Library(handle)) @@ -221,8 +185,8 @@ impl Library { ensure_compatible_types::()?; let symbol = cstr_cow_from_bytes(symbol)?; with_get_last_error(|source| crate::Error::GetProcAddress { source }, || { - let symbol = libloaderapi::GetProcAddress(self.0, symbol.as_ptr()); - if symbol.is_null() { + let symbol = GetProcAddress(self.0, symbol.as_ptr().cast()); + if symbol.is_none() { None } else { Some(Symbol { @@ -238,12 +202,12 @@ impl Library { /// # Safety /// /// Users of this API must specify the correct type of the function or variable loaded. - pub unsafe fn get_ordinal(&self, ordinal: WORD) -> Result, crate::Error> { + pub unsafe fn get_ordinal(&self, ordinal: u16) -> Result, crate::Error> { ensure_compatible_types::()?; with_get_last_error(|source| crate::Error::GetProcAddress { source }, || { - let ordinal = ordinal as usize as *mut _; - let symbol = libloaderapi::GetProcAddress(self.0, ordinal); - if symbol.is_null() { + let ordinal = ordinal as usize as *const _; + let symbol = GetProcAddress(self.0, ordinal); + if symbol.is_none() { None } else { Some(Symbol { @@ -280,7 +244,7 @@ impl Library { /// The underlying data structures may still get leaked if an error does occur. pub fn close(self) -> Result<(), crate::Error> { let result = with_get_last_error(|source| crate::Error::FreeLibrary { source }, || { - if unsafe { libloaderapi::FreeLibrary(self.0) == 0 } { + if unsafe { FreeLibrary(self.0) == 0 } { None } else { Some(()) @@ -296,7 +260,7 @@ impl Library { impl Drop for Library { fn drop(&mut self) { - unsafe { libloaderapi::FreeLibrary(self.0); } + unsafe { FreeLibrary(self.0); } } } @@ -305,17 +269,17 @@ impl fmt::Debug for Library { unsafe { // FIXME: use Maybeuninit::uninit_array when stable let mut buf = - mem::MaybeUninit::<[mem::MaybeUninit::; 1024]>::uninit().assume_init(); - let len = libloaderapi::GetModuleFileNameW(self.0, + mem::MaybeUninit::<[mem::MaybeUninit; 1024]>::uninit().assume_init(); + let len = GetModuleFileNameW(self.0, buf[..].as_mut_ptr().cast(), 1024) as usize; if len == 0 { - f.write_str(&format!("Library@{:p}", self.0)) + f.write_str(&format!("Library@{:#x}", self.0)) } else { let string: OsString = OsString::from_wide( // FIXME: use Maybeuninit::slice_get_ref when stable - &*(&buf[..len] as *const [_] as *const [WCHAR]) + &*(&buf[..len] as *const [_] as *const [u16]), ); - f.write_str(&format!("Library@{:p} from {:?}", self.0, string)) + f.write_str(&format!("Library@{:#x} from {:?}", self.0, string)) } } } @@ -340,7 +304,7 @@ impl Symbol { impl Symbol> { /// Lift Option out of the symbol. pub fn lift_option(self) -> Option> { - if self.pointer.is_null() { + if self.pointer.is_none() { None } else { Some(Symbol { @@ -363,16 +327,16 @@ impl Clone for Symbol { impl ::std::ops::Deref for Symbol { type Target = T; fn deref(&self) -> &T { - unsafe { - // Additional reference level for a dereference on `deref` return value. - &*(&self.pointer as *const *mut _ as *const T) - } + unsafe { &*((&self.pointer) as *const FARPROC as *const T) } } } impl fmt::Debug for Symbol { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&format!("Symbol@{:p}", self.pointer)) + match self.pointer { + None => f.write_str("Symbol@0x0"), + Some(ptr) => f.write_str(&format!("Symbol@{:p}", ptr as *const ())), + } } } @@ -383,13 +347,13 @@ impl ErrorModeGuard { fn new() -> Option { unsafe { let mut previous_mode = 0; - if errhandlingapi::SetThreadErrorMode(SEM_FAILCE, &mut previous_mode) == 0 { + if SetThreadErrorMode(SEM_FAILCRITICALERRORS, &mut previous_mode) == 0 { // How in the world is it possible for what is essentially a simple variable swap // to fail? For now we just ignore the error -- the worst that can happen here is // the previous mode staying on and user seeing a dialog error on older Windows // machines. None - } else if previous_mode == SEM_FAILCE { + } else if previous_mode == SEM_FAILCRITICALERRORS { None } else { Some(ErrorModeGuard(previous_mode)) @@ -401,7 +365,7 @@ impl ErrorModeGuard { impl Drop for ErrorModeGuard { fn drop(&mut self) { unsafe { - errhandlingapi::SetThreadErrorMode(self.0, ptr::null_mut()); + SetThreadErrorMode(self.0, ptr::null_mut()); } } } @@ -410,7 +374,7 @@ fn with_get_last_error(wrap: fn(crate::error::WindowsError) -> crate::Erro -> Result> where F: FnOnce() -> Option { closure().ok_or_else(|| { - let error = unsafe { errhandlingapi::GetLastError() }; + let error = unsafe { GetLastError() }; if error == 0 { None } else { @@ -419,13 +383,29 @@ where F: FnOnce() -> Option { }) } + +#[allow(clippy::upper_case_acronyms)] +type BOOL = i32; +#[allow(clippy::upper_case_acronyms)] +type DWORD = u32; +#[allow(clippy::upper_case_acronyms)] +type HANDLE = isize; +#[allow(clippy::upper_case_acronyms)] +type HMODULE = isize; +#[allow(clippy::upper_case_acronyms)] +type FARPROC = Option isize>; +#[allow(non_camel_case_types)] +type LOAD_LIBRARY_FLAGS = DWORD; + +const SEM_FAILCRITICALERRORS: DWORD = 1; + /// Do not check AppLocker rules or apply Software Restriction Policies for the DLL. /// /// This action applies only to the DLL being loaded and not to its dependencies. This value is /// recommended for use in setup programs that must run extracted DLLs during installation. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL; +pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = 0x00000010; /// Map the file into the calling process’ virtual address space as if it were a data file. /// @@ -435,7 +415,7 @@ pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_L /// messages or resources from it. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE; +pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = 0x00000002; /// Map the file into the calling process’ virtual address space as if it were a data file. /// @@ -444,7 +424,7 @@ pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE; /// while it is in use. However, the DLL can still be opened by other processes. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE; +pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = 0x00000040; /// Map the file into the process’ virtual address space as an image file. /// @@ -456,7 +436,7 @@ pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DA /// [`LOAD_LIBRARY_AS_DATAFILE`]. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE; +pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = 0x00000020; /// Search the application's installation directory for the DLL and its dependencies. /// @@ -464,7 +444,7 @@ pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_ /// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR; +pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = 0x00000200; /// Search default directories when looking for the DLL and its dependencies. /// @@ -474,7 +454,7 @@ pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEAR /// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; +pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 0x00001000; /// Directory that contains the DLL is temporarily added to the beginning of the list of /// directories that are searched for the DLL’s dependencies. @@ -485,7 +465,7 @@ pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_ /// with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; +pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = 0x00000100; /// Search `%windows%\system32` for the DLL and its dependencies. /// @@ -493,7 +473,7 @@ pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_ /// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32; +pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = 0x00000800; /// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched /// for the DLL and its dependencies. @@ -503,7 +483,7 @@ pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYST /// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS; +pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = 0x00000400; /// If `filename` specifies an absolute path, the system uses the alternate file search strategy /// discussed in the [Remarks section] to find associated executable modules that the specified @@ -518,15 +498,15 @@ pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USE /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). /// /// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks -pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH; +pub const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = 0x00000008; /// Specifies that the digital signature of the binary image must be checked at load time. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET; +pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = 0x00000080; /// Allow loading a DLL for execution from the current directory only if it is under a directory in /// the Safe load list. /// /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). -pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS; +pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = 0x00002000; diff --git a/third_party/rust/libloading/tests/functions.rs b/third_party/rust/libloading/tests/functions.rs index c8d1952b3c..a0175a6747 100644 --- a/third_party/rust/libloading/tests/functions.rs +++ b/third_party/rust/libloading/tests/functions.rs @@ -1,5 +1,5 @@ #[cfg(windows)] -extern crate winapi; +extern crate windows_sys; extern crate libloading; use libloading::{Library, Symbol}; @@ -237,14 +237,13 @@ fn library_this() { #[test] fn works_getlasterror() { use libloading::os::windows::{Library, Symbol}; - use winapi::shared::minwindef::DWORD; - use winapi::um::errhandlingapi; + use windows_sys::Win32::Foundation::{GetLastError, SetLastError}; unsafe { let lib = Library::new("kernel32.dll").unwrap(); - let gle: Symbol DWORD> = lib.get(b"GetLastError").unwrap(); - errhandlingapi::SetLastError(42); - assert_eq!(errhandlingapi::GetLastError(), gle()) + let gle: Symbol u32> = lib.get(b"GetLastError").unwrap(); + SetLastError(42); + assert_eq!(GetLastError(), gle()) } } @@ -252,14 +251,13 @@ fn works_getlasterror() { #[test] fn works_getlasterror0() { use libloading::os::windows::{Library, Symbol}; - use winapi::shared::minwindef::DWORD; - use winapi::um::errhandlingapi; + use windows_sys::Win32::Foundation::{GetLastError, SetLastError}; unsafe { let lib = Library::new("kernel32.dll").unwrap(); - let gle: Symbol DWORD> = lib.get(b"GetLastError\0").unwrap(); - errhandlingapi::SetLastError(42); - assert_eq!(errhandlingapi::GetLastError(), gle()) + let gle: Symbol u32> = lib.get(b"GetLastError\0").unwrap(); + SetLastError(42); + assert_eq!(GetLastError(), gle()) } } diff --git a/third_party/rust/metal/.cargo-checksum.json b/third_party/rust/metal/.cargo-checksum.json index a14acdb20b..792477e782 100644 --- a/third_party/rust/metal/.cargo-checksum.json +++ b/third_party/rust/metal/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"ff54827be57e86ac1a50fb371f128cfc0fa87b26de767444e4f59905c98cacfd","Cargo.toml":"eb5025605544e8c4506fea4fa153171c5adaf9bc4a8a2741aaf79c153a1bb7df","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","Makefile":"99c4c592467981921d1257a4e9e841dce53624448738d0ed52a75431a406f7bc","README.md":"b61a350d23e7c88c34b1cd703083978e17c28a286e4231f1dc0a2383a1f85902","assets/metal.svg":"3a295bd130785bc2fea2f3a91a4f6c7b4b3c40682c3fcb7a75f9887b66b06264","bors.toml":"c2733ec512a08bf76b6a1ed77270810a0edeb888ba24c2a75679e1eb1bd563a5","examples/argument-buffer/main.rs":"a087db6648a4b092520de29616521c704d892e0d3ace935d16f3f339415c4361","examples/bind/main.rs":"a0c85aad05f08666f9b380a7146a8473a6a6fe0db5d523760373093a0af20e5f","examples/bindless/main.rs":"0aaad9e42634c1ea204342a76c1bfe80c8fcf9d3ebe8247846cf63ecb08fb0d5","examples/caps/main.rs":"b7be00c1cc9042140d34ea05051152a7035f316f0bdcd31ac5a660a97e0c4f70","examples/circle/README.md":"e1c97cf5252f0d1f2934ace78b5d839c5f45911f3007dbd2925eeceefb8f0af6","examples/circle/main.rs":"22bd52ccba85debc1ccb3f277750e4759283d3c9b135b9a0da496c747e4cf637","examples/circle/screenshot.png":"97bf07c85bf02367447b9c8a81707c124e4a3b420fa386b95ba08b21938f4f2a","examples/circle/shaders.metal":"5e4f40efca5bb386204a09e1b983cc6c634fdf1ca9dd4974227313adbf50e8b5","examples/circle/shaders.metallib":"666a9491d795ef9c0b9c122c7ada571cc2c0e8774d2d89e5b4b996f3dc47962b","examples/compute/compute-argument-buffer.metal":"6530bbd6a0101d9db2893805436f5dc877959e81ea97a27014c0fc52fc9fa77b","examples/compute/compute-argument-buffer.rs":"e3de61fd7cc2f14d9d52300e4878601dbc072bc26d9dafc66115df58f94e0470","examples/compute/embedded-lib.rs":"55f701810fa5270c27ca771e713f9f8cf09e124a997b0b03790b38435593a7ea","examples/compute/main.rs":"bf160f3aba9f7492e3f4b6cf3198f8e454a49d6a29225312a84fdb9d784ffec4","examples/compute/shaders.metal":"f2b15551bb5247b88a3029c3d8ef37c6fa04a4a6cca9f90f069894ed6822b4bf","examples/compute/shaders.metallib":"fef91643e60c0ec99ad2bd2f3916299bcc3e6a80038ea27bed59681badfea7d1","examples/events/main.rs":"9cb35381b0a3918bd7d530171de8f7cceafe3d4851c0f430b4aff1f5c2aae749","examples/fence/main.rs":"47741327e62db1d8bd344b6a9ec26ef13ffb0b56b0dd7077c5d926d43faaeff7","examples/headless-render/README.md":"b1c97b52701cfb41fc0b9e269ba7a7a454d9161746198e2f5789f2636f60842d","examples/headless-render/main.rs":"2e6eb5db66f28833d1b53df3f134b4b53907a00036eeb6cdd9e428478e164aae","examples/headless-render/screenshot.png":"01d6ea5791b63b0f01190198756446cf313fc25dc64d0138c1b4f62c9f862dd1","examples/library/main.rs":"a1420ec28a471f28a789b75b3ecf5abb699ed352b337747169914812fb98045a","examples/mesh-shader/main.rs":"49899300f80f2d1e64366176313f69b597b69f3728a52a6a6f56ff7cd54c3c23","examples/mesh-shader/shaders.metal":"6ba934c3edd3ba0b8f6c4ac37be0fd0fe35eeef004e371521b7bf5a2fae9a223","examples/mesh-shader/shaders.metallib":"0af3b7ab0cd6186a90163550b76fab5bd2ef6ba97e791354d4281ca92d4887ff","examples/mps/main.rs":"2cbb532635270bc55cdfa3ee231cc2ee20dd8b3a5e6bf76062cca89ef1e3498f","examples/mps/shaders.metal":"155922d6a4184078ae7ee29504a268e1218f07d908f921eef60e5bfa8a793bda","examples/mps/shaders.metallib":"b62451223549b1e7eb90ec3d3534c0ed4cdfdc581c7df3ffcdc4786a5fcacde4","examples/raytracing/README.md":"6f0d683efac74572099c317ce9f65c3e6ff3c5252c6870c0c38c67f08b37bb01","examples/raytracing/camera.rs":"bed7a1787e1a52060dd0d64ff630a6fb769f15098d0a9d3ea68d4b57aee78b53","examples/raytracing/geometry.rs":"d3db29b4ab2d3d39de74718e0a7133a4e576dc26dcc6b6728c047865fb78952a","examples/raytracing/main.rs":"c3571854cbaaaeea386d7eb8af1fe9ea0492eae9af62b60203f4b6937dc4999a","examples/raytracing/renderer.rs":"d4e704b8f8e61919882aafc009b3a20928902d5b7edb9122d05f3e468d32f613","examples/raytracing/scene.rs":"fc2f214e0ad90e916fdbe2a339567a5dd323ef45b916fa8432c1156b4e94b998","examples/raytracing/screenshot.png":"400bb138f5adb69e4db8626681fb17667e5e112c94864879d9282d5348d970db","examples/raytracing/shaders.metal":"696f6a0ba79d82e2fa0e03eadbff2f6cdeac87acc805c2b7df657b85c1173174","examples/raytracing/shaders.metallib":"249b71998f58ddf8b3de37d79e9cc1f4a3494fba4bd7ba3f5411fb603de9dd5a","examples/reflection/main.rs":"563b49f5c057f1f8d17f3480cbc466e073ea575bfafaf84018a331a984d90a62","examples/shader-dylib/main.rs":"f18f4eb01420e12c196848c42657d41390cf10a3e47e8870025c20a1b29ddc71","examples/shader-dylib/test_dylib.metal":"3469de785c2c0da784e84758fc0da5a81e474ca15588485d9e04398690641cc8","examples/shader-dylib/test_shader.metal":"1a04ff8ab3288b09d14cd35440b2557e92ddedbff9d07c4144a22e9062e6e1e4","examples/window/README.md":"69655cff298e07887fe70e8a13e27d8a87efcd0cc0da4e15485134e064e1aceb","examples/window/main.rs":"09c508013223de859f33fb69410bde30e8d7f04952850504d8b1f8faf7049b1b","examples/window/screenshot.png":"da7369d7cc297c7f7f6bd773c93e7d708d72442c9c5ff5a20c2f2ee6852552dc","examples/window/shaders.metal":"90dee6c752add5c617dfdca93064b2824b44ff8c01ef63986826f6a1531e95d6","examples/window/shaders.metallib":"16fa82beb70bf16c3501970cae0d5028a747a08164337161dc9c2e8965d4c366","src/accelerator_structure.rs":"3b014b17a30e96d32d6fc69b6d067c08a9d4356cb10dc9121824117711211449","src/argument.rs":"347a5a01d4804044641e09d120d37bba140fc6a364782a96470b753e1ee74b30","src/blitpass.rs":"67b561b319e0650aa8438ce056998d4abd86b765a345f382013ab3cae7a2e71f","src/buffer.rs":"78d9021ab75ef0dad09ff92d126f1ceea241cca606cd7b05553c9351458babed","src/capturedescriptor.rs":"c687c4db298fb83ef640eb34929758c2d7955174a68725e986838e367291e302","src/capturemanager.rs":"c8a42854eebcfb6a7b777d931e368e04a5e35dff2e46c38c481d266dba9b792d","src/commandbuffer.rs":"464d504969ba1c213f6f8812b414c1581e39490cd048888404e04fbb5a1bd4ce","src/commandqueue.rs":"a7d6dee5d064093521465e1da30bded851aa9d59f078942d88926d0f38de82fd","src/computepass.rs":"7c209dc60abc3cb45ed4b1648fd01faaeb561ef980d2b37c3d69a7e5fed9129d","src/constants.rs":"bbfeecf910d4f9ed149a7988d8a79df6e9ad479de81f7fc1294d3434a721b7fd","src/counters.rs":"d36d88f95015eef3655fc114eba1ef680d6a5bf74849389da2d09178244a01c4","src/depthstencil.rs":"71f221640a2031ef40449697297f09cd42d23833854c51759b3006ba55c84de9","src/device.rs":"20a30e95a7e32ee22df068bbdc0ee84790c76fa0fb3ab57f1641b8c5aedf98c6","src/drawable.rs":"2006151031fced10a8b347d9cf465ef15f62551f134d3ff1715e3f3831155f23","src/encoder.rs":"55030f58a4ababcd4c0b4c5b99884ac3bbeae6f16407fc258dce85656c71f276","src/heap.rs":"843536c73cb19643bf7d286433daebf703c28238775d5e006865247c50dabfbf","src/indirect_encoder.rs":"eee68af3cef45555864472622152fcb7a529341b27a98adec882324975fda3f1","src/lib.rs":"e5491ebe9c38e10a28ca5f3f5626bebd4c3901eb55400849c3a0921772f23afe","src/library.rs":"380ff5704b4068a1ff6415a64ff7559691340d059c3c6cd5a87270f00cba1598","src/mps.rs":"b5c5bceb8766a26c50782db80ac15b524890479bab4077685faa02af8d6265a3","src/pipeline/compute.rs":"01a0c8a9485b87a62183c22eaea85afc3345c81c30eb503d05fcf19b3a2c9baf","src/pipeline/mod.rs":"280916e71b6f3c5fffda6ffee31c616bf4aba6e5a186401ea2febe71c3264145","src/pipeline/render.rs":"611ac6d65348cd753ad897ed7a485328e5fd8c87d6f43f9c53868a58883706ed","src/renderpass.rs":"01d4bd8001b6b224f8d7ac5fe5cde45bc34712308e2c1ef05c2e1a4b50397c41","src/resource.rs":"910aa947ba979ad7ed5c5fdd3998b3a334637fe11ee45d3115c0f1363106be75","src/sampler.rs":"780b75b22ab1f6a6675d6e1bd04bd7457660c3325519bffb13a08b1abc64a79c","src/sync.rs":"d0db320dea7609992650062d341f506bf74b60efa761309730fc14bdb682539c","src/texture.rs":"334a7e6e32914ef72d40a7eba87ee90e5ed3dacc763da80b82e1076e0a77cbe2","src/types.rs":"d255f9c1b449acdb971616255e1c98d35b3b1ac54d9c388f7cdff6cfc3a8b944","src/vertexdescriptor.rs":"6a1378f270f7adf631319bcc8c8d6831c9f9be55e7b39a7ccfe151af9a9363c4"},"package":"c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25"} \ No newline at end of file +{"files":{"Cargo.lock":"64c3498f7a31ea043d974120cfaf294b3b6b32a6ba2fd6ddd72e3ee7983c8b57","Cargo.toml":"ac538c2ce2cfde5b76d9fba33bcb11765c11eb556e541c59e3261cee0d1ed17e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","Makefile":"99c4c592467981921d1257a4e9e841dce53624448738d0ed52a75431a406f7bc","README.md":"5cc24c3a06efb2be2280529bc0252b39c55bac347b3a558bc64047f9f421b9e2","assets/metal.svg":"3a295bd130785bc2fea2f3a91a4f6c7b4b3c40682c3fcb7a75f9887b66b06264","bors.toml":"c2733ec512a08bf76b6a1ed77270810a0edeb888ba24c2a75679e1eb1bd563a5","examples/argument-buffer/main.rs":"a087db6648a4b092520de29616521c704d892e0d3ace935d16f3f339415c4361","examples/bind/main.rs":"a0c85aad05f08666f9b380a7146a8473a6a6fe0db5d523760373093a0af20e5f","examples/bindless/main.rs":"0aaad9e42634c1ea204342a76c1bfe80c8fcf9d3ebe8247846cf63ecb08fb0d5","examples/caps/main.rs":"b7be00c1cc9042140d34ea05051152a7035f316f0bdcd31ac5a660a97e0c4f70","examples/circle/README.md":"e1c97cf5252f0d1f2934ace78b5d839c5f45911f3007dbd2925eeceefb8f0af6","examples/circle/main.rs":"22bd52ccba85debc1ccb3f277750e4759283d3c9b135b9a0da496c747e4cf637","examples/circle/screenshot.png":"97bf07c85bf02367447b9c8a81707c124e4a3b420fa386b95ba08b21938f4f2a","examples/circle/shaders.metal":"5e4f40efca5bb386204a09e1b983cc6c634fdf1ca9dd4974227313adbf50e8b5","examples/circle/shaders.metallib":"666a9491d795ef9c0b9c122c7ada571cc2c0e8774d2d89e5b4b996f3dc47962b","examples/compute/compute-argument-buffer.metal":"6530bbd6a0101d9db2893805436f5dc877959e81ea97a27014c0fc52fc9fa77b","examples/compute/compute-argument-buffer.rs":"e3de61fd7cc2f14d9d52300e4878601dbc072bc26d9dafc66115df58f94e0470","examples/compute/embedded-lib.rs":"55f701810fa5270c27ca771e713f9f8cf09e124a997b0b03790b38435593a7ea","examples/compute/main.rs":"bf160f3aba9f7492e3f4b6cf3198f8e454a49d6a29225312a84fdb9d784ffec4","examples/compute/shaders.metal":"f2b15551bb5247b88a3029c3d8ef37c6fa04a4a6cca9f90f069894ed6822b4bf","examples/compute/shaders.metallib":"fef91643e60c0ec99ad2bd2f3916299bcc3e6a80038ea27bed59681badfea7d1","examples/events/main.rs":"9cb35381b0a3918bd7d530171de8f7cceafe3d4851c0f430b4aff1f5c2aae749","examples/fence/main.rs":"47741327e62db1d8bd344b6a9ec26ef13ffb0b56b0dd7077c5d926d43faaeff7","examples/headless-render/README.md":"b1c97b52701cfb41fc0b9e269ba7a7a454d9161746198e2f5789f2636f60842d","examples/headless-render/main.rs":"2e6eb5db66f28833d1b53df3f134b4b53907a00036eeb6cdd9e428478e164aae","examples/headless-render/screenshot.png":"01d6ea5791b63b0f01190198756446cf313fc25dc64d0138c1b4f62c9f862dd1","examples/library/main.rs":"a1420ec28a471f28a789b75b3ecf5abb699ed352b337747169914812fb98045a","examples/mesh-shader/main.rs":"49899300f80f2d1e64366176313f69b597b69f3728a52a6a6f56ff7cd54c3c23","examples/mesh-shader/shaders.metal":"6ba934c3edd3ba0b8f6c4ac37be0fd0fe35eeef004e371521b7bf5a2fae9a223","examples/mesh-shader/shaders.metallib":"0af3b7ab0cd6186a90163550b76fab5bd2ef6ba97e791354d4281ca92d4887ff","examples/mps/main.rs":"2cbb532635270bc55cdfa3ee231cc2ee20dd8b3a5e6bf76062cca89ef1e3498f","examples/mps/shaders.metal":"155922d6a4184078ae7ee29504a268e1218f07d908f921eef60e5bfa8a793bda","examples/mps/shaders.metallib":"b62451223549b1e7eb90ec3d3534c0ed4cdfdc581c7df3ffcdc4786a5fcacde4","examples/raytracing/README.md":"6f0d683efac74572099c317ce9f65c3e6ff3c5252c6870c0c38c67f08b37bb01","examples/raytracing/camera.rs":"bed7a1787e1a52060dd0d64ff630a6fb769f15098d0a9d3ea68d4b57aee78b53","examples/raytracing/geometry.rs":"d3db29b4ab2d3d39de74718e0a7133a4e576dc26dcc6b6728c047865fb78952a","examples/raytracing/main.rs":"c3571854cbaaaeea386d7eb8af1fe9ea0492eae9af62b60203f4b6937dc4999a","examples/raytracing/renderer.rs":"d4e704b8f8e61919882aafc009b3a20928902d5b7edb9122d05f3e468d32f613","examples/raytracing/scene.rs":"fc2f214e0ad90e916fdbe2a339567a5dd323ef45b916fa8432c1156b4e94b998","examples/raytracing/screenshot.png":"400bb138f5adb69e4db8626681fb17667e5e112c94864879d9282d5348d970db","examples/raytracing/shaders.metal":"696f6a0ba79d82e2fa0e03eadbff2f6cdeac87acc805c2b7df657b85c1173174","examples/raytracing/shaders.metallib":"249b71998f58ddf8b3de37d79e9cc1f4a3494fba4bd7ba3f5411fb603de9dd5a","examples/reflection/main.rs":"563b49f5c057f1f8d17f3480cbc466e073ea575bfafaf84018a331a984d90a62","examples/shader-dylib/main.rs":"f18f4eb01420e12c196848c42657d41390cf10a3e47e8870025c20a1b29ddc71","examples/shader-dylib/test_dylib.metal":"3469de785c2c0da784e84758fc0da5a81e474ca15588485d9e04398690641cc8","examples/shader-dylib/test_shader.metal":"1a04ff8ab3288b09d14cd35440b2557e92ddedbff9d07c4144a22e9062e6e1e4","examples/window/README.md":"69655cff298e07887fe70e8a13e27d8a87efcd0cc0da4e15485134e064e1aceb","examples/window/main.rs":"09c508013223de859f33fb69410bde30e8d7f04952850504d8b1f8faf7049b1b","examples/window/screenshot.png":"da7369d7cc297c7f7f6bd773c93e7d708d72442c9c5ff5a20c2f2ee6852552dc","examples/window/shaders.metal":"90dee6c752add5c617dfdca93064b2824b44ff8c01ef63986826f6a1531e95d6","examples/window/shaders.metallib":"16fa82beb70bf16c3501970cae0d5028a747a08164337161dc9c2e8965d4c366","src/accelerator_structure.rs":"3b014b17a30e96d32d6fc69b6d067c08a9d4356cb10dc9121824117711211449","src/argument.rs":"347a5a01d4804044641e09d120d37bba140fc6a364782a96470b753e1ee74b30","src/blitpass.rs":"67b561b319e0650aa8438ce056998d4abd86b765a345f382013ab3cae7a2e71f","src/buffer.rs":"78d9021ab75ef0dad09ff92d126f1ceea241cca606cd7b05553c9351458babed","src/capturedescriptor.rs":"c687c4db298fb83ef640eb34929758c2d7955174a68725e986838e367291e302","src/capturemanager.rs":"c8a42854eebcfb6a7b777d931e368e04a5e35dff2e46c38c481d266dba9b792d","src/commandbuffer.rs":"464d504969ba1c213f6f8812b414c1581e39490cd048888404e04fbb5a1bd4ce","src/commandqueue.rs":"a7d6dee5d064093521465e1da30bded851aa9d59f078942d88926d0f38de82fd","src/computepass.rs":"7c209dc60abc3cb45ed4b1648fd01faaeb561ef980d2b37c3d69a7e5fed9129d","src/constants.rs":"bbfeecf910d4f9ed149a7988d8a79df6e9ad479de81f7fc1294d3434a721b7fd","src/counters.rs":"d36d88f95015eef3655fc114eba1ef680d6a5bf74849389da2d09178244a01c4","src/depthstencil.rs":"71f221640a2031ef40449697297f09cd42d23833854c51759b3006ba55c84de9","src/device.rs":"4fe4e0d3dd56a7f5bb0b80c016479f7844f779b5e255ecfec2f6b7995c804584","src/drawable.rs":"2006151031fced10a8b347d9cf465ef15f62551f134d3ff1715e3f3831155f23","src/encoder.rs":"55030f58a4ababcd4c0b4c5b99884ac3bbeae6f16407fc258dce85656c71f276","src/heap.rs":"843536c73cb19643bf7d286433daebf703c28238775d5e006865247c50dabfbf","src/indirect_encoder.rs":"eee68af3cef45555864472622152fcb7a529341b27a98adec882324975fda3f1","src/lib.rs":"54765ef6ca93d35aeed2022fd765b811b9f396292c024e44da28f1c1c5809309","src/library.rs":"a550201b0076d646134728c2fde0ed2257254f3d941e461f71fc258781dcc4df","src/mps.rs":"b02dd94d31f7252265ebca5d22a13307d8b61e418887047b3a22a04562f681cc","src/pipeline/compute.rs":"01a0c8a9485b87a62183c22eaea85afc3345c81c30eb503d05fcf19b3a2c9baf","src/pipeline/mod.rs":"280916e71b6f3c5fffda6ffee31c616bf4aba6e5a186401ea2febe71c3264145","src/pipeline/render.rs":"611ac6d65348cd753ad897ed7a485328e5fd8c87d6f43f9c53868a58883706ed","src/renderpass.rs":"01d4bd8001b6b224f8d7ac5fe5cde45bc34712308e2c1ef05c2e1a4b50397c41","src/resource.rs":"910aa947ba979ad7ed5c5fdd3998b3a334637fe11ee45d3115c0f1363106be75","src/sampler.rs":"780b75b22ab1f6a6675d6e1bd04bd7457660c3325519bffb13a08b1abc64a79c","src/sync.rs":"5d56ccbe4948683486bae1f0a3f0d4192b5b3e09c76457aecbd3a21569923639","src/texture.rs":"334a7e6e32914ef72d40a7eba87ee90e5ed3dacc763da80b82e1076e0a77cbe2","src/types.rs":"d255f9c1b449acdb971616255e1c98d35b3b1ac54d9c388f7cdff6cfc3a8b944","src/vertexdescriptor.rs":"6a1378f270f7adf631319bcc8c8d6831c9f9be55e7b39a7ccfe151af9a9363c4"},"package":"5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb"} \ No newline at end of file diff --git a/third_party/rust/metal/Cargo.lock b/third_party/rust/metal/Cargo.lock index d2717b65ee..75c1bf69e1 100644 --- a/third_party/rust/metal/Cargo.lock +++ b/third_party/rust/metal/Cargo.lock @@ -34,9 +34,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block" @@ -46,15 +46,15 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" [[package]] name = "calloop" @@ -103,7 +103,7 @@ dependencies = [ "core-foundation", "core-graphics", "foreign-types 0.3.2", - "libc 0.2.149", + "libc 0.2.153", "objc", ] @@ -118,25 +118,25 @@ dependencies = [ "core-foundation", "core-graphics-types", "foreign-types 0.3.2", - "libc 0.2.149", + "libc 0.2.153", "objc", ] [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", - "libc 0.2.149", + "libc 0.2.153", ] [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core-graphics" @@ -148,19 +148,18 @@ dependencies = [ "core-foundation", "core-graphics-types", "foreign-types 0.3.2", - "libc 0.2.149", + "libc 0.2.153", ] [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", "core-foundation", - "foreign-types 0.3.2", - "libc 0.2.149", + "libc 0.2.153", ] [[package]] @@ -172,7 +171,7 @@ dependencies = [ "core-foundation", "core-graphics", "foreign-types 0.3.2", - "libc 0.2.149", + "libc 0.2.153", ] [[package]] @@ -198,7 +197,7 @@ dependencies = [ "dwrote", "foreign-types 0.5.0", "freetype-rs", - "libc 0.2.149", + "libc 0.2.153", "log", "objc", "once_cell", @@ -276,7 +275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" dependencies = [ "lazy_static", - "libc 0.2.149", + "libc 0.2.153", "serde", "serde_derive", "winapi", @@ -301,18 +300,18 @@ dependencies = [ [[package]] name = "fdeflate" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ "simd-adler32", ] [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" dependencies = [ "crc32fast", "miniz_oxide", @@ -351,7 +350,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.60", ] [[package]] @@ -374,7 +373,7 @@ checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb" dependencies = [ "bitflags 1.3.2", "freetype-sys", - "libc 0.2.149", + "libc 0.2.153", ] [[package]] @@ -384,7 +383,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" dependencies = [ "cmake", - "libc 0.2.149", + "libc 0.2.153", "pkg-config", ] @@ -401,7 +400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", - "libc 0.2.149", + "libc 0.2.153", "wasi 0.11.0+wasi-snapshot-preview1", ] @@ -413,9 +412,9 @@ checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774" [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "ident_case" @@ -425,9 +424,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.0.2" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -453,9 +452,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -474,9 +473,9 @@ checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" @@ -513,7 +512,7 @@ version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" dependencies = [ - "libc 0.1.12", + "libc 0.2.153", ] [[package]] @@ -528,7 +527,7 @@ version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ - "libc 0.2.149", + "libc 0.2.153", ] [[package]] @@ -542,9 +541,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.27.0" +version = "0.28.0" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "block", "cocoa", "core-graphics-types", @@ -569,9 +568,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", "simd-adler32", @@ -579,11 +578,11 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ - "libc 0.2.149", + "libc 0.2.153", "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", @@ -615,7 +614,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f" dependencies = [ - "libc 0.2.149", + "libc 0.2.153", "log", "ndk", "ndk-context", @@ -655,7 +654,7 @@ checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ "bitflags 1.3.2", "cfg-if", - "libc 0.2.149", + "libc 0.2.153", "memoffset", ] @@ -668,7 +667,7 @@ dependencies = [ "autocfg", "bitflags 1.3.2", "cfg-if", - "libc 0.2.149", + "libc 0.2.153", "memoffset", ] @@ -710,29 +709,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -740,15 +729,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", - "libc 0.2.149", + "libc 0.2.153", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.5", ] [[package]] @@ -771,9 +760,9 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "png" -version = "0.17.10" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -800,18 +789,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -822,7 +811,7 @@ version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" dependencies = [ - "libc 0.2.149", + "libc 0.2.153", "rand 0.4.6", ] @@ -833,7 +822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" dependencies = [ "fuchsia-cprng", - "libc 0.2.149", + "libc 0.2.153", "rand_core 0.3.1", "rdrand", "winapi", @@ -845,7 +834,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc 0.2.149", + "libc 0.2.153", "rand_chacha", "rand_core 0.6.4", ] @@ -910,11 +899,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] @@ -969,13 +958,13 @@ checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.60", ] [[package]] @@ -984,7 +973,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" dependencies = [ - "libc 0.2.149", + "libc 0.2.153", "servo-fontconfig-sys", ] @@ -1007,9 +996,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] @@ -1058,9 +1047,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -1093,7 +1082,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ - "libc 0.2.149", + "libc 0.2.153", "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -1172,9 +1161,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1182,24 +1171,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.60", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1207,22 +1196,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-client" @@ -1232,7 +1221,7 @@ checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" dependencies = [ "bitflags 1.3.2", "downcast-rs", - "libc 0.2.149", + "libc 0.2.153", "nix 0.24.3", "scoped-tls", "wayland-commons", @@ -1299,9 +1288,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -1348,7 +1337,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1357,21 +1346,43 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" @@ -1384,6 +1395,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.36.1" @@ -1396,6 +1413,18 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.36.1" @@ -1408,6 +1437,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" @@ -1420,12 +1455,24 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" @@ -1438,6 +1485,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "winit" version = "0.27.5" @@ -1450,7 +1503,7 @@ dependencies = [ "core-graphics", "dispatch", "instant", - "libc 0.2.149", + "libc 0.2.153", "log", "mio", "ndk", @@ -1473,9 +1526,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] @@ -1496,7 +1549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" dependencies = [ "lazy_static", - "libc 0.2.149", + "libc 0.2.153", "pkg-config", ] diff --git a/third_party/rust/metal/Cargo.toml b/third_party/rust/metal/Cargo.toml index a81b535fd0..152460eb2d 100644 --- a/third_party/rust/metal/Cargo.toml +++ b/third_party/rust/metal/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "metal" -version = "0.27.0" +version = "0.28.0" authors = ["gfx-rs developers"] exclude = [ "guide/**/*", @@ -97,7 +97,7 @@ version = "2" version = "0.1.6" [dependencies.core-graphics-types] -version = "0.1" +version = "0.1.3" [dependencies.dispatch] version = "0.2" @@ -111,7 +111,6 @@ version = "0.4" [dependencies.objc] version = "0.2.4" -features = ["objc_exception"] [dependencies.paste] version = "1" @@ -139,6 +138,6 @@ version = "0.27" [features] default = ["link"] -link = [] +link = ["core-graphics-types/link"] mps = [] private = [] diff --git a/third_party/rust/metal/README.md b/third_party/rust/metal/README.md index ef94a72da8..1311edfbe1 100644 --- a/third_party/rust/metal/README.md +++ b/third_party/rust/metal/README.md @@ -8,13 +8,6 @@

Unsafe Rust bindings for the Metal 3D Graphics API.

-## Documentation - -Note that [docs.rs](docs.rs) will fail to build the (albeit limited) documentation for this crate! -They build in a Linux container, but of course this will only compile on MacOS. - -Please build the documentation yourself with `cargo docs`. - ## Examples The [examples](/examples) directory highlights different ways of using the Metal graphics API for rendering diff --git a/third_party/rust/metal/src/device.rs b/third_party/rust/metal/src/device.rs index 11b5575577..75061cc497 100644 --- a/third_party/rust/metal/src/device.rs +++ b/third_party/rust/metal/src/device.rs @@ -8,8 +8,7 @@ use super::*; use block::{Block, ConcreteBlock}; -use foreign_types::ForeignType; -use objc::runtime::{Object, NO, YES}; +use objc::runtime::{NO, YES}; use std::{ffi::CStr, os::raw::c_char, path::Path, ptr}; diff --git a/third_party/rust/metal/src/lib.rs b/third_party/rust/metal/src/lib.rs index b79acf6e84..535c01da68 100644 --- a/third_party/rust/metal/src/lib.rs +++ b/third_party/rust/metal/src/lib.rs @@ -20,13 +20,7 @@ pub extern crate foreign_types; #[macro_use] pub extern crate paste; -use std::{ - borrow::{Borrow, ToOwned}, - marker::PhantomData, - mem, - ops::Deref, - os::raw::c_void, -}; +use std::{borrow::Borrow, marker::PhantomData, mem, ops::Deref, os::raw::c_void}; use core_graphics_types::{base::CGFloat, geometry::CGSize}; use foreign_types::ForeignType; diff --git a/third_party/rust/metal/src/library.rs b/third_party/rust/metal/src/library.rs index 2c7d0c92ce..9f7d58cc7c 100644 --- a/third_party/rust/metal/src/library.rs +++ b/third_party/rust/metal/src/library.rs @@ -7,11 +7,10 @@ use super::*; -use foreign_types::ForeignType; -use objc::runtime::{Object, BOOL, NO, YES}; +use objc::runtime::{BOOL, NO, YES}; use std::ffi::CStr; -use std::os::raw::{c_char, c_void}; +use std::os::raw::c_char; use std::ptr; /// Only available on (macos(10.12), ios(10.0) @@ -361,6 +360,10 @@ pub enum MTLLanguageVersion { V2_3 = 0x20003, /// available on macOS 12.0+, iOS 15.0+ V2_4 = 0x20004, + /// available on macOS 13.0+, iOS 16.0+ + V3_0 = 0x30000, + /// available on macOS 14.0+, iOS 17.0+ + V3_1 = 0x30001, } /// See diff --git a/third_party/rust/metal/src/mps.rs b/third_party/rust/metal/src/mps.rs index edd4936e8e..f4c9fc89a2 100644 --- a/third_party/rust/metal/src/mps.rs +++ b/third_party/rust/metal/src/mps.rs @@ -7,9 +7,12 @@ use super::*; -use objc::runtime::{BOOL, YES}; +use objc::runtime::BOOL; -#[cfg_attr(feature = "link", link(name = "MetalPerformanceShaders", kind = "framework"))] +#[cfg_attr( + feature = "link", + link(name = "MetalPerformanceShaders", kind = "framework") +)] extern "C" { fn MPSSupportsMTLDevice(device: *const std::ffi::c_void) -> BOOL; } diff --git a/third_party/rust/metal/src/sync.rs b/third_party/rust/metal/src/sync.rs index 550e06be12..c36804813e 100644 --- a/third_party/rust/metal/src/sync.rs +++ b/third_party/rust/metal/src/sync.rs @@ -7,7 +7,7 @@ use super::*; use block::{Block, RcBlock}; -use std::mem; +use std::ptr; #[cfg(feature = "dispatch_queue")] use dispatch; @@ -63,7 +63,7 @@ impl SharedEventRef { *mut BlockBase<(&SharedEventRef, u64), ()>, >(block); (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE; - (*block).extra = &BLOCK_EXTRA; + (*block).extra = ptr::addr_of!(BLOCK_EXTRA); let () = msg_send![self, notifyListener:listener atValue:value block:block]; } diff --git a/third_party/rust/minidump-common/.cargo-checksum.json b/third_party/rust/minidump-common/.cargo-checksum.json index 1ddebcac04..84e8ed9037 100644 --- a/third_party/rust/minidump-common/.cargo-checksum.json +++ b/third_party/rust/minidump-common/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e0f49679fe070718b42d9e9bed49860a29471f6e2854a501dceba286301888b1","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"4c2a1448aab9177fd5f033faaf704af7bb222bf0804079fd3cff90fa1df4b812","src/errors/linux.rs":"df743ac9478e39f8a577f4f10f2d1317babad7b7c0d26cdbba2ea6b5426f4126","src/errors/macos.rs":"02ac6427f376e6f587c1f3e4d5df2a72e4cf13c4858409e73f26d47ad8e54340","src/errors/mod.rs":"f224af66124fd31a040c8da11bbab7b7795b48e4edea76e01c1f4dee537ea38a","src/errors/windows.rs":"0567af7bfac3ae2a8dff418e10873d8a5bf15a8b8ac6892c5ffdab08ec3ac901","src/format.rs":"f453ada36ffcb986a62391f9451b7826bdde9d5024beb11a495d1ed1e93bb52c","src/lib.rs":"0900c00594b3c386b86127055889006f0d7d0004b08455fadb0e60d55a469cab","src/traits.rs":"93127ad69a849325ed66a0626e0bdae05868488f81c539d35c71a7bfbb9e51ac","src/utils.rs":"17e8777b05998a8149fc5168af3bca1e0f9aeffe28cb3d6dbfb89c546f75e5ed"},"package":"3dbc11dfb55b3b7b5684fb16d98e0fc9d1e93a64d6b00bf383eabfc4541aaac2"} \ No newline at end of file +{"files":{"Cargo.toml":"32470c1f1471a46161eb9fda47e6e7d50e2615bfb0722bcd9355fbb90174319e","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"4c2a1448aab9177fd5f033faaf704af7bb222bf0804079fd3cff90fa1df4b812","src/errors/linux.rs":"df743ac9478e39f8a577f4f10f2d1317babad7b7c0d26cdbba2ea6b5426f4126","src/errors/macos.rs":"4516aaeb7abf6209f5cd94e86a1e55a9675ef77262f52e3b2d5596fd4b858458","src/errors/mod.rs":"f224af66124fd31a040c8da11bbab7b7795b48e4edea76e01c1f4dee537ea38a","src/errors/windows.rs":"0567af7bfac3ae2a8dff418e10873d8a5bf15a8b8ac6892c5ffdab08ec3ac901","src/format.rs":"4d9baaa3b3b52b4311efaadb12921088141becba8890ae977f0a2807eaa7f820","src/lib.rs":"0900c00594b3c386b86127055889006f0d7d0004b08455fadb0e60d55a469cab","src/traits.rs":"93127ad69a849325ed66a0626e0bdae05868488f81c539d35c71a7bfbb9e51ac","src/utils.rs":"17e8777b05998a8149fc5168af3bca1e0f9aeffe28cb3d6dbfb89c546f75e5ed"},"package":"1bb6eaf88cc770fa58e6ae721cf2e40c2ca6a4c942ae8c7aa324d680bd3c6717"} \ No newline at end of file diff --git a/third_party/rust/minidump-common/Cargo.toml b/third_party/rust/minidump-common/Cargo.toml index 798d7a27d3..416d3b703e 100644 --- a/third_party/rust/minidump-common/Cargo.toml +++ b/third_party/rust/minidump-common/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "minidump-common" -version = "0.19.1" +version = "0.21.1" authors = ["Ted Mielczarek "] description = "Some common types for working with minidump files." homepage = "https://github.com/rust-minidump/rust-minidump" @@ -42,7 +42,7 @@ version = "0.2" version = "0.2" [dependencies.scroll] -version = "0.11.0" +version = "0.12.0" features = ["derive"] [dependencies.smart-default] diff --git a/third_party/rust/minidump-common/src/errors/macos.rs b/third_party/rust/minidump-common/src/errors/macos.rs index d27c772e2a..667bb3919c 100644 --- a/third_party/rust/minidump-common/src/errors/macos.rs +++ b/third_party/rust/minidump-common/src/errors/macos.rs @@ -330,7 +330,7 @@ pub enum ExceptionCodeMacResourceThreadsFlavor { /// /// See the [osfmk/kern/exc_guard.h][header] header in Apple's kernel sources /// -/// [header]: https://github.com/apple/darwin-xnu/blob/main/osfmk/kern/exc_guard.h +/// [header]: https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/kern/exc_guard.h #[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)] pub enum ExceptionCodeMacGuardType { GUARD_TYPE_NONE = 0, @@ -339,18 +339,21 @@ pub enum ExceptionCodeMacGuardType { GUARD_TYPE_USER = 3, GUARD_TYPE_VN = 4, GUARD_TYPE_VIRT_MEMORY = 5, + GUARD_TYPE_REJECTED_SC = 6, } /// Mac/iOS Mach port guard exception flavors /// /// See the [osfmk/mach/port.h][header] header in Apple's kernel sources /// -/// [header]: https://github.com/apple/darwin-xnu/blob/main/osfmk/mach/port.h +/// [header]: https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/mach/port.h #[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)] pub enum ExceptionCodeMacGuardMachPortFlavor { - GUARD_EXC_DESTROY = 0x00000001, - GUARD_EXC_MOD_REFS = 0x00000002, - GUARD_EXC_SET_CONTEXT = 0x00000004, + GUARD_EXC_DESTROY = 1, + GUARD_EXC_MOD_REFS = 2, + GUARD_EXC_INVALID_OPTIONS = 3, + GUARD_EXC_SET_CONTEXT = 4, + GUARD_EXC_THREAD_SET_STATE = 5, GUARD_EXC_UNGUARDED = 0x00000008, GUARD_EXC_INCORRECT_GUARD = 0x00000010, GUARD_EXC_IMMOVABLE = 0x00000020, @@ -371,6 +374,8 @@ pub enum ExceptionCodeMacGuardMachPortFlavor { GUARD_EXC_RCV_GUARDED_DESC = 0x00100000, GUARD_EXC_MOD_REFS_NON_FATAL = 0x00200000, GUARD_EXC_IMMOVABLE_NON_FATAL = 0x00400000, + GUARD_EXC_REQUIRE_REPLY_PORT_SEMANTICS = 0x00800000, + GUARD_EXC_EXCEPTION_BEHAVIOR_ENFORCE = 0x01000000, } /// Mac/iOS fd guard exception flavors @@ -414,3 +419,13 @@ pub enum ExceptionCodeMacGuardVNFlavor { pub enum ExceptionCodeMacGuardVirtMemoryFlavor { GUARD_EXC_DEALLOC_GAP = 0x00000001, } + +/// Mac/iOS rejected syscall guard exception flavors +/// +/// See the [osfmk/kern/exc_guard.h][header] header in Apple's kernel sources +/// +/// [header]: https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/kern/exc_guard.h#L149-L163 +#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)] +pub enum ExceptionCodeMacGuardRejecteSysCallFlavor { + GUARD_EXC_MACH_TRAP = 0x00000000, +} diff --git a/third_party/rust/minidump-common/src/format.rs b/third_party/rust/minidump-common/src/format.rs index 2b610ef559..d6a8f629b5 100644 --- a/third_party/rust/minidump-common/src/format.rs +++ b/third_party/rust/minidump-common/src/format.rs @@ -2552,3 +2552,27 @@ pub struct MINIDUMP_HANDLE_DATA_STREAM { /// Reserved for future use; must be zero. pub reserved: u32, } + +#[derive(Debug, Clone, Pread, Pwrite, SizeWith)] +pub struct MINIDUMP_THREAD_INFO { + /// Thread identifier + pub thread_id: u32, + /// Thread state flags + pub dump_flags: u32, + /// HRESULT value of dump status + pub dump_error: u32, + /// The thread's exit code + pub exit_status: u32, + /// UTC time the thread was created + pub create_time: u64, + /// UTC time the thread exited + pub exit_time: u64, + /// Time executed in kernel mode + pub kernel_time: u64, + /// Time executed in user mode + pub user_time: u64, + /// Start address of the thread + pub start_address: u64, + /// Processor affinity mask + pub affinity: u64, +} diff --git a/third_party/rust/minidump-writer/.cargo-checksum.json b/third_party/rust/minidump-writer/.cargo-checksum.json index 461af91038..1036c5f77f 100644 --- a/third_party/rust/minidump-writer/.cargo-checksum.json +++ b/third_party/rust/minidump-writer/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"bd47a727b96e7175b86cb9384fa9a4174ef6172869ad535374c38825fd2c3b38","Cargo.lock":"9bf0a7576a9f71f2a06a1ebf886af125fcd11fb771cb6491804ad2e1c07bf408","Cargo.toml":"34acafdc4e13be804e847b771c2a9da6928d161bddab467f4d9a4085c79e9210","LICENSE":"1ecdd8e8977af83c07c5f97bec87b47d27059b7ea323ca3160fbfa2314f5d99c","README.md":"ba247891c565089e59211c414755ed4693b81371233fa3b398a501b545f6b962","build.rs":"689cd32a441f5011f694a9f86bc03bc27c2a09bcb4130f47e04fe00bb069b1b5","deny.toml":"d0eab3030d061ba5bf0b7b11ce3001cc2e5b49ea0add047602edd334fdceb5bc","examples/synthetic.rs":"cd13bd0bba64a1d8c8c326bb1ce1818bead6904e5708418fd09edeaef1437c24","release.toml":"f554067378aec602383b96e5fa63427136533a7dd00137fd0664b279fb8fcc56","src/bin/test.rs":"3b6b59e7205b2f51184d169b7902b52cf9c8a863bb27f91a45f4466e1f0d1359","src/dir_section.rs":"b7c83b16acefb4327b406612e1a667dffb91f86bec40f9330171dba8d10346ff","src/lib.rs":"6f393273ea6b354f412e70c9a4925fe2e646bc477591962c96a61aed9fde4e3b","src/linux.rs":"65d1249e80a3c3b6ab8c4361891b5ef35fe68f91253f6378ae03a0ad59ecd807","src/linux/android.rs":"9f2fd633de0d545b400c479a70f000cb9d04bb6e322f62098f4a7ebe7299f051","src/linux/app_memory.rs":"5f093e4ed0aecc6086366a9c09658761fdd3b0e6e9ff2111690719e56612df64","src/linux/auxv_reader.rs":"e9c75b0093c845da8dd321c6582e65678772c57658358213098aa6267f3679e1","src/linux/crash_context.rs":"069d949c7a9fc23a1e8710f7c018cacf71af2326a2dd6ca0283d492c5253107a","src/linux/crash_context/aarch64.rs":"158d02200b25a7ca029ff5132ba3b7f76a05c9976ff529a5658523aff370e4d2","src/linux/crash_context/arm.rs":"a4f41aae015937d3dccdf759df84bc657cf457d8baaf07711617d17f4b40f6f1","src/linux/crash_context/x86.rs":"d464680ee9df8a7f11dae2bb199cc4efb66dfc790a87c9b773c3a9b44b9339d8","src/linux/crash_context/x86_64.rs":"dceabbcf4d3c4ff5ad7658daa7dec3349cad9b61091385bcd868de6b11eb4957","src/linux/dso_debug.rs":"39beabf0598fe6bfaf0edd068bbe20442b45a7c0567588e978e8d9f5c331888b","src/linux/dumper_cpu_info.rs":"76558ffc85386e416bbfc49adc550f61fb206dfbfb0b6a25f620a5fc91f32bc1","src/linux/dumper_cpu_info/arm.rs":"6fc140181f3a32504c3b66f0235136e730424be830602c87cfbeb1dfb4c1cec3","src/linux/dumper_cpu_info/x86_mips.rs":"1b7f554190c2c0f0575e36995aae5211a0fc9f29f3949ac7521a9d148566f6e9","src/linux/errors.rs":"f0bc2a400a16d322f8d0dd5c76afa61fa32cf8a86f1b4e937298f767de031cb8","src/linux/maps_reader.rs":"0fde4c432f718e38d3ff35abcf00d3d3b478836fec2113ee11a8a1419921fe7b","src/linux/minidump_writer.rs":"b85eadb008c2f92d3d86c2c44c10bd139f793a0988d79aa51969848773bfb0fc","src/linux/ptrace_dumper.rs":"a2d6a06bb088caad1254746d842cb2c8d4fed918cfc318ec562aa160af3526d1","src/linux/sections.rs":"98aabd7e4b0542201783af90cafdc66bb3845585d0ed24af7476c1ea3ab40fb9","src/linux/sections/app_memory.rs":"52fdfe9622a395763fef94c5fea924935fcd86103c3eb1b0fb8d7ea61fd3e783","src/linux/sections/exception_stream.rs":"e1b73b5168506f8804479206ef0941aca5f792500cc56c5c17db55cd6b273a99","src/linux/sections/handle_data_stream.rs":"3aae030c009543142555d493f9273e3445454b18085dfdb3b44bc83d43b510dd","src/linux/sections/mappings.rs":"3b3bdf51e8e11f5b579d51b1a06244f1785cdfcdda3ee835472e5ab58756e71c","src/linux/sections/memory_info_list_stream.rs":"bd927824e859e2fcbc85ef9d5e3d8b7be13c4918a636f70f0712070d6c65b002","src/linux/sections/memory_list_stream.rs":"f2d5b33fb4167b502dc8e74371d50b4ad66e0b48f541fe16bcbf5fb62491bf2d","src/linux/sections/systeminfo_stream.rs":"02373c97d4caeb66f4601c066d430ad2929b5584eaa0af3be1dc51ef818e5cb8","src/linux/sections/thread_list_stream.rs":"9ea966c00a878ef1a6e6781005ddf9909c18177f2c455cb250c4ac191040fc69","src/linux/sections/thread_names_stream.rs":"2a123335626e941cf0a3349f9327c3e7606af593a8370ef5f71325012107b91f","src/linux/thread_info.rs":"b57a989a97418821a40c019d8edcb3143b43d3f76d7172d55a05001c9bfc210f","src/linux/thread_info/aarch64.rs":"fcbdd6b9185f00b4f42eef27076a8c9edab8afcaf22e1c005e32702be16e2264","src/linux/thread_info/arm.rs":"cf927d9f0ea48e07a874e8d6049e447c0f12a0715ed166448c3b07a410dd958a","src/linux/thread_info/mips.rs":"332d7888bb08a36d3b77023a4a0385193a07b1c6c5bf0e91aacb5d948ba8b903","src/linux/thread_info/x86.rs":"a759b2298f0831298c56e49717b4f188c213ebeb30b38be23af5bcbe6fd96369","src/mac.rs":"4671ad90c433db559ec633c880c3fe083f38a2e185ef4fc99577318526076519","src/mac/errors.rs":"696473d1187a0f003409e3ac0fc83a02cafbad8451a62bda868b08acc36e7443","src/mac/mach.rs":"1ae13287b6d76075473b0179b2a106bd2422c5234561770c0fedb5597c4128e9","src/mac/minidump_writer.rs":"d6f07685779c45f6b773d4163965f5dc5e0a73421937d9ec6b8e4d3320d23e85","src/mac/streams.rs":"82e1b9fefa26d98f1c0efdd98de0aed9a9ee9edf3e4b4f636212c73f8d3e464e","src/mac/streams/breakpad_info.rs":"9aafbc3f376050e39a2295e77a1b764223403ffdd47bded39efa9450a53b5a06","src/mac/streams/exception.rs":"316cf3b9ccb6b1bb3b431b4e927e4d68201f845d80e31fcaa6b80bcc30748147","src/mac/streams/memory_list.rs":"e507a1ada858ef535e3e211d91195901e9976ba0ff6cf601919d7cacb48c5e9f","src/mac/streams/misc_info.rs":"ed9fe394ded145cae62094adf3a9e454e23bfd5b6fab7871f0cf62c6a5e79017","src/mac/streams/module_list.rs":"0d735c07d162311d386aa40d5a80ebcbdc644df0dfc811d7c4b85a2fae51c5f9","src/mac/streams/system_info.rs":"4bd0d171c9d7c97afbacf6fd144d5554f0e46d47ae78f00b85331d6d1a1d24b3","src/mac/streams/thread_list.rs":"2b003e3409daebbd38ebc8a49a2c24e7a75b296d28f58a2c85114cf611174c1b","src/mac/streams/thread_names.rs":"2c8ca3a98b0c4ac9bd0373721324f32038569b70eb5b47bafe7de4cc3f76483b","src/mac/task_dumper.rs":"b22f42b11bb7e9af5976ec04cbf9f8bf4d1d70c3c7738b1072e7bd41e8d5af3c","src/mem_writer.rs":"44d594e4b8a4bedf28c61f89c34f13be42deb9a8820a1d3267dd9572d65d0c97","src/minidump_cpu.rs":"ccb3dc179699159883e539e29285f8f6ba936afb8ce8980dbcb5060a80b6618c","src/minidump_format.rs":"9d5940d71da3a543efa90279e287e0dbbe303de386a4d5aab15e8ccfdd556116","src/windows.rs":"7aae8747519b203f1889c369cb1122ff308d255e9514cf9d4d3f09257a3bb96c","src/windows/errors.rs":"9b8752122784417ed48b9c3fccc9bdabc6c4e6285cdb77c79723cba56cb0de82","src/windows/ffi.rs":"24a6f99de9f25ae7bc80f2763d8c5b97e65699682a99ec6265ebc435c3310999","src/windows/minidump_writer.rs":"1c89d43c31f59c9091e84155d7062bf85d4674c54899a4e92b4ba2bd5fcd1354","tests/common/mod.rs":"457d8c26f41d2c883c42ede5f7f2b604368581ef299f41a18b5d8c4ee7974c21","tests/linux_minidump_writer.rs":"128273f06bad3bcc316ea4cd3ba7ef1bc74f1fb349c5d38129fcfdf30ddc5037","tests/mac_minidump_writer.rs":"355e28635e9f8ccc831627e3323fe37907915047cd525f07eefd15d658cf4823","tests/ptrace_dumper.rs":"c4ec7f903cbe2181891951680efa9aaf21875b42184068436b3a17f412ece227","tests/task_dumper.rs":"3881899e4cfef0dae772d16b1a783497eebd2b58025394e0819cb03a0960d480","tests/windows_minidump_writer.rs":"138551179c4e610141d56ba99305a0fc05531c8e9924805dd071d380338f0f74"},"package":"017101620fe5d413ac2d98224ab8b1fff0d4bacaf2803c130ad4a6db3e5d3e70"} \ No newline at end of file +{"files":{"CHANGELOG.md":"dd79b025c48c70745cf60d41443191ad6ed92034efe8dd3db4b8c6cef031e4ab","Cargo.lock":"34813428631324758b699a604e0a077c56338cae5312b09f42949e8e341948fc","Cargo.toml":"84688c1ccef09106253992cb34a263e2eee168ad824fc52fe19e845d5169c169","LICENSE":"1ecdd8e8977af83c07c5f97bec87b47d27059b7ea323ca3160fbfa2314f5d99c","README.md":"71742b170ac34ceecf317d6d69456063bf5d8974453075e9cd2838785717fcdb","build.rs":"689cd32a441f5011f694a9f86bc03bc27c2a09bcb4130f47e04fe00bb069b1b5","deny.toml":"872e0c050720257cf85e660834ffe3d9e39f9fb7b3c795c0c44af3702ec2ff21","examples/synthetic.rs":"cd13bd0bba64a1d8c8c326bb1ce1818bead6904e5708418fd09edeaef1437c24","release.toml":"f554067378aec602383b96e5fa63427136533a7dd00137fd0664b279fb8fcc56","src/bin/test.rs":"dc408d74b7d142687b5d450c20ff0e9af7c508bd78af84988472e5dd4e940f29","src/dir_section.rs":"b7c83b16acefb4327b406612e1a667dffb91f86bec40f9330171dba8d10346ff","src/lib.rs":"6f393273ea6b354f412e70c9a4925fe2e646bc477591962c96a61aed9fde4e3b","src/linux.rs":"65d1249e80a3c3b6ab8c4361891b5ef35fe68f91253f6378ae03a0ad59ecd807","src/linux/android.rs":"9f2fd633de0d545b400c479a70f000cb9d04bb6e322f62098f4a7ebe7299f051","src/linux/app_memory.rs":"5f093e4ed0aecc6086366a9c09658761fdd3b0e6e9ff2111690719e56612df64","src/linux/auxv_reader.rs":"e9c75b0093c845da8dd321c6582e65678772c57658358213098aa6267f3679e1","src/linux/crash_context.rs":"069d949c7a9fc23a1e8710f7c018cacf71af2326a2dd6ca0283d492c5253107a","src/linux/crash_context/aarch64.rs":"158d02200b25a7ca029ff5132ba3b7f76a05c9976ff529a5658523aff370e4d2","src/linux/crash_context/arm.rs":"a4f41aae015937d3dccdf759df84bc657cf457d8baaf07711617d17f4b40f6f1","src/linux/crash_context/x86.rs":"d464680ee9df8a7f11dae2bb199cc4efb66dfc790a87c9b773c3a9b44b9339d8","src/linux/crash_context/x86_64.rs":"dceabbcf4d3c4ff5ad7658daa7dec3349cad9b61091385bcd868de6b11eb4957","src/linux/dso_debug.rs":"2f117049a71362797af88ce6f8aaa9d43ba4572a3fec46a1c5642c46f78a9abf","src/linux/dumper_cpu_info.rs":"76558ffc85386e416bbfc49adc550f61fb206dfbfb0b6a25f620a5fc91f32bc1","src/linux/dumper_cpu_info/arm.rs":"6fc140181f3a32504c3b66f0235136e730424be830602c87cfbeb1dfb4c1cec3","src/linux/dumper_cpu_info/x86_mips.rs":"1b7f554190c2c0f0575e36995aae5211a0fc9f29f3949ac7521a9d148566f6e9","src/linux/errors.rs":"f0bc2a400a16d322f8d0dd5c76afa61fa32cf8a86f1b4e937298f767de031cb8","src/linux/maps_reader.rs":"0831f0775336eb4123bdc92a734b8c4b1235c0d34a06fb09e363dcc83eda8b5c","src/linux/minidump_writer.rs":"048ffcebb95f899494bbeed84b79a2294375ce240f6293ad95fa5bba41187e95","src/linux/ptrace_dumper.rs":"c35a790e381d96b312bb3ffe864b4a55069da194fc4c6eeb1cf12a89d0a7ca9d","src/linux/sections.rs":"98aabd7e4b0542201783af90cafdc66bb3845585d0ed24af7476c1ea3ab40fb9","src/linux/sections/app_memory.rs":"52fdfe9622a395763fef94c5fea924935fcd86103c3eb1b0fb8d7ea61fd3e783","src/linux/sections/exception_stream.rs":"e1b73b5168506f8804479206ef0941aca5f792500cc56c5c17db55cd6b273a99","src/linux/sections/handle_data_stream.rs":"3aae030c009543142555d493f9273e3445454b18085dfdb3b44bc83d43b510dd","src/linux/sections/mappings.rs":"833f1783a4d9b761f1360ba438d6f7f032f831b8a1b15585dea1c90d7637f58a","src/linux/sections/memory_info_list_stream.rs":"bd927824e859e2fcbc85ef9d5e3d8b7be13c4918a636f70f0712070d6c65b002","src/linux/sections/memory_list_stream.rs":"f2d5b33fb4167b502dc8e74371d50b4ad66e0b48f541fe16bcbf5fb62491bf2d","src/linux/sections/systeminfo_stream.rs":"02373c97d4caeb66f4601c066d430ad2929b5584eaa0af3be1dc51ef818e5cb8","src/linux/sections/thread_list_stream.rs":"9ea966c00a878ef1a6e6781005ddf9909c18177f2c455cb250c4ac191040fc69","src/linux/sections/thread_names_stream.rs":"2a123335626e941cf0a3349f9327c3e7606af593a8370ef5f71325012107b91f","src/linux/thread_info.rs":"3588e6c9deedfd88bd024c30405172c05cea1bd37dcc64df687d6c218d2e4c5a","src/linux/thread_info/aarch64.rs":"fcbdd6b9185f00b4f42eef27076a8c9edab8afcaf22e1c005e32702be16e2264","src/linux/thread_info/arm.rs":"cf927d9f0ea48e07a874e8d6049e447c0f12a0715ed166448c3b07a410dd958a","src/linux/thread_info/mips.rs":"332d7888bb08a36d3b77023a4a0385193a07b1c6c5bf0e91aacb5d948ba8b903","src/linux/thread_info/x86.rs":"a759b2298f0831298c56e49717b4f188c213ebeb30b38be23af5bcbe6fd96369","src/mac.rs":"4671ad90c433db559ec633c880c3fe083f38a2e185ef4fc99577318526076519","src/mac/errors.rs":"696473d1187a0f003409e3ac0fc83a02cafbad8451a62bda868b08acc36e7443","src/mac/mach.rs":"f5f5b3bde9fd3ea85903b75c80ddb15931a56d5d4425f01fda9643fba8e419d3","src/mac/minidump_writer.rs":"d6f07685779c45f6b773d4163965f5dc5e0a73421937d9ec6b8e4d3320d23e85","src/mac/streams.rs":"82e1b9fefa26d98f1c0efdd98de0aed9a9ee9edf3e4b4f636212c73f8d3e464e","src/mac/streams/breakpad_info.rs":"9aafbc3f376050e39a2295e77a1b764223403ffdd47bded39efa9450a53b5a06","src/mac/streams/exception.rs":"6ad730ff0fbba4ec8a7c8576effb737138ca92e0f676eeff5d8e3c47d20a1434","src/mac/streams/memory_list.rs":"e507a1ada858ef535e3e211d91195901e9976ba0ff6cf601919d7cacb48c5e9f","src/mac/streams/misc_info.rs":"ed9fe394ded145cae62094adf3a9e454e23bfd5b6fab7871f0cf62c6a5e79017","src/mac/streams/module_list.rs":"959239425c1ea4c9766303fd10a12c82d1fed27b462f836a8a317a470ea0ace7","src/mac/streams/system_info.rs":"4bd0d171c9d7c97afbacf6fd144d5554f0e46d47ae78f00b85331d6d1a1d24b3","src/mac/streams/thread_list.rs":"2b003e3409daebbd38ebc8a49a2c24e7a75b296d28f58a2c85114cf611174c1b","src/mac/streams/thread_names.rs":"cc1464c2610e6022046b5322d9b48a72a6b5d35923d75afd7aa4b82d355c7dc4","src/mac/task_dumper.rs":"b22f42b11bb7e9af5976ec04cbf9f8bf4d1d70c3c7738b1072e7bd41e8d5af3c","src/mem_writer.rs":"44d594e4b8a4bedf28c61f89c34f13be42deb9a8820a1d3267dd9572d65d0c97","src/minidump_cpu.rs":"ccb3dc179699159883e539e29285f8f6ba936afb8ce8980dbcb5060a80b6618c","src/minidump_format.rs":"9d5940d71da3a543efa90279e287e0dbbe303de386a4d5aab15e8ccfdd556116","src/windows.rs":"7aae8747519b203f1889c369cb1122ff308d255e9514cf9d4d3f09257a3bb96c","src/windows/errors.rs":"9b8752122784417ed48b9c3fccc9bdabc6c4e6285cdb77c79723cba56cb0de82","src/windows/ffi.rs":"24a6f99de9f25ae7bc80f2763d8c5b97e65699682a99ec6265ebc435c3310999","src/windows/minidump_writer.rs":"fbbb576161f753d9572c5e8c78a85066070948917e0ee2c111e63f3fc14fd5d3","tests/common/mod.rs":"7f340f28206924af467b09f190393ff81be8f542af1b5f9d8847b2bc409bf828","tests/linux_minidump_writer.rs":"bc81920c3dc48b0026bce0a1da3994c541a712c3e36ea2cf1037887843876511","tests/mac_minidump_writer.rs":"355e28635e9f8ccc831627e3323fe37907915047cd525f07eefd15d658cf4823","tests/ptrace_dumper.rs":"5596925274589697153657a010dd77866f94852ac8db487c86b5a9ca0f5395ea","tests/task_dumper.rs":"3881899e4cfef0dae772d16b1a783497eebd2b58025394e0819cb03a0960d480","tests/windows_minidump_writer.rs":"138551179c4e610141d56ba99305a0fc05531c8e9924805dd071d380338f0f74"},"package":"e2abcd9c8a1e6e1e9d56ce3627851f39a17ea83e17c96bc510f29d7e43d78a7d"} \ No newline at end of file diff --git a/third_party/rust/minidump-writer/CHANGELOG.md b/third_party/rust/minidump-writer/CHANGELOG.md index 770d621be3..96c4584d78 100644 --- a/third_party/rust/minidump-writer/CHANGELOG.md +++ b/third_party/rust/minidump-writer/CHANGELOG.md @@ -8,6 +8,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - ReleaseDate +## [0.8.9] - 2024-04-01 +### Fixed +- [PR#110](https://github.com/rust-minidump/minidump-writer/pull/110) changed it so that `SIGCONT` is sent regardless if the process was not able to be `SIGSTOP`ed quickly enough. +- [PR#113](https://github.com/rust-minidump/minidump-writer/pull/113) fixed a segfault(!) on linux if it was compiled with rustc 1.77.0 in release mode. + +## [0.8.8] - 2024-03-21 +### Fixed +- [PR#108](https://github.com/rust-minidump/minidump-writer/pull/108) resolved [#28](https://github.com/rust-minidump/minidump-writer/issues/28) by sending a `SIGSTOP` to the process that is about to be dumped to (hopefully) increase the robustness of the dumping process by reducing the chance of errors, particularly with regard to threads. This is done as a best effort, and will perform the old behavior if the process has not stopped within a timeout (by default 100ms), which can be overriden by the user. + +## [0.8.7] - 2024-03-04 +### Changed +- [PR#106](https://github.com/rust-minidump/minidump-writer/pull/106) bumped `minidump-common`, `minidump`, `minidump-processor`, and `minidump-unwind` -> 0.21. + +## [0.8.6] - 2024-02-26 +### Changed +- [PR#104](https://github.com/rust-minidump/minidump-writer/pull/104) slightly tweaked .so version parsing in the case of more "exotic" versions such as `libdbus-1.so.3.34.2rc5`. Previously this was parsed as `3.34.25` but would cause ambiguity if there was ever an _actual_ .25 patch/age in the future. Now, the last version is parsed as 1-2 numbers, ignoring non-digit characters if the last component has them. If 2 numbers are parsed, the last number is now placed in [VS_FIXEDFILEINFO::product_version_lo](https://docs.rs/minidump-common/latest/minidump_common/format/struct.VS_FIXEDFILEINFO.html#structfield.product_version_lo) so that it is distinct from the patch/age component placed in [VS_FIXEDFILEINFO::product_version_hi](https://docs.rs/minidump-common/latest/minidump_common/format/struct.VS_FIXEDFILEINFO.html#structfield.product_version_hi). + +## [0.8.5] - 2024-02-23 +### Added +- [PR#103](https://github.com/rust-minidump/minidump-writer/pull/103) added `.so` file versions as additional metadata to minidumps, resolving [this Mozilla bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1847098). There is no true standard for .so file versions, so this is a best effort to pull what version information we can from the .so filename. The version components are `major.minor.release` similarly to semver, where `major` -> [VS_FIXEDFILEINFO::file_version_hi](https://docs.rs/minidump-common/latest/minidump_common/format/struct.VS_FIXEDFILEINFO.html#structfield.file_version_hi), `major` -> [VS_FIXEDFILEINFO::file_version_lo](https://docs.rs/minidump-common/latest/minidump_common/format/struct.VS_FIXEDFILEINFO.html#structfield.file_version_lo), and `release` -> [VS_FIXEDFILEINFO::product_version_hi](https://docs.rs/minidump-common/latest/minidump_common/format/struct.VS_FIXEDFILEINFO.html#structfield.product_version_hi) + - `libmozsandbox.so` -> `0.0.0` + - `libstdc++.so.6.0.32` -> `6.0.32` + - `libcairo-gobject.so.2.11800.0` -> `2.11800.0` + - `libm.so.6` -> `6.0.0` + - `libabsl_time_zone.so.20220623.0.0` -> `20220623.0.0` + - `libdbus-1.so.3.34.2rc5` -> `3.34.25` + +## [0.8.4] - 2024-02-15 +### Changed +- [PR#97](https://github.com/rust-minidump/minidump-writer/pull/97) bumped `goblin` -> 0.8. +- [PR#99](https://github.com/rust-minidump/minidump-writer/pull/99) bumped `minidump-common` -> 0.20, `scroll` -> 0.12, `memmap2` -> 0.9. + ## [0.8.3] - 2023-11-07 ### Added - [PR#94](https://github.com/rust-minidump/minidump-writer/pull/94) added support for writing [file information](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_handle_descriptor) for every file open in the process the dump is being performed for into the [`MINIDUMP_HANDLE_DATA_STREAM`](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_handle_data_stream) stream. @@ -103,7 +135,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release, including basic support for `x86_64-unknown-linux-gnu/musl` and `x86_64-pc-windows-msvc` -[Unreleased]: https://github.com/rust-minidump/minidump-writer/compare/0.8.3...HEAD +[Unreleased]: https://github.com/rust-minidump/minidump-writer/compare/0.8.9...HEAD +[0.8.9]: https://github.com/rust-minidump/minidump-writer/compare/0.8.8...0.8.9 +[0.8.8]: https://github.com/rust-minidump/minidump-writer/compare/0.8.7...0.8.8 +[0.8.7]: https://github.com/rust-minidump/minidump-writer/compare/0.8.6...0.8.7 +[0.8.6]: https://github.com/rust-minidump/minidump-writer/compare/0.8.5...0.8.6 +[0.8.5]: https://github.com/rust-minidump/minidump-writer/compare/0.8.4...0.8.5 +[0.8.4]: https://github.com/rust-minidump/minidump-writer/compare/0.8.3...0.8.4 [0.8.3]: https://github.com/rust-minidump/minidump-writer/compare/0.8.2...0.8.3 [0.8.2]: https://github.com/rust-minidump/minidump-writer/compare/0.8.1...0.8.2 [0.8.1]: https://github.com/rust-minidump/minidump-writer/compare/0.8.0...0.8.1 diff --git a/third_party/rust/minidump-writer/Cargo.lock b/third_party/rust/minidump-writer/Cargo.lock index 514186142d..0b6c79825c 100644 --- a/third_party/rust/minidump-writer/Cargo.lock +++ b/third_party/rust/minidump-writer/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "fallible-iterator 0.3.0", + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -10,9 +20,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -21,18 +31,33 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arrayvec" @@ -40,15 +65,29 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-compression" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] @@ -57,6 +96,27 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "binary-merge" version = "0.1.2" @@ -71,21 +131,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - -[[package]] -name = "bitvec" -version = "1.0.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "block-buffer" @@ -98,9 +146,9 @@ dependencies = [ [[package]] name = "breakpad-symbols" -version = "0.19.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b002797414ffc34425bdf5b21a9e50d102013292625749eeba0a59923176ab05" +checksum = "14722511e9c032b38689b0e952a633826850873adb10de56ec775b217a519366" dependencies = [ "async-trait", "cachemap2", @@ -114,6 +162,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "brownstone" version = "3.0.0" @@ -131,14 +200,26 @@ checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", - "regex-automata", + "regex-automata 0.1.10", ] +[[package]] +name = "bumpalo" +version = "3.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" + [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cab" @@ -148,21 +229,33 @@ checksum = "ae6b4de23c7d39c0631fd3cc952d87951c86c75a13812d7247cb7a896e7b3551" dependencies = [ "byteorder", "flate2", - "lzxd", + "lzxd 0.1.4", + "time", +] + +[[package]] +name = "cab" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8636d870cf15918e416b7904f0db1cbd06de0ffe392986c3b16662552df00c" +dependencies = [ + "byteorder", + "flate2", + "lzxd 0.2.5", "time", ] [[package]] name = "cachemap2" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bba2f68a9fefca870fed897de7c655f9d5c1eaf1cd9517db96c9a3861f648b" +checksum = "68ccbd3153aa153b2f5eff557537ffce81e4dd6c50ae0eddc41dc8d0c388436f" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" [[package]] name = "cfg-if" @@ -170,6 +263,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "circular" version = "0.3.0" @@ -178,30 +277,46 @@ checksum = "b0fc239e0f6cb375d2402d48afb92f76f5404fd1df208a41930ec81eda078bea" [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys 0.45.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpp_demangle" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6" +checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" dependencies = [ "cfg-if", ] [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -228,26 +343,25 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" dependencies = [ - "cfg-if", "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", @@ -257,56 +371,46 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -318,6 +422,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "current_platform" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74858bcfe44b22016cb49337d7b6f04618c58e5dbfdef61b06b8c434324a0bc" + [[package]] name = "debugid" version = "0.8.0" @@ -328,6 +438,26 @@ dependencies = [ "uuid", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.10.7" @@ -344,7 +474,16 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ - "dirs-sys", + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", ] [[package]] @@ -358,6 +497,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dmsort" version = "1.0.2" @@ -366,17 +517,17 @@ checksum = "f0bc8fbe9441c17c9f46f75dfe27fa1ddb6c68a461ccaed0481419219d4f10d3" [[package]] name = "dump_syms" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0640a83419dce0966981ccf5f41359cf858ce786314e55af12bff22e782585d5" +checksum = "f33fc75a82f02047c9f4cebd1c6f0e12872aea9c217d841a5b57dd42fdf82990" dependencies = [ "anyhow", - "bitflags 1.3.2", - "cab", + "bitflags 2.4.2", + "cab 0.4.1", "crossbeam", - "dirs", - "goblin 0.6.1", - "hashbrown", + "dirs 4.0.0", + "goblin 0.7.1", + "hashbrown 0.12.3", "log", "lzma-rs", "num_cpus", @@ -401,9 +552,9 @@ dependencies = [ [[package]] name = "elsa" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e0aca8dce8856e420195bd13b6a64de3334235ccc9214e824b86b12bf26283" +checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" dependencies = [ "stable_deref_trait", ] @@ -416,32 +567,27 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] -name = "errno" -version = "0.3.1" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -450,42 +596,75 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] -name = "funty" -version = "2.0.0" +name = "framehop" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bb3ea0d42943711eafa7a6182b47a21d51247d2ecad6641ff61d9213d099ea" +dependencies = [ + "arrayvec", + "fallible-iterator 0.3.0", + "gimli", + "macho-unwind-info", + "object", + "pe-unwind-info", + "thiserror", +] + +[[package]] +name = "fs4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" +dependencies = [ + "async-trait", + "rustix", + "tokio", + "windows-sys 0.48.0", +] [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -498,9 +677,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -508,15 +687,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -525,38 +704,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -582,9 +761,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -593,34 +772,54 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ - "fallible-iterator", + "fallible-iterator 0.3.0", + "indexmap", "stable_deref_trait", ] [[package]] name = "goblin" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134" dependencies = [ "log", "plain", - "scroll", + "scroll 0.11.0", ] [[package]] name = "goblin" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134" +checksum = "bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887" dependencies = [ "log", "plain", - "scroll", + "scroll 0.12.0", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] @@ -633,14 +832,17 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -648,11 +850,83 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -666,12 +940,12 @@ checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" [[package]] name = "indexmap" -version = "1.9.3" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ - "autocfg", - "hashbrown", + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -683,11 +957,17 @@ dependencies = [ "smallvec", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "joinery" @@ -695,6 +975,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5" +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -709,31 +998,73 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "linux-raw-sys" -version = "0.4.7" +name = "libredox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] [[package]] -name = "lock_api" -version = "0.4.10" +name = "linear-map" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ +checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" + +[[package]] +name = "linux-perf-data" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e5edc4ed86c4995d6fe86ed4153727d27b4f8be7167d14b05d74e41c16b087" +dependencies = [ + "byteorder", + "linear-map", + "linux-perf-event-reader", + "memchr", + "thiserror", +] + +[[package]] +name = "linux-perf-event-reader" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e93938b52460a3e539c9465592c5f645c7ca3847da1d7dbee20e3564d55c5a90" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "memchr", + "thiserror", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.19" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lzma-rs" @@ -751,15 +1082,32 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784462f20dddd9dfdb45de963fa4ad4a288cb10a7889ac5d2c34fb6481c6b213" +[[package]] +name = "lzxd" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de7336a183103429ad66d11d56d8bdc9c4a2916f6b85a8f11e5b127bde12001" + [[package]] name = "mach2" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ "libc", ] +[[package]] +name = "macho-unwind-info" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b6086acc74bc23f56b60e88bb082d505e23849d68d6c0f12bb6a7ad5c60e03e" +dependencies = [ + "thiserror", + "zerocopy", + "zerocopy-derive", +] + [[package]] name = "maybe-owned" version = "0.3.4" @@ -768,24 +1116,15 @@ checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" [[package]] name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.5.10" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memmap2" -version = "0.8.0" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] @@ -799,19 +1138,26 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minidump" -version = "0.19.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c671544a05d0e8daa3018c8fb6687c11935c4ae8f122de8f2386c2896b4e9b8" +checksum = "64cb8353fdcd59c0caaf7525cb83b29ee02e6eac4c85d5a7944a9773d0f33f2e" dependencies = [ "debugid", "encoding_rs", - "memmap2 0.8.0", + "memmap2", "minidump-common", "num-traits", + "procfs-core", "range-map", - "scroll", + "scroll 0.12.0", "thiserror", "time", "tracing", @@ -820,34 +1166,33 @@ dependencies = [ [[package]] name = "minidump-common" -version = "0.19.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dbc11dfb55b3b7b5684fb16d98e0fc9d1e93a64d6b00bf383eabfc4541aaac2" +checksum = "1bb6eaf88cc770fa58e6ae721cf2e40c2ca6a4c942ae8c7aa324d680bd3c6717" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "debugid", "num-derive", "num-traits", "range-map", - "scroll", + "scroll 0.12.0", "smart-default", ] [[package]] name = "minidump-processor" -version = "0.19.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b49bde7c0ae9a7142c540c27c7fc29db2288fd9614f11a9ce57badeb74af43" +checksum = "62bc8e39bb830c2e92ff0f3af8166f3fbc3ad2dc0c843c66de3b918b71190a6c" dependencies = [ "async-trait", "breakpad-symbols", "debugid", "futures-util", - "memmap2 0.8.0", "minidump", "minidump-common", "minidump-unwind", - "scroll", + "scroll 0.12.0", "serde", "serde_json", "thiserror", @@ -856,39 +1201,40 @@ dependencies = [ [[package]] name = "minidump-unwind" -version = "0.19.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63aef4cd2e018881680b152296ae28e674242823faa1767b417b6669a1896cdc" +checksum = "2096876dbb3d5a0bbc5c42a913d44e935cb7f6139dcf9eda043ae1ce702ab529" dependencies = [ "async-trait", "breakpad-symbols", "cachemap2", + "framehop", "futures-util", - "memmap2 0.8.0", + "memmap2", "minidump", "minidump-common", - "scroll", - "symbolic-cfi", - "symbolic-common", - "symbolic-debuginfo", - "symbolic-demangle", + "object", + "scroll 0.12.0", "tracing", + "wholesym", ] [[package]] name = "minidump-writer" -version = "0.8.3" +version = "0.8.9" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "byteorder", "cfg-if", "crash-context", + "current_platform", "dump_syms", "futures", - "goblin 0.7.1", + "goblin 0.8.0", "libc", + "log", "mach2", - "memmap2 0.8.0", + "memmap2", "memoffset", "minidump", "minidump-common", @@ -896,7 +1242,7 @@ dependencies = [ "minidump-unwind", "nix", "procfs-core", - "scroll", + "scroll 0.12.0", "similar-asserts", "tempfile", "thiserror", @@ -911,13 +1257,24 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "msvc-demangler" version = "0.9.0" @@ -927,6 +1284,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "msvc-demangler" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2588c982e3a7fbfbd73b21f824cacc43fc6392a1103c709ffd6001c0bf33fdb3" +dependencies = [ + "bitflags 2.4.2", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -935,12 +1301,13 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "cfg-if", + "cfg_aliases", "libc", ] @@ -967,41 +1334,64 @@ dependencies = [ "nom", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "flate2", + "memchr", + "ruzstd", +] + [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "parking_lot" @@ -1015,15 +1405,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall", "smallvec", - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -1032,8 +1422,8 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82040a392923abe6279c00ab4aff62d5250d1c8555dc780e4b02783a7aa74863" dependencies = [ - "fallible-iterator", - "scroll", + "fallible-iterator 0.2.0", + "scroll 0.11.0", "uuid", ] @@ -1047,15 +1437,53 @@ dependencies = [ "elsa", "maybe-owned", "pdb", - "range-collections", + "range-collections 0.2.4", + "thiserror", +] + +[[package]] +name = "pdb-addr2line" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb51ef7ed9998e108891711812822831daac0b17d67768c3bdc69aa909366123" +dependencies = [ + "bitflags 2.4.2", + "elsa", + "maybe-owned", + "pdb2", + "range-collections 0.4.5", + "thiserror", +] + +[[package]] +name = "pdb2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e30e131bcab0d41a2e471cf777ea9b1402f2a0764bcf1780251eab1b0d175d" +dependencies = [ + "fallible-iterator 0.2.0", + "scroll 0.11.0", + "uuid", +] + +[[package]] +name = "pe-unwind-info" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ec3b43050c38ffb9de87e17d874e9956e3a9131b343c9b7b7002597727c3891" +dependencies = [ + "arrayvec", + "bitflags 2.4.2", "thiserror", + "zerocopy", + "zerocopy-derive", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf_shared" @@ -1068,9 +1496,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1084,6 +1512,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1092,9 +1526,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -1105,33 +1539,39 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "hex", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] -name = "radium" -version = "0.7.0" +name = "range-collections" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +checksum = "61fdfd79629e2b44a1d34b4d227957174cb858e6b86ee45fad114edbcfc903ab" +dependencies = [ + "binary-merge", + "inplace-vec-builder", + "smallvec", +] [[package]] name = "range-collections" -version = "0.2.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fdfd79629e2b44a1d34b4d227957174cb858e6b86ee45fad114edbcfc903ab" +checksum = "ca9edd21e2db51000ac63eccddabba622f826e631a60be7bade9bd6a76b69537" dependencies = [ "binary-merge", "inplace-vec-builder", + "ref-cast", "smallvec", ] @@ -1145,42 +1585,60 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "rangemap" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] +[[package]] +name = "ref-cast" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "regex" -version = "1.8.4" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", + "regex-automata 0.4.6", "regex-syntax", ] @@ -1190,11 +1648,81 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +dependencies = [ + "async-compression", + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] [[package]] name = "rustc-demangle" @@ -1204,28 +1732,102 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.14" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "ruzstd" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +dependencies = [ + "byteorder", + "derive_more", + "twox-hash", ] [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "samply-symbols" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "72b02bfab817ed66f35a0afa07216a02325b82faf777e20fdcd0dadd5ebfd8eb" +dependencies = [ + "addr2line", + "bitflags 2.4.2", + "cpp_demangle", + "debugid", + "elsa", + "flate2", + "gimli", + "linux-perf-data", + "lzma-rs", + "macho-unwind-info", + "memchr", + "msvc-demangler 0.10.0", + "nom", + "object", + "pdb-addr2line 0.11.0", + "rangemap", + "rustc-demangle", + "srcsrv", + "thiserror", + "uuid", + "yoke", + "yoke-derive", + "zerocopy", + "zerocopy-derive", +] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scroll" @@ -1233,56 +1835,104 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" dependencies = [ - "scroll_derive", + "scroll_derive 0.11.1", +] + +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive 0.12.0", ] [[package]] name = "scroll_derive" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.52", ] +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + [[package]] name = "serde" -version = "1.0.164" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1291,9 +1941,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" dependencies = [ "bstr", "unicode-segmentation", @@ -1311,24 +1961,24 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smart-default" @@ -1338,7 +1988,33 @@ checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", +] + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "srcsrv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022437a70e522e49b1952cb1d923589d629cb4aee97eb56d65ce938c04e8ac70" +dependencies = [ + "memchr", + "thiserror", ] [[package]] @@ -1347,6 +2023,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "string_cache" version = "0.8.7" @@ -1363,9 +2045,9 @@ dependencies = [ [[package]] name = "symbolic" -version = "12.1.5" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d311bfa722c01294e838091c455ed4e63c96ea7b8fb65b7fd7acdc72a4b0309" +checksum = "05ec4f53c56d7ee8809c2322925d362e193bcc7bbe7e777a3304b34ea7e85a36" dependencies = [ "symbolic-cfi", "symbolic-common", @@ -1375,9 +2057,9 @@ dependencies = [ [[package]] name = "symbolic-cfi" -version = "12.1.5" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d568f889388e2d96b4b3c258a9e36ebe4ad95bd941ee245719c30cbc2c1ad51" +checksum = "0a3724d1d1a3e531038da32de84725fd93d0afeeee51de4d3871cf657f283ad9" dependencies = [ "symbolic-common", "symbolic-debuginfo", @@ -1386,39 +2068,38 @@ dependencies = [ [[package]] name = "symbolic-common" -version = "12.1.5" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb6682826c7186b16c5c0ed2a68f419609f8af62f070c688871caae4911432d" +checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" dependencies = [ "debugid", - "memmap2 0.5.10", + "memmap2", "stable_deref_trait", "uuid", ] [[package]] name = "symbolic-debuginfo" -version = "12.1.5" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222363f4ca5fb00cdd4915afba4a6aa18549d3438b27c048db2c41f0ea7a1e58" +checksum = "eb52777be67777947c5a159f1b6e8bfe4473d91fad7e5d4aff85ee4d3963cc04" dependencies = [ - "bitvec", "debugid", "dmsort", "elementtree", "elsa", - "fallible-iterator", + "fallible-iterator 0.3.0", "flate2", "gimli", - "goblin 0.6.1", + "goblin 0.7.1", "lazy_static", "nom", "nom-supreme", "once_cell", "parking_lot", - "pdb-addr2line", + "pdb-addr2line 0.10.4", "regex", - "scroll", + "scroll 0.11.0", "serde", "serde_json", "smallvec", @@ -1431,25 +2112,26 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.1.5" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7597986728aebeae5b865266b6158b134a4d61f078049552b5c897bb0a61985" +checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" dependencies = [ "cc", "cpp_demangle", - "msvc-demangler", + "msvc-demangler 0.9.0", "rustc-demangle", "symbolic-common", ] [[package]] name = "symbolic-ppdb" -version = "12.1.5" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e3c9b6cc654de90c05d841af02f3dd37415278538fa23534cbcb58a1a74ae8b" +checksum = "dace84623ccc926886fc880c36e2a81af4b17f8276abc4d77dc947ca3c6c8f8c" dependencies = [ "flate2", "indexmap", + "serde", "serde_json", "symbolic-common", "thiserror", @@ -1457,6 +2139,21 @@ dependencies = [ "watto", ] +[[package]] +name = "symsrv" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6a9f40855a5ba9f9008b2c12eef13a67d2655459ba9f74970aea341e0fb5e9" +dependencies = [ + "cab 0.5.0", + "dirs 5.0.1", + "fs4", + "futures-util", + "reqwest", + "thiserror", + "tokio", +] + [[package]] name = "syn" version = "1.0.109" @@ -1470,9 +2167,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -1480,51 +2177,85 @@ dependencies = [ ] [[package]] -name = "tap" -version = "1.0.1" +name = "sync_wrapper" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] name = "tempfile" -version = "3.8.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] name = "time" -version = "0.3.22" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -1532,16 +2263,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -1560,13 +2292,57 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -1575,62 +2351,84 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1639,9 +2437,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" [[package]] name = "version_check" @@ -1649,20 +2447,108 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasmparser" -version = "0.102.0" +version = "0.118.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b" +checksum = "77f1154f1ab868e2a01d9834a805faca7bf8b50d041b4ca714d005d0dab1c50c" dependencies = [ "indexmap", - "url", + "semver", ] [[package]] @@ -1675,6 +2561,44 @@ dependencies = [ "thiserror", ] +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "wholesym" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9050809aead9c09ea73d2719d7639b55ea2803287b008dc1bb24b647661afa7c" +dependencies = [ + "bytes", + "core-foundation", + "core-foundation-sys", + "debugid", + "futures-util", + "libc", + "memmap2", + "reqwest", + "samply-symbols", + "symsrv", + "tokio", + "uuid", + "yoke", + "yoke-derive", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1699,145 +2623,196 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.42.2", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.52.4", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] -name = "wyz" -version = "0.5.1" +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "yoke" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4" +dependencies = [ + "serde", + "stable_deref_trait", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ - "tap", + "byteorder", + "zerocopy-derive", ] +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "zerofrom" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" + [[package]] name = "zip" version = "0.6.6" diff --git a/third_party/rust/minidump-writer/Cargo.toml b/third_party/rust/minidump-writer/Cargo.toml index 6b33b5eebf..d137677165 100644 --- a/third_party/rust/minidump-writer/Cargo.toml +++ b/third_party/rust/minidump-writer/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "minidump-writer" -version = "0.8.3" +version = "0.8.9" authors = ["Martin Sirringhaus"] description = "Rust rewrite of Breakpad's minidump_writer" homepage = "https://github.com/rust-minidump/minidump-writer" @@ -32,14 +32,17 @@ version = "1.0" [dependencies.crash-context] version = "0.6" +[dependencies.log] +version = "0.4" + [dependencies.memoffset] version = "0.9" [dependencies.minidump-common] -version = "0.19.1" +version = "0.21" [dependencies.scroll] -version = "0.11" +version = "0.12" [dependencies.tempfile] version = "3.8" @@ -47,22 +50,26 @@ version = "3.8" [dependencies.thiserror] version = "1.0" +[dev-dependencies.current_platform] +version = "0.2" + [dev-dependencies.futures] version = "0.3" features = ["executor"] [dev-dependencies.memmap2] -version = "0.8" +version = "0.9" [dev-dependencies.minidump] -version = "0.19" +version = "0.21" [target."cfg(any(target_os = \"linux\", target_os = \"android\"))".dependencies.nix] -version = "0.27" +version = "0.28" features = [ "mman", "process", "ptrace", + "signal", "user", ] default-features = false @@ -79,11 +86,11 @@ version = "2.2" default-features = false [target."cfg(target_os = \"macos\")".dev-dependencies.minidump-processor] -version = "0.19" +version = "0.21" default-features = false [target."cfg(target_os = \"macos\")".dev-dependencies.minidump-unwind] -version = "0.19" +version = "0.21" features = ["debuginfo"] [target."cfg(target_os = \"macos\")".dev-dependencies.similar-asserts] @@ -96,10 +103,10 @@ version = "1.4" version = "2.4" [target."cfg(unix)".dependencies.goblin] -version = "0.7.1" +version = "0.8" [target."cfg(unix)".dependencies.libc] version = "0.2" [target."cfg(unix)".dependencies.memmap2] -version = "0.8" +version = "0.9" diff --git a/third_party/rust/minidump-writer/README.md b/third_party/rust/minidump-writer/README.md index 20962c913f..9c9ed9d789 100644 --- a/third_party/rust/minidump-writer/README.md +++ b/third_party/rust/minidump-writer/README.md @@ -22,31 +22,7 @@ For more information on how to dump an external process you can check out the do #### Local process -```rust -fn write_minidump() { - // At a minimum, the crashdump writer needs to know the process and thread that you want to dump - let mut writer = minidump_writer::minidump_writer::MinidumpWriter::new( - std::process::id() as _, - // This gets the current thread, but you could get the id for any thread - // in the current process - unsafe { libc::syscall(libc::SYS_gettid) } as i32 - ); - - // If provided with a full [crash_context::CrashContext](https://docs.rs/crash-context/latest/crash_context/struct.CrashContext.html), - // the crash will contain more info on the crash cause, such as the signal - //writer.set_crash_context(minidump_writer::crash_context::CrashContext { inner: crash_context }); - - // Here we could add more context or modify how the minidump is written, eg - // Add application specific memory blocks to the minidump - //writer.set_app_memory() - // Sanitize stack memory before it is written to the minidump by replacing - // non-pointer values with a sentinel value - //writer.sanitize_stack(); - - let mut minidump_file = std::fs::File::create("example_dump.mdmp").expect("failed to create file"); - writer.dump(&mut minidump_file).expect("failed to write minidump"); -} -``` +The Linux implementation uses ptrace to gather information about the process when writing a minidump for it, which cannot be done from the process itself. It's possible to clone the process and dump the current process from that clone, but that's out of scope for an example. #### External process diff --git a/third_party/rust/minidump-writer/deny.toml b/third_party/rust/minidump-writer/deny.toml index 3cadd53b23..ed28113432 100644 --- a/third_party/rust/minidump-writer/deny.toml +++ b/third_party/rust/minidump-writer/deny.toml @@ -13,10 +13,10 @@ ignore = [] [bans] multiple-versions = "deny" -skip = [ - # scroll still depends on 1.0 - { name = "syn", version = "=1.0.109" }, +deny = [ + #{ crate = "chrono", use-instead = "time", reason = "unneccessary dependency" }, ] +skip-tree = [] [licenses] allow = ["MIT", "Apache-2.0"] diff --git a/third_party/rust/minidump-writer/src/bin/test.rs b/third_party/rust/minidump-writer/src/bin/test.rs index 85b6fa6a93..df39b28655 100644 --- a/third_party/rust/minidump-writer/src/bin/test.rs +++ b/third_party/rust/minidump-writer/src/bin/test.rs @@ -8,14 +8,14 @@ pub type Result = std::result::Result; mod linux { use super::*; use minidump_writer::{ + minidump_writer::STOP_TIMEOUT, ptrace_dumper::{PtraceDumper, AT_SYSINFO_EHDR}, LINUX_GATE_LIBRARY_NAME, }; use nix::{ - sys::mman::{mmap, MapFlags, ProtFlags}, + sys::mman::{mmap_anonymous, MapFlags, ProtFlags}, unistd::getppid, }; - use std::os::fd::BorrowedFd; macro_rules! test { ($x:expr, $errmsg:expr) => { @@ -29,13 +29,13 @@ mod linux { fn test_setup() -> Result<()> { let ppid = getppid(); - PtraceDumper::new(ppid.as_raw())?; + PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT)?; Ok(()) } fn test_thread_list() -> Result<()> { let ppid = getppid(); - let dumper = PtraceDumper::new(ppid.as_raw())?; + let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT)?; test!(!dumper.threads.is_empty(), "No threads")?; test!( dumper @@ -51,7 +51,7 @@ mod linux { fn test_copy_from_process(stack_var: usize, heap_var: usize) -> Result<()> { let ppid = getppid().as_raw(); - let mut dumper = PtraceDumper::new(ppid)?; + let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT)?; dumper.suspend_threads()?; let stack_res = PtraceDumper::copy_from_process(ppid, stack_var as *mut libc::c_void, 1)?; @@ -73,7 +73,7 @@ mod linux { fn test_find_mappings(addr1: usize, addr2: usize) -> Result<()> { let ppid = getppid(); - let dumper = PtraceDumper::new(ppid.as_raw())?; + let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT)?; dumper .find_mapping(addr1) .ok_or("No mapping for addr1 found")?; @@ -90,7 +90,7 @@ mod linux { let ppid = getppid().as_raw(); let exe_link = format!("/proc/{}/exe", ppid); let exe_name = std::fs::read_link(exe_link)?.into_os_string(); - let mut dumper = PtraceDumper::new(getppid().as_raw())?; + let mut dumper = PtraceDumper::new(getppid().as_raw(), STOP_TIMEOUT)?; let mut found_exe = None; for (idx, mapping) in dumper.mappings.iter().enumerate() { if mapping.name.as_ref().map(|x| x.into()).as_ref() == Some(&exe_name) { @@ -107,7 +107,7 @@ mod linux { fn test_merged_mappings(path: String, mapped_mem: usize, mem_size: usize) -> Result<()> { // Now check that PtraceDumper interpreted the mappings properly. - let dumper = PtraceDumper::new(getppid().as_raw())?; + let dumper = PtraceDumper::new(getppid().as_raw(), STOP_TIMEOUT)?; let mut mapping_count = 0; for map in &dumper.mappings { if map @@ -129,7 +129,7 @@ mod linux { fn test_linux_gate_mapping_id() -> Result<()> { let ppid = getppid().as_raw(); - let mut dumper = PtraceDumper::new(ppid)?; + let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT)?; let mut found_linux_gate = false; for mut mapping in dumper.mappings.clone() { if mapping.name == Some(LINUX_GATE_LIBRARY_NAME.into()) { @@ -148,7 +148,7 @@ mod linux { fn test_mappings_include_linux_gate() -> Result<()> { let ppid = getppid().as_raw(); - let dumper = PtraceDumper::new(ppid)?; + let dumper = PtraceDumper::new(ppid, STOP_TIMEOUT)?; let linux_gate_loc = dumper.auxv[&AT_SYSINFO_EHDR]; test!(linux_gate_loc != 0, "linux_gate_loc == 0")?; let mut found_linux_gate = false; @@ -215,18 +215,16 @@ mod linux { let memory_size = std::num::NonZeroUsize::new(page_size.unwrap() as usize).unwrap(); // Get some memory to be mapped by the child-process let mapped_mem = unsafe { - mmap::( + mmap_anonymous( None, memory_size, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_PRIVATE | MapFlags::MAP_ANON, - None, - 0, ) .unwrap() }; - println!("{} {}", mapped_mem as usize, memory_size); + println!("{} {}", mapped_mem.as_ptr() as usize, memory_size); loop { std::thread::park(); } diff --git a/third_party/rust/minidump-writer/src/linux/dso_debug.rs b/third_party/rust/minidump-writer/src/linux/dso_debug.rs index b9f466261f..01c0a73505 100644 --- a/third_party/rust/minidump-writer/src/linux/dso_debug.rs +++ b/third_party/rust/minidump-writer/src/linux/dso_debug.rs @@ -161,11 +161,6 @@ pub fn write_dso_debug_stream( assert!(head.is_empty(), "Data was not aligned"); let dyn_struct = &body[0]; - // #ifdef __mips__ - // const int32_t debug_tag = DT_MIPS_RLD_MAP; - // #else - // const int32_t debug_tag = DT_DEBUG; - // #endif let debug_tag = goblin::elf::dynamic::DT_DEBUG; if dyn_struct.d_tag == debug_tag { r_debug = dyn_struct.d_val as usize; diff --git a/third_party/rust/minidump-writer/src/linux/maps_reader.rs b/third_party/rust/minidump-writer/src/linux/maps_reader.rs index 4d0d3b5aaa..b5b7fb23e6 100644 --- a/third_party/rust/minidump-writer/src/linux/maps_reader.rs +++ b/third_party/rust/minidump-writer/src/linux/maps_reader.rs @@ -289,10 +289,9 @@ impl MappingInfo { true } - fn elf_file_so_name(&self) -> Result { - // Find the shared object name (SONAME) by examining the ELF information - // for |mapping|. If the SONAME is found copy it into the passed buffer - // |soname| and return true. The size of the buffer is |soname_size|. + /// Find the shared object name (SONAME) by examining the ELF information + /// for the mapping. + fn so_name(&self) -> Result { let mapped_file = MappingInfo::get_mmap(&self.name, self.offset)?; let elf_obj = elf::Elf::parse(&mapped_file)?; @@ -303,7 +302,14 @@ impl MappingInfo { Ok(soname.to_string()) } - pub fn get_mapping_effective_path_and_name(&self) -> Result<(PathBuf, String)> { + #[inline] + fn so_version(&self) -> Option { + SoVersion::parse(self.name.as_deref()?) + } + + pub fn get_mapping_effective_path_name_and_version( + &self, + ) -> Result<(PathBuf, String, Option)> { let mut file_path = PathBuf::from(self.name.clone().unwrap_or_default()); // Tools such as minidump_stackwalk use the name of the module to look up @@ -312,16 +318,15 @@ impl MappingInfo { // filesystem name of the module. // Just use the filesystem name if no SONAME is present. - let file_name = if let Ok(name) = self.elf_file_so_name() { - name - } else { + let Ok(file_name) = self.so_name() else { // file_path := /path/to/libname.so // file_name := libname.so let file_name = file_path .file_name() .map(|s| s.to_string_lossy().into_owned()) .unwrap_or_default(); - return Ok((file_path, file_name)); + + return Ok((file_path, file_name, self.so_version())); }; if self.is_executable() && self.offset != 0 { @@ -337,7 +342,7 @@ impl MappingInfo { file_path.set_file_name(&file_name); } - Ok((file_path, file_name)) + Ok((file_path, file_name, self.so_version())) } pub fn is_contained_in(&self, user_mapping_list: &MappingList) -> bool { @@ -382,6 +387,97 @@ impl MappingInfo { } } +/// Version metadata retrieved from an .so filename +/// +/// There is no standard for .so version numbers so this implementation just +/// does a best effort to pull as much data as it can based on real .so schemes +/// seen +/// +/// That being said, the [libtool](https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html) +/// versioning scheme is fairly common +#[cfg_attr(test, derive(Debug))] +pub struct SoVersion { + /// Might be non-zero if there is at least one non-zero numeric component after .so. + /// + /// Equivalent to `current` in libtool versions + pub major: u32, + /// The numeric component after the major version, if any + /// + /// Equivalent to `revision` in libtool versions + pub minor: u32, + /// The numeric component after the minor version, if any + /// + /// Equivalent to `age` in libtool versions + pub patch: u32, + /// The patch component may contain additional non-numeric metadata similar + /// to a semver prelease, this is any numeric data that suffixes that prerelease + /// string + pub prerelease: u32, +} + +impl SoVersion { + /// Attempts to retrieve the .so version of the elf path via its filename + fn parse(so_path: &OsStr) -> Option { + let filename = std::path::Path::new(so_path).file_name()?; + + // Avoid an allocation unless the string contains non-utf8 + let filename = filename.to_string_lossy(); + + let (_, version) = filename.split_once(".so.")?; + + let mut sov = Self { + major: 0, + minor: 0, + patch: 0, + prerelease: 0, + }; + + let comps = [ + &mut sov.major, + &mut sov.minor, + &mut sov.patch, + &mut sov.prerelease, + ]; + + for (i, comp) in version.split('.').enumerate() { + if i <= 1 { + *comps[i] = comp.parse().unwrap_or_default(); + } else if i >= 4 { + break; + } else { + // In some cases the release/patch version is alphanumeric (eg. '2rc5'), + // so try to parse either a single or two numbers + if let Some(pend) = comp.find(|c: char| !c.is_ascii_digit()) { + if let Ok(patch) = comp[..pend].parse() { + *comps[i] = patch; + } + + if i >= comps.len() - 1 { + break; + } + if let Some(pre) = comp.rfind(|c: char| !c.is_ascii_digit()) { + if let Ok(pre) = comp[pre + 1..].parse() { + *comps[i + 1] = pre; + break; + } + } + } else { + *comps[i] = comp.parse().unwrap_or_default(); + } + } + } + + Some(sov) + } +} + +#[cfg(test)] +impl PartialEq<(u32, u32, u32, u32)> for SoVersion { + fn eq(&self, o: &(u32, u32, u32, u32)) -> bool { + self.major == o.0 && self.minor == o.1 && self.patch == o.2 && self.prerelease == o.3 + } +} + #[cfg(test)] #[cfg(target_pointer_width = "64")] // All addresses are 64 bit and I'm currently too lazy to adjust it to work for both mod tests { @@ -628,13 +724,40 @@ a4840000-a4873000 rw-p 09021000 08:12 393449 /data/app/org.mozilla.firefox-1 ); assert_eq!(mappings.len(), 1); - let (file_path, file_name) = mappings[0] - .get_mapping_effective_path_and_name() + let (file_path, file_name, _version) = mappings[0] + .get_mapping_effective_path_name_and_version() .expect("Couldn't get effective name for mapping"); assert_eq!(file_name, "libmozgtk.so"); assert_eq!(file_path, PathBuf::from("/home/martin/Documents/mozilla/devel/mozilla-central/obj/widget/gtk/mozgtk/gtk3/libmozgtk.so")); } + #[test] + fn test_elf_file_so_version() { + #[rustfmt::skip] + let test_cases = [ + ("/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.32", (6, 0, 32, 0)), + ("/usr/lib/x86_64-linux-gnu/libcairo-gobject.so.2.11800.0", (2, 11800, 0, 0)), + ("/usr/lib/x86_64-linux-gnu/libm.so.6", (6, 0, 0, 0)), + ("/usr/lib/x86_64-linux-gnu/libpthread.so.0", (0, 0, 0, 0)), + ("/usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.7800.0", (0, 7800, 0, 0)), + ("/usr/lib/x86_64-linux-gnu/libabsl_time_zone.so.20220623.0.0", (20220623, 0, 0, 0)), + ("/usr/lib/x86_64-linux-gnu/libdbus-1.so.3.34.2rc5", (3, 34, 2, 5)), + ("/usr/lib/x86_64-linux-gnu/libdbus-1.so.3.34.2rc", (3, 34, 2, 0)), + ("/usr/lib/x86_64-linux-gnu/libdbus-1.so.3.34.rc5", (3, 34, 0, 5)), + ("/usr/lib/x86_64-linux-gnu/libtoto.so.AAA", (0, 0, 0, 0)), + ("/usr/lib/x86_64-linux-gnu/libsemver-1.so.1.2.alpha.1", (1, 2, 0, 1)), + ("/usr/lib/x86_64-linux-gnu/libboop.so.1.2.3.4.5", (1, 2, 3, 4)), + ("/usr/lib/x86_64-linux-gnu/libboop.so.1.2.3pre4.5", (1, 2, 3, 4)), + ]; + + assert!(SoVersion::parse(OsStr::new("/home/alex/bin/firefox/libmozsandbox.so")).is_none()); + + for (path, expected) in test_cases { + let actual = SoVersion::parse(OsStr::new(path)).unwrap(); + assert_eq!(actual, expected); + } + } + #[test] fn test_whitespaces_in_name() { let mappings = get_mappings_for( diff --git a/third_party/rust/minidump-writer/src/linux/minidump_writer.rs b/third_party/rust/minidump-writer/src/linux/minidump_writer.rs index da395b53f5..c83308f576 100644 --- a/third_party/rust/minidump-writer/src/linux/minidump_writer.rs +++ b/third_party/rust/minidump-writer/src/linux/minidump_writer.rs @@ -13,7 +13,10 @@ use crate::{ mem_writer::{Buffer, MemoryArrayWriter, MemoryWriter, MemoryWriterError}, minidump_format::*, }; -use std::io::{Seek, Write}; +use std::{ + io::{Seek, Write}, + time::Duration, +}; pub enum CrashingThreadContext { None, @@ -21,6 +24,10 @@ pub enum CrashingThreadContext { CrashContextPlusAddress((MDLocationDescriptor, usize)), } +/// The default timeout after a `SIGSTOP` after which minidump writing proceeds +/// regardless of the process state +pub const STOP_TIMEOUT: Duration = Duration::from_millis(100); + pub struct MinidumpWriter { pub process_id: Pid, pub blamed_thread: Pid, @@ -34,6 +41,7 @@ pub struct MinidumpWriter { pub sanitize_stack: bool, pub crash_context: Option, pub crashing_thread_context: CrashingThreadContext, + pub stop_timeout: Duration, } // This doesn't work yet: @@ -62,6 +70,7 @@ impl MinidumpWriter { sanitize_stack: false, crash_context: None, crashing_thread_context: CrashingThreadContext::None, + stop_timeout: STOP_TIMEOUT, } } @@ -100,10 +109,18 @@ impl MinidumpWriter { self } + /// Sets the timeout after `SIGSTOP` is sent to the process, if the process + /// has not stopped by the time the timeout has reached, we proceed with + /// minidump generation + pub fn stop_timeout(&mut self, duration: Duration) -> &mut Self { + self.stop_timeout = duration; + self + } + /// Generates a minidump and writes to the destination provided. Returns the in-memory /// version of the minidump as well. pub fn dump(&mut self, destination: &mut (impl Write + Seek)) -> Result> { - let mut dumper = PtraceDumper::new(self.process_id)?; + let mut dumper = PtraceDumper::new(self.process_id, self.stop_timeout)?; dumper.suspend_threads()?; dumper.late_init()?; @@ -215,31 +232,24 @@ impl MinidumpWriter { dir_section.write_to_file(buffer, None)?; let dirent = thread_list_stream::write(self, buffer, dumper)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = mappings::write(self, buffer, dumper)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; app_memory::write(self, buffer)?; - // Write section to file dir_section.write_to_file(buffer, None)?; let dirent = memory_list_stream::write(self, buffer)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = exception_stream::write(self, buffer)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = systeminfo_stream::write(buffer)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = memory_info_list_stream::write(self, buffer)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, "/proc/cpuinfo") { @@ -249,7 +259,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/status", self.blamed_thread)) @@ -260,7 +269,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self @@ -273,7 +281,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/cmdline", self.blamed_thread)) @@ -284,7 +291,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/environ", self.blamed_thread)) @@ -295,7 +301,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/auxv", self.blamed_thread)) { @@ -305,7 +310,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/maps", self.blamed_thread)) { @@ -315,12 +319,10 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = dso_debug::write_dso_debug_stream(buffer, self.process_id, &dumper.auxv) .unwrap_or_default(); - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/limits", self.blamed_thread)) @@ -331,11 +333,9 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = thread_names_stream::write(buffer, dumper)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; // This section is optional, so we ignore errors when writing it diff --git a/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs b/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs index f75499bcdd..0dd0fa2719 100644 --- a/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs +++ b/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs @@ -15,10 +15,20 @@ use crate::{ use goblin::elf; use nix::{ errno::Errno, - sys::{ptrace, wait}, + sys::{ptrace, signal, wait}, +}; +use procfs_core::{ + process::{MMPermissions, ProcState, Stat}, + FromRead, ProcError, +}; +use std::{ + collections::HashMap, + ffi::c_void, + io::BufReader, + path, + result::Result, + time::{Duration, Instant}, }; -use procfs_core::process::MMPermissions; -use std::{collections::HashMap, ffi::c_void, io::BufReader, path, result::Result}; #[derive(Debug, Clone)] pub struct Thread { @@ -45,9 +55,27 @@ impl Drop for PtraceDumper { fn drop(&mut self) { // Always try to resume all threads (e.g. in case of error) let _ = self.resume_threads(); + // Always allow the process to continue. + let _ = self.continue_process(); } } +#[derive(Debug, thiserror::Error)] +enum StopProcessError { + #[error("Failed to stop the process")] + Stop(#[from] Errno), + #[error("Failed to get the process state")] + State(#[from] ProcError), + #[error("Timeout waiting for process to stop")] + Timeout, +} + +#[derive(Debug, thiserror::Error)] +enum ContinueProcessError { + #[error("Failed to continue the process")] + Continue(#[from] Errno), +} + /// PTRACE_DETACH the given pid. /// /// This handles special errno cases (ESRCH) which we won't consider errors. @@ -67,7 +95,7 @@ fn ptrace_detach(child: Pid) -> Result<(), DumperError> { impl PtraceDumper { /// Constructs a dumper for extracting information of a given process /// with a process ID of |pid|. - pub fn new(pid: Pid) -> Result { + pub fn new(pid: Pid, stop_timeout: Duration) -> Result { let mut dumper = PtraceDumper { pid, threads_suspended: false, @@ -76,12 +104,16 @@ impl PtraceDumper { mappings: Vec::new(), page_size: 0, }; - dumper.init()?; + dumper.init(stop_timeout)?; Ok(dumper) } // TODO: late_init for chromeos and android - pub fn init(&mut self) -> Result<(), InitError> { + pub fn init(&mut self, stop_timeout: Duration) -> Result<(), InitError> { + // Stopping the process is best-effort. + if let Err(e) = self.stop_process(stop_timeout) { + log::warn!("failed to stop process {}: {e}", self.pid); + } self.read_auxv()?; self.enumerate_threads()?; self.enumerate_mappings()?; @@ -207,6 +239,38 @@ impl PtraceDumper { result } + /// Send SIGSTOP to the process so that we can get a consistent state. + /// + /// This will block waiting for the process to stop until `timeout` has passed. + fn stop_process(&mut self, timeout: Duration) -> Result<(), StopProcessError> { + signal::kill(nix::unistd::Pid::from_raw(self.pid), Some(signal::SIGSTOP))?; + + // Something like waitpid for non-child processes would be better, but we have no such + // tool, so we poll the status. + const POLL_INTERVAL: Duration = Duration::from_millis(1); + let proc_file = format!("/proc/{}/stat", self.pid); + let end = Instant::now() + timeout; + + loop { + if let Ok(ProcState::Stopped) = Stat::from_file(&proc_file)?.state() { + return Ok(()); + } + + std::thread::sleep(POLL_INTERVAL); + if Instant::now() > end { + return Err(StopProcessError::Timeout); + } + } + } + + /// Send SIGCONT to the process to continue. + /// + /// Unlike `stop_process`, this function does not wait for the process to continue. + fn continue_process(&mut self) -> Result<(), ContinueProcessError> { + signal::kill(nix::unistd::Pid::from_raw(self.pid), Some(signal::SIGCONT))?; + Ok(()) + } + /// Parse /proc/$pid/task to list all the threads of the process identified by /// pid. fn enumerate_threads(&mut self) -> Result<(), InitError> { @@ -334,8 +398,9 @@ impl PtraceDumper { let mut mapping = self.find_mapping(stack_pointer); // The guard page has been 1 MiB in size since kernel 4.12, older - // kernels used a 4 KiB one instead. - let guard_page_max_addr = stack_pointer + (1024 * 1024); + // kernels used a 4 KiB one instead. Note the saturating add, as 32-bit + // processes can have a stack pointer within 1MiB of usize::MAX + let guard_page_max_addr = stack_pointer.saturating_add(1024 * 1024); // If we found no mapping, or the mapping we found has no permissions // then we might have hit a guard page, try looking for a mapping in diff --git a/third_party/rust/minidump-writer/src/linux/sections/mappings.rs b/third_party/rust/minidump-writer/src/linux/sections/mappings.rs index de19c54068..9012ae351b 100644 --- a/third_party/rust/minidump-writer/src/linux/sections/mappings.rs +++ b/third_party/rust/minidump-writer/src/linux/sections/mappings.rs @@ -83,16 +83,29 @@ fn fill_raw_module( sig_section.location() }; - let (file_path, _) = mapping - .get_mapping_effective_path_and_name() + let (file_path, _, so_version) = mapping + .get_mapping_effective_path_name_and_version() .map_err(|e| errors::SectionMappingsError::GetEffectivePathError(mapping.clone(), e))?; let name_header = write_string_to_location(buffer, file_path.to_string_lossy().as_ref())?; - Ok(MDRawModule { + let version_info = so_version.map_or(Default::default(), |sov| format::VS_FIXEDFILEINFO { + signature: format::VS_FFI_SIGNATURE, + struct_version: format::VS_FFI_STRUCVERSION, + file_version_hi: sov.major, + file_version_lo: sov.minor, + product_version_hi: sov.patch, + product_version_lo: sov.prerelease, + ..Default::default() + }); + + let raw_module = MDRawModule { base_of_image: mapping.start_address as u64, size_of_image: mapping.size as u32, cv_record, module_name_rva: name_header.rva, + version_info, ..Default::default() - }) + }; + + Ok(raw_module) } diff --git a/third_party/rust/minidump-writer/src/linux/thread_info.rs b/third_party/rust/minidump-writer/src/linux/thread_info.rs index 5bb1f9e8fb..a3fbed952f 100644 --- a/third_party/rust/minidump-writer/src/linux/thread_info.rs +++ b/third_party/rust/minidump-writer/src/linux/thread_info.rs @@ -37,20 +37,18 @@ enum NT_Elf { NT_ARM_VFP = 0x400, // ARM VFP/NEON registers } -#[inline] -pub fn to_u128(slice: &[u32]) -> &[u128] { - unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), slice.len().saturating_div(4)) } -} - -#[inline] -pub fn copy_registers(dst: &mut [u128], src: &[u128]) { - let to_copy = std::cmp::min(dst.len(), src.len()); - dst[..to_copy].copy_from_slice(&src[..to_copy]); -} - #[inline] pub fn copy_u32_registers(dst: &mut [u128], src: &[u32]) { - copy_registers(dst, to_u128(src)); + // SAFETY: We are copying a block of memory from ptrace as u32s to the u128 + // format of minidump-common + unsafe { + let dst: &mut [u8] = + std::slice::from_raw_parts_mut(dst.as_mut_ptr().cast(), dst.len() * 16); + let src: &[u8] = std::slice::from_raw_parts(src.as_ptr().cast(), src.len() * 4); + + let to_copy = std::cmp::min(dst.len(), src.len()); + dst[..to_copy].copy_from_slice(&src[..to_copy]); + } } trait CommonThreadInfo { diff --git a/third_party/rust/minidump-writer/src/mac/mach.rs b/third_party/rust/minidump-writer/src/mac/mach.rs index f95211dc64..9b0179fad4 100644 --- a/third_party/rust/minidump-writer/src/mac/mach.rs +++ b/third_party/rust/minidump-writer/src/mac/mach.rs @@ -590,7 +590,8 @@ pub fn sysctl_by_name(name: &[u8]) -> T { 0, ) != 0 { - // log? + // TODO convert to ascii characters when logging? + log::warn!("failed to get sysctl for {name:?}"); T::default() } else { out diff --git a/third_party/rust/minidump-writer/src/mac/streams/exception.rs b/third_party/rust/minidump-writer/src/mac/streams/exception.rs index e594dd8d95..7dd7f8fae4 100644 --- a/third_party/rust/minidump-writer/src/mac/streams/exception.rs +++ b/third_party/rust/minidump-writer/src/mac/streams/exception.rs @@ -69,9 +69,11 @@ impl MinidumpWriter { } else { // For all other exceptions types, the value in the code // _should_ never exceed 32 bits, crashpad does an actual - // range check here, but since we don't really log anything - // else at the moment I'll punt that for now - // TODO: log/do something if exc.code > u32::MAX + // range check here. + if code > u32::MAX.into() { + // TODO: do something more than logging? + log::warn!("exception code {code:#018x} exceeds the expected 32 bits"); + } code as u32 }; diff --git a/third_party/rust/minidump-writer/src/mac/streams/module_list.rs b/third_party/rust/minidump-writer/src/mac/streams/module_list.rs index 2b4d13ea74..d1307c80a8 100644 --- a/third_party/rust/minidump-writer/src/mac/streams/module_list.rs +++ b/third_party/rust/minidump-writer/src/mac/streams/module_list.rs @@ -344,6 +344,14 @@ mod test { /// both the local and intra-process scenarios #[test] fn images_match() { + if std::env::var_os("CI").is_some() && cfg!(target_arch = "aarch64") { + // https://github.com/rust-minidump/minidump-writer/issues/101 + println!( + "this fails on github actions but works on a local aarch64-apple-darwin machine..." + ); + return; + } + let mdw = MinidumpWriter::new(None, None); let td = TaskDumper::new(mdw.task); diff --git a/third_party/rust/minidump-writer/src/mac/streams/thread_names.rs b/third_party/rust/minidump-writer/src/mac/streams/thread_names.rs index 42242a6397..016dd48eb8 100644 --- a/third_party/rust/minidump-writer/src/mac/streams/thread_names.rs +++ b/third_party/rust/minidump-writer/src/mac/streams/thread_names.rs @@ -25,8 +25,8 @@ impl MinidumpWriter { // not a critical failure let name_loc = match Self::write_thread_name(buffer, dumper, tid) { Ok(loc) => loc, - Err(_err) => { - // TODO: log error + Err(err) => { + log::warn!("failed to write thread name for thread {tid}: {err}"); write_string_to_location(buffer, "")? } }; diff --git a/third_party/rust/minidump-writer/src/windows/minidump_writer.rs b/third_party/rust/minidump-writer/src/windows/minidump_writer.rs index 70cc420e57..2175368935 100644 --- a/third_party/rust/minidump-writer/src/windows/minidump_writer.rs +++ b/third_party/rust/minidump-writer/src/windows/minidump_writer.rs @@ -185,13 +185,13 @@ impl MinidumpWriter { // This is a mut pointer for some reason...I don't _think_ it is // actually mut in practice...? ExceptionPointers: crash_context.exception_pointers as *mut _, - /// The `EXCEPTION_POINTERS` contained in crash context is a pointer into the - /// memory of the process that crashed, as it contains an `EXCEPTION_RECORD` - /// record which is an internally linked list, so in the case that we are - /// dumping a process other than the current one, we need to tell - /// `MiniDumpWriteDump` that the pointers come from an external process so that - /// it can use eg `ReadProcessMemory` to get the contextual information from - /// the crash, rather than from the current process + // The `EXCEPTION_POINTERS` contained in crash context is a pointer into the + // memory of the process that crashed, as it contains an `EXCEPTION_RECORD` + // record which is an internally linked list, so in the case that we are + // dumping a process other than the current one, we need to tell + // `MiniDumpWriteDump` that the pointers come from an external process so that + // it can use eg `ReadProcessMemory` to get the contextual information from + // the crash, rather than from the current process ClientPointers: i32::from(is_external_process), }, ); diff --git a/third_party/rust/minidump-writer/tests/common/mod.rs b/third_party/rust/minidump-writer/tests/common/mod.rs index bbb6abf35c..1d5497b3ba 100644 --- a/third_party/rust/minidump-writer/tests/common/mod.rs +++ b/third_party/rust/minidump-writer/tests/common/mod.rs @@ -8,21 +8,27 @@ type Error = Box; #[allow(unused)] pub type Result = result::Result; +fn build_command() -> Command { + let mut cmd = Command::new("cargo"); + + cmd.env("RUST_BACKTRACE", "1") + .args(["run", "-q", "--bin", "test"]); + + // In normal cases where the host and target are the same this won't matter, + // but tests will fail if you are eg running in a cross container which will + // likely be x86_64 but may be targetting aarch64 or i686, which will result + // in tests failing, or at the least not testing what you think + cmd.args(["--target", current_platform::CURRENT_PLATFORM, "--"]); + + cmd +} + #[allow(unused)] pub fn spawn_child(command: &str, args: &[&str]) { - let mut cmd_object = Command::new("cargo"); - let mut cmd_ref = cmd_object - .env("RUST_BACKTRACE", "1") - .arg("run") - .arg("-q") - .arg("--bin") - .arg("test") - .arg("--") - .arg(command); - for arg in args { - cmd_ref = cmd_ref.arg(arg); - } - let child = cmd_ref.output().expect("failed to execute child"); + let mut cmd = build_command(); + cmd.arg(command).args(args); + + let child = cmd.output().expect("failed to execute child"); println!("Child output:"); std::io::stdout().write_all(&child.stdout).unwrap(); @@ -30,20 +36,12 @@ pub fn spawn_child(command: &str, args: &[&str]) { assert_eq!(child.status.code().expect("No return value"), 0); } -fn start_child_and_wait_for_threads_helper(cmd: &str, num: usize) -> Child { - let mut child = Command::new("cargo") - .env("RUST_BACKTRACE", "1") - .arg("run") - .arg("-q") - .arg("--bin") - .arg("test") - .arg("--") - .arg(cmd) - .arg(format!("{}", num)) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to execute child"); +fn start_child_and_wait_for_threads_helper(command: &str, num: usize) -> Child { + let mut cmd = build_command(); + cmd.arg(command).arg(num.to_string()); + cmd.stdout(Stdio::piped()); + let mut child = cmd.spawn().expect("failed to spawn cargo"); wait_for_threads(&mut child, num); child } @@ -84,17 +82,10 @@ pub fn wait_for_threads(child: &mut Child, num: usize) { #[allow(unused)] pub fn start_child_and_return(args: &[&str]) -> Child { - let mut child = Command::new("cargo") - .env("RUST_BACKTRACE", "1") - .arg("run") - .arg("-q") - .arg("--bin") - .arg("test") - .arg("--") - .args(args) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to execute child"); + let mut cmd = build_command(); + cmd.args(args); - child + cmd.stdout(Stdio::piped()) + .spawn() + .expect("failed to execute child") } diff --git a/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs b/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs index d9864bae13..c8458b1583 100644 --- a/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs +++ b/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs @@ -72,31 +72,31 @@ fn get_crash_context(tid: Pid) -> CrashContext { } } -macro_rules! contextual_tests { - () => {}; - ( fn $name:ident ($ctx:ident : Context) $body:block $($rest:tt)* ) => { +macro_rules! contextual_test { + ( $(#[$attr:meta])? fn $name:ident ($ctx:ident : Context) $body:block ) => { mod $name { use super::*; fn test($ctx: Context) $body #[test] - fn run() { + $(#[$attr])? + fn without_context() { test(Context::Without) } #[cfg(not(target_arch = "mips"))] #[test] - fn run_with_context() { + $(#[$attr])? + fn with_context() { test(Context::With) } } - contextual_tests! { $($rest)* } } } -contextual_tests! { - fn test_write_dump(context: Context) { +contextual_test! { + fn write_dump(context: Context) { let num_of_threads = 3; let mut child = start_child_and_wait_for_threads(num_of_threads); let pid = child.id() as i32; @@ -123,8 +123,11 @@ contextual_tests! { assert_eq!(mem_slice.len(), in_memory_buffer.len()); assert_eq!(mem_slice, in_memory_buffer); } +} - fn test_write_and_read_dump_from_parent(context: Context) { +contextual_test! { + #[ignore] + fn write_and_read_dump_from_parent(context: Context) { let mut child = start_child_and_return(&["spawn_mmap_wait"]); let pid = child.id() as i32; @@ -228,8 +231,10 @@ contextual_tests! { .get_raw_stream(MozLinuxLimits as u32) .expect("Couldn't find MozLinuxLimits"); } +} - fn test_write_with_additional_memory(context: Context) { +contextual_test! { + fn write_with_additional_memory(context: Context) { let mut child = start_child_and_return(&["spawn_alloc_wait"]); let pid = child.id() as i32; @@ -289,8 +294,10 @@ contextual_tests! { // Verify memory contents. assert_eq!(region.bytes, values); } +} - fn test_skip_if_requested(context: Context) { +contextual_test! { + fn skip_if_requested(context: Context) { let num_of_threads = 1; let mut child = start_child_and_wait_for_threads(num_of_threads); let pid = child.id() as i32; @@ -325,8 +332,10 @@ contextual_tests! { assert!(res.is_err()); } +} - fn test_sanitized_stacks(context: Context) { +contextual_test! { + fn sanitized_stacks(context: Context) { if context == Context::With { // FIXME the context's stack pointer very often doesn't lie in mapped memory, resulting // in the stack memory having 0 size (so no slice will match `defaced` in the @@ -378,8 +387,10 @@ contextual_tests! { assert!(slice.windows(defaced.len()).any(|window| window == defaced)); } } +} - fn test_write_early_abort(context: Context) { +contextual_test! { + fn write_early_abort(context: Context) { let mut child = start_child_and_return(&["spawn_alloc_wait"]); let pid = child.id() as i32; @@ -434,8 +445,10 @@ contextual_tests! { // Should be missing: assert!(dump.get_stream::().is_err()); } +} - fn test_named_threads(context: Context) { +contextual_test! { + fn named_threads(context: Context) { let num_of_threads = 5; let mut child = start_child_and_wait_for_named_threads(num_of_threads); let pid = child.id() as i32; @@ -476,10 +489,11 @@ contextual_tests! { expected.insert(format!("thread_{}", id)); } assert_eq!(expected, names); - } +} - fn test_file_descriptors(context: Context) { +contextual_test! { + fn file_descriptors(context: Context) { let num_of_files = 5; let mut child = start_child_and_wait_for_create_files(num_of_files); let pid = child.id() as i32; @@ -520,7 +534,7 @@ contextual_tests! { } #[test] -fn test_minidump_size_limit() { +fn minidump_size_limit() { let num_of_threads = 40; let mut child = start_child_and_wait_for_threads(num_of_threads); let pid = child.id() as i32; @@ -662,7 +676,7 @@ fn test_minidump_size_limit() { } #[test] -fn test_with_deleted_binary() { +fn with_deleted_binary() { let num_of_threads = 1; let binary_copy_dir = tempfile::Builder::new() .prefix("deleted_binary") @@ -686,36 +700,9 @@ fn test_with_deleted_binary() { let pid = child.id() as i32; - let build_id = PtraceDumper::elf_file_identifier_from_mapped_file(&mem_slice) + let mut build_id = PtraceDumper::elf_file_identifier_from_mapped_file(&mem_slice) .expect("Failed to get build_id"); - let guid = GUID { - data1: u32::from_ne_bytes(build_id[0..4].try_into().unwrap()), - data2: u16::from_ne_bytes(build_id[4..6].try_into().unwrap()), - data3: u16::from_ne_bytes(build_id[6..8].try_into().unwrap()), - data4: build_id[8..16].try_into().unwrap(), - }; - - // guid_to_string() is not public in minidump, so copied it here - // And append a zero, because module IDs include an "age" field - // which is always zero on Linux. - let filtered = format!( - "{:08X}{:04X}{:04X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}0", - guid.data1, - guid.data2, - guid.data3, - guid.data4[0], - guid.data4[1], - guid.data4[2], - guid.data4[3], - guid.data4[4], - guid.data4[5], - guid.data4[6], - guid.data4[7], - ); - // Strip out dashes - //let mut filtered: String = identifier.chars().filter(|x| *x != '-').collect(); - std::fs::remove_file(&binary_copy).expect("Failed to remove binary"); let mut tmpfile = tempfile::Builder::new() @@ -747,11 +734,34 @@ fn test_with_deleted_binary() { .main_module() .expect("Could not get main module"); assert_eq!(main_module.code_file(), binary_copy.to_string_lossy()); - assert_eq!(main_module.debug_identifier(), filtered.parse().ok()); + + let did = main_module + .debug_identifier() + .expect("expected value debug id"); + { + let uuid = did.uuid(); + let uuid = uuid.as_bytes(); + + // Swap bytes in the original to match the expected uuid + if cfg!(target_endian = "little") { + build_id[..4].reverse(); + build_id[4..6].reverse(); + build_id[6..8].reverse(); + } + + // The build_id from the binary can be as little as 8 bytes, eg LLD uses + // xxhash to calculate the build_id by default from 10+ + build_id.resize(16, 0); + + assert_eq!(uuid.as_slice(), &build_id); + } + + // The 'age'/appendix, always 0 on non-windows targets + assert_eq!(did.appendix(), 0); } #[test] -fn test_memory_info_list_stream() { +fn memory_info_list_stream() { let mut child = start_child_and_wait_for_threads(1); let pid = child.id() as i32; diff --git a/third_party/rust/minidump-writer/tests/ptrace_dumper.rs b/third_party/rust/minidump-writer/tests/ptrace_dumper.rs index 1be27f0809..6b62a4f6f3 100644 --- a/third_party/rust/minidump-writer/tests/ptrace_dumper.rs +++ b/third_party/rust/minidump-writer/tests/ptrace_dumper.rs @@ -7,7 +7,6 @@ use nix::sys::signal::Signal; use std::convert::TryInto; use std::io::{BufRead, BufReader}; use std::mem::size_of; -use std::os::unix::io::AsFd; use std::os::unix::process::ExitStatusExt; mod common; @@ -29,7 +28,8 @@ fn test_thread_list_from_parent() { let num_of_threads = 5; let mut child = start_child_and_wait_for_threads(num_of_threads); let pid = child.id() as i32; - let mut dumper = PtraceDumper::new(pid).expect("Couldn't init dumper"); + let mut dumper = PtraceDumper::new(pid, minidump_writer::minidump_writer::STOP_TIMEOUT) + .expect("Couldn't init dumper"); assert_eq!(dumper.threads.len(), num_of_threads); dumper.suspend_threads().expect("Could not suspend threads"); @@ -129,20 +129,22 @@ fn test_merged_mappings() { map_size, ProtFlags::PROT_READ, MapFlags::MAP_SHARED, - Some(file.as_fd()), + &file, 0, ) .unwrap() }; + let mapped = mapped_mem.as_ptr() as usize; + // Carve a page out of the first mapping with different permissions. let _inside_mapping = unsafe { mmap( - std::num::NonZeroUsize::new(mapped_mem as usize + 2 * page_size.get()), + std::num::NonZeroUsize::new(mapped + 2 * page_size.get()), page_size, ProtFlags::PROT_NONE, MapFlags::MAP_SHARED | MapFlags::MAP_FIXED, - Some(file.as_fd()), + &file, // Map a different offset just to // better test real-world conditions. page_size.get().try_into().unwrap(), // try_into() in order to work for 32 and 64 bit @@ -151,11 +153,7 @@ fn test_merged_mappings() { spawn_child( "merged_mappings", - &[ - path, - &format!("{}", mapped_mem as usize), - &format!("{map_size}"), - ], + &[path, &format!("{mapped}"), &format!("{map_size}")], ); } @@ -209,7 +207,8 @@ fn test_sanitize_stack_copy() { let heap_addr = usize::from_str_radix(output.next().unwrap().trim_start_matches("0x"), 16) .expect("unable to parse mmap_addr"); - let mut dumper = PtraceDumper::new(pid).expect("Couldn't init dumper"); + let mut dumper = PtraceDumper::new(pid, minidump_writer::minidump_writer::STOP_TIMEOUT) + .expect("Couldn't init dumper"); assert_eq!(dumper.threads.len(), num_of_threads); dumper.suspend_threads().expect("Could not suspend threads"); let thread_info = dumper diff --git a/third_party/rust/naga/.cargo-checksum.json b/third_party/rust/naga/.cargo-checksum.json index 8a1163971f..d01b0848ce 100644 --- a/third_party/rust/naga/.cargo-checksum.json +++ b/third_party/rust/naga/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".cargo/config.toml":"d7389d2a0c08ec72b79e83a3c76980903e3f9123625c32e69c798721193e2e74","CHANGELOG.md":"6b2c4d8dfd8c537811c33744703b4c03fa8aa15f5fab8f0e2be76f597cb7e273","Cargo.toml":"dd06bf980497dcb0d35c2c33d845ba80cb7a2f78bd0e824e3d6be6b950b8088b","README.md":"468211bb7457683510ff862f31f27e3ba07514f851a4390570d0e9259cbeaf6f","benches/criterion.rs":"f45e38b26e1323e934d32623572ff5395a53fed06f760eb1e07b22ed07858a38","src/arena.rs":"33ed2ec7b36429b133ed2a7de6fb9735827f69ea8b6c2ce97f64746a24a5bf36","src/back/dot/mod.rs":"a40050a73ac00c8fa43dd0b45a84fca6959d28c8c99ab3046b01f33c02f8c8f4","src/back/glsl/features.rs":"3d12147d201aaed746a94741356458a435a1ff7cf30b66baf44ba0b8dfe4b0ca","src/back/glsl/keywords.rs":"1546facbaddf696602102f32e47db7afc875f8ca3fbccc2122e0bcc45e022b53","src/back/glsl/mod.rs":"9e8b34a09401744a2ad4deae4d4863bd0be1d7d5da6ca72a98ca80fe0e3dfde6","src/back/hlsl/conv.rs":"2d7a8e7753b8fb21659e582612eea82e42e353abd23df719de450074a4da731e","src/back/hlsl/help.rs":"06da97ea0d58e2b94823ca1dae67a8611be6d5d047649b1d83755acb4c110808","src/back/hlsl/keywords.rs":"a7164690a4da866e6bfb18ced20e32cc8c42dd7387e0e84addf0c2674f529cf5","src/back/hlsl/mod.rs":"2f5296c45a2147093cae17250321580e7f01c57f907e529d19521eccd0cd4147","src/back/hlsl/storage.rs":"2c2a0071cafe487a398e396dddc85bdb319b1a5d74c097d529078e247a904359","src/back/hlsl/writer.rs":"36f0410edf9c0a8295e4916ca0e7a4e98cd170fcd5ecf6826df6051bef003b9c","src/back/mod.rs":"6101d92bff1c5b7fe3e503188554dfdcce56d4eb610237e0126bf6d8c4e1a85d","src/back/msl/keywords.rs":"e6a4ef77363f995de1f8079c0b8591497cbf9520c5d3b2d41c7e1f483e8abd24","src/back/msl/mod.rs":"15fdb90b8cd2b98273b22b9569fc322eb473fd135865eef82cc615d27320d779","src/back/msl/sampler.rs":"9b01d68669e12ff7123243284b85e1a9d2c4d49140bd74ca32dedc007cbf15af","src/back/msl/writer.rs":"27e8604a5d11391b91b328f420e93f7cf475364a783b3dc5ba8bb720f17d9d86","src/back/spv/block.rs":"e2326e10cc8ca64398636c1b27166b406611006ffc2388c20fca4a271d609afe","src/back/spv/helpers.rs":"a4e260130f39c7345decec40dadf1e94419c8f6d236ce7a53b5300aa72952a1b","src/back/spv/image.rs":"e4b982ce430e17881d6370191d849dbe6bb8f6d86f4896815eb1736e43b4e302","src/back/spv/index.rs":"54bb90176be12a9a243099343e62b8dd35dd019d237d4d7dcdb9f0da7747df09","src/back/spv/instructions.rs":"d0ced535fdec49323105a7d6ee40a8ed6b4966ac5f0f40b062f0eb11a531b106","src/back/spv/layout.rs":"e263de53cd2f9a03ad94b82b434ce636609bc1ed435a2d1132951663bfaa8ebd","src/back/spv/mod.rs":"bd0589e0f6ce33b294f1f907dd5a1c03b46429b1b0d77986f8bb98ad317b11e3","src/back/spv/ray.rs":"a34bf6b26d873f7270caa45841d9ef291aca8d9732ecd086b14d8856038e1e41","src/back/spv/recyclable.rs":"114db0ea12774d6514f995d07295cb9a42631ab75165fc60980c10e9b5ecb832","src/back/spv/selection.rs":"81e404abfa0a977f7c1f76ccb37a78d13ccadbda229048dad53cc67687cc39db","src/back/spv/writer.rs":"87460df9918c1f104213394c0532e384ae282d132fdb7e09823eeb10c2392e3d","src/back/wgsl/mod.rs":"2dd12bbea9ace835850192bb68c5760953da6bac6a636073d1eca19381c0c0b6","src/back/wgsl/writer.rs":"96795df390cffade8ca27baea88ab29592d7e425c4351a9e2591d4f4ecdc73f3","src/block.rs":"c69089e5bbb6de6ba24efb15b21d5d434fcabfbc4d48feae948d2a4da135aae7","src/compact/expressions.rs":"7a4c916282a5b484519ed29ab451c7b595d8dea73c83c5c2cf7efc6fbc648fda","src/compact/functions.rs":"174bd9167ecf6353afb8c36d365ba3f9b483233eb4bacf578e50183c7433aa15","src/compact/handle_set_map.rs":"817c5193352d5fd6a61a5c970daba23224e14a65aea15f8f1c8679c99f834ca2","src/compact/mod.rs":"f1a606e8732f3c5837ab40ba5569eb1687336ef412f7f4b6cc348dd52b8076b3","src/compact/statements.rs":"4df33ee9589300e769e75c674bdc30578e93704ec3eb2aabc7132121745b55c8","src/compact/types.rs":"18343f2ca2c123eea2531cffc1d54a7798797caccecaa1f9b8c4fd5dd6ca1a05","src/front/glsl/ast.rs":"a4615f0c52b0dc9fdb07f816b4534c1ca547c2d176008ca86d66f9e6874f227d","src/front/glsl/builtins.rs":"d35501d5b42b61c261da24436b82eafdf96371b1600d148648d90d041f736ae4","src/front/glsl/context.rs":"066203c24ff5bc6154aa671f4492b5e8dfede8b57ef886f093cc95470d66411b","src/front/glsl/error.rs":"cca4a3aa9de2808952ff68c183755df5fdf6a7cb81f170ba747795176c0342fd","src/front/glsl/functions.rs":"b420be6b54195e9cdabdf76bb854e3e1f3be6542c6c129656fd0b1bd900dcebd","src/front/glsl/lex.rs":"08736ae8beb955da5b0e6e3e0f45995a824995f7096d516a2910417e9c7afa32","src/front/glsl/mod.rs":"c6e81710ae94a52583ba6f2a80a505d6bcd6ea6552008b80b27539af48838df1","src/front/glsl/offset.rs":"9358602ca4f9ef21d5066d674dae757bf88fdf5c289c4360534354d13bd41dc0","src/front/glsl/parser.rs":"fe5291512db412b33b6c09d5b3dcf7c54ff6ec55b47f0a078dcc11695e78471d","src/front/glsl/parser/declarations.rs":"d637cc52e553910a2e97b70b3366c15aefbe737f413adb11c27efd184c1fbf9d","src/front/glsl/parser/expressions.rs":"520cfc9402d5fbd48e52ef1d36562c6b74794c09ec33ec1ebb10aa48d129b66f","src/front/glsl/parser/functions.rs":"75aedcea4133bc4aba06ef49b1697eac96cc28d191e9830689fc4a6c0c4856eb","src/front/glsl/parser/types.rs":"aeb97e1a5fb03205cd5630c29da59d81a376ce9a83a603b62b037e63ad948e88","src/front/glsl/parser_tests.rs":"bfd4dff2580f4369a57edbcace47d23e2666751ffc3ab55f8d7dfe01f1a66311","src/front/glsl/token.rs":"c25c489b152ee2d445ace3c2046473abe64d558b8d27fa08709110e58718b6ac","src/front/glsl/types.rs":"58c9cf3d570dff8cb68f2931faf5b18e875e510741bf035ec10b9ff6df27c5d8","src/front/glsl/variables.rs":"bfed08368b56dc1f55fe487b240cf7b8e09443e508ea410cfac48df477591eee","src/front/interpolator.rs":"9b6ca498d5fbd9bc1515510a04e303a00b324121d7285da3c955cfe18eb4224c","src/front/mod.rs":"77acd7fb71d004969d1ee69fc728647f03242762988786c4e15fadf8315600af","src/front/spv/convert.rs":"dccc6671e6a4a7f1139aecdf979faa3689609081af5fa2cbbd6a2e8c4128c004","src/front/spv/error.rs":"6438aac57cfcf5d3858dd7652ccda1967a3123c6374f1cab829092b00549f70f","src/front/spv/function.rs":"1acb7bdd34ecfe08c6f4b4d06c2a0ea74aaf9975352e8804e3e4fab90745132f","src/front/spv/image.rs":"5d55cfbf6752732a594114cd09a9a207216e1ee85d8f2c9bc4310217a55ea321","src/front/spv/mod.rs":"22d0de7c43c42279e788144ff806cadfe3a3ea7923d961d11740af22492c4087","src/front/spv/null.rs":"e1446d99d04c76a9c3bbd24dd9b20c4711ce8a918a9b403be6cccbde1175b3b4","src/front/type_gen.rs":"b4f1df23380e06c9fdad4140810ce96ab041dbb1d371a07045b4e0069aa8ba55","src/front/wgsl/error.rs":"e1efd61062a5eb5f7e0413dc05d17abdbe0679c08f2fbdb7478e2b6e8dd13b25","src/front/wgsl/index.rs":"2b9a4929a46bd822d3ed6f9a150e24d437e5bdca8293eb748aebe80ce7e74153","src/front/wgsl/lower/construction.rs":"92342e27f5bdeb598e178799b74aa610788549c19a49fe0ae8914916bfa3c7be","src/front/wgsl/lower/conversion.rs":"961b19bf8ddd4667c6caf854a1889f3d6477757f4125538c3e9ca7d730975dd7","src/front/wgsl/lower/mod.rs":"08eece7a5460e414e2f8398cec96f12a8b9f6a457270426d8e4f045b62290d1f","src/front/wgsl/mod.rs":"02b194a0a29ef7281f71b424564e18ada4a8b1a0d8c26ec40b6be195bd4c4904","src/front/wgsl/parse/ast.rs":"c7eaae40179f0889f2b142d3b31968cbfab6d3cfe02e425912c6da8dadac51df","src/front/wgsl/parse/conv.rs":"9b2a06b5fd577e1881b2212e1d675d3aefe4d1fee99a17b5f7b07c36913e8186","src/front/wgsl/parse/lexer.rs":"17db87d0017f8f9a80fa151b8545f04e1b40c4e5feef6197f4a117efa03488bf","src/front/wgsl/parse/mod.rs":"3b4895a2baf91c719b95f0afb6441ffac2036c2a9ff817e633882fd257afcc38","src/front/wgsl/parse/number.rs":"dafd3d8651cfa1389cb359d76d39bd689e54f8d5025aa23e06c6edd871369efd","src/front/wgsl/tests.rs":"7a0a083a5b66af8e7d4b1a02401b27f077eb72d07181b610693f35b11f107c6c","src/front/wgsl/to_wgsl.rs":"2e2e30d86b07f209b866e530d3a882803bf28b39ce379052561a749f628e8e28","src/keywords/mod.rs":"0138f3931f8af0b0a05174549d0fd2152945b027dc3febefc1bbd676581d2e45","src/keywords/wgsl.rs":"c648ac44241ad55c8c8bad3d8f1bab973d11ddb9c380dcca369b735ed3975309","src/lib.rs":"f2072172957699d4282f247c452d8d8f0a0da08b9d78b279ee010296669d28d8","src/proc/constant_evaluator.rs":"bea5d259dbc4d9f9dacf3717dcb17a0774a22f1b3e5251b7e5b6991330ed3057","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"f4250f6944c2b631e8140979024e8deb86fa8d5352d8641ba954a388b2c0940e","src/proc/layouter.rs":"b3d061c87424f36981c902716f37ab7b72f2bb2d0c2d7e900c51149318ea1a0a","src/proc/mod.rs":"4be5dcb137147cd8182a291f90959c46f1681c2d2c7da9e63f702a5f84c8809d","src/proc/namer.rs":"7328fac41e40890c64c7ee2fa985a4395424f18b08d30f30ca2583fdabd2fd35","src/proc/terminator.rs":"13c59bf00f5b26171d971effc421091f5e00dedddd246c2daa44fe65aeda060a","src/proc/typifier.rs":"99de19270d01c12ec49d14323aa1d9b8774f1ee715804af7235deff70739ba3d","src/span.rs":"47d92ea25ce7178ad903ac4f5acd0bc40ebd90de1e470e538a2aa3063d980890","src/valid/analyzer.rs":"65ed1487c5a169688714a7386046b30ec380eaf44e5500f366b9c9a308f59464","src/valid/compose.rs":"83e4c09c39f853cf085b83b87e48b3db571da619132960d3ec954ebdfb0a74f2","src/valid/expression.rs":"7a8d5f74677c627dee3e15d223e83453ea7f6567dc806fcdfeebd32081012779","src/valid/function.rs":"40754e51906b053becdd8813b189fe709b7693c08babd28b5d3f5c576475b171","src/valid/handles.rs":"0878915e67b16d7c41cf8245d9ab3b3f4a604e7d4e87527ea40e03efcbf1f74a","src/valid/interface.rs":"32ef8e4665106b5c71540833e17ee9cd1dde5a900c9b81f61e0b7b8192c4aaf2","src/valid/mod.rs":"3b2772c88561aeb4dc8f5ce0d8ed5169bcdf5f7db04a62aaf22d04c171cb4f35","src/valid/type.rs":"635a4f7b2681d2cc7645a5589640098efb3cdaf3c492d79924c9e80c806c7890"},"package":null} \ No newline at end of file +{"files":{".cargo/config.toml":"d7389d2a0c08ec72b79e83a3c76980903e3f9123625c32e69c798721193e2e74","CHANGELOG.md":"6b2c4d8dfd8c537811c33744703b4c03fa8aa15f5fab8f0e2be76f597cb7e273","Cargo.toml":"52d6fbc7cdb6af39f63af59159fa60aa2c230bb73689cb12dd024ff72c2459aa","README.md":"468211bb7457683510ff862f31f27e3ba07514f851a4390570d0e9259cbeaf6f","benches/criterion.rs":"f45e38b26e1323e934d32623572ff5395a53fed06f760eb1e07b22ed07858a38","src/arena.rs":"2b9cc6eafa2083171b9b053f309c4506796784f8770e8b62d9cfb322cdffef2a","src/back/dot/mod.rs":"559d7bb9abc214a2ae8448cb3718ca249c55a24cddfa368eb765ee5c0c977524","src/back/glsl/features.rs":"382f01bec9db166f14348e60fd5347c55ddb87487b2c0040301d9a6da366a86c","src/back/glsl/keywords.rs":"1546facbaddf696602102f32e47db7afc875f8ca3fbccc2122e0bcc45e022b53","src/back/glsl/mod.rs":"e621689676095d978a5d64af1dfa1fd18e02181a1c759ac957aea1408858d122","src/back/hlsl/conv.rs":"62639a33f59fecb9fee53fcf22c77ab9f1b04b4fa81396b3bd53d217a3d424d3","src/back/hlsl/help.rs":"9ee290466c4d27ee565dc7fe3dc9ec79e7aa498790fe345dcf1d09e6e80cfdcf","src/back/hlsl/keywords.rs":"a7164690a4da866e6bfb18ced20e32cc8c42dd7387e0e84addf0c2674f529cf5","src/back/hlsl/mod.rs":"09ea1c58f0c25938935747ad5a5a94dc9643038193f01269a5c4c30f19d7669a","src/back/hlsl/storage.rs":"2c2a0071cafe487a398e396dddc85bdb319b1a5d74c097d529078e247a904359","src/back/hlsl/writer.rs":"8aa5a3916f8f4c4fb69e048102681563fa2de06ff449c1802ac3535b10b4163c","src/back/mod.rs":"de0579806ca2b341a77725defd56d5e8758ec921e48344affaffc0656d67b84f","src/back/msl/keywords.rs":"e6a4ef77363f995de1f8079c0b8591497cbf9520c5d3b2d41c7e1f483e8abd24","src/back/msl/mod.rs":"1edba5f84857b0fbd3abf0eee56c7d5cf42b54bcea7e549428ff3ec2df1f70e0","src/back/msl/sampler.rs":"9b01d68669e12ff7123243284b85e1a9d2c4d49140bd74ca32dedc007cbf15af","src/back/msl/writer.rs":"205ed801d6ebde745dc1f9cab9d5eb321d784e8b7beeb771419a8546fb647269","src/back/pipeline_constants.rs":"ffb1817d2fa1356f73798bce9baf739fcf7f82a98935a8370f279db06310d1a1","src/back/spv/block.rs":"5229b297df23fc99897d3f387604c61268532cc6f89a61a27124ff06d6b93c62","src/back/spv/helpers.rs":"bd666bf519a5d5561c2fab6ff78229739853ae6877d132911e71b57cfd656e42","src/back/spv/image.rs":"e4b982ce430e17881d6370191d849dbe6bb8f6d86f4896815eb1736e43b4e302","src/back/spv/index.rs":"54bb90176be12a9a243099343e62b8dd35dd019d237d4d7dcdb9f0da7747df09","src/back/spv/instructions.rs":"105e38c29889b9b2be7edd7dd228246a91189a829eab7afc18ba92337401213f","src/back/spv/layout.rs":"e263de53cd2f9a03ad94b82b434ce636609bc1ed435a2d1132951663bfaa8ebd","src/back/spv/mod.rs":"c00fb2089bee377bb892b7bd51fcccf64380f3a197152a087cf8918352278b4b","src/back/spv/ray.rs":"a34bf6b26d873f7270caa45841d9ef291aca8d9732ecd086b14d8856038e1e41","src/back/spv/recyclable.rs":"114db0ea12774d6514f995d07295cb9a42631ab75165fc60980c10e9b5ecb832","src/back/spv/selection.rs":"81e404abfa0a977f7c1f76ccb37a78d13ccadbda229048dad53cc67687cc39db","src/back/spv/subgroup.rs":"cb68fb9581064ec9ef79e56a0c94c802b2f04cc5e2173a953ae9a7b2776042d5","src/back/spv/writer.rs":"04305d6b5b2047af2026bb0f93cd9bc8ed09cdf25a233692b38314e436c36737","src/back/wgsl/mod.rs":"2dd12bbea9ace835850192bb68c5760953da6bac6a636073d1eca19381c0c0b6","src/back/wgsl/writer.rs":"718dd8695a6630a66989b507fb0deddcceb3d229872e4eb3e605d945ac9e24fa","src/block.rs":"e447f7e041fd67052b23d1139cf0574eea93220a818af71691d960bdf026d45f","src/compact/expressions.rs":"6d876dfbaf7d6ce6e66d4ec4ef6cb783455cc85cc67b30991e975b2f52f2b843","src/compact/functions.rs":"e10945ca13aa0bb556cd675be31c85e1ac3698293e79b8c5e1a984bbd6fda800","src/compact/handle_set_map.rs":"817c5193352d5fd6a61a5c970daba23224e14a65aea15f8f1c8679c99f834ca2","src/compact/mod.rs":"f03f1876f14c111757152de8661497593cff23a4a638e441d2201c8383698ef5","src/compact/statements.rs":"4c12ab531f9aa696bd662b44e3834a6e2b151dd1859f960eba6f4c2cec3b793a","src/compact/types.rs":"18343f2ca2c123eea2531cffc1d54a7798797caccecaa1f9b8c4fd5dd6ca1a05","src/error.rs":"588e0ca123e8923d3bb3392e6b46f2386122c21f7a487ab2bfb458c72a52a0f1","src/front/glsl/ast.rs":"a4615f0c52b0dc9fdb07f816b4534c1ca547c2d176008ca86d66f9e6874f227d","src/front/glsl/builtins.rs":"d35501d5b42b61c261da24436b82eafdf96371b1600d148648d90d041f736ae4","src/front/glsl/context.rs":"e82bc54d0bf7bc65b70e2caf298374eed591fd181170c2ee5a35f96b6349dff0","src/front/glsl/error.rs":"ec74419598635e818f70f4080eadfaa3b499202affff3aed437e59c4451f9224","src/front/glsl/functions.rs":"3ff5b5ad5707146fa50c517329414cf8f63ec5cb28e481db07120e88986a78c9","src/front/glsl/lex.rs":"08736ae8beb955da5b0e6e3e0f45995a824995f7096d516a2910417e9c7afa32","src/front/glsl/mod.rs":"bf97bf1710d5d1f8facb77913cb82868697920914a96ed309adf0f19154a2ab4","src/front/glsl/offset.rs":"9358602ca4f9ef21d5066d674dae757bf88fdf5c289c4360534354d13bd41dc0","src/front/glsl/parser.rs":"a752f2abac17e6d35c0eb406f2f1c24d2b622a55b1bececbdd13614edb686622","src/front/glsl/parser/declarations.rs":"796514c1d571b324817bf1236d4c1227a91a512c0660ce5bb1264cd900027158","src/front/glsl/parser/expressions.rs":"520cfc9402d5fbd48e52ef1d36562c6b74794c09ec33ec1ebb10aa48d129b66f","src/front/glsl/parser/functions.rs":"d7d25be7790213dd358080b52355b06e2d286c37c301fa1ad16e35bc301492c4","src/front/glsl/parser/types.rs":"aeb97e1a5fb03205cd5630c29da59d81a376ce9a83a603b62b037e63ad948e88","src/front/glsl/parser_tests.rs":"c44ed3252096c83a0ce1ea9be8d2b867784cdc1c11aa4501aee1a85d86c62511","src/front/glsl/token.rs":"c25c489b152ee2d445ace3c2046473abe64d558b8d27fa08709110e58718b6ac","src/front/glsl/types.rs":"91c3a4e4d11b397ea647ff287e17a48baedf2f2c310e81b04618675daeb83f69","src/front/glsl/variables.rs":"dbab566eb24c2efb97d1b036e05be7f42619feab837ea01e872a7c389186e9ca","src/front/interpolator.rs":"9b6ca498d5fbd9bc1515510a04e303a00b324121d7285da3c955cfe18eb4224c","src/front/mod.rs":"77acd7fb71d004969d1ee69fc728647f03242762988786c4e15fadf8315600af","src/front/spv/convert.rs":"b52ffba12a51b2f2f3cf0098b8451daa8db61c6b8b5194ba4d7d8cd3bc521a42","src/front/spv/error.rs":"d1f9e8b3cf34a436e0c2793ce1446617d0de77739f9d668fd08a313dd23d7ffd","src/front/spv/function.rs":"6254b4d600a52cf8ded6f19718d8fbcbef4b44ffe860059ce51b1a6fecc28406","src/front/spv/image.rs":"a5ac477c01894a9c9ce5ec9d6751f991622d610f5581a759fc2e72034677d9e4","src/front/spv/mod.rs":"c211f4c8dc838dbcde8240d1e606ea9b8b0a95f31f212197cf63e9f6f29b1e8c","src/front/spv/null.rs":"a8ff44e97ffe42a4773d89b88fdb3a8ef8fba58bf6645c73b7a66470234ccf10","src/front/type_gen.rs":"b4f1df23380e06c9fdad4140810ce96ab041dbb1d371a07045b4e0069aa8ba55","src/front/wgsl/error.rs":"8554557ff38abf04a05bf32e9ee7935c36564b8555dfc43b4eb3fcdfa8a991ac","src/front/wgsl/index.rs":"c5928ac405ffbd74de60b96360f7e07a3470b39f8f76c6e0b06544b4b5f61f57","src/front/wgsl/lower/construction.rs":"92342e27f5bdeb598e178799b74aa610788549c19a49fe0ae8914916bfa3c7be","src/front/wgsl/lower/conversion.rs":"961b19bf8ddd4667c6caf854a1889f3d6477757f4125538c3e9ca7d730975dd7","src/front/wgsl/lower/mod.rs":"e1bc9d1312cbe98607aea0f79b85a944faad0b6fa46dd565c271e6d4f5be504e","src/front/wgsl/mod.rs":"cebe3f61843cca32d6764b93b07cb369ae22d1240d81eabe25f5c42dc603fca1","src/front/wgsl/parse/ast.rs":"31d10aaf229b2e40d690d9fe50481d4f8c8edffd07356e344597a6ea2e3bd1d8","src/front/wgsl/parse/conv.rs":"e9bde6f186278475f35e8808bcdc5bb760e2fd26d8df054e69f81a840b3d346e","src/front/wgsl/parse/lexer.rs":"17db87d0017f8f9a80fa151b8545f04e1b40c4e5feef6197f4a117efa03488bf","src/front/wgsl/parse/mod.rs":"26e3119adbe142bf0ad313dd53873d87f783f46379a9e33368d3f2a29274ffc5","src/front/wgsl/parse/number.rs":"dafd3d8651cfa1389cb359d76d39bd689e54f8d5025aa23e06c6edd871369efd","src/front/wgsl/tests.rs":"7a0a083a5b66af8e7d4b1a02401b27f077eb72d07181b610693f35b11f107c6c","src/front/wgsl/to_wgsl.rs":"5bd13063bcb86682185b895892219ec3763cf3f06bcbf4c2dec261d23e7f9dac","src/keywords/mod.rs":"0138f3931f8af0b0a05174549d0fd2152945b027dc3febefc1bbd676581d2e45","src/keywords/wgsl.rs":"c648ac44241ad55c8c8bad3d8f1bab973d11ddb9c380dcca369b735ed3975309","src/lib.rs":"e2b808f5a1d0173e18f130e1dbf8810db6fd22f8b2c228d31f7dd1f42749b0fb","src/proc/constant_evaluator.rs":"f8cf5aa74e6178ac694b5f600dc80b1dafa4b2db07eb484ea19a5ea8b5573d68","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"ab083e3740d6e9e0d1abd9db32498d16ebc564587b589962b7056b059b220eff","src/proc/layouter.rs":"b3d061c87424f36981c902716f37ab7b72f2bb2d0c2d7e900c51149318ea1a0a","src/proc/mod.rs":"df786d2602d4a7c3e3780b066cadef9ac0f0c2cc4c28c903b8673f9ad33931cf","src/proc/namer.rs":"7328fac41e40890c64c7ee2fa985a4395424f18b08d30f30ca2583fdabd2fd35","src/proc/terminator.rs":"fef2160473fcddd670c6b5806a8ea0ecbdcc0fdf6ed793dce131ecd08cce3944","src/proc/typifier.rs":"493664b4396353470b10ae82f9a92932066a02925eb97324401aac1d19d9e97e","src/span.rs":"fd3b338256f9301fc5289c37af9ccec704d2e5db92923b0dec45da371e84ce6a","src/valid/analyzer.rs":"fdd84e34adfc2f77868bfb74bf3df12eb0dbfa32d13e5997232c28d06c9fd09e","src/valid/compose.rs":"83e4c09c39f853cf085b83b87e48b3db571da619132960d3ec954ebdfb0a74f2","src/valid/expression.rs":"149efe7d0958df6272361b79bbc62715f0a7041f13fa9e736d066d727f4c5aa2","src/valid/function.rs":"1dec6a302a070c3d16e91f45e07c2cf37c3af4dc138acf7411bcebdf4930a42a","src/valid/handles.rs":"dfdb1cdd54b751a930f873ebeb8f71fae8a13fe644a25a750d5c1eec27fa1a8f","src/valid/interface.rs":"a668d727178292dd0ce25d824b61a00e855a03045532fb6b9380178813c4130a","src/valid/mod.rs":"a0db031aec6fd9b5f31fc90e067b27f7b884ae4bbbfff988bf694c1261ec1b46","src/valid/type.rs":"6c192dc3517656daf330da74ad1e85bc5a1d371e0cb3f323de2bc177239f1636"},"package":null} \ No newline at end of file diff --git a/third_party/rust/naga/Cargo.toml b/third_party/rust/naga/Cargo.toml index 04375a9960..f645cc53f4 100644 --- a/third_party/rust/naga/Cargo.toml +++ b/third_party/rust/naga/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.74" name = "naga" -version = "0.19.0" +version = "0.20.0" authors = ["gfx-rs developers"] exclude = [ "bin/**/*", @@ -48,11 +48,11 @@ harness = false [dependencies] arrayvec = "0.7" bit-set = "0.5" -bitflags = "2.4" +bitflags = "2.5" log = "0.4" num-traits = "0.2" rustc-hash = "1.1.0" -thiserror = "1.0.57" +thiserror = "1.0.59" [dependencies.arbitrary] version = "1.3" @@ -79,7 +79,7 @@ version = "0.2.1" optional = true [dependencies.serde] -version = "1.0.196" +version = "1.0.198" features = ["derive"] optional = true @@ -122,7 +122,6 @@ arbitrary = [ "bitflags/arbitrary", "indexmap/arbitrary", ] -clone = [] compact = [] default = [] deserialize = [ diff --git a/third_party/rust/naga/src/arena.rs b/third_party/rust/naga/src/arena.rs index c37538667f..740df85b86 100644 --- a/third_party/rust/naga/src/arena.rs +++ b/third_party/rust/naga/src/arena.rs @@ -122,6 +122,7 @@ impl Handle { serde(transparent) )] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(test, derive(PartialEq))] pub struct Range { inner: ops::Range, #[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))] @@ -140,6 +141,7 @@ impl Range { // NOTE: Keep this diagnostic in sync with that of [`BadHandle`]. #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] #[error("Handle range {range:?} of {kind} is either not present, or inaccessible yet")] pub struct BadRangeError { // This error is used for many `Handle` types, but there's no point in making this generic, so @@ -239,7 +241,7 @@ impl Range { /// Adding new items to the arena produces a strongly-typed [`Handle`]. /// The arena can be indexed using the given handle to obtain /// a reference to the stored item. -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "serialize", serde(transparent))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] @@ -297,6 +299,17 @@ impl Arena { .map(|(i, v)| unsafe { (Handle::from_usize_unchecked(i), v) }) } + /// Drains the arena, returning an iterator over the items stored. + pub fn drain(&mut self) -> impl DoubleEndedIterator, T, Span)> { + let arena = std::mem::take(self); + arena + .data + .into_iter() + .zip(arena.span_info) + .enumerate() + .map(|(i, (v, span))| unsafe { (Handle::from_usize_unchecked(i), v, span) }) + } + /// Returns a iterator over the items stored in this arena, /// returning both the item's handle and a mutable reference to it. pub fn iter_mut(&mut self) -> impl DoubleEndedIterator, &mut T)> { @@ -531,7 +544,7 @@ mod tests { /// /// `UniqueArena` is similar to [`Arena`]: If `Arena` is vector-like, /// `UniqueArena` is `HashSet`-like. -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Clone)] pub struct UniqueArena { set: FastIndexSet, diff --git a/third_party/rust/naga/src/back/dot/mod.rs b/third_party/rust/naga/src/back/dot/mod.rs index 1556371df1..9a7702b3f6 100644 --- a/third_party/rust/naga/src/back/dot/mod.rs +++ b/third_party/rust/naga/src/back/dot/mod.rs @@ -279,6 +279,94 @@ impl StatementGraph { crate::RayQueryFunction::Terminate => "RayQueryTerminate", } } + S::SubgroupBallot { result, predicate } => { + if let Some(predicate) = predicate { + self.dependencies.push((id, predicate, "predicate")); + } + self.emits.push((id, result)); + "SubgroupBallot" + } + S::SubgroupCollectiveOperation { + op, + collective_op, + argument, + result, + } => { + self.dependencies.push((id, argument, "arg")); + self.emits.push((id, result)); + match (collective_op, op) { + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::All) => { + "SubgroupAll" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Any) => { + "SubgroupAny" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Add) => { + "SubgroupAdd" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Mul) => { + "SubgroupMul" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Max) => { + "SubgroupMax" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Min) => { + "SubgroupMin" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::And) => { + "SubgroupAnd" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Or) => { + "SubgroupOr" + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Xor) => { + "SubgroupXor" + } + ( + crate::CollectiveOperation::ExclusiveScan, + crate::SubgroupOperation::Add, + ) => "SubgroupExclusiveAdd", + ( + crate::CollectiveOperation::ExclusiveScan, + crate::SubgroupOperation::Mul, + ) => "SubgroupExclusiveMul", + ( + crate::CollectiveOperation::InclusiveScan, + crate::SubgroupOperation::Add, + ) => "SubgroupInclusiveAdd", + ( + crate::CollectiveOperation::InclusiveScan, + crate::SubgroupOperation::Mul, + ) => "SubgroupInclusiveMul", + _ => unimplemented!(), + } + } + S::SubgroupGather { + mode, + argument, + result, + } => { + match mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + self.dependencies.push((id, index, "index")) + } + } + self.dependencies.push((id, argument, "arg")); + self.emits.push((id, result)); + match mode { + crate::GatherMode::BroadcastFirst => "SubgroupBroadcastFirst", + crate::GatherMode::Broadcast(_) => "SubgroupBroadcast", + crate::GatherMode::Shuffle(_) => "SubgroupShuffle", + crate::GatherMode::ShuffleDown(_) => "SubgroupShuffleDown", + crate::GatherMode::ShuffleUp(_) => "SubgroupShuffleUp", + crate::GatherMode::ShuffleXor(_) => "SubgroupShuffleXor", + } + } }; // Set the last node to the merge node last_node = merge_id; @@ -404,6 +492,7 @@ fn write_function_expressions( let (label, color_id) = match *expression { E::Literal(_) => ("Literal".into(), 2), E::Constant(_) => ("Constant".into(), 2), + E::Override(_) => ("Override".into(), 2), E::ZeroValue(_) => ("ZeroValue".into(), 2), E::Compose { ref components, .. } => { payload = Some(Payload::Arguments(components)); @@ -586,6 +675,8 @@ fn write_function_expressions( let ty = if committed { "Committed" } else { "Candidate" }; (format!("rayQueryGet{}Intersection", ty).into(), 4) } + E::SubgroupBallotResult => ("SubgroupBallotResult".into(), 4), + E::SubgroupOperationResult { .. } => ("SubgroupOperationResult".into(), 4), }; // give uniform expressions an outline diff --git a/third_party/rust/naga/src/back/glsl/features.rs b/third_party/rust/naga/src/back/glsl/features.rs index 99c128c6d9..e5a43f3e02 100644 --- a/third_party/rust/naga/src/back/glsl/features.rs +++ b/third_party/rust/naga/src/back/glsl/features.rs @@ -50,6 +50,8 @@ bitflags::bitflags! { const INSTANCE_INDEX = 1 << 22; /// Sample specific LODs of cube / array shadow textures const TEXTURE_SHADOW_LOD = 1 << 23; + /// Subgroup operations + const SUBGROUP_OPERATIONS = 1 << 24; } } @@ -117,6 +119,7 @@ impl FeaturesManager { check_feature!(SAMPLE_VARIABLES, 400, 300); check_feature!(DYNAMIC_ARRAY_SIZE, 430, 310); check_feature!(DUAL_SOURCE_BLENDING, 330, 300 /* with extension */); + check_feature!(SUBGROUP_OPERATIONS, 430, 310); match version { Version::Embedded { is_webgl: true, .. } => check_feature!(MULTI_VIEW, 140, 300), _ => check_feature!(MULTI_VIEW, 140, 310), @@ -259,6 +262,22 @@ impl FeaturesManager { writeln!(out, "#extension GL_EXT_texture_shadow_lod : require")?; } + if self.0.contains(Features::SUBGROUP_OPERATIONS) { + // https://registry.khronos.org/OpenGL/extensions/KHR/KHR_shader_subgroup.txt + writeln!(out, "#extension GL_KHR_shader_subgroup_basic : require")?; + writeln!(out, "#extension GL_KHR_shader_subgroup_vote : require")?; + writeln!( + out, + "#extension GL_KHR_shader_subgroup_arithmetic : require" + )?; + writeln!(out, "#extension GL_KHR_shader_subgroup_ballot : require")?; + writeln!(out, "#extension GL_KHR_shader_subgroup_shuffle : require")?; + writeln!( + out, + "#extension GL_KHR_shader_subgroup_shuffle_relative : require" + )?; + } + Ok(()) } } @@ -518,6 +537,10 @@ impl<'a, W> Writer<'a, W> { } } } + Expression::SubgroupBallotResult | + Expression::SubgroupOperationResult { .. } => { + features.request(Features::SUBGROUP_OPERATIONS) + } _ => {} } } diff --git a/third_party/rust/naga/src/back/glsl/mod.rs b/third_party/rust/naga/src/back/glsl/mod.rs index 9bda594610..c8c7ea557d 100644 --- a/third_party/rust/naga/src/back/glsl/mod.rs +++ b/third_party/rust/naga/src/back/glsl/mod.rs @@ -282,7 +282,7 @@ impl Default for Options { } /// A subset of options meant to be changed per pipeline. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct PipelineOptions { @@ -497,6 +497,8 @@ pub enum Error { ImageMultipleSamplers, #[error("{0}")] Custom(String), + #[error("overrides should not be present at this stage")] + Override, } /// Binary operation with a different logic on the GLSL side. @@ -565,6 +567,10 @@ impl<'a, W: Write> Writer<'a, W> { pipeline_options: &'a PipelineOptions, policies: proc::BoundsCheckPolicies, ) -> Result { + if !module.overrides.is_empty() { + return Err(Error::Override); + } + // Check if the requested version is supported if !options.version.is_supported() { log::error!("Version {}", options.version); @@ -2384,6 +2390,125 @@ impl<'a, W: Write> Writer<'a, W> { writeln!(self.out, ");")?; } Statement::RayQuery { .. } => unreachable!(), + Statement::SubgroupBallot { result, predicate } => { + write!(self.out, "{level}")?; + let res_name = format!("{}{}", back::BAKE_PREFIX, result.index()); + let res_ty = ctx.info[result].ty.inner_with(&self.module.types); + self.write_value_type(res_ty)?; + write!(self.out, " {res_name} = ")?; + self.named_expressions.insert(result, res_name); + + write!(self.out, "subgroupBallot(")?; + match predicate { + Some(predicate) => self.write_expr(predicate, ctx)?, + None => write!(self.out, "true")?, + } + writeln!(self.out, ");")?; + } + Statement::SubgroupCollectiveOperation { + op, + collective_op, + argument, + result, + } => { + write!(self.out, "{level}")?; + let res_name = format!("{}{}", back::BAKE_PREFIX, result.index()); + let res_ty = ctx.info[result].ty.inner_with(&self.module.types); + self.write_value_type(res_ty)?; + write!(self.out, " {res_name} = ")?; + self.named_expressions.insert(result, res_name); + + match (collective_op, op) { + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::All) => { + write!(self.out, "subgroupAll(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Any) => { + write!(self.out, "subgroupAny(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Add) => { + write!(self.out, "subgroupAdd(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Mul) => { + write!(self.out, "subgroupMul(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Max) => { + write!(self.out, "subgroupMax(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Min) => { + write!(self.out, "subgroupMin(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::And) => { + write!(self.out, "subgroupAnd(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Or) => { + write!(self.out, "subgroupOr(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Xor) => { + write!(self.out, "subgroupXor(")? + } + (crate::CollectiveOperation::ExclusiveScan, crate::SubgroupOperation::Add) => { + write!(self.out, "subgroupExclusiveAdd(")? + } + (crate::CollectiveOperation::ExclusiveScan, crate::SubgroupOperation::Mul) => { + write!(self.out, "subgroupExclusiveMul(")? + } + (crate::CollectiveOperation::InclusiveScan, crate::SubgroupOperation::Add) => { + write!(self.out, "subgroupInclusiveAdd(")? + } + (crate::CollectiveOperation::InclusiveScan, crate::SubgroupOperation::Mul) => { + write!(self.out, "subgroupInclusiveMul(")? + } + _ => unimplemented!(), + } + self.write_expr(argument, ctx)?; + writeln!(self.out, ");")?; + } + Statement::SubgroupGather { + mode, + argument, + result, + } => { + write!(self.out, "{level}")?; + let res_name = format!("{}{}", back::BAKE_PREFIX, result.index()); + let res_ty = ctx.info[result].ty.inner_with(&self.module.types); + self.write_value_type(res_ty)?; + write!(self.out, " {res_name} = ")?; + self.named_expressions.insert(result, res_name); + + match mode { + crate::GatherMode::BroadcastFirst => { + write!(self.out, "subgroupBroadcastFirst(")?; + } + crate::GatherMode::Broadcast(_) => { + write!(self.out, "subgroupBroadcast(")?; + } + crate::GatherMode::Shuffle(_) => { + write!(self.out, "subgroupShuffle(")?; + } + crate::GatherMode::ShuffleDown(_) => { + write!(self.out, "subgroupShuffleDown(")?; + } + crate::GatherMode::ShuffleUp(_) => { + write!(self.out, "subgroupShuffleUp(")?; + } + crate::GatherMode::ShuffleXor(_) => { + write!(self.out, "subgroupShuffleXor(")?; + } + } + self.write_expr(argument, ctx)?; + match mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + write!(self.out, ", ")?; + self.write_expr(index, ctx)?; + } + } + writeln!(self.out, ");")?; + } } Ok(()) @@ -2402,7 +2527,7 @@ impl<'a, W: Write> Writer<'a, W> { fn write_const_expr(&mut self, expr: Handle) -> BackendResult { self.write_possibly_const_expr( expr, - &self.module.const_expressions, + &self.module.global_expressions, |expr| &self.info[expr], |writer, expr| writer.write_const_expr(expr), ) @@ -2536,6 +2661,7 @@ impl<'a, W: Write> Writer<'a, W> { |writer, expr| writer.write_expr(expr, ctx), )?; } + Expression::Override(_) => return Err(Error::Override), // `Access` is applied to arrays, vectors and matrices and is written as indexing Expression::Access { base, index } => { self.write_expr(base, ctx)?; @@ -3411,7 +3537,8 @@ impl<'a, W: Write> Writer<'a, W> { let scalar_bits = ctx .resolve_type(arg, &self.module.types) .scalar_width() - .unwrap(); + .unwrap() + * 8; write!(self.out, "bitfieldExtract(")?; self.write_expr(arg, ctx)?; @@ -3430,7 +3557,8 @@ impl<'a, W: Write> Writer<'a, W> { let scalar_bits = ctx .resolve_type(arg, &self.module.types) .scalar_width() - .unwrap(); + .unwrap() + * 8; write!(self.out, "bitfieldInsert(")?; self.write_expr(arg, ctx)?; @@ -3649,7 +3777,9 @@ impl<'a, W: Write> Writer<'a, W> { Expression::CallResult(_) | Expression::AtomicResult { .. } | Expression::RayQueryProceedResult - | Expression::WorkGroupUniformLoadResult { .. } => unreachable!(), + | Expression::WorkGroupUniformLoadResult { .. } + | Expression::SubgroupOperationResult { .. } + | Expression::SubgroupBallotResult => unreachable!(), // `ArrayLength` is written as `expr.length()` and we convert it to a uint Expression::ArrayLength(expr) => { write!(self.out, "uint(")?; @@ -4218,6 +4348,9 @@ impl<'a, W: Write> Writer<'a, W> { if flags.contains(crate::Barrier::WORK_GROUP) { writeln!(self.out, "{level}memoryBarrierShared();")?; } + if flags.contains(crate::Barrier::SUB_GROUP) { + writeln!(self.out, "{level}subgroupMemoryBarrier();")?; + } writeln!(self.out, "{level}barrier();")?; Ok(()) } @@ -4487,6 +4620,11 @@ const fn glsl_built_in(built_in: crate::BuiltIn, options: VaryingOptions) -> &'s Bi::WorkGroupId => "gl_WorkGroupID", Bi::WorkGroupSize => "gl_WorkGroupSize", Bi::NumWorkGroups => "gl_NumWorkGroups", + // subgroup + Bi::NumSubgroups => "gl_NumSubgroups", + Bi::SubgroupId => "gl_SubgroupID", + Bi::SubgroupSize => "gl_SubgroupSize", + Bi::SubgroupInvocationId => "gl_SubgroupInvocationID", } } diff --git a/third_party/rust/naga/src/back/hlsl/conv.rs b/third_party/rust/naga/src/back/hlsl/conv.rs index 2a6db35db8..7d15f43f6c 100644 --- a/third_party/rust/naga/src/back/hlsl/conv.rs +++ b/third_party/rust/naga/src/back/hlsl/conv.rs @@ -179,6 +179,11 @@ impl crate::BuiltIn { // to this field will get replaced with references to `SPECIAL_CBUF_VAR` // in `Writer::write_expr`. Self::NumWorkGroups => "SV_GroupID", + // These builtins map to functions + Self::SubgroupSize + | Self::SubgroupInvocationId + | Self::NumSubgroups + | Self::SubgroupId => unreachable!(), Self::BaseInstance | Self::BaseVertex | Self::WorkGroupSize => { return Err(Error::Unimplemented(format!("builtin {self:?}"))) } diff --git a/third_party/rust/naga/src/back/hlsl/help.rs b/third_party/rust/naga/src/back/hlsl/help.rs index 4dd9ea5987..d3bb1ce7f5 100644 --- a/third_party/rust/naga/src/back/hlsl/help.rs +++ b/third_party/rust/naga/src/back/hlsl/help.rs @@ -70,6 +70,11 @@ pub(super) struct WrappedMath { pub(super) components: Option, } +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +pub(super) struct WrappedZeroValue { + pub(super) ty: Handle, +} + /// HLSL backend requires its own `ImageQuery` enum. /// /// It is used inside `WrappedImageQuery` and should be unique per ImageQuery function. @@ -359,7 +364,7 @@ impl<'a, W: Write> super::Writer<'a, W> { } /// Helper function that write wrapped function for `Expression::Compose` for structures. - pub(super) fn write_wrapped_constructor_function( + fn write_wrapped_constructor_function( &mut self, module: &crate::Module, constructor: WrappedConstructor, @@ -862,6 +867,25 @@ impl<'a, W: Write> super::Writer<'a, W> { Ok(()) } + // TODO: we could merge this with iteration in write_wrapped_compose_functions... + // + /// Helper function that writes zero value wrapped functions + pub(super) fn write_wrapped_zero_value_functions( + &mut self, + module: &crate::Module, + expressions: &crate::Arena, + ) -> BackendResult { + for (handle, _) in expressions.iter() { + if let crate::Expression::ZeroValue(ty) = expressions[handle] { + let zero_value = WrappedZeroValue { ty }; + if self.wrapped.zero_values.insert(zero_value) { + self.write_wrapped_zero_value_function(module, zero_value)?; + } + } + } + Ok(()) + } + pub(super) fn write_wrapped_math_functions( &mut self, module: &crate::Module, @@ -1006,6 +1030,7 @@ impl<'a, W: Write> super::Writer<'a, W> { ) -> BackendResult { self.write_wrapped_math_functions(module, func_ctx)?; self.write_wrapped_compose_functions(module, func_ctx.expressions)?; + self.write_wrapped_zero_value_functions(module, func_ctx.expressions)?; for (handle, _) in func_ctx.expressions.iter() { match func_ctx.expressions[handle] { @@ -1283,4 +1308,71 @@ impl<'a, W: Write> super::Writer<'a, W> { Ok(()) } + + pub(super) fn write_wrapped_zero_value_function_name( + &mut self, + module: &crate::Module, + zero_value: WrappedZeroValue, + ) -> BackendResult { + let name = crate::TypeInner::hlsl_type_id(zero_value.ty, module.to_ctx(), &self.names)?; + write!(self.out, "ZeroValue{name}")?; + Ok(()) + } + + /// Helper function that write wrapped function for `Expression::ZeroValue` + /// + /// This is necessary since we might have a member access after the zero value expression, e.g. + /// `.y` (in practice this can come up when consuming SPIRV that's been produced by glslc). + /// + /// So we can't just write `(float4)0` since `(float4)0.y` won't parse correctly. + /// + /// Parenthesizing the expression like `((float4)0).y` would work... except DXC can't handle + /// cases like: + /// + /// ```ignore + /// tests\out\hlsl\access.hlsl:183:41: error: cannot compile this l-value expression yet + /// t_1.am = (__mat4x2[2])((float4x2[2])0); + /// ^ + /// ``` + fn write_wrapped_zero_value_function( + &mut self, + module: &crate::Module, + zero_value: WrappedZeroValue, + ) -> BackendResult { + use crate::back::INDENT; + + const RETURN_VARIABLE_NAME: &str = "ret"; + + // Write function return type and name + if let crate::TypeInner::Array { base, size, .. } = module.types[zero_value.ty].inner { + write!(self.out, "typedef ")?; + self.write_type(module, zero_value.ty)?; + write!(self.out, " ret_")?; + self.write_wrapped_zero_value_function_name(module, zero_value)?; + self.write_array_size(module, base, size)?; + writeln!(self.out, ";")?; + + write!(self.out, "ret_")?; + self.write_wrapped_zero_value_function_name(module, zero_value)?; + } else { + self.write_type(module, zero_value.ty)?; + } + write!(self.out, " ")?; + self.write_wrapped_zero_value_function_name(module, zero_value)?; + + // Write function parameters (none) and start function body + writeln!(self.out, "() {{")?; + + // Write `ZeroValue` function. + write!(self.out, "{INDENT}return ")?; + self.write_default_init(module, zero_value.ty)?; + writeln!(self.out, ";")?; + + // End of function body + writeln!(self.out, "}}")?; + // Write extra new line + writeln!(self.out)?; + + Ok(()) + } } diff --git a/third_party/rust/naga/src/back/hlsl/mod.rs b/third_party/rust/naga/src/back/hlsl/mod.rs index f37a223f47..28edbf70e1 100644 --- a/third_party/rust/naga/src/back/hlsl/mod.rs +++ b/third_party/rust/naga/src/back/hlsl/mod.rs @@ -131,6 +131,13 @@ pub enum ShaderModel { V5_0, V5_1, V6_0, + V6_1, + V6_2, + V6_3, + V6_4, + V6_5, + V6_6, + V6_7, } impl ShaderModel { @@ -139,6 +146,13 @@ impl ShaderModel { Self::V5_0 => "5_0", Self::V5_1 => "5_1", Self::V6_0 => "6_0", + Self::V6_1 => "6_1", + Self::V6_2 => "6_2", + Self::V6_3 => "6_3", + Self::V6_4 => "6_4", + Self::V6_5 => "6_5", + Self::V6_6 => "6_6", + Self::V6_7 => "6_7", } } } @@ -247,10 +261,13 @@ pub enum Error { Unimplemented(String), // TODO: Error used only during development #[error("{0}")] Custom(String), + #[error("overrides should not be present at this stage")] + Override, } #[derive(Default)] struct Wrapped { + zero_values: crate::FastHashSet, array_lengths: crate::FastHashSet, image_queries: crate::FastHashSet, constructors: crate::FastHashSet, diff --git a/third_party/rust/naga/src/back/hlsl/writer.rs b/third_party/rust/naga/src/back/hlsl/writer.rs index 4ba856946b..86d8f89035 100644 --- a/third_party/rust/naga/src/back/hlsl/writer.rs +++ b/third_party/rust/naga/src/back/hlsl/writer.rs @@ -1,5 +1,8 @@ use super::{ - help::{WrappedArrayLength, WrappedConstructor, WrappedImageQuery, WrappedStructMatrixAccess}, + help::{ + WrappedArrayLength, WrappedConstructor, WrappedImageQuery, WrappedStructMatrixAccess, + WrappedZeroValue, + }, storage::StoreValue, BackendResult, Error, Options, }; @@ -77,6 +80,19 @@ enum Io { Output, } +const fn is_subgroup_builtin_binding(binding: &Option) -> bool { + let &Some(crate::Binding::BuiltIn(builtin)) = binding else { + return false; + }; + matches!( + builtin, + crate::BuiltIn::SubgroupSize + | crate::BuiltIn::SubgroupInvocationId + | crate::BuiltIn::NumSubgroups + | crate::BuiltIn::SubgroupId + ) +} + impl<'a, W: fmt::Write> super::Writer<'a, W> { pub fn new(out: W, options: &'a Options) -> Self { Self { @@ -161,6 +177,19 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } } } + for statement in func.body.iter() { + match *statement { + crate::Statement::SubgroupCollectiveOperation { + op: _, + collective_op: crate::CollectiveOperation::InclusiveScan, + argument, + result: _, + } => { + self.need_bake_expressions.insert(argument); + } + _ => {} + } + } } pub fn write( @@ -168,6 +197,10 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { module: &Module, module_info: &valid::ModuleInfo, ) -> Result { + if !module.overrides.is_empty() { + return Err(Error::Override); + } + self.reset(module); // Write special constants, if needed @@ -233,7 +266,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { self.write_special_functions(module)?; - self.write_wrapped_compose_functions(module, &module.const_expressions)?; + self.write_wrapped_compose_functions(module, &module.global_expressions)?; + self.write_wrapped_zero_value_functions(module, &module.global_expressions)?; // Write all named constants let mut constants = module @@ -397,31 +431,32 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { // if they are struct, so that the `stage` argument here could be omitted. fn write_semantic( &mut self, - binding: &crate::Binding, + binding: &Option, stage: Option<(ShaderStage, Io)>, ) -> BackendResult { match *binding { - crate::Binding::BuiltIn(builtin) => { + Some(crate::Binding::BuiltIn(builtin)) if !is_subgroup_builtin_binding(binding) => { let builtin_str = builtin.to_hlsl_str()?; write!(self.out, " : {builtin_str}")?; } - crate::Binding::Location { + Some(crate::Binding::Location { second_blend_source: true, .. - } => { + }) => { write!(self.out, " : SV_Target1")?; } - crate::Binding::Location { + Some(crate::Binding::Location { location, second_blend_source: false, .. - } => { + }) => { if stage == Some((crate::ShaderStage::Fragment, Io::Output)) { write!(self.out, " : SV_Target{location}")?; } else { write!(self.out, " : {LOCATION_SEMANTIC}{location}")?; } } + _ => {} } Ok(()) @@ -442,17 +477,30 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, "struct {struct_name}")?; writeln!(self.out, " {{")?; for m in members.iter() { + if is_subgroup_builtin_binding(&m.binding) { + continue; + } write!(self.out, "{}", back::INDENT)?; if let Some(ref binding) = m.binding { self.write_modifier(binding)?; } self.write_type(module, m.ty)?; write!(self.out, " {}", &m.name)?; - if let Some(ref binding) = m.binding { - self.write_semantic(binding, Some(shader_stage))?; - } + self.write_semantic(&m.binding, Some(shader_stage))?; writeln!(self.out, ";")?; } + if members.iter().any(|arg| { + matches!( + arg.binding, + Some(crate::Binding::BuiltIn(crate::BuiltIn::SubgroupId)) + ) + }) { + writeln!( + self.out, + "{}uint __local_invocation_index : SV_GroupIndex;", + back::INDENT + )?; + } writeln!(self.out, "}};")?; writeln!(self.out)?; @@ -553,8 +601,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } /// Writes special interface structures for an entry point. The special structures have - /// all the fields flattened into them and sorted by binding. They are only needed for - /// VS outputs and FS inputs, so that these interfaces match. + /// all the fields flattened into them and sorted by binding. They are needed to emulate + /// subgroup built-ins and to make the interfaces between VS outputs and FS inputs match. fn write_ep_interface( &mut self, module: &Module, @@ -563,7 +611,13 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { ep_name: &str, ) -> Result { Ok(EntryPointInterface { - input: if !func.arguments.is_empty() && stage == ShaderStage::Fragment { + input: if !func.arguments.is_empty() + && (stage == ShaderStage::Fragment + || func + .arguments + .iter() + .any(|arg| is_subgroup_builtin_binding(&arg.binding))) + { Some(self.write_ep_input_struct(module, func, stage, ep_name)?) } else { None @@ -577,6 +631,38 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { }) } + fn write_ep_argument_initialization( + &mut self, + ep: &crate::EntryPoint, + ep_input: &EntryPointBinding, + fake_member: &EpStructMember, + ) -> BackendResult { + match fake_member.binding { + Some(crate::Binding::BuiltIn(crate::BuiltIn::SubgroupSize)) => { + write!(self.out, "WaveGetLaneCount()")? + } + Some(crate::Binding::BuiltIn(crate::BuiltIn::SubgroupInvocationId)) => { + write!(self.out, "WaveGetLaneIndex()")? + } + Some(crate::Binding::BuiltIn(crate::BuiltIn::NumSubgroups)) => write!( + self.out, + "({}u + WaveGetLaneCount() - 1u) / WaveGetLaneCount()", + ep.workgroup_size[0] * ep.workgroup_size[1] * ep.workgroup_size[2] + )?, + Some(crate::Binding::BuiltIn(crate::BuiltIn::SubgroupId)) => { + write!( + self.out, + "{}.__local_invocation_index / WaveGetLaneCount()", + ep_input.arg_name + )?; + } + _ => { + write!(self.out, "{}.{}", ep_input.arg_name, fake_member.name)?; + } + } + Ok(()) + } + /// Write an entry point preface that initializes the arguments as specified in IR. fn write_ep_arguments_initialization( &mut self, @@ -584,6 +670,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { func: &crate::Function, ep_index: u16, ) -> BackendResult { + let ep = &module.entry_points[ep_index as usize]; let ep_input = match self.entry_point_io[ep_index as usize].input.take() { Some(ep_input) => ep_input, None => return Ok(()), @@ -597,8 +684,13 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { match module.types[arg.ty].inner { TypeInner::Array { base, size, .. } => { self.write_array_size(module, base, size)?; - let fake_member = fake_iter.next().unwrap(); - writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?; + write!(self.out, " = ")?; + self.write_ep_argument_initialization( + ep, + &ep_input, + fake_iter.next().unwrap(), + )?; + writeln!(self.out, ";")?; } TypeInner::Struct { ref members, .. } => { write!(self.out, " = {{ ")?; @@ -606,14 +698,22 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { if index != 0 { write!(self.out, ", ")?; } - let fake_member = fake_iter.next().unwrap(); - write!(self.out, "{}.{}", ep_input.arg_name, fake_member.name)?; + self.write_ep_argument_initialization( + ep, + &ep_input, + fake_iter.next().unwrap(), + )?; } writeln!(self.out, " }};")?; } _ => { - let fake_member = fake_iter.next().unwrap(); - writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?; + write!(self.out, " = ")?; + self.write_ep_argument_initialization( + ep, + &ep_input, + fake_iter.next().unwrap(), + )?; + writeln!(self.out, ";")?; } } } @@ -928,9 +1028,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } } - if let Some(ref binding) = member.binding { - self.write_semantic(binding, shader_stage)?; - }; + self.write_semantic(&member.binding, shader_stage)?; writeln!(self.out, ";")?; } @@ -1143,7 +1241,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } back::FunctionType::EntryPoint(ep_index) => { if let Some(ref ep_input) = self.entry_point_io[ep_index as usize].input { - write!(self.out, "{} {}", ep_input.ty_name, ep_input.arg_name,)?; + write!(self.out, "{} {}", ep_input.ty_name, ep_input.arg_name)?; } else { let stage = module.entry_points[ep_index as usize].stage; for (index, arg) in func.arguments.iter().enumerate() { @@ -1160,17 +1258,16 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { self.write_array_size(module, base, size)?; } - if let Some(ref binding) = arg.binding { - self.write_semantic(binding, Some((stage, Io::Input)))?; - } + self.write_semantic(&arg.binding, Some((stage, Io::Input)))?; } - - if need_workgroup_variables_initialization { - if !func.arguments.is_empty() { - write!(self.out, ", ")?; - } - write!(self.out, "uint3 __local_invocation_id : SV_GroupThreadID")?; + } + if need_workgroup_variables_initialization { + if self.entry_point_io[ep_index as usize].input.is_some() + || !func.arguments.is_empty() + { + write!(self.out, ", ")?; } + write!(self.out, "uint3 __local_invocation_id : SV_GroupThreadID")?; } } } @@ -1180,11 +1277,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { // Write semantic if it present if let back::FunctionType::EntryPoint(index) = func_ctx.ty { let stage = module.entry_points[index as usize].stage; - if let Some(crate::FunctionResult { - binding: Some(ref binding), - .. - }) = func.result - { + if let Some(crate::FunctionResult { ref binding, .. }) = func.result { self.write_semantic(binding, Some((stage, Io::Output)))?; } } @@ -1984,6 +2077,129 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { writeln!(self.out, "{level}}}")? } Statement::RayQuery { .. } => unreachable!(), + Statement::SubgroupBallot { result, predicate } => { + write!(self.out, "{level}")?; + let name = format!("{}{}", back::BAKE_PREFIX, result.index()); + write!(self.out, "const uint4 {name} = ")?; + self.named_expressions.insert(result, name); + + write!(self.out, "WaveActiveBallot(")?; + match predicate { + Some(predicate) => self.write_expr(module, predicate, func_ctx)?, + None => write!(self.out, "true")?, + } + writeln!(self.out, ");")?; + } + Statement::SubgroupCollectiveOperation { + op, + collective_op, + argument, + result, + } => { + write!(self.out, "{level}")?; + write!(self.out, "const ")?; + let name = format!("{}{}", back::BAKE_PREFIX, result.index()); + match func_ctx.info[result].ty { + proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?, + proc::TypeResolution::Value(ref value) => { + self.write_value_type(module, value)? + } + }; + write!(self.out, " {name} = ")?; + self.named_expressions.insert(result, name); + + match (collective_op, op) { + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::All) => { + write!(self.out, "WaveActiveAllTrue(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Any) => { + write!(self.out, "WaveActiveAnyTrue(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Add) => { + write!(self.out, "WaveActiveSum(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Mul) => { + write!(self.out, "WaveActiveProduct(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Max) => { + write!(self.out, "WaveActiveMax(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Min) => { + write!(self.out, "WaveActiveMin(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::And) => { + write!(self.out, "WaveActiveBitAnd(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Or) => { + write!(self.out, "WaveActiveBitOr(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Xor) => { + write!(self.out, "WaveActiveBitXor(")? + } + (crate::CollectiveOperation::ExclusiveScan, crate::SubgroupOperation::Add) => { + write!(self.out, "WavePrefixSum(")? + } + (crate::CollectiveOperation::ExclusiveScan, crate::SubgroupOperation::Mul) => { + write!(self.out, "WavePrefixProduct(")? + } + (crate::CollectiveOperation::InclusiveScan, crate::SubgroupOperation::Add) => { + self.write_expr(module, argument, func_ctx)?; + write!(self.out, " + WavePrefixSum(")?; + } + (crate::CollectiveOperation::InclusiveScan, crate::SubgroupOperation::Mul) => { + self.write_expr(module, argument, func_ctx)?; + write!(self.out, " * WavePrefixProduct(")?; + } + _ => unimplemented!(), + } + self.write_expr(module, argument, func_ctx)?; + writeln!(self.out, ");")?; + } + Statement::SubgroupGather { + mode, + argument, + result, + } => { + write!(self.out, "{level}")?; + write!(self.out, "const ")?; + let name = format!("{}{}", back::BAKE_PREFIX, result.index()); + match func_ctx.info[result].ty { + proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?, + proc::TypeResolution::Value(ref value) => { + self.write_value_type(module, value)? + } + }; + write!(self.out, " {name} = ")?; + self.named_expressions.insert(result, name); + + if matches!(mode, crate::GatherMode::BroadcastFirst) { + write!(self.out, "WaveReadLaneFirst(")?; + self.write_expr(module, argument, func_ctx)?; + } else { + write!(self.out, "WaveReadLaneAt(")?; + self.write_expr(module, argument, func_ctx)?; + write!(self.out, ", ")?; + match mode { + crate::GatherMode::BroadcastFirst => unreachable!(), + crate::GatherMode::Broadcast(index) | crate::GatherMode::Shuffle(index) => { + self.write_expr(module, index, func_ctx)?; + } + crate::GatherMode::ShuffleDown(index) => { + write!(self.out, "WaveGetLaneIndex() + ")?; + self.write_expr(module, index, func_ctx)?; + } + crate::GatherMode::ShuffleUp(index) => { + write!(self.out, "WaveGetLaneIndex() - ")?; + self.write_expr(module, index, func_ctx)?; + } + crate::GatherMode::ShuffleXor(index) => { + write!(self.out, "WaveGetLaneIndex() ^ ")?; + self.write_expr(module, index, func_ctx)?; + } + } + } + writeln!(self.out, ");")?; + } } Ok(()) @@ -1997,7 +2213,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { self.write_possibly_const_expression( module, expr, - &module.const_expressions, + &module.global_expressions, |writer, expr| writer.write_const_expression(module, expr), ) } @@ -2039,7 +2255,10 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { self.write_const_expression(module, constant.init)?; } } - Expression::ZeroValue(ty) => self.write_default_init(module, ty)?, + Expression::ZeroValue(ty) => { + self.write_wrapped_zero_value_function_name(module, WrappedZeroValue { ty })?; + write!(self.out, "()")?; + } Expression::Compose { ty, ref components } => { match module.types[ty].inner { TypeInner::Struct { .. } | TypeInner::Array { .. } => { @@ -2140,6 +2359,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { |writer, expr| writer.write_expr(module, expr, func_ctx), )?; } + Expression::Override(_) => return Err(Error::Override), // All of the multiplication can be expressed as `mul`, // except vector * vector, which needs to use the "*" operator. Expression::Binary { @@ -2588,7 +2808,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { true } None => { - if inner.scalar_width() == Some(64) { + if inner.scalar_width() == Some(8) { false } else { write!(self.out, "{}(", kind.to_hlsl_cast(),)?; @@ -3129,7 +3349,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { Expression::CallResult(_) | Expression::AtomicResult { .. } | Expression::WorkGroupUniformLoadResult { .. } - | Expression::RayQueryProceedResult => {} + | Expression::RayQueryProceedResult + | Expression::SubgroupBallotResult + | Expression::SubgroupOperationResult { .. } => {} } if !closing_bracket.is_empty() { @@ -3179,7 +3401,11 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } /// Helper function that write default zero initialization - fn write_default_init(&mut self, module: &Module, ty: Handle) -> BackendResult { + pub(super) fn write_default_init( + &mut self, + module: &Module, + ty: Handle, + ) -> BackendResult { write!(self.out, "(")?; self.write_type(module, ty)?; if let TypeInner::Array { base, size, .. } = module.types[ty].inner { @@ -3196,6 +3422,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { if barrier.contains(crate::Barrier::WORK_GROUP) { writeln!(self.out, "{level}GroupMemoryBarrierWithGroupSync();")?; } + if barrier.contains(crate::Barrier::SUB_GROUP) { + // Does not exist in DirectX + } Ok(()) } } diff --git a/third_party/rust/naga/src/back/mod.rs b/third_party/rust/naga/src/back/mod.rs index c8f091decb..0c9c5e4761 100644 --- a/third_party/rust/naga/src/back/mod.rs +++ b/third_party/rust/naga/src/back/mod.rs @@ -16,6 +16,14 @@ pub mod spv; #[cfg(feature = "wgsl-out")] pub mod wgsl; +#[cfg(any( + feature = "hlsl-out", + feature = "msl-out", + feature = "spv-out", + feature = "glsl-out" +))] +pub mod pipeline_constants; + /// Names of vector components. pub const COMPONENTS: &[char] = &['x', 'y', 'z', 'w']; /// Indent for backends. @@ -26,6 +34,15 @@ pub const BAKE_PREFIX: &str = "_e"; /// Expressions that need baking. pub type NeedBakeExpressions = crate::FastHashSet>; +/// Specifies the values of pipeline-overridable constants in the shader module. +/// +/// If an `@id` attribute was specified on the declaration, +/// the key must be the pipeline constant ID as a decimal ASCII number; if not, +/// the key must be the constant's identifier name. +/// +/// The value may represent any of WGSL's concrete scalar types. +pub type PipelineConstants = std::collections::HashMap; + /// Indentation level. #[derive(Clone, Copy)] pub struct Level(pub usize); diff --git a/third_party/rust/naga/src/back/msl/mod.rs b/third_party/rust/naga/src/back/msl/mod.rs index 68e5b79906..8b03e20376 100644 --- a/third_party/rust/naga/src/back/msl/mod.rs +++ b/third_party/rust/naga/src/back/msl/mod.rs @@ -143,6 +143,8 @@ pub enum Error { UnsupportedArrayOfType(Handle), #[error("ray tracing is not supported prior to MSL 2.3")] UnsupportedRayTracing, + #[error("overrides should not be present at this stage")] + Override, } #[derive(Clone, Debug, PartialEq, thiserror::Error)] @@ -221,7 +223,7 @@ impl Default for Options { } /// A subset of options that are meant to be changed per pipeline. -#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct PipelineOptions { @@ -434,6 +436,11 @@ impl ResolvedBinding { Bi::WorkGroupId => "threadgroup_position_in_grid", Bi::WorkGroupSize => "dispatch_threads_per_threadgroup", Bi::NumWorkGroups => "threadgroups_per_grid", + // subgroup + Bi::NumSubgroups => "simdgroups_per_threadgroup", + Bi::SubgroupId => "simdgroup_index_in_threadgroup", + Bi::SubgroupSize => "threads_per_simdgroup", + Bi::SubgroupInvocationId => "thread_index_in_simdgroup", Bi::CullDistance | Bi::ViewIndex => { return Err(Error::UnsupportedBuiltIn(built_in)) } @@ -536,3 +543,21 @@ fn test_error_size() { use std::mem::size_of; assert_eq!(size_of::(), 32); } + +impl crate::AtomicFunction { + fn to_msl(self) -> Result<&'static str, Error> { + Ok(match self { + Self::Add => "fetch_add", + Self::Subtract => "fetch_sub", + Self::And => "fetch_and", + Self::InclusiveOr => "fetch_or", + Self::ExclusiveOr => "fetch_xor", + Self::Min => "fetch_min", + Self::Max => "fetch_max", + Self::Exchange { compare: None } => "exchange", + Self::Exchange { compare: Some(_) } => Err(Error::FeatureNotImplemented( + "atomic CompareExchange".to_string(), + ))?, + }) + } +} diff --git a/third_party/rust/naga/src/back/msl/writer.rs b/third_party/rust/naga/src/back/msl/writer.rs index 5227d8e7db..e250d0b72c 100644 --- a/third_party/rust/naga/src/back/msl/writer.rs +++ b/third_party/rust/naga/src/back/msl/writer.rs @@ -1131,21 +1131,10 @@ impl Writer { Ok(()) } - fn put_atomic_fetch( - &mut self, - pointer: Handle, - key: &str, - value: Handle, - context: &ExpressionContext, - ) -> BackendResult { - self.put_atomic_operation(pointer, "fetch_", key, value, context) - } - fn put_atomic_operation( &mut self, pointer: Handle, - key1: &str, - key2: &str, + key: &str, value: Handle, context: &ExpressionContext, ) -> BackendResult { @@ -1163,7 +1152,7 @@ impl Writer { write!( self.out, - "{NAMESPACE}::atomic_{key1}{key2}_explicit({ATOMIC_REFERENCE}" + "{NAMESPACE}::atomic_{key}_explicit({ATOMIC_REFERENCE}" )?; self.put_access_chain(pointer, policy, context)?; write!(self.out, ", ")?; @@ -1248,7 +1237,7 @@ impl Writer { ) -> BackendResult { self.put_possibly_const_expression( expr_handle, - &module.const_expressions, + &module.global_expressions, module, mod_info, &(module, mod_info), @@ -1431,6 +1420,7 @@ impl Writer { |writer, context, expr| writer.put_expression(expr, context, true), )?; } + crate::Expression::Override(_) => return Err(Error::Override), crate::Expression::Access { base, .. } | crate::Expression::AccessIndex { base, .. } => { // This is an acceptable place to generate a `ReadZeroSkipWrite` check. @@ -1944,7 +1934,7 @@ impl Writer { // // extract_bits(e, min(offset, w), min(count, w - min(offset, w)))) - let scalar_bits = context.resolve_type(arg).scalar_width().unwrap(); + let scalar_bits = context.resolve_type(arg).scalar_width().unwrap() * 8; write!(self.out, "{NAMESPACE}::extract_bits(")?; self.put_expression(arg, context, true)?; @@ -1960,7 +1950,7 @@ impl Writer { // // insertBits(e, newBits, min(offset, w), min(count, w - min(offset, w)))) - let scalar_bits = context.resolve_type(arg).scalar_width().unwrap(); + let scalar_bits = context.resolve_type(arg).scalar_width().unwrap() * 8; write!(self.out, "{NAMESPACE}::insert_bits(")?; self.put_expression(arg, context, true)?; @@ -2041,6 +2031,8 @@ impl Writer { crate::Expression::CallResult(_) | crate::Expression::AtomicResult { .. } | crate::Expression::WorkGroupUniformLoadResult { .. } + | crate::Expression::SubgroupBallotResult + | crate::Expression::SubgroupOperationResult { .. } | crate::Expression::RayQueryProceedResult => { unreachable!() } @@ -2994,43 +2986,8 @@ impl Writer { let res_name = format!("{}{}", back::BAKE_PREFIX, result.index()); self.start_baking_expression(result, &context.expression, &res_name)?; self.named_expressions.insert(result, res_name); - match *fun { - crate::AtomicFunction::Add => { - self.put_atomic_fetch(pointer, "add", value, &context.expression)?; - } - crate::AtomicFunction::Subtract => { - self.put_atomic_fetch(pointer, "sub", value, &context.expression)?; - } - crate::AtomicFunction::And => { - self.put_atomic_fetch(pointer, "and", value, &context.expression)?; - } - crate::AtomicFunction::InclusiveOr => { - self.put_atomic_fetch(pointer, "or", value, &context.expression)?; - } - crate::AtomicFunction::ExclusiveOr => { - self.put_atomic_fetch(pointer, "xor", value, &context.expression)?; - } - crate::AtomicFunction::Min => { - self.put_atomic_fetch(pointer, "min", value, &context.expression)?; - } - crate::AtomicFunction::Max => { - self.put_atomic_fetch(pointer, "max", value, &context.expression)?; - } - crate::AtomicFunction::Exchange { compare: None } => { - self.put_atomic_operation( - pointer, - "exchange", - "", - value, - &context.expression, - )?; - } - crate::AtomicFunction::Exchange { .. } => { - return Err(Error::FeatureNotImplemented( - "atomic CompareExchange".to_string(), - )); - } - } + let fun_str = fun.to_msl()?; + self.put_atomic_operation(pointer, fun_str, value, &context.expression)?; // done writeln!(self.out, ";")?; } @@ -3144,6 +3101,121 @@ impl Writer { } } } + crate::Statement::SubgroupBallot { result, predicate } => { + write!(self.out, "{level}")?; + let name = self.namer.call(""); + self.start_baking_expression(result, &context.expression, &name)?; + self.named_expressions.insert(result, name); + write!(self.out, "uint4((uint64_t){NAMESPACE}::simd_ballot(")?; + if let Some(predicate) = predicate { + self.put_expression(predicate, &context.expression, true)?; + } else { + write!(self.out, "true")?; + } + writeln!(self.out, "), 0, 0, 0);")?; + } + crate::Statement::SubgroupCollectiveOperation { + op, + collective_op, + argument, + result, + } => { + write!(self.out, "{level}")?; + let name = self.namer.call(""); + self.start_baking_expression(result, &context.expression, &name)?; + self.named_expressions.insert(result, name); + match (collective_op, op) { + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::All) => { + write!(self.out, "{NAMESPACE}::simd_all(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Any) => { + write!(self.out, "{NAMESPACE}::simd_any(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Add) => { + write!(self.out, "{NAMESPACE}::simd_sum(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Mul) => { + write!(self.out, "{NAMESPACE}::simd_product(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Max) => { + write!(self.out, "{NAMESPACE}::simd_max(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Min) => { + write!(self.out, "{NAMESPACE}::simd_min(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::And) => { + write!(self.out, "{NAMESPACE}::simd_and(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Or) => { + write!(self.out, "{NAMESPACE}::simd_or(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Xor) => { + write!(self.out, "{NAMESPACE}::simd_xor(")? + } + ( + crate::CollectiveOperation::ExclusiveScan, + crate::SubgroupOperation::Add, + ) => write!(self.out, "{NAMESPACE}::simd_prefix_exclusive_sum(")?, + ( + crate::CollectiveOperation::ExclusiveScan, + crate::SubgroupOperation::Mul, + ) => write!(self.out, "{NAMESPACE}::simd_prefix_exclusive_product(")?, + ( + crate::CollectiveOperation::InclusiveScan, + crate::SubgroupOperation::Add, + ) => write!(self.out, "{NAMESPACE}::simd_prefix_inclusive_sum(")?, + ( + crate::CollectiveOperation::InclusiveScan, + crate::SubgroupOperation::Mul, + ) => write!(self.out, "{NAMESPACE}::simd_prefix_inclusive_product(")?, + _ => unimplemented!(), + } + self.put_expression(argument, &context.expression, true)?; + writeln!(self.out, ");")?; + } + crate::Statement::SubgroupGather { + mode, + argument, + result, + } => { + write!(self.out, "{level}")?; + let name = self.namer.call(""); + self.start_baking_expression(result, &context.expression, &name)?; + self.named_expressions.insert(result, name); + match mode { + crate::GatherMode::BroadcastFirst => { + write!(self.out, "{NAMESPACE}::simd_broadcast_first(")?; + } + crate::GatherMode::Broadcast(_) => { + write!(self.out, "{NAMESPACE}::simd_broadcast(")?; + } + crate::GatherMode::Shuffle(_) => { + write!(self.out, "{NAMESPACE}::simd_shuffle(")?; + } + crate::GatherMode::ShuffleDown(_) => { + write!(self.out, "{NAMESPACE}::simd_shuffle_down(")?; + } + crate::GatherMode::ShuffleUp(_) => { + write!(self.out, "{NAMESPACE}::simd_shuffle_up(")?; + } + crate::GatherMode::ShuffleXor(_) => { + write!(self.out, "{NAMESPACE}::simd_shuffle_xor(")?; + } + } + self.put_expression(argument, &context.expression, true)?; + match mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + write!(self.out, ", ")?; + self.put_expression(index, &context.expression, true)?; + } + } + writeln!(self.out, ");")?; + } } } @@ -3220,6 +3292,10 @@ impl Writer { options: &Options, pipeline_options: &PipelineOptions, ) -> Result { + if !module.overrides.is_empty() { + return Err(Error::Override); + } + self.names.clear(); self.namer.reset( module, @@ -4487,6 +4563,12 @@ impl Writer { "{level}{NAMESPACE}::threadgroup_barrier({NAMESPACE}::mem_flags::mem_threadgroup);", )?; } + if flags.contains(crate::Barrier::SUB_GROUP) { + writeln!( + self.out, + "{level}{NAMESPACE}::simdgroup_barrier({NAMESPACE}::mem_flags::mem_threadgroup);", + )?; + } Ok(()) } } @@ -4757,8 +4839,8 @@ fn test_stack_size() { } let stack_size = addresses_end - addresses_start; // check the size (in debug only) - // last observed macOS value: 19152 (CI) - if !(9000..=20000).contains(&stack_size) { + // last observed macOS value: 22256 (CI) + if !(15000..=25000).contains(&stack_size) { panic!("`put_block` stack size {stack_size} has changed!"); } } diff --git a/third_party/rust/naga/src/back/pipeline_constants.rs b/third_party/rust/naga/src/back/pipeline_constants.rs new file mode 100644 index 0000000000..0dbe9cf4e8 --- /dev/null +++ b/third_party/rust/naga/src/back/pipeline_constants.rs @@ -0,0 +1,957 @@ +use super::PipelineConstants; +use crate::{ + proc::{ConstantEvaluator, ConstantEvaluatorError, Emitter}, + valid::{Capabilities, ModuleInfo, ValidationError, ValidationFlags, Validator}, + Arena, Block, Constant, Expression, Function, Handle, Literal, Module, Override, Range, Scalar, + Span, Statement, TypeInner, WithSpan, +}; +use std::{borrow::Cow, collections::HashSet, mem}; +use thiserror::Error; + +#[derive(Error, Debug, Clone)] +#[cfg_attr(test, derive(PartialEq))] +pub enum PipelineConstantError { + #[error("Missing value for pipeline-overridable constant with identifier string: '{0}'")] + MissingValue(String), + #[error("Source f64 value needs to be finite (NaNs and Inifinites are not allowed) for number destinations")] + SrcNeedsToBeFinite, + #[error("Source f64 value doesn't fit in destination")] + DstRangeTooSmall, + #[error(transparent)] + ConstantEvaluatorError(#[from] ConstantEvaluatorError), + #[error(transparent)] + ValidationError(#[from] WithSpan), +} + +/// Replace all overrides in `module` with constants. +/// +/// If no changes are needed, this just returns `Cow::Borrowed` +/// references to `module` and `module_info`. Otherwise, it clones +/// `module`, edits its [`global_expressions`] arena to contain only +/// fully-evaluated expressions, and returns `Cow::Owned` values +/// holding the simplified module and its validation results. +/// +/// In either case, the module returned has an empty `overrides` +/// arena, and the `global_expressions` arena contains only +/// fully-evaluated expressions. +/// +/// [`global_expressions`]: Module::global_expressions +pub fn process_overrides<'a>( + module: &'a Module, + module_info: &'a ModuleInfo, + pipeline_constants: &PipelineConstants, +) -> Result<(Cow<'a, Module>, Cow<'a, ModuleInfo>), PipelineConstantError> { + if module.overrides.is_empty() { + return Ok((Cow::Borrowed(module), Cow::Borrowed(module_info))); + } + + let mut module = module.clone(); + + // A map from override handles to the handles of the constants + // we've replaced them with. + let mut override_map = Vec::with_capacity(module.overrides.len()); + + // A map from `module`'s original global expression handles to + // handles in the new, simplified global expression arena. + let mut adjusted_global_expressions = Vec::with_capacity(module.global_expressions.len()); + + // The set of constants whose initializer handles we've already + // updated to refer to the newly built global expression arena. + // + // All constants in `module` must have their `init` handles + // updated to point into the new, simplified global expression + // arena. Some of these we can most easily handle as a side effect + // during the simplification process, but we must handle the rest + // in a final fixup pass, guided by `adjusted_global_expressions`. We + // add their handles to this set, so that the final fixup step can + // leave them alone. + let mut adjusted_constant_initializers = HashSet::with_capacity(module.constants.len()); + + let mut global_expression_kind_tracker = crate::proc::ExpressionKindTracker::new(); + + // An iterator through the original overrides table, consumed in + // approximate tandem with the global expressions. + let mut override_iter = module.overrides.drain(); + + // Do two things in tandem: + // + // - Rebuild the global expression arena from scratch, fully + // evaluating all expressions, and replacing each `Override` + // expression in `module.global_expressions` with a `Constant` + // expression. + // + // - Build a new `Constant` in `module.constants` to take the + // place of each `Override`. + // + // Build a map from old global expression handles to their + // fully-evaluated counterparts in `adjusted_global_expressions` as we + // go. + // + // Why in tandem? Overrides refer to expressions, and expressions + // refer to overrides, so we can't disentangle the two into + // separate phases. However, we can take advantage of the fact + // that the overrides and expressions must form a DAG, and work + // our way from the leaves to the roots, replacing and evaluating + // as we go. + // + // Although the two loops are nested, this is really two + // alternating phases: we adjust and evaluate constant expressions + // until we hit an `Override` expression, at which point we switch + // to building `Constant`s for `Overrides` until we've handled the + // one used by the expression. Then we switch back to processing + // expressions. Because we know they form a DAG, we know the + // `Override` expressions we encounter can only have initializers + // referring to global expressions we've already simplified. + for (old_h, expr, span) in module.global_expressions.drain() { + let mut expr = match expr { + Expression::Override(h) => { + let c_h = if let Some(new_h) = override_map.get(h.index()) { + *new_h + } else { + let mut new_h = None; + for entry in override_iter.by_ref() { + let stop = entry.0 == h; + new_h = Some(process_override( + entry, + pipeline_constants, + &mut module, + &mut override_map, + &adjusted_global_expressions, + &mut adjusted_constant_initializers, + &mut global_expression_kind_tracker, + )?); + if stop { + break; + } + } + new_h.unwrap() + }; + Expression::Constant(c_h) + } + Expression::Constant(c_h) => { + if adjusted_constant_initializers.insert(c_h) { + let init = &mut module.constants[c_h].init; + *init = adjusted_global_expressions[init.index()]; + } + expr + } + expr => expr, + }; + let mut evaluator = ConstantEvaluator::for_wgsl_module( + &mut module, + &mut global_expression_kind_tracker, + false, + ); + adjust_expr(&adjusted_global_expressions, &mut expr); + let h = evaluator.try_eval_and_append(expr, span)?; + debug_assert_eq!(old_h.index(), adjusted_global_expressions.len()); + adjusted_global_expressions.push(h); + } + + // Finish processing any overrides we didn't visit in the loop above. + for entry in override_iter { + process_override( + entry, + pipeline_constants, + &mut module, + &mut override_map, + &adjusted_global_expressions, + &mut adjusted_constant_initializers, + &mut global_expression_kind_tracker, + )?; + } + + // Update the initialization expression handles of all `Constant`s + // and `GlobalVariable`s. Skip `Constant`s we'd already updated en + // passant. + for (_, c) in module + .constants + .iter_mut() + .filter(|&(c_h, _)| !adjusted_constant_initializers.contains(&c_h)) + { + c.init = adjusted_global_expressions[c.init.index()]; + } + + for (_, v) in module.global_variables.iter_mut() { + if let Some(ref mut init) = v.init { + *init = adjusted_global_expressions[init.index()]; + } + } + + let mut functions = mem::take(&mut module.functions); + for (_, function) in functions.iter_mut() { + process_function(&mut module, &override_map, function)?; + } + module.functions = functions; + + let mut entry_points = mem::take(&mut module.entry_points); + for ep in entry_points.iter_mut() { + process_function(&mut module, &override_map, &mut ep.function)?; + } + module.entry_points = entry_points; + + // Now that we've rewritten all the expressions, we need to + // recompute their types and other metadata. For the time being, + // do a full re-validation. + let mut validator = Validator::new(ValidationFlags::all(), Capabilities::all()); + let module_info = validator.validate_no_overrides(&module)?; + + Ok((Cow::Owned(module), Cow::Owned(module_info))) +} + +/// Add a [`Constant`] to `module` for the override `old_h`. +/// +/// Add the new `Constant` to `override_map` and `adjusted_constant_initializers`. +fn process_override( + (old_h, override_, span): (Handle, Override, Span), + pipeline_constants: &PipelineConstants, + module: &mut Module, + override_map: &mut Vec>, + adjusted_global_expressions: &[Handle], + adjusted_constant_initializers: &mut HashSet>, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, +) -> Result, PipelineConstantError> { + // Determine which key to use for `override_` in `pipeline_constants`. + let key = if let Some(id) = override_.id { + Cow::Owned(id.to_string()) + } else if let Some(ref name) = override_.name { + Cow::Borrowed(name) + } else { + unreachable!(); + }; + + // Generate a global expression for `override_`'s value, either + // from the provided `pipeline_constants` table or its initializer + // in the module. + let init = if let Some(value) = pipeline_constants.get::(&key) { + let literal = match module.types[override_.ty].inner { + TypeInner::Scalar(scalar) => map_value_to_literal(*value, scalar)?, + _ => unreachable!(), + }; + let expr = module + .global_expressions + .append(Expression::Literal(literal), Span::UNDEFINED); + global_expression_kind_tracker.insert(expr, crate::proc::ExpressionKind::Const); + expr + } else if let Some(init) = override_.init { + adjusted_global_expressions[init.index()] + } else { + return Err(PipelineConstantError::MissingValue(key.to_string())); + }; + + // Generate a new `Constant` to represent the override's value. + let constant = Constant { + name: override_.name, + ty: override_.ty, + init, + }; + let h = module.constants.append(constant, span); + debug_assert_eq!(old_h.index(), override_map.len()); + override_map.push(h); + adjusted_constant_initializers.insert(h); + Ok(h) +} + +/// Replace all override expressions in `function` with fully-evaluated constants. +/// +/// Replace all `Expression::Override`s in `function`'s expression arena with +/// the corresponding `Expression::Constant`s, as given in `override_map`. +/// Replace any expressions whose values are now known with their fully +/// evaluated form. +/// +/// If `h` is a `Handle`, then `override_map[h.index()]` is the +/// `Handle` for the override's final value. +fn process_function( + module: &mut Module, + override_map: &[Handle], + function: &mut Function, +) -> Result<(), ConstantEvaluatorError> { + // A map from original local expression handles to + // handles in the new, local expression arena. + let mut adjusted_local_expressions = Vec::with_capacity(function.expressions.len()); + + let mut local_expression_kind_tracker = crate::proc::ExpressionKindTracker::new(); + + let mut expressions = mem::take(&mut function.expressions); + + // Dummy `emitter` and `block` for the constant evaluator. + // We can ignore the concept of emitting expressions here since + // expressions have already been covered by a `Statement::Emit` + // in the frontend. + // The only thing we might have to do is remove some expressions + // that have been covered by a `Statement::Emit`. See the docs of + // `filter_emits_in_block` for the reasoning. + let mut emitter = Emitter::default(); + let mut block = Block::new(); + + let mut evaluator = ConstantEvaluator::for_wgsl_function( + module, + &mut function.expressions, + &mut local_expression_kind_tracker, + &mut emitter, + &mut block, + ); + + for (old_h, mut expr, span) in expressions.drain() { + if let Expression::Override(h) = expr { + expr = Expression::Constant(override_map[h.index()]); + } + adjust_expr(&adjusted_local_expressions, &mut expr); + let h = evaluator.try_eval_and_append(expr, span)?; + debug_assert_eq!(old_h.index(), adjusted_local_expressions.len()); + adjusted_local_expressions.push(h); + } + + adjust_block(&adjusted_local_expressions, &mut function.body); + + filter_emits_in_block(&mut function.body, &function.expressions); + + // Update local expression initializers. + for (_, local) in function.local_variables.iter_mut() { + if let &mut Some(ref mut init) = &mut local.init { + *init = adjusted_local_expressions[init.index()]; + } + } + + // We've changed the keys of `function.named_expression`, so we have to + // rebuild it from scratch. + let named_expressions = mem::take(&mut function.named_expressions); + for (expr_h, name) in named_expressions { + function + .named_expressions + .insert(adjusted_local_expressions[expr_h.index()], name); + } + + Ok(()) +} + +/// Replace every expression handle in `expr` with its counterpart +/// given by `new_pos`. +fn adjust_expr(new_pos: &[Handle], expr: &mut Expression) { + let adjust = |expr: &mut Handle| { + *expr = new_pos[expr.index()]; + }; + match *expr { + Expression::Compose { + ref mut components, + ty: _, + } => { + for c in components.iter_mut() { + adjust(c); + } + } + Expression::Access { + ref mut base, + ref mut index, + } => { + adjust(base); + adjust(index); + } + Expression::AccessIndex { + ref mut base, + index: _, + } => { + adjust(base); + } + Expression::Splat { + ref mut value, + size: _, + } => { + adjust(value); + } + Expression::Swizzle { + ref mut vector, + size: _, + pattern: _, + } => { + adjust(vector); + } + Expression::Load { ref mut pointer } => { + adjust(pointer); + } + Expression::ImageSample { + ref mut image, + ref mut sampler, + ref mut coordinate, + ref mut array_index, + ref mut offset, + ref mut level, + ref mut depth_ref, + gather: _, + } => { + adjust(image); + adjust(sampler); + adjust(coordinate); + if let Some(e) = array_index.as_mut() { + adjust(e); + } + if let Some(e) = offset.as_mut() { + adjust(e); + } + match *level { + crate::SampleLevel::Exact(ref mut expr) + | crate::SampleLevel::Bias(ref mut expr) => { + adjust(expr); + } + crate::SampleLevel::Gradient { + ref mut x, + ref mut y, + } => { + adjust(x); + adjust(y); + } + _ => {} + } + if let Some(e) = depth_ref.as_mut() { + adjust(e); + } + } + Expression::ImageLoad { + ref mut image, + ref mut coordinate, + ref mut array_index, + ref mut sample, + ref mut level, + } => { + adjust(image); + adjust(coordinate); + if let Some(e) = array_index.as_mut() { + adjust(e); + } + if let Some(e) = sample.as_mut() { + adjust(e); + } + if let Some(e) = level.as_mut() { + adjust(e); + } + } + Expression::ImageQuery { + ref mut image, + ref mut query, + } => { + adjust(image); + match *query { + crate::ImageQuery::Size { ref mut level } => { + if let Some(e) = level.as_mut() { + adjust(e); + } + } + crate::ImageQuery::NumLevels + | crate::ImageQuery::NumLayers + | crate::ImageQuery::NumSamples => {} + } + } + Expression::Unary { + ref mut expr, + op: _, + } => { + adjust(expr); + } + Expression::Binary { + ref mut left, + ref mut right, + op: _, + } => { + adjust(left); + adjust(right); + } + Expression::Select { + ref mut condition, + ref mut accept, + ref mut reject, + } => { + adjust(condition); + adjust(accept); + adjust(reject); + } + Expression::Derivative { + ref mut expr, + axis: _, + ctrl: _, + } => { + adjust(expr); + } + Expression::Relational { + ref mut argument, + fun: _, + } => { + adjust(argument); + } + Expression::Math { + ref mut arg, + ref mut arg1, + ref mut arg2, + ref mut arg3, + fun: _, + } => { + adjust(arg); + if let Some(e) = arg1.as_mut() { + adjust(e); + } + if let Some(e) = arg2.as_mut() { + adjust(e); + } + if let Some(e) = arg3.as_mut() { + adjust(e); + } + } + Expression::As { + ref mut expr, + kind: _, + convert: _, + } => { + adjust(expr); + } + Expression::ArrayLength(ref mut expr) => { + adjust(expr); + } + Expression::RayQueryGetIntersection { + ref mut query, + committed: _, + } => { + adjust(query); + } + Expression::Literal(_) + | Expression::FunctionArgument(_) + | Expression::GlobalVariable(_) + | Expression::LocalVariable(_) + | Expression::CallResult(_) + | Expression::RayQueryProceedResult + | Expression::Constant(_) + | Expression::Override(_) + | Expression::ZeroValue(_) + | Expression::AtomicResult { + ty: _, + comparison: _, + } + | Expression::WorkGroupUniformLoadResult { ty: _ } + | Expression::SubgroupBallotResult + | Expression::SubgroupOperationResult { .. } => {} + } +} + +/// Replace every expression handle in `block` with its counterpart +/// given by `new_pos`. +fn adjust_block(new_pos: &[Handle], block: &mut Block) { + for stmt in block.iter_mut() { + adjust_stmt(new_pos, stmt); + } +} + +/// Replace every expression handle in `stmt` with its counterpart +/// given by `new_pos`. +fn adjust_stmt(new_pos: &[Handle], stmt: &mut Statement) { + let adjust = |expr: &mut Handle| { + *expr = new_pos[expr.index()]; + }; + match *stmt { + Statement::Emit(ref mut range) => { + if let Some((mut first, mut last)) = range.first_and_last() { + adjust(&mut first); + adjust(&mut last); + *range = Range::new_from_bounds(first, last); + } + } + Statement::Block(ref mut block) => { + adjust_block(new_pos, block); + } + Statement::If { + ref mut condition, + ref mut accept, + ref mut reject, + } => { + adjust(condition); + adjust_block(new_pos, accept); + adjust_block(new_pos, reject); + } + Statement::Switch { + ref mut selector, + ref mut cases, + } => { + adjust(selector); + for case in cases.iter_mut() { + adjust_block(new_pos, &mut case.body); + } + } + Statement::Loop { + ref mut body, + ref mut continuing, + ref mut break_if, + } => { + adjust_block(new_pos, body); + adjust_block(new_pos, continuing); + if let Some(e) = break_if.as_mut() { + adjust(e); + } + } + Statement::Return { ref mut value } => { + if let Some(e) = value.as_mut() { + adjust(e); + } + } + Statement::Store { + ref mut pointer, + ref mut value, + } => { + adjust(pointer); + adjust(value); + } + Statement::ImageStore { + ref mut image, + ref mut coordinate, + ref mut array_index, + ref mut value, + } => { + adjust(image); + adjust(coordinate); + if let Some(e) = array_index.as_mut() { + adjust(e); + } + adjust(value); + } + crate::Statement::Atomic { + ref mut pointer, + ref mut value, + ref mut result, + ref mut fun, + } => { + adjust(pointer); + adjust(value); + adjust(result); + match *fun { + crate::AtomicFunction::Exchange { + compare: Some(ref mut compare), + } => { + adjust(compare); + } + crate::AtomicFunction::Add + | crate::AtomicFunction::Subtract + | crate::AtomicFunction::And + | crate::AtomicFunction::ExclusiveOr + | crate::AtomicFunction::InclusiveOr + | crate::AtomicFunction::Min + | crate::AtomicFunction::Max + | crate::AtomicFunction::Exchange { compare: None } => {} + } + } + Statement::WorkGroupUniformLoad { + ref mut pointer, + ref mut result, + } => { + adjust(pointer); + adjust(result); + } + Statement::SubgroupBallot { + ref mut result, + ref mut predicate, + } => { + if let Some(ref mut predicate) = *predicate { + adjust(predicate); + } + adjust(result); + } + Statement::SubgroupCollectiveOperation { + ref mut argument, + ref mut result, + .. + } => { + adjust(argument); + adjust(result); + } + Statement::SubgroupGather { + ref mut mode, + ref mut argument, + ref mut result, + } => { + match *mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(ref mut index) + | crate::GatherMode::Shuffle(ref mut index) + | crate::GatherMode::ShuffleDown(ref mut index) + | crate::GatherMode::ShuffleUp(ref mut index) + | crate::GatherMode::ShuffleXor(ref mut index) => { + adjust(index); + } + } + adjust(argument); + adjust(result) + } + Statement::Call { + ref mut arguments, + ref mut result, + function: _, + } => { + for argument in arguments.iter_mut() { + adjust(argument); + } + if let Some(e) = result.as_mut() { + adjust(e); + } + } + Statement::RayQuery { + ref mut query, + ref mut fun, + } => { + adjust(query); + match *fun { + crate::RayQueryFunction::Initialize { + ref mut acceleration_structure, + ref mut descriptor, + } => { + adjust(acceleration_structure); + adjust(descriptor); + } + crate::RayQueryFunction::Proceed { ref mut result } => { + adjust(result); + } + crate::RayQueryFunction::Terminate => {} + } + } + Statement::Break | Statement::Continue | Statement::Kill | Statement::Barrier(_) => {} + } +} + +/// Adjust [`Emit`] statements in `block` to skip [`needs_pre_emit`] expressions we have introduced. +/// +/// According to validation, [`Emit`] statements must not cover any expressions +/// for which [`Expression::needs_pre_emit`] returns true. All expressions built +/// by successful constant evaluation fall into that category, meaning that +/// `process_function` will usually rewrite [`Override`] expressions and those +/// that use their values into pre-emitted expressions, leaving any [`Emit`] +/// statements that cover them invalid. +/// +/// This function rewrites all [`Emit`] statements into zero or more new +/// [`Emit`] statements covering only those expressions in the original range +/// that are not pre-emitted. +/// +/// [`Emit`]: Statement::Emit +/// [`needs_pre_emit`]: Expression::needs_pre_emit +/// [`Override`]: Expression::Override +fn filter_emits_in_block(block: &mut Block, expressions: &Arena) { + let original = std::mem::replace(block, Block::with_capacity(block.len())); + for (stmt, span) in original.span_into_iter() { + match stmt { + Statement::Emit(range) => { + let mut current = None; + for expr_h in range { + if expressions[expr_h].needs_pre_emit() { + if let Some((first, last)) = current { + block.push(Statement::Emit(Range::new_from_bounds(first, last)), span); + } + + current = None; + } else if let Some((_, ref mut last)) = current { + *last = expr_h; + } else { + current = Some((expr_h, expr_h)); + } + } + if let Some((first, last)) = current { + block.push(Statement::Emit(Range::new_from_bounds(first, last)), span); + } + } + Statement::Block(mut child) => { + filter_emits_in_block(&mut child, expressions); + block.push(Statement::Block(child), span); + } + Statement::If { + condition, + mut accept, + mut reject, + } => { + filter_emits_in_block(&mut accept, expressions); + filter_emits_in_block(&mut reject, expressions); + block.push( + Statement::If { + condition, + accept, + reject, + }, + span, + ); + } + Statement::Switch { + selector, + mut cases, + } => { + for case in &mut cases { + filter_emits_in_block(&mut case.body, expressions); + } + block.push(Statement::Switch { selector, cases }, span); + } + Statement::Loop { + mut body, + mut continuing, + break_if, + } => { + filter_emits_in_block(&mut body, expressions); + filter_emits_in_block(&mut continuing, expressions); + block.push( + Statement::Loop { + body, + continuing, + break_if, + }, + span, + ); + } + stmt => block.push(stmt.clone(), span), + } + } +} + +fn map_value_to_literal(value: f64, scalar: Scalar) -> Result { + // note that in rust 0.0 == -0.0 + match scalar { + Scalar::BOOL => { + // https://webidl.spec.whatwg.org/#js-boolean + let value = value != 0.0 && !value.is_nan(); + Ok(Literal::Bool(value)) + } + Scalar::I32 => { + // https://webidl.spec.whatwg.org/#js-long + if !value.is_finite() { + return Err(PipelineConstantError::SrcNeedsToBeFinite); + } + + let value = value.trunc(); + if value < f64::from(i32::MIN) || value > f64::from(i32::MAX) { + return Err(PipelineConstantError::DstRangeTooSmall); + } + + let value = value as i32; + Ok(Literal::I32(value)) + } + Scalar::U32 => { + // https://webidl.spec.whatwg.org/#js-unsigned-long + if !value.is_finite() { + return Err(PipelineConstantError::SrcNeedsToBeFinite); + } + + let value = value.trunc(); + if value < f64::from(u32::MIN) || value > f64::from(u32::MAX) { + return Err(PipelineConstantError::DstRangeTooSmall); + } + + let value = value as u32; + Ok(Literal::U32(value)) + } + Scalar::F32 => { + // https://webidl.spec.whatwg.org/#js-float + if !value.is_finite() { + return Err(PipelineConstantError::SrcNeedsToBeFinite); + } + + let value = value as f32; + if !value.is_finite() { + return Err(PipelineConstantError::DstRangeTooSmall); + } + + Ok(Literal::F32(value)) + } + Scalar::F64 => { + // https://webidl.spec.whatwg.org/#js-double + if !value.is_finite() { + return Err(PipelineConstantError::SrcNeedsToBeFinite); + } + + Ok(Literal::F64(value)) + } + _ => unreachable!(), + } +} + +#[test] +fn test_map_value_to_literal() { + let bool_test_cases = [ + (0.0, false), + (-0.0, false), + (f64::NAN, false), + (1.0, true), + (f64::INFINITY, true), + (f64::NEG_INFINITY, true), + ]; + for (value, out) in bool_test_cases { + let res = Ok(Literal::Bool(out)); + assert_eq!(map_value_to_literal(value, Scalar::BOOL), res); + } + + for scalar in [Scalar::I32, Scalar::U32, Scalar::F32, Scalar::F64] { + for value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { + let res = Err(PipelineConstantError::SrcNeedsToBeFinite); + assert_eq!(map_value_to_literal(value, scalar), res); + } + } + + // i32 + assert_eq!( + map_value_to_literal(f64::from(i32::MIN), Scalar::I32), + Ok(Literal::I32(i32::MIN)) + ); + assert_eq!( + map_value_to_literal(f64::from(i32::MAX), Scalar::I32), + Ok(Literal::I32(i32::MAX)) + ); + assert_eq!( + map_value_to_literal(f64::from(i32::MIN) - 1.0, Scalar::I32), + Err(PipelineConstantError::DstRangeTooSmall) + ); + assert_eq!( + map_value_to_literal(f64::from(i32::MAX) + 1.0, Scalar::I32), + Err(PipelineConstantError::DstRangeTooSmall) + ); + + // u32 + assert_eq!( + map_value_to_literal(f64::from(u32::MIN), Scalar::U32), + Ok(Literal::U32(u32::MIN)) + ); + assert_eq!( + map_value_to_literal(f64::from(u32::MAX), Scalar::U32), + Ok(Literal::U32(u32::MAX)) + ); + assert_eq!( + map_value_to_literal(f64::from(u32::MIN) - 1.0, Scalar::U32), + Err(PipelineConstantError::DstRangeTooSmall) + ); + assert_eq!( + map_value_to_literal(f64::from(u32::MAX) + 1.0, Scalar::U32), + Err(PipelineConstantError::DstRangeTooSmall) + ); + + // f32 + assert_eq!( + map_value_to_literal(f64::from(f32::MIN), Scalar::F32), + Ok(Literal::F32(f32::MIN)) + ); + assert_eq!( + map_value_to_literal(f64::from(f32::MAX), Scalar::F32), + Ok(Literal::F32(f32::MAX)) + ); + assert_eq!( + map_value_to_literal(-f64::from_bits(0x47efffffefffffff), Scalar::F32), + Ok(Literal::F32(f32::MIN)) + ); + assert_eq!( + map_value_to_literal(f64::from_bits(0x47efffffefffffff), Scalar::F32), + Ok(Literal::F32(f32::MAX)) + ); + assert_eq!( + map_value_to_literal(-f64::from_bits(0x47effffff0000000), Scalar::F32), + Err(PipelineConstantError::DstRangeTooSmall) + ); + assert_eq!( + map_value_to_literal(f64::from_bits(0x47effffff0000000), Scalar::F32), + Err(PipelineConstantError::DstRangeTooSmall) + ); + + // f64 + assert_eq!( + map_value_to_literal(f64::MIN, Scalar::F64), + Ok(Literal::F64(f64::MIN)) + ); + assert_eq!( + map_value_to_literal(f64::MAX, Scalar::F64), + Ok(Literal::F64(f64::MAX)) + ); +} diff --git a/third_party/rust/naga/src/back/spv/block.rs b/third_party/rust/naga/src/back/spv/block.rs index 81f2fc10e0..120d60fc40 100644 --- a/third_party/rust/naga/src/back/spv/block.rs +++ b/third_party/rust/naga/src/back/spv/block.rs @@ -239,6 +239,7 @@ impl<'w> BlockContext<'w> { let init = self.ir_module.constants[handle].init; self.writer.constant_ids[init.index()] } + crate::Expression::Override(_) => return Err(Error::Override), crate::Expression::ZeroValue(_) => self.writer.get_constant_null(result_type_id), crate::Expression::Compose { ty, ref components } => { self.temp_list.clear(); @@ -1072,7 +1073,7 @@ impl<'w> BlockContext<'w> { // // bitfieldExtract(x, o, c) - let bit_width = arg_ty.scalar_width().unwrap(); + let bit_width = arg_ty.scalar_width().unwrap() * 8; let width_constant = self .writer .get_constant_scalar(crate::Literal::U32(bit_width as u32)); @@ -1128,7 +1129,7 @@ impl<'w> BlockContext<'w> { Mf::InsertBits => { // The behavior of InsertBits has the same undefined behavior as ExtractBits. - let bit_width = arg_ty.scalar_width().unwrap(); + let bit_width = arg_ty.scalar_width().unwrap() * 8; let width_constant = self .writer .get_constant_scalar(crate::Literal::U32(bit_width as u32)); @@ -1184,7 +1185,7 @@ impl<'w> BlockContext<'w> { } Mf::FindLsb => MathOp::Ext(spirv::GLOp::FindILsb), Mf::FindMsb => { - if arg_ty.scalar_width() == Some(32) { + if arg_ty.scalar_width() == Some(4) { let thing = match arg_scalar_kind { Some(crate::ScalarKind::Uint) => spirv::GLOp::FindUMsb, Some(crate::ScalarKind::Sint) => spirv::GLOp::FindSMsb, @@ -1278,7 +1279,9 @@ impl<'w> BlockContext<'w> { crate::Expression::CallResult(_) | crate::Expression::AtomicResult { .. } | crate::Expression::WorkGroupUniformLoadResult { .. } - | crate::Expression::RayQueryProceedResult => self.cached[expr_handle], + | crate::Expression::RayQueryProceedResult + | crate::Expression::SubgroupBallotResult + | crate::Expression::SubgroupOperationResult { .. } => self.cached[expr_handle], crate::Expression::As { expr, kind, @@ -2489,6 +2492,27 @@ impl<'w> BlockContext<'w> { crate::Statement::RayQuery { query, ref fun } => { self.write_ray_query_function(query, fun, &mut block); } + crate::Statement::SubgroupBallot { + result, + ref predicate, + } => { + self.write_subgroup_ballot(predicate, result, &mut block)?; + } + crate::Statement::SubgroupCollectiveOperation { + ref op, + ref collective_op, + argument, + result, + } => { + self.write_subgroup_operation(op, collective_op, argument, result, &mut block)?; + } + crate::Statement::SubgroupGather { + ref mode, + argument, + result, + } => { + self.write_subgroup_gather(mode, argument, result, &mut block)?; + } } } diff --git a/third_party/rust/naga/src/back/spv/helpers.rs b/third_party/rust/naga/src/back/spv/helpers.rs index 5b6226db85..1fb447e384 100644 --- a/third_party/rust/naga/src/back/spv/helpers.rs +++ b/third_party/rust/naga/src/back/spv/helpers.rs @@ -10,8 +10,12 @@ pub(super) fn bytes_to_words(bytes: &[u8]) -> Vec { pub(super) fn string_to_words(input: &str) -> Vec { let bytes = input.as_bytes(); - let mut words = bytes_to_words(bytes); + str_bytes_to_words(bytes) +} + +pub(super) fn str_bytes_to_words(bytes: &[u8]) -> Vec { + let mut words = bytes_to_words(bytes); if bytes.len() % 4 == 0 { // nul-termination words.push(0x0u32); @@ -20,6 +24,21 @@ pub(super) fn string_to_words(input: &str) -> Vec { words } +/// split a string into chunks and keep utf8 valid +#[allow(unstable_name_collisions)] +pub(super) fn string_to_byte_chunks(input: &str, limit: usize) -> Vec<&[u8]> { + let mut offset: usize = 0; + let mut start: usize = 0; + let mut words = vec![]; + while offset < input.len() { + offset = input.floor_char_boundary(offset + limit); + words.push(input[start..offset].as_bytes()); + start = offset; + } + + words +} + pub(super) const fn map_storage_class(space: crate::AddressSpace) -> spirv::StorageClass { match space { crate::AddressSpace::Handle => spirv::StorageClass::UniformConstant, @@ -107,3 +126,35 @@ pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariab _ => true, } } + +///HACK: this is taken from std unstable, remove it when std's floor_char_boundary is stable +trait U8Internal { + fn is_utf8_char_boundary(&self) -> bool; +} + +impl U8Internal for u8 { + fn is_utf8_char_boundary(&self) -> bool { + // This is bit magic equivalent to: b < 128 || b >= 192 + (*self as i8) >= -0x40 + } +} + +trait StrUnstable { + fn floor_char_boundary(&self, index: usize) -> usize; +} + +impl StrUnstable for str { + fn floor_char_boundary(&self, index: usize) -> usize { + if index >= self.len() { + self.len() + } else { + let lower_bound = index.saturating_sub(3); + let new_index = self.as_bytes()[lower_bound..=index] + .iter() + .rposition(|b| b.is_utf8_char_boundary()); + + // SAFETY: we know that the character boundary will be within four bytes + unsafe { lower_bound + new_index.unwrap_unchecked() } + } + } +} diff --git a/third_party/rust/naga/src/back/spv/instructions.rs b/third_party/rust/naga/src/back/spv/instructions.rs index b963793ad3..df2774ab9c 100644 --- a/third_party/rust/naga/src/back/spv/instructions.rs +++ b/third_party/rust/naga/src/back/spv/instructions.rs @@ -43,6 +43,42 @@ impl super::Instruction { instruction } + pub(super) fn source_continued(source: &[u8]) -> Self { + let mut instruction = Self::new(Op::SourceContinued); + instruction.add_operands(helpers::str_bytes_to_words(source)); + instruction + } + + pub(super) fn source_auto_continued( + source_language: spirv::SourceLanguage, + version: u32, + source: &Option, + ) -> Vec { + let mut instructions = vec![]; + + let with_continue = source.as_ref().and_then(|debug_info| { + (debug_info.source_code.len() > u16::MAX as usize).then_some(debug_info) + }); + if let Some(debug_info) = with_continue { + let mut instruction = Self::new(Op::Source); + instruction.add_operand(source_language as u32); + instruction.add_operands(helpers::bytes_to_words(&version.to_le_bytes())); + + let words = helpers::string_to_byte_chunks(debug_info.source_code, u16::MAX as usize); + instruction.add_operand(debug_info.source_file_id); + instruction.add_operands(helpers::str_bytes_to_words(words[0])); + instructions.push(instruction); + for word_bytes in words[1..].iter() { + let instruction_continue = Self::source_continued(word_bytes); + instructions.push(instruction_continue); + } + } else { + let instruction = Self::source(source_language, version, source); + instructions.push(instruction); + } + instructions + } + pub(super) fn name(target_id: Word, name: &str) -> Self { let mut instruction = Self::new(Op::Name); instruction.add_operand(target_id); @@ -1037,6 +1073,73 @@ impl super::Instruction { instruction.add_operand(semantics_id); instruction } + + // Group Instructions + + pub(super) fn group_non_uniform_ballot( + result_type_id: Word, + id: Word, + exec_scope_id: Word, + predicate: Word, + ) -> Self { + let mut instruction = Self::new(Op::GroupNonUniformBallot); + instruction.set_type(result_type_id); + instruction.set_result(id); + instruction.add_operand(exec_scope_id); + instruction.add_operand(predicate); + + instruction + } + pub(super) fn group_non_uniform_broadcast_first( + result_type_id: Word, + id: Word, + exec_scope_id: Word, + value: Word, + ) -> Self { + let mut instruction = Self::new(Op::GroupNonUniformBroadcastFirst); + instruction.set_type(result_type_id); + instruction.set_result(id); + instruction.add_operand(exec_scope_id); + instruction.add_operand(value); + + instruction + } + pub(super) fn group_non_uniform_gather( + op: Op, + result_type_id: Word, + id: Word, + exec_scope_id: Word, + value: Word, + index: Word, + ) -> Self { + let mut instruction = Self::new(op); + instruction.set_type(result_type_id); + instruction.set_result(id); + instruction.add_operand(exec_scope_id); + instruction.add_operand(value); + instruction.add_operand(index); + + instruction + } + pub(super) fn group_non_uniform_arithmetic( + op: Op, + result_type_id: Word, + id: Word, + exec_scope_id: Word, + group_op: Option, + value: Word, + ) -> Self { + let mut instruction = Self::new(op); + instruction.set_type(result_type_id); + instruction.set_result(id); + instruction.add_operand(exec_scope_id); + if let Some(group_op) = group_op { + instruction.add_operand(group_op as u32); + } + instruction.add_operand(value); + + instruction + } } impl From for spirv::ImageFormat { diff --git a/third_party/rust/naga/src/back/spv/mod.rs b/third_party/rust/naga/src/back/spv/mod.rs index eb29e3cd8b..38a87049e6 100644 --- a/third_party/rust/naga/src/back/spv/mod.rs +++ b/third_party/rust/naga/src/back/spv/mod.rs @@ -13,6 +13,7 @@ mod layout; mod ray; mod recyclable; mod selection; +mod subgroup; mod writer; pub use spirv::Capability; @@ -70,6 +71,8 @@ pub enum Error { FeatureNotImplemented(&'static str), #[error("module is not validated properly: {0}")] Validation(&'static str), + #[error("overrides should not be present at this stage")] + Override, } #[derive(Default)] @@ -245,7 +248,7 @@ impl LocalImageType { /// this, by converting everything possible to a `LocalType` before inspecting /// it. /// -/// ## `Localtype` equality and SPIR-V `OpType` uniqueness +/// ## `LocalType` equality and SPIR-V `OpType` uniqueness /// /// The definition of `Eq` on `LocalType` is carefully chosen to help us follow /// certain SPIR-V rules. SPIR-V §2.8 requires some classes of `OpType...` @@ -454,7 +457,7 @@ impl recyclable::Recyclable for CachedExpressions { #[derive(Eq, Hash, PartialEq)] enum CachedConstant { - Literal(crate::Literal), + Literal(crate::proc::HashableLiteral), Composite { ty: LookupType, constituent_ids: Vec, @@ -527,6 +530,42 @@ struct FunctionArgument { handle_id: Word, } +/// Tracks the expressions for which the backend emits the following instructions: +/// - OpConstantTrue +/// - OpConstantFalse +/// - OpConstant +/// - OpConstantComposite +/// - OpConstantNull +struct ExpressionConstnessTracker { + inner: bit_set::BitSet, +} + +impl ExpressionConstnessTracker { + fn from_arena(arena: &crate::Arena) -> Self { + let mut inner = bit_set::BitSet::new(); + for (handle, expr) in arena.iter() { + let insert = match *expr { + crate::Expression::Literal(_) + | crate::Expression::ZeroValue(_) + | crate::Expression::Constant(_) => true, + crate::Expression::Compose { ref components, .. } => { + components.iter().all(|h| inner.contains(h.index())) + } + crate::Expression::Splat { value, .. } => inner.contains(value.index()), + _ => false, + }; + if insert { + inner.insert(handle.index()); + } + } + Self { inner } + } + + fn is_const(&self, value: Handle) -> bool { + self.inner.contains(value.index()) + } +} + /// General information needed to emit SPIR-V for Naga statements. struct BlockContext<'w> { /// The writer handling the module to which this code belongs. @@ -552,7 +591,7 @@ struct BlockContext<'w> { temp_list: Vec, /// Tracks the constness of `Expression`s residing in `self.ir_function.expressions` - expression_constness: crate::proc::ExpressionConstnessTracker, + expression_constness: ExpressionConstnessTracker, } impl BlockContext<'_> { @@ -725,7 +764,7 @@ impl<'a> Default for Options<'a> { } // A subset of options meant to be changed per pipeline. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct PipelineOptions { diff --git a/third_party/rust/naga/src/back/spv/subgroup.rs b/third_party/rust/naga/src/back/spv/subgroup.rs new file mode 100644 index 0000000000..c952cb11a7 --- /dev/null +++ b/third_party/rust/naga/src/back/spv/subgroup.rs @@ -0,0 +1,207 @@ +use super::{Block, BlockContext, Error, Instruction}; +use crate::{ + arena::Handle, + back::spv::{LocalType, LookupType}, + TypeInner, +}; + +impl<'w> BlockContext<'w> { + pub(super) fn write_subgroup_ballot( + &mut self, + predicate: &Option>, + result: Handle, + block: &mut Block, + ) -> Result<(), Error> { + self.writer.require_any( + "GroupNonUniformBallot", + &[spirv::Capability::GroupNonUniformBallot], + )?; + let vec4_u32_type_id = self.get_type_id(LookupType::Local(LocalType::Value { + vector_size: Some(crate::VectorSize::Quad), + scalar: crate::Scalar::U32, + pointer_space: None, + })); + let exec_scope_id = self.get_index_constant(spirv::Scope::Subgroup as u32); + let predicate = if let Some(predicate) = *predicate { + self.cached[predicate] + } else { + self.writer.get_constant_scalar(crate::Literal::Bool(true)) + }; + let id = self.gen_id(); + block.body.push(Instruction::group_non_uniform_ballot( + vec4_u32_type_id, + id, + exec_scope_id, + predicate, + )); + self.cached[result] = id; + Ok(()) + } + pub(super) fn write_subgroup_operation( + &mut self, + op: &crate::SubgroupOperation, + collective_op: &crate::CollectiveOperation, + argument: Handle, + result: Handle, + block: &mut Block, + ) -> Result<(), Error> { + use crate::SubgroupOperation as sg; + match *op { + sg::All | sg::Any => { + self.writer.require_any( + "GroupNonUniformVote", + &[spirv::Capability::GroupNonUniformVote], + )?; + } + _ => { + self.writer.require_any( + "GroupNonUniformArithmetic", + &[spirv::Capability::GroupNonUniformArithmetic], + )?; + } + } + + let id = self.gen_id(); + let result_ty = &self.fun_info[result].ty; + let result_type_id = self.get_expression_type_id(result_ty); + let result_ty_inner = result_ty.inner_with(&self.ir_module.types); + + let (is_scalar, scalar) = match *result_ty_inner { + TypeInner::Scalar(kind) => (true, kind), + TypeInner::Vector { scalar: kind, .. } => (false, kind), + _ => unimplemented!(), + }; + + use crate::ScalarKind as sk; + let spirv_op = match (scalar.kind, *op) { + (sk::Bool, sg::All) if is_scalar => spirv::Op::GroupNonUniformAll, + (sk::Bool, sg::Any) if is_scalar => spirv::Op::GroupNonUniformAny, + (_, sg::All | sg::Any) => unimplemented!(), + + (sk::Sint | sk::Uint, sg::Add) => spirv::Op::GroupNonUniformIAdd, + (sk::Float, sg::Add) => spirv::Op::GroupNonUniformFAdd, + (sk::Sint | sk::Uint, sg::Mul) => spirv::Op::GroupNonUniformIMul, + (sk::Float, sg::Mul) => spirv::Op::GroupNonUniformFMul, + (sk::Sint, sg::Max) => spirv::Op::GroupNonUniformSMax, + (sk::Uint, sg::Max) => spirv::Op::GroupNonUniformUMax, + (sk::Float, sg::Max) => spirv::Op::GroupNonUniformFMax, + (sk::Sint, sg::Min) => spirv::Op::GroupNonUniformSMin, + (sk::Uint, sg::Min) => spirv::Op::GroupNonUniformUMin, + (sk::Float, sg::Min) => spirv::Op::GroupNonUniformFMin, + (_, sg::Add | sg::Mul | sg::Min | sg::Max) => unimplemented!(), + + (sk::Sint | sk::Uint, sg::And) => spirv::Op::GroupNonUniformBitwiseAnd, + (sk::Sint | sk::Uint, sg::Or) => spirv::Op::GroupNonUniformBitwiseOr, + (sk::Sint | sk::Uint, sg::Xor) => spirv::Op::GroupNonUniformBitwiseXor, + (sk::Bool, sg::And) => spirv::Op::GroupNonUniformLogicalAnd, + (sk::Bool, sg::Or) => spirv::Op::GroupNonUniformLogicalOr, + (sk::Bool, sg::Xor) => spirv::Op::GroupNonUniformLogicalXor, + (_, sg::And | sg::Or | sg::Xor) => unimplemented!(), + }; + + let exec_scope_id = self.get_index_constant(spirv::Scope::Subgroup as u32); + + use crate::CollectiveOperation as c; + let group_op = match *op { + sg::All | sg::Any => None, + _ => Some(match *collective_op { + c::Reduce => spirv::GroupOperation::Reduce, + c::InclusiveScan => spirv::GroupOperation::InclusiveScan, + c::ExclusiveScan => spirv::GroupOperation::ExclusiveScan, + }), + }; + + let arg_id = self.cached[argument]; + block.body.push(Instruction::group_non_uniform_arithmetic( + spirv_op, + result_type_id, + id, + exec_scope_id, + group_op, + arg_id, + )); + self.cached[result] = id; + Ok(()) + } + pub(super) fn write_subgroup_gather( + &mut self, + mode: &crate::GatherMode, + argument: Handle, + result: Handle, + block: &mut Block, + ) -> Result<(), Error> { + self.writer.require_any( + "GroupNonUniformBallot", + &[spirv::Capability::GroupNonUniformBallot], + )?; + match *mode { + crate::GatherMode::BroadcastFirst | crate::GatherMode::Broadcast(_) => { + self.writer.require_any( + "GroupNonUniformBallot", + &[spirv::Capability::GroupNonUniformBallot], + )?; + } + crate::GatherMode::Shuffle(_) | crate::GatherMode::ShuffleXor(_) => { + self.writer.require_any( + "GroupNonUniformShuffle", + &[spirv::Capability::GroupNonUniformShuffle], + )?; + } + crate::GatherMode::ShuffleDown(_) | crate::GatherMode::ShuffleUp(_) => { + self.writer.require_any( + "GroupNonUniformShuffleRelative", + &[spirv::Capability::GroupNonUniformShuffleRelative], + )?; + } + } + + let id = self.gen_id(); + let result_ty = &self.fun_info[result].ty; + let result_type_id = self.get_expression_type_id(result_ty); + + let exec_scope_id = self.get_index_constant(spirv::Scope::Subgroup as u32); + + let arg_id = self.cached[argument]; + match *mode { + crate::GatherMode::BroadcastFirst => { + block + .body + .push(Instruction::group_non_uniform_broadcast_first( + result_type_id, + id, + exec_scope_id, + arg_id, + )); + } + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + let index_id = self.cached[index]; + let op = match *mode { + crate::GatherMode::BroadcastFirst => unreachable!(), + // Use shuffle to emit broadcast to allow the index to + // be dynamically uniform on Vulkan 1.1. The argument to + // OpGroupNonUniformBroadcast must be a constant pre SPIR-V + // 1.5 (vulkan 1.2) + crate::GatherMode::Broadcast(_) => spirv::Op::GroupNonUniformShuffle, + crate::GatherMode::Shuffle(_) => spirv::Op::GroupNonUniformShuffle, + crate::GatherMode::ShuffleDown(_) => spirv::Op::GroupNonUniformShuffleDown, + crate::GatherMode::ShuffleUp(_) => spirv::Op::GroupNonUniformShuffleUp, + crate::GatherMode::ShuffleXor(_) => spirv::Op::GroupNonUniformShuffleXor, + }; + block.body.push(Instruction::group_non_uniform_gather( + op, + result_type_id, + id, + exec_scope_id, + arg_id, + index_id, + )); + } + } + self.cached[result] = id; + Ok(()) + } +} diff --git a/third_party/rust/naga/src/back/spv/writer.rs b/third_party/rust/naga/src/back/spv/writer.rs index a5065e0623..73a16c273e 100644 --- a/third_party/rust/naga/src/back/spv/writer.rs +++ b/third_party/rust/naga/src/back/spv/writer.rs @@ -615,7 +615,7 @@ impl Writer { // Steal the Writer's temp list for a bit. temp_list: std::mem::take(&mut self.temp_list), writer: self, - expression_constness: crate::proc::ExpressionConstnessTracker::from_arena( + expression_constness: super::ExpressionConstnessTracker::from_arena( &ir_function.expressions, ), }; @@ -970,6 +970,11 @@ impl Writer { handle: Handle, ) -> Result { let ty = &arena[handle]; + // If it's a type that needs SPIR-V capabilities, request them now. + // This needs to happen regardless of the LocalType lookup succeeding, + // because some types which map to the same LocalType have different + // capability requirements. See https://github.com/gfx-rs/wgpu/issues/5569 + self.request_type_capabilities(&ty.inner)?; let id = if let Some(local) = make_local(&ty.inner) { // This type can be represented as a `LocalType`, so check if we've // already written an instruction for it. If not, do so now, with @@ -985,10 +990,6 @@ impl Writer { self.write_type_declaration_local(id, local); - // If it's a type that needs SPIR-V capabilities, request them now, - // so write_type_declaration_local can stay infallible. - self.request_type_capabilities(&ty.inner)?; - id } } @@ -1150,7 +1151,7 @@ impl Writer { } pub(super) fn get_constant_scalar(&mut self, value: crate::Literal) -> Word { - let scalar = CachedConstant::Literal(value); + let scalar = CachedConstant::Literal(value.into()); if let Some(&id) = self.cached_constants.get(&scalar) { return id; } @@ -1258,7 +1259,7 @@ impl Writer { ir_module: &crate::Module, mod_info: &ModuleInfo, ) -> Result { - let id = match ir_module.const_expressions[handle] { + let id = match ir_module.global_expressions[handle] { crate::Expression::Literal(literal) => self.get_constant_scalar(literal), crate::Expression::Constant(constant) => { let constant = &ir_module.constants[constant]; @@ -1272,7 +1273,7 @@ impl Writer { let component_ids: Vec<_> = crate::proc::flatten_compose( ty, components, - &ir_module.const_expressions, + &ir_module.global_expressions, &ir_module.types, ) .map(|component| self.constant_ids[component.index()]) @@ -1310,7 +1311,11 @@ impl Writer { spirv::MemorySemantics::WORKGROUP_MEMORY, flags.contains(crate::Barrier::WORK_GROUP), ); - let exec_scope_id = self.get_index_constant(spirv::Scope::Workgroup as u32); + let exec_scope_id = if flags.contains(crate::Barrier::SUB_GROUP) { + self.get_index_constant(spirv::Scope::Subgroup as u32) + } else { + self.get_index_constant(spirv::Scope::Workgroup as u32) + }; let mem_scope_id = self.get_index_constant(memory_scope as u32); let semantics_id = self.get_index_constant(semantics.bits()); block.body.push(Instruction::control_barrier( @@ -1585,6 +1590,41 @@ impl Writer { Bi::WorkGroupId => BuiltIn::WorkgroupId, Bi::WorkGroupSize => BuiltIn::WorkgroupSize, Bi::NumWorkGroups => BuiltIn::NumWorkgroups, + // Subgroup + Bi::NumSubgroups => { + self.require_any( + "`num_subgroups` built-in", + &[spirv::Capability::GroupNonUniform], + )?; + BuiltIn::NumSubgroups + } + Bi::SubgroupId => { + self.require_any( + "`subgroup_id` built-in", + &[spirv::Capability::GroupNonUniform], + )?; + BuiltIn::SubgroupId + } + Bi::SubgroupSize => { + self.require_any( + "`subgroup_size` built-in", + &[ + spirv::Capability::GroupNonUniform, + spirv::Capability::SubgroupBallotKHR, + ], + )?; + BuiltIn::SubgroupSize + } + Bi::SubgroupInvocationId => { + self.require_any( + "`subgroup_invocation_id` built-in", + &[ + spirv::Capability::GroupNonUniform, + spirv::Capability::SubgroupBallotKHR, + ], + )?; + BuiltIn::SubgroupLocalInvocationId + } }; self.decorate(id, Decoration::BuiltIn, &[built_in as u32]); @@ -1899,7 +1939,7 @@ impl Writer { source_code: debug_info.source_code, source_file_id, }); - self.debugs.push(Instruction::source( + self.debugs.append(&mut Instruction::source_auto_continued( spirv::SourceLanguage::Unknown, 0, &debug_info_inner, @@ -1914,8 +1954,8 @@ impl Writer { // write all const-expressions as constants self.constant_ids - .resize(ir_module.const_expressions.len(), 0); - for (handle, _) in ir_module.const_expressions.iter() { + .resize(ir_module.global_expressions.len(), 0); + for (handle, _) in ir_module.global_expressions.iter() { self.write_constant_expr(handle, ir_module, mod_info)?; } debug_assert!(self.constant_ids.iter().all(|&id| id != 0)); @@ -2029,6 +2069,10 @@ impl Writer { debug_info: &Option, words: &mut Vec, ) -> Result<(), Error> { + if !ir_module.overrides.is_empty() { + return Err(Error::Override); + } + self.reset(); // Try to find the entry point and corresponding index diff --git a/third_party/rust/naga/src/back/wgsl/writer.rs b/third_party/rust/naga/src/back/wgsl/writer.rs index 3039cbbbe4..789f6f62bf 100644 --- a/third_party/rust/naga/src/back/wgsl/writer.rs +++ b/third_party/rust/naga/src/back/wgsl/writer.rs @@ -106,6 +106,12 @@ impl Writer { } pub fn write(&mut self, module: &Module, info: &valid::ModuleInfo) -> BackendResult { + if !module.overrides.is_empty() { + return Err(Error::Unimplemented( + "Pipeline constants are not yet supported for this back-end".to_string(), + )); + } + self.reset(module); // Save all ep result types @@ -918,8 +924,124 @@ impl Writer { if barrier.contains(crate::Barrier::WORK_GROUP) { writeln!(self.out, "{level}workgroupBarrier();")?; } + + if barrier.contains(crate::Barrier::SUB_GROUP) { + writeln!(self.out, "{level}subgroupBarrier();")?; + } } Statement::RayQuery { .. } => unreachable!(), + Statement::SubgroupBallot { result, predicate } => { + write!(self.out, "{level}")?; + let res_name = format!("{}{}", back::BAKE_PREFIX, result.index()); + self.start_named_expr(module, result, func_ctx, &res_name)?; + self.named_expressions.insert(result, res_name); + + write!(self.out, "subgroupBallot(")?; + if let Some(predicate) = predicate { + self.write_expr(module, predicate, func_ctx)?; + } + writeln!(self.out, ");")?; + } + Statement::SubgroupCollectiveOperation { + op, + collective_op, + argument, + result, + } => { + write!(self.out, "{level}")?; + let res_name = format!("{}{}", back::BAKE_PREFIX, result.index()); + self.start_named_expr(module, result, func_ctx, &res_name)?; + self.named_expressions.insert(result, res_name); + + match (collective_op, op) { + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::All) => { + write!(self.out, "subgroupAll(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Any) => { + write!(self.out, "subgroupAny(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Add) => { + write!(self.out, "subgroupAdd(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Mul) => { + write!(self.out, "subgroupMul(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Max) => { + write!(self.out, "subgroupMax(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Min) => { + write!(self.out, "subgroupMin(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::And) => { + write!(self.out, "subgroupAnd(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Or) => { + write!(self.out, "subgroupOr(")? + } + (crate::CollectiveOperation::Reduce, crate::SubgroupOperation::Xor) => { + write!(self.out, "subgroupXor(")? + } + (crate::CollectiveOperation::ExclusiveScan, crate::SubgroupOperation::Add) => { + write!(self.out, "subgroupExclusiveAdd(")? + } + (crate::CollectiveOperation::ExclusiveScan, crate::SubgroupOperation::Mul) => { + write!(self.out, "subgroupExclusiveMul(")? + } + (crate::CollectiveOperation::InclusiveScan, crate::SubgroupOperation::Add) => { + write!(self.out, "subgroupInclusiveAdd(")? + } + (crate::CollectiveOperation::InclusiveScan, crate::SubgroupOperation::Mul) => { + write!(self.out, "subgroupInclusiveMul(")? + } + _ => unimplemented!(), + } + self.write_expr(module, argument, func_ctx)?; + writeln!(self.out, ");")?; + } + Statement::SubgroupGather { + mode, + argument, + result, + } => { + write!(self.out, "{level}")?; + let res_name = format!("{}{}", back::BAKE_PREFIX, result.index()); + self.start_named_expr(module, result, func_ctx, &res_name)?; + self.named_expressions.insert(result, res_name); + + match mode { + crate::GatherMode::BroadcastFirst => { + write!(self.out, "subgroupBroadcastFirst(")?; + } + crate::GatherMode::Broadcast(_) => { + write!(self.out, "subgroupBroadcast(")?; + } + crate::GatherMode::Shuffle(_) => { + write!(self.out, "subgroupShuffle(")?; + } + crate::GatherMode::ShuffleDown(_) => { + write!(self.out, "subgroupShuffleDown(")?; + } + crate::GatherMode::ShuffleUp(_) => { + write!(self.out, "subgroupShuffleUp(")?; + } + crate::GatherMode::ShuffleXor(_) => { + write!(self.out, "subgroupShuffleXor(")?; + } + } + self.write_expr(module, argument, func_ctx)?; + match mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + write!(self.out, ", ")?; + self.write_expr(module, index, func_ctx)?; + } + } + writeln!(self.out, ");")?; + } } Ok(()) @@ -1070,7 +1192,7 @@ impl Writer { self.write_possibly_const_expression( module, expr, - &module.const_expressions, + &module.global_expressions, |writer, expr| writer.write_const_expression(module, expr), ) } @@ -1199,6 +1321,7 @@ impl Writer { |writer, expr| writer.write_expr(module, expr, func_ctx), )?; } + Expression::Override(_) => unreachable!(), Expression::FunctionArgument(pos) => { let name_key = func_ctx.argument_key(pos); let name = &self.names[&name_key]; @@ -1691,6 +1814,8 @@ impl Writer { Expression::CallResult(_) | Expression::AtomicResult { .. } | Expression::RayQueryProceedResult + | Expression::SubgroupBallotResult + | Expression::SubgroupOperationResult { .. } | Expression::WorkGroupUniformLoadResult { .. } => {} } @@ -1792,6 +1917,10 @@ fn builtin_str(built_in: crate::BuiltIn) -> Result<&'static str, Error> { Bi::SampleMask => "sample_mask", Bi::PrimitiveIndex => "primitive_index", Bi::ViewIndex => "view_index", + Bi::NumSubgroups => "num_subgroups", + Bi::SubgroupId => "subgroup_id", + Bi::SubgroupSize => "subgroup_size", + Bi::SubgroupInvocationId => "subgroup_invocation_id", Bi::BaseInstance | Bi::BaseVertex | Bi::ClipDistance diff --git a/third_party/rust/naga/src/block.rs b/third_party/rust/naga/src/block.rs index 0abda9da7c..2e86a928f1 100644 --- a/third_party/rust/naga/src/block.rs +++ b/third_party/rust/naga/src/block.rs @@ -65,6 +65,12 @@ impl Block { self.span_info.splice(range.clone(), other.span_info); self.body.splice(range, other.body); } + + pub fn span_into_iter(self) -> impl Iterator { + let Block { body, span_info } = self; + body.into_iter().zip(span_info) + } + pub fn span_iter(&self) -> impl Iterator { let span_iter = self.span_info.iter(); self.body.iter().zip(span_iter) diff --git a/third_party/rust/naga/src/compact/expressions.rs b/third_party/rust/naga/src/compact/expressions.rs index 301bbe3240..a418bde301 100644 --- a/third_party/rust/naga/src/compact/expressions.rs +++ b/third_party/rust/naga/src/compact/expressions.rs @@ -3,6 +3,7 @@ use crate::arena::{Arena, Handle}; pub struct ExpressionTracer<'tracer> { pub constants: &'tracer Arena, + pub overrides: &'tracer Arena, /// The arena in which we are currently tracing expressions. pub expressions: &'tracer Arena, @@ -20,11 +21,11 @@ pub struct ExpressionTracer<'tracer> { /// the module's constant expression arena. pub expressions_used: &'tracer mut HandleSet, - /// The used set for the module's `const_expressions` arena. + /// The used set for the module's `global_expressions` arena. /// /// If `None`, we are already tracing the constant expressions, /// and `expressions_used` already refers to their handle set. - pub const_expressions_used: Option<&'tracer mut HandleSet>, + pub global_expressions_used: Option<&'tracer mut HandleSet>, } impl<'tracer> ExpressionTracer<'tracer> { @@ -39,11 +40,11 @@ impl<'tracer> ExpressionTracer<'tracer> { /// marked. /// /// [fe]: crate::Function::expressions - /// [ce]: crate::Module::const_expressions + /// [ce]: crate::Module::global_expressions pub fn trace_expressions(&mut self) { log::trace!( "entering trace_expression of {}", - if self.const_expressions_used.is_some() { + if self.global_expressions_used.is_some() { "function expressions" } else { "const expressions" @@ -71,6 +72,7 @@ impl<'tracer> ExpressionTracer<'tracer> { | Ex::GlobalVariable(_) | Ex::LocalVariable(_) | Ex::CallResult(_) + | Ex::SubgroupBallotResult | Ex::RayQueryProceedResult => {} Ex::Constant(handle) => { @@ -83,11 +85,16 @@ impl<'tracer> ExpressionTracer<'tracer> { // and the constant refers to the initializer, it must // precede `expr` in the arena. let init = self.constants[handle].init; - match self.const_expressions_used { + match self.global_expressions_used { Some(ref mut used) => used.insert(init), None => self.expressions_used.insert(init), } } + Ex::Override(_) => { + // All overrides are considered used by definition. We mark + // their types and initialization expressions as used in + // `compact::compact`, so we have no more work to do here. + } Ex::ZeroValue(ty) => self.types_used.insert(ty), Ex::Compose { ty, ref components } => { self.types_used.insert(ty); @@ -116,7 +123,7 @@ impl<'tracer> ExpressionTracer<'tracer> { self.expressions_used .insert_iter([image, sampler, coordinate]); self.expressions_used.insert_iter(array_index); - match self.const_expressions_used { + match self.global_expressions_used { Some(ref mut used) => used.insert_iter(offset), None => self.expressions_used.insert_iter(offset), } @@ -186,6 +193,7 @@ impl<'tracer> ExpressionTracer<'tracer> { Ex::AtomicResult { ty, comparison: _ } => self.types_used.insert(ty), Ex::WorkGroupUniformLoadResult { ty } => self.types_used.insert(ty), Ex::ArrayLength(expr) => self.expressions_used.insert(expr), + Ex::SubgroupOperationResult { ty } => self.types_used.insert(ty), Ex::RayQueryGetIntersection { query, committed: _, @@ -217,8 +225,12 @@ impl ModuleMap { | Ex::GlobalVariable(_) | Ex::LocalVariable(_) | Ex::CallResult(_) + | Ex::SubgroupBallotResult | Ex::RayQueryProceedResult => {} + // All overrides are retained, so their handles never change. + Ex::Override(_) => {} + // Expressions that contain handles that need to be adjusted. Ex::Constant(ref mut constant) => self.constants.adjust(constant), Ex::ZeroValue(ref mut ty) => self.types.adjust(ty), @@ -267,7 +279,7 @@ impl ModuleMap { adjust(coordinate); operand_map.adjust_option(array_index); if let Some(ref mut offset) = *offset { - self.const_expressions.adjust(offset); + self.global_expressions.adjust(offset); } self.adjust_sample_level(level, operand_map); operand_map.adjust_option(depth_ref); @@ -344,6 +356,7 @@ impl ModuleMap { comparison: _, } => self.types.adjust(ty), Ex::WorkGroupUniformLoadResult { ref mut ty } => self.types.adjust(ty), + Ex::SubgroupOperationResult { ref mut ty } => self.types.adjust(ty), Ex::ArrayLength(ref mut expr) => adjust(expr), Ex::RayQueryGetIntersection { ref mut query, diff --git a/third_party/rust/naga/src/compact/functions.rs b/third_party/rust/naga/src/compact/functions.rs index b0d08c7e96..4ac2223eb7 100644 --- a/third_party/rust/naga/src/compact/functions.rs +++ b/third_party/rust/naga/src/compact/functions.rs @@ -4,10 +4,11 @@ use super::{FunctionMap, ModuleMap}; pub struct FunctionTracer<'a> { pub function: &'a crate::Function, pub constants: &'a crate::Arena, + pub overrides: &'a crate::Arena, pub types_used: &'a mut HandleSet, pub constants_used: &'a mut HandleSet, - pub const_expressions_used: &'a mut HandleSet, + pub global_expressions_used: &'a mut HandleSet, /// Function-local expressions used. pub expressions_used: HandleSet, @@ -47,12 +48,13 @@ impl<'a> FunctionTracer<'a> { fn as_expression(&mut self) -> super::expressions::ExpressionTracer { super::expressions::ExpressionTracer { constants: self.constants, + overrides: self.overrides, expressions: &self.function.expressions, types_used: self.types_used, constants_used: self.constants_used, expressions_used: &mut self.expressions_used, - const_expressions_used: Some(&mut self.const_expressions_used), + global_expressions_used: Some(&mut self.global_expressions_used), } } } diff --git a/third_party/rust/naga/src/compact/mod.rs b/third_party/rust/naga/src/compact/mod.rs index b4e57ed5c9..0d7a37b579 100644 --- a/third_party/rust/naga/src/compact/mod.rs +++ b/third_party/rust/naga/src/compact/mod.rs @@ -38,7 +38,7 @@ pub fn compact(module: &mut crate::Module) { log::trace!("tracing global {:?}", global.name); module_tracer.types_used.insert(global.ty); if let Some(init) = global.init { - module_tracer.const_expressions_used.insert(init); + module_tracer.global_expressions_used.insert(init); } } } @@ -50,7 +50,15 @@ pub fn compact(module: &mut crate::Module) { for (handle, constant) in module.constants.iter() { if constant.name.is_some() { module_tracer.constants_used.insert(handle); - module_tracer.const_expressions_used.insert(constant.init); + module_tracer.global_expressions_used.insert(constant.init); + } + } + + // We treat all overrides as used by definition. + for (_, override_) in module.overrides.iter() { + module_tracer.types_used.insert(override_.ty); + if let Some(init) = override_.init { + module_tracer.global_expressions_used.insert(init); } } @@ -137,9 +145,9 @@ pub fn compact(module: &mut crate::Module) { // Drop unused constant expressions, reusing existing storage. log::trace!("adjusting constant expressions"); - module.const_expressions.retain_mut(|handle, expr| { - if module_map.const_expressions.used(handle) { - module_map.adjust_expression(expr, &module_map.const_expressions); + module.global_expressions.retain_mut(|handle, expr| { + if module_map.global_expressions.used(handle) { + module_map.adjust_expression(expr, &module_map.global_expressions); true } else { false @@ -151,20 +159,29 @@ pub fn compact(module: &mut crate::Module) { module.constants.retain_mut(|handle, constant| { if module_map.constants.used(handle) { module_map.types.adjust(&mut constant.ty); - module_map.const_expressions.adjust(&mut constant.init); + module_map.global_expressions.adjust(&mut constant.init); true } else { false } }); + // Adjust override types and initializers. + log::trace!("adjusting overrides"); + for (_, override_) in module.overrides.iter_mut() { + module_map.types.adjust(&mut override_.ty); + if let Some(init) = override_.init.as_mut() { + module_map.global_expressions.adjust(init); + } + } + // Adjust global variables' types and initializers. log::trace!("adjusting global variables"); for (_, global) in module.global_variables.iter_mut() { log::trace!("adjusting global {:?}", global.name); module_map.types.adjust(&mut global.ty); if let Some(ref mut init) = global.init { - module_map.const_expressions.adjust(init); + module_map.global_expressions.adjust(init); } } @@ -193,7 +210,7 @@ struct ModuleTracer<'module> { module: &'module crate::Module, types_used: HandleSet, constants_used: HandleSet, - const_expressions_used: HandleSet, + global_expressions_used: HandleSet, } impl<'module> ModuleTracer<'module> { @@ -202,7 +219,7 @@ impl<'module> ModuleTracer<'module> { module, types_used: HandleSet::for_arena(&module.types), constants_used: HandleSet::for_arena(&module.constants), - const_expressions_used: HandleSet::for_arena(&module.const_expressions), + global_expressions_used: HandleSet::for_arena(&module.global_expressions), } } @@ -233,12 +250,13 @@ impl<'module> ModuleTracer<'module> { fn as_const_expression(&mut self) -> expressions::ExpressionTracer { expressions::ExpressionTracer { - expressions: &self.module.const_expressions, + expressions: &self.module.global_expressions, constants: &self.module.constants, + overrides: &self.module.overrides, types_used: &mut self.types_used, constants_used: &mut self.constants_used, - expressions_used: &mut self.const_expressions_used, - const_expressions_used: None, + expressions_used: &mut self.global_expressions_used, + global_expressions_used: None, } } @@ -249,9 +267,10 @@ impl<'module> ModuleTracer<'module> { FunctionTracer { function, constants: &self.module.constants, + overrides: &self.module.overrides, types_used: &mut self.types_used, constants_used: &mut self.constants_used, - const_expressions_used: &mut self.const_expressions_used, + global_expressions_used: &mut self.global_expressions_used, expressions_used: HandleSet::for_arena(&function.expressions), } } @@ -260,7 +279,7 @@ impl<'module> ModuleTracer<'module> { struct ModuleMap { types: HandleMap, constants: HandleMap, - const_expressions: HandleMap, + global_expressions: HandleMap, } impl From> for ModuleMap { @@ -268,7 +287,7 @@ impl From> for ModuleMap { ModuleMap { types: HandleMap::from_set(used.types_used), constants: HandleMap::from_set(used.constants_used), - const_expressions: HandleMap::from_set(used.const_expressions_used), + global_expressions: HandleMap::from_set(used.global_expressions_used), } } } diff --git a/third_party/rust/naga/src/compact/statements.rs b/third_party/rust/naga/src/compact/statements.rs index 0698b57258..a124281bc1 100644 --- a/third_party/rust/naga/src/compact/statements.rs +++ b/third_party/rust/naga/src/compact/statements.rs @@ -97,6 +97,39 @@ impl FunctionTracer<'_> { self.expressions_used.insert(query); self.trace_ray_query_function(fun); } + St::SubgroupBallot { result, predicate } => { + if let Some(predicate) = predicate { + self.expressions_used.insert(predicate) + } + self.expressions_used.insert(result) + } + St::SubgroupCollectiveOperation { + op: _, + collective_op: _, + argument, + result, + } => { + self.expressions_used.insert(argument); + self.expressions_used.insert(result) + } + St::SubgroupGather { + mode, + argument, + result, + } => { + match mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + self.expressions_used.insert(index) + } + } + self.expressions_used.insert(argument); + self.expressions_used.insert(result) + } // Trivial statements. St::Break @@ -250,6 +283,40 @@ impl FunctionMap { adjust(query); self.adjust_ray_query_function(fun); } + St::SubgroupBallot { + ref mut result, + ref mut predicate, + } => { + if let Some(ref mut predicate) = *predicate { + adjust(predicate); + } + adjust(result); + } + St::SubgroupCollectiveOperation { + op: _, + collective_op: _, + ref mut argument, + ref mut result, + } => { + adjust(argument); + adjust(result); + } + St::SubgroupGather { + ref mut mode, + ref mut argument, + ref mut result, + } => { + match *mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(ref mut index) + | crate::GatherMode::Shuffle(ref mut index) + | crate::GatherMode::ShuffleDown(ref mut index) + | crate::GatherMode::ShuffleUp(ref mut index) + | crate::GatherMode::ShuffleXor(ref mut index) => adjust(index), + } + adjust(argument); + adjust(result); + } // Trivial statements. St::Break diff --git a/third_party/rust/naga/src/error.rs b/third_party/rust/naga/src/error.rs new file mode 100644 index 0000000000..5f2e28360b --- /dev/null +++ b/third_party/rust/naga/src/error.rs @@ -0,0 +1,74 @@ +use std::{error::Error, fmt}; + +#[derive(Clone, Debug)] +pub struct ShaderError { + /// The source code of the shader. + pub source: String, + pub label: Option, + pub inner: Box, +} + +#[cfg(feature = "wgsl-in")] +impl fmt::Display for ShaderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let label = self.label.as_deref().unwrap_or_default(); + let string = self.inner.emit_to_string(&self.source); + write!(f, "\nShader '{label}' parsing {string}") + } +} +#[cfg(feature = "glsl-in")] +impl fmt::Display for ShaderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let label = self.label.as_deref().unwrap_or_default(); + let string = self.inner.emit_to_string(&self.source); + write!(f, "\nShader '{label}' parsing {string}") + } +} +#[cfg(feature = "spv-in")] +impl fmt::Display for ShaderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let label = self.label.as_deref().unwrap_or_default(); + let string = self.inner.emit_to_string(&self.source); + write!(f, "\nShader '{label}' parsing {string}") + } +} +impl fmt::Display for ShaderError> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use codespan_reporting::{ + diagnostic::{Diagnostic, Label}, + files::SimpleFile, + term, + }; + + let label = self.label.as_deref().unwrap_or_default(); + let files = SimpleFile::new(label, &self.source); + let config = term::Config::default(); + let mut writer = term::termcolor::NoColor::new(Vec::new()); + + let diagnostic = Diagnostic::error().with_labels( + self.inner + .spans() + .map(|&(span, ref desc)| { + Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned()) + }) + .collect(), + ); + + term::emit(&mut writer, &config, &files, &diagnostic).expect("cannot write error"); + + write!( + f, + "\nShader validation {}", + String::from_utf8_lossy(&writer.into_inner()) + ) + } +} +impl Error for ShaderError +where + ShaderError: fmt::Display, + E: Error + 'static, +{ + fn source(&self) -> Option<&(dyn Error + 'static)> { + Some(&self.inner) + } +} diff --git a/third_party/rust/naga/src/front/glsl/context.rs b/third_party/rust/naga/src/front/glsl/context.rs index f26c57965d..6ba7df593a 100644 --- a/third_party/rust/naga/src/front/glsl/context.rs +++ b/third_party/rust/naga/src/front/glsl/context.rs @@ -77,12 +77,19 @@ pub struct Context<'a> { pub body: Block, pub module: &'a mut crate::Module, pub is_const: bool, - /// Tracks the constness of `Expression`s residing in `self.expressions` - pub expression_constness: crate::proc::ExpressionConstnessTracker, + /// Tracks the expression kind of `Expression`s residing in `self.expressions` + pub local_expression_kind_tracker: crate::proc::ExpressionKindTracker, + /// Tracks the expression kind of `Expression`s residing in `self.module.global_expressions` + pub global_expression_kind_tracker: &'a mut crate::proc::ExpressionKindTracker, } impl<'a> Context<'a> { - pub fn new(frontend: &Frontend, module: &'a mut crate::Module, is_const: bool) -> Result { + pub fn new( + frontend: &Frontend, + module: &'a mut crate::Module, + is_const: bool, + global_expression_kind_tracker: &'a mut crate::proc::ExpressionKindTracker, + ) -> Result { let mut this = Context { expressions: Arena::new(), locals: Arena::new(), @@ -101,7 +108,8 @@ impl<'a> Context<'a> { body: Block::new(), module, is_const: false, - expression_constness: crate::proc::ExpressionConstnessTracker::new(), + local_expression_kind_tracker: crate::proc::ExpressionKindTracker::new(), + global_expression_kind_tracker, }; this.emit_start(); @@ -249,40 +257,24 @@ impl<'a> Context<'a> { pub fn add_expression(&mut self, expr: Expression, meta: Span) -> Result> { let mut eval = if self.is_const { - crate::proc::ConstantEvaluator::for_glsl_module(self.module) + crate::proc::ConstantEvaluator::for_glsl_module( + self.module, + self.global_expression_kind_tracker, + ) } else { crate::proc::ConstantEvaluator::for_glsl_function( self.module, &mut self.expressions, - &mut self.expression_constness, + &mut self.local_expression_kind_tracker, &mut self.emitter, &mut self.body, ) }; - let res = eval.try_eval_and_append(&expr, meta).map_err(|e| Error { + eval.try_eval_and_append(expr, meta).map_err(|e| Error { kind: e.into(), meta, - }); - - match res { - Ok(expr) => Ok(expr), - Err(e) => { - if self.is_const { - Err(e) - } else { - let needs_pre_emit = expr.needs_pre_emit(); - if needs_pre_emit { - self.body.extend(self.emitter.finish(&self.expressions)); - } - let h = self.expressions.append(expr, meta); - if needs_pre_emit { - self.emitter.start(&self.expressions); - } - Ok(h) - } - } - } + }) } /// Add variable to current scope @@ -1479,7 +1471,7 @@ impl Index> for Context<'_> { fn index(&self, index: Handle) -> &Self::Output { if self.is_const { - &self.module.const_expressions[index] + &self.module.global_expressions[index] } else { &self.expressions[index] } diff --git a/third_party/rust/naga/src/front/glsl/error.rs b/third_party/rust/naga/src/front/glsl/error.rs index bd16ee30bc..e0771437e6 100644 --- a/third_party/rust/naga/src/front/glsl/error.rs +++ b/third_party/rust/naga/src/front/glsl/error.rs @@ -1,4 +1,5 @@ use super::token::TokenValue; +use crate::SourceLocation; use crate::{proc::ConstantEvaluatorError, Span}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::SimpleFile; @@ -137,14 +138,21 @@ pub struct Error { pub meta: Span, } +impl Error { + /// Returns a [`SourceLocation`] for the error message. + pub fn location(&self, source: &str) -> Option { + Some(self.meta.location(source)) + } +} + /// A collection of errors returned during shader parsing. #[derive(Clone, Debug)] #[cfg_attr(test, derive(PartialEq))] -pub struct ParseError { +pub struct ParseErrors { pub errors: Vec, } -impl ParseError { +impl ParseErrors { pub fn emit_to_writer(&self, writer: &mut impl WriteColor, source: &str) { self.emit_to_writer_with_path(writer, source, "glsl"); } @@ -172,19 +180,19 @@ impl ParseError { } } -impl std::fmt::Display for ParseError { +impl std::fmt::Display for ParseErrors { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.errors.iter().try_for_each(|e| write!(f, "{e:?}")) } } -impl std::error::Error for ParseError { +impl std::error::Error for ParseErrors { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } } -impl From> for ParseError { +impl From> for ParseErrors { fn from(errors: Vec) -> Self { Self { errors } } diff --git a/third_party/rust/naga/src/front/glsl/functions.rs b/third_party/rust/naga/src/front/glsl/functions.rs index 01846eb814..fa1bbef56b 100644 --- a/third_party/rust/naga/src/front/glsl/functions.rs +++ b/third_party/rust/naga/src/front/glsl/functions.rs @@ -1236,6 +1236,8 @@ impl Frontend { let pointer = ctx .expressions .append(Expression::GlobalVariable(arg.handle), Default::default()); + ctx.local_expression_kind_tracker + .insert(pointer, crate::proc::ExpressionKind::Runtime); let ty = ctx.module.global_variables[arg.handle].ty; @@ -1256,6 +1258,8 @@ impl Frontend { let value = ctx .expressions .append(Expression::FunctionArgument(idx), Default::default()); + ctx.local_expression_kind_tracker + .insert(value, crate::proc::ExpressionKind::Runtime); ctx.body .push(Statement::Store { pointer, value }, Default::default()); }, @@ -1285,6 +1289,8 @@ impl Frontend { let pointer = ctx .expressions .append(Expression::GlobalVariable(arg.handle), Default::default()); + ctx.local_expression_kind_tracker + .insert(pointer, crate::proc::ExpressionKind::Runtime); let ty = ctx.module.global_variables[arg.handle].ty; @@ -1307,6 +1313,8 @@ impl Frontend { let load = ctx .expressions .append(Expression::Load { pointer }, Default::default()); + ctx.local_expression_kind_tracker + .insert(load, crate::proc::ExpressionKind::Runtime); ctx.body.push( Statement::Emit(ctx.expressions.range_from(len)), Default::default(), @@ -1329,6 +1337,8 @@ impl Frontend { let res = ctx .expressions .append(Expression::Compose { ty, components }, Default::default()); + ctx.local_expression_kind_tracker + .insert(res, crate::proc::ExpressionKind::Runtime); ctx.body.push( Statement::Emit(ctx.expressions.range_from(len)), Default::default(), diff --git a/third_party/rust/naga/src/front/glsl/mod.rs b/third_party/rust/naga/src/front/glsl/mod.rs index 75f3929db4..ea202b2445 100644 --- a/third_party/rust/naga/src/front/glsl/mod.rs +++ b/third_party/rust/naga/src/front/glsl/mod.rs @@ -13,7 +13,7 @@ To begin, take a look at the documentation for the [`Frontend`]. */ pub use ast::{Precision, Profile}; -pub use error::{Error, ErrorKind, ExpectedToken, ParseError}; +pub use error::{Error, ErrorKind, ExpectedToken, ParseErrors}; pub use token::TokenValue; use crate::{proc::Layouter, FastHashMap, FastHashSet, Handle, Module, ShaderStage, Span, Type}; @@ -196,7 +196,7 @@ impl Frontend { &mut self, options: &Options, source: &str, - ) -> std::result::Result { + ) -> std::result::Result { self.reset(options.stage); let lexer = lex::Lexer::new(source, &options.defines); diff --git a/third_party/rust/naga/src/front/glsl/parser.rs b/third_party/rust/naga/src/front/glsl/parser.rs index 851d2e1d79..28e0808063 100644 --- a/third_party/rust/naga/src/front/glsl/parser.rs +++ b/third_party/rust/naga/src/front/glsl/parser.rs @@ -164,9 +164,15 @@ impl<'source> ParsingContext<'source> { pub fn parse(&mut self, frontend: &mut Frontend) -> Result { let mut module = Module::default(); + let mut global_expression_kind_tracker = crate::proc::ExpressionKindTracker::new(); // Body and expression arena for global initialization - let mut ctx = Context::new(frontend, &mut module, false)?; + let mut ctx = Context::new( + frontend, + &mut module, + false, + &mut global_expression_kind_tracker, + )?; while self.peek(frontend).is_some() { self.parse_external_declaration(frontend, &mut ctx)?; @@ -196,7 +202,11 @@ impl<'source> ParsingContext<'source> { frontend: &mut Frontend, ctx: &mut Context, ) -> Result<(u32, Span)> { - let (const_expr, meta) = self.parse_constant_expression(frontend, ctx.module)?; + let (const_expr, meta) = self.parse_constant_expression( + frontend, + ctx.module, + ctx.global_expression_kind_tracker, + )?; let res = ctx.module.to_ctx().eval_expr_to_u32(const_expr); @@ -219,8 +229,9 @@ impl<'source> ParsingContext<'source> { &mut self, frontend: &mut Frontend, module: &mut Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, ) -> Result<(Handle, Span)> { - let mut ctx = Context::new(frontend, module, true)?; + let mut ctx = Context::new(frontend, module, true, global_expression_kind_tracker)?; let mut stmt_ctx = ctx.stmt_ctx(); let expr = self.parse_conditional(frontend, &mut ctx, &mut stmt_ctx, None)?; diff --git a/third_party/rust/naga/src/front/glsl/parser/declarations.rs b/third_party/rust/naga/src/front/glsl/parser/declarations.rs index f5e38fb016..2d253a378d 100644 --- a/third_party/rust/naga/src/front/glsl/parser/declarations.rs +++ b/third_party/rust/naga/src/front/glsl/parser/declarations.rs @@ -251,7 +251,7 @@ impl<'source> ParsingContext<'source> { init.and_then(|expr| ctx.ctx.lift_up_const_expression(expr).ok()); late_initializer = None; } else if let Some(init) = init { - if ctx.is_inside_loop || !ctx.ctx.expression_constness.is_const(init) { + if ctx.is_inside_loop || !ctx.ctx.local_expression_kind_tracker.is_const(init) { decl_initializer = None; late_initializer = Some(init); } else { @@ -326,7 +326,12 @@ impl<'source> ParsingContext<'source> { let result = ty.map(|ty| FunctionResult { ty, binding: None }); - let mut context = Context::new(frontend, ctx.module, false)?; + let mut context = Context::new( + frontend, + ctx.module, + false, + ctx.global_expression_kind_tracker, + )?; self.parse_function_args(frontend, &mut context)?; diff --git a/third_party/rust/naga/src/front/glsl/parser/functions.rs b/third_party/rust/naga/src/front/glsl/parser/functions.rs index d428d74761..d0c889e4d3 100644 --- a/third_party/rust/naga/src/front/glsl/parser/functions.rs +++ b/third_party/rust/naga/src/front/glsl/parser/functions.rs @@ -192,10 +192,13 @@ impl<'source> ParsingContext<'source> { TokenValue::Case => { self.bump(frontend)?; - let (const_expr, meta) = - self.parse_constant_expression(frontend, ctx.module)?; + let (const_expr, meta) = self.parse_constant_expression( + frontend, + ctx.module, + ctx.global_expression_kind_tracker, + )?; - match ctx.module.const_expressions[const_expr] { + match ctx.module.global_expressions[const_expr] { Expression::Literal(Literal::I32(value)) => match uint { // This unchecked cast isn't good, but since // we only reach this code when the selector diff --git a/third_party/rust/naga/src/front/glsl/parser_tests.rs b/third_party/rust/naga/src/front/glsl/parser_tests.rs index 259052cd27..135765ca58 100644 --- a/third_party/rust/naga/src/front/glsl/parser_tests.rs +++ b/third_party/rust/naga/src/front/glsl/parser_tests.rs @@ -1,7 +1,7 @@ use super::{ ast::Profile, error::ExpectedToken, - error::{Error, ErrorKind, ParseError}, + error::{Error, ErrorKind, ParseErrors}, token::TokenValue, Frontend, Options, Span, }; @@ -21,7 +21,7 @@ fn version() { ) .err() .unwrap(), - ParseError { + ParseErrors { errors: vec![Error { kind: ErrorKind::InvalidVersion(99000), meta: Span::new(9, 14) @@ -37,7 +37,7 @@ fn version() { ) .err() .unwrap(), - ParseError { + ParseErrors { errors: vec![Error { kind: ErrorKind::InvalidVersion(449), meta: Span::new(9, 12) @@ -53,7 +53,7 @@ fn version() { ) .err() .unwrap(), - ParseError { + ParseErrors { errors: vec![Error { kind: ErrorKind::InvalidProfile("smart".into()), meta: Span::new(13, 18), @@ -69,7 +69,7 @@ fn version() { ) .err() .unwrap(), - ParseError { + ParseErrors { errors: vec![ Error { kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,), @@ -455,7 +455,7 @@ fn functions() { ) .err() .unwrap(), - ParseError { + ParseErrors { errors: vec![Error { kind: ErrorKind::SemanticError("Function already defined".into()), meta: Span::new(134, 152), @@ -539,7 +539,7 @@ fn constants() { let mut types = module.types.iter(); let mut constants = module.constants.iter(); - let mut const_expressions = module.const_expressions.iter(); + let mut global_expressions = module.global_expressions.iter(); let (ty_handle, ty) = types.next().unwrap(); assert_eq!( @@ -550,14 +550,13 @@ fn constants() { } ); - let (init_handle, init) = const_expressions.next().unwrap(); + let (init_handle, init) = global_expressions.next().unwrap(); assert_eq!(init, &Expression::Literal(crate::Literal::F32(1.0))); assert_eq!( constants.next().unwrap().1, &Constant { name: Some("a".to_owned()), - r#override: crate::Override::None, ty: ty_handle, init: init_handle } @@ -567,7 +566,6 @@ fn constants() { constants.next().unwrap().1, &Constant { name: Some("b".to_owned()), - r#override: crate::Override::None, ty: ty_handle, init: init_handle } @@ -636,7 +634,7 @@ fn implicit_conversions() { ) .err() .unwrap(), - ParseError { + ParseErrors { errors: vec![Error { kind: ErrorKind::SemanticError("Unknown function \'test\'".into()), meta: Span::new(156, 165), @@ -660,7 +658,7 @@ fn implicit_conversions() { ) .err() .unwrap(), - ParseError { + ParseErrors { errors: vec![Error { kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()), meta: Span::new(158, 165), diff --git a/third_party/rust/naga/src/front/glsl/types.rs b/third_party/rust/naga/src/front/glsl/types.rs index e87d76fffc..f6836169c0 100644 --- a/third_party/rust/naga/src/front/glsl/types.rs +++ b/third_party/rust/naga/src/front/glsl/types.rs @@ -233,7 +233,7 @@ impl Context<'_> { }; let expressions = if self.is_const { - &self.module.const_expressions + &self.module.global_expressions } else { &self.expressions }; @@ -330,23 +330,25 @@ impl Context<'_> { expr: Handle, ) -> Result> { let meta = self.expressions.get_span(expr); - Ok(match self.expressions[expr] { + let h = match self.expressions[expr] { ref expr @ (Expression::Literal(_) | Expression::Constant(_) - | Expression::ZeroValue(_)) => self.module.const_expressions.append(expr.clone(), meta), + | Expression::ZeroValue(_)) => { + self.module.global_expressions.append(expr.clone(), meta) + } Expression::Compose { ty, ref components } => { let mut components = components.clone(); for component in &mut components { *component = self.lift_up_const_expression(*component)?; } self.module - .const_expressions + .global_expressions .append(Expression::Compose { ty, components }, meta) } Expression::Splat { size, value } => { let value = self.lift_up_const_expression(value)?; self.module - .const_expressions + .global_expressions .append(Expression::Splat { size, value }, meta) } _ => { @@ -355,6 +357,9 @@ impl Context<'_> { meta, }) } - }) + }; + self.global_expression_kind_tracker + .insert(h, crate::proc::ExpressionKind::Const); + Ok(h) } } diff --git a/third_party/rust/naga/src/front/glsl/variables.rs b/third_party/rust/naga/src/front/glsl/variables.rs index 9d2e7a0e7b..0725fbd94f 100644 --- a/third_party/rust/naga/src/front/glsl/variables.rs +++ b/third_party/rust/naga/src/front/glsl/variables.rs @@ -472,7 +472,6 @@ impl Frontend { let constant = Constant { name: name.clone(), - r#override: crate::Override::None, ty, init, }; diff --git a/third_party/rust/naga/src/front/spv/convert.rs b/third_party/rust/naga/src/front/spv/convert.rs index f0a714fbeb..a6bf0e0451 100644 --- a/third_party/rust/naga/src/front/spv/convert.rs +++ b/third_party/rust/naga/src/front/spv/convert.rs @@ -153,6 +153,11 @@ pub(super) fn map_builtin(word: spirv::Word, invariant: bool) -> Result crate::BuiltIn::WorkGroupId, Some(Bi::WorkgroupSize) => crate::BuiltIn::WorkGroupSize, Some(Bi::NumWorkgroups) => crate::BuiltIn::NumWorkGroups, + // subgroup + Some(Bi::NumSubgroups) => crate::BuiltIn::NumSubgroups, + Some(Bi::SubgroupId) => crate::BuiltIn::SubgroupId, + Some(Bi::SubgroupSize) => crate::BuiltIn::SubgroupSize, + Some(Bi::SubgroupLocalInvocationId) => crate::BuiltIn::SubgroupInvocationId, _ => return Err(Error::UnsupportedBuiltIn(word)), }) } diff --git a/third_party/rust/naga/src/front/spv/error.rs b/third_party/rust/naga/src/front/spv/error.rs index af025636c0..44beadce98 100644 --- a/third_party/rust/naga/src/front/spv/error.rs +++ b/third_party/rust/naga/src/front/spv/error.rs @@ -5,7 +5,7 @@ use codespan_reporting::files::SimpleFile; use codespan_reporting::term; use termcolor::{NoColor, WriteColor}; -#[derive(Debug, thiserror::Error)] +#[derive(Clone, Debug, thiserror::Error)] pub enum Error { #[error("invalid header")] InvalidHeader, @@ -58,6 +58,8 @@ pub enum Error { UnknownBinaryOperator(spirv::Op), #[error("unknown relational function {0:?}")] UnknownRelationalFunction(spirv::Op), + #[error("unsupported group operation %{0}")] + UnsupportedGroupOperation(spirv::Word), #[error("invalid parameter {0:?}")] InvalidParameter(spirv::Op), #[error("invalid operand count {1} for {0:?}")] @@ -118,8 +120,8 @@ pub enum Error { ControlFlowGraphCycle(crate::front::spv::BlockId), #[error("recursive function call %{0}")] FunctionCallCycle(spirv::Word), - #[error("invalid array size {0:?}")] - InvalidArraySize(Handle), + #[error("invalid array size %{0}")] + InvalidArraySize(spirv::Word), #[error("invalid barrier scope %{0}")] InvalidBarrierScope(spirv::Word), #[error("invalid barrier memory semantics %{0}")] @@ -130,6 +132,8 @@ pub enum Error { come from a binding)" )] NonBindingArrayOfImageOrSamplers, + #[error("naga only supports specialization constant IDs up to 65535 but was given {0}")] + SpecIdTooHigh(u32), } impl Error { diff --git a/third_party/rust/naga/src/front/spv/function.rs b/third_party/rust/naga/src/front/spv/function.rs index e81ecf5c9b..113ca56313 100644 --- a/third_party/rust/naga/src/front/spv/function.rs +++ b/third_party/rust/naga/src/front/spv/function.rs @@ -59,8 +59,11 @@ impl> super::Frontend { }) }, local_variables: Arena::new(), - expressions: self - .make_expression_storage(&module.global_variables, &module.constants), + expressions: self.make_expression_storage( + &module.global_variables, + &module.constants, + &module.overrides, + ), named_expressions: crate::NamedExpressions::default(), body: crate::Block::new(), } @@ -128,7 +131,8 @@ impl> super::Frontend { expressions: &mut fun.expressions, local_arena: &mut fun.local_variables, const_arena: &mut module.constants, - const_expressions: &mut module.const_expressions, + overrides: &mut module.overrides, + global_expressions: &mut module.global_expressions, type_arena: &module.types, global_arena: &module.global_variables, arguments: &fun.arguments, @@ -581,7 +585,8 @@ impl<'function> BlockContext<'function> { crate::proc::GlobalCtx { types: self.type_arena, constants: self.const_arena, - const_expressions: self.const_expressions, + overrides: self.overrides, + global_expressions: self.global_expressions, } } diff --git a/third_party/rust/naga/src/front/spv/image.rs b/third_party/rust/naga/src/front/spv/image.rs index 0f25dd626b..284c4cf7fd 100644 --- a/third_party/rust/naga/src/front/spv/image.rs +++ b/third_party/rust/naga/src/front/spv/image.rs @@ -507,11 +507,14 @@ impl> super::Frontend { } spirv::ImageOperands::CONST_OFFSET => { let offset_constant = self.next()?; - let offset_handle = self.lookup_constant.lookup(offset_constant)?.handle; - let offset_handle = ctx.const_expressions.append( - crate::Expression::Constant(offset_handle), - Default::default(), - ); + let offset_expr = self + .lookup_constant + .lookup(offset_constant)? + .inner + .to_expr(); + let offset_handle = ctx + .global_expressions + .append(offset_expr, Default::default()); offset = Some(offset_handle); words_left -= 1; } diff --git a/third_party/rust/naga/src/front/spv/mod.rs b/third_party/rust/naga/src/front/spv/mod.rs index b793448597..7ac5a18cd6 100644 --- a/third_party/rust/naga/src/front/spv/mod.rs +++ b/third_party/rust/naga/src/front/spv/mod.rs @@ -196,7 +196,7 @@ struct Decoration { location: Option, desc_set: Option, desc_index: Option, - specialization: Option, + specialization_constant_id: Option, storage_buffer: bool, offset: Option, array_stride: Option, @@ -216,11 +216,6 @@ impl Decoration { } } - fn specialization(&self) -> crate::Override { - self.specialization - .map_or(crate::Override::None, crate::Override::ByNameOrId) - } - const fn resource_binding(&self) -> Option { match *self { Decoration { @@ -283,9 +278,24 @@ struct LookupType { base_id: Option, } +#[derive(Debug)] +enum Constant { + Constant(Handle), + Override(Handle), +} + +impl Constant { + const fn to_expr(&self) -> crate::Expression { + match *self { + Self::Constant(c) => crate::Expression::Constant(c), + Self::Override(o) => crate::Expression::Override(o), + } + } +} + #[derive(Debug)] struct LookupConstant { - handle: Handle, + inner: Constant, type_id: spirv::Word, } @@ -537,7 +547,8 @@ struct BlockContext<'function> { local_arena: &'function mut Arena, /// Constants arena of the module being processed const_arena: &'function mut Arena, - const_expressions: &'function mut Arena, + overrides: &'function mut Arena, + global_expressions: &'function mut Arena, /// Type arena of the module being processed type_arena: &'function UniqueArena, /// Global arena of the module being processed @@ -757,7 +768,7 @@ impl> Frontend { dec.matrix_major = Some(Majority::Row); } spirv::Decoration::SpecId => { - dec.specialization = Some(self.next()?); + dec.specialization_constant_id = Some(self.next()?); } other => { log::warn!("Unknown decoration {:?}", other); @@ -1393,10 +1404,7 @@ impl> Frontend { inst.expect(5)?; let init_id = self.next()?; let lconst = self.lookup_constant.lookup(init_id)?; - Some( - ctx.expressions - .append(crate::Expression::Constant(lconst.handle), span), - ) + Some(ctx.expressions.append(lconst.inner.to_expr(), span)) } else { None }; @@ -3650,9 +3658,9 @@ impl> Frontend { let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?; let semantics_const = self.lookup_constant.lookup(semantics_id)?; - let exec_scope = resolve_constant(ctx.gctx(), exec_scope_const.handle) + let exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner) .ok_or(Error::InvalidBarrierScope(exec_scope_id))?; - let semantics = resolve_constant(ctx.gctx(), semantics_const.handle) + let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner) .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?; if exec_scope == spirv::Scope::Workgroup as u32 { @@ -3692,6 +3700,254 @@ impl> Frontend { }, ); } + Op::GroupNonUniformBallot => { + inst.expect(5)?; + block.extend(emitter.finish(ctx.expressions)); + let result_type_id = self.next()?; + let result_id = self.next()?; + let exec_scope_id = self.next()?; + let predicate_id = self.next()?; + + let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?; + let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner) + .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32) + .ok_or(Error::InvalidBarrierScope(exec_scope_id))?; + + let predicate = if self + .lookup_constant + .lookup(predicate_id) + .ok() + .filter(|predicate_const| match predicate_const.inner { + Constant::Constant(constant) => matches!( + ctx.gctx().global_expressions[ctx.gctx().constants[constant].init], + crate::Expression::Literal(crate::Literal::Bool(true)), + ), + Constant::Override(_) => false, + }) + .is_some() + { + None + } else { + let predicate_lookup = self.lookup_expression.lookup(predicate_id)?; + let predicate_handle = get_expr_handle!(predicate_id, predicate_lookup); + Some(predicate_handle) + }; + + let result_handle = ctx + .expressions + .append(crate::Expression::SubgroupBallotResult, span); + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: result_handle, + type_id: result_type_id, + block_id, + }, + ); + + block.push( + crate::Statement::SubgroupBallot { + result: result_handle, + predicate, + }, + span, + ); + emitter.start(ctx.expressions); + } + spirv::Op::GroupNonUniformAll + | spirv::Op::GroupNonUniformAny + | spirv::Op::GroupNonUniformIAdd + | spirv::Op::GroupNonUniformFAdd + | spirv::Op::GroupNonUniformIMul + | spirv::Op::GroupNonUniformFMul + | spirv::Op::GroupNonUniformSMax + | spirv::Op::GroupNonUniformUMax + | spirv::Op::GroupNonUniformFMax + | spirv::Op::GroupNonUniformSMin + | spirv::Op::GroupNonUniformUMin + | spirv::Op::GroupNonUniformFMin + | spirv::Op::GroupNonUniformBitwiseAnd + | spirv::Op::GroupNonUniformBitwiseOr + | spirv::Op::GroupNonUniformBitwiseXor + | spirv::Op::GroupNonUniformLogicalAnd + | spirv::Op::GroupNonUniformLogicalOr + | spirv::Op::GroupNonUniformLogicalXor => { + block.extend(emitter.finish(ctx.expressions)); + inst.expect( + if matches!( + inst.op, + spirv::Op::GroupNonUniformAll | spirv::Op::GroupNonUniformAny + ) { + 5 + } else { + 6 + }, + )?; + let result_type_id = self.next()?; + let result_id = self.next()?; + let exec_scope_id = self.next()?; + let collective_op_id = match inst.op { + spirv::Op::GroupNonUniformAll | spirv::Op::GroupNonUniformAny => { + crate::CollectiveOperation::Reduce + } + _ => { + let group_op_id = self.next()?; + match spirv::GroupOperation::from_u32(group_op_id) { + Some(spirv::GroupOperation::Reduce) => { + crate::CollectiveOperation::Reduce + } + Some(spirv::GroupOperation::InclusiveScan) => { + crate::CollectiveOperation::InclusiveScan + } + Some(spirv::GroupOperation::ExclusiveScan) => { + crate::CollectiveOperation::ExclusiveScan + } + _ => return Err(Error::UnsupportedGroupOperation(group_op_id)), + } + } + }; + let argument_id = self.next()?; + + let argument_lookup = self.lookup_expression.lookup(argument_id)?; + let argument_handle = get_expr_handle!(argument_id, argument_lookup); + + let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?; + let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner) + .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32) + .ok_or(Error::InvalidBarrierScope(exec_scope_id))?; + + let op_id = match inst.op { + spirv::Op::GroupNonUniformAll => crate::SubgroupOperation::All, + spirv::Op::GroupNonUniformAny => crate::SubgroupOperation::Any, + spirv::Op::GroupNonUniformIAdd | spirv::Op::GroupNonUniformFAdd => { + crate::SubgroupOperation::Add + } + spirv::Op::GroupNonUniformIMul | spirv::Op::GroupNonUniformFMul => { + crate::SubgroupOperation::Mul + } + spirv::Op::GroupNonUniformSMax + | spirv::Op::GroupNonUniformUMax + | spirv::Op::GroupNonUniformFMax => crate::SubgroupOperation::Max, + spirv::Op::GroupNonUniformSMin + | spirv::Op::GroupNonUniformUMin + | spirv::Op::GroupNonUniformFMin => crate::SubgroupOperation::Min, + spirv::Op::GroupNonUniformBitwiseAnd + | spirv::Op::GroupNonUniformLogicalAnd => crate::SubgroupOperation::And, + spirv::Op::GroupNonUniformBitwiseOr + | spirv::Op::GroupNonUniformLogicalOr => crate::SubgroupOperation::Or, + spirv::Op::GroupNonUniformBitwiseXor + | spirv::Op::GroupNonUniformLogicalXor => crate::SubgroupOperation::Xor, + _ => unreachable!(), + }; + + let result_type = self.lookup_type.lookup(result_type_id)?; + + let result_handle = ctx.expressions.append( + crate::Expression::SubgroupOperationResult { + ty: result_type.handle, + }, + span, + ); + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: result_handle, + type_id: result_type_id, + block_id, + }, + ); + + block.push( + crate::Statement::SubgroupCollectiveOperation { + result: result_handle, + op: op_id, + collective_op: collective_op_id, + argument: argument_handle, + }, + span, + ); + emitter.start(ctx.expressions); + } + Op::GroupNonUniformBroadcastFirst + | Op::GroupNonUniformBroadcast + | Op::GroupNonUniformShuffle + | Op::GroupNonUniformShuffleDown + | Op::GroupNonUniformShuffleUp + | Op::GroupNonUniformShuffleXor => { + inst.expect( + if matches!(inst.op, spirv::Op::GroupNonUniformBroadcastFirst) { + 5 + } else { + 6 + }, + )?; + block.extend(emitter.finish(ctx.expressions)); + let result_type_id = self.next()?; + let result_id = self.next()?; + let exec_scope_id = self.next()?; + let argument_id = self.next()?; + + let argument_lookup = self.lookup_expression.lookup(argument_id)?; + let argument_handle = get_expr_handle!(argument_id, argument_lookup); + + let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?; + let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner) + .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32) + .ok_or(Error::InvalidBarrierScope(exec_scope_id))?; + + let mode = if matches!(inst.op, spirv::Op::GroupNonUniformBroadcastFirst) { + crate::GatherMode::BroadcastFirst + } else { + let index_id = self.next()?; + let index_lookup = self.lookup_expression.lookup(index_id)?; + let index_handle = get_expr_handle!(index_id, index_lookup); + match inst.op { + spirv::Op::GroupNonUniformBroadcast => { + crate::GatherMode::Broadcast(index_handle) + } + spirv::Op::GroupNonUniformShuffle => { + crate::GatherMode::Shuffle(index_handle) + } + spirv::Op::GroupNonUniformShuffleDown => { + crate::GatherMode::ShuffleDown(index_handle) + } + spirv::Op::GroupNonUniformShuffleUp => { + crate::GatherMode::ShuffleUp(index_handle) + } + spirv::Op::GroupNonUniformShuffleXor => { + crate::GatherMode::ShuffleXor(index_handle) + } + _ => unreachable!(), + } + }; + + let result_type = self.lookup_type.lookup(result_type_id)?; + + let result_handle = ctx.expressions.append( + crate::Expression::SubgroupOperationResult { + ty: result_type.handle, + }, + span, + ); + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: result_handle, + type_id: result_type_id, + block_id, + }, + ); + + block.push( + crate::Statement::SubgroupGather { + result: result_handle, + mode, + argument: argument_handle, + }, + span, + ); + emitter.start(ctx.expressions); + } _ => return Err(Error::UnsupportedInstruction(self.state, inst.op)), } }; @@ -3713,6 +3969,7 @@ impl> Frontend { &mut self, globals: &Arena, constants: &Arena, + overrides: &Arena, ) -> Arena { let mut expressions = Arena::new(); #[allow(clippy::panic)] @@ -3737,8 +3994,11 @@ impl> Frontend { } // register constants for (&id, con) in self.lookup_constant.iter() { - let span = constants.get_span(con.handle); - let handle = expressions.append(crate::Expression::Constant(con.handle), span); + let (expr, span) = match con.inner { + Constant::Constant(c) => (crate::Expression::Constant(c), constants.get_span(c)), + Constant::Override(o) => (crate::Expression::Override(o), overrides.get_span(o)), + }; + let handle = expressions.append(expr, span); self.lookup_expression.insert( id, LookupExpression { @@ -3812,7 +4072,10 @@ impl> Frontend { | S::Store { .. } | S::ImageStore { .. } | S::Atomic { .. } - | S::RayQuery { .. } => {} + | S::RayQuery { .. } + | S::SubgroupBallot { .. } + | S::SubgroupCollectiveOperation { .. } + | S::SubgroupGather { .. } => {} S::Call { function: ref mut callee, ref arguments, @@ -3944,10 +4207,16 @@ impl> Frontend { Op::TypeSampledImage => self.parse_type_sampled_image(inst), Op::TypeSampler => self.parse_type_sampler(inst, &mut module), Op::Constant | Op::SpecConstant => self.parse_constant(inst, &mut module), - Op::ConstantComposite => self.parse_composite_constant(inst, &mut module), + Op::ConstantComposite | Op::SpecConstantComposite => { + self.parse_composite_constant(inst, &mut module) + } Op::ConstantNull | Op::Undef => self.parse_null_constant(inst, &mut module), - Op::ConstantTrue => self.parse_bool_constant(inst, true, &mut module), - Op::ConstantFalse => self.parse_bool_constant(inst, false, &mut module), + Op::ConstantTrue | Op::SpecConstantTrue => { + self.parse_bool_constant(inst, true, &mut module) + } + Op::ConstantFalse | Op::SpecConstantFalse => { + self.parse_bool_constant(inst, false, &mut module) + } Op::Variable => self.parse_global_variable(inst, &mut module), Op::Function => { self.switch(ModuleState::Function, inst.op)?; @@ -4504,9 +4773,9 @@ impl> Frontend { let length_id = self.next()?; let length_const = self.lookup_constant.lookup(length_id)?; - let size = resolve_constant(module.to_ctx(), length_const.handle) + let size = resolve_constant(module.to_ctx(), &length_const.inner) .and_then(NonZeroU32::new) - .ok_or(Error::InvalidArraySize(length_const.handle))?; + .ok_or(Error::InvalidArraySize(length_id))?; let decor = self.future_decor.remove(&id).unwrap_or_default(); let base = self.lookup_type.lookup(type_id)?.handle; @@ -4919,29 +5188,13 @@ impl> Frontend { _ => return Err(Error::UnsupportedType(type_lookup.handle)), }; - let decor = self.future_decor.remove(&id).unwrap_or_default(); - let span = self.span_from_with_op(start); let init = module - .const_expressions + .global_expressions .append(crate::Expression::Literal(literal), span); - self.lookup_constant.insert( - id, - LookupConstant { - handle: module.constants.append( - crate::Constant { - r#override: decor.specialization(), - name: decor.name, - ty, - init, - }, - span, - ), - type_id, - }, - ); - Ok(()) + + self.insert_parsed_constant(module, id, type_id, ty, init, span) } fn parse_composite_constant( @@ -4965,34 +5218,18 @@ impl> Frontend { let span = self.span_from_with_op(start); let constant = self.lookup_constant.lookup(component_id)?; let expr = module - .const_expressions - .append(crate::Expression::Constant(constant.handle), span); + .global_expressions + .append(constant.inner.to_expr(), span); components.push(expr); } - let decor = self.future_decor.remove(&id).unwrap_or_default(); - let span = self.span_from_with_op(start); let init = module - .const_expressions + .global_expressions .append(crate::Expression::Compose { ty, components }, span); - self.lookup_constant.insert( - id, - LookupConstant { - handle: module.constants.append( - crate::Constant { - r#override: decor.specialization(), - name: decor.name, - ty, - init, - }, - span, - ), - type_id, - }, - ); - Ok(()) + + self.insert_parsed_constant(module, id, type_id, ty, init, span) } fn parse_null_constant( @@ -5010,23 +5247,11 @@ impl> Frontend { let type_lookup = self.lookup_type.lookup(type_id)?; let ty = type_lookup.handle; - let decor = self.future_decor.remove(&id).unwrap_or_default(); - let init = module - .const_expressions + .global_expressions .append(crate::Expression::ZeroValue(ty), span); - let handle = module.constants.append( - crate::Constant { - r#override: decor.specialization(), - name: decor.name, - ty, - init, - }, - span, - ); - self.lookup_constant - .insert(id, LookupConstant { handle, type_id }); - Ok(()) + + self.insert_parsed_constant(module, id, type_id, ty, init, span) } fn parse_bool_constant( @@ -5045,27 +5270,44 @@ impl> Frontend { let type_lookup = self.lookup_type.lookup(type_id)?; let ty = type_lookup.handle; - let decor = self.future_decor.remove(&id).unwrap_or_default(); - - let init = module.const_expressions.append( + let init = module.global_expressions.append( crate::Expression::Literal(crate::Literal::Bool(value)), span, ); - self.lookup_constant.insert( - id, - LookupConstant { - handle: module.constants.append( - crate::Constant { - r#override: decor.specialization(), - name: decor.name, - ty, - init, - }, - span, - ), - type_id, - }, - ); + + self.insert_parsed_constant(module, id, type_id, ty, init, span) + } + + fn insert_parsed_constant( + &mut self, + module: &mut crate::Module, + id: u32, + type_id: u32, + ty: Handle, + init: Handle, + span: crate::Span, + ) -> Result<(), Error> { + let decor = self.future_decor.remove(&id).unwrap_or_default(); + + let inner = if let Some(id) = decor.specialization_constant_id { + let o = crate::Override { + name: decor.name, + id: Some(id.try_into().map_err(|_| Error::SpecIdTooHigh(id))?), + ty, + init: Some(init), + }; + Constant::Override(module.overrides.append(o, span)) + } else { + let c = crate::Constant { + name: decor.name, + ty, + init, + }; + Constant::Constant(module.constants.append(c, span)) + }; + + self.lookup_constant + .insert(id, LookupConstant { inner, type_id }); Ok(()) } @@ -5087,8 +5329,8 @@ impl> Frontend { let span = self.span_from_with_op(start); let lconst = self.lookup_constant.lookup(init_id)?; let expr = module - .const_expressions - .append(crate::Expression::Constant(lconst.handle), span); + .global_expressions + .append(lconst.inner.to_expr(), span); Some(expr) } else { None @@ -5209,7 +5451,7 @@ impl> Frontend { match null::generate_default_built_in( Some(built_in), ty, - &mut module.const_expressions, + &mut module.global_expressions, span, ) { Ok(handle) => Some(handle), @@ -5231,14 +5473,14 @@ impl> Frontend { let handle = null::generate_default_built_in( built_in, member.ty, - &mut module.const_expressions, + &mut module.global_expressions, span, )?; components.push(handle); } Some( module - .const_expressions + .global_expressions .append(crate::Expression::Compose { ty, components }, span), ) } @@ -5303,11 +5545,12 @@ fn make_index_literal( Ok(expr) } -fn resolve_constant( - gctx: crate::proc::GlobalCtx, - constant: Handle, -) -> Option { - match gctx.const_expressions[gctx.constants[constant].init] { +fn resolve_constant(gctx: crate::proc::GlobalCtx, constant: &Constant) -> Option { + let constant = match *constant { + Constant::Constant(constant) => constant, + Constant::Override(_) => return None, + }; + match gctx.global_expressions[gctx.constants[constant].init] { crate::Expression::Literal(crate::Literal::U32(id)) => Some(id), crate::Expression::Literal(crate::Literal::I32(id)) => Some(id as u32), _ => None, diff --git a/third_party/rust/naga/src/front/spv/null.rs b/third_party/rust/naga/src/front/spv/null.rs index 42cccca80a..c7d3776841 100644 --- a/third_party/rust/naga/src/front/spv/null.rs +++ b/third_party/rust/naga/src/front/spv/null.rs @@ -5,14 +5,14 @@ use crate::arena::{Arena, Handle}; pub fn generate_default_built_in( built_in: Option, ty: Handle, - const_expressions: &mut Arena, + global_expressions: &mut Arena, span: crate::Span, ) -> Result, Error> { let expr = match built_in { Some(crate::BuiltIn::Position { .. }) => { - let zero = const_expressions + let zero = global_expressions .append(crate::Expression::Literal(crate::Literal::F32(0.0)), span); - let one = const_expressions + let one = global_expressions .append(crate::Expression::Literal(crate::Literal::F32(1.0)), span); crate::Expression::Compose { ty, @@ -27,5 +27,5 @@ pub fn generate_default_built_in( // Note: `crate::BuiltIn::ClipDistance` is intentionally left for the default path _ => crate::Expression::ZeroValue(ty), }; - Ok(const_expressions.append(expr, span)) + Ok(global_expressions.append(expr, span)) } diff --git a/third_party/rust/naga/src/front/wgsl/error.rs b/third_party/rust/naga/src/front/wgsl/error.rs index 54aa8296b1..dc1339521c 100644 --- a/third_party/rust/naga/src/front/wgsl/error.rs +++ b/third_party/rust/naga/src/front/wgsl/error.rs @@ -13,6 +13,7 @@ use thiserror::Error; #[derive(Clone, Debug)] pub struct ParseError { message: String, + // The first span should be the primary span, and the other ones should be complementary. labels: Vec<(Span, Cow<'static, str>)>, notes: Vec, } @@ -190,7 +191,7 @@ pub enum Error<'a> { expected: String, got: String, }, - MissingType(Span), + DeclMissingTypeAndInit(Span), MissingAttribute(&'static str, Span), InvalidAtomicPointer(Span), InvalidAtomicOperandType(Span), @@ -269,6 +270,11 @@ pub enum Error<'a> { scalar: String, inner: ConstantEvaluatorError, }, + ExceededLimitForNestedBraces { + span: Span, + limit: u8, + }, + PipelineConstantIDValue(Span), } impl<'a> Error<'a> { @@ -518,11 +524,11 @@ impl<'a> Error<'a> { notes: vec![], } } - Error::MissingType(name_span) => ParseError { - message: format!("variable `{}` needs a type", &source[name_span]), + Error::DeclMissingTypeAndInit(name_span) => ParseError { + message: format!("declaration of `{}` needs a type specifier or initializer", &source[name_span]), labels: vec![( name_span, - format!("definition of `{}`", &source[name_span]).into(), + "needs a type specifier or initializer".into(), )], notes: vec![], }, @@ -770,6 +776,21 @@ impl<'a> Error<'a> { format!("the expression should have been converted to have {} scalar type", scalar), ] }, + Error::ExceededLimitForNestedBraces { span, limit } => ParseError { + message: "brace nesting limit reached".into(), + labels: vec![(span, "limit reached at this brace".into())], + notes: vec![ + format!("nesting limit is currently set to {limit}"), + ], + }, + Error::PipelineConstantIDValue(span) => ParseError { + message: "pipeline constant ID must be between 0 and 65535 inclusive".to_string(), + labels: vec![( + span, + "must be between 0 and 65535 inclusive".into(), + )], + notes: vec![], + }, } } } diff --git a/third_party/rust/naga/src/front/wgsl/index.rs b/third_party/rust/naga/src/front/wgsl/index.rs index a5524fe8f1..593405508f 100644 --- a/third_party/rust/naga/src/front/wgsl/index.rs +++ b/third_party/rust/naga/src/front/wgsl/index.rs @@ -187,6 +187,7 @@ const fn decl_ident<'a>(decl: &ast::GlobalDecl<'a>) -> ast::Ident<'a> { ast::GlobalDeclKind::Fn(ref f) => f.name, ast::GlobalDeclKind::Var(ref v) => v.name, ast::GlobalDeclKind::Const(ref c) => c.name, + ast::GlobalDeclKind::Override(ref o) => o.name, ast::GlobalDeclKind::Struct(ref s) => s.name, ast::GlobalDeclKind::Type(ref t) => t.name, } diff --git a/third_party/rust/naga/src/front/wgsl/lower/mod.rs b/third_party/rust/naga/src/front/wgsl/lower/mod.rs index 2ca6c182b7..e7cce17723 100644 --- a/third_party/rust/naga/src/front/wgsl/lower/mod.rs +++ b/third_party/rust/naga/src/front/wgsl/lower/mod.rs @@ -86,6 +86,8 @@ pub struct GlobalContext<'source, 'temp, 'out> { module: &'out mut crate::Module, const_typifier: &'temp mut Typifier, + + global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker, } impl<'source> GlobalContext<'source, '_, '_> { @@ -97,6 +99,19 @@ impl<'source> GlobalContext<'source, '_, '_> { module: self.module, const_typifier: self.const_typifier, expr_type: ExpressionContextType::Constant, + global_expression_kind_tracker: self.global_expression_kind_tracker, + } + } + + fn as_override(&mut self) -> ExpressionContext<'source, '_, '_> { + ExpressionContext { + ast_expressions: self.ast_expressions, + globals: self.globals, + types: self.types, + module: self.module, + const_typifier: self.const_typifier, + expr_type: ExpressionContextType::Override, + global_expression_kind_tracker: self.global_expression_kind_tracker, } } @@ -164,7 +179,8 @@ pub struct StatementContext<'source, 'temp, 'out> { /// with the form of the expressions; it is also tracking whether WGSL says /// we should consider them to be const. See the use of `force_non_const` in /// the code for lowering `let` bindings. - expression_constness: &'temp mut crate::proc::ExpressionConstnessTracker, + local_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker, + global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker, } impl<'a, 'temp> StatementContext<'a, 'temp, '_> { @@ -181,6 +197,7 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> { types: self.types, ast_expressions: self.ast_expressions, const_typifier: self.const_typifier, + global_expression_kind_tracker: self.global_expression_kind_tracker, module: self.module, expr_type: ExpressionContextType::Runtime(RuntimeExpressionContext { local_table: self.local_table, @@ -188,7 +205,7 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> { block, emitter, typifier: self.typifier, - expression_constness: self.expression_constness, + local_expression_kind_tracker: self.local_expression_kind_tracker, }), } } @@ -200,6 +217,7 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> { types: self.types, module: self.module, const_typifier: self.const_typifier, + global_expression_kind_tracker: self.global_expression_kind_tracker, } } @@ -232,8 +250,8 @@ pub struct RuntimeExpressionContext<'temp, 'out> { /// Which `Expression`s in `self.naga_expressions` are const expressions, in /// the WGSL sense. /// - /// See [`StatementContext::expression_constness`] for details. - expression_constness: &'temp mut crate::proc::ExpressionConstnessTracker, + /// See [`StatementContext::local_expression_kind_tracker`] for details. + local_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker, } /// The type of Naga IR expression we are lowering an [`ast::Expression`] to. @@ -253,6 +271,14 @@ pub enum ExpressionContextType<'temp, 'out> { /// available in the [`ExpressionContext`], so this variant /// carries no further information. Constant, + + /// We are lowering to an override expression, to be included in the module's + /// constant expression arena. + /// + /// Everything override expressions are allowed to refer to is + /// available in the [`ExpressionContext`], so this variant + /// carries no further information. + Override, } /// State for lowering an [`ast::Expression`] to Naga IR. @@ -307,10 +333,11 @@ pub struct ExpressionContext<'source, 'temp, 'out> { /// [`Module`]: crate::Module module: &'out mut crate::Module, - /// Type judgments for [`module::const_expressions`]. + /// Type judgments for [`module::global_expressions`]. /// - /// [`module::const_expressions`]: crate::Module::const_expressions + /// [`module::global_expressions`]: crate::Module::global_expressions const_typifier: &'temp mut Typifier, + global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker, /// Whether we are lowering a constant expression or a general /// runtime expression, and the data needed in each case. @@ -326,6 +353,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { const_typifier: self.const_typifier, module: self.module, expr_type: ExpressionContextType::Constant, + global_expression_kind_tracker: self.global_expression_kind_tracker, } } @@ -336,6 +364,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { types: self.types, module: self.module, const_typifier: self.const_typifier, + global_expression_kind_tracker: self.global_expression_kind_tracker, } } @@ -344,11 +373,20 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { ExpressionContextType::Runtime(ref mut rctx) => ConstantEvaluator::for_wgsl_function( self.module, &mut rctx.function.expressions, - rctx.expression_constness, + rctx.local_expression_kind_tracker, rctx.emitter, rctx.block, ), - ExpressionContextType::Constant => ConstantEvaluator::for_wgsl_module(self.module), + ExpressionContextType::Constant => ConstantEvaluator::for_wgsl_module( + self.module, + self.global_expression_kind_tracker, + false, + ), + ExpressionContextType::Override => ConstantEvaluator::for_wgsl_module( + self.module, + self.global_expression_kind_tracker, + true, + ), } } @@ -358,24 +396,14 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { span: Span, ) -> Result, Error<'source>> { let mut eval = self.as_const_evaluator(); - match eval.try_eval_and_append(&expr, span) { - Ok(expr) => Ok(expr), - - // `expr` is not a constant expression. This is fine as - // long as we're not building `Module::const_expressions`. - Err(err) => match self.expr_type { - ExpressionContextType::Runtime(ref mut rctx) => { - Ok(rctx.function.expressions.append(expr, span)) - } - ExpressionContextType::Constant => Err(Error::ConstantEvaluatorError(err, span)), - }, - } + eval.try_eval_and_append(expr, span) + .map_err(|e| Error::ConstantEvaluatorError(e, span)) } fn const_access(&self, handle: Handle) -> Option { match self.expr_type { ExpressionContextType::Runtime(ref ctx) => { - if !ctx.expression_constness.is_const(handle) { + if !ctx.local_expression_kind_tracker.is_const(handle) { return None; } @@ -385,20 +413,25 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { .ok() } ExpressionContextType::Constant => self.module.to_ctx().eval_expr_to_u32(handle).ok(), + ExpressionContextType::Override => None, } } fn get_expression_span(&self, handle: Handle) -> Span { match self.expr_type { ExpressionContextType::Runtime(ref ctx) => ctx.function.expressions.get_span(handle), - ExpressionContextType::Constant => self.module.const_expressions.get_span(handle), + ExpressionContextType::Constant | ExpressionContextType::Override => { + self.module.global_expressions.get_span(handle) + } } } fn typifier(&self) -> &Typifier { match self.expr_type { ExpressionContextType::Runtime(ref ctx) => ctx.typifier, - ExpressionContextType::Constant => self.const_typifier, + ExpressionContextType::Constant | ExpressionContextType::Override => { + self.const_typifier + } } } @@ -408,7 +441,9 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { ) -> Result<&mut RuntimeExpressionContext<'temp, 'out>, Error<'source>> { match self.expr_type { ExpressionContextType::Runtime(ref mut ctx) => Ok(ctx), - ExpressionContextType::Constant => Err(Error::UnexpectedOperationInConstContext(span)), + ExpressionContextType::Constant | ExpressionContextType::Override => { + Err(Error::UnexpectedOperationInConstContext(span)) + } } } @@ -420,7 +455,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { ) -> Result> { match self.expr_type { ExpressionContextType::Runtime(ref rctx) => { - if !rctx.expression_constness.is_const(expr) { + if !rctx.local_expression_kind_tracker.is_const(expr) { return Err(Error::ExpectedConstExprConcreteIntegerScalar( component_span, )); @@ -445,7 +480,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { } // This means a `gather` operation appeared in a constant expression. // This error refers to the `gather` itself, not its "component" argument. - ExpressionContextType::Constant => { + ExpressionContextType::Constant | ExpressionContextType::Override => { Err(Error::UnexpectedOperationInConstContext(gather_span)) } } @@ -471,7 +506,9 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { // to also borrow self.module.types mutably below. let typifier = match self.expr_type { ExpressionContextType::Runtime(ref ctx) => ctx.typifier, - ExpressionContextType::Constant => &*self.const_typifier, + ExpressionContextType::Constant | ExpressionContextType::Override => { + &*self.const_typifier + } }; Ok(typifier.register_type(handle, &mut self.module.types)) } @@ -514,10 +551,10 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { typifier = &mut *ctx.typifier; expressions = &ctx.function.expressions; } - ExpressionContextType::Constant => { + ExpressionContextType::Constant | ExpressionContextType::Override => { resolve_ctx = ResolveContext::with_locals(self.module, &empty_arena, &[]); typifier = self.const_typifier; - expressions = &self.module.const_expressions; + expressions = &self.module.global_expressions; } }; typifier @@ -610,14 +647,14 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { rctx.block .extend(rctx.emitter.finish(&rctx.function.expressions)); } - ExpressionContextType::Constant => {} + ExpressionContextType::Constant | ExpressionContextType::Override => {} } let result = self.append_expression(expression, span); match self.expr_type { ExpressionContextType::Runtime(ref mut rctx) => { rctx.emitter.start(&rctx.function.expressions); } - ExpressionContextType::Constant => {} + ExpressionContextType::Constant | ExpressionContextType::Override => {} } result } @@ -786,6 +823,7 @@ enum LoweredGlobalDecl { Function(Handle), Var(Handle), Const(Handle), + Override(Handle), Type(Handle), EntryPoint, } @@ -836,6 +874,29 @@ impl Texture { } } +enum SubgroupGather { + BroadcastFirst, + Broadcast, + Shuffle, + ShuffleDown, + ShuffleUp, + ShuffleXor, +} + +impl SubgroupGather { + pub fn map(word: &str) -> Option { + Some(match word { + "subgroupBroadcastFirst" => Self::BroadcastFirst, + "subgroupBroadcast" => Self::Broadcast, + "subgroupShuffle" => Self::Shuffle, + "subgroupShuffleDown" => Self::ShuffleDown, + "subgroupShuffleUp" => Self::ShuffleUp, + "subgroupShuffleXor" => Self::ShuffleXor, + _ => return None, + }) + } +} + pub struct Lowerer<'source, 'temp> { index: &'temp Index<'source>, layouter: Layouter, @@ -861,6 +922,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { types: &tu.types, module: &mut module, const_typifier: &mut Typifier::new(), + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker::new(), }; for decl_handle in self.index.visit_ordered() { @@ -877,7 +939,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let init; if let Some(init_ast) = v.init { - let mut ectx = ctx.as_const(); + let mut ectx = ctx.as_override(); let lowered = self.expression_for_abstract(init_ast, &mut ectx)?; let ty_res = crate::proc::TypeResolution::Handle(ty); let converted = ectx @@ -956,7 +1018,6 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let handle = ctx.module.constants.append( crate::Constant { name: Some(c.name.name.to_string()), - r#override: crate::Override::None, ty, init, }, @@ -966,6 +1027,65 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ctx.globals .insert(c.name.name, LoweredGlobalDecl::Const(handle)); } + ast::GlobalDeclKind::Override(ref o) => { + let init = o + .init + .map(|init| self.expression(init, &mut ctx.as_override())) + .transpose()?; + let inferred_type = init + .map(|init| ctx.as_const().register_type(init)) + .transpose()?; + + let explicit_ty = + o.ty.map(|ty| self.resolve_ast_type(ty, &mut ctx)) + .transpose()?; + + let id = + o.id.map(|id| self.const_u32(id, &mut ctx.as_const())) + .transpose()?; + + let id = if let Some((id, id_span)) = id { + Some( + u16::try_from(id) + .map_err(|_| Error::PipelineConstantIDValue(id_span))?, + ) + } else { + None + }; + + let ty = match (explicit_ty, inferred_type) { + (Some(explicit_ty), Some(inferred_type)) => { + if explicit_ty == inferred_type { + explicit_ty + } else { + let gctx = ctx.module.to_ctx(); + return Err(Error::InitializationTypeMismatch { + name: o.name.span, + expected: explicit_ty.to_wgsl(&gctx), + got: inferred_type.to_wgsl(&gctx), + }); + } + } + (Some(explicit_ty), None) => explicit_ty, + (None, Some(inferred_type)) => inferred_type, + (None, None) => { + return Err(Error::DeclMissingTypeAndInit(o.name.span)); + } + }; + + let handle = ctx.module.overrides.append( + crate::Override { + name: Some(o.name.name.to_string()), + id, + ty, + init, + }, + span, + ); + + ctx.globals + .insert(o.name.name, LoweredGlobalDecl::Override(handle)); + } ast::GlobalDeclKind::Struct(ref s) => { let handle = self.r#struct(s, span, &mut ctx)?; ctx.globals @@ -1000,6 +1120,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let mut local_table = FastHashMap::default(); let mut expressions = Arena::new(); let mut named_expressions = FastIndexMap::default(); + let mut local_expression_kind_tracker = crate::proc::ExpressionKindTracker::new(); let arguments = f .arguments @@ -1011,6 +1132,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .append(crate::Expression::FunctionArgument(i as u32), arg.name.span); local_table.insert(arg.handle, Typed::Plain(expr)); named_expressions.insert(expr, (arg.name.name.to_string(), arg.name.span)); + local_expression_kind_tracker.insert(expr, crate::proc::ExpressionKind::Runtime); Ok(crate::FunctionArgument { name: Some(arg.name.name.to_string()), @@ -1053,7 +1175,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { named_expressions: &mut named_expressions, types: ctx.types, module: ctx.module, - expression_constness: &mut crate::proc::ExpressionConstnessTracker::new(), + local_expression_kind_tracker: &mut local_expression_kind_tracker, + global_expression_kind_tracker: ctx.global_expression_kind_tracker, }; let mut body = self.block(&f.body, false, &mut stmt_ctx)?; ensure_block_returns(&mut body); @@ -1132,7 +1255,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { // affects when errors must be reported, so we can't even // treat suitable `let` bindings as constant as an // optimization. - ctx.expression_constness.force_non_const(value); + ctx.local_expression_kind_tracker.force_non_const(value); let explicit_ty = l.ty.map(|ty| self.resolve_ast_type(ty, &mut ctx.as_global())) @@ -1203,7 +1326,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ty = explicit_ty; initializer = None; } - (None, None) => return Err(Error::MissingType(v.name.span)), + (None, None) => return Err(Error::DeclMissingTypeAndInit(v.name.span)), } let (const_initializer, initializer) = { @@ -1216,7 +1339,9 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { // - the initialization is not a constant // expression, so its value depends on the // state at the point of initialization. - if is_inside_loop || !ctx.expression_constness.is_const(init) { + if is_inside_loop + || !ctx.local_expression_kind_tracker.is_const_or_override(init) + { (None, Some(init)) } else { (Some(init), None) @@ -1469,6 +1594,10 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .function .expressions .append(crate::Expression::Binary { op, left, right }, stmt.span); + rctx.local_expression_kind_tracker + .insert(left, crate::proc::ExpressionKind::Runtime); + rctx.local_expression_kind_tracker + .insert(value, crate::proc::ExpressionKind::Runtime); block.extend(emitter.finish(&ctx.function.expressions)); crate::Statement::Store { @@ -1562,7 +1691,12 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { LoweredGlobalDecl::Const(handle) => { Typed::Plain(crate::Expression::Constant(handle)) } - _ => { + LoweredGlobalDecl::Override(handle) => { + Typed::Plain(crate::Expression::Override(handle)) + } + LoweredGlobalDecl::Function(_) + | LoweredGlobalDecl::Type(_) + | LoweredGlobalDecl::EntryPoint => { return Err(Error::Unexpected(span, ExpectedToken::Variable)); } }; @@ -1819,9 +1953,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { )?; Ok(Some(handle)) } - Some(&LoweredGlobalDecl::Const(_) | &LoweredGlobalDecl::Var(_)) => { - Err(Error::Unexpected(function.span, ExpectedToken::Function)) - } + Some( + &LoweredGlobalDecl::Const(_) + | &LoweredGlobalDecl::Override(_) + | &LoweredGlobalDecl::Var(_), + ) => Err(Error::Unexpected(function.span, ExpectedToken::Function)), Some(&LoweredGlobalDecl::EntryPoint) => Err(Error::CalledEntryPoint(function.span)), Some(&LoweredGlobalDecl::Function(function)) => { let arguments = arguments @@ -1835,9 +1971,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { rctx.block .extend(rctx.emitter.finish(&rctx.function.expressions)); let result = has_result.then(|| { - rctx.function + let result = rctx + .function .expressions - .append(crate::Expression::CallResult(function), span) + .append(crate::Expression::CallResult(function), span); + rctx.local_expression_kind_tracker + .insert(result, crate::proc::ExpressionKind::Runtime); + result }); rctx.emitter.start(&rctx.function.expressions); rctx.block.push( @@ -1937,6 +2077,16 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { } } else if let Some(fun) = Texture::map(function.name) { self.texture_sample_helper(fun, arguments, span, ctx)? + } else if let Some((op, cop)) = conv::map_subgroup_operation(function.name) { + return Ok(Some( + self.subgroup_operation_helper(span, op, cop, arguments, ctx)?, + )); + } else if let Some(mode) = SubgroupGather::map(function.name) { + return Ok(Some( + self.subgroup_gather_helper(span, mode, arguments, ctx)?, + )); + } else if let Some(fun) = crate::AtomicFunction::map(function.name) { + return Ok(Some(self.atomic_helper(span, fun, arguments, ctx)?)); } else { match function.name { "select" => { @@ -1982,70 +2132,6 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .push(crate::Statement::Store { pointer, value }, span); return Ok(None); } - "atomicAdd" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::Add, - arguments, - ctx, - )?)) - } - "atomicSub" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::Subtract, - arguments, - ctx, - )?)) - } - "atomicAnd" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::And, - arguments, - ctx, - )?)) - } - "atomicOr" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::InclusiveOr, - arguments, - ctx, - )?)) - } - "atomicXor" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::ExclusiveOr, - arguments, - ctx, - )?)) - } - "atomicMin" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::Min, - arguments, - ctx, - )?)) - } - "atomicMax" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::Max, - arguments, - ctx, - )?)) - } - "atomicExchange" => { - return Ok(Some(self.atomic_helper( - span, - crate::AtomicFunction::Exchange { compare: None }, - arguments, - ctx, - )?)) - } "atomicCompareExchangeWeak" => { let mut args = ctx.prepare_args(arguments, 3, span); @@ -2104,6 +2190,14 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .push(crate::Statement::Barrier(crate::Barrier::WORK_GROUP), span); return Ok(None); } + "subgroupBarrier" => { + ctx.prepare_args(arguments, 0, span).finish()?; + + let rctx = ctx.runtime_expression_ctx(span)?; + rctx.block + .push(crate::Statement::Barrier(crate::Barrier::SUB_GROUP), span); + return Ok(None); + } "workgroupUniformLoad" => { let mut args = ctx.prepare_args(arguments, 1, span); let expr = args.next()?; @@ -2311,6 +2405,22 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { )?; return Ok(Some(handle)); } + "subgroupBallot" => { + let mut args = ctx.prepare_args(arguments, 0, span); + let predicate = if arguments.len() == 1 { + Some(self.expression(args.next()?, ctx)?) + } else { + None + }; + args.finish()?; + + let result = ctx + .interrupt_emitter(crate::Expression::SubgroupBallotResult, span)?; + let rctx = ctx.runtime_expression_ctx(span)?; + rctx.block + .push(crate::Statement::SubgroupBallot { result, predicate }, span); + return Ok(Some(result)); + } _ => return Err(Error::UnknownIdent(function.span, function.name)), } }; @@ -2502,6 +2612,80 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { }) } + fn subgroup_operation_helper( + &mut self, + span: Span, + op: crate::SubgroupOperation, + collective_op: crate::CollectiveOperation, + arguments: &[Handle>], + ctx: &mut ExpressionContext<'source, '_, '_>, + ) -> Result, Error<'source>> { + let mut args = ctx.prepare_args(arguments, 1, span); + + let argument = self.expression(args.next()?, ctx)?; + args.finish()?; + + let ty = ctx.register_type(argument)?; + + let result = + ctx.interrupt_emitter(crate::Expression::SubgroupOperationResult { ty }, span)?; + let rctx = ctx.runtime_expression_ctx(span)?; + rctx.block.push( + crate::Statement::SubgroupCollectiveOperation { + op, + collective_op, + argument, + result, + }, + span, + ); + Ok(result) + } + + fn subgroup_gather_helper( + &mut self, + span: Span, + mode: SubgroupGather, + arguments: &[Handle>], + ctx: &mut ExpressionContext<'source, '_, '_>, + ) -> Result, Error<'source>> { + let mut args = ctx.prepare_args(arguments, 2, span); + + let argument = self.expression(args.next()?, ctx)?; + + use SubgroupGather as Sg; + let mode = if let Sg::BroadcastFirst = mode { + crate::GatherMode::BroadcastFirst + } else { + let index = self.expression(args.next()?, ctx)?; + match mode { + Sg::Broadcast => crate::GatherMode::Broadcast(index), + Sg::Shuffle => crate::GatherMode::Shuffle(index), + Sg::ShuffleDown => crate::GatherMode::ShuffleDown(index), + Sg::ShuffleUp => crate::GatherMode::ShuffleUp(index), + Sg::ShuffleXor => crate::GatherMode::ShuffleXor(index), + Sg::BroadcastFirst => unreachable!(), + } + }; + + args.finish()?; + + let ty = ctx.register_type(argument)?; + + let result = + ctx.interrupt_emitter(crate::Expression::SubgroupOperationResult { ty }, span)?; + let rctx = ctx.runtime_expression_ctx(span)?; + rctx.block.push( + crate::Statement::SubgroupGather { + mode, + argument, + result, + }, + span, + ); + Ok(result) + } + fn r#struct( &mut self, s: &ast::Struct<'source>, @@ -2760,3 +2944,19 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { } } } + +impl crate::AtomicFunction { + pub fn map(word: &str) -> Option { + Some(match word { + "atomicAdd" => crate::AtomicFunction::Add, + "atomicSub" => crate::AtomicFunction::Subtract, + "atomicAnd" => crate::AtomicFunction::And, + "atomicOr" => crate::AtomicFunction::InclusiveOr, + "atomicXor" => crate::AtomicFunction::ExclusiveOr, + "atomicMin" => crate::AtomicFunction::Min, + "atomicMax" => crate::AtomicFunction::Max, + "atomicExchange" => crate::AtomicFunction::Exchange { compare: None }, + _ => return None, + }) + } +} diff --git a/third_party/rust/naga/src/front/wgsl/mod.rs b/third_party/rust/naga/src/front/wgsl/mod.rs index b6151fe1c0..aec1e657fc 100644 --- a/third_party/rust/naga/src/front/wgsl/mod.rs +++ b/third_party/rust/naga/src/front/wgsl/mod.rs @@ -44,6 +44,17 @@ impl Frontend { } } +///
+// NOTE: Keep this in sync with `wgpu::Device::create_shader_module`! +// NOTE: Keep this in sync with `wgpu_core::Global::device_create_shader_module`! +/// +/// This function may consume a lot of stack space. Compiler-enforced limits for parsing recursion +/// exist; if shader compilation runs into them, it will return an error gracefully. However, on +/// some build profiles and platforms, the default stack size for a thread may be exceeded before +/// this limit is reached during parsing. Callers should ensure that there is enough stack space +/// for this, particularly if calls to this method are exposed to user input. +/// +///
pub fn parse_str(source: &str) -> Result { Frontend::new().parse(source) } diff --git a/third_party/rust/naga/src/front/wgsl/parse/ast.rs b/third_party/rust/naga/src/front/wgsl/parse/ast.rs index dbaac523cb..ea8013ee7c 100644 --- a/third_party/rust/naga/src/front/wgsl/parse/ast.rs +++ b/third_party/rust/naga/src/front/wgsl/parse/ast.rs @@ -82,6 +82,7 @@ pub enum GlobalDeclKind<'a> { Fn(Function<'a>), Var(GlobalVariable<'a>), Const(Const<'a>), + Override(Override<'a>), Struct(Struct<'a>), Type(TypeAlias<'a>), } @@ -200,6 +201,14 @@ pub struct Const<'a> { pub init: Handle>, } +#[derive(Debug)] +pub struct Override<'a> { + pub name: Ident<'a>, + pub id: Option>>, + pub ty: Option>>, + pub init: Option>>, +} + /// The size of an [`Array`] or [`BindingArray`]. /// /// [`Array`]: Type::Array diff --git a/third_party/rust/naga/src/front/wgsl/parse/conv.rs b/third_party/rust/naga/src/front/wgsl/parse/conv.rs index 1a4911a3bd..207f0eda41 100644 --- a/third_party/rust/naga/src/front/wgsl/parse/conv.rs +++ b/third_party/rust/naga/src/front/wgsl/parse/conv.rs @@ -35,6 +35,11 @@ pub fn map_built_in(word: &str, span: Span) -> Result> "local_invocation_index" => crate::BuiltIn::LocalInvocationIndex, "workgroup_id" => crate::BuiltIn::WorkGroupId, "num_workgroups" => crate::BuiltIn::NumWorkGroups, + // subgroup + "num_subgroups" => crate::BuiltIn::NumSubgroups, + "subgroup_id" => crate::BuiltIn::SubgroupId, + "subgroup_size" => crate::BuiltIn::SubgroupSize, + "subgroup_invocation_id" => crate::BuiltIn::SubgroupInvocationId, _ => return Err(Error::UnknownBuiltin(span)), }) } @@ -260,3 +265,26 @@ pub fn map_conservative_depth( _ => Err(Error::UnknownConservativeDepth(span)), } } + +pub fn map_subgroup_operation( + word: &str, +) -> Option<(crate::SubgroupOperation, crate::CollectiveOperation)> { + use crate::CollectiveOperation as co; + use crate::SubgroupOperation as sg; + Some(match word { + "subgroupAll" => (sg::All, co::Reduce), + "subgroupAny" => (sg::Any, co::Reduce), + "subgroupAdd" => (sg::Add, co::Reduce), + "subgroupMul" => (sg::Mul, co::Reduce), + "subgroupMin" => (sg::Min, co::Reduce), + "subgroupMax" => (sg::Max, co::Reduce), + "subgroupAnd" => (sg::And, co::Reduce), + "subgroupOr" => (sg::Or, co::Reduce), + "subgroupXor" => (sg::Xor, co::Reduce), + "subgroupExclusiveAdd" => (sg::Add, co::ExclusiveScan), + "subgroupExclusiveMul" => (sg::Mul, co::ExclusiveScan), + "subgroupInclusiveAdd" => (sg::Add, co::InclusiveScan), + "subgroupInclusiveMul" => (sg::Mul, co::InclusiveScan), + _ => return None, + }) +} diff --git a/third_party/rust/naga/src/front/wgsl/parse/mod.rs b/third_party/rust/naga/src/front/wgsl/parse/mod.rs index 51fc2f013b..79ea1ae609 100644 --- a/third_party/rust/naga/src/front/wgsl/parse/mod.rs +++ b/third_party/rust/naga/src/front/wgsl/parse/mod.rs @@ -1619,22 +1619,21 @@ impl Parser { lexer: &mut Lexer<'a>, ctx: &mut ExpressionContext<'a, '_, '_>, block: &mut ast::Block<'a>, + brace_nesting_level: u8, ) -> Result<(), Error<'a>> { self.push_rule_span(Rule::Statement, lexer); match lexer.peek() { (Token::Separator(';'), _) => { let _ = lexer.next(); self.pop_rule_span(lexer); - return Ok(()); } (Token::Paren('{'), _) => { - let (inner, span) = self.block(lexer, ctx)?; + let (inner, span) = self.block(lexer, ctx, brace_nesting_level)?; block.stmts.push(ast::Statement { kind: ast::StatementKind::Block(inner), span, }); self.pop_rule_span(lexer); - return Ok(()); } (Token::Word(word), _) => { let kind = match word { @@ -1711,7 +1710,7 @@ impl Parser { let _ = lexer.next(); let condition = self.general_expression(lexer, ctx)?; - let accept = self.block(lexer, ctx)?.0; + let accept = self.block(lexer, ctx, brace_nesting_level)?.0; let mut elsif_stack = Vec::new(); let mut elseif_span_start = lexer.start_byte_offset(); @@ -1722,12 +1721,12 @@ impl Parser { if !lexer.skip(Token::Word("if")) { // ... else { ... } - break self.block(lexer, ctx)?.0; + break self.block(lexer, ctx, brace_nesting_level)?.0; } // ... else if (...) { ... } let other_condition = self.general_expression(lexer, ctx)?; - let other_block = self.block(lexer, ctx)?; + let other_block = self.block(lexer, ctx, brace_nesting_level)?; elsif_stack.push((elseif_span_start, other_condition, other_block)); elseif_span_start = lexer.start_byte_offset(); }; @@ -1759,7 +1758,9 @@ impl Parser { "switch" => { let _ = lexer.next(); let selector = self.general_expression(lexer, ctx)?; - lexer.expect(Token::Paren('{'))?; + let brace_span = lexer.expect_span(Token::Paren('{'))?; + let brace_nesting_level = + Self::increase_brace_nesting(brace_nesting_level, brace_span)?; let mut cases = Vec::new(); loop { @@ -1784,7 +1785,7 @@ impl Parser { }); }; - let body = self.block(lexer, ctx)?.0; + let body = self.block(lexer, ctx, brace_nesting_level)?.0; cases.push(ast::SwitchCase { value, @@ -1794,7 +1795,7 @@ impl Parser { } (Token::Word("default"), _) => { lexer.skip(Token::Separator(':')); - let body = self.block(lexer, ctx)?.0; + let body = self.block(lexer, ctx, brace_nesting_level)?.0; cases.push(ast::SwitchCase { value: ast::SwitchValue::Default, body, @@ -1810,7 +1811,7 @@ impl Parser { ast::StatementKind::Switch { selector, cases } } - "loop" => self.r#loop(lexer, ctx)?, + "loop" => self.r#loop(lexer, ctx, brace_nesting_level)?, "while" => { let _ = lexer.next(); let mut body = ast::Block::default(); @@ -1834,7 +1835,7 @@ impl Parser { span, }); - let (block, span) = self.block(lexer, ctx)?; + let (block, span) = self.block(lexer, ctx, brace_nesting_level)?; body.stmts.push(ast::Statement { kind: ast::StatementKind::Block(block), span, @@ -1857,7 +1858,9 @@ impl Parser { let (_, span) = { let ctx = &mut *ctx; let block = &mut *block; - lexer.capture_span(|lexer| self.statement(lexer, ctx, block))? + lexer.capture_span(|lexer| { + self.statement(lexer, ctx, block, brace_nesting_level) + })? }; if block.stmts.len() != num_statements { @@ -1902,7 +1905,7 @@ impl Parser { lexer.expect(Token::Paren(')'))?; } - let (block, span) = self.block(lexer, ctx)?; + let (block, span) = self.block(lexer, ctx, brace_nesting_level)?; body.stmts.push(ast::Statement { kind: ast::StatementKind::Block(block), span, @@ -1964,13 +1967,15 @@ impl Parser { &mut self, lexer: &mut Lexer<'a>, ctx: &mut ExpressionContext<'a, '_, '_>, + brace_nesting_level: u8, ) -> Result, Error<'a>> { let _ = lexer.next(); let mut body = ast::Block::default(); let mut continuing = ast::Block::default(); let mut break_if = None; - lexer.expect(Token::Paren('{'))?; + let brace_span = lexer.expect_span(Token::Paren('{'))?; + let brace_nesting_level = Self::increase_brace_nesting(brace_nesting_level, brace_span)?; ctx.local_table.push_scope(); @@ -1980,7 +1985,9 @@ impl Parser { // the last thing in the loop body // Expect a opening brace to start the continuing block - lexer.expect(Token::Paren('{'))?; + let brace_span = lexer.expect_span(Token::Paren('{'))?; + let brace_nesting_level = + Self::increase_brace_nesting(brace_nesting_level, brace_span)?; loop { if lexer.skip(Token::Word("break")) { // Branch for the `break if` statement, this statement @@ -2009,7 +2016,7 @@ impl Parser { break; } else { // Otherwise try to parse a statement - self.statement(lexer, ctx, &mut continuing)?; + self.statement(lexer, ctx, &mut continuing, brace_nesting_level)?; } } // Since the continuing block must be the last part of the loop body, @@ -2023,7 +2030,7 @@ impl Parser { break; } // Otherwise try to parse a statement - self.statement(lexer, ctx, &mut body)?; + self.statement(lexer, ctx, &mut body, brace_nesting_level)?; } ctx.local_table.pop_scope(); @@ -2040,15 +2047,17 @@ impl Parser { &mut self, lexer: &mut Lexer<'a>, ctx: &mut ExpressionContext<'a, '_, '_>, + brace_nesting_level: u8, ) -> Result<(ast::Block<'a>, Span), Error<'a>> { self.push_rule_span(Rule::Block, lexer); ctx.local_table.push_scope(); - lexer.expect(Token::Paren('{'))?; + let brace_span = lexer.expect_span(Token::Paren('{'))?; + let brace_nesting_level = Self::increase_brace_nesting(brace_nesting_level, brace_span)?; let mut block = ast::Block::default(); while !lexer.skip(Token::Paren('}')) { - self.statement(lexer, ctx, &mut block)?; + self.statement(lexer, ctx, &mut block, brace_nesting_level)?; } ctx.local_table.pop_scope(); @@ -2135,9 +2144,10 @@ impl Parser { // do not use `self.block` here, since we must not push a new scope lexer.expect(Token::Paren('{'))?; + let brace_nesting_level = 1; let mut body = ast::Block::default(); while !lexer.skip(Token::Paren('}')) { - self.statement(lexer, &mut ctx, &mut body)?; + self.statement(lexer, &mut ctx, &mut body, brace_nesting_level)?; } ctx.local_table.pop_scope(); @@ -2170,6 +2180,7 @@ impl Parser { let mut early_depth_test = ParsedAttribute::default(); let (mut bind_index, mut bind_group) = (ParsedAttribute::default(), ParsedAttribute::default()); + let mut id = ParsedAttribute::default(); let mut dependencies = FastIndexSet::default(); let mut ctx = ExpressionContext { @@ -2193,6 +2204,11 @@ impl Parser { bind_group.set(self.general_expression(lexer, &mut ctx)?, name_span)?; lexer.expect(Token::Paren(')'))?; } + ("id", name_span) => { + lexer.expect(Token::Paren('('))?; + id.set(self.general_expression(lexer, &mut ctx)?, name_span)?; + lexer.expect(Token::Paren(')'))?; + } ("vertex", name_span) => { stage.set(crate::ShaderStage::Vertex, name_span)?; } @@ -2283,6 +2299,30 @@ impl Parser { Some(ast::GlobalDeclKind::Const(ast::Const { name, ty, init })) } + (Token::Word("override"), _) => { + let name = lexer.next_ident()?; + + let ty = if lexer.skip(Token::Separator(':')) { + Some(self.type_decl(lexer, &mut ctx)?) + } else { + None + }; + + let init = if lexer.skip(Token::Operation('=')) { + Some(self.general_expression(lexer, &mut ctx)?) + } else { + None + }; + + lexer.expect(Token::Separator(';'))?; + + Some(ast::GlobalDeclKind::Override(ast::Override { + name, + id: id.value, + ty, + init, + })) + } (Token::Word("var"), _) => { let mut var = self.variable_decl(lexer, &mut ctx)?; var.binding = binding.take(); @@ -2347,4 +2387,30 @@ impl Parser { Ok(tu) } + + const fn increase_brace_nesting( + brace_nesting_level: u8, + brace_span: Span, + ) -> Result> { + // From [spec.](https://gpuweb.github.io/gpuweb/wgsl/#limits): + // + // > § 2.4. Limits + // > + // > … + // > + // > Maximum nesting depth of brace-enclosed statements in a function[:] 127 + // + // _However_, we choose 64 instead because (a) it avoids stack overflows in CI and + // (b) we expect the limit to be decreased to 63 based on this conversation in + // WebGPU CTS upstream: + // + const BRACE_NESTING_MAXIMUM: u8 = 64; + if brace_nesting_level + 1 > BRACE_NESTING_MAXIMUM { + return Err(Error::ExceededLimitForNestedBraces { + span: brace_span, + limit: BRACE_NESTING_MAXIMUM, + }); + } + Ok(brace_nesting_level + 1) + } } diff --git a/third_party/rust/naga/src/front/wgsl/to_wgsl.rs b/third_party/rust/naga/src/front/wgsl/to_wgsl.rs index c8331ace09..63bc9f7317 100644 --- a/third_party/rust/naga/src/front/wgsl/to_wgsl.rs +++ b/third_party/rust/naga/src/front/wgsl/to_wgsl.rs @@ -226,7 +226,8 @@ mod tests { let gctx = crate::proc::GlobalCtx { types: &types, constants: &crate::Arena::new(), - const_expressions: &crate::Arena::new(), + overrides: &crate::Arena::new(), + global_expressions: &crate::Arena::new(), }; let array = crate::TypeInner::Array { base: mytype1, diff --git a/third_party/rust/naga/src/lib.rs b/third_party/rust/naga/src/lib.rs index 4b45174300..24e1b02c76 100644 --- a/third_party/rust/naga/src/lib.rs +++ b/third_party/rust/naga/src/lib.rs @@ -34,9 +34,6 @@ with optional span info, representing a series of statements executed in order. `EntryPoint`s or `Function` is a `Block`, and `Statement` has a [`Block`][Statement::Block] variant. -If the `clone` feature is enabled, [`Arena`], [`UniqueArena`], [`Type`], [`TypeInner`], -[`Constant`], [`Function`], [`EntryPoint`] and [`Module`] can be cloned. - ## Arenas To improve translator performance and reduce memory usage, most structures are @@ -175,7 +172,7 @@ tree. A Naga *constant expression* is one of the following [`Expression`] variants, whose operands (if any) are also constant expressions: - [`Literal`] -- [`Constant`], for [`Constant`s][const_type] whose [`override`] is [`None`] +- [`Constant`], for [`Constant`]s - [`ZeroValue`], for fixed-size types - [`Compose`] - [`Access`] @@ -194,8 +191,7 @@ A constant expression can be evaluated at module translation time. ## Override expressions A Naga *override expression* is the same as a [constant expression], -except that it is also allowed to refer to [`Constant`s][const_type] -whose [`override`] is something other than [`None`]. +except that it is also allowed to reference other [`Override`]s. An override expression can be evaluated at pipeline creation time. @@ -238,10 +234,6 @@ An override expression can be evaluated at pipeline creation time. [`Math`]: Expression::Math [`As`]: Expression::As -[const_type]: Constant -[`override`]: Constant::override -[`None`]: Override::None - [constant expression]: index.html#constant-expressions */ @@ -282,6 +274,7 @@ pub mod back; mod block; #[cfg(feature = "compact")] pub mod compact; +pub mod error; pub mod front; pub mod keywords; pub mod proc; @@ -439,6 +432,11 @@ pub enum BuiltIn { WorkGroupId, WorkGroupSize, NumWorkGroups, + // subgroup + NumSubgroups, + SubgroupId, + SubgroupSize, + SubgroupInvocationId, } /// Number of bytes per scalar. @@ -874,7 +872,7 @@ pub enum TypeInner { BindingArray { base: Handle, size: ArraySize }, } -#[derive(Debug, Clone, Copy, PartialOrd)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -892,41 +890,37 @@ pub enum Literal { AbstractFloat(f64), } -#[derive(Debug, PartialEq)] -#[cfg_attr(feature = "clone", derive(Clone))] +/// Pipeline-overridable constant. +#[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -pub enum Override { - None, - ByName, - ByNameOrId(u32), +pub struct Override { + pub name: Option, + /// Pipeline Constant ID. + pub id: Option, + pub ty: Handle, + + /// The default value of the pipeline-overridable constant. + /// + /// This [`Handle`] refers to [`Module::global_expressions`], not + /// any [`Function::expressions`] arena. + pub init: Option>, } /// Constant value. -#[derive(Debug, PartialEq)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub struct Constant { pub name: Option, - pub r#override: Override, pub ty: Handle, /// The value of the constant. /// - /// This [`Handle`] refers to [`Module::const_expressions`], not + /// This [`Handle`] refers to [`Module::global_expressions`], not /// any [`Function::expressions`] arena. - /// - /// If [`override`] is [`None`], then this must be a Naga - /// [constant expression]. Otherwise, this may be a Naga - /// [override expression] or [constant expression]. - /// - /// [`override`]: Constant::override - /// [`None`]: Override::None - /// [constant expression]: index.html#constant-expressions - /// [override expression]: index.html#override-expressions pub init: Handle, } @@ -992,7 +986,7 @@ pub struct GlobalVariable { pub ty: Handle, /// Initial value for this variable. /// - /// Expression handle lives in const_expressions + /// Expression handle lives in global_expressions pub init: Option>, } @@ -1010,7 +1004,7 @@ pub struct LocalVariable { /// /// This handle refers to this `LocalVariable`'s function's /// [`expressions`] arena, but it is required to be an evaluated - /// constant expression. + /// override expression. /// /// [`expressions`]: Function::expressions pub init: Option>, @@ -1289,6 +1283,51 @@ pub enum SwizzleComponent { W = 3, } +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub enum GatherMode { + /// All gather from the active lane with the smallest index + BroadcastFirst, + /// All gather from the same lane at the index given by the expression + Broadcast(Handle), + /// Each gathers from a different lane at the index given by the expression + Shuffle(Handle), + /// Each gathers from their lane plus the shift given by the expression + ShuffleDown(Handle), + /// Each gathers from their lane minus the shift given by the expression + ShuffleUp(Handle), + /// Each gathers from their lane xored with the given by the expression + ShuffleXor(Handle), +} + +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub enum SubgroupOperation { + All = 0, + Any = 1, + Add = 2, + Mul = 3, + Min = 4, + Max = 5, + And = 6, + Or = 7, + Xor = 8, +} + +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub enum CollectiveOperation { + Reduce = 0, + InclusiveScan = 1, + ExclusiveScan = 2, +} + bitflags::bitflags! { /// Memory barrier flags. #[cfg_attr(feature = "serialize", derive(Serialize))] @@ -1297,9 +1336,11 @@ bitflags::bitflags! { #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct Barrier: u32 { /// Barrier affects all `AddressSpace::Storage` accesses. - const STORAGE = 0x1; + const STORAGE = 1 << 0; /// Barrier affects all `AddressSpace::WorkGroup` accesses. - const WORK_GROUP = 0x2; + const WORK_GROUP = 1 << 1; + /// Barrier synchronizes execution across all invocations within a subgroup that exectue this instruction. + const SUB_GROUP = 1 << 2; } } @@ -1315,6 +1356,8 @@ pub enum Expression { Literal(Literal), /// Constant value. Constant(Handle), + /// Pipeline-overridable constant. + Override(Handle), /// Zero value of a type. ZeroValue(Handle), /// Composite expression. @@ -1440,7 +1483,7 @@ pub enum Expression { gather: Option, coordinate: Handle, array_index: Option>, - /// Expression handle lives in const_expressions + /// Expression handle lives in global_expressions offset: Option>, level: SampleLevel, depth_ref: Option>, @@ -1598,6 +1641,15 @@ pub enum Expression { query: Handle, committed: bool, }, + /// Result of a [`SubgroupBallot`] statement. + /// + /// [`SubgroupBallot`]: Statement::SubgroupBallot + SubgroupBallotResult, + /// Result of a [`SubgroupCollectiveOperation`] or [`SubgroupGather`] statement. + /// + /// [`SubgroupCollectiveOperation`]: Statement::SubgroupCollectiveOperation + /// [`SubgroupGather`]: Statement::SubgroupGather + SubgroupOperationResult { ty: Handle }, } pub use block::Block; @@ -1882,6 +1934,39 @@ pub enum Statement { /// The specific operation we're performing on `query`. fun: RayQueryFunction, }, + /// Calculate a bitmask using a boolean from each active thread in the subgroup + SubgroupBallot { + /// The [`SubgroupBallotResult`] expression representing this load's result. + /// + /// [`SubgroupBallotResult`]: Expression::SubgroupBallotResult + result: Handle, + /// The value from this thread to store in the ballot + predicate: Option>, + }, + /// Gather a value from another active thread in the subgroup + SubgroupGather { + /// Specifies which thread to gather from + mode: GatherMode, + /// The value to broadcast over + argument: Handle, + /// The [`SubgroupOperationResult`] expression representing this load's result. + /// + /// [`SubgroupOperationResult`]: Expression::SubgroupOperationResult + result: Handle, + }, + /// Compute a collective operation across all active threads in the subgroup + SubgroupCollectiveOperation { + /// What operation to compute + op: SubgroupOperation, + /// How to combine the results + collective_op: CollectiveOperation, + /// The value to compute over + argument: Handle, + /// The [`SubgroupOperationResult`] expression representing this load's result. + /// + /// [`SubgroupOperationResult`]: Expression::SubgroupOperationResult + result: Handle, + }, } /// A function argument. @@ -1913,8 +1998,7 @@ pub struct FunctionResult { } /// A function defined in the module. -#[derive(Debug, Default)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -1978,8 +2062,7 @@ pub struct Function { /// [`Location`]: Binding::Location /// [`function`]: EntryPoint::function /// [`stage`]: EntryPoint::stage -#[derive(Debug)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Debug, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -2003,8 +2086,7 @@ pub struct EntryPoint { /// These cannot be spelled in WGSL source. /// /// Stored in [`SpecialTypes::predeclared_types`] and created by [`Module::generate_predeclared_type`]. -#[derive(Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Debug, PartialEq, Eq, Hash, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -2021,8 +2103,7 @@ pub enum PredeclaredType { } /// Set of special types that can be optionally generated by the frontends. -#[derive(Debug, Default)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -2057,8 +2138,7 @@ pub struct SpecialTypes { /// Alternatively, you can load an existing shader using one of the [available front ends][front]. /// /// When finished, you can export modules using one of the [available backends][back]. -#[derive(Debug, Default)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -2069,6 +2149,8 @@ pub struct Module { pub special_types: SpecialTypes, /// Arena for the constants defined in this module. pub constants: Arena, + /// Arena for the pipeline-overridable constants defined in this module. + pub overrides: Arena, /// Arena for the global variables defined in this module. pub global_variables: Arena, /// [Constant expressions] and [override expressions] used by this module. @@ -2078,7 +2160,7 @@ pub struct Module { /// /// [Constant expressions]: index.html#constant-expressions /// [override expressions]: index.html#override-expressions - pub const_expressions: Arena, + pub global_expressions: Arena, /// Arena for the functions defined in this module. /// /// Each function must appear in this arena strictly before all its callers. diff --git a/third_party/rust/naga/src/proc/constant_evaluator.rs b/third_party/rust/naga/src/proc/constant_evaluator.rs index 983af3718c..ead3d00980 100644 --- a/third_party/rust/naga/src/proc/constant_evaluator.rs +++ b/third_party/rust/naga/src/proc/constant_evaluator.rs @@ -4,8 +4,8 @@ use arrayvec::ArrayVec; use crate::{ arena::{Arena, Handle, UniqueArena}, - ArraySize, BinaryOperator, Constant, Expression, Literal, ScalarKind, Span, Type, TypeInner, - UnaryOperator, + ArraySize, BinaryOperator, Constant, Expression, Literal, Override, ScalarKind, Span, Type, + TypeInner, UnaryOperator, }; /// A macro that allows dollar signs (`$`) to be emitted by other macros. Useful for generating @@ -253,9 +253,20 @@ gen_component_wise_extractor! { } #[derive(Debug)] -enum Behavior { - Wgsl, - Glsl, +enum Behavior<'a> { + Wgsl(WgslRestrictions<'a>), + Glsl(GlslRestrictions<'a>), +} + +impl Behavior<'_> { + /// Returns `true` if the inner WGSL/GLSL restrictions are runtime restrictions. + const fn has_runtime_restrictions(&self) -> bool { + matches!( + self, + &Behavior::Wgsl(WgslRestrictions::Runtime(_)) + | &Behavior::Glsl(GlslRestrictions::Runtime(_)) + ) + } } /// A context for evaluating constant expressions. @@ -278,7 +289,7 @@ enum Behavior { #[derive(Debug)] pub struct ConstantEvaluator<'a> { /// Which language's evaluation rules we should follow. - behavior: Behavior, + behavior: Behavior<'a>, /// The module's type arena. /// @@ -291,71 +302,155 @@ pub struct ConstantEvaluator<'a> { /// The module's constant arena. constants: &'a Arena, + /// The module's override arena. + overrides: &'a Arena, + /// The arena to which we are contributing expressions. expressions: &'a mut Arena, - /// When `self.expressions` refers to a function's local expression - /// arena, this needs to be populated - function_local_data: Option>, + /// Tracks the constness of expressions residing in [`Self::expressions`] + expression_kind_tracker: &'a mut ExpressionKindTracker, +} + +#[derive(Debug)] +enum WgslRestrictions<'a> { + /// - const-expressions will be evaluated and inserted in the arena + Const, + /// - const-expressions will be evaluated and inserted in the arena + /// - override-expressions will be inserted in the arena + Override, + /// - const-expressions will be evaluated and inserted in the arena + /// - override-expressions will be inserted in the arena + /// - runtime-expressions will be inserted in the arena + Runtime(FunctionLocalData<'a>), +} + +#[derive(Debug)] +enum GlslRestrictions<'a> { + /// - const-expressions will be evaluated and inserted in the arena + Const, + /// - const-expressions will be evaluated and inserted in the arena + /// - override-expressions will be inserted in the arena + /// - runtime-expressions will be inserted in the arena + Runtime(FunctionLocalData<'a>), } #[derive(Debug)] struct FunctionLocalData<'a> { /// Global constant expressions - const_expressions: &'a Arena, - /// Tracks the constness of expressions residing in `ConstantEvaluator.expressions` - expression_constness: &'a mut ExpressionConstnessTracker, + global_expressions: &'a Arena, emitter: &'a mut super::Emitter, block: &'a mut crate::Block, } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +pub enum ExpressionKind { + Const, + Override, + Runtime, +} + #[derive(Debug)] -pub struct ExpressionConstnessTracker { - inner: bit_set::BitSet, +pub struct ExpressionKindTracker { + inner: Vec, } -impl ExpressionConstnessTracker { - pub fn new() -> Self { - Self { - inner: bit_set::BitSet::new(), - } +impl ExpressionKindTracker { + pub const fn new() -> Self { + Self { inner: Vec::new() } } /// Forces the the expression to not be const pub fn force_non_const(&mut self, value: Handle) { - self.inner.remove(value.index()); + self.inner[value.index()] = ExpressionKind::Runtime; } - fn insert(&mut self, value: Handle) { - self.inner.insert(value.index()); + pub fn insert(&mut self, value: Handle, expr_type: ExpressionKind) { + assert_eq!(self.inner.len(), value.index()); + self.inner.push(expr_type); + } + pub fn is_const(&self, h: Handle) -> bool { + matches!(self.type_of(h), ExpressionKind::Const) + } + + pub fn is_const_or_override(&self, h: Handle) -> bool { + matches!( + self.type_of(h), + ExpressionKind::Const | ExpressionKind::Override + ) } - pub fn is_const(&self, value: Handle) -> bool { - self.inner.contains(value.index()) + fn type_of(&self, value: Handle) -> ExpressionKind { + self.inner[value.index()] } pub fn from_arena(arena: &Arena) -> Self { - let mut tracker = Self::new(); - for (handle, expr) in arena.iter() { - let insert = match *expr { - crate::Expression::Literal(_) - | crate::Expression::ZeroValue(_) - | crate::Expression::Constant(_) => true, - crate::Expression::Compose { ref components, .. } => { - components.iter().all(|h| tracker.is_const(*h)) - } - crate::Expression::Splat { value, .. } => tracker.is_const(value), - _ => false, - }; - if insert { - tracker.insert(handle); - } + let mut tracker = Self { + inner: Vec::with_capacity(arena.len()), + }; + for (_, expr) in arena.iter() { + tracker.inner.push(tracker.type_of_with_expr(expr)); } tracker } + + fn type_of_with_expr(&self, expr: &Expression) -> ExpressionKind { + match *expr { + Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => { + ExpressionKind::Const + } + Expression::Override(_) => ExpressionKind::Override, + Expression::Compose { ref components, .. } => { + let mut expr_type = ExpressionKind::Const; + for component in components { + expr_type = expr_type.max(self.type_of(*component)) + } + expr_type + } + Expression::Splat { value, .. } => self.type_of(value), + Expression::AccessIndex { base, .. } => self.type_of(base), + Expression::Access { base, index } => self.type_of(base).max(self.type_of(index)), + Expression::Swizzle { vector, .. } => self.type_of(vector), + Expression::Unary { expr, .. } => self.type_of(expr), + Expression::Binary { left, right, .. } => self.type_of(left).max(self.type_of(right)), + Expression::Math { + arg, + arg1, + arg2, + arg3, + .. + } => self + .type_of(arg) + .max( + arg1.map(|arg| self.type_of(arg)) + .unwrap_or(ExpressionKind::Const), + ) + .max( + arg2.map(|arg| self.type_of(arg)) + .unwrap_or(ExpressionKind::Const), + ) + .max( + arg3.map(|arg| self.type_of(arg)) + .unwrap_or(ExpressionKind::Const), + ), + Expression::As { expr, .. } => self.type_of(expr), + Expression::Select { + condition, + accept, + reject, + } => self + .type_of(condition) + .max(self.type_of(accept)) + .max(self.type_of(reject)), + Expression::Relational { argument, .. } => self.type_of(argument), + Expression::ArrayLength(expr) => self.type_of(expr), + _ => ExpressionKind::Runtime, + } + } } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum ConstantEvaluatorError { #[error("Constants cannot access function arguments")] FunctionArg, @@ -381,6 +476,8 @@ pub enum ConstantEvaluatorError { ImageExpression, #[error("Constants don't support ray query expressions")] RayQueryExpression, + #[error("Constants don't support subgroup expressions")] + SubgroupExpression, #[error("Cannot access the type")] InvalidAccessBase, #[error("Cannot access at the index")] @@ -432,6 +529,12 @@ pub enum ConstantEvaluatorError { ShiftedMoreThan32Bits, #[error(transparent)] Literal(#[from] crate::valid::LiteralError), + #[error("Can't use pipeline-overridable constants in const-expressions")] + Override, + #[error("Unexpected runtime-expression")] + RuntimeExpr, + #[error("Unexpected override-expression")] + OverrideExpr, } impl<'a> ConstantEvaluator<'a> { @@ -439,25 +542,49 @@ impl<'a> ConstantEvaluator<'a> { /// constant expression arena. /// /// Report errors according to WGSL's rules for constant evaluation. - pub fn for_wgsl_module(module: &'a mut crate::Module) -> Self { - Self::for_module(Behavior::Wgsl, module) + pub fn for_wgsl_module( + module: &'a mut crate::Module, + global_expression_kind_tracker: &'a mut ExpressionKindTracker, + in_override_ctx: bool, + ) -> Self { + Self::for_module( + Behavior::Wgsl(if in_override_ctx { + WgslRestrictions::Override + } else { + WgslRestrictions::Const + }), + module, + global_expression_kind_tracker, + ) } /// Return a [`ConstantEvaluator`] that will add expressions to `module`'s /// constant expression arena. /// /// Report errors according to GLSL's rules for constant evaluation. - pub fn for_glsl_module(module: &'a mut crate::Module) -> Self { - Self::for_module(Behavior::Glsl, module) + pub fn for_glsl_module( + module: &'a mut crate::Module, + global_expression_kind_tracker: &'a mut ExpressionKindTracker, + ) -> Self { + Self::for_module( + Behavior::Glsl(GlslRestrictions::Const), + module, + global_expression_kind_tracker, + ) } - fn for_module(behavior: Behavior, module: &'a mut crate::Module) -> Self { + fn for_module( + behavior: Behavior<'a>, + module: &'a mut crate::Module, + global_expression_kind_tracker: &'a mut ExpressionKindTracker, + ) -> Self { Self { behavior, types: &mut module.types, constants: &module.constants, - expressions: &mut module.const_expressions, - function_local_data: None, + overrides: &module.overrides, + expressions: &mut module.global_expressions, + expression_kind_tracker: global_expression_kind_tracker, } } @@ -468,18 +595,22 @@ impl<'a> ConstantEvaluator<'a> { pub fn for_wgsl_function( module: &'a mut crate::Module, expressions: &'a mut Arena, - expression_constness: &'a mut ExpressionConstnessTracker, + local_expression_kind_tracker: &'a mut ExpressionKindTracker, emitter: &'a mut super::Emitter, block: &'a mut crate::Block, ) -> Self { - Self::for_function( - Behavior::Wgsl, - module, + Self { + behavior: Behavior::Wgsl(WgslRestrictions::Runtime(FunctionLocalData { + global_expressions: &module.global_expressions, + emitter, + block, + })), + types: &mut module.types, + constants: &module.constants, + overrides: &module.overrides, expressions, - expression_constness, - emitter, - block, - ) + expression_kind_tracker: local_expression_kind_tracker, + } } /// Return a [`ConstantEvaluator`] that will add expressions to `function`'s @@ -489,39 +620,21 @@ impl<'a> ConstantEvaluator<'a> { pub fn for_glsl_function( module: &'a mut crate::Module, expressions: &'a mut Arena, - expression_constness: &'a mut ExpressionConstnessTracker, - emitter: &'a mut super::Emitter, - block: &'a mut crate::Block, - ) -> Self { - Self::for_function( - Behavior::Glsl, - module, - expressions, - expression_constness, - emitter, - block, - ) - } - - fn for_function( - behavior: Behavior, - module: &'a mut crate::Module, - expressions: &'a mut Arena, - expression_constness: &'a mut ExpressionConstnessTracker, + local_expression_kind_tracker: &'a mut ExpressionKindTracker, emitter: &'a mut super::Emitter, block: &'a mut crate::Block, ) -> Self { Self { - behavior, + behavior: Behavior::Glsl(GlslRestrictions::Runtime(FunctionLocalData { + global_expressions: &module.global_expressions, + emitter, + block, + })), types: &mut module.types, constants: &module.constants, + overrides: &module.overrides, expressions, - function_local_data: Some(FunctionLocalData { - const_expressions: &module.const_expressions, - expression_constness, - emitter, - block, - }), + expression_kind_tracker: local_expression_kind_tracker, } } @@ -529,19 +642,18 @@ impl<'a> ConstantEvaluator<'a> { crate::proc::GlobalCtx { types: self.types, constants: self.constants, - const_expressions: match self.function_local_data { - Some(ref data) => data.const_expressions, + overrides: self.overrides, + global_expressions: match self.function_local_data() { + Some(data) => data.global_expressions, None => self.expressions, }, } } fn check(&self, expr: Handle) -> Result<(), ConstantEvaluatorError> { - if let Some(ref function_local_data) = self.function_local_data { - if !function_local_data.expression_constness.is_const(expr) { - log::debug!("check: SubexpressionsAreNotConstant"); - return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant); - } + if !self.expression_kind_tracker.is_const(expr) { + log::debug!("check: SubexpressionsAreNotConstant"); + return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant); } Ok(()) } @@ -554,11 +666,11 @@ impl<'a> ConstantEvaluator<'a> { Expression::Constant(c) => { // Are we working in a function's expression arena, or the // module's constant expression arena? - if let Some(ref function_local_data) = self.function_local_data { + if let Some(function_local_data) = self.function_local_data() { // Deep-copy the constant's value into our arena. self.copy_from( self.constants[c].init, - function_local_data.const_expressions, + function_local_data.global_expressions, ) } else { // "See through" the constant and use its initializer. @@ -580,9 +692,11 @@ impl<'a> ConstantEvaluator<'a> { /// [`ZeroValue`], and [`Swizzle`] expressions - to the expression arena /// `self` contributes to. /// - /// If `expr`'s value cannot be determined at compile time, return a an - /// error. If it's acceptable to evaluate `expr` at runtime, this error can - /// be ignored, and the caller can append `expr` to the arena itself. + /// If `expr`'s value cannot be determined at compile time, and `self` is + /// contributing to some function's expression arena, then append `expr` to + /// that arena unchanged (and thus unevaluated). Otherwise, `self` must be + /// contributing to the module's constant expression arena; since `expr`'s + /// value is not a constant, return an error. /// /// We only consider `expr` itself, without recursing into its operands. Its /// operands must all have been produced by prior calls to @@ -594,17 +708,82 @@ impl<'a> ConstantEvaluator<'a> { /// [`ZeroValue`]: Expression::ZeroValue /// [`Swizzle`]: Expression::Swizzle pub fn try_eval_and_append( + &mut self, + expr: Expression, + span: Span, + ) -> Result, ConstantEvaluatorError> { + match self.expression_kind_tracker.type_of_with_expr(&expr) { + ExpressionKind::Const => { + let eval_result = self.try_eval_and_append_impl(&expr, span); + // We should be able to evaluate `Const` expressions at this + // point. If we failed to, then that probably means we just + // haven't implemented that part of constant evaluation. Work + // around this by simply emitting it as a run-time expression. + if self.behavior.has_runtime_restrictions() + && matches!( + eval_result, + Err(ConstantEvaluatorError::NotImplemented(_) + | ConstantEvaluatorError::InvalidBinaryOpArgs,) + ) + { + Ok(self.append_expr(expr, span, ExpressionKind::Runtime)) + } else { + eval_result + } + } + ExpressionKind::Override => match self.behavior { + Behavior::Wgsl(WgslRestrictions::Override | WgslRestrictions::Runtime(_)) => { + Ok(self.append_expr(expr, span, ExpressionKind::Override)) + } + Behavior::Wgsl(WgslRestrictions::Const) => { + Err(ConstantEvaluatorError::OverrideExpr) + } + Behavior::Glsl(_) => { + unreachable!() + } + }, + ExpressionKind::Runtime => { + if self.behavior.has_runtime_restrictions() { + Ok(self.append_expr(expr, span, ExpressionKind::Runtime)) + } else { + Err(ConstantEvaluatorError::RuntimeExpr) + } + } + } + } + + /// Is the [`Self::expressions`] arena the global module expression arena? + const fn is_global_arena(&self) -> bool { + matches!( + self.behavior, + Behavior::Wgsl(WgslRestrictions::Const | WgslRestrictions::Override) + | Behavior::Glsl(GlslRestrictions::Const) + ) + } + + const fn function_local_data(&self) -> Option<&FunctionLocalData<'a>> { + match self.behavior { + Behavior::Wgsl(WgslRestrictions::Runtime(ref function_local_data)) + | Behavior::Glsl(GlslRestrictions::Runtime(ref function_local_data)) => { + Some(function_local_data) + } + _ => None, + } + } + + fn try_eval_and_append_impl( &mut self, expr: &Expression, span: Span, ) -> Result, ConstantEvaluatorError> { log::trace!("try_eval_and_append: {:?}", expr); match *expr { - Expression::Constant(c) if self.function_local_data.is_none() => { + Expression::Constant(c) if self.is_global_arena() => { // "See through" the constant and use its initializer. // This is mainly done to avoid having constants pointing to other constants. Ok(self.constants[c].init) } + Expression::Override(_) => Err(ConstantEvaluatorError::Override), Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => { self.register_evaluated_expr(expr.clone(), span) } @@ -685,8 +864,8 @@ impl<'a> ConstantEvaluator<'a> { format!("{fun:?} built-in function"), )), Expression::ArrayLength(expr) => match self.behavior { - Behavior::Wgsl => Err(ConstantEvaluatorError::ArrayLength), - Behavior::Glsl => { + Behavior::Wgsl(_) => Err(ConstantEvaluatorError::ArrayLength), + Behavior::Glsl(_) => { let expr = self.check_and_get(expr)?; self.array_length(expr, span) } @@ -707,6 +886,12 @@ impl<'a> ConstantEvaluator<'a> { Expression::RayQueryProceedResult | Expression::RayQueryGetIntersection { .. } => { Err(ConstantEvaluatorError::RayQueryExpression) } + Expression::SubgroupBallotResult { .. } => { + Err(ConstantEvaluatorError::SubgroupExpression) + } + Expression::SubgroupOperationResult { .. } => { + Err(ConstantEvaluatorError::SubgroupExpression) + } } } @@ -765,10 +950,10 @@ impl<'a> ConstantEvaluator<'a> { pattern: [crate::SwizzleComponent; 4], ) -> Result, ConstantEvaluatorError> { let mut get_dst_ty = |ty| match self.types[ty].inner { - crate::TypeInner::Vector { size: _, scalar } => Ok(self.types.insert( + TypeInner::Vector { size: _, scalar } => Ok(self.types.insert( Type { name: None, - inner: crate::TypeInner::Vector { size, scalar }, + inner: TypeInner::Vector { size, scalar }, }, span, )), @@ -1059,13 +1244,11 @@ impl<'a> ConstantEvaluator<'a> { Expression::ZeroValue(ty) | Expression::Compose { ty, .. } => { match self.types[ty].inner { TypeInner::Array { size, .. } => match size { - crate::ArraySize::Constant(len) => { + ArraySize::Constant(len) => { let expr = Expression::Literal(Literal::U32(len.get())); self.register_evaluated_expr(expr, span) } - crate::ArraySize::Dynamic => { - Err(ConstantEvaluatorError::ArrayLengthDynamic) - } + ArraySize::Dynamic => Err(ConstantEvaluatorError::ArrayLengthDynamic), }, _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg), } @@ -1128,7 +1311,7 @@ impl<'a> ConstantEvaluator<'a> { Expression::ZeroValue(ty) if matches!( self.types[ty].inner, - crate::TypeInner::Scalar(crate::Scalar { + TypeInner::Scalar(crate::Scalar { kind: ScalarKind::Uint, .. }) @@ -1443,7 +1626,7 @@ impl<'a> ConstantEvaluator<'a> { return self.cast(expr, target, span); }; - let crate::TypeInner::Array { + let TypeInner::Array { base: _, size, stride: _, @@ -1853,29 +2036,35 @@ impl<'a> ConstantEvaluator<'a> { crate::valid::check_literal_value(literal)?; } - if let Some(FunctionLocalData { - ref mut emitter, - ref mut block, - ref mut expression_constness, - .. - }) = self.function_local_data - { - let is_running = emitter.is_running(); - let needs_pre_emit = expr.needs_pre_emit(); - if is_running && needs_pre_emit { - block.extend(emitter.finish(self.expressions)); - let h = self.expressions.append(expr, span); - emitter.start(self.expressions); - expression_constness.insert(h); - Ok(h) - } else { - let h = self.expressions.append(expr, span); - expression_constness.insert(h); - Ok(h) + Ok(self.append_expr(expr, span, ExpressionKind::Const)) + } + + fn append_expr( + &mut self, + expr: Expression, + span: Span, + expr_type: ExpressionKind, + ) -> Handle { + let h = match self.behavior { + Behavior::Wgsl(WgslRestrictions::Runtime(ref mut function_local_data)) + | Behavior::Glsl(GlslRestrictions::Runtime(ref mut function_local_data)) => { + let is_running = function_local_data.emitter.is_running(); + let needs_pre_emit = expr.needs_pre_emit(); + if is_running && needs_pre_emit { + function_local_data + .block + .extend(function_local_data.emitter.finish(self.expressions)); + let h = self.expressions.append(expr, span); + function_local_data.emitter.start(self.expressions); + h + } else { + self.expressions.append(expr, span) + } } - } else { - Ok(self.expressions.append(expr, span)) - } + _ => self.expressions.append(expr, span), + }; + self.expression_kind_tracker.insert(h, expr_type); + h } fn resolve_type( @@ -2029,13 +2218,14 @@ mod tests { UniqueArena, VectorSize, }; - use super::{Behavior, ConstantEvaluator}; + use super::{Behavior, ConstantEvaluator, ExpressionKindTracker, WgslRestrictions}; #[test] fn unary_op() { let mut types = UniqueArena::new(); let mut constants = Arena::new(); - let mut const_expressions = Arena::new(); + let overrides = Arena::new(); + let mut global_expressions = Arena::new(); let scalar_ty = types.insert( Type { @@ -2059,9 +2249,8 @@ mod tests { let h = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: scalar_ty, - init: const_expressions + init: global_expressions .append(Expression::Literal(Literal::I32(4)), Default::default()), }, Default::default(), @@ -2070,9 +2259,8 @@ mod tests { let h1 = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: scalar_ty, - init: const_expressions + init: global_expressions .append(Expression::Literal(Literal::I32(8)), Default::default()), }, Default::default(), @@ -2081,9 +2269,8 @@ mod tests { let vec_h = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: vec_ty, - init: const_expressions.append( + init: global_expressions.append( Expression::Compose { ty: vec_ty, components: vec![constants[h].init, constants[h1].init], @@ -2094,8 +2281,8 @@ mod tests { Default::default(), ); - let expr = const_expressions.append(Expression::Constant(h), Default::default()); - let expr1 = const_expressions.append(Expression::Constant(vec_h), Default::default()); + let expr = global_expressions.append(Expression::Constant(h), Default::default()); + let expr1 = global_expressions.append(Expression::Constant(vec_h), Default::default()); let expr2 = Expression::Unary { op: UnaryOperator::Negate, @@ -2112,35 +2299,37 @@ mod tests { expr: expr1, }; + let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl, + behavior: Behavior::Wgsl(WgslRestrictions::Const), types: &mut types, constants: &constants, - expressions: &mut const_expressions, - function_local_data: None, + overrides: &overrides, + expressions: &mut global_expressions, + expression_kind_tracker, }; let res1 = solver - .try_eval_and_append(&expr2, Default::default()) + .try_eval_and_append(expr2, Default::default()) .unwrap(); let res2 = solver - .try_eval_and_append(&expr3, Default::default()) + .try_eval_and_append(expr3, Default::default()) .unwrap(); let res3 = solver - .try_eval_and_append(&expr4, Default::default()) + .try_eval_and_append(expr4, Default::default()) .unwrap(); assert_eq!( - const_expressions[res1], + global_expressions[res1], Expression::Literal(Literal::I32(-4)) ); assert_eq!( - const_expressions[res2], + global_expressions[res2], Expression::Literal(Literal::I32(!4)) ); - let res3_inner = &const_expressions[res3]; + let res3_inner = &global_expressions[res3]; match *res3_inner { Expression::Compose { @@ -2150,11 +2339,11 @@ mod tests { assert_eq!(*ty, vec_ty); let mut components_iter = components.iter().copied(); assert_eq!( - const_expressions[components_iter.next().unwrap()], + global_expressions[components_iter.next().unwrap()], Expression::Literal(Literal::I32(!4)) ); assert_eq!( - const_expressions[components_iter.next().unwrap()], + global_expressions[components_iter.next().unwrap()], Expression::Literal(Literal::I32(!8)) ); assert!(components_iter.next().is_none()); @@ -2167,7 +2356,8 @@ mod tests { fn cast() { let mut types = UniqueArena::new(); let mut constants = Arena::new(); - let mut const_expressions = Arena::new(); + let overrides = Arena::new(); + let mut global_expressions = Arena::new(); let scalar_ty = types.insert( Type { @@ -2180,15 +2370,14 @@ mod tests { let h = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: scalar_ty, - init: const_expressions + init: global_expressions .append(Expression::Literal(Literal::I32(4)), Default::default()), }, Default::default(), ); - let expr = const_expressions.append(Expression::Constant(h), Default::default()); + let expr = global_expressions.append(Expression::Constant(h), Default::default()); let root = Expression::As { expr, @@ -2196,20 +2385,22 @@ mod tests { convert: Some(crate::BOOL_WIDTH), }; + let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl, + behavior: Behavior::Wgsl(WgslRestrictions::Const), types: &mut types, constants: &constants, - expressions: &mut const_expressions, - function_local_data: None, + overrides: &overrides, + expressions: &mut global_expressions, + expression_kind_tracker, }; let res = solver - .try_eval_and_append(&root, Default::default()) + .try_eval_and_append(root, Default::default()) .unwrap(); assert_eq!( - const_expressions[res], + global_expressions[res], Expression::Literal(Literal::Bool(true)) ); } @@ -2218,7 +2409,8 @@ mod tests { fn access() { let mut types = UniqueArena::new(); let mut constants = Arena::new(); - let mut const_expressions = Arena::new(); + let overrides = Arena::new(); + let mut global_expressions = Arena::new(); let matrix_ty = types.insert( Type { @@ -2247,7 +2439,7 @@ mod tests { let mut vec2_components = Vec::with_capacity(3); for i in 0..3 { - let h = const_expressions.append( + let h = global_expressions.append( Expression::Literal(Literal::F32(i as f32)), Default::default(), ); @@ -2256,7 +2448,7 @@ mod tests { } for i in 3..6 { - let h = const_expressions.append( + let h = global_expressions.append( Expression::Literal(Literal::F32(i as f32)), Default::default(), ); @@ -2267,9 +2459,8 @@ mod tests { let vec1 = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: vec_ty, - init: const_expressions.append( + init: global_expressions.append( Expression::Compose { ty: vec_ty, components: vec1_components, @@ -2283,9 +2474,8 @@ mod tests { let vec2 = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: vec_ty, - init: const_expressions.append( + init: global_expressions.append( Expression::Compose { ty: vec_ty, components: vec2_components, @@ -2299,9 +2489,8 @@ mod tests { let h = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: matrix_ty, - init: const_expressions.append( + init: global_expressions.append( Expression::Compose { ty: matrix_ty, components: vec![constants[vec1].init, constants[vec2].init], @@ -2312,20 +2501,22 @@ mod tests { Default::default(), ); - let base = const_expressions.append(Expression::Constant(h), Default::default()); + let base = global_expressions.append(Expression::Constant(h), Default::default()); + let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl, + behavior: Behavior::Wgsl(WgslRestrictions::Const), types: &mut types, constants: &constants, - expressions: &mut const_expressions, - function_local_data: None, + overrides: &overrides, + expressions: &mut global_expressions, + expression_kind_tracker, }; let root1 = Expression::AccessIndex { base, index: 1 }; let res1 = solver - .try_eval_and_append(&root1, Default::default()) + .try_eval_and_append(root1, Default::default()) .unwrap(); let root2 = Expression::AccessIndex { @@ -2334,10 +2525,10 @@ mod tests { }; let res2 = solver - .try_eval_and_append(&root2, Default::default()) + .try_eval_and_append(root2, Default::default()) .unwrap(); - match const_expressions[res1] { + match global_expressions[res1] { Expression::Compose { ref ty, ref components, @@ -2345,15 +2536,15 @@ mod tests { assert_eq!(*ty, vec_ty); let mut components_iter = components.iter().copied(); assert_eq!( - const_expressions[components_iter.next().unwrap()], + global_expressions[components_iter.next().unwrap()], Expression::Literal(Literal::F32(3.)) ); assert_eq!( - const_expressions[components_iter.next().unwrap()], + global_expressions[components_iter.next().unwrap()], Expression::Literal(Literal::F32(4.)) ); assert_eq!( - const_expressions[components_iter.next().unwrap()], + global_expressions[components_iter.next().unwrap()], Expression::Literal(Literal::F32(5.)) ); assert!(components_iter.next().is_none()); @@ -2362,7 +2553,7 @@ mod tests { } assert_eq!( - const_expressions[res2], + global_expressions[res2], Expression::Literal(Literal::F32(5.)) ); } @@ -2371,7 +2562,8 @@ mod tests { fn compose_of_constants() { let mut types = UniqueArena::new(); let mut constants = Arena::new(); - let mut const_expressions = Arena::new(); + let overrides = Arena::new(); + let mut global_expressions = Arena::new(); let i32_ty = types.insert( Type { @@ -2395,27 +2587,28 @@ mod tests { let h = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: i32_ty, - init: const_expressions + init: global_expressions .append(Expression::Literal(Literal::I32(4)), Default::default()), }, Default::default(), ); - let h_expr = const_expressions.append(Expression::Constant(h), Default::default()); + let h_expr = global_expressions.append(Expression::Constant(h), Default::default()); + let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl, + behavior: Behavior::Wgsl(WgslRestrictions::Const), types: &mut types, constants: &constants, - expressions: &mut const_expressions, - function_local_data: None, + overrides: &overrides, + expressions: &mut global_expressions, + expression_kind_tracker, }; let solved_compose = solver .try_eval_and_append( - &Expression::Compose { + Expression::Compose { ty: vec2_i32_ty, components: vec![h_expr, h_expr], }, @@ -2424,7 +2617,7 @@ mod tests { .unwrap(); let solved_negate = solver .try_eval_and_append( - &Expression::Unary { + Expression::Unary { op: UnaryOperator::Negate, expr: solved_compose, }, @@ -2432,11 +2625,11 @@ mod tests { ) .unwrap(); - let pass = match const_expressions[solved_negate] { + let pass = match global_expressions[solved_negate] { Expression::Compose { ty, ref components } => { ty == vec2_i32_ty && components.iter().all(|&component| { - let component = &const_expressions[component]; + let component = &global_expressions[component]; matches!(*component, Expression::Literal(Literal::I32(-4))) }) } @@ -2451,7 +2644,8 @@ mod tests { fn splat_of_constant() { let mut types = UniqueArena::new(); let mut constants = Arena::new(); - let mut const_expressions = Arena::new(); + let overrides = Arena::new(); + let mut global_expressions = Arena::new(); let i32_ty = types.insert( Type { @@ -2475,27 +2669,28 @@ mod tests { let h = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: i32_ty, - init: const_expressions + init: global_expressions .append(Expression::Literal(Literal::I32(4)), Default::default()), }, Default::default(), ); - let h_expr = const_expressions.append(Expression::Constant(h), Default::default()); + let h_expr = global_expressions.append(Expression::Constant(h), Default::default()); + let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl, + behavior: Behavior::Wgsl(WgslRestrictions::Const), types: &mut types, constants: &constants, - expressions: &mut const_expressions, - function_local_data: None, + overrides: &overrides, + expressions: &mut global_expressions, + expression_kind_tracker, }; let solved_compose = solver .try_eval_and_append( - &Expression::Splat { + Expression::Splat { size: VectorSize::Bi, value: h_expr, }, @@ -2504,7 +2699,7 @@ mod tests { .unwrap(); let solved_negate = solver .try_eval_and_append( - &Expression::Unary { + Expression::Unary { op: UnaryOperator::Negate, expr: solved_compose, }, @@ -2512,11 +2707,11 @@ mod tests { ) .unwrap(); - let pass = match const_expressions[solved_negate] { + let pass = match global_expressions[solved_negate] { Expression::Compose { ty, ref components } => { ty == vec2_i32_ty && components.iter().all(|&component| { - let component = &const_expressions[component]; + let component = &global_expressions[component]; matches!(*component, Expression::Literal(Literal::I32(-4))) }) } diff --git a/third_party/rust/naga/src/proc/index.rs b/third_party/rust/naga/src/proc/index.rs index af3221c0fe..e2c3de8eb0 100644 --- a/third_party/rust/naga/src/proc/index.rs +++ b/third_party/rust/naga/src/proc/index.rs @@ -239,7 +239,7 @@ pub enum GuardedIndex { pub fn find_checked_indexes( module: &crate::Module, function: &crate::Function, - info: &crate::valid::FunctionInfo, + info: &valid::FunctionInfo, policies: BoundsCheckPolicies, ) -> BitSet { use crate::Expression as Ex; @@ -321,7 +321,7 @@ pub fn access_needs_check( mut index: GuardedIndex, module: &crate::Module, function: &crate::Function, - info: &crate::valid::FunctionInfo, + info: &valid::FunctionInfo, ) -> Option { let base_inner = info[base].ty.inner_with(&module.types); // Unwrap safety: `Err` here indicates unindexable base types and invalid diff --git a/third_party/rust/naga/src/proc/mod.rs b/third_party/rust/naga/src/proc/mod.rs index 46cbb6c3b3..93aac5b3e5 100644 --- a/third_party/rust/naga/src/proc/mod.rs +++ b/third_party/rust/naga/src/proc/mod.rs @@ -11,7 +11,7 @@ mod terminator; mod typifier; pub use constant_evaluator::{ - ConstantEvaluator, ConstantEvaluatorError, ExpressionConstnessTracker, + ConstantEvaluator, ConstantEvaluatorError, ExpressionKind, ExpressionKindTracker, }; pub use emitter::Emitter; pub use index::{BoundsCheckPolicies, BoundsCheckPolicy, IndexableLength, IndexableLengthError}; @@ -153,56 +153,31 @@ impl super::Scalar { } } -impl PartialEq for crate::Literal { - fn eq(&self, other: &Self) -> bool { - match (*self, *other) { - (Self::F64(a), Self::F64(b)) => a.to_bits() == b.to_bits(), - (Self::F32(a), Self::F32(b)) => a.to_bits() == b.to_bits(), - (Self::U32(a), Self::U32(b)) => a == b, - (Self::I32(a), Self::I32(b)) => a == b, - (Self::U64(a), Self::U64(b)) => a == b, - (Self::I64(a), Self::I64(b)) => a == b, - (Self::Bool(a), Self::Bool(b)) => a == b, - _ => false, - } - } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum HashableLiteral { + F64(u64), + F32(u32), + U32(u32), + I32(i32), + U64(u64), + I64(i64), + Bool(bool), + AbstractInt(i64), + AbstractFloat(u64), } -impl Eq for crate::Literal {} -impl std::hash::Hash for crate::Literal { - fn hash(&self, hasher: &mut H) { - match *self { - Self::F64(v) | Self::AbstractFloat(v) => { - hasher.write_u8(0); - v.to_bits().hash(hasher); - } - Self::F32(v) => { - hasher.write_u8(1); - v.to_bits().hash(hasher); - } - Self::U32(v) => { - hasher.write_u8(2); - v.hash(hasher); - } - Self::I32(v) => { - hasher.write_u8(3); - v.hash(hasher); - } - Self::Bool(v) => { - hasher.write_u8(4); - v.hash(hasher); - } - Self::I64(v) => { - hasher.write_u8(5); - v.hash(hasher); - } - Self::U64(v) => { - hasher.write_u8(6); - v.hash(hasher); - } - Self::AbstractInt(v) => { - hasher.write_u8(7); - v.hash(hasher); - } + +impl From for HashableLiteral { + fn from(l: crate::Literal) -> Self { + match l { + crate::Literal::F64(v) => Self::F64(v.to_bits()), + crate::Literal::F32(v) => Self::F32(v.to_bits()), + crate::Literal::U32(v) => Self::U32(v), + crate::Literal::I32(v) => Self::I32(v), + crate::Literal::U64(v) => Self::U64(v), + crate::Literal::I64(v) => Self::I64(v), + crate::Literal::Bool(v) => Self::Bool(v), + crate::Literal::AbstractInt(v) => Self::AbstractInt(v), + crate::Literal::AbstractFloat(v) => Self::AbstractFloat(v.to_bits()), } } } @@ -216,8 +191,8 @@ impl crate::Literal { (value, crate::ScalarKind::Sint, 4) => Some(Self::I32(value as _)), (value, crate::ScalarKind::Uint, 8) => Some(Self::U64(value as _)), (value, crate::ScalarKind::Sint, 8) => Some(Self::I64(value as _)), - (1, crate::ScalarKind::Bool, 4) => Some(Self::Bool(true)), - (0, crate::ScalarKind::Bool, 4) => Some(Self::Bool(false)), + (1, crate::ScalarKind::Bool, crate::BOOL_WIDTH) => Some(Self::Bool(true)), + (0, crate::ScalarKind::Bool, crate::BOOL_WIDTH) => Some(Self::Bool(false)), _ => None, } } @@ -279,8 +254,9 @@ impl super::TypeInner { self.scalar().map(|scalar| scalar.kind) } + /// Returns the scalar width in bytes pub fn scalar_width(&self) -> Option { - self.scalar().map(|scalar| scalar.width * 8) + self.scalar().map(|scalar| scalar.width) } pub const fn pointer_space(&self) -> Option { @@ -532,6 +508,7 @@ impl crate::Expression { match *self { Self::Literal(_) | Self::Constant(_) + | Self::Override(_) | Self::ZeroValue(_) | Self::FunctionArgument(_) | Self::GlobalVariable(_) @@ -553,13 +530,9 @@ impl crate::Expression { /// /// [`Access`]: crate::Expression::Access /// [`ResolveContext`]: crate::proc::ResolveContext - pub fn is_dynamic_index(&self, module: &crate::Module) -> bool { + pub const fn is_dynamic_index(&self) -> bool { match *self { - Self::Literal(_) | Self::ZeroValue(_) => false, - Self::Constant(handle) => { - let constant = &module.constants[handle]; - !matches!(constant.r#override, crate::Override::None) - } + Self::Literal(_) | Self::ZeroValue(_) | Self::Constant(_) => false, _ => true, } } @@ -652,7 +625,8 @@ impl crate::Module { GlobalCtx { types: &self.types, constants: &self.constants, - const_expressions: &self.const_expressions, + overrides: &self.overrides, + global_expressions: &self.global_expressions, } } } @@ -667,17 +641,18 @@ pub(super) enum U32EvalError { pub struct GlobalCtx<'a> { pub types: &'a crate::UniqueArena, pub constants: &'a crate::Arena, - pub const_expressions: &'a crate::Arena, + pub overrides: &'a crate::Arena, + pub global_expressions: &'a crate::Arena, } impl GlobalCtx<'_> { - /// Try to evaluate the expression in `self.const_expressions` using its `handle` and return it as a `u32`. + /// Try to evaluate the expression in `self.global_expressions` using its `handle` and return it as a `u32`. #[allow(dead_code)] pub(super) fn eval_expr_to_u32( &self, handle: crate::Handle, ) -> Result { - self.eval_expr_to_u32_from(handle, self.const_expressions) + self.eval_expr_to_u32_from(handle, self.global_expressions) } /// Try to evaluate the expression in the `arena` using its `handle` and return it as a `u32`. @@ -700,7 +675,7 @@ impl GlobalCtx<'_> { &self, handle: crate::Handle, ) -> Option { - self.eval_expr_to_literal_from(handle, self.const_expressions) + self.eval_expr_to_literal_from(handle, self.global_expressions) } fn eval_expr_to_literal_from( @@ -724,7 +699,7 @@ impl GlobalCtx<'_> { } match arena[handle] { crate::Expression::Constant(c) => { - get(*self, self.constants[c].init, self.const_expressions) + get(*self, self.constants[c].init, self.global_expressions) } _ => get(*self, handle, arena), } diff --git a/third_party/rust/naga/src/proc/terminator.rs b/third_party/rust/naga/src/proc/terminator.rs index a5239d4eca..5edf55cb73 100644 --- a/third_party/rust/naga/src/proc/terminator.rs +++ b/third_party/rust/naga/src/proc/terminator.rs @@ -37,6 +37,9 @@ pub fn ensure_block_returns(block: &mut crate::Block) { | S::RayQuery { .. } | S::Atomic { .. } | S::WorkGroupUniformLoad { .. } + | S::SubgroupBallot { .. } + | S::SubgroupCollectiveOperation { .. } + | S::SubgroupGather { .. } | S::Barrier(_)), ) | None => block.push(S::Return { value: None }, Default::default()), diff --git a/third_party/rust/naga/src/proc/typifier.rs b/third_party/rust/naga/src/proc/typifier.rs index 9c4403445c..3936e7efbe 100644 --- a/third_party/rust/naga/src/proc/typifier.rs +++ b/third_party/rust/naga/src/proc/typifier.rs @@ -185,6 +185,7 @@ pub enum ResolveError { pub struct ResolveContext<'a> { pub constants: &'a Arena, + pub overrides: &'a Arena, pub types: &'a UniqueArena, pub special_types: &'a crate::SpecialTypes, pub global_vars: &'a Arena, @@ -202,6 +203,7 @@ impl<'a> ResolveContext<'a> { ) -> Self { Self { constants: &module.constants, + overrides: &module.overrides, types: &module.types, special_types: &module.special_types, global_vars: &module.global_variables, @@ -407,6 +409,7 @@ impl<'a> ResolveContext<'a> { }, crate::Expression::Literal(lit) => TypeResolution::Value(lit.ty_inner()), crate::Expression::Constant(h) => TypeResolution::Handle(self.constants[h].ty), + crate::Expression::Override(h) => TypeResolution::Handle(self.overrides[h].ty), crate::Expression::ZeroValue(ty) => TypeResolution::Handle(ty), crate::Expression::Compose { ty, .. } => TypeResolution::Handle(ty), crate::Expression::FunctionArgument(index) => { @@ -595,6 +598,7 @@ impl<'a> ResolveContext<'a> { | crate::BinaryOperator::ShiftRight => past(left)?.clone(), }, crate::Expression::AtomicResult { ty, .. } => TypeResolution::Handle(ty), + crate::Expression::SubgroupOperationResult { ty } => TypeResolution::Handle(ty), crate::Expression::WorkGroupUniformLoadResult { ty } => TypeResolution::Handle(ty), crate::Expression::Select { accept, .. } => past(accept)?.clone(), crate::Expression::Derivative { expr, .. } => past(expr)?.clone(), @@ -882,6 +886,10 @@ impl<'a> ResolveContext<'a> { .ok_or(ResolveError::MissingSpecialType)?; TypeResolution::Handle(result) } + crate::Expression::SubgroupBallotResult => TypeResolution::Value(Ti::Vector { + scalar: crate::Scalar::U32, + size: crate::VectorSize::Quad, + }), }) } } diff --git a/third_party/rust/naga/src/span.rs b/third_party/rust/naga/src/span.rs index 10744647e9..82cfbe5a4b 100644 --- a/third_party/rust/naga/src/span.rs +++ b/third_party/rust/naga/src/span.rs @@ -72,8 +72,8 @@ impl Span { pub fn location(&self, source: &str) -> SourceLocation { let prefix = &source[..self.start as usize]; let line_number = prefix.matches('\n').count() as u32 + 1; - let line_start = prefix.rfind('\n').map(|pos| pos + 1).unwrap_or(0); - let line_position = source[line_start..self.start as usize].chars().count() as u32 + 1; + let line_start = prefix.rfind('\n').map(|pos| pos + 1).unwrap_or(0) as u32; + let line_position = self.start - line_start + 1; SourceLocation { line_number, @@ -107,14 +107,14 @@ impl std::ops::Index for str { /// Roughly corresponds to the positional members of [`GPUCompilationMessage`][gcm] from /// the WebGPU specification, except /// - `offset` and `length` are in bytes (UTF-8 code units), instead of UTF-16 code units. -/// - `line_position` counts entire Unicode code points, instead of UTF-16 code units. +/// - `line_position` is in bytes (UTF-8 code units), instead of UTF-16 code units. /// /// [gcm]: https://www.w3.org/TR/webgpu/#gpucompilationmessage #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct SourceLocation { /// 1-based line number. pub line_number: u32, - /// 1-based column of the start of this span, counted in Unicode code points. + /// 1-based column in code units (in bytes) of the start of the span. pub line_position: u32, /// 0-based Offset in code units (in bytes) of the start of the span. pub offset: u32, @@ -136,7 +136,7 @@ impl fmt::Display for WithSpan where E: fmt::Display, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } @@ -304,7 +304,7 @@ impl WithSpan { use term::termcolor::NoColor; let files = files::SimpleFile::new(path, source); - let config = codespan_reporting::term::Config::default(); + let config = term::Config::default(); let mut writer = NoColor::new(Vec::new()); term::emit(&mut writer, &config, &files, &self.diagnostic()).expect("cannot write error"); String::from_utf8(writer.into_inner()).unwrap() diff --git a/third_party/rust/naga/src/valid/analyzer.rs b/third_party/rust/naga/src/valid/analyzer.rs index 03fbc4089b..6799e5db27 100644 --- a/third_party/rust/naga/src/valid/analyzer.rs +++ b/third_party/rust/naga/src/valid/analyzer.rs @@ -226,7 +226,7 @@ struct Sampling { sampler: GlobalOrArgument, } -#[derive(Debug)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct FunctionInfo { @@ -574,7 +574,7 @@ impl FunctionInfo { non_uniform_result: self.add_ref(vector), requirements: UniformityRequirements::empty(), }, - E::Literal(_) | E::Constant(_) | E::ZeroValue(_) => Uniformity::new(), + E::Literal(_) | E::Constant(_) | E::Override(_) | E::ZeroValue(_) => Uniformity::new(), E::Compose { ref components, .. } => { let non_uniform_result = components .iter() @@ -787,6 +787,14 @@ impl FunctionInfo { non_uniform_result: self.add_ref(query), requirements: UniformityRequirements::empty(), }, + E::SubgroupBallotResult => Uniformity { + non_uniform_result: Some(handle), + requirements: UniformityRequirements::empty(), + }, + E::SubgroupOperationResult { .. } => Uniformity { + non_uniform_result: Some(handle), + requirements: UniformityRequirements::empty(), + }, }; let ty = resolve_context.resolve(expression, |h| Ok(&self[h].ty))?; @@ -827,7 +835,7 @@ impl FunctionInfo { let req = self.expressions[expr.index()].uniformity.requirements; if self .flags - .contains(super::ValidationFlags::CONTROL_FLOW_UNIFORMITY) + .contains(ValidationFlags::CONTROL_FLOW_UNIFORMITY) && !req.is_empty() { if let Some(cause) = disruptor { @@ -1029,6 +1037,42 @@ impl FunctionInfo { } FunctionUniformity::new() } + S::SubgroupBallot { + result: _, + predicate, + } => { + if let Some(predicate) = predicate { + let _ = self.add_ref(predicate); + } + FunctionUniformity::new() + } + S::SubgroupCollectiveOperation { + op: _, + collective_op: _, + argument, + result: _, + } => { + let _ = self.add_ref(argument); + FunctionUniformity::new() + } + S::SubgroupGather { + mode, + argument, + result: _, + } => { + let _ = self.add_ref(argument); + match mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + let _ = self.add_ref(index); + } + } + FunctionUniformity::new() + } }; disruptor = disruptor.or(uniformity.exit_disruptor()); @@ -1047,7 +1091,7 @@ impl ModuleInfo { gctx: crate::proc::GlobalCtx, ) -> Result<(), super::ConstExpressionError> { self.const_expression_types[handle.index()] = - resolve_context.resolve(&gctx.const_expressions[handle], |h| Ok(&self[h]))?; + resolve_context.resolve(&gctx.global_expressions[handle], |h| Ok(&self[h]))?; Ok(()) } @@ -1186,6 +1230,7 @@ fn uniform_control_flow() { }; let resolve_context = ResolveContext { constants: &Arena::new(), + overrides: &Arena::new(), types: &type_arena, special_types: &crate::SpecialTypes::default(), global_vars: &global_var_arena, diff --git a/third_party/rust/naga/src/valid/expression.rs b/third_party/rust/naga/src/valid/expression.rs index 838ecc4e27..525bd28c17 100644 --- a/third_party/rust/naga/src/valid/expression.rs +++ b/third_party/rust/naga/src/valid/expression.rs @@ -90,6 +90,8 @@ pub enum ExpressionError { sampler: bool, has_ref: bool, }, + #[error("Sample offset must be a const-expression")] + InvalidSampleOffsetExprType, #[error("Sample offset constant {1:?} doesn't match the image dimension {0:?}")] InvalidSampleOffset(crate::ImageDimension, Handle), #[error("Depth reference {0:?} is not a scalar float")] @@ -129,9 +131,12 @@ pub enum ExpressionError { } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum ConstExpressionError { - #[error("The expression is not a constant expression")] - NonConst, + #[error("The expression is not a constant or override expression")] + NonConstOrOverride, + #[error("The expression is not a fully evaluated constant expression")] + NonFullyEvaluatedConst, #[error(transparent)] Compose(#[from] super::ComposeError), #[error("Splatting {0:?} can't be done")] @@ -184,10 +189,15 @@ impl super::Validator { handle: Handle, gctx: crate::proc::GlobalCtx, mod_info: &ModuleInfo, + global_expr_kind: &crate::proc::ExpressionKindTracker, ) -> Result<(), ConstExpressionError> { use crate::Expression as E; - match gctx.const_expressions[handle] { + if !global_expr_kind.is_const_or_override(handle) { + return Err(ConstExpressionError::NonConstOrOverride); + } + + match gctx.global_expressions[handle] { E::Literal(literal) => { self.validate_literal(literal)?; } @@ -201,14 +211,19 @@ impl super::Validator { } E::Splat { value, .. } => match *mod_info[value].inner_with(gctx.types) { crate::TypeInner::Scalar { .. } => {} - _ => return Err(super::ConstExpressionError::InvalidSplatType(value)), + _ => return Err(ConstExpressionError::InvalidSplatType(value)), }, - _ => return Err(super::ConstExpressionError::NonConst), + _ if global_expr_kind.is_const(handle) || !self.allow_overrides => { + return Err(ConstExpressionError::NonFullyEvaluatedConst) + } + // the constant evaluator will report errors about override-expressions + _ => {} } Ok(()) } + #[allow(clippy::too_many_arguments)] pub(super) fn validate_expression( &self, root: Handle, @@ -217,6 +232,7 @@ impl super::Validator { module: &crate::Module, info: &FunctionInfo, mod_info: &ModuleInfo, + global_expr_kind: &crate::proc::ExpressionKindTracker, ) -> Result { use crate::{Expression as E, Scalar as Sc, ScalarKind as Sk, TypeInner as Ti}; @@ -252,9 +268,7 @@ impl super::Validator { return Err(ExpressionError::InvalidIndexType(index)); } } - if dynamic_indexing_restricted - && function.expressions[index].is_dynamic_index(module) - { + if dynamic_indexing_restricted && function.expressions[index].is_dynamic_index() { return Err(ExpressionError::IndexMustBeConstant(base)); } @@ -347,7 +361,7 @@ impl super::Validator { self.validate_literal(literal)?; ShaderStages::all() } - E::Constant(_) | E::ZeroValue(_) => ShaderStages::all(), + E::Constant(_) | E::Override(_) | E::ZeroValue(_) => ShaderStages::all(), E::Compose { ref components, ty } => { validate_compose( ty, @@ -464,6 +478,10 @@ impl super::Validator { // check constant offset if let Some(const_expr) = offset { + if !global_expr_kind.is_const(const_expr) { + return Err(ExpressionError::InvalidSampleOffsetExprType); + } + match *mod_info[const_expr].inner_with(&module.types) { Ti::Scalar(Sc { kind: Sk::Sint, .. }) if num_components == 1 => {} Ti::Vector { @@ -1623,6 +1641,7 @@ impl super::Validator { return Err(ExpressionError::InvalidRayQueryType(query)); } }, + E::SubgroupBallotResult | E::SubgroupOperationResult { .. } => self.subgroup_stages, }; Ok(stages) } @@ -1716,7 +1735,7 @@ fn validate_with_const_expression( use crate::span::Span; let mut module = crate::Module::default(); - module.const_expressions.append(expr, Span::default()); + module.global_expressions.append(expr, Span::default()); let mut validator = super::Validator::new(super::ValidationFlags::CONSTANTS, caps); diff --git a/third_party/rust/naga/src/valid/function.rs b/third_party/rust/naga/src/valid/function.rs index f0ca22cbda..71128fc86d 100644 --- a/third_party/rust/naga/src/valid/function.rs +++ b/third_party/rust/naga/src/valid/function.rs @@ -47,6 +47,19 @@ pub enum AtomicError { ResultTypeMismatch(Handle), } +#[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] +pub enum SubgroupError { + #[error("Operand {0:?} has invalid type.")] + InvalidOperand(Handle), + #[error("Result type for {0:?} doesn't match the statement")] + ResultTypeMismatch(Handle), + #[error("Support for subgroup operation {0:?} is required")] + UnsupportedOperation(super::SubgroupOperationSet), + #[error("Unknown operation")] + UnknownOperation, +} + #[derive(Clone, Debug, thiserror::Error)] #[cfg_attr(test, derive(PartialEq))] pub enum LocalVariableError { @@ -54,8 +67,8 @@ pub enum LocalVariableError { InvalidType(Handle), #[error("Initializer doesn't match the variable type")] InitializerType, - #[error("Initializer is not const")] - NonConstInitializer, + #[error("Initializer is not a const or override expression")] + NonConstOrOverrideInitializer, } #[derive(Clone, Debug, thiserror::Error)] @@ -135,6 +148,8 @@ pub enum FunctionError { InvalidRayDescriptor(Handle), #[error("Ray Query {0:?} does not have a matching type")] InvalidRayQueryType(Handle), + #[error("Shader requires capability {0:?}")] + MissingCapability(super::Capabilities), #[error( "Required uniformity of control flow for {0:?} in {1:?} is not fulfilled because of {2:?}" )] @@ -155,6 +170,8 @@ pub enum FunctionError { WorkgroupUniformLoadExpressionMismatch(Handle), #[error("The expression {0:?} is not valid as a WorkGroupUniformLoad argument. It should be a Pointer in Workgroup address space")] WorkgroupUniformLoadInvalidPointer(Handle), + #[error("Subgroup operation is invalid")] + InvalidSubgroup(#[from] SubgroupError), } bitflags::bitflags! { @@ -399,6 +416,127 @@ impl super::Validator { } Ok(()) } + fn validate_subgroup_operation( + &mut self, + op: &crate::SubgroupOperation, + collective_op: &crate::CollectiveOperation, + argument: Handle, + result: Handle, + context: &BlockContext, + ) -> Result<(), WithSpan> { + let argument_inner = context.resolve_type(argument, &self.valid_expression_set)?; + + let (is_scalar, scalar) = match *argument_inner { + crate::TypeInner::Scalar(scalar) => (true, scalar), + crate::TypeInner::Vector { scalar, .. } => (false, scalar), + _ => { + log::error!("Subgroup operand type {:?}", argument_inner); + return Err(SubgroupError::InvalidOperand(argument) + .with_span_handle(argument, context.expressions) + .into_other()); + } + }; + + use crate::ScalarKind as sk; + use crate::SubgroupOperation as sg; + match (scalar.kind, *op) { + (sk::Bool, sg::All | sg::Any) if is_scalar => {} + (sk::Sint | sk::Uint | sk::Float, sg::Add | sg::Mul | sg::Min | sg::Max) => {} + (sk::Sint | sk::Uint, sg::And | sg::Or | sg::Xor) => {} + + (_, _) => { + log::error!("Subgroup operand type {:?}", argument_inner); + return Err(SubgroupError::InvalidOperand(argument) + .with_span_handle(argument, context.expressions) + .into_other()); + } + }; + + use crate::CollectiveOperation as co; + match (*collective_op, *op) { + ( + co::Reduce, + sg::All + | sg::Any + | sg::Add + | sg::Mul + | sg::Min + | sg::Max + | sg::And + | sg::Or + | sg::Xor, + ) => {} + (co::InclusiveScan | co::ExclusiveScan, sg::Add | sg::Mul) => {} + + (_, _) => { + return Err(SubgroupError::UnknownOperation.with_span().into_other()); + } + }; + + self.emit_expression(result, context)?; + match context.expressions[result] { + crate::Expression::SubgroupOperationResult { ty } + if { &context.types[ty].inner == argument_inner } => {} + _ => { + return Err(SubgroupError::ResultTypeMismatch(result) + .with_span_handle(result, context.expressions) + .into_other()) + } + } + Ok(()) + } + fn validate_subgroup_gather( + &mut self, + mode: &crate::GatherMode, + argument: Handle, + result: Handle, + context: &BlockContext, + ) -> Result<(), WithSpan> { + match *mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => { + let index_ty = context.resolve_type(index, &self.valid_expression_set)?; + match *index_ty { + crate::TypeInner::Scalar(crate::Scalar::U32) => {} + _ => { + log::error!( + "Subgroup gather index type {:?}, expected unsigned int", + index_ty + ); + return Err(SubgroupError::InvalidOperand(argument) + .with_span_handle(index, context.expressions) + .into_other()); + } + } + } + } + let argument_inner = context.resolve_type(argument, &self.valid_expression_set)?; + if !matches!(*argument_inner, + crate::TypeInner::Scalar ( scalar, .. ) | crate::TypeInner::Vector { scalar, .. } + if matches!(scalar.kind, crate::ScalarKind::Uint | crate::ScalarKind::Sint | crate::ScalarKind::Float) + ) { + log::error!("Subgroup gather operand type {:?}", argument_inner); + return Err(SubgroupError::InvalidOperand(argument) + .with_span_handle(argument, context.expressions) + .into_other()); + } + + self.emit_expression(result, context)?; + match context.expressions[result] { + crate::Expression::SubgroupOperationResult { ty } + if { &context.types[ty].inner == argument_inner } => {} + _ => { + return Err(SubgroupError::ResultTypeMismatch(result) + .with_span_handle(result, context.expressions) + .into_other()) + } + } + Ok(()) + } fn validate_block_impl( &mut self, @@ -613,8 +751,30 @@ impl super::Validator { stages &= super::ShaderStages::FRAGMENT; finished = true; } - S::Barrier(_) => { + S::Barrier(barrier) => { stages &= super::ShaderStages::COMPUTE; + if barrier.contains(crate::Barrier::SUB_GROUP) { + if !self.capabilities.contains( + super::Capabilities::SUBGROUP | super::Capabilities::SUBGROUP_BARRIER, + ) { + return Err(FunctionError::MissingCapability( + super::Capabilities::SUBGROUP + | super::Capabilities::SUBGROUP_BARRIER, + ) + .with_span_static(span, "missing capability for this operation")); + } + if !self + .subgroup_operations + .contains(super::SubgroupOperationSet::BASIC) + { + return Err(FunctionError::InvalidSubgroup( + SubgroupError::UnsupportedOperation( + super::SubgroupOperationSet::BASIC, + ), + ) + .with_span_static(span, "support for this operation is not present")); + } + } } S::Store { pointer, value } => { let mut current = pointer; @@ -904,6 +1064,86 @@ impl super::Validator { crate::RayQueryFunction::Terminate => {} } } + S::SubgroupBallot { result, predicate } => { + stages &= self.subgroup_stages; + if !self.capabilities.contains(super::Capabilities::SUBGROUP) { + return Err(FunctionError::MissingCapability( + super::Capabilities::SUBGROUP, + ) + .with_span_static(span, "missing capability for this operation")); + } + if !self + .subgroup_operations + .contains(super::SubgroupOperationSet::BALLOT) + { + return Err(FunctionError::InvalidSubgroup( + SubgroupError::UnsupportedOperation( + super::SubgroupOperationSet::BALLOT, + ), + ) + .with_span_static(span, "support for this operation is not present")); + } + if let Some(predicate) = predicate { + let predicate_inner = + context.resolve_type(predicate, &self.valid_expression_set)?; + if !matches!( + *predicate_inner, + crate::TypeInner::Scalar(crate::Scalar::BOOL,) + ) { + log::error!( + "Subgroup ballot predicate type {:?} expected bool", + predicate_inner + ); + return Err(SubgroupError::InvalidOperand(predicate) + .with_span_handle(predicate, context.expressions) + .into_other()); + } + } + self.emit_expression(result, context)?; + } + S::SubgroupCollectiveOperation { + ref op, + ref collective_op, + argument, + result, + } => { + stages &= self.subgroup_stages; + if !self.capabilities.contains(super::Capabilities::SUBGROUP) { + return Err(FunctionError::MissingCapability( + super::Capabilities::SUBGROUP, + ) + .with_span_static(span, "missing capability for this operation")); + } + let operation = op.required_operations(); + if !self.subgroup_operations.contains(operation) { + return Err(FunctionError::InvalidSubgroup( + SubgroupError::UnsupportedOperation(operation), + ) + .with_span_static(span, "support for this operation is not present")); + } + self.validate_subgroup_operation(op, collective_op, argument, result, context)?; + } + S::SubgroupGather { + ref mode, + argument, + result, + } => { + stages &= self.subgroup_stages; + if !self.capabilities.contains(super::Capabilities::SUBGROUP) { + return Err(FunctionError::MissingCapability( + super::Capabilities::SUBGROUP, + ) + .with_span_static(span, "missing capability for this operation")); + } + let operation = mode.required_operations(); + if !self.subgroup_operations.contains(operation) { + return Err(FunctionError::InvalidSubgroup( + SubgroupError::UnsupportedOperation(operation), + ) + .with_span_static(span, "support for this operation is not present")); + } + self.validate_subgroup_gather(mode, argument, result, context)?; + } } } Ok(BlockInfo { stages, finished }) @@ -927,7 +1167,7 @@ impl super::Validator { var: &crate::LocalVariable, gctx: crate::proc::GlobalCtx, fun_info: &FunctionInfo, - expression_constness: &crate::proc::ExpressionConstnessTracker, + local_expr_kind: &crate::proc::ExpressionKindTracker, ) -> Result<(), LocalVariableError> { log::debug!("var {:?}", var); let type_info = self @@ -945,8 +1185,8 @@ impl super::Validator { return Err(LocalVariableError::InitializerType); } - if !expression_constness.is_const(init) { - return Err(LocalVariableError::NonConstInitializer); + if !local_expr_kind.is_const_or_override(init) { + return Err(LocalVariableError::NonConstOrOverrideInitializer); } } @@ -959,14 +1199,14 @@ impl super::Validator { module: &crate::Module, mod_info: &ModuleInfo, entry_point: bool, + global_expr_kind: &crate::proc::ExpressionKindTracker, ) -> Result> { let mut info = mod_info.process_function(fun, module, self.flags, self.capabilities)?; - let expression_constness = - crate::proc::ExpressionConstnessTracker::from_arena(&fun.expressions); + let local_expr_kind = crate::proc::ExpressionKindTracker::from_arena(&fun.expressions); for (var_handle, var) in fun.local_variables.iter() { - self.validate_local_var(var, module.to_ctx(), &info, &expression_constness) + self.validate_local_var(var, module.to_ctx(), &info, &local_expr_kind) .map_err(|source| { FunctionError::LocalVariable { handle: var_handle, @@ -1032,7 +1272,15 @@ impl super::Validator { self.valid_expression_set.insert(handle.index()); } if self.flags.contains(super::ValidationFlags::EXPRESSIONS) { - match self.validate_expression(handle, expr, fun, module, &info, mod_info) { + match self.validate_expression( + handle, + expr, + fun, + module, + &info, + mod_info, + global_expr_kind, + ) { Ok(stages) => info.available_stages &= stages, Err(source) => { return Err(FunctionError::Expression { handle, source } diff --git a/third_party/rust/naga/src/valid/handles.rs b/third_party/rust/naga/src/valid/handles.rs index e482f293bb..8f78204055 100644 --- a/third_party/rust/naga/src/valid/handles.rs +++ b/third_party/rust/naga/src/valid/handles.rs @@ -31,12 +31,13 @@ impl super::Validator { pub(super) fn validate_module_handles(module: &crate::Module) -> Result<(), ValidationError> { let &crate::Module { ref constants, + ref overrides, ref entry_points, ref functions, ref global_variables, ref types, ref special_types, - ref const_expressions, + ref global_expressions, } = module; // NOTE: Types being first is important. All other forms of validation depend on this. @@ -67,23 +68,31 @@ impl super::Validator { } } - for handle_and_expr in const_expressions.iter() { - Self::validate_const_expression_handles(handle_and_expr, constants, types)?; + for handle_and_expr in global_expressions.iter() { + Self::validate_const_expression_handles(handle_and_expr, constants, overrides, types)?; } let validate_type = |handle| Self::validate_type_handle(handle, types); let validate_const_expr = - |handle| Self::validate_expression_handle(handle, const_expressions); + |handle| Self::validate_expression_handle(handle, global_expressions); for (_handle, constant) in constants.iter() { - let &crate::Constant { + let &crate::Constant { name: _, ty, init } = constant; + validate_type(ty)?; + validate_const_expr(init)?; + } + + for (_handle, override_) in overrides.iter() { + let &crate::Override { name: _, - r#override: _, + id: _, ty, init, - } = constant; + } = override_; validate_type(ty)?; - validate_const_expr(init)?; + if let Some(init_expr) = init { + validate_const_expr(init_expr)?; + } } for (_handle, global_variable) in global_variables.iter() { @@ -140,7 +149,8 @@ impl super::Validator { Self::validate_expression_handles( handle_and_expr, constants, - const_expressions, + overrides, + global_expressions, types, local_variables, global_variables, @@ -186,6 +196,13 @@ impl super::Validator { handle.check_valid_for(constants).map(|_| ()) } + fn validate_override_handle( + handle: Handle, + overrides: &Arena, + ) -> Result<(), InvalidHandleError> { + handle.check_valid_for(overrides).map(|_| ()) + } + fn validate_expression_handle( handle: Handle, expressions: &Arena, @@ -203,9 +220,11 @@ impl super::Validator { fn validate_const_expression_handles( (handle, expression): (Handle, &crate::Expression), constants: &Arena, + overrides: &Arena, types: &UniqueArena, ) -> Result<(), InvalidHandleError> { let validate_constant = |handle| Self::validate_constant_handle(handle, constants); + let validate_override = |handle| Self::validate_override_handle(handle, overrides); let validate_type = |handle| Self::validate_type_handle(handle, types); match *expression { @@ -214,6 +233,12 @@ impl super::Validator { validate_constant(constant)?; handle.check_dep(constants[constant].init)?; } + crate::Expression::Override(override_) => { + validate_override(override_)?; + if let Some(init) = overrides[override_].init { + handle.check_dep(init)?; + } + } crate::Expression::ZeroValue(ty) => { validate_type(ty)?; } @@ -230,7 +255,8 @@ impl super::Validator { fn validate_expression_handles( (handle, expression): (Handle, &crate::Expression), constants: &Arena, - const_expressions: &Arena, + overrides: &Arena, + global_expressions: &Arena, types: &UniqueArena, local_variables: &Arena, global_variables: &Arena, @@ -239,8 +265,9 @@ impl super::Validator { current_function: Option>, ) -> Result<(), InvalidHandleError> { let validate_constant = |handle| Self::validate_constant_handle(handle, constants); + let validate_override = |handle| Self::validate_override_handle(handle, overrides); let validate_const_expr = - |handle| Self::validate_expression_handle(handle, const_expressions); + |handle| Self::validate_expression_handle(handle, global_expressions); let validate_type = |handle| Self::validate_type_handle(handle, types); match *expression { @@ -260,6 +287,9 @@ impl super::Validator { crate::Expression::Constant(constant) => { validate_constant(constant)?; } + crate::Expression::Override(override_) => { + validate_override(override_)?; + } crate::Expression::ZeroValue(ty) => { validate_type(ty)?; } @@ -390,6 +420,8 @@ impl super::Validator { } crate::Expression::AtomicResult { .. } | crate::Expression::RayQueryProceedResult + | crate::Expression::SubgroupBallotResult + | crate::Expression::SubgroupOperationResult { .. } | crate::Expression::WorkGroupUniformLoadResult { .. } => (), crate::Expression::ArrayLength(array) => { handle.check_dep(array)?; @@ -535,6 +567,38 @@ impl super::Validator { } Ok(()) } + crate::Statement::SubgroupBallot { result, predicate } => { + validate_expr_opt(predicate)?; + validate_expr(result)?; + Ok(()) + } + crate::Statement::SubgroupCollectiveOperation { + op: _, + collective_op: _, + argument, + result, + } => { + validate_expr(argument)?; + validate_expr(result)?; + Ok(()) + } + crate::Statement::SubgroupGather { + mode, + argument, + result, + } => { + validate_expr(argument)?; + match mode { + crate::GatherMode::BroadcastFirst => {} + crate::GatherMode::Broadcast(index) + | crate::GatherMode::Shuffle(index) + | crate::GatherMode::ShuffleDown(index) + | crate::GatherMode::ShuffleUp(index) + | crate::GatherMode::ShuffleXor(index) => validate_expr(index)?, + } + validate_expr(result)?; + Ok(()) + } crate::Statement::Break | crate::Statement::Continue | crate::Statement::Kill @@ -562,6 +626,7 @@ impl From for ValidationError { } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum InvalidHandleError { #[error(transparent)] BadHandle(#[from] BadHandle), @@ -572,6 +637,7 @@ pub enum InvalidHandleError { } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] #[error( "{subject:?} of kind {subject_kind:?} depends on {depends_on:?} of kind {depends_on_kind}, \ which has not been processed yet" @@ -664,6 +730,7 @@ fn constant_deps() { let mut const_exprs = Arena::new(); let mut fun_exprs = Arena::new(); let mut constants = Arena::new(); + let overrides = Arena::new(); let i32_handle = types.insert( Type { @@ -679,7 +746,6 @@ fn constant_deps() { let self_referential_const = constants.append( Constant { name: None, - r#override: crate::Override::None, ty: i32_handle, init: fun_expr, }, @@ -692,6 +758,7 @@ fn constant_deps() { assert!(super::Validator::validate_const_expression_handles( handle_and_expr, &constants, + &overrides, &types, ) .is_err()); diff --git a/third_party/rust/naga/src/valid/interface.rs b/third_party/rust/naga/src/valid/interface.rs index 84c8b09ddb..db890ddbac 100644 --- a/third_party/rust/naga/src/valid/interface.rs +++ b/third_party/rust/naga/src/valid/interface.rs @@ -10,6 +10,7 @@ use bit_set::BitSet; const MAX_WORKGROUP_SIZE: u32 = 0x4000; #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum GlobalVariableError { #[error("Usage isn't compatible with address space {0:?}")] InvalidUsage(crate::AddressSpace), @@ -30,6 +31,8 @@ pub enum GlobalVariableError { Handle, #[source] Disalignment, ), + #[error("Initializer must be an override-expression")] + InitializerExprType, #[error("Initializer doesn't match the variable type")] InitializerType, #[error("Initializer can't be used with address space {0:?}")] @@ -39,6 +42,7 @@ pub enum GlobalVariableError { } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum VaryingError { #[error("The type {0:?} does not match the varying")] InvalidType(Handle), @@ -73,9 +77,12 @@ pub enum VaryingError { location: u32, attribute: &'static str, }, + #[error("Workgroup size is multi dimensional, @builtin(subgroup_id) and @builtin(subgroup_invocation_id) are not supported.")] + InvalidMultiDimensionalSubgroupBuiltIn, } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum EntryPointError { #[error("Multiple conflicting entry points")] Conflict, @@ -135,6 +142,7 @@ struct VaryingContext<'a> { impl VaryingContext<'_> { fn validate_impl( &mut self, + ep: &crate::EntryPoint, ty: Handle, binding: &crate::Binding, ) -> Result<(), VaryingError> { @@ -162,12 +170,24 @@ impl VaryingContext<'_> { Bi::PrimitiveIndex => Capabilities::PRIMITIVE_INDEX, Bi::ViewIndex => Capabilities::MULTIVIEW, Bi::SampleIndex => Capabilities::MULTISAMPLED_SHADING, + Bi::NumSubgroups + | Bi::SubgroupId + | Bi::SubgroupSize + | Bi::SubgroupInvocationId => Capabilities::SUBGROUP, _ => Capabilities::empty(), }; if !self.capabilities.contains(required) { return Err(VaryingError::UnsupportedCapability(required)); } + if matches!( + built_in, + crate::BuiltIn::SubgroupId | crate::BuiltIn::SubgroupInvocationId + ) && ep.workgroup_size[1..].iter().any(|&s| s > 1) + { + return Err(VaryingError::InvalidMultiDimensionalSubgroupBuiltIn); + } + let (visible, type_good) = match built_in { Bi::BaseInstance | Bi::BaseVertex | Bi::InstanceIndex | Bi::VertexIndex => ( self.stage == St::Vertex && !self.output, @@ -249,6 +269,17 @@ impl VaryingContext<'_> { scalar: crate::Scalar::U32, }, ), + Bi::NumSubgroups | Bi::SubgroupId => ( + self.stage == St::Compute && !self.output, + *ty_inner == Ti::Scalar(crate::Scalar::U32), + ), + Bi::SubgroupSize | Bi::SubgroupInvocationId => ( + match self.stage { + St::Compute | St::Fragment => !self.output, + St::Vertex => false, + }, + *ty_inner == Ti::Scalar(crate::Scalar::U32), + ), }; if !visible { @@ -349,13 +380,14 @@ impl VaryingContext<'_> { fn validate( &mut self, + ep: &crate::EntryPoint, ty: Handle, binding: Option<&crate::Binding>, ) -> Result<(), WithSpan> { let span_context = self.types.get_span_context(ty); match binding { Some(binding) => self - .validate_impl(ty, binding) + .validate_impl(ep, ty, binding) .map_err(|e| e.with_span_context(span_context)), None => { match self.types[ty].inner { @@ -372,7 +404,7 @@ impl VaryingContext<'_> { } } Some(ref binding) => self - .validate_impl(member.ty, binding) + .validate_impl(ep, member.ty, binding) .map_err(|e| e.with_span_context(span_context))?, } } @@ -395,6 +427,7 @@ impl super::Validator { var: &crate::GlobalVariable, gctx: crate::proc::GlobalCtx, mod_info: &ModuleInfo, + global_expr_kind: &crate::proc::ExpressionKindTracker, ) -> Result<(), GlobalVariableError> { use super::TypeFlags; @@ -523,6 +556,10 @@ impl super::Validator { } } + if !global_expr_kind.is_const_or_override(init) { + return Err(GlobalVariableError::InitializerExprType); + } + let decl_ty = &gctx.types[var.ty].inner; let init_ty = mod_info[init].inner_with(gctx.types); if !decl_ty.equivalent(init_ty, gctx.types) { @@ -538,6 +575,7 @@ impl super::Validator { ep: &crate::EntryPoint, module: &crate::Module, mod_info: &ModuleInfo, + global_expr_kind: &crate::proc::ExpressionKindTracker, ) -> Result> { if ep.early_depth_test.is_some() { let required = Capabilities::EARLY_DEPTH_TEST; @@ -566,7 +604,7 @@ impl super::Validator { } let mut info = self - .validate_function(&ep.function, module, mod_info, true) + .validate_function(&ep.function, module, mod_info, true, global_expr_kind) .map_err(WithSpan::into_other)?; { @@ -598,7 +636,7 @@ impl super::Validator { capabilities: self.capabilities, flags: self.flags, }; - ctx.validate(fa.ty, fa.binding.as_ref()) + ctx.validate(ep, fa.ty, fa.binding.as_ref()) .map_err_inner(|e| EntryPointError::Argument(index as u32, e).with_span())?; } @@ -616,7 +654,7 @@ impl super::Validator { capabilities: self.capabilities, flags: self.flags, }; - ctx.validate(fr.ty, fr.binding.as_ref()) + ctx.validate(ep, fr.ty, fr.binding.as_ref()) .map_err_inner(|e| EntryPointError::Result(e).with_span())?; if ctx.second_blend_source { // Only the first location may be used when dual source blending diff --git a/third_party/rust/naga/src/valid/mod.rs b/third_party/rust/naga/src/valid/mod.rs index 5459434f33..a0057f39ac 100644 --- a/third_party/rust/naga/src/valid/mod.rs +++ b/third_party/rust/naga/src/valid/mod.rs @@ -12,7 +12,7 @@ mod r#type; use crate::{ arena::Handle, - proc::{LayoutError, Layouter, TypeResolution}, + proc::{ExpressionKindTracker, LayoutError, Layouter, TypeResolution}, FastHashSet, }; use bit_set::BitSet; @@ -77,7 +77,7 @@ bitflags::bitflags! { #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct Capabilities: u16 { + pub struct Capabilities: u32 { /// Support for [`AddressSpace:PushConstant`]. const PUSH_CONSTANT = 0x1; /// Float values with width = 8. @@ -110,6 +110,10 @@ bitflags::bitflags! { const CUBE_ARRAY_TEXTURES = 0x4000; /// Support for 64-bit signed and unsigned integers. const SHADER_INT64 = 0x8000; + /// Support for subgroup operations. + const SUBGROUP = 0x10000; + /// Support for subgroup barriers. + const SUBGROUP_BARRIER = 0x20000; } } @@ -119,6 +123,57 @@ impl Default for Capabilities { } } +bitflags::bitflags! { + /// Supported subgroup operations + #[cfg_attr(feature = "serialize", derive(serde::Serialize))] + #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] + pub struct SubgroupOperationSet: u8 { + /// Elect, Barrier + const BASIC = 1 << 0; + /// Any, All + const VOTE = 1 << 1; + /// reductions, scans + const ARITHMETIC = 1 << 2; + /// ballot, broadcast + const BALLOT = 1 << 3; + /// shuffle, shuffle xor + const SHUFFLE = 1 << 4; + /// shuffle up, down + const SHUFFLE_RELATIVE = 1 << 5; + // We don't support these operations yet + // /// Clustered + // const CLUSTERED = 1 << 6; + // /// Quad supported + // const QUAD_FRAGMENT_COMPUTE = 1 << 7; + // /// Quad supported in all stages + // const QUAD_ALL_STAGES = 1 << 8; + } +} + +impl super::SubgroupOperation { + const fn required_operations(&self) -> SubgroupOperationSet { + use SubgroupOperationSet as S; + match *self { + Self::All | Self::Any => S::VOTE, + Self::Add | Self::Mul | Self::Min | Self::Max | Self::And | Self::Or | Self::Xor => { + S::ARITHMETIC + } + } + } +} + +impl super::GatherMode { + const fn required_operations(&self) -> SubgroupOperationSet { + use SubgroupOperationSet as S; + match *self { + Self::BroadcastFirst | Self::Broadcast(_) => S::BALLOT, + Self::Shuffle(_) | Self::ShuffleXor(_) => S::SHUFFLE, + Self::ShuffleUp(_) | Self::ShuffleDown(_) => S::SHUFFLE_RELATIVE, + } + } +} + bitflags::bitflags! { /// Validation flags. #[cfg_attr(feature = "serialize", derive(serde::Serialize))] @@ -131,7 +186,7 @@ bitflags::bitflags! { } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct ModuleInfo { @@ -166,6 +221,8 @@ impl ops::Index> for ModuleInfo { pub struct Validator { flags: ValidationFlags, capabilities: Capabilities, + subgroup_stages: ShaderStages, + subgroup_operations: SubgroupOperationSet, types: Vec, layouter: Layouter, location_mask: BitSet, @@ -174,10 +231,15 @@ pub struct Validator { switch_values: FastHashSet, valid_expression_list: Vec>, valid_expression_set: BitSet, + override_ids: FastHashSet, + allow_overrides: bool, } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum ConstantError { + #[error("Initializer must be a const-expression")] + InitializerExprType, #[error("The type doesn't match the constant")] InvalidType, #[error("The type is not constructible")] @@ -185,6 +247,26 @@ pub enum ConstantError { } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] +pub enum OverrideError { + #[error("Override name and ID are missing")] + MissingNameAndID, + #[error("Override ID must be unique")] + DuplicateID, + #[error("Initializer must be a const-expression or override-expression")] + InitializerExprType, + #[error("The type doesn't match the override")] + InvalidType, + #[error("The type is not constructible")] + NonConstructibleType, + #[error("The type is not a scalar")] + TypeNotScalar, + #[error("Override declarations are not allowed")] + NotAllowed, +} + +#[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum ValidationError { #[error(transparent)] InvalidHandle(#[from] InvalidHandleError), @@ -207,6 +289,12 @@ pub enum ValidationError { name: String, source: ConstantError, }, + #[error("Override {handle:?} '{name}' is invalid")] + Override { + handle: Handle, + name: String, + source: OverrideError, + }, #[error("Global variable {handle:?} '{name}' is invalid")] GlobalVariable { handle: Handle, @@ -286,6 +374,8 @@ impl Validator { Validator { flags, capabilities, + subgroup_stages: ShaderStages::empty(), + subgroup_operations: SubgroupOperationSet::empty(), types: Vec::new(), layouter: Layouter::default(), location_mask: BitSet::new(), @@ -293,9 +383,21 @@ impl Validator { switch_values: FastHashSet::default(), valid_expression_list: Vec::new(), valid_expression_set: BitSet::new(), + override_ids: FastHashSet::default(), + allow_overrides: true, } } + pub fn subgroup_stages(&mut self, stages: ShaderStages) -> &mut Self { + self.subgroup_stages = stages; + self + } + + pub fn subgroup_operations(&mut self, operations: SubgroupOperationSet) -> &mut Self { + self.subgroup_operations = operations; + self + } + /// Reset the validator internals pub fn reset(&mut self) { self.types.clear(); @@ -305,6 +407,7 @@ impl Validator { self.switch_values.clear(); self.valid_expression_list.clear(); self.valid_expression_set.clear(); + self.override_ids.clear(); } fn validate_constant( @@ -312,6 +415,7 @@ impl Validator { handle: Handle, gctx: crate::proc::GlobalCtx, mod_info: &ModuleInfo, + global_expr_kind: &ExpressionKindTracker, ) -> Result<(), ConstantError> { let con = &gctx.constants[handle]; @@ -320,6 +424,10 @@ impl Validator { return Err(ConstantError::NonConstructibleType); } + if !global_expr_kind.is_const(con.init) { + return Err(ConstantError::InitializerExprType); + } + let decl_ty = &gctx.types[con.ty].inner; let init_ty = mod_info[con.init].inner_with(gctx.types); if !decl_ty.equivalent(init_ty, gctx.types) { @@ -329,10 +437,79 @@ impl Validator { Ok(()) } + fn validate_override( + &mut self, + handle: Handle, + gctx: crate::proc::GlobalCtx, + mod_info: &ModuleInfo, + ) -> Result<(), OverrideError> { + if !self.allow_overrides { + return Err(OverrideError::NotAllowed); + } + + let o = &gctx.overrides[handle]; + + if o.name.is_none() && o.id.is_none() { + return Err(OverrideError::MissingNameAndID); + } + + if let Some(id) = o.id { + if !self.override_ids.insert(id) { + return Err(OverrideError::DuplicateID); + } + } + + let type_info = &self.types[o.ty.index()]; + if !type_info.flags.contains(TypeFlags::CONSTRUCTIBLE) { + return Err(OverrideError::NonConstructibleType); + } + + let decl_ty = &gctx.types[o.ty].inner; + match decl_ty { + &crate::TypeInner::Scalar(scalar) => match scalar { + crate::Scalar::BOOL + | crate::Scalar::I32 + | crate::Scalar::U32 + | crate::Scalar::F32 + | crate::Scalar::F64 => {} + _ => return Err(OverrideError::TypeNotScalar), + }, + _ => return Err(OverrideError::TypeNotScalar), + } + + if let Some(init) = o.init { + let init_ty = mod_info[init].inner_with(gctx.types); + if !decl_ty.equivalent(init_ty, gctx.types) { + return Err(OverrideError::InvalidType); + } + } + + Ok(()) + } + /// Check the given module to be valid. pub fn validate( &mut self, module: &crate::Module, + ) -> Result> { + self.allow_overrides = true; + self.validate_impl(module) + } + + /// Check the given module to be valid. + /// + /// With the additional restriction that overrides are not present. + pub fn validate_no_overrides( + &mut self, + module: &crate::Module, + ) -> Result> { + self.allow_overrides = false; + self.validate_impl(module) + } + + fn validate_impl( + &mut self, + module: &crate::Module, ) -> Result> { self.reset(); self.reset_types(module.types.len()); @@ -354,7 +531,7 @@ impl Validator { type_flags: Vec::with_capacity(module.types.len()), functions: Vec::with_capacity(module.functions.len()), entry_points: Vec::with_capacity(module.entry_points.len()), - const_expression_types: vec![placeholder; module.const_expressions.len()] + const_expression_types: vec![placeholder; module.global_expressions.len()] .into_boxed_slice(), }; @@ -376,27 +553,34 @@ impl Validator { { let t = crate::Arena::new(); let resolve_context = crate::proc::ResolveContext::with_locals(module, &t, &[]); - for (handle, _) in module.const_expressions.iter() { + for (handle, _) in module.global_expressions.iter() { mod_info .process_const_expression(handle, &resolve_context, module.to_ctx()) .map_err(|source| { ValidationError::ConstExpression { handle, source } - .with_span_handle(handle, &module.const_expressions) + .with_span_handle(handle, &module.global_expressions) })? } } + let global_expr_kind = ExpressionKindTracker::from_arena(&module.global_expressions); + if self.flags.contains(ValidationFlags::CONSTANTS) { - for (handle, _) in module.const_expressions.iter() { - self.validate_const_expression(handle, module.to_ctx(), &mod_info) - .map_err(|source| { - ValidationError::ConstExpression { handle, source } - .with_span_handle(handle, &module.const_expressions) - })? + for (handle, _) in module.global_expressions.iter() { + self.validate_const_expression( + handle, + module.to_ctx(), + &mod_info, + &global_expr_kind, + ) + .map_err(|source| { + ValidationError::ConstExpression { handle, source } + .with_span_handle(handle, &module.global_expressions) + })? } for (handle, constant) in module.constants.iter() { - self.validate_constant(handle, module.to_ctx(), &mod_info) + self.validate_constant(handle, module.to_ctx(), &mod_info, &global_expr_kind) .map_err(|source| { ValidationError::Constant { handle, @@ -406,10 +590,22 @@ impl Validator { .with_span_handle(handle, &module.constants) })? } + + for (handle, override_) in module.overrides.iter() { + self.validate_override(handle, module.to_ctx(), &mod_info) + .map_err(|source| { + ValidationError::Override { + handle, + name: override_.name.clone().unwrap_or_default(), + source, + } + .with_span_handle(handle, &module.overrides) + })? + } } for (var_handle, var) in module.global_variables.iter() { - self.validate_global_var(var, module.to_ctx(), &mod_info) + self.validate_global_var(var, module.to_ctx(), &mod_info, &global_expr_kind) .map_err(|source| { ValidationError::GlobalVariable { handle: var_handle, @@ -421,7 +617,7 @@ impl Validator { } for (handle, fun) in module.functions.iter() { - match self.validate_function(fun, module, &mod_info, false) { + match self.validate_function(fun, module, &mod_info, false, &global_expr_kind) { Ok(info) => mod_info.functions.push(info), Err(error) => { return Err(error.and_then(|source| { @@ -447,7 +643,7 @@ impl Validator { .with_span()); // TODO: keep some EP span information? } - match self.validate_entry_point(ep, module, &mod_info) { + match self.validate_entry_point(ep, module, &mod_info, &global_expr_kind) { Ok(info) => mod_info.entry_points.push(info), Err(error) => { return Err(error.and_then(|source| { diff --git a/third_party/rust/naga/src/valid/type.rs b/third_party/rust/naga/src/valid/type.rs index b8eb618ed4..f5b9856074 100644 --- a/third_party/rust/naga/src/valid/type.rs +++ b/third_party/rust/naga/src/valid/type.rs @@ -63,6 +63,7 @@ bitflags::bitflags! { } #[derive(Clone, Copy, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum Disalignment { #[error("The array stride {stride} is not a multiple of the required alignment {alignment}")] ArrayStride { stride: u32, alignment: Alignment }, @@ -87,6 +88,7 @@ pub enum Disalignment { } #[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] pub enum TypeError { #[error("Capability {0:?} is required")] MissingCapability(Capabilities), @@ -326,7 +328,6 @@ impl super::Validator { TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::COPY - | TypeFlags::HOST_SHAREABLE | TypeFlags::ARGUMENT | TypeFlags::CONSTRUCTIBLE | shareable, diff --git a/third_party/rust/neqo-common/.cargo-checksum.json b/third_party/rust/neqo-common/.cargo-checksum.json index 64d5739014..d94920d26f 100644 --- a/third_party/rust/neqo-common/.cargo-checksum.json +++ b/third_party/rust/neqo-common/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"28a963b1a9067fef18e945a938a6ae5ea14a3a29a937f3be2ec4c0e3ae33854f","benches/timer.rs":"52d35abe1e06b92e913f43d95295b4eded0f19809677a7a63857fe92dad2c6fa","build.rs":"306b2f909a25ae38daf5404a4e128d2a94e8975b70870864c2a71cafec9717c7","src/codec.rs":"fd239f75d374db6ff744211344c82bcd19ecf753e07410e1fe37732bbb81dfe9","src/datagram.rs":"691ad94a3618d6bf5202a7911419b5e75e318d09c8cc57a9a542a864dcc764ec","src/event.rs":"106ca6c4afb107fa49a1bc72f5eb4ae95f4baa1ba19736aa38c8ba973774c160","src/header.rs":"467b947f78bfe354d8bb51e8df0c2be69e75a45e2be688d81f0d268aa77c89ef","src/hrtime.rs":"112dc758e65301b8a7a508b125d3d61063180d432bffaec566a050d4f907ab18","src/incrdecoder.rs":"577c32b9ace51f2daaf940be6d0c391c4f55cd42ef6848c68c1ffc970d8c57b5","src/lib.rs":"c917282134f43d0ddfbd67bbceea9f615a7db8a23608f809b4746808c08a9b3f","src/log.rs":"6ed99e15707c4256ae793011ed2f4b33aa81fed70205aaf5f8d3cd11ad451cf0","src/qlog.rs":"9b081f32bf158fd340300693acc97fe0554b617ae664eba86e4d3572e2b1e16e","src/timer.rs":"f6da86baf3b5d91c1230d5296ef886fb7233cdefa8c8e2b4197fcf82425a54fa","src/tos.rs":"baec87b4f8a6253b88cd257730bd1e3147c046ef993288b08235d54a24f88fbe","tests/log.rs":"a11e21fb570258ca93bb40e3923817d381e1e605accbc3aed1df5a0a9918b41d"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"3459350f69e0272710e4d5d861f9646225f9c187698e721f01d38f2d9b1b3394","benches/timer.rs":"52d35abe1e06b92e913f43d95295b4eded0f19809677a7a63857fe92dad2c6fa","build.rs":"306b2f909a25ae38daf5404a4e128d2a94e8975b70870864c2a71cafec9717c7","src/codec.rs":"fd239f75d374db6ff744211344c82bcd19ecf753e07410e1fe37732bbb81dfe9","src/datagram.rs":"19882ecf3d3b03d6e87a1b8f871429f07f5b0db6d891c9362c91306a0cee33c7","src/event.rs":"106ca6c4afb107fa49a1bc72f5eb4ae95f4baa1ba19736aa38c8ba973774c160","src/fuzz.rs":"1ca74a34bdc97fedecf8a63c4a13cc487d1b2212398fb76f67792c822002138d","src/header.rs":"467b947f78bfe354d8bb51e8df0c2be69e75a45e2be688d81f0d268aa77c89ef","src/hrtime.rs":"112dc758e65301b8a7a508b125d3d61063180d432bffaec566a050d4f907ab18","src/incrdecoder.rs":"577c32b9ace51f2daaf940be6d0c391c4f55cd42ef6848c68c1ffc970d8c57b5","src/lib.rs":"bc585a11daf56f9680fc5a652c5ca79e00eb0f3fa34a45ecd1b6c60200b95cf1","src/log.rs":"6ed99e15707c4256ae793011ed2f4b33aa81fed70205aaf5f8d3cd11ad451cf0","src/qlog.rs":"9b081f32bf158fd340300693acc97fe0554b617ae664eba86e4d3572e2b1e16e","src/timer.rs":"f6da86baf3b5d91c1230d5296ef886fb7233cdefa8c8e2b4197fcf82425a54fa","src/tos.rs":"087cd9b12a2510f05605e755d85c07179817c22670fe1b5d6db987357f77b38e","tests/log.rs":"a11e21fb570258ca93bb40e3923817d381e1e605accbc3aed1df5a0a9918b41d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-common/Cargo.toml b/third_party/rust/neqo-common/Cargo.toml index 90b254c888..0659508aeb 100644 --- a/third_party/rust/neqo-common/Cargo.toml +++ b/third_party/rust/neqo-common/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.74.0" +rust-version = "1.76.0" name = "neqo-common" -version = "0.7.5" +version = "0.7.7" authors = ["The Neqo Authors "] build = "build.rs" homepage = "https://github.com/mozilla/neqo/" @@ -35,12 +35,18 @@ default-features = false version = "0.10" default-features = false +[dependencies.hex] +version = "0.4" +features = ["alloc"] +optional = true +default-features = false + [dependencies.log] version = "0.4" default-features = false [dependencies.qlog] -version = "0.12" +version = "0.13" default-features = false [dependencies.time] @@ -57,6 +63,7 @@ default-features = false path = "../test-fixture" [features] +build-fuzzing-corpus = ["hex"] ci = [] [target."cfg(windows)".dependencies.winapi] diff --git a/third_party/rust/neqo-common/src/datagram.rs b/third_party/rust/neqo-common/src/datagram.rs index cc2cb7d113..2f2bb53766 100644 --- a/third_party/rust/neqo-common/src/datagram.rs +++ b/third_party/rust/neqo-common/src/datagram.rs @@ -95,6 +95,6 @@ fn fmt_datagram() { let d = datagram([0; 1].to_vec()); assert_eq!( &format!("{d:?}"), - "Datagram IpTos(Cs0, NotEct) TTL Some(128) [fe80::1]:443->[fe80::1]:443: [1]: 00" + "Datagram IpTos(Cs0, Ect0) TTL Some(128) [fe80::1]:443->[fe80::1]:443: [1]: 00" ); } diff --git a/third_party/rust/neqo-common/src/fuzz.rs b/third_party/rust/neqo-common/src/fuzz.rs new file mode 100644 index 0000000000..d0a35a49ae --- /dev/null +++ b/third_party/rust/neqo-common/src/fuzz.rs @@ -0,0 +1,43 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{ + collections::hash_map::DefaultHasher, + fs::File, + hash::{Hash, Hasher}, + io::Write, + path::Path, +}; + +/// Write a data item `data` for the fuzzing target `target` to the fuzzing corpus. The caller needs +/// to make sure that `target` is the correct fuzzing target name for the data written. +/// +/// # Panics +/// +/// Panics if the corpus directory does not exist or if the corpus item cannot be written. +pub fn write_item_to_fuzzing_corpus(target: &str, data: &[u8]) { + // This bakes in the assumption that we're executing in the root of the neqo workspace. + // Unfortunately, `cargo fuzz` doesn't provide a way to learn the location of the corpus + // directory. + let corpus = Path::new("../fuzz/corpus").join(target); + if !corpus.exists() { + std::fs::create_dir_all(&corpus).expect("failed to create corpus directory"); + } + + // Hash the data to get a unique name for the corpus item. + let mut hasher = DefaultHasher::new(); + data.hash(&mut hasher); + let item_name = hex::encode(hasher.finish().to_be_bytes()); + let item_path = corpus.join(item_name); + if item_path.exists() { + // Don't overwrite existing corpus items. + return; + } + + // Write the data to the corpus item. + let mut file = File::create(item_path).expect("failed to create corpus item"); + Write::write_all(&mut file, data).expect("failed to write to corpus item"); +} diff --git a/third_party/rust/neqo-common/src/lib.rs b/third_party/rust/neqo-common/src/lib.rs index e988c6071d..3a72425e44 100644 --- a/third_party/rust/neqo-common/src/lib.rs +++ b/third_party/rust/neqo-common/src/lib.rs @@ -9,6 +9,8 @@ mod codec; mod datagram; pub mod event; +#[cfg(feature = "build-fuzzing-corpus")] +mod fuzz; pub mod header; pub mod hrtime; mod incrdecoder; @@ -21,6 +23,8 @@ use std::fmt::Write; use enum_map::Enum; +#[cfg(feature = "build-fuzzing-corpus")] +pub use self::fuzz::write_item_to_fuzzing_corpus; pub use self::{ codec::{Decoder, Encoder}, datagram::Datagram, diff --git a/third_party/rust/neqo-common/src/tos.rs b/third_party/rust/neqo-common/src/tos.rs index 533c5447e2..c7e5228dee 100644 --- a/third_party/rust/neqo-common/src/tos.rs +++ b/third_party/rust/neqo-common/src/tos.rs @@ -52,6 +52,16 @@ impl From for IpTosEcn { } } +impl IpTosEcn { + #[must_use] + pub fn is_ecn_marked(&self) -> bool { + match self { + IpTosEcn::Ect0 | IpTosEcn::Ect1 | IpTosEcn::Ce => true, + IpTosEcn::NotEct => false, + } + } +} + /// Diffserv Codepoints, mapped to the upper six bits of the TOS field. /// #[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug)] @@ -228,6 +238,11 @@ impl IpTos { pub fn set_dscp(&mut self, dscp: IpTosDscp) { self.0 = u8::from(IpTosEcn::from(*self)) | u8::from(dscp); } + + #[must_use] + pub fn is_ecn_marked(&self) -> bool { + IpTosEcn::from(*self).is_ecn_marked() + } } #[cfg(test)] @@ -346,4 +361,16 @@ mod tests { iptos.set_dscp(IpTosDscp::Le); assert_eq!(u8::from(iptos), 0b0000_0101); } + + #[test] + fn iptos_is_ecn_marked() { + let iptos: IpTos = (IpTosDscp::Af41, IpTosEcn::Ce).into(); + assert!(iptos.is_ecn_marked()); + } + + #[test] + fn iptosecn_is_ecn_marked() { + assert!(IpTosEcn::Ce.is_ecn_marked()); + assert!(!IpTosEcn::NotEct.is_ecn_marked()); + } } diff --git a/third_party/rust/neqo-crypto/.cargo-checksum.json b/third_party/rust/neqo-crypto/.cargo-checksum.json index c3e603bd5a..1b9e9cee87 100644 --- a/third_party/rust/neqo-crypto/.cargo-checksum.json +++ b/third_party/rust/neqo-crypto/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e0ddb5aa433c742c87b94760fc995afb8091b8fa1360bf1ce66ed59d4e34a44d","bindings/bindings.toml":"29ec7a8ef3d5f1e4a632003e2d36c270e1caf12fd3fcf108a22d1893b90a41a6","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"cbf6a7d912314784c8c124cf7319c910a786d0e263f466843edd3f43826f036c","min_version.txt":"7e98f86c69cddb4f65cf96a6de1f4297e3ce224a4c4628609e29042b6c4dcfb9","src/aead.rs":"fc42bc20b84d2e5ccfd56271ae2d2db082e55586ea2926470c102da177f22296","src/aead_null.rs":"664f80bbb56d0abd3794b99cc927fd5f678ddb4ce95456001413ec18a6c6a6a9","src/agent.rs":"b12004faee4a136c10e8168848d397443b5927e9497edb62c72e6db3eb1c10a0","src/agentio.rs":"c4cb1b3cd92ef53eb0b4fb0b34a597068d82d78ba470dae5821670a0f06c9cda","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"8942cb3ce25a61f92b6ffc30fb286052ed6f56eeda3be12fd46ea76ceba6c1cf","src/constants.rs":"f22bf16bd8cb539862cb1e47138dbba79e93fe738f4b907e465891326f98883c","src/ech.rs":"9d322fcc01c0886f1dfe9bb6273cb9f88a746452ac9a802761b1816a05930c1f","src/err.rs":"ae979f334604aba89640c4491262641910033f0bd790d58671f649f5039b291c","src/exp.rs":"cec59d61fc95914f9703d2fb6490a8507af993c9db710dde894f2f8fd38123c7","src/ext.rs":"cbf7d9f5ecabf4b8c9efd6c334637ab1596ec5266d38ab8d2d6ceae305283deb","src/hkdf.rs":"ef32f20e30a9bd7f094199536d19c87c4231b7fbbe4a9c54c70e84ca9c6575be","src/hp.rs":"644f1bed67f1c6189a67c8d02ab3358aaa7f63af4b913dd7395becbc01a84291","src/lib.rs":"6b2d0eb2c55f6351d673d3a3e5fc5adac8d1030c67dae9af4c79552de0f57455","src/min_version.rs":"89b7ef6f9d2301db4f689f4d963b58375d577f705b92003a804048441e00cfd1","src/p11.rs":"e8c366def0df470101f3d120dcc4391f74f921fe59e2f3db2a56832e2852b855","src/prio.rs":"e5e169296c0ac69919c59fb6c1f8bd6bf079452eaa13d75da0edd41d435d3f6f","src/replay.rs":"96b7af8eff9e14313e79303092018b12e8834f780c96b8e247c497fdc680c696","src/result.rs":"0587cbb6aace71a7f9765ef7c01dcd9f73a49dcc6331e1d8fe4de2aef6ca65b6","src/secrets.rs":"4ffaa66f25df47dadf042063bff5953effa7bf2f4920cafe827757d6a659cb58","src/selfencrypt.rs":"b7cc1c896c7661c37461fc3a8bcbfdf2589433b907fa5f968ae4f6907704b441","src/ssl.rs":"c83baa5518b81dd06f2e4072ea3c2d666ccdeb8b1ff6e3746eea9f1af47023a6","src/time.rs":"c71a01ff8aa2c0e97fb16ad620df4ed6b7cc1819ff93f46634e2f1c9551627ec","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"824735f88e487a3748200844e9481e81a72163ad74d82faa9aa16594d9b9bb25","tests/ext.rs":"1b047d23d9b224ad06eb65d8f3a7b351e263774e404c79bbcbe8f43790e29c18","tests/handshake.rs":"e892a2839b31414be16e96cdf3b1a65978716094700c1a4989229f7edbf578a0","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"b24fec53771c169be788772532d2617a5349196cf87d6444dc74214f7c73e92c","tests/init.rs":"616313cb38eac44b8c71a1d23a52a7d7b4c7c07d4c20dc9ea6600c3317f92613","tests/selfencrypt.rs":"8d10840b41629bf449a6b3a551377315e8a05ca26c6b041548748196652c5909"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"c3bbe27a12dc333744b81b97fec121b1e016524ab22bd4cf553a43b7e7f4cd68","bindings/bindings.toml":"29ec7a8ef3d5f1e4a632003e2d36c270e1caf12fd3fcf108a22d1893b90a41a6","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"cbf6a7d912314784c8c124cf7319c910a786d0e263f466843edd3f43826f036c","min_version.txt":"7e98f86c69cddb4f65cf96a6de1f4297e3ce224a4c4628609e29042b6c4dcfb9","src/aead.rs":"fc42bc20b84d2e5ccfd56271ae2d2db082e55586ea2926470c102da177f22296","src/aead_null.rs":"3a553f21126c9ca0116c2be81e5a777011b33c159fd88c4f384614bbdb06bb2e","src/agent.rs":"b12004faee4a136c10e8168848d397443b5927e9497edb62c72e6db3eb1c10a0","src/agentio.rs":"415f70b95312d3ee6d74ba6f28094246101ab6d535aa9df880c38d8bb5a9279e","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"8942cb3ce25a61f92b6ffc30fb286052ed6f56eeda3be12fd46ea76ceba6c1cf","src/constants.rs":"f5c779db128a8b0607841ca18c376971017eb327e102e5e6959a7d8effe4b3a6","src/ech.rs":"9d322fcc01c0886f1dfe9bb6273cb9f88a746452ac9a802761b1816a05930c1f","src/err.rs":"ae979f334604aba89640c4491262641910033f0bd790d58671f649f5039b291c","src/exp.rs":"cec59d61fc95914f9703d2fb6490a8507af993c9db710dde894f2f8fd38123c7","src/ext.rs":"cbf7d9f5ecabf4b8c9efd6c334637ab1596ec5266d38ab8d2d6ceae305283deb","src/hkdf.rs":"ef32f20e30a9bd7f094199536d19c87c4231b7fbbe4a9c54c70e84ca9c6575be","src/hp.rs":"644f1bed67f1c6189a67c8d02ab3358aaa7f63af4b913dd7395becbc01a84291","src/lib.rs":"6b2d0eb2c55f6351d673d3a3e5fc5adac8d1030c67dae9af4c79552de0f57455","src/min_version.rs":"89b7ef6f9d2301db4f689f4d963b58375d577f705b92003a804048441e00cfd1","src/p11.rs":"704c5f164c4f195c8051c5bf1e69a912c34b613a8cf6bed5f577dc5674eea34e","src/prio.rs":"e5e169296c0ac69919c59fb6c1f8bd6bf079452eaa13d75da0edd41d435d3f6f","src/replay.rs":"96b7af8eff9e14313e79303092018b12e8834f780c96b8e247c497fdc680c696","src/result.rs":"0587cbb6aace71a7f9765ef7c01dcd9f73a49dcc6331e1d8fe4de2aef6ca65b6","src/secrets.rs":"4ffaa66f25df47dadf042063bff5953effa7bf2f4920cafe827757d6a659cb58","src/selfencrypt.rs":"b7cc1c896c7661c37461fc3a8bcbfdf2589433b907fa5f968ae4f6907704b441","src/ssl.rs":"c83baa5518b81dd06f2e4072ea3c2d666ccdeb8b1ff6e3746eea9f1af47023a6","src/time.rs":"c71a01ff8aa2c0e97fb16ad620df4ed6b7cc1819ff93f46634e2f1c9551627ec","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"824735f88e487a3748200844e9481e81a72163ad74d82faa9aa16594d9b9bb25","tests/ext.rs":"1b047d23d9b224ad06eb65d8f3a7b351e263774e404c79bbcbe8f43790e29c18","tests/handshake.rs":"e892a2839b31414be16e96cdf3b1a65978716094700c1a4989229f7edbf578a0","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"b24fec53771c169be788772532d2617a5349196cf87d6444dc74214f7c73e92c","tests/init.rs":"616313cb38eac44b8c71a1d23a52a7d7b4c7c07d4c20dc9ea6600c3317f92613","tests/selfencrypt.rs":"8d10840b41629bf449a6b3a551377315e8a05ca26c6b041548748196652c5909"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-crypto/Cargo.toml b/third_party/rust/neqo-crypto/Cargo.toml index 9507a066df..a0eaef87f5 100644 --- a/third_party/rust/neqo-crypto/Cargo.toml +++ b/third_party/rust/neqo-crypto/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.74.0" +rust-version = "1.76.0" name = "neqo-crypto" -version = "0.7.5" +version = "0.7.7" authors = ["The Neqo Authors "] build = "build.rs" homepage = "https://github.com/mozilla/neqo/" @@ -61,6 +61,7 @@ default-features = false [features] disable-encryption = [] +disable-random = [] gecko = ["mozbuild"] [lints.clippy.pedantic] diff --git a/third_party/rust/neqo-crypto/src/aead_null.rs b/third_party/rust/neqo-crypto/src/aead_null.rs index 2d5656de73..6fcb72871f 100644 --- a/third_party/rust/neqo-crypto/src/aead_null.rs +++ b/third_party/rust/neqo-crypto/src/aead_null.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg(feature = "disable-encryption")] - use std::fmt; use crate::{ diff --git a/third_party/rust/neqo-crypto/src/agentio.rs b/third_party/rust/neqo-crypto/src/agentio.rs index 7c57a0ef45..3beede5c12 100644 --- a/third_party/rust/neqo-crypto/src/agentio.rs +++ b/third_party/rust/neqo-crypto/src/agentio.rs @@ -29,7 +29,7 @@ const PR_FAILURE: PrStatus = prio::PRStatus::PR_FAILURE; /// Convert a pinned, boxed object into a void pointer. pub fn as_c_void(pin: &mut Pin>) -> *mut c_void { - (Pin::into_inner(pin.as_mut()) as *mut T).cast() + (std::ptr::from_mut::(Pin::into_inner(pin.as_mut()))).cast() } /// A slice of the output. diff --git a/third_party/rust/neqo-crypto/src/constants.rs b/third_party/rust/neqo-crypto/src/constants.rs index 76db972290..daef3d3c56 100644 --- a/third_party/rust/neqo-crypto/src/constants.rs +++ b/third_party/rust/neqo-crypto/src/constants.rs @@ -27,7 +27,7 @@ pub const TLS_EPOCH_APPLICATION_DATA: Epoch = 3_u16; macro_rules! remap_enum { { $t:ident: $s:ty { $( $n:ident = $v:path ),+ $(,)? } } => { pub type $t = $s; - $( pub const $n: $t = $v as $t; )+ + $(#[allow(clippy::cast_possible_truncation)] pub const $n: $t = $v as $t; )+ }; { $t:ident: $s:ty => $e:ident { $( $n:ident = $v:ident ),+ $(,)? } } => { remap_enum!{ $t: $s { $( $n = $e::$v ),+ } } diff --git a/third_party/rust/neqo-crypto/src/p11.rs b/third_party/rust/neqo-crypto/src/p11.rs index 5552882e2e..c235bb869c 100644 --- a/third_party/rust/neqo-crypto/src/p11.rs +++ b/third_party/rust/neqo-crypto/src/p11.rs @@ -13,7 +13,7 @@ use std::{ cell::RefCell, mem, ops::{Deref, DerefMut}, - os::raw::{c_int, c_uint}, + os::raw::c_uint, ptr::null_mut, }; @@ -290,14 +290,31 @@ impl Item { } } +#[cfg(feature = "disable-random")] +thread_local! { + static CURRENT_VALUE: std::cell::Cell = const { std::cell::Cell::new(0) }; +} + +#[cfg(feature = "disable-random")] +/// Fill a buffer with a predictable sequence of bytes. +pub fn randomize>(mut buf: B) -> B { + let m_buf = buf.as_mut(); + for v in m_buf.iter_mut() { + *v = CURRENT_VALUE.get(); + CURRENT_VALUE.set(v.wrapping_add(1)); + } + buf +} + /// Fill a buffer with randomness. /// /// # Panics /// /// When `size` is too large or NSS fails. +#[cfg(not(feature = "disable-random"))] pub fn randomize>(mut buf: B) -> B { let m_buf = buf.as_mut(); - let len = c_int::try_from(m_buf.len()).unwrap(); + let len = std::os::raw::c_int::try_from(m_buf.len()).unwrap(); secstatus_to_res(unsafe { PK11_GenerateRandom(m_buf.as_mut_ptr(), len) }).unwrap(); buf } @@ -359,10 +376,13 @@ mod test { use test_fixture::fixture_init; use super::RandomCache; - use crate::{random, randomize}; + use crate::random; + #[cfg(not(feature = "disable-random"))] #[test] fn randomness() { + use crate::randomize; + fixture_init(); // If any of these ever fail, there is either a bug, or it's time to buy a lottery ticket. assert_ne!(random::<16>(), randomize([0; 16])); diff --git a/third_party/rust/neqo-http3/.cargo-checksum.json b/third_party/rust/neqo-http3/.cargo-checksum.json index dff33cc964..f456e3f62d 100644 --- a/third_party/rust/neqo-http3/.cargo-checksum.json +++ b/third_party/rust/neqo-http3/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f3d4e7ace03bbc6ee36fb30540e0a96aebdf5222090cd95abdff14b840cfa68e","src/buffered_send_stream.rs":"f45bdf9ad2a04b3828c74ff5440681d3c9d1af39b55470e4f729842dc2412295","src/client_events.rs":"77fedca72ce54956eaba3fb7103085d196a631b764662584ea2629224c5c234e","src/conn_params.rs":"224a8ea6ef632930a7788a1cabf47ce69ad41bd4bc8dcf3053fbd998fdb38e82","src/connection.rs":"e9c869ec4c650162927543cfe608721fad037554c5101962b323496bf69e29a5","src/connection_client.rs":"2026e7b2c11f4d5a71b35eedaf14175d7d7cf96ce2bb64c4a97d6062cbb646c7","src/connection_server.rs":"de5a6cb42b8c4dc08fb1f626f681b45cd22435892b11e6053b61a5401490db94","src/control_stream_local.rs":"ae52e3286f1686ca1265e7de841392addd42616db02799bb967a59feb6039cb5","src/control_stream_remote.rs":"59eb4041e366d92f9f294e8446755caa5e91fd943bba7b79b726698ba13be248","src/features/extended_connect/mod.rs":"3b02f6b18627f3855465a81b1d9b285e6f13839e75a8a6db648ed9082908d7f0","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"4c85a90afb753ce588e3fdeb773669bc49c013aebc28912340359eb01b74fd70","src/features/extended_connect/tests/webtransport/mod.rs":"a30ea715f5271a826a739278b18e145964dedbce7026eed45f1b7d0355c407d5","src/features/extended_connect/tests/webtransport/negotiation.rs":"98254ef8446581ec520026b04ef9549645602181b61602c9936f6660141edf0b","src/features/extended_connect/tests/webtransport/sessions.rs":"de3d836f666c2bec31e70b33bdc2669572cabbe17df2225db7282613a224a364","src/features/extended_connect/tests/webtransport/streams.rs":"8b3c34cac1b2171252a4bb53d420ac2098549a20309c327bf56e2e9ba9e33538","src/features/extended_connect/webtransport_session.rs":"239d92c06fbc5f6226078bb411a803f57b555dea0077349d49d7f57671cf2eab","src/features/extended_connect/webtransport_streams.rs":"5d7507aaf6a819d266fbea9b7a415c8324329df0f6936d9045b73e17a5b844ee","src/features/mod.rs":"925aae4427ad82e4d019354802b223d53db5e5585d4a940f5417a24a9503d7ee","src/frames/hframe.rs":"56c36ac597504f28c73cf2370acd82104f8c7a7b9ffc0f6d222378abc524482d","src/frames/mod.rs":"7d0a46ca147336d14781edb8dbee8b03c2e4bcd6646f5473a9d93d31fe73fecb","src/frames/reader.rs":"e07ee9de74bc499c10afcda592fefd9a7eef3381c045aa14f6596d67313546ca","src/frames/tests/hframe.rs":"01ec74eb3eb25d95042aa0263f9267f89535e6b7b8c1161fab4ba9ee5352d4a7","src/frames/tests/mod.rs":"0610609b316767a6a022837d32ee0452e37ea296fde37e51bec87e7c77e923a3","src/frames/tests/reader.rs":"2bfadc7afbc41bff9f5f930b31550259a8a92484d35f6c5d8dd8fd9acfb88f5b","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"1d9d0256ace2ba7262343ed035df795f21a4d45065792d3fd45b3391b6916b2f","src/headers_checks.rs":"be0f0109298dcc3a40350b7c0950076ddfe20617d195b305e3ffc8582557ab18","src/lib.rs":"4f908a021222bcc79b9d569bc3759a493379a20b47dfa228fddf51600bf6e446","src/priority.rs":"f3b77c208962e44a4e2d13138c6998b703d40e7bcf8f73ea84d8ef5b556e0aee","src/push_controller.rs":"13bccf2834ae19109504cf695a5948c3b2d03fd101bc032a92bb77a033423854","src/qlog.rs":"2debd75c7ea103c95ff79e44412f1408c3e496e324976100c55d5a833912b6c3","src/qpack_decoder_receiver.rs":"c927dfc3e58c71d282210ba79280f6f03e789733bc3bedc247e68bab516b9e9e","src/qpack_encoder_receiver.rs":"d0ac03cc111b6e1c555a8654d3234116f2b135b5b040edac23cefe2d640beba9","src/recv_message.rs":"7ac8d4057ba53874e4edfc62cd25ad5d3f0b10aaac5bf6e156103c3bc44e18cc","src/request_target.rs":"6041a69a0a74969ec08bc164509c055e9bad99f53bbeb16c0aa17d108dd68b8c","src/send_message.rs":"374e168f60063b8102a2aff52c719ae2e1e5078527cf50d095b3e7217f6ec7d2","src/server.rs":"b9e6060da36cfb467478f5b78b17e22a123214ad2d64c919ce688ea2bc0e24bb","src/server_connection_events.rs":"12d353ca6301467f6d475dde3b789951a5716c89ddd7dbf1383efef8082361f3","src/server_events.rs":"1cda8d6c413fad0fa67fcfd7cb78e795bf7ef7f0e09b5720992646a82d51ce16","src/settings.rs":"476b154b5eea4c8d69a4a790fee3e527cef4d375df1cfb5eed04ec56406fe15a","src/stream_type_reader.rs":"7a7226b7911d69f7e00ec4987c2a32a5e8a33463203398cbee1e6645d2691478","tests/httpconn.rs":"bb6927801a8c75e4f05eb6cdb1e7f2d57be69b74e68ddad2a1614f2aeed04369","tests/priority.rs":"364754507873298612ad12e8d1d106d26d993712142d0be4cbf056da5338854c","tests/send_message.rs":"b5435045b16429d9e626ea94a8f10e2937e1a5a878af0035763a4f5ec09bf53c","tests/webtransport.rs":"25794305017ff58e57dc3c3b9b078e5bfc1814ea82a521b7b7156228e613c092"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"08e52a9eb3d14c9b985d5ab9e88f2bfec51bc9f13b6d62d84e143aece1f55654","src/buffered_send_stream.rs":"0e8ad3f443a33e213d55ba26a1ff266692c9087a1627c9b3d10c5025dee550ac","src/client_events.rs":"77fedca72ce54956eaba3fb7103085d196a631b764662584ea2629224c5c234e","src/conn_params.rs":"224a8ea6ef632930a7788a1cabf47ce69ad41bd4bc8dcf3053fbd998fdb38e82","src/connection.rs":"f5f49dd72170f7e42c180b738ff8bddae92fd0c71acc5a08736e298bf53483e7","src/connection_client.rs":"77cf08711b89e03c7cea47bf3cf02c76397485877121e42c321206cf7bef4ddc","src/connection_server.rs":"de5a6cb42b8c4dc08fb1f626f681b45cd22435892b11e6053b61a5401490db94","src/control_stream_local.rs":"ae52e3286f1686ca1265e7de841392addd42616db02799bb967a59feb6039cb5","src/control_stream_remote.rs":"59eb4041e366d92f9f294e8446755caa5e91fd943bba7b79b726698ba13be248","src/features/extended_connect/mod.rs":"3b02f6b18627f3855465a81b1d9b285e6f13839e75a8a6db648ed9082908d7f0","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"4c85a90afb753ce588e3fdeb773669bc49c013aebc28912340359eb01b74fd70","src/features/extended_connect/tests/webtransport/mod.rs":"a30ea715f5271a826a739278b18e145964dedbce7026eed45f1b7d0355c407d5","src/features/extended_connect/tests/webtransport/negotiation.rs":"a8940b99e21a6b29fef2fc32f3dce05d12de8b09079dfdc0502c13e4582dbdb6","src/features/extended_connect/tests/webtransport/sessions.rs":"de3d836f666c2bec31e70b33bdc2669572cabbe17df2225db7282613a224a364","src/features/extended_connect/tests/webtransport/streams.rs":"8b3c34cac1b2171252a4bb53d420ac2098549a20309c327bf56e2e9ba9e33538","src/features/extended_connect/webtransport_session.rs":"239d92c06fbc5f6226078bb411a803f57b555dea0077349d49d7f57671cf2eab","src/features/extended_connect/webtransport_streams.rs":"5d7507aaf6a819d266fbea9b7a415c8324329df0f6936d9045b73e17a5b844ee","src/features/mod.rs":"925aae4427ad82e4d019354802b223d53db5e5585d4a940f5417a24a9503d7ee","src/frames/hframe.rs":"56c36ac597504f28c73cf2370acd82104f8c7a7b9ffc0f6d222378abc524482d","src/frames/mod.rs":"7d0a46ca147336d14781edb8dbee8b03c2e4bcd6646f5473a9d93d31fe73fecb","src/frames/reader.rs":"e07ee9de74bc499c10afcda592fefd9a7eef3381c045aa14f6596d67313546ca","src/frames/tests/hframe.rs":"01ec74eb3eb25d95042aa0263f9267f89535e6b7b8c1161fab4ba9ee5352d4a7","src/frames/tests/mod.rs":"0610609b316767a6a022837d32ee0452e37ea296fde37e51bec87e7c77e923a3","src/frames/tests/reader.rs":"2bfadc7afbc41bff9f5f930b31550259a8a92484d35f6c5d8dd8fd9acfb88f5b","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"1d9d0256ace2ba7262343ed035df795f21a4d45065792d3fd45b3391b6916b2f","src/headers_checks.rs":"be0f0109298dcc3a40350b7c0950076ddfe20617d195b305e3ffc8582557ab18","src/lib.rs":"4f908a021222bcc79b9d569bc3759a493379a20b47dfa228fddf51600bf6e446","src/priority.rs":"f3b77c208962e44a4e2d13138c6998b703d40e7bcf8f73ea84d8ef5b556e0aee","src/push_controller.rs":"13bccf2834ae19109504cf695a5948c3b2d03fd101bc032a92bb77a033423854","src/qlog.rs":"2debd75c7ea103c95ff79e44412f1408c3e496e324976100c55d5a833912b6c3","src/qpack_decoder_receiver.rs":"c927dfc3e58c71d282210ba79280f6f03e789733bc3bedc247e68bab516b9e9e","src/qpack_encoder_receiver.rs":"d0ac03cc111b6e1c555a8654d3234116f2b135b5b040edac23cefe2d640beba9","src/recv_message.rs":"7ac8d4057ba53874e4edfc62cd25ad5d3f0b10aaac5bf6e156103c3bc44e18cc","src/request_target.rs":"6041a69a0a74969ec08bc164509c055e9bad99f53bbeb16c0aa17d108dd68b8c","src/send_message.rs":"bc1bb096e56560088db961ab0f7a4e08acd3d3977f483ffcbdcfeec7ed8d855a","src/server.rs":"24822b9b164271862777cf5afcc74edbecaa4ce648978b0a6559e1490e3cea55","src/server_connection_events.rs":"12d353ca6301467f6d475dde3b789951a5716c89ddd7dbf1383efef8082361f3","src/server_events.rs":"1cda8d6c413fad0fa67fcfd7cb78e795bf7ef7f0e09b5720992646a82d51ce16","src/settings.rs":"476b154b5eea4c8d69a4a790fee3e527cef4d375df1cfb5eed04ec56406fe15a","src/stream_type_reader.rs":"7a7226b7911d69f7e00ec4987c2a32a5e8a33463203398cbee1e6645d2691478","tests/httpconn.rs":"ee2f29c6104f5379bee2606f160005683f00ae85f2c43216e7ffaa89ff633466","tests/priority.rs":"364754507873298612ad12e8d1d106d26d993712142d0be4cbf056da5338854c","tests/send_message.rs":"b5435045b16429d9e626ea94a8f10e2937e1a5a878af0035763a4f5ec09bf53c","tests/webtransport.rs":"25794305017ff58e57dc3c3b9b078e5bfc1814ea82a521b7b7156228e613c092"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-http3/Cargo.toml b/third_party/rust/neqo-http3/Cargo.toml index c844ba43ef..6ab5f166f4 100644 --- a/third_party/rust/neqo-http3/Cargo.toml +++ b/third_party/rust/neqo-http3/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.74.0" +rust-version = "1.76.0" name = "neqo-http3" -version = "0.7.5" +version = "0.7.7" authors = ["The Neqo Authors "] homepage = "https://github.com/mozilla/neqo/" license = "MIT OR Apache-2.0" @@ -43,7 +43,7 @@ path = "./../neqo-qpack" path = "./../neqo-transport" [dependencies.qlog] -version = "0.12" +version = "0.13" default-features = false [dependencies.sfv] diff --git a/third_party/rust/neqo-http3/src/buffered_send_stream.rs b/third_party/rust/neqo-http3/src/buffered_send_stream.rs index 4f6761fa80..60da0512b5 100644 --- a/third_party/rust/neqo-http3/src/buffered_send_stream.rs +++ b/third_party/rust/neqo-http3/src/buffered_send_stream.rs @@ -7,7 +7,7 @@ use neqo_common::qtrace; use neqo_transport::{Connection, StreamId}; -use crate::Res; +use crate::{qlog, Res}; #[derive(Debug, PartialEq, Eq)] pub enum BufferedStream { @@ -38,7 +38,7 @@ impl BufferedStream { /// # Panics /// - /// If the `BufferedStream` is initialized more than one it will panic. + /// If the `BufferedStream` is initialized more than once, it will panic. pub fn init(&mut self, stream_id: StreamId) { debug_assert!(&Self::Uninitialized == self); *self = Self::Initialized { @@ -63,19 +63,23 @@ impl BufferedStream { /// Returns `neqo_transport` errors. pub fn send_buffer(&mut self, conn: &mut Connection) -> Res { let label = ::neqo_common::log_subject!(::log::Level::Debug, self); - let mut sent = 0; - if let Self::Initialized { stream_id, buf } = self { - if !buf.is_empty() { - qtrace!([label], "sending data."); - sent = conn.stream_send(*stream_id, &buf[..])?; - if sent == buf.len() { - buf.clear(); - } else { - let b = buf.split_off(sent); - *buf = b; - } - } + let Self::Initialized { stream_id, buf } = self else { + return Ok(0); + }; + if buf.is_empty() { + return Ok(0); + } + qtrace!([label], "sending data."); + let sent = conn.stream_send(*stream_id, &buf[..])?; + if sent == 0 { + return Ok(0); + } else if sent == buf.len() { + buf.clear(); + } else { + let b = buf.split_off(sent); + *buf = b; } + qlog::h3_data_moved_down(conn.qlog_mut(), *stream_id, sent); Ok(sent) } @@ -85,16 +89,17 @@ impl BufferedStream { pub fn send_atomic(&mut self, conn: &mut Connection, to_send: &[u8]) -> Res { // First try to send anything that is in the buffer. self.send_buffer(conn)?; - if let Self::Initialized { stream_id, buf } = self { - if buf.is_empty() { - let res = conn.stream_send_atomic(*stream_id, to_send)?; - Ok(res) - } else { - Ok(false) - } - } else { - Ok(false) + let Self::Initialized { stream_id, buf } = self else { + return Ok(false); + }; + if !buf.is_empty() { + return Ok(false); + } + let res = conn.stream_send_atomic(*stream_id, to_send)?; + if res { + qlog::h3_data_moved_down(conn.qlog_mut(), *stream_id, to_send.len()); } + Ok(res) } #[must_use] diff --git a/third_party/rust/neqo-http3/src/connection.rs b/third_party/rust/neqo-http3/src/connection.rs index dd45797baa..d14eb6f2a5 100644 --- a/third_party/rust/neqo-http3/src/connection.rs +++ b/third_party/rust/neqo-http3/src/connection.rs @@ -17,7 +17,7 @@ use std::{ use neqo_common::{qdebug, qerror, qinfo, qtrace, qwarn, Decoder, Header, MessageType, Role}; use neqo_qpack::{decoder::QPackDecoder, encoder::QPackEncoder}; use neqo_transport::{ - streams::SendOrder, AppError, Connection, ConnectionError, DatagramTracking, State, StreamId, + streams::SendOrder, AppError, CloseReason, Connection, DatagramTracking, State, StreamId, StreamType, ZeroRttState, }; @@ -81,22 +81,22 @@ enum Http3RemoteSettingsState { /// - `ZeroRtt`: 0-RTT has been enabled and is active /// - Connected /// - GoingAway(StreamId): The connection has received a `GOAWAY` frame -/// - Closing(ConnectionError): The connection is closed. The closing has been initiated by this end -/// of the connection, e.g., the `CONNECTION_CLOSE` frame has been sent. In this state, the +/// - Closing(CloseReason): The connection is closed. The closing has been initiated by this end of +/// the connection, e.g., the `CONNECTION_CLOSE` frame has been sent. In this state, the /// connection waits a certain amount of time to retransmit the `CONNECTION_CLOSE` frame if /// needed. -/// - Closed(ConnectionError): This is the final close state: closing has been initialized by the -/// peer and an ack for the `CONNECTION_CLOSE` frame has been sent or the closing has been -/// initiated by this end of the connection and the ack for the `CONNECTION_CLOSE` has been -/// received or the waiting time has passed. +/// - Closed(CloseReason): This is the final close state: closing has been initialized by the peer +/// and an ack for the `CONNECTION_CLOSE` frame has been sent or the closing has been initiated by +/// this end of the connection and the ack for the `CONNECTION_CLOSE` has been received or the +/// waiting time has passed. #[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone)] pub enum Http3State { Initializing, ZeroRtt, Connected, GoingAway(StreamId), - Closing(ConnectionError), - Closed(ConnectionError), + Closing(CloseReason), + Closed(CloseReason), } impl Http3State { @@ -767,7 +767,7 @@ impl Http3Connection { /// This is called when an application closes the connection. pub fn close(&mut self, error: AppError) { qdebug!([self], "Close connection error {:?}.", error); - self.state = Http3State::Closing(ConnectionError::Application(error)); + self.state = Http3State::Closing(CloseReason::Application(error)); if (!self.send_streams.is_empty() || !self.recv_streams.is_empty()) && (error == 0) { qwarn!("close(0) called when streams still active"); } diff --git a/third_party/rust/neqo-http3/src/connection_client.rs b/third_party/rust/neqo-http3/src/connection_client.rs index 4c8772d14a..18e513e743 100644 --- a/third_party/rust/neqo-http3/src/connection_client.rs +++ b/third_party/rust/neqo-http3/src/connection_client.rs @@ -1291,8 +1291,8 @@ mod tests { use neqo_crypto::{AllowZeroRtt, AntiReplay, ResumptionToken}; use neqo_qpack::{encoder::QPackEncoder, QpackSettings}; use neqo_transport::{ - ConnectionError, ConnectionEvent, ConnectionParameters, Output, State, StreamId, - StreamType, Version, RECV_BUFFER_SIZE, SEND_BUFFER_SIZE, + CloseReason, ConnectionEvent, ConnectionParameters, Output, State, StreamId, StreamType, + Version, RECV_BUFFER_SIZE, SEND_BUFFER_SIZE, }; use test_fixture::{ anti_replay, default_server_h3, fixture_init, new_server, now, @@ -1314,7 +1314,7 @@ mod tests { fn assert_closed(client: &Http3Client, expected: &Error) { match client.state() { Http3State::Closing(err) | Http3State::Closed(err) => { - assert_eq!(err, ConnectionError::Application(expected.code())); + assert_eq!(err, CloseReason::Application(expected.code())); } _ => panic!("Wrong state {:?}", client.state()), }; @@ -4419,7 +4419,7 @@ mod tests { HSetting::new(HSettingType::BlockedStreams, 100), HSetting::new(HSettingType::MaxHeaderListSize, 10000), ], - &Http3State::Closing(ConnectionError::Application(265)), + &Http3State::Closing(CloseReason::Application(265)), ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION, ); } @@ -4437,7 +4437,7 @@ mod tests { HSetting::new(HSettingType::MaxTableCapacity, 100), HSetting::new(HSettingType::MaxHeaderListSize, 10000), ], - &Http3State::Closing(ConnectionError::Application(265)), + &Http3State::Closing(CloseReason::Application(265)), ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION, ); } @@ -4474,7 +4474,7 @@ mod tests { HSetting::new(HSettingType::BlockedStreams, 100), HSetting::new(HSettingType::MaxHeaderListSize, 10000), ], - &Http3State::Closing(ConnectionError::Application(514)), + &Http3State::Closing(CloseReason::Application(514)), ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION, ); } @@ -4493,7 +4493,7 @@ mod tests { HSetting::new(HSettingType::BlockedStreams, 100), HSetting::new(HSettingType::MaxHeaderListSize, 10000), ], - &Http3State::Closing(ConnectionError::Application(265)), + &Http3State::Closing(CloseReason::Application(265)), ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION, ); } @@ -4531,7 +4531,7 @@ mod tests { HSetting::new(HSettingType::BlockedStreams, 50), HSetting::new(HSettingType::MaxHeaderListSize, 10000), ], - &Http3State::Closing(ConnectionError::Application(265)), + &Http3State::Closing(CloseReason::Application(265)), ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION, ); } @@ -4569,7 +4569,7 @@ mod tests { HSetting::new(HSettingType::BlockedStreams, 100), HSetting::new(HSettingType::MaxHeaderListSize, 5000), ], - &Http3State::Closing(ConnectionError::Application(265)), + &Http3State::Closing(CloseReason::Application(265)), ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION, ); } @@ -4626,7 +4626,7 @@ mod tests { HSetting::new(HSettingType::BlockedStreams, 100), HSetting::new(HSettingType::MaxHeaderListSize, 10000), ], - &Http3State::Closing(ConnectionError::Application(265)), + &Http3State::Closing(CloseReason::Application(265)), ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION, ); } diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs index 27f669861d..9b54f1dc46 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs @@ -8,7 +8,7 @@ use std::time::Duration; use neqo_common::{event::Provider, Encoder}; use neqo_crypto::AuthenticationStatus; -use neqo_transport::{Connection, ConnectionError, StreamType}; +use neqo_transport::{CloseReason, Connection, StreamType}; use test_fixture::{default_server_h3, now}; use super::{connect, default_http3_client, default_http3_server, exchange_packets}; @@ -270,10 +270,7 @@ fn wrong_setting_value() { exchange_packets2(&mut client, &mut server); match client.state() { Http3State::Closing(err) | Http3State::Closed(err) => { - assert_eq!( - err, - ConnectionError::Application(Error::HttpSettings.code()) - ); + assert_eq!(err, CloseReason::Application(Error::HttpSettings.code())); } _ => panic!("Wrong state {:?}", client.state()), }; diff --git a/third_party/rust/neqo-http3/src/send_message.rs b/third_party/rust/neqo-http3/src/send_message.rs index 15965c44f6..7fb37beb70 100644 --- a/third_party/rust/neqo-http3/src/send_message.rs +++ b/third_party/rust/neqo-http3/src/send_message.rs @@ -13,7 +13,7 @@ use neqo_transport::{Connection, StreamId}; use crate::{ frames::HFrame, headers_checks::{headers_valid, is_interim, trailers_valid}, - qlog, BufferedStream, CloseType, Error, Http3StreamInfo, Http3StreamType, HttpSendStream, Res, + BufferedStream, CloseType, Error, Http3StreamInfo, Http3StreamType, HttpSendStream, Res, SendStream, SendStreamEvents, Stream, }; @@ -216,7 +216,6 @@ impl SendStream for SendMessage { .send_atomic(conn, &buf[..to_send]) .map_err(|e| Error::map_stream_send_errors(&e))?; debug_assert!(sent); - qlog::h3_data_moved_down(conn.qlog_mut(), self.stream_id(), to_send); Ok(to_send) } @@ -243,7 +242,6 @@ impl SendStream for SendMessage { /// info that the stream has been closed.) fn send(&mut self, conn: &mut Connection) -> Res<()> { let sent = Error::map_error(self.stream.send_buffer(conn), Error::HttpInternal(5))?; - qlog::h3_data_moved_down(conn.qlog_mut(), self.stream_id(), sent); qtrace!([self], "{} bytes sent", sent); if !self.stream.has_buffered_data() { diff --git a/third_party/rust/neqo-http3/src/server.rs b/third_party/rust/neqo-http3/src/server.rs index 1396a4e4cf..8fce803fb3 100644 --- a/third_party/rust/neqo-http3/src/server.rs +++ b/third_party/rust/neqo-http3/src/server.rs @@ -323,7 +323,7 @@ mod tests { use neqo_crypto::{AuthenticationStatus, ZeroRttCheckResult, ZeroRttChecker}; use neqo_qpack::{encoder::QPackEncoder, QpackSettings}; use neqo_transport::{ - Connection, ConnectionError, ConnectionEvent, State, StreamId, StreamType, ZeroRttState, + CloseReason, Connection, ConnectionEvent, State, StreamId, StreamType, ZeroRttState, }; use test_fixture::{ anti_replay, default_client, fixture_init, now, CountingConnectionIdGenerator, @@ -366,7 +366,7 @@ mod tests { } fn assert_closed(hconn: &mut Http3Server, expected: &Error) { - let err = ConnectionError::Application(expected.code()); + let err = CloseReason::Application(expected.code()); let closed = |e| matches!(e, Http3ServerEvent::StateChange{ state: Http3State::Closing(e) | Http3State::Closed(e), .. } if e == err); assert!(hconn.events().any(closed)); } diff --git a/third_party/rust/neqo-http3/tests/httpconn.rs b/third_party/rust/neqo-http3/tests/httpconn.rs index a0b2bcdb80..c0c62de9c9 100644 --- a/third_party/rust/neqo-http3/tests/httpconn.rs +++ b/third_party/rust/neqo-http3/tests/httpconn.rs @@ -17,7 +17,7 @@ use neqo_http3::{ Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent, Http3State, Priority, }; -use neqo_transport::{ConnectionError, ConnectionParameters, Error, Output, StreamType}; +use neqo_transport::{CloseReason, ConnectionParameters, Error, Output, StreamType}; use test_fixture::*; const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63]; @@ -448,7 +448,7 @@ fn fetch_noresponse_will_idletimeout() { if let Http3ClientEvent::StateChange(state) = event { match state { Http3State::Closing(error_code) | Http3State::Closed(error_code) => { - assert_eq!(error_code, ConnectionError::Transport(Error::IdleTimeout)); + assert_eq!(error_code, CloseReason::Transport(Error::IdleTimeout)); done = true; } _ => {} diff --git a/third_party/rust/neqo-qpack/.cargo-checksum.json b/third_party/rust/neqo-qpack/.cargo-checksum.json index d717487018..d322bc4d81 100644 --- a/third_party/rust/neqo-qpack/.cargo-checksum.json +++ b/third_party/rust/neqo-qpack/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"b963363c6eb1b0b3318d5901d372599db89dff87131e0979b2eb09f42c84d72a","src/decoder.rs":"0675444129e074e9d5d56f0d45d2eaed614c85e22cfe9f2d28cdee912c15b420","src/decoder_instructions.rs":"d991d70e51f079bc5b30d3982fd0176edfa9bb7ba14c17a20ec3eea878c56206","src/encoder.rs":"84649cbee81e050f55d7ea691ac871e072741abd8bbf96303eb2e98aa8ee0aea","src/encoder_instructions.rs":"86e3abbd9cf94332041326ac6cf806ed64623e3fd38dbc0385b1f63c37e73fd9","src/header_block.rs":"3925476df69b90d950594faadc5cb24c374d46de8c75a374a235f0d27323a7d8","src/huffman.rs":"71ec740426eee0abb6205104e504f5b97f525a76c4a5f5827b78034d28ce1876","src/huffman_decode_helper.rs":"9ce470e318b3664f58aa109bed483ab15bfd9e0b17d261ea2b609668a42a9d80","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"fd673630b5ed64197851c9a9758685096d3c0aa04f4994290733a38057004ee6","src/prefix.rs":"fb4a9acbcf6fd3178f4474404cd3d3b131abca934f69fe14a9d744bc7e636dc5","src/qlog.rs":"e320007ea8309546b26f9c0019ab8722da80dbd38fa976233fd8ae19a0af637c","src/qpack_send_buf.rs":"755af90fe077b1bcca34a1a2a1bdce5ce601ea490b2ca3f1313e0107d13e67e2","src/reader.rs":"1581261741a0922b147a6975cc8b1a3503846f6dbfdb771d254760c298996982","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"ddf055a228bed575d640d9a06e19e1e9fd98a48e393a7d326f8254438fb94889"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"e0a99f1f9f0580d7166549bb90c603fbfc88babd675a84191fe6fb5124104d01","src/decoder.rs":"0675444129e074e9d5d56f0d45d2eaed614c85e22cfe9f2d28cdee912c15b420","src/decoder_instructions.rs":"d991d70e51f079bc5b30d3982fd0176edfa9bb7ba14c17a20ec3eea878c56206","src/encoder.rs":"84649cbee81e050f55d7ea691ac871e072741abd8bbf96303eb2e98aa8ee0aea","src/encoder_instructions.rs":"86e3abbd9cf94332041326ac6cf806ed64623e3fd38dbc0385b1f63c37e73fd9","src/header_block.rs":"3925476df69b90d950594faadc5cb24c374d46de8c75a374a235f0d27323a7d8","src/huffman.rs":"71ec740426eee0abb6205104e504f5b97f525a76c4a5f5827b78034d28ce1876","src/huffman_decode_helper.rs":"9ce470e318b3664f58aa109bed483ab15bfd9e0b17d261ea2b609668a42a9d80","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"fd673630b5ed64197851c9a9758685096d3c0aa04f4994290733a38057004ee6","src/prefix.rs":"fb4a9acbcf6fd3178f4474404cd3d3b131abca934f69fe14a9d744bc7e636dc5","src/qlog.rs":"e320007ea8309546b26f9c0019ab8722da80dbd38fa976233fd8ae19a0af637c","src/qpack_send_buf.rs":"755af90fe077b1bcca34a1a2a1bdce5ce601ea490b2ca3f1313e0107d13e67e2","src/reader.rs":"1581261741a0922b147a6975cc8b1a3503846f6dbfdb771d254760c298996982","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"ddf055a228bed575d640d9a06e19e1e9fd98a48e393a7d326f8254438fb94889"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-qpack/Cargo.toml b/third_party/rust/neqo-qpack/Cargo.toml index 822cddd9c0..0758437fa7 100644 --- a/third_party/rust/neqo-qpack/Cargo.toml +++ b/third_party/rust/neqo-qpack/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.74.0" +rust-version = "1.76.0" name = "neqo-qpack" -version = "0.7.5" +version = "0.7.7" authors = ["The Neqo Authors "] homepage = "https://github.com/mozilla/neqo/" license = "MIT OR Apache-2.0" @@ -36,7 +36,7 @@ path = "./../neqo-crypto" path = "./../neqo-transport" [dependencies.qlog] -version = "0.12" +version = "0.13" default-features = false [dependencies.static_assertions] diff --git a/third_party/rust/neqo-transport/.cargo-checksum.json b/third_party/rust/neqo-transport/.cargo-checksum.json index 3fc724515c..4d0f39c2b4 100644 --- a/third_party/rust/neqo-transport/.cargo-checksum.json +++ b/third_party/rust/neqo-transport/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"28025605522925d25700870cd043f2a169acad5193b2da09c7a296bd9f73d389","benches/range_tracker.rs":"590dd1f81c92e89ce28af1efdda583d85240438bd9c4c68767286d22a299ad4b","benches/rx_stream_orderer.rs":"53a008357703251a18100521a12d8fa9443c5601ddc3cbd1b3c2899074da4c4f","benches/transfer.rs":"94eb0ec1a0a7d0a4863ddc1c6d006521e52c1f2e7f03c69428b18f7eb827d33f","src/ackrate.rs":"4bb882e1069a0707dc85338b75327e2910c93ee5f36575767a0d58c4c41c9d4f","src/addr_valid.rs":"03c0b2ff85254179c5d425b12acfdcc6b1ea5735aeb0f604b9b3603451b3ef0a","src/cc/classic_cc.rs":"aaaf3670bfaacf10c2ab77b547b4aeec2618ec6b2bb2d921000a8b795f38ea87","src/cc/cubic.rs":"24c6913cc6346e5361007221c26e8096ece51583431fc3ab9c99e4ce4b0a9f5d","src/cc/mod.rs":"e0837937c9991b37edad15cd870ea9e0623489babfccc340074dd8322e1ef401","src/cc/new_reno.rs":"25d0921005688e0f0666efd0a4931b4f8cd44363587d98e5b6404818c5d05dd4","src/cc/tests/cubic.rs":"109fc8be5efba8959e777288c32ae8f2db581fc08719f318ad676e187f655478","src/cc/tests/mod.rs":"44f8df551e742ae1037cd1cdb85b2c1334c2e5ab3c23ed63d856dbc6b8743afc","src/cc/tests/new_reno.rs":"5414e26b6c928c5f82c5eeb42f04772b05be1ec2c8ee21c2b698ce8cb32829a1","src/cid.rs":"9686a3070c593cfca846d7549863728e31211b304b9fa876220f79bff5e24173","src/connection/dump.rs":"bd4fb55785fe42f5c94f7bcc14ccf4ae377d28b691fb55dbf1139ae9412b0ea9","src/connection/idle.rs":"b3bc2ad1290e54278d8703092d135eda973eb12316d1f6dffedaffdf25e2a47e","src/connection/mod.rs":"907ded3ba14ec8ef675e1ea55c5698d6ffe023de5e81a006746d9759eb243640","src/connection/params.rs":"38e0b47c8cc5fbe602e3174d7a70df410829bc240b42f21cebd10818e606ef7c","src/connection/saved.rs":"97eb19792be3c4d721057021a43ea50a52f89a3cfa583d3d3dcf5d9144b332f5","src/connection/state.rs":"c0c4b1c15624a8762eabc8d5fa76f169f3f93945a9ee86f30fbd7714f1ac1d37","src/connection/test_internal.rs":"f3ebfe97b25c9c716d41406066295e5aff4e96a3051ef4e2b5fb258282bbc14c","src/connection/tests/ackrate.rs":"4a2b835575850ae4a14209d3e51883ecb1e69afb44ef91b5e13a5e6cb7174fab","src/connection/tests/cc.rs":"d0d6ac038572ad3dcd9e6734596eaeedc6d3222d24e31b023aaab3540d195e46","src/connection/tests/close.rs":"20bf9b044ba52517693c2bd10820ff04a8c07de01d59c8c47b4e9478aa730211","src/connection/tests/datagram.rs":"f4c85099b6a8739fb99eadd8711b02066ad80fc8341a2e5e0dae2520378af9fe","src/connection/tests/handshake.rs":"c759737ee98c7b33b2327eb7d521f45c63aed15dc8f272b7bbcc510ee8e48877","src/connection/tests/idle.rs":"f3bcb12cd79cb8eabc969ce3fb0fab4eea26d6383b81a323c0e18ca9c42cfb59","src/connection/tests/keys.rs":"55558c057beb4221245beb262076de3991dca3f2661411db61c09d21194873df","src/connection/tests/migration.rs":"624985d925236be197eee52208dbdebe35c0df5bd9d30982d6f183dfda4cbab5","src/connection/tests/mod.rs":"280077d4e69faabd2fc1fe03f754096b8b83a8e2b2438fd05b3d7cd924154489","src/connection/tests/null.rs":"38f76a4ea15e6b11634d4374cb0f2a68bd250e5d35831edfce0fa48deeaa420d","src/connection/tests/priority.rs":"dd3504f52d3fce7a96441624bc1c82c733e6bb556b9b79d24d0f4fb4efaf5a9e","src/connection/tests/recovery.rs":"7f28767f3cca2ff60e3dcfa803e12ef043486a222f54681a8faf2ea2fee564a1","src/connection/tests/resumption.rs":"1a0de0993cd325224fc79a3c094d22636d5b122ab1123d16265d4fafb23574bd","src/connection/tests/stream.rs":"8e4af07d8033a951fc57f2afda570a08843b36931eca53ba3781a5992978afb2","src/connection/tests/vn.rs":"550eb6b4d39d5960aafc70037c25a1a0f5db1232ce0ec6080b2c29a731a9574e","src/connection/tests/zerortt.rs":"67f77721e33d9fa2691c5ea3ef4a90935987541d81f0f42fbcfca31e690b352a","src/crypto.rs":"416b73c06fcc2812cc252936bcb039fc13cf0b715e7e22a54314a3f72aee743c","src/events.rs":"6e115f309c5c46f30f6223e1347bea477ada457f8bb2189ecccc6d65483318d6","src/fc.rs":"ec9de1028286870c0adf88a92e1355acf13dede8b1e91179230df3263e3827a9","src/frame.rs":"5c8e5bc21e1052367f7db31523ee422efa4278ccdfc8cd581bb44a50ee205f16","src/lib.rs":"95810fd3ec1b7da9e42f4786e1360a6e40444d69c427065856e751fd1cf411bb","src/pace.rs":"86a674ac4d086148ea297214910458c3705918bd627b996ba8bbb12f2c4bf99e","src/packet/mod.rs":"e21e594c28c568c5d21bfa1dff2903ff3fe6f9dcb98c478eeca120c535d763ef","src/packet/retry.rs":"d5f999485f21b388a7383cd011fc6e96109c1a9fb5aef79b19017df6844271ff","src/path.rs":"610e6ce83da91b785d0690995591fa4da7b5a1add3d0022eea0be5050612cee9","src/qlog.rs":"f3d3661835a29e6023014f7a0996494fc8dc1f2d062154b94346a0c21bbf6fd1","src/quic_datagrams.rs":"3d33ecb9e6e80c77b812e8260fc807352300fb2305a29b797259ae34c52b67c5","src/recovery.rs":"1dadc6717dd133007943e762231a50680087392466904c2f2e6fface084e2ba9","src/recv_stream.rs":"f21ae0bb786901bb7d726a94cb3352607b0057128beaa331808137f2f57a330b","src/rtt.rs":"4635dc0c401b78a1fd9d34da6f9bf7f6e7f5be3a57ed9716e0efc8f0f94f1e47","src/send_stream.rs":"f717f64b75e368cf5fa4ca43078aa7c1b5aff48b4f6266713e6fa7dc458328aa","src/sender.rs":"5f760988bdd6fbbd5956877a97abe7c17370dd531f68b751a9e4e4459583f87b","src/server.rs":"048aaac84e15d49fd25850294759107fe1855bbbc0481c16f8bd888d8f2a8f6d","src/stats.rs":"257ab1242ea2e6bfac0900e6c4bdad794bc67b666930323d24e022e46b9be82b","src/stream_id.rs":"fd07cbb81709a54bdb0659f676ef851cd145c004b817044ede5b21e54fdb60e4","src/streams.rs":"062b1b61edd1a76a86914f2cc1ca007c03edd9136c0c3409d960ddb805805fc6","src/tparams.rs":"10d62ac64865e0606c3c14141f9674631c610b3f042e274e110bdcef5d388491","src/tracking.rs":"f9a9aa01abc79fdd7a2cfb2c3ae342b9ab709e6a2a11076ec5c475fc89c1f598","src/version.rs":"182484ed9ecc2e17cab73cc61914a86a2d206936cab313825ae76fd37eeade77","tests/common/mod.rs":"a6584d268da0157190f8f61842a655ffe81ee68702b3e6569ae300a169080eab","tests/conn_vectors.rs":"997702f4d8b8fa3b987b33077a0eb325e968b25b61fb4703532f8d97e1d4c98c","tests/connection.rs":"d1bc28294d70a5a484eb869162115e399862742caa791749fbd6b923b702b7cc","tests/network.rs":"9e30b8610124250262fceef27d09fdecf2d6e9c3a96b1e676ff4189b9e06d5ba","tests/retry.rs":"3225b64c0c0ca918df12d94df21f6023091e72606701c1dc8c060ce3c1e09c52","tests/server.rs":"cb83de909d858950bfd75a789fc23c3c44fcdf1d965b63800b2c7b498507987f"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"8082901bf0395c450584af1084608a1568f051acf376b369a82d402d11519acc","benches/range_tracker.rs":"590dd1f81c92e89ce28af1efdda583d85240438bd9c4c68767286d22a299ad4b","benches/rx_stream_orderer.rs":"53a008357703251a18100521a12d8fa9443c5601ddc3cbd1b3c2899074da4c4f","benches/transfer.rs":"94eb0ec1a0a7d0a4863ddc1c6d006521e52c1f2e7f03c69428b18f7eb827d33f","src/ackrate.rs":"4bb882e1069a0707dc85338b75327e2910c93ee5f36575767a0d58c4c41c9d4f","src/addr_valid.rs":"03c0b2ff85254179c5d425b12acfdcc6b1ea5735aeb0f604b9b3603451b3ef0a","src/cc/classic_cc.rs":"b8007d623b07772806b676b760bcc1ccd5a37ddcd6a99f5562da39a5b03777df","src/cc/cubic.rs":"24c6913cc6346e5361007221c26e8096ece51583431fc3ab9c99e4ce4b0a9f5d","src/cc/mod.rs":"f4febe164fcbdc5881a53850eafd4011650ed394b7ec3d0977ec4803a1ec8543","src/cc/new_reno.rs":"25d0921005688e0f0666efd0a4931b4f8cd44363587d98e5b6404818c5d05dd4","src/cc/tests/cubic.rs":"87c6b95572fe5eebc54c46411f76026984d3bdaa75e356a87a16a5cc4b8dd4e1","src/cc/tests/mod.rs":"44f8df551e742ae1037cd1cdb85b2c1334c2e5ab3c23ed63d856dbc6b8743afc","src/cc/tests/new_reno.rs":"c5c39855353e99041abceba62bab2e5b58b77b92847eda1ef6f48ae91c8e4aea","src/cid.rs":"9686a3070c593cfca846d7549863728e31211b304b9fa876220f79bff5e24173","src/connection/dump.rs":"bd4fb55785fe42f5c94f7bcc14ccf4ae377d28b691fb55dbf1139ae9412b0ea9","src/connection/idle.rs":"b3bc2ad1290e54278d8703092d135eda973eb12316d1f6dffedaffdf25e2a47e","src/connection/mod.rs":"33eee67314c5f8c6dcd1085c6e39b8f0f5d1b5538b2e4bd50083dcd523a980cf","src/connection/params.rs":"38e0b47c8cc5fbe602e3174d7a70df410829bc240b42f21cebd10818e606ef7c","src/connection/saved.rs":"97eb19792be3c4d721057021a43ea50a52f89a3cfa583d3d3dcf5d9144b332f5","src/connection/state.rs":"b1d4bdda3479e7957d1949a969281ecd8a3d88f4fbaff6dcf7ebbb576759339c","src/connection/test_internal.rs":"f3ebfe97b25c9c716d41406066295e5aff4e96a3051ef4e2b5fb258282bbc14c","src/connection/tests/ackrate.rs":"4a2b835575850ae4a14209d3e51883ecb1e69afb44ef91b5e13a5e6cb7174fab","src/connection/tests/cc.rs":"d9a0f00a8f439c4ea8d4b6fa689fbde8bd283256afdd68ec4a27f6638b729704","src/connection/tests/close.rs":"5f245fd134bc0759ef0c83a6d53e0a8d5a8e58dcdf203c750ec9121940272461","src/connection/tests/datagram.rs":"908cfa6881963841d54ea2deb812f8eb217d68f149b5058036d979db1181abf0","src/connection/tests/ecn.rs":"3ff05893154fb6a895fe4453db7cc54684ba3bdf268a36b69c36c4070768d7b4","src/connection/tests/handshake.rs":"67a6f090ed89ef6c63129f7e662dc1cfff3f291711a866dff3d779caa40e51c7","src/connection/tests/idle.rs":"f3bcb12cd79cb8eabc969ce3fb0fab4eea26d6383b81a323c0e18ca9c42cfb59","src/connection/tests/keys.rs":"7c58b255e9732711e13f2a3e1daa13ac9481d8c919a32ca62e70c850845a6b38","src/connection/tests/migration.rs":"40d4feba9957de7eef7391009996016af1a3052fabc7659680b64796cf9fb8bf","src/connection/tests/mod.rs":"43b7745e9722333f7bc851c70ccdfdd1dc4da3991a4b821fac677664719e760f","src/connection/tests/null.rs":"38f76a4ea15e6b11634d4374cb0f2a68bd250e5d35831edfce0fa48deeaa420d","src/connection/tests/priority.rs":"dd3504f52d3fce7a96441624bc1c82c733e6bb556b9b79d24d0f4fb4efaf5a9e","src/connection/tests/recovery.rs":"7f28767f3cca2ff60e3dcfa803e12ef043486a222f54681a8faf2ea2fee564a1","src/connection/tests/resumption.rs":"1a0de0993cd325224fc79a3c094d22636d5b122ab1123d16265d4fafb23574bd","src/connection/tests/stream.rs":"3a6b23be63e1901ea479749d8132db86959279329121fe5d51b34c3fef4d4d05","src/connection/tests/vn.rs":"5307221790560598a7f771acf504fb153c753e005aca7370b772186f0f0c8655","src/connection/tests/zerortt.rs":"67f77721e33d9fa2691c5ea3ef4a90935987541d81f0f42fbcfca31e690b352a","src/crypto.rs":"416b73c06fcc2812cc252936bcb039fc13cf0b715e7e22a54314a3f72aee743c","src/ecn.rs":"3e9c9151dced7a1ec31e6a6d1bc5b0e4ce37cbb5cc361f5801be477c34249740","src/events.rs":"3cdd7d5496b2745626db4ceb863b5a91ae943090a43a5816a1f9bcf873fba2be","src/fc.rs":"ec9de1028286870c0adf88a92e1355acf13dede8b1e91179230df3263e3827a9","src/frame.rs":"4262717662f155e62bb29c9f0cac295bbae96076eb2d92c27052a35f979aa196","src/lib.rs":"6ed3732a020d0c9550ed295e660059b2747cbc647c24cc654cdde9de6f589a8f","src/pace.rs":"86a674ac4d086148ea297214910458c3705918bd627b996ba8bbb12f2c4bf99e","src/packet/mod.rs":"121a6dbfc3b3a9b6b5ebc94442d2d20a3148fc588dc1a1c4f9eb6c213741dca1","src/packet/retry.rs":"d5f999485f21b388a7383cd011fc6e96109c1a9fb5aef79b19017df6844271ff","src/path.rs":"8214a1683155bd0a82b53cc6bd957147286f6d4df527b5f3f640c266130122c0","src/qlog.rs":"c8ab11eca4712eba42cf26e17d07e88555e3976519a91f2d82d93afb1b420fc9","src/quic_datagrams.rs":"3d33ecb9e6e80c77b812e8260fc807352300fb2305a29b797259ae34c52b67c5","src/recovery.rs":"ad45dc9c94d716d9703601db40adc3eb4d353d5a173429d826829a2c50e52d9c","src/recv_stream.rs":"f21ae0bb786901bb7d726a94cb3352607b0057128beaa331808137f2f57a330b","src/rtt.rs":"4635dc0c401b78a1fd9d34da6f9bf7f6e7f5be3a57ed9716e0efc8f0f94f1e47","src/send_stream.rs":"ae0b6aa87649c1afee39b0e0a73bb713752f95f83199132f939e7f48ec2bbc7f","src/sender.rs":"ccde9e9a544670f403b82108ad04b5fecf8a00c1c3e26432ce0e23b2fa30436e","src/server.rs":"00b3e8d5ded84520bf30aadcb379332ad6ee2a0268a23a2893857a6c88673fd1","src/stats.rs":"257ab1242ea2e6bfac0900e6c4bdad794bc67b666930323d24e022e46b9be82b","src/stream_id.rs":"fd07cbb81709a54bdb0659f676ef851cd145c004b817044ede5b21e54fdb60e4","src/streams.rs":"062b1b61edd1a76a86914f2cc1ca007c03edd9136c0c3409d960ddb805805fc6","src/tparams.rs":"10d62ac64865e0606c3c14141f9674631c610b3f042e274e110bdcef5d388491","src/tracking.rs":"307e8cd007619e28000ce229df63ef73cfa07afb602e5399331c4624f787ad0c","src/version.rs":"182484ed9ecc2e17cab73cc61914a86a2d206936cab313825ae76fd37eeade77","tests/common/mod.rs":"7f9437d5efc38f4b9cabfece575e9168580e78e8638f46e538de58607f46ebb8","tests/conn_vectors.rs":"997702f4d8b8fa3b987b33077a0eb325e968b25b61fb4703532f8d97e1d4c98c","tests/connection.rs":"4c4d5adcde2413c105acc76567037fbeb1fe433e95e0aadf36d95e604541cb9b","tests/network.rs":"04921aa5af583e842e6d2176a898fbfea747e831bbe292b5ef8441eaf546b93a","tests/retry.rs":"a4250be3b104c754d6334784c3a6a258dd8b218645688fe3a61267ca7b773835","tests/server.rs":"e9eda467b0cb68e213f2b9ab124a35e05042f06d1aa3783deb1de1d8d1e1d7e7"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-transport/Cargo.toml b/third_party/rust/neqo-transport/Cargo.toml index 9abdf9b984..78e551072e 100644 --- a/third_party/rust/neqo-transport/Cargo.toml +++ b/third_party/rust/neqo-transport/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.74.0" +rust-version = "1.76.0" name = "neqo-transport" -version = "0.7.5" +version = "0.7.7" authors = ["The Neqo Authors "] homepage = "https://github.com/mozilla/neqo/" license = "MIT OR Apache-2.0" @@ -37,8 +37,12 @@ name = "range_tracker" harness = false required-features = ["bench"] +[dependencies.enum-map] +version = "2.7" +default-features = false + [dependencies.indexmap] -version = "1.9" +version = "2.2" default-features = false [dependencies.log] @@ -52,7 +56,7 @@ path = "../neqo-common" path = "../neqo-crypto" [dependencies.qlog] -version = "0.12" +version = "0.13" default-features = false [dependencies.smallvec] @@ -64,15 +68,17 @@ version = "0.5" features = ["html_reports"] default-features = false -[dev-dependencies.enum-map] -version = "2.7" -default-features = false - [dev-dependencies.test-fixture] path = "../test-fixture" [features] bench = [] +build-fuzzing-corpus = [ + "neqo-common/build-fuzzing-corpus", + "neqo-crypto/disable-encryption", + "neqo-crypto/disable-random", + "test-fixture/disable-random", +] disable-encryption = ["neqo-crypto/disable-encryption"] [lints.clippy.pedantic] diff --git a/third_party/rust/neqo-transport/src/cc/classic_cc.rs b/third_party/rust/neqo-transport/src/cc/classic_cc.rs index f8bcee6722..6914e91f67 100644 --- a/third_party/rust/neqo-transport/src/cc/classic_cc.rs +++ b/third_party/rust/neqo-transport/src/cc/classic_cc.rs @@ -298,6 +298,14 @@ impl CongestionControl for ClassicCongestionControl { congestion || persistent_congestion } + /// Report received ECN CE mark(s) to the congestion controller as a + /// congestion event. + /// + /// See . + fn on_ecn_ce_received(&mut self, largest_acked_pkt: &SentPacket) -> bool { + self.on_congestion_event(largest_acked_pkt) + } + fn discard(&mut self, pkt: &SentPacket) { if pkt.cc_outstanding() { assert!(self.bytes_in_flight >= pkt.size); @@ -488,8 +496,8 @@ impl ClassicCongestionControl { /// Handle a congestion event. /// Returns true if this was a true congestion event. fn on_congestion_event(&mut self, last_packet: &SentPacket) -> bool { - // Start a new congestion event if lost packet was sent after the start - // of the previous congestion recovery period. + // Start a new congestion event if lost or ECN CE marked packet was sent + // after the start of the previous congestion recovery period. if !self.after_recovery_start(last_packet) { return false; } @@ -538,7 +546,7 @@ impl ClassicCongestionControl { mod tests { use std::time::{Duration, Instant}; - use neqo_common::qinfo; + use neqo_common::{qinfo, IpTosEcn}; use test_fixture::now; use super::{ @@ -582,6 +590,7 @@ mod tests { SentPacket::new( PacketType::Short, pn, + IpTosEcn::default(), now() + t, ack_eliciting, Vec::new(), @@ -795,6 +804,7 @@ mod tests { SentPacket::new( PacketType::Short, u64::try_from(i).unwrap(), + IpTosEcn::default(), by_pto(t), true, Vec::new(), @@ -915,6 +925,7 @@ mod tests { lost[0] = SentPacket::new( lost[0].pt, lost[0].pn, + lost[0].ecn_mark, lost[0].time_sent, false, Vec::new(), @@ -1015,11 +1026,12 @@ mod tests { for _ in 0..packet_burst_size { let p = SentPacket::new( PacketType::Short, - next_pn, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + next_pn, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); next_pn += 1; cc.on_packet_sent(&p); @@ -1039,11 +1051,12 @@ mod tests { for _ in 0..ABOVE_APP_LIMIT_PKTS { let p = SentPacket::new( PacketType::Short, - next_pn, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + next_pn, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); next_pn += 1; cc.on_packet_sent(&p); @@ -1082,11 +1095,12 @@ mod tests { let p_lost = SentPacket::new( PacketType::Short, - 1, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + 1, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); cc.on_packet_sent(&p_lost); cwnd_is_default(&cc); @@ -1095,11 +1109,12 @@ mod tests { cwnd_is_halved(&cc); let p_not_lost = SentPacket::new( PacketType::Short, - 2, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + 2, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); cc.on_packet_sent(&p_not_lost); now += RTT; @@ -1118,11 +1133,12 @@ mod tests { for _ in 0..packet_burst_size { let p = SentPacket::new( PacketType::Short, - next_pn, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + next_pn, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); next_pn += 1; cc.on_packet_sent(&p); @@ -1148,11 +1164,12 @@ mod tests { for _ in 0..ABOVE_APP_LIMIT_PKTS { let p = SentPacket::new( PacketType::Short, - next_pn, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + next_pn, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); next_pn += 1; cc.on_packet_sent(&p); @@ -1180,4 +1197,26 @@ mod tests { last_acked_bytes = cc.acked_bytes; } } + + #[test] + fn ecn_ce() { + let mut cc = ClassicCongestionControl::new(NewReno::default()); + let p_ce = SentPacket::new( + PacketType::Short, + 1, + IpTosEcn::default(), + now(), + true, + Vec::new(), + MAX_DATAGRAM_SIZE, + ); + cc.on_packet_sent(&p_ce); + cwnd_is_default(&cc); + assert_eq!(cc.state, State::SlowStart); + + // Signal congestion (ECN CE) and thus change state to recovery start. + cc.on_ecn_ce_received(&p_ce); + cwnd_is_halved(&cc); + assert_eq!(cc.state, State::RecoveryStart); + } } diff --git a/third_party/rust/neqo-transport/src/cc/mod.rs b/third_party/rust/neqo-transport/src/cc/mod.rs index 486d15e67e..2adffbc0c4 100644 --- a/third_party/rust/neqo-transport/src/cc/mod.rs +++ b/third_party/rust/neqo-transport/src/cc/mod.rs @@ -53,6 +53,9 @@ pub trait CongestionControl: Display + Debug { lost_packets: &[SentPacket], ) -> bool; + /// Returns true if the congestion window was reduced. + fn on_ecn_ce_received(&mut self, largest_acked_pkt: &SentPacket) -> bool; + #[must_use] fn recovery_packet(&self) -> bool; diff --git a/third_party/rust/neqo-transport/src/cc/tests/cubic.rs b/third_party/rust/neqo-transport/src/cc/tests/cubic.rs index 2e0200fd6d..8ff591cb47 100644 --- a/third_party/rust/neqo-transport/src/cc/tests/cubic.rs +++ b/third_party/rust/neqo-transport/src/cc/tests/cubic.rs @@ -12,6 +12,7 @@ use std::{ time::{Duration, Instant}, }; +use neqo_common::IpTosEcn; use test_fixture::now; use crate::{ @@ -41,11 +42,12 @@ fn fill_cwnd(cc: &mut ClassicCongestionControl, mut next_pn: u64, now: In while cc.bytes_in_flight() < cc.cwnd() { let sent = SentPacket::new( PacketType::Short, - next_pn, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + next_pn, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); cc.on_packet_sent(&sent); next_pn += 1; @@ -56,11 +58,12 @@ fn fill_cwnd(cc: &mut ClassicCongestionControl, mut next_pn: u64, now: In fn ack_packet(cc: &mut ClassicCongestionControl, pn: u64, now: Instant) { let acked = SentPacket::new( PacketType::Short, - pn, // pn - now, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + pn, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); cc.on_packets_acked(&[acked], &RTT_ESTIMATE, now); } @@ -69,11 +72,12 @@ fn packet_lost(cc: &mut ClassicCongestionControl, pn: u64) { const PTO: Duration = Duration::from_millis(120); let p_lost = SentPacket::new( PacketType::Short, - pn, // pn - now(), // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + pn, + IpTosEcn::default(), + now(), + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); cc.on_packets_lost(None, None, PTO, &[p_lost]); } diff --git a/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs b/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs index 4cc20de5a7..0cc560bf2b 100644 --- a/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs +++ b/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs @@ -8,6 +8,7 @@ use std::time::Duration; +use neqo_common::IpTosEcn; use test_fixture::now; use crate::{ @@ -44,59 +45,66 @@ fn issue_876() { let sent_packets = &[ SentPacket::new( PacketType::Short, - 1, // pn - time_before, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE - 1, // size + 1, + IpTosEcn::default(), + time_before, + true, + Vec::new(), + MAX_DATAGRAM_SIZE - 1, ), SentPacket::new( PacketType::Short, - 2, // pn - time_before, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE - 2, // size + 2, + IpTosEcn::default(), + time_before, + true, + Vec::new(), + MAX_DATAGRAM_SIZE - 2, ), SentPacket::new( PacketType::Short, - 3, // pn - time_before, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + 3, + IpTosEcn::default(), + time_before, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ), SentPacket::new( PacketType::Short, - 4, // pn - time_before, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + 4, + IpTosEcn::default(), + time_before, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ), SentPacket::new( PacketType::Short, - 5, // pn - time_before, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + 5, + IpTosEcn::default(), + time_before, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ), SentPacket::new( PacketType::Short, - 6, // pn - time_before, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + 6, + IpTosEcn::default(), + time_before, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ), SentPacket::new( PacketType::Short, - 7, // pn - time_after, // time sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE - 3, // size + 7, + IpTosEcn::default(), + time_after, + true, + Vec::new(), + MAX_DATAGRAM_SIZE - 3, ), ]; @@ -146,11 +154,12 @@ fn issue_1465() { let mut next_packet = |now| { let p = SentPacket::new( PacketType::Short, - pn, // pn - now, // time_sent - true, // ack eliciting - Vec::new(), // tokens - MAX_DATAGRAM_SIZE, // size + pn, + IpTosEcn::default(), + now, + true, + Vec::new(), + MAX_DATAGRAM_SIZE, ); pn += 1; p diff --git a/third_party/rust/neqo-transport/src/connection/mod.rs b/third_party/rust/neqo-transport/src/connection/mod.rs index 8522507a69..f955381414 100644 --- a/third_party/rust/neqo-transport/src/connection/mod.rs +++ b/third_party/rust/neqo-transport/src/connection/mod.rs @@ -19,7 +19,7 @@ use std::{ use neqo_common::{ event::Provider as EventProvider, hex, hex_snip_middle, hrtime, qdebug, qerror, qinfo, - qlog::NeqoQlog, qtrace, qwarn, Datagram, Decoder, Encoder, IpTos, Role, + qlog::NeqoQlog, qtrace, qwarn, Datagram, Decoder, Encoder, Role, }; use neqo_crypto::{ agent::CertificateInfo, Agent, AntiReplay, AuthenticationStatus, Cipher, Client, Group, @@ -35,6 +35,7 @@ use crate::{ ConnectionIdRef, ConnectionIdStore, LOCAL_ACTIVE_CID_LIMIT, }, crypto::{Crypto, CryptoDxState, CryptoSpace}, + ecn::EcnCount, events::{ConnectionEvent, ConnectionEvents, OutgoingDatagramOutcome}, frame::{ CloseError, Frame, FrameType, FRAME_TYPE_CONNECTION_CLOSE_APPLICATION, @@ -46,7 +47,7 @@ use crate::{ quic_datagrams::{DatagramTracking, QuicDatagrams}, recovery::{LossRecovery, RecoveryToken, SendProfile}, recv_stream::RecvStreamStats, - rtt::GRANULARITY, + rtt::{RttEstimate, GRANULARITY}, send_stream::SendStream, stats::{Stats, StatsCell}, stream_id::StreamType, @@ -55,9 +56,9 @@ use crate::{ self, TransportParameter, TransportParameterId, TransportParameters, TransportParametersHandler, }, - tracking::{AckTracker, PacketNumberSpace, SentPacket}, + tracking::{AckTracker, PacketNumberSpace, RecvdPackets, SentPacket}, version::{Version, WireVersion}, - AppError, ConnectionError, Error, Res, StreamId, + AppError, CloseReason, Error, Res, StreamId, }; mod dump; @@ -291,7 +292,7 @@ impl Debug for Connection { "{:?} Connection: {:?} {:?}", self.role, self.state, - self.paths.primary_fallible() + self.paths.primary() ) } } @@ -591,7 +592,11 @@ impl Connection { fn make_resumption_token(&mut self) -> ResumptionToken { debug_assert_eq!(self.role, Role::Client); debug_assert!(self.crypto.has_resumption_token()); - let rtt = self.paths.primary().borrow().rtt().estimate(); + let rtt = self.paths.primary().map_or_else( + || RttEstimate::default().estimate(), + |p| p.borrow().rtt().estimate(), + ); + self.crypto .create_resumption_token( self.new_token.take_token(), @@ -610,11 +615,10 @@ impl Connection { /// a value of this approximate order. Don't use this for loss recovery, /// only use it where a more precise value is not important. fn pto(&self) -> Duration { - self.paths - .primary() - .borrow() - .rtt() - .pto(PacketNumberSpace::ApplicationData) + self.paths.primary().map_or_else( + || RttEstimate::default().pto(PacketNumberSpace::ApplicationData), + |p| p.borrow().rtt().pto(PacketNumberSpace::ApplicationData), + ) } fn create_resumption_token(&mut self, now: Instant) { @@ -746,7 +750,12 @@ impl Connection { if !init_token.is_empty() { self.address_validation = AddressValidationInfo::NewToken(init_token.to_vec()); } - self.paths.primary().borrow_mut().rtt_mut().set_initial(rtt); + self.paths + .primary() + .ok_or(Error::InternalError)? + .borrow_mut() + .rtt_mut() + .set_initial(rtt); self.set_initial_limits(); // Start up TLS, which has the effect of setting up all the necessary // state for 0-RTT. This only stages the CRYPTO frames. @@ -786,7 +795,7 @@ impl Connection { // If we are able, also send a NEW_TOKEN frame. // This should be recording all remote addresses that are valid, // but there are just 0 or 1 in the current implementation. - if let Some(path) = self.paths.primary_fallible() { + if let Some(path) = self.paths.primary() { if let Some(token) = self .address_validation .generate_new_token(path.borrow().remote_address(), now) @@ -858,7 +867,7 @@ impl Connection { #[must_use] pub fn stats(&self) -> Stats { let mut v = self.stats.borrow().clone(); - if let Some(p) = self.paths.primary_fallible() { + if let Some(p) = self.paths.primary() { let p = p.borrow(); v.rtt = p.rtt().estimate(); v.rttvar = p.rtt().rttvar(); @@ -880,7 +889,7 @@ impl Connection { let msg = format!("{v:?}"); #[cfg(not(debug_assertions))] let msg = ""; - let error = ConnectionError::Transport(v.clone()); + let error = CloseReason::Transport(v.clone()); match &self.state { State::Closing { error: err, .. } | State::Draining { error: err, .. } @@ -895,14 +904,14 @@ impl Connection { State::WaitInitial => { // We don't have any state yet, so don't bother with // the closing state, just send one CONNECTION_CLOSE. - if let Some(path) = path.or_else(|| self.paths.primary_fallible()) { + if let Some(path) = path.or_else(|| self.paths.primary()) { self.state_signaling .close(path, error.clone(), frame_type, msg); } self.set_state(State::Closed(error)); } _ => { - if let Some(path) = path.or_else(|| self.paths.primary_fallible()) { + if let Some(path) = path.or_else(|| self.paths.primary()) { self.state_signaling .close(path, error.clone(), frame_type, msg); if matches!(v, Error::KeysExhausted) { @@ -951,9 +960,7 @@ impl Connection { let pto = self.pto(); if self.idle_timeout.expired(now, pto) { qinfo!([self], "idle timeout expired"); - self.set_state(State::Closed(ConnectionError::Transport( - Error::IdleTimeout, - ))); + self.set_state(State::Closed(CloseReason::Transport(Error::IdleTimeout))); return; } @@ -962,9 +969,11 @@ impl Connection { let res = self.crypto.states.check_key_update(now); self.absorb_error(now, res); - let lost = self.loss_recovery.timeout(&self.paths.primary(), now); - self.handle_lost_packets(&lost); - qlog::packets_lost(&mut self.qlog, &lost); + if let Some(path) = self.paths.primary() { + let lost = self.loss_recovery.timeout(&path, now); + self.handle_lost_packets(&lost); + qlog::packets_lost(&mut self.qlog, &lost); + } if self.release_resumption_token_timer.is_some() { self.create_resumption_token(now); @@ -1014,7 +1023,7 @@ impl Connection { delays.push(ack_time); } - if let Some(p) = self.paths.primary_fallible() { + if let Some(p) = self.paths.primary() { let path = p.borrow(); let rtt = path.rtt(); let pto = rtt.pto(PacketNumberSpace::ApplicationData); @@ -1102,7 +1111,15 @@ impl Connection { self.input(d, now, now); self.process_saved(now); } - self.process_output(now) + #[allow(clippy::let_and_return)] + let output = self.process_output(now); + #[cfg(all(feature = "build-fuzzing-corpus", test))] + if self.test_frame_writer.is_none() { + if let Some(d) = output.clone().dgram() { + neqo_common::write_item_to_fuzzing_corpus("packet", &d); + } + } + output } fn handle_retry(&mut self, packet: &PublicPacket, now: Instant) { @@ -1123,7 +1140,13 @@ impl Connection { } // At this point, we should only have the connection ID that we generated. // Update to the one that the server prefers. - let path = self.paths.primary(); + let Some(path) = self.paths.primary() else { + self.stats + .borrow_mut() + .pkt_dropped("Retry without an existing path"); + return; + }; + path.borrow_mut().set_remote_cid(packet.scid()); let retry_scid = ConnectionId::from(packet.scid()); @@ -1151,8 +1174,9 @@ impl Connection { fn discard_keys(&mut self, space: PacketNumberSpace, now: Instant) { if self.crypto.discard(space) { qdebug!([self], "Drop packet number space {}", space); - let primary = self.paths.primary(); - self.loss_recovery.discard(&primary, space, now); + if let Some(path) = self.paths.primary() { + self.loss_recovery.discard(&path, space, now); + } self.acks.drop_space(space); } } @@ -1180,7 +1204,7 @@ impl Connection { qdebug!([self], "Stateless reset: {}", hex(&d[d.len() - 16..])); self.state_signaling.reset(); self.set_state(State::Draining { - error: ConnectionError::Transport(Error::StatelessReset), + error: CloseReason::Transport(Error::StatelessReset), timeout: self.get_closing_period_time(now), }); Err(Error::StatelessReset) @@ -1227,8 +1251,9 @@ impl Connection { assert_ne!(self.version, version); qinfo!([self], "Version negotiation: trying {:?}", version); - let local_addr = self.paths.primary().borrow().local_address(); - let remote_addr = self.paths.primary().borrow().remote_address(); + let path = self.paths.primary().ok_or(Error::NoAvailablePath)?; + let local_addr = path.borrow().local_address(); + let remote_addr = path.borrow().remote_address(); let conn_params = self .conn_params .clone() @@ -1256,7 +1281,7 @@ impl Connection { } else { qinfo!([self], "Version negotiation: failed with {:?}", supported); // This error goes straight to closed. - self.set_state(State::Closed(ConnectionError::Transport( + self.set_state(State::Closed(CloseReason::Transport( Error::VersionNegotiation, ))); Err(Error::VersionNegotiation) @@ -1417,6 +1442,13 @@ impl Connection { migrate: bool, now: Instant, ) { + let space = PacketNumberSpace::from(packet.packet_type()); + if let Some(space) = self.acks.get_mut(space) { + *space.ecn_marks() += d.tos().into(); + } else { + qtrace!("Not tracking ECN for dropped packet number space"); + } + if self.state == State::WaitInitial { self.start_handshake(path, packet, now); } @@ -1491,6 +1523,16 @@ impl Connection { d.tos(), ); + #[cfg(feature = "build-fuzzing-corpus")] + if packet.packet_type() == PacketType::Initial { + let target = if self.role == Role::Client { + "server_initial" + } else { + "client_initial" + }; + neqo_common::write_item_to_fuzzing_corpus(target, &payload[..]); + } + qlog::packet_received(&mut self.qlog, &packet, &payload); let space = PacketNumberSpace::from(payload.packet_type()); if self.acks.get_mut(space).unwrap().is_duplicate(payload.pn()) { @@ -1562,7 +1604,11 @@ impl Connection { let mut probing = true; let mut d = Decoder::from(&packet[..]); while d.remaining() > 0 { + #[cfg(feature = "build-fuzzing-corpus")] + let pos = d.offset(); let f = Frame::decode(&mut d)?; + #[cfg(feature = "build-fuzzing-corpus")] + neqo_common::write_item_to_fuzzing_corpus("frame", &packet[pos..d.offset()]); ack_eliciting |= f.ack_eliciting(); probing &= f.path_probing(); let t = f.get_type(); @@ -1623,10 +1669,15 @@ impl Connection { if let Some(cid) = self.connection_ids.next() { self.paths.make_permanent(path, None, cid); Ok(()) - } else if self.paths.primary().borrow().remote_cid().is_empty() { - self.paths - .make_permanent(path, None, ConnectionIdEntry::empty_remote()); - Ok(()) + } else if let Some(primary) = self.paths.primary() { + if primary.borrow().remote_cid().is_empty() { + self.paths + .make_permanent(path, None, ConnectionIdEntry::empty_remote()); + Ok(()) + } else { + qtrace!([self], "Unable to make path permanent: {}", path.borrow()); + Err(Error::InvalidMigration) + } } else { qtrace!([self], "Unable to make path permanent: {}", path.borrow()); Err(Error::InvalidMigration) @@ -1719,8 +1770,10 @@ impl Connection { // Pointless migration is pointless. return Err(Error::InvalidMigration); } - let local = local.unwrap_or_else(|| self.paths.primary().borrow().local_address()); - let remote = remote.unwrap_or_else(|| self.paths.primary().borrow().remote_address()); + + let path = self.paths.primary().ok_or(Error::InvalidMigration)?; + let local = local.unwrap_or_else(|| path.borrow().local_address()); + let remote = remote.unwrap_or_else(|| path.borrow().remote_address()); if mem::discriminant(&local.ip()) != mem::discriminant(&remote.ip()) { // Can't mix address families. @@ -1773,7 +1826,12 @@ impl Connection { // has to use the existing address. So only pay attention to a preferred // address from the same family as is currently in use. More thought will // be needed to work out how to get addresses from a different family. - let prev = self.paths.primary().borrow().remote_address(); + let prev = self + .paths + .primary() + .ok_or(Error::NoAvailablePath)? + .borrow() + .remote_address(); let remote = match prev.ip() { IpAddr::V4(_) => addr.ipv4().map(SocketAddr::V4), IpAddr::V6(_) => addr.ipv6().map(SocketAddr::V6), @@ -1937,20 +1995,15 @@ impl Connection { } } - self.streams - .write_frames(TransmissionPriority::Critical, builder, tokens, frame_stats); - if builder.is_full() { - return; - } - - self.streams.write_frames( + for prio in [ + TransmissionPriority::Critical, TransmissionPriority::Important, - builder, - tokens, - frame_stats, - ); - if builder.is_full() { - return; + ] { + self.streams + .write_frames(prio, builder, tokens, frame_stats); + if builder.is_full() { + return; + } } // NEW_CONNECTION_ID, RETIRE_CONNECTION_ID, and ACK_FREQUENCY. @@ -1958,21 +2011,18 @@ impl Connection { if builder.is_full() { return; } - self.paths.write_frames(builder, tokens, frame_stats); - if builder.is_full() { - return; - } - self.streams - .write_frames(TransmissionPriority::High, builder, tokens, frame_stats); + self.paths.write_frames(builder, tokens, frame_stats); if builder.is_full() { return; } - self.streams - .write_frames(TransmissionPriority::Normal, builder, tokens, frame_stats); - if builder.is_full() { - return; + for prio in [TransmissionPriority::High, TransmissionPriority::Normal] { + self.streams + .write_frames(prio, builder, tokens, &mut stats.frame_tx); + if builder.is_full() { + return; + } } // Datagrams are best-effort and unreliable. Let streams starve them for now. @@ -1981,9 +2031,9 @@ impl Connection { return; } - let frame_stats = &mut stats.frame_tx; // CRYPTO here only includes NewSessionTicket, plus NEW_TOKEN. // Both of these are only used for resumption and so can be relatively low priority. + let frame_stats = &mut stats.frame_tx; self.crypto.write_frame( PacketNumberSpace::ApplicationData, builder, @@ -1993,6 +2043,7 @@ impl Connection { if builder.is_full() { return; } + self.new_token.write_frames(builder, tokens, frame_stats); if builder.is_full() { return; @@ -2002,10 +2053,8 @@ impl Connection { .write_frames(TransmissionPriority::Low, builder, tokens, frame_stats); #[cfg(test)] - { - if let Some(w) = &mut self.test_frame_writer { - w.write_frames(builder); - } + if let Some(w) = &mut self.test_frame_writer { + w.write_frames(builder); } } @@ -2138,6 +2187,40 @@ impl Connection { (tokens, ack_eliciting, padded) } + fn write_closing_frames( + &mut self, + close: &ClosingFrame, + builder: &mut PacketBuilder, + space: PacketNumberSpace, + now: Instant, + path: &PathRef, + tokens: &mut Vec, + ) { + if builder.remaining() > ClosingFrame::MIN_LENGTH + RecvdPackets::USEFUL_ACK_LEN { + // Include an ACK frame with the CONNECTION_CLOSE. + let limit = builder.limit(); + builder.set_limit(limit - ClosingFrame::MIN_LENGTH); + self.acks.immediate_ack(now); + self.acks.write_frame( + space, + now, + path.borrow().rtt().estimate(), + builder, + tokens, + &mut self.stats.borrow_mut().frame_tx, + ); + builder.set_limit(limit); + } + // CloseReason::Application is only allowed at 1RTT. + let sanitized = if space == PacketNumberSpace::ApplicationData { + None + } else { + close.sanitize() + }; + sanitized.as_ref().unwrap_or(close).write_frame(builder); + self.stats.borrow_mut().frame_tx.connection_close += 1; + } + /// Build a datagram, possibly from multiple packets (for different PN /// spaces) and each containing 1+ frames. #[allow(clippy::too_many_lines)] // Yeah, that's just the way it is. @@ -2201,17 +2284,7 @@ impl Connection { let payload_start = builder.len(); let (mut tokens, mut ack_eliciting, mut padded) = (Vec::new(), false, false); if let Some(ref close) = closing_frame { - // ConnectionError::Application is only allowed at 1RTT. - let sanitized = if *space == PacketNumberSpace::ApplicationData { - None - } else { - close.sanitize() - }; - sanitized - .as_ref() - .unwrap_or(close) - .write_frame(&mut builder); - self.stats.borrow_mut().frame_tx.connection_close += 1; + self.write_closing_frames(close, &mut builder, *space, now, path, &mut tokens); } else { (tokens, ack_eliciting, padded) = self.write_frames(path, *space, &profile, &mut builder, now); @@ -2229,7 +2302,7 @@ impl Connection { pt, pn, &builder.as_ref()[payload_start..], - IpTos::default(), // TODO: set from path + path.borrow().tos(), ); qlog::packet_sent( &mut self.qlog, @@ -2251,6 +2324,7 @@ impl Connection { let sent = SentPacket::new( pt, pn, + path.borrow().tos().into(), now, ack_eliciting, tokens, @@ -2303,7 +2377,7 @@ impl Connection { self.loss_recovery.on_packet_sent(path, initial); } path.borrow_mut().add_sent(packets.len()); - Ok(SendOption::Yes(path.borrow().datagram(packets))) + Ok(SendOption::Yes(path.borrow_mut().datagram(packets))) } } @@ -2330,7 +2404,9 @@ impl Connection { fn client_start(&mut self, now: Instant) -> Res<()> { qdebug!([self], "client_start"); debug_assert_eq!(self.role, Role::Client); - qlog::client_connection_started(&mut self.qlog, &self.paths.primary()); + if let Some(path) = self.paths.primary() { + qlog::client_connection_started(&mut self.qlog, &path); + } qlog::client_version_information_initiated(&mut self.qlog, self.conn_params.get_versions()); self.handshake(now, self.version, PacketNumberSpace::Initial, None)?; @@ -2351,9 +2427,9 @@ impl Connection { /// Close the connection. pub fn close(&mut self, now: Instant, app_error: AppError, msg: impl AsRef) { - let error = ConnectionError::Application(app_error); + let error = CloseReason::Application(app_error); let timeout = self.get_closing_period_time(now); - if let Some(path) = self.paths.primary_fallible() { + if let Some(path) = self.paths.primary() { self.state_signaling.close(path, error.clone(), 0, msg); self.set_state(State::Closing { error, timeout }); } else { @@ -2411,10 +2487,8 @@ impl Connection { // That's OK, they can try guessing this. ConnectionIdEntry::random_srt() }; - self.paths - .primary() - .borrow_mut() - .set_reset_token(reset_token); + let path = self.paths.primary().ok_or(Error::NoAvailablePath)?; + path.borrow_mut().set_reset_token(reset_token); let max_ad = Duration::from_millis(remote.get_integer(tparams::MAX_ACK_DELAY)); let min_ad = if remote.has_value(tparams::MIN_ACK_DELAY) { @@ -2426,11 +2500,8 @@ impl Connection { } else { None }; - self.paths.primary().borrow_mut().set_ack_delay( - max_ad, - min_ad, - self.conn_params.get_ack_ratio(), - ); + path.borrow_mut() + .set_ack_delay(max_ad, min_ad, self.conn_params.get_ack_ratio()); let max_active_cids = remote.get_integer(tparams::ACTIVE_CONNECTION_ID_LIMIT); self.cid_manager.set_limit(max_active_cids); @@ -2673,10 +2744,18 @@ impl Connection { ack_delay, first_ack_range, ack_ranges, + ecn_count, } => { let ranges = Frame::decode_ack_frame(largest_acknowledged, first_ack_range, &ack_ranges)?; - self.handle_ack(space, largest_acknowledged, ranges, ack_delay, now); + self.handle_ack( + space, + largest_acknowledged, + ranges, + ecn_count, + ack_delay, + now, + ); } Frame::Crypto { offset, data } => { qtrace!( @@ -2747,7 +2826,6 @@ impl Connection { reason_phrase, } => { self.stats.borrow_mut().frame_rx.connection_close += 1; - let reason_phrase = String::from_utf8_lossy(&reason_phrase); qinfo!( [self], "ConnectionClose received. Error code: {:?} frame type {:x} reason {}", @@ -2768,7 +2846,7 @@ impl Connection { FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT, ) }; - let error = ConnectionError::Transport(detail); + let error = CloseReason::Transport(detail); self.state_signaling .drain(Rc::clone(path), error.clone(), frame_type, ""); self.set_state(State::Draining { @@ -2853,6 +2931,7 @@ impl Connection { space: PacketNumberSpace, largest_acknowledged: u64, ack_ranges: R, + ack_ecn: Option, ack_delay: u64, now: Instant, ) where @@ -2861,11 +2940,15 @@ impl Connection { { qdebug!([self], "Rx ACK space={}, ranges={:?}", space, ack_ranges); + let Some(path) = self.paths.primary() else { + return; + }; let (acked_packets, lost_packets) = self.loss_recovery.on_ack_received( - &self.paths.primary(), + &path, space, largest_acknowledged, ack_ranges, + ack_ecn, self.decode_ack_delay(ack_delay), now, ); @@ -2903,8 +2986,10 @@ impl Connection { qdebug!([self], "0-RTT rejected"); // Tell 0-RTT packets that they were "lost". - let dropped = self.loss_recovery.drop_0rtt(&self.paths.primary(), now); - self.handle_lost_packets(&dropped); + if let Some(path) = self.paths.primary() { + let dropped = self.loss_recovery.drop_0rtt(&path, now); + self.handle_lost_packets(&dropped); + } self.streams.zero_rtt_rejected(); @@ -2923,7 +3008,7 @@ impl Connection { // Remove the randomized client CID from the list of acceptable CIDs. self.cid_manager.remove_odcid(); // Mark the path as validated, if it isn't already. - let path = self.paths.primary(); + let path = self.paths.primary().ok_or(Error::NoAvailablePath)?; path.borrow_mut().set_valid(now); // Generate a qlog event that the server connection started. qlog::server_connection_started(&mut self.qlog, &path); @@ -3191,7 +3276,7 @@ impl Connection { else { return Err(Error::NotAvailable); }; - let path = self.paths.primary_fallible().ok_or(Error::NotAvailable)?; + let path = self.paths.primary().ok_or(Error::NotAvailable)?; let mtu = path.borrow().mtu(); let encoder = Encoder::with_capacity(mtu); diff --git a/third_party/rust/neqo-transport/src/connection/state.rs b/third_party/rust/neqo-transport/src/connection/state.rs index cc2f6e30d2..e76f937938 100644 --- a/third_party/rust/neqo-transport/src/connection/state.rs +++ b/third_party/rust/neqo-transport/src/connection/state.rs @@ -21,7 +21,7 @@ use crate::{ packet::PacketBuilder, path::PathRef, recovery::RecoveryToken, - ConnectionError, Error, + CloseReason, Error, }; #[derive(Clone, Debug, PartialEq, Eq)] @@ -42,14 +42,14 @@ pub enum State { Connected, Confirmed, Closing { - error: ConnectionError, + error: CloseReason, timeout: Instant, }, Draining { - error: ConnectionError, + error: CloseReason, timeout: Instant, }, - Closed(ConnectionError), + Closed(CloseReason), } impl State { @@ -67,7 +67,7 @@ impl State { } #[must_use] - pub fn error(&self) -> Option<&ConnectionError> { + pub fn error(&self) -> Option<&CloseReason> { if let Self::Closing { error, .. } | Self::Draining { error, .. } | Self::Closed(error) = self { @@ -116,7 +116,7 @@ impl Ord for State { #[derive(Debug, Clone)] pub struct ClosingFrame { path: PathRef, - error: ConnectionError, + error: CloseReason, frame_type: FrameType, reason_phrase: Vec, } @@ -124,7 +124,7 @@ pub struct ClosingFrame { impl ClosingFrame { fn new( path: PathRef, - error: ConnectionError, + error: CloseReason, frame_type: FrameType, message: impl AsRef, ) -> Self { @@ -142,12 +142,12 @@ impl ClosingFrame { } pub fn sanitize(&self) -> Option { - if let ConnectionError::Application(_) = self.error { + if let CloseReason::Application(_) = self.error { // The default CONNECTION_CLOSE frame that is sent when an application // error code needs to be sent in an Initial or Handshake packet. Some(Self { path: Rc::clone(&self.path), - error: ConnectionError::Transport(Error::ApplicationError), + error: CloseReason::Transport(Error::ApplicationError), frame_type: 0, reason_phrase: Vec::new(), }) @@ -156,19 +156,22 @@ impl ClosingFrame { } } + /// Length of a closing frame with a truncated `reason_length`. Allow 8 bytes for the reason + /// phrase to ensure that if it needs to be truncated there is still at least a few bytes of + /// the value. + pub const MIN_LENGTH: usize = 1 + 8 + 8 + 2 + 8; + pub fn write_frame(&self, builder: &mut PacketBuilder) { - // Allow 8 bytes for the reason phrase to ensure that if it needs to be - // truncated there is still at least a few bytes of the value. - if builder.remaining() < 1 + 8 + 8 + 2 + 8 { + if builder.remaining() < ClosingFrame::MIN_LENGTH { return; } match &self.error { - ConnectionError::Transport(e) => { + CloseReason::Transport(e) => { builder.encode_varint(FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT); builder.encode_varint(e.code()); builder.encode_varint(self.frame_type); } - ConnectionError::Application(code) => { + CloseReason::Application(code) => { builder.encode_varint(FRAME_TYPE_CONNECTION_CLOSE_APPLICATION); builder.encode_varint(*code); } @@ -209,10 +212,6 @@ pub enum StateSignaling { impl StateSignaling { pub fn handshake_done(&mut self) { if !matches!(self, Self::Idle) { - debug_assert!( - false, - "StateSignaling must be in Idle state but is in {self:?} state.", - ); return; } *self = Self::HandshakeDone; @@ -231,7 +230,7 @@ impl StateSignaling { pub fn close( &mut self, path: PathRef, - error: ConnectionError, + error: CloseReason, frame_type: FrameType, message: impl AsRef, ) { @@ -243,7 +242,7 @@ impl StateSignaling { pub fn drain( &mut self, path: PathRef, - error: ConnectionError, + error: CloseReason, frame_type: FrameType, message: impl AsRef, ) { diff --git a/third_party/rust/neqo-transport/src/connection/tests/cc.rs b/third_party/rust/neqo-transport/src/connection/tests/cc.rs index b708bc421d..f21f4e184f 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/cc.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/cc.rs @@ -6,7 +6,7 @@ use std::{mem, time::Duration}; -use neqo_common::{qdebug, qinfo, Datagram}; +use neqo_common::{qdebug, qinfo, Datagram, IpTosEcn}; use super::{ super::Output, ack_bytes, assert_full_cwnd, connect_rtt_idle, cwnd, cwnd_avail, cwnd_packets, @@ -36,9 +36,13 @@ fn cc_slow_start() { assert!(cwnd_avail(&client) < ACK_ONLY_SIZE_LIMIT); } -#[test] -/// Verify that CC moves to cong avoidance when a packet is marked lost. -fn cc_slow_start_to_cong_avoidance_recovery_period() { +#[derive(PartialEq, Eq, Clone, Copy)] +enum CongestionSignal { + PacketLoss, + EcnCe, +} + +fn cc_slow_start_to_cong_avoidance_recovery_period(congestion_signal: CongestionSignal) { let mut client = default_client(); let mut server = default_server(); let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT); @@ -78,9 +82,17 @@ fn cc_slow_start_to_cong_avoidance_recovery_period() { assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND * 2); let flight2_largest = flight1_largest + u64::try_from(c_tx_dgrams.len()).unwrap(); - // Server: Receive and generate ack again, but drop first packet + // Server: Receive and generate ack again, but this time add congestion + // signal first. now += DEFAULT_RTT / 2; - c_tx_dgrams.remove(0); + match congestion_signal { + CongestionSignal::PacketLoss => { + c_tx_dgrams.remove(0); + } + CongestionSignal::EcnCe => { + c_tx_dgrams.last_mut().unwrap().set_tos(IpTosEcn::Ce.into()); + } + } let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now); assert_eq!( server.stats().frame_tx.largest_acknowledged, @@ -97,6 +109,18 @@ fn cc_slow_start_to_cong_avoidance_recovery_period() { assert!(cwnd(&client) < cwnd_before_cong); } +#[test] +/// Verify that CC moves to cong avoidance when a packet is marked lost. +fn cc_slow_start_to_cong_avoidance_recovery_period_due_to_packet_loss() { + cc_slow_start_to_cong_avoidance_recovery_period(CongestionSignal::PacketLoss); +} + +/// Verify that CC moves to cong avoidance when ACK is marked with ECN CE. +#[test] +fn cc_slow_start_to_cong_avoidance_recovery_period_due_to_ecn_ce() { + cc_slow_start_to_cong_avoidance_recovery_period(CongestionSignal::EcnCe); +} + #[test] /// Verify that CC stays in recovery period when packet sent before start of /// recovery period is acked. diff --git a/third_party/rust/neqo-transport/src/connection/tests/close.rs b/third_party/rust/neqo-transport/src/connection/tests/close.rs index 5351dd0d5c..7c620de17e 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/close.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/close.rs @@ -14,13 +14,13 @@ use super::{ }; use crate::{ tparams::{self, TransportParameter}, - AppError, ConnectionError, Error, ERROR_APPLICATION_CLOSE, + AppError, CloseReason, Error, ERROR_APPLICATION_CLOSE, }; fn assert_draining(c: &Connection, expected: &Error) { assert!(c.state().closed()); if let State::Draining { - error: ConnectionError::Transport(error), + error: CloseReason::Transport(error), .. } = c.state() { @@ -40,7 +40,14 @@ fn connection_close() { client.close(now, 42, ""); + let stats_before = client.stats().frame_tx; let out = client.process(None, now); + let stats_after = client.stats().frame_tx; + assert_eq!( + stats_after.connection_close, + stats_before.connection_close + 1 + ); + assert_eq!(stats_after.ack, stats_before.ack + 1); server.process_input(&out.dgram().unwrap(), now); assert_draining(&server, &Error::PeerApplicationError(42)); @@ -57,7 +64,14 @@ fn connection_close_with_long_reason_string() { let long_reason = String::from_utf8([0x61; 2048].to_vec()).unwrap(); client.close(now, 42, long_reason); + let stats_before = client.stats().frame_tx; let out = client.process(None, now); + let stats_after = client.stats().frame_tx; + assert_eq!( + stats_after.connection_close, + stats_before.connection_close + 1 + ); + assert_eq!(stats_after.ack, stats_before.ack + 1); server.process_input(&out.dgram().unwrap(), now); assert_draining(&server, &Error::PeerApplicationError(42)); @@ -100,7 +114,7 @@ fn bad_tls_version() { let dgram = server.process(dgram.as_ref(), now()).dgram(); assert_eq!( *server.state(), - State::Closed(ConnectionError::Transport(Error::ProtocolViolation)) + State::Closed(CloseReason::Transport(Error::ProtocolViolation)) ); assert!(dgram.is_some()); client.process_input(&dgram.unwrap(), now()); @@ -154,7 +168,6 @@ fn closing_and_draining() { assert!(client_close.is_some()); let client_close_timer = client.process(None, now()).callback(); assert_ne!(client_close_timer, Duration::from_secs(0)); - // The client will spit out the same packet in response to anything it receives. let p3 = send_something(&mut server, now()); let client_close2 = client.process(Some(&p3), now()).dgram(); @@ -168,7 +181,7 @@ fn closing_and_draining() { assert_eq!(end, Output::None); assert_eq!( *client.state(), - State::Closed(ConnectionError::Application(APP_ERROR)) + State::Closed(CloseReason::Application(APP_ERROR)) ); // When the server receives the close, it too should generate CONNECTION_CLOSE. @@ -186,7 +199,7 @@ fn closing_and_draining() { assert_eq!(end, Output::None); assert_eq!( *server.state(), - State::Closed(ConnectionError::Transport(Error::PeerApplicationError( + State::Closed(CloseReason::Transport(Error::PeerApplicationError( APP_ERROR ))) ); diff --git a/third_party/rust/neqo-transport/src/connection/tests/datagram.rs b/third_party/rust/neqo-transport/src/connection/tests/datagram.rs index ade8c753be..f1b64b3c8f 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/datagram.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/datagram.rs @@ -19,7 +19,7 @@ use crate::{ packet::PacketBuilder, quic_datagrams::MAX_QUIC_DATAGRAM, send_stream::{RetransmissionPriority, TransmissionPriority}, - Connection, ConnectionError, ConnectionParameters, Error, StreamType, + CloseReason, Connection, ConnectionParameters, Error, StreamType, }; const DATAGRAM_LEN_MTU: u64 = 1310; @@ -362,10 +362,7 @@ fn dgram_no_allowed() { client.process_input(&out, now()); - assert_error( - &client, - &ConnectionError::Transport(Error::ProtocolViolation), - ); + assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation)); } #[test] @@ -383,10 +380,7 @@ fn dgram_too_big() { client.process_input(&out, now()); - assert_error( - &client, - &ConnectionError::Transport(Error::ProtocolViolation), - ); + assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation)); } #[test] @@ -587,7 +581,7 @@ fn datagram_fill() { // Work out how much space we have for a datagram. let space = { - let p = client.paths.primary(); + let p = client.paths.primary().unwrap(); let path = p.borrow(); // Minimum overhead is connection ID length, 1 byte short header, 1 byte packet number, // 1 byte for the DATAGRAM frame type, and 16 bytes for the AEAD. diff --git a/third_party/rust/neqo-transport/src/connection/tests/ecn.rs b/third_party/rust/neqo-transport/src/connection/tests/ecn.rs new file mode 100644 index 0000000000..87957297e5 --- /dev/null +++ b/third_party/rust/neqo-transport/src/connection/tests/ecn.rs @@ -0,0 +1,392 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::time::Duration; + +use neqo_common::{Datagram, IpTos, IpTosEcn}; +use test_fixture::{ + assertions::{assert_v4_path, assert_v6_path}, + fixture_init, now, DEFAULT_ADDR_V4, +}; + +use super::send_something_with_modifier; +use crate::{ + connection::tests::{ + connect_force_idle, connect_force_idle_with_modifier, default_client, default_server, + migration::get_cid, new_client, new_server, send_something, + }, + ecn::ECN_TEST_COUNT, + ConnectionId, ConnectionParameters, StreamType, +}; + +fn assert_ecn_enabled(tos: IpTos) { + assert!(tos.is_ecn_marked()); +} + +fn assert_ecn_disabled(tos: IpTos) { + assert!(!tos.is_ecn_marked()); +} + +fn set_tos(mut d: Datagram, ecn: IpTosEcn) -> Datagram { + d.set_tos(ecn.into()); + d +} + +fn noop() -> fn(Datagram) -> Option { + Some +} + +fn bleach() -> fn(Datagram) -> Option { + |d| Some(set_tos(d, IpTosEcn::NotEct)) +} + +fn remark() -> fn(Datagram) -> Option { + |d| { + if d.tos().is_ecn_marked() { + Some(set_tos(d, IpTosEcn::Ect1)) + } else { + Some(d) + } + } +} + +fn ce() -> fn(Datagram) -> Option { + |d| { + if d.tos().is_ecn_marked() { + Some(set_tos(d, IpTosEcn::Ce)) + } else { + Some(d) + } + } +} + +fn drop() -> fn(Datagram) -> Option { + |_| None +} + +#[test] +fn disables_on_loss() { + let now = now(); + let mut client = default_client(); + let mut server = default_server(); + connect_force_idle(&mut client, &mut server); + + // Right after the handshake, the ECN validation should still be in progress. + let client_pkt = send_something(&mut client, now); + assert_ecn_enabled(client_pkt.tos()); + + for _ in 0..ECN_TEST_COUNT { + send_something(&mut client, now); + } + + // ECN should now be disabled. + let client_pkt = send_something(&mut client, now); + assert_ecn_disabled(client_pkt.tos()); +} + +/// This function performs a handshake over a path that modifies packets via `orig_path_modifier`. +/// It then sends `burst` packets on that path, and then migrates to a new path that +/// modifies packets via `new_path_modifier`. It sends `burst` packets on the new path. +/// The function returns the TOS value of the last packet sent on the old path and the TOS value +/// of the last packet sent on the new path to allow for verification of correct behavior. +pub fn migration_with_modifiers( + orig_path_modifier: fn(Datagram) -> Option, + new_path_modifier: fn(Datagram) -> Option, + burst: usize, +) -> (IpTos, IpTos, bool) { + fixture_init(); + let mut client = new_client(ConnectionParameters::default().max_streams(StreamType::UniDi, 64)); + let mut server = new_server(ConnectionParameters::default().max_streams(StreamType::UniDi, 64)); + + connect_force_idle_with_modifier(&mut client, &mut server, orig_path_modifier); + let mut now = now(); + + // Right after the handshake, the ECN validation should still be in progress. + let client_pkt = send_something(&mut client, now); + assert_ecn_enabled(client_pkt.tos()); + server.process_input(&orig_path_modifier(client_pkt).unwrap(), now); + + // Send some data on the current path. + for _ in 0..burst { + let client_pkt = send_something_with_modifier(&mut client, now, orig_path_modifier); + server.process_input(&client_pkt, now); + } + + if let Some(ack) = server.process_output(now).dgram() { + client.process_input(&ack, now); + } + + let client_pkt = send_something(&mut client, now); + let tos_before_migration = client_pkt.tos(); + server.process_input(&orig_path_modifier(client_pkt).unwrap(), now); + + client + .migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), false, now) + .unwrap(); + + let mut migrated = false; + let probe = new_path_modifier(client.process_output(now).dgram().unwrap()); + if let Some(probe) = probe { + assert_v4_path(&probe, true); // Contains PATH_CHALLENGE. + assert_eq!(client.stats().frame_tx.path_challenge, 1); + let probe_cid = ConnectionId::from(get_cid(&probe)); + + let resp = new_path_modifier(server.process(Some(&probe), now).dgram().unwrap()).unwrap(); + assert_v4_path(&resp, true); + assert_eq!(server.stats().frame_tx.path_response, 1); + assert_eq!(server.stats().frame_tx.path_challenge, 1); + + // Data continues to be exchanged on the old path. + let client_data = send_something_with_modifier(&mut client, now, orig_path_modifier); + assert_ne!(get_cid(&client_data), probe_cid); + assert_v6_path(&client_data, false); + server.process_input(&client_data, now); + let server_data = send_something_with_modifier(&mut server, now, orig_path_modifier); + assert_v6_path(&server_data, false); + client.process_input(&server_data, now); + + // Once the client receives the probe response, it migrates to the new path. + client.process_input(&resp, now); + assert_eq!(client.stats().frame_rx.path_challenge, 1); + migrated = true; + + let migrate_client = send_something_with_modifier(&mut client, now, new_path_modifier); + assert_v4_path(&migrate_client, true); // Responds to server probe. + + // The server now sees the migration and will switch over. + // However, it will probe the old path again, even though it has just + // received a response to its last probe, because it needs to verify + // that the migration is genuine. + server.process_input(&migrate_client, now); + } + + let stream_before = server.stats().frame_tx.stream; + let probe_old_server = send_something_with_modifier(&mut server, now, orig_path_modifier); + // This is just the double-check probe; no STREAM frames. + assert_v6_path(&probe_old_server, migrated); + assert_eq!( + server.stats().frame_tx.path_challenge, + if migrated { 2 } else { 0 } + ); + assert_eq!( + server.stats().frame_tx.stream, + if migrated { stream_before } else { 1 } + ); + + if migrated { + // The server then sends data on the new path. + let migrate_server = + new_path_modifier(server.process_output(now).dgram().unwrap()).unwrap(); + assert_v4_path(&migrate_server, false); + assert_eq!(server.stats().frame_tx.path_challenge, 2); + assert_eq!(server.stats().frame_tx.stream, stream_before + 1); + + // The client receives these checks and responds to the probe, but uses the new path. + client.process_input(&migrate_server, now); + client.process_input(&probe_old_server, now); + let old_probe_resp = send_something_with_modifier(&mut client, now, new_path_modifier); + assert_v6_path(&old_probe_resp, true); + let client_confirmation = client.process_output(now).dgram().unwrap(); + assert_v4_path(&client_confirmation, false); + + // The server has now sent 2 packets, so it is blocked on the pacer. Wait. + let server_pacing = server.process_output(now).callback(); + assert_ne!(server_pacing, Duration::new(0, 0)); + // ... then confirm that the server sends on the new path still. + let server_confirmation = + send_something_with_modifier(&mut server, now + server_pacing, new_path_modifier); + assert_v4_path(&server_confirmation, false); + client.process_input(&server_confirmation, now); + + // Send some data on the new path. + for _ in 0..burst { + now += client.process_output(now).callback(); + let client_pkt = send_something_with_modifier(&mut client, now, new_path_modifier); + server.process_input(&client_pkt, now); + } + + if let Some(ack) = server.process_output(now).dgram() { + client.process_input(&ack, now); + } + } + + now += client.process_output(now).callback(); + let mut client_pkt = send_something(&mut client, now); + while !migrated && client_pkt.source() == DEFAULT_ADDR_V4 { + client_pkt = send_something(&mut client, now); + } + let tos_after_migration = client_pkt.tos(); + (tos_before_migration, tos_after_migration, migrated) +} + +#[test] +fn ecn_migration_zero_burst_all_cases() { + for orig_path_mod in &[noop(), bleach(), remark(), ce()] { + for new_path_mod in &[noop(), bleach(), remark(), ce(), drop()] { + let (before, after, migrated) = + migration_with_modifiers(*orig_path_mod, *new_path_mod, 0); + // Too few packets sent before and after migration to conclude ECN validation. + assert_ecn_enabled(before); + assert_ecn_enabled(after); + // Migration succeeds except if the new path drops ECN. + assert!(*new_path_mod == drop() || migrated); + } + } +} + +#[test] +fn ecn_migration_noop_bleach_data() { + let (before, after, migrated) = migration_with_modifiers(noop(), bleach(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration. + assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching. + assert!(migrated); +} + +#[test] +fn ecn_migration_noop_remark_data() { + let (before, after, migrated) = migration_with_modifiers(noop(), remark(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration. + assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. + assert!(migrated); +} + +#[test] +fn ecn_migration_noop_ce_data() { + let (before, after, migrated) = migration_with_modifiers(noop(), ce(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration. + assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. + assert!(migrated); +} + +#[test] +fn ecn_migration_noop_drop_data() { + let (before, after, migrated) = migration_with_modifiers(noop(), drop(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration. + assert_ecn_enabled(after); // Migration failed, ECN on original path is still validated. + assert!(!migrated); +} + +#[test] +fn ecn_migration_bleach_noop_data() { + let (before, after, migrated) = migration_with_modifiers(bleach(), noop(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. + assert_ecn_enabled(after); // ECN validation concludes after migration. + assert!(migrated); +} + +#[test] +fn ecn_migration_bleach_bleach_data() { + let (before, after, migrated) = migration_with_modifiers(bleach(), bleach(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. + assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching. + assert!(migrated); +} + +#[test] +fn ecn_migration_bleach_remark_data() { + let (before, after, migrated) = migration_with_modifiers(bleach(), remark(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. + assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. + assert!(migrated); +} + +#[test] +fn ecn_migration_bleach_ce_data() { + let (before, after, migrated) = migration_with_modifiers(bleach(), ce(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. + assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. + assert!(migrated); +} + +#[test] +fn ecn_migration_bleach_drop_data() { + let (before, after, migrated) = migration_with_modifiers(bleach(), drop(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. + // Migration failed, ECN on original path is still disabled. + assert_ecn_disabled(after); + assert!(!migrated); +} + +#[test] +fn ecn_migration_remark_noop_data() { + let (before, after, migrated) = migration_with_modifiers(remark(), noop(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. + assert_ecn_enabled(after); // ECN validation succeeds after migration. + assert!(migrated); +} + +#[test] +fn ecn_migration_remark_bleach_data() { + let (before, after, migrated) = migration_with_modifiers(remark(), bleach(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. + assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching. + assert!(migrated); +} + +#[test] +fn ecn_migration_remark_remark_data() { + let (before, after, migrated) = migration_with_modifiers(remark(), remark(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. + assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. + assert!(migrated); +} + +#[test] +fn ecn_migration_remark_ce_data() { + let (before, after, migrated) = migration_with_modifiers(remark(), ce(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. + assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. + assert!(migrated); +} + +#[test] +fn ecn_migration_remark_drop_data() { + let (before, after, migrated) = migration_with_modifiers(remark(), drop(), ECN_TEST_COUNT); + assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. + assert_ecn_disabled(after); // Migration failed, ECN on original path is still disabled. + assert!(!migrated); +} + +#[test] +fn ecn_migration_ce_noop_data() { + let (before, after, migrated) = migration_with_modifiers(ce(), noop(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. + assert_ecn_enabled(after); // ECN validation concludes after migration. + assert!(migrated); +} + +#[test] +fn ecn_migration_ce_bleach_data() { + let (before, after, migrated) = migration_with_modifiers(ce(), bleach(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. + assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching + assert!(migrated); +} + +#[test] +fn ecn_migration_ce_remark_data() { + let (before, after, migrated) = migration_with_modifiers(ce(), remark(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. + assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. + assert!(migrated); +} + +#[test] +fn ecn_migration_ce_ce_data() { + let (before, after, migrated) = migration_with_modifiers(ce(), ce(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. + assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. + assert!(migrated); +} + +#[test] +fn ecn_migration_ce_drop_data() { + let (before, after, migrated) = migration_with_modifiers(ce(), drop(), ECN_TEST_COUNT); + assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. + // Migration failed, ECN on original path is still enabled. + assert_ecn_enabled(after); + assert!(!migrated); +} diff --git a/third_party/rust/neqo-transport/src/connection/tests/handshake.rs b/third_party/rust/neqo-transport/src/connection/tests/handshake.rs index f2103523ec..c908340616 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/handshake.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/handshake.rs @@ -35,7 +35,7 @@ use crate::{ server::ValidateAddress, tparams::{TransportParameter, MIN_ACK_DELAY}, tracking::DEFAULT_ACK_DELAY, - ConnectionError, ConnectionParameters, EmptyConnectionIdGenerator, Error, StreamType, Version, + CloseReason, ConnectionParameters, EmptyConnectionIdGenerator, Error, StreamType, Version, }; const ECH_CONFIG_ID: u8 = 7; @@ -111,8 +111,8 @@ fn handshake_failed_authentication() { qdebug!("---- server: Alert(certificate_revoked)"); let out = server.process(out.as_dgram_ref(), now()); assert!(out.as_dgram_ref().is_some()); - assert_error(&client, &ConnectionError::Transport(Error::CryptoAlert(44))); - assert_error(&server, &ConnectionError::Transport(Error::PeerError(300))); + assert_error(&client, &CloseReason::Transport(Error::CryptoAlert(44))); + assert_error(&server, &CloseReason::Transport(Error::PeerError(300))); } #[test] @@ -133,11 +133,8 @@ fn no_alpn() { handshake(&mut client, &mut server, now(), Duration::new(0, 0)); // TODO (mt): errors are immediate, which means that we never send CONNECTION_CLOSE // and the client never sees the server's rejection of its handshake. - // assert_error(&client, ConnectionError::Transport(Error::CryptoAlert(120))); - assert_error( - &server, - &ConnectionError::Transport(Error::CryptoAlert(120)), - ); + // assert_error(&client, CloseReason::Transport(Error::CryptoAlert(120))); + assert_error(&server, &CloseReason::Transport(Error::CryptoAlert(120))); } #[test] @@ -934,10 +931,10 @@ fn ech_retry() { server.process_input(&dgram.unwrap(), now()); assert_eq!( server.state().error(), - Some(&ConnectionError::Transport(Error::PeerError(0x100 + 121))) + Some(&CloseReason::Transport(Error::PeerError(0x100 + 121))) ); - let Some(ConnectionError::Transport(Error::EchRetry(updated_config))) = client.state().error() + let Some(CloseReason::Transport(Error::EchRetry(updated_config))) = client.state().error() else { panic!( "Client state should be failed with EchRetry, is {:?}", @@ -984,7 +981,7 @@ fn ech_retry_fallback_rejected() { client.authenticated(AuthenticationStatus::PolicyRejection, now()); assert!(client.state().error().is_some()); - if let Some(ConnectionError::Transport(Error::EchRetry(_))) = client.state().error() { + if let Some(CloseReason::Transport(Error::EchRetry(_))) = client.state().error() { panic!("Client should not get EchRetry error"); } @@ -993,14 +990,13 @@ fn ech_retry_fallback_rejected() { server.process_input(&dgram.unwrap(), now()); assert_eq!( server.state().error(), - Some(&ConnectionError::Transport(Error::PeerError(298))) + Some(&CloseReason::Transport(Error::PeerError(298))) ); // A bad_certificate alert. } #[test] fn bad_min_ack_delay() { - const EXPECTED_ERROR: ConnectionError = - ConnectionError::Transport(Error::TransportParameterError); + const EXPECTED_ERROR: CloseReason = CloseReason::Transport(Error::TransportParameterError); let mut server = default_server(); let max_ad = u64::try_from(DEFAULT_ACK_DELAY.as_micros()).unwrap(); server @@ -1018,7 +1014,7 @@ fn bad_min_ack_delay() { server.process_input(&dgram.unwrap(), now()); assert_eq!( server.state().error(), - Some(&ConnectionError::Transport(Error::PeerError( + Some(&CloseReason::Transport(Error::PeerError( Error::TransportParameterError.code() ))) ); diff --git a/third_party/rust/neqo-transport/src/connection/tests/keys.rs b/third_party/rust/neqo-transport/src/connection/tests/keys.rs index 847b253284..c2ae9529bf 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/keys.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/keys.rs @@ -11,7 +11,7 @@ use test_fixture::now; use super::{ super::{ - super::{ConnectionError, ERROR_AEAD_LIMIT_REACHED}, + super::{CloseReason, ERROR_AEAD_LIMIT_REACHED}, Connection, ConnectionParameters, Error, Output, State, StreamType, }, connect, connect_force_idle, default_client, default_server, maybe_authenticate, @@ -269,7 +269,7 @@ fn exhaust_write_keys() { assert!(dgram.is_none()); assert!(matches!( client.state(), - State::Closed(ConnectionError::Transport(Error::KeysExhausted)) + State::Closed(CloseReason::Transport(Error::KeysExhausted)) )); } @@ -285,14 +285,14 @@ fn exhaust_read_keys() { let dgram = server.process(Some(&dgram), now()).dgram(); assert!(matches!( server.state(), - State::Closed(ConnectionError::Transport(Error::KeysExhausted)) + State::Closed(CloseReason::Transport(Error::KeysExhausted)) )); client.process_input(&dgram.unwrap(), now()); assert!(matches!( client.state(), State::Draining { - error: ConnectionError::Transport(Error::PeerError(ERROR_AEAD_LIMIT_REACHED)), + error: CloseReason::Transport(Error::PeerError(ERROR_AEAD_LIMIT_REACHED)), .. } )); @@ -341,6 +341,6 @@ fn automatic_update_write_keys_blocked() { assert!(dgram.is_none()); assert!(matches!( client.state(), - State::Closed(ConnectionError::Transport(Error::KeysExhausted)) + State::Closed(CloseReason::Transport(Error::KeysExhausted)) )); } diff --git a/third_party/rust/neqo-transport/src/connection/tests/migration.rs b/third_party/rust/neqo-transport/src/connection/tests/migration.rs index 405ae161a4..779cc78c53 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/migration.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/migration.rs @@ -30,7 +30,7 @@ use crate::{ packet::PacketBuilder, path::{PATH_MTU_V4, PATH_MTU_V6}, tparams::{self, PreferredAddress, TransportParameter}, - ConnectionError, ConnectionId, ConnectionIdDecoder, ConnectionIdGenerator, ConnectionIdRef, + CloseReason, ConnectionId, ConnectionIdDecoder, ConnectionIdGenerator, ConnectionIdRef, ConnectionParameters, EmptyConnectionIdGenerator, Error, }; @@ -357,13 +357,13 @@ fn migrate_same_fail() { assert!(matches!(res, Output::None)); assert!(matches!( client.state(), - State::Closed(ConnectionError::Transport(Error::NoAvailablePath)) + State::Closed(CloseReason::Transport(Error::NoAvailablePath)) )); } /// This gets the connection ID from a datagram using the default /// connection ID generator/decoder. -fn get_cid(d: &Datagram) -> ConnectionIdRef { +pub fn get_cid(d: &Datagram) -> ConnectionIdRef { let gen = CountingConnectionIdGenerator::default(); assert_eq!(d[0] & 0x80, 0); // Only support short packets for now. gen.decode_cid(&mut Decoder::from(&d[1..])).unwrap() @@ -894,7 +894,7 @@ fn retire_prior_to_migration_failure() { assert!(matches!( client.state(), State::Closing { - error: ConnectionError::Transport(Error::InvalidMigration), + error: CloseReason::Transport(Error::InvalidMigration), .. } )); diff --git a/third_party/rust/neqo-transport/src/connection/tests/mod.rs b/third_party/rust/neqo-transport/src/connection/tests/mod.rs index c8c87a0df0..65283b8eb8 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/mod.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/mod.rs @@ -17,7 +17,7 @@ use neqo_common::{event::Provider, qdebug, qtrace, Datagram, Decoder, Role}; use neqo_crypto::{random, AllowZeroRtt, AuthenticationStatus, ResumptionToken}; use test_fixture::{fixture_init, new_neqo_qlog, now, DEFAULT_ADDR}; -use super::{Connection, ConnectionError, ConnectionId, Output, State}; +use super::{CloseReason, Connection, ConnectionId, Output, State}; use crate::{ addr_valid::{AddressValidation, ValidateAddress}, cc::{CWND_INITIAL_PKTS, CWND_MIN}, @@ -37,6 +37,7 @@ mod ackrate; mod cc; mod close; mod datagram; +mod ecn; mod handshake; mod idle; mod keys; @@ -170,17 +171,13 @@ impl crate::connection::test_internal::FrameWriter for PingWriter { } } -trait DatagramModifier: FnMut(Datagram) -> Option {} - -impl DatagramModifier for T where T: FnMut(Datagram) -> Option {} - /// Drive the handshake between the client and server. fn handshake_with_modifier( client: &mut Connection, server: &mut Connection, now: Instant, rtt: Duration, - mut modifier: impl DatagramModifier, + modifier: fn(Datagram) -> Option, ) -> Instant { let mut a = client; let mut b = server; @@ -248,8 +245,8 @@ fn connect_fail( server_error: Error, ) { handshake(client, server, now(), Duration::new(0, 0)); - assert_error(client, &ConnectionError::Transport(client_error)); - assert_error(server, &ConnectionError::Transport(server_error)); + assert_error(client, &CloseReason::Transport(client_error)); + assert_error(server, &CloseReason::Transport(server_error)); } fn connect_with_rtt_and_modifier( @@ -257,7 +254,7 @@ fn connect_with_rtt_and_modifier( server: &mut Connection, now: Instant, rtt: Duration, - modifier: impl DatagramModifier, + modifier: fn(Datagram) -> Option, ) -> Instant { fn check_rtt(stats: &Stats, rtt: Duration) { assert_eq!(stats.rtt, rtt); @@ -287,7 +284,7 @@ fn connect(client: &mut Connection, server: &mut Connection) { connect_with_rtt(client, server, now(), Duration::new(0, 0)); } -fn assert_error(c: &Connection, expected: &ConnectionError) { +fn assert_error(c: &Connection, expected: &CloseReason) { match c.state() { State::Closing { error, .. } | State::Draining { error, .. } | State::Closed(error) => { assert_eq!(*error, *expected, "{c} error mismatch"); @@ -333,7 +330,7 @@ fn connect_rtt_idle_with_modifier( client: &mut Connection, server: &mut Connection, rtt: Duration, - modifier: impl DatagramModifier, + modifier: fn(Datagram) -> Option, ) -> Instant { let now = connect_with_rtt_and_modifier(client, server, now(), rtt, modifier); assert_idle(client, server, rtt, now); @@ -351,7 +348,7 @@ fn connect_rtt_idle(client: &mut Connection, server: &mut Connection, rtt: Durat fn connect_force_idle_with_modifier( client: &mut Connection, server: &mut Connection, - modifier: impl DatagramModifier, + modifier: fn(Datagram) -> Option, ) { connect_rtt_idle_with_modifier(client, server, Duration::new(0, 0), modifier); } @@ -380,7 +377,7 @@ fn fill_stream(c: &mut Connection, stream: StreamId) { fn fill_cwnd(c: &mut Connection, stream: StreamId, mut now: Instant) -> (Vec, Instant) { // Train wreck function to get the remaining congestion window on the primary path. fn cwnd(c: &Connection) -> usize { - c.paths.primary().borrow().sender().cwnd_avail() + c.paths.primary().unwrap().borrow().sender().cwnd_avail() } qtrace!("fill_cwnd starting cwnd: {}", cwnd(c)); @@ -478,10 +475,10 @@ where // Get the current congestion window for the connection. fn cwnd(c: &Connection) -> usize { - c.paths.primary().borrow().sender().cwnd() + c.paths.primary().unwrap().borrow().sender().cwnd() } fn cwnd_avail(c: &Connection) -> usize { - c.paths.primary().borrow().sender().cwnd_avail() + c.paths.primary().unwrap().borrow().sender().cwnd_avail() } fn induce_persistent_congestion( @@ -576,7 +573,7 @@ fn send_something_paced_with_modifier( sender: &mut Connection, mut now: Instant, allow_pacing: bool, - mut modifier: impl DatagramModifier, + modifier: fn(Datagram) -> Option, ) -> (Datagram, Instant) { let stream_id = sender.stream_create(StreamType::UniDi).unwrap(); assert!(sender.stream_send(stream_id, DEFAULT_STREAM_DATA).is_ok()); @@ -608,7 +605,7 @@ fn send_something_paced( fn send_something_with_modifier( sender: &mut Connection, now: Instant, - modifier: impl DatagramModifier, + modifier: fn(Datagram) -> Option, ) -> Datagram { send_something_paced_with_modifier(sender, now, false, modifier).0 } diff --git a/third_party/rust/neqo-transport/src/connection/tests/stream.rs b/third_party/rust/neqo-transport/src/connection/tests/stream.rs index 66d3bf32f3..f7472d917f 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/stream.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/stream.rs @@ -19,9 +19,9 @@ use crate::{ send_stream::{OrderGroup, SendStreamState, SEND_BUFFER_SIZE}, streams::{SendOrder, StreamOrder}, tparams::{self, TransportParameter}, + CloseReason, // tracking::DEFAULT_ACK_PACKET_TOLERANCE, Connection, - ConnectionError, ConnectionParameters, Error, StreamId, @@ -494,12 +494,9 @@ fn exceed_max_data() { assert_error( &client, - &ConnectionError::Transport(Error::PeerError(Error::FlowControlError.code())), - ); - assert_error( - &server, - &ConnectionError::Transport(Error::FlowControlError), + &CloseReason::Transport(Error::PeerError(Error::FlowControlError.code())), ); + assert_error(&server, &CloseReason::Transport(Error::FlowControlError)); } #[test] diff --git a/third_party/rust/neqo-transport/src/connection/tests/vn.rs b/third_party/rust/neqo-transport/src/connection/tests/vn.rs index 93872a94f4..815868d78d 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/vn.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/vn.rs @@ -10,7 +10,7 @@ use neqo_common::{event::Provider, Decoder, Encoder}; use test_fixture::{assertions, datagram, now}; use super::{ - super::{ConnectionError, ConnectionEvent, Output, State, ZeroRttState}, + super::{CloseReason, ConnectionEvent, Output, State, ZeroRttState}, connect, connect_fail, default_client, default_server, exchange_ticket, new_client, new_server, send_something, }; @@ -124,7 +124,7 @@ fn version_negotiation_only_reserved() { assert_eq!(client.process(Some(&dgram), now()), Output::None); match client.state() { State::Closed(err) => { - assert_eq!(*err, ConnectionError::Transport(Error::VersionNegotiation)); + assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation)); } _ => panic!("Invalid client state"), } @@ -183,7 +183,7 @@ fn version_negotiation_not_supported() { assert_eq!(client.process(Some(&dgram), now()), Output::None); match client.state() { State::Closed(err) => { - assert_eq!(*err, ConnectionError::Transport(Error::VersionNegotiation)); + assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation)); } _ => panic!("Invalid client state"), } @@ -338,7 +338,7 @@ fn invalid_server_version() { // The server effectively hasn't reacted here. match server.state() { State::Closed(err) => { - assert_eq!(*err, ConnectionError::Transport(Error::CryptoAlert(47))); + assert_eq!(*err, CloseReason::Transport(Error::CryptoAlert(47))); } _ => panic!("invalid server state"), } diff --git a/third_party/rust/neqo-transport/src/ecn.rs b/third_party/rust/neqo-transport/src/ecn.rs new file mode 100644 index 0000000000..20eb4da003 --- /dev/null +++ b/third_party/rust/neqo-transport/src/ecn.rs @@ -0,0 +1,225 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::{AddAssign, Deref, DerefMut, Sub}; + +use enum_map::EnumMap; +use neqo_common::{qdebug, qinfo, qwarn, IpTosEcn}; + +use crate::{packet::PacketNumber, tracking::SentPacket}; + +/// The number of packets to use for testing a path for ECN capability. +pub const ECN_TEST_COUNT: usize = 10; + +/// The state information related to testing a path for ECN capability. +/// See RFC9000, Appendix A.4. +#[derive(Debug, PartialEq, Clone)] +enum EcnValidationState { + /// The path is currently being tested for ECN capability, with the number of probes sent so + /// far on the path during the ECN validation. + Testing(usize), + /// The validation test has concluded but the path's ECN capability is not yet known. + Unknown, + /// The path is known to **not** be ECN capable. + Failed, + /// The path is known to be ECN capable. + Capable, +} + +impl Default for EcnValidationState { + fn default() -> Self { + EcnValidationState::Testing(0) + } +} + +/// The counts for different ECN marks. +#[derive(PartialEq, Eq, Debug, Clone, Copy, Default)] +pub struct EcnCount(EnumMap); + +impl Deref for EcnCount { + type Target = EnumMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for EcnCount { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl EcnCount { + pub fn new(not_ect: u64, ect0: u64, ect1: u64, ce: u64) -> Self { + // Yes, the enum array order is different from the argument order. + Self(EnumMap::from_array([not_ect, ect1, ect0, ce])) + } + + /// Whether any of the ECN counts are non-zero. + pub fn is_some(&self) -> bool { + self[IpTosEcn::Ect0] > 0 || self[IpTosEcn::Ect1] > 0 || self[IpTosEcn::Ce] > 0 + } +} + +impl Sub for EcnCount { + type Output = EcnCount; + + /// Subtract the ECN counts in `other` from `self`. + fn sub(self, other: EcnCount) -> EcnCount { + let mut diff = EcnCount::default(); + for (ecn, count) in &mut *diff { + *count = self[ecn].saturating_sub(other[ecn]); + } + diff + } +} + +impl AddAssign for EcnCount { + fn add_assign(&mut self, ecn: IpTosEcn) { + self[ecn] += 1; + } +} + +#[derive(Debug, Default)] +pub struct EcnInfo { + /// The current state of ECN validation on this path. + state: EcnValidationState, + + /// The largest ACK seen so far. + largest_acked: PacketNumber, + + /// The ECN counts from the last ACK frame that increased `largest_acked`. + baseline: EcnCount, +} + +impl EcnInfo { + /// Set the baseline (= the ECN counts from the last ACK Frame). + pub fn set_baseline(&mut self, baseline: EcnCount) { + self.baseline = baseline; + } + + /// Expose the current baseline. + pub fn baseline(&self) -> EcnCount { + self.baseline + } + + /// Count the number of packets sent out on this path during ECN validation. + /// Exit ECN validation if the number of packets sent exceeds `ECN_TEST_COUNT`. + /// We do not implement the part of the RFC that says to exit ECN validation if the time since + /// the start of ECN validation exceeds 3 * PTO, since this seems to happen much too quickly. + pub fn on_packet_sent(&mut self) { + if let EcnValidationState::Testing(ref mut probes_sent) = &mut self.state { + *probes_sent += 1; + qdebug!("ECN probing: sent {} probes", probes_sent); + if *probes_sent == ECN_TEST_COUNT { + qdebug!("ECN probing concluded with {} probes sent", probes_sent); + self.state = EcnValidationState::Unknown; + } + } + } + + /// Process ECN counts from an ACK frame. + /// + /// Returns whether ECN counts contain new valid ECN CE marks. + pub fn on_packets_acked( + &mut self, + acked_packets: &[SentPacket], + ack_ecn: Option, + ) -> bool { + let prev_baseline = self.baseline; + + self.validate_ack_ecn_and_update(acked_packets, ack_ecn); + + matches!(self.state, EcnValidationState::Capable) + && (self.baseline - prev_baseline)[IpTosEcn::Ce] > 0 + } + + /// After the ECN validation test has ended, check if the path is ECN capable. + pub fn validate_ack_ecn_and_update( + &mut self, + acked_packets: &[SentPacket], + ack_ecn: Option, + ) { + // RFC 9000, Appendix A.4: + // + // > From the "unknown" state, successful validation of the ECN counts in an ACK frame + // > (see Section 13.4.2.1) causes the ECN state for the path to become "capable", unless + // > no marked packet has been acknowledged. + match self.state { + EcnValidationState::Testing { .. } | EcnValidationState::Failed => return, + EcnValidationState::Unknown | EcnValidationState::Capable => {} + } + + // RFC 9000, Section 13.4.2.1: + // + // > Validating ECN counts from reordered ACK frames can result in failure. An endpoint MUST + // > NOT fail ECN validation as a result of processing an ACK frame that does not increase + // > the largest acknowledged packet number. + let largest_acked = acked_packets.first().expect("must be there").pn; + if largest_acked <= self.largest_acked { + return; + } + + // RFC 9000, Section 13.4.2.1: + // + // > An endpoint that receives an ACK frame with ECN counts therefore validates + // > the counts before using them. It performs this validation by comparing newly + // > received counts against those from the last successfully processed ACK frame. + // + // > If an ACK frame newly acknowledges a packet that the endpoint sent with + // > either the ECT(0) or ECT(1) codepoint set, ECN validation fails if the + // > corresponding ECN counts are not present in the ACK frame. + let Some(ack_ecn) = ack_ecn else { + qwarn!("ECN validation failed, no ECN counts in ACK frame"); + self.state = EcnValidationState::Failed; + return; + }; + + // We always mark with ECT(0) - if at all - so we only need to check for that. + // + // > ECN validation also fails if the sum of the increase in ECT(0) and ECN-CE counts is + // > less than the number of newly acknowledged packets that were originally sent with an + // > ECT(0) marking. + let newly_acked_sent_with_ect0: u64 = acked_packets + .iter() + .filter(|p| p.ecn_mark == IpTosEcn::Ect0) + .count() + .try_into() + .unwrap(); + if newly_acked_sent_with_ect0 == 0 { + qwarn!("ECN validation failed, no ECT(0) packets were newly acked"); + self.state = EcnValidationState::Failed; + return; + } + let ecn_diff = ack_ecn - self.baseline; + let sum_inc = ecn_diff[IpTosEcn::Ect0] + ecn_diff[IpTosEcn::Ce]; + if sum_inc < newly_acked_sent_with_ect0 { + qwarn!( + "ECN validation failed, ACK counted {} new marks, but {} of newly acked packets were sent with ECT(0)", + sum_inc, + newly_acked_sent_with_ect0 + ); + self.state = EcnValidationState::Failed; + } else if ecn_diff[IpTosEcn::Ect1] > 0 { + qwarn!("ECN validation failed, ACK counted ECT(1) marks that were never sent"); + self.state = EcnValidationState::Failed; + } else { + qinfo!("ECN validation succeeded, path is capable",); + self.state = EcnValidationState::Capable; + } + self.baseline = ack_ecn; + self.largest_acked = largest_acked; + } + + /// The ECN mark to use for packets sent on this path. + pub fn ecn_mark(&self) -> IpTosEcn { + match self.state { + EcnValidationState::Testing { .. } | EcnValidationState::Capable => IpTosEcn::Ect0, + EcnValidationState::Failed | EcnValidationState::Unknown => IpTosEcn::NotEct, + } + } +} diff --git a/third_party/rust/neqo-transport/src/events.rs b/third_party/rust/neqo-transport/src/events.rs index a892e384b9..68ef0d6798 100644 --- a/third_party/rust/neqo-transport/src/events.rs +++ b/third_party/rust/neqo-transport/src/events.rs @@ -256,7 +256,7 @@ impl EventProvider for ConnectionEvents { mod tests { use neqo_common::event::Provider; - use crate::{ConnectionError, ConnectionEvent, ConnectionEvents, Error, State, StreamId}; + use crate::{CloseReason, ConnectionEvent, ConnectionEvents, Error, State, StreamId}; #[test] fn event_culling() { @@ -314,7 +314,7 @@ mod tests { evts.send_stream_writable(9.into()); evts.send_stream_stop_sending(10.into(), 55); - evts.connection_state_change(State::Closed(ConnectionError::Transport( + evts.connection_state_change(State::Closed(CloseReason::Transport( Error::StreamStateError, ))); assert_eq!(evts.events().count(), 1); diff --git a/third_party/rust/neqo-transport/src/frame.rs b/third_party/rust/neqo-transport/src/frame.rs index d84eb61ce8..7d009f3b46 100644 --- a/third_party/rust/neqo-transport/src/frame.rs +++ b/third_party/rust/neqo-transport/src/frame.rs @@ -8,13 +8,14 @@ use std::ops::RangeInclusive; -use neqo_common::{qtrace, Decoder}; +use neqo_common::{qtrace, Decoder, Encoder}; use crate::{ cid::MAX_CONNECTION_ID_LEN, + ecn::EcnCount, packet::PacketType, stream_id::{StreamId, StreamType}, - AppError, ConnectionError, Error, Res, TransportError, + AppError, CloseReason, Error, Res, TransportError, }; #[allow(clippy::module_name_repetitions)] @@ -23,7 +24,7 @@ pub type FrameType = u64; pub const FRAME_TYPE_PADDING: FrameType = 0x0; pub const FRAME_TYPE_PING: FrameType = 0x1; pub const FRAME_TYPE_ACK: FrameType = 0x2; -const FRAME_TYPE_ACK_ECN: FrameType = 0x3; +pub const FRAME_TYPE_ACK_ECN: FrameType = 0x3; pub const FRAME_TYPE_RESET_STREAM: FrameType = 0x4; pub const FRAME_TYPE_STOP_SENDING: FrameType = 0x5; pub const FRAME_TYPE_CRYPTO: FrameType = 0x6; @@ -86,11 +87,11 @@ impl CloseError { } } -impl From for CloseError { - fn from(err: ConnectionError) -> Self { +impl From for CloseError { + fn from(err: CloseReason) -> Self { match err { - ConnectionError::Transport(c) => Self::Transport(c.code()), - ConnectionError::Application(c) => Self::Application(c), + CloseReason::Transport(c) => Self::Transport(c.code()), + CloseReason::Application(c) => Self::Application(c), } } } @@ -116,6 +117,7 @@ pub enum Frame<'a> { ack_delay: u64, first_ack_range: u64, ack_ranges: Vec, + ecn_count: Option, }, ResetStream { stream_id: StreamId, @@ -182,7 +184,7 @@ pub enum Frame<'a> { frame_type: u64, // Not a reference as we use this to hold the value. // This is not used in optimized builds anyway. - reason_phrase: Vec, + reason_phrase: String, }, HandshakeDone, AckFrequency { @@ -224,7 +226,7 @@ impl<'a> Frame<'a> { match self { Self::Padding { .. } => FRAME_TYPE_PADDING, Self::Ping => FRAME_TYPE_PING, - Self::Ack { .. } => FRAME_TYPE_ACK, // We don't do ACK ECN. + Self::Ack { .. } => FRAME_TYPE_ACK, Self::ResetStream { .. } => FRAME_TYPE_RESET_STREAM, Self::StopSending { .. } => FRAME_TYPE_STOP_SENDING, Self::Crypto { .. } => FRAME_TYPE_CRYPTO, @@ -426,8 +428,54 @@ impl<'a> Frame<'a> { d(dec.decode_varint()) } - // TODO(ekr@rtfm.com): check for minimal encoding + fn decode_ack<'a>(dec: &mut Decoder<'a>, ecn: bool) -> Res> { + let la = dv(dec)?; + let ad = dv(dec)?; + let nr = dv(dec).and_then(|nr| { + if nr < MAX_ACK_RANGE_COUNT { + Ok(nr) + } else { + Err(Error::TooMuchData) + } + })?; + let fa = dv(dec)?; + let mut arr: Vec = Vec::with_capacity(usize::try_from(nr)?); + for _ in 0..nr { + let ar = AckRange { + gap: dv(dec)?, + range: dv(dec)?, + }; + arr.push(ar); + } + + // Now check for the values for ACK_ECN. + let ecn_count = if ecn { + Some(EcnCount::new(0, dv(dec)?, dv(dec)?, dv(dec)?)) + } else { + None + }; + + Ok(Frame::Ack { + largest_acknowledged: la, + ack_delay: ad, + first_ack_range: fa, + ack_ranges: arr, + ecn_count, + }) + } + + // Check for minimal encoding of frame type. + let pos = dec.offset(); let t = dv(dec)?; + // RFC 9000, Section 12.4: + // + // The Frame Type field uses a variable-length integer encoding [...], + // with one exception. To ensure simple and efficient implementations of + // frame parsing, a frame type MUST use the shortest possible encoding. + if Encoder::varint_len(t) != dec.offset() - pos { + return Err(Error::ProtocolViolation); + } + match t { FRAME_TYPE_PADDING => { let mut length: u16 = 1; @@ -449,40 +497,8 @@ impl<'a> Frame<'a> { _ => return Err(Error::NoMoreData), }, }), - FRAME_TYPE_ACK | FRAME_TYPE_ACK_ECN => { - let la = dv(dec)?; - let ad = dv(dec)?; - let nr = dv(dec).and_then(|nr| { - if nr < MAX_ACK_RANGE_COUNT { - Ok(nr) - } else { - Err(Error::TooMuchData) - } - })?; - let fa = dv(dec)?; - let mut arr: Vec = Vec::with_capacity(usize::try_from(nr)?); - for _ in 0..nr { - let ar = AckRange { - gap: dv(dec)?, - range: dv(dec)?, - }; - arr.push(ar); - } - - // Now check for the values for ACK_ECN. - if t == FRAME_TYPE_ACK_ECN { - dv(dec)?; - dv(dec)?; - dv(dec)?; - } - - Ok(Self::Ack { - largest_acknowledged: la, - ack_delay: ad, - first_ack_range: fa, - ack_ranges: arr, - }) - } + FRAME_TYPE_ACK => decode_ack(dec, false), + FRAME_TYPE_ACK_ECN => decode_ack(dec, true), FRAME_TYPE_STOP_SENDING => Ok(Self::StopSending { stream_id: StreamId::from(dv(dec)?), application_error_code: dv(dec)?, @@ -598,7 +614,7 @@ impl<'a> Frame<'a> { 0 }; // We can tolerate this copy for now. - let reason_phrase = d(dec.decode_vvec())?.to_vec(); + let reason_phrase = String::from_utf8_lossy(d(dec.decode_vvec())?).to_string(); Ok(Self::ConnectionClose { error_code, frame_type, @@ -647,13 +663,14 @@ mod tests { use crate::{ cid::MAX_CONNECTION_ID_LEN, + ecn::EcnCount, frame::{AckRange, Frame, FRAME_TYPE_ACK}, CloseError, Error, StreamId, StreamType, }; fn just_dec(f: &Frame, s: &str) { let encoded = Encoder::from_hex(s); - let decoded = Frame::decode(&mut encoded.as_decoder()).unwrap(); + let decoded = Frame::decode(&mut encoded.as_decoder()).expect("Failed to decode frame"); assert_eq!(*f, decoded); } @@ -679,7 +696,8 @@ mod tests { largest_acknowledged: 0x1234, ack_delay: 0x1235, first_ack_range: 0x1236, - ack_ranges: ar, + ack_ranges: ar.clone(), + ecn_count: None, }; just_dec(&f, "025234523502523601020304"); @@ -689,10 +707,18 @@ mod tests { let mut dec = enc.as_decoder(); assert_eq!(Frame::decode(&mut dec).unwrap_err(), Error::NoMoreData); - // Try to parse ACK_ECN without ECN values + // Try to parse ACK_ECN with ECN values + let ecn_count = Some(EcnCount::new(0, 1, 2, 3)); + let fe = Frame::Ack { + largest_acknowledged: 0x1234, + ack_delay: 0x1235, + first_ack_range: 0x1236, + ack_ranges: ar, + ecn_count, + }; let enc = Encoder::from_hex("035234523502523601020304010203"); let mut dec = enc.as_decoder(); - assert_eq!(Frame::decode(&mut dec).unwrap(), f); + assert_eq!(Frame::decode(&mut dec).unwrap(), fe); } #[test] @@ -899,7 +925,7 @@ mod tests { let f = Frame::ConnectionClose { error_code: CloseError::Transport(0x5678), frame_type: 0x1234, - reason_phrase: vec![0x01, 0x02, 0x03], + reason_phrase: String::from("\x01\x02\x03"), }; just_dec(&f, "1c80005678523403010203"); @@ -910,7 +936,7 @@ mod tests { let f = Frame::ConnectionClose { error_code: CloseError::Application(0x5678), frame_type: 0, - reason_phrase: vec![0x01, 0x02, 0x03], + reason_phrase: String::from("\x01\x02\x03"), }; just_dec(&f, "1d8000567803010203"); @@ -989,14 +1015,14 @@ mod tests { fill: true, }; - just_dec(&f, "4030010203"); + just_dec(&f, "30010203"); // With the length bit. let f = Frame::Datagram { data: &[1, 2, 3], fill: false, }; - just_dec(&f, "403103010203"); + just_dec(&f, "3103010203"); } #[test] @@ -1010,4 +1036,15 @@ mod tests { assert_eq!(Err(Error::TooMuchData), Frame::decode(&mut e.as_decoder())); } + + #[test] + #[should_panic(expected = "Failed to decode frame")] + fn invalid_frame_type_len() { + let f = Frame::Datagram { + data: &[1, 2, 3], + fill: true, + }; + + just_dec(&f, "4030010203"); + } } diff --git a/third_party/rust/neqo-transport/src/lib.rs b/third_party/rust/neqo-transport/src/lib.rs index 5488472b58..723a86980e 100644 --- a/third_party/rust/neqo-transport/src/lib.rs +++ b/third_party/rust/neqo-transport/src/lib.rs @@ -15,10 +15,17 @@ mod cc; mod cid; mod connection; mod crypto; +mod ecn; mod events; mod fc; +#[cfg(fuzzing)] +pub mod frame; +#[cfg(not(fuzzing))] mod frame; mod pace; +#[cfg(fuzzing)] +pub mod packet; +#[cfg(not(fuzzing))] mod packet; mod path; mod qlog; @@ -202,13 +209,17 @@ impl ::std::fmt::Display for Error { pub type AppError = u64; +#[deprecated(note = "use `CloseReason` instead")] +pub type ConnectionError = CloseReason; + +/// Reason why a connection closed. #[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] -pub enum ConnectionError { +pub enum CloseReason { Transport(Error), Application(AppError), } -impl ConnectionError { +impl CloseReason { #[must_use] pub fn app_code(&self) -> Option { match self { @@ -216,9 +227,19 @@ impl ConnectionError { Self::Transport(_) => None, } } + + /// Checks enclosed error for [`Error::NoError`] and + /// [`CloseReason::Application(0)`]. + #[must_use] + pub fn is_error(&self) -> bool { + !matches!( + self, + CloseReason::Transport(Error::NoError) | CloseReason::Application(0), + ) + } } -impl From for ConnectionError { +impl From for CloseReason { fn from(err: CloseError) -> Self { match err { CloseError::Transport(c) => Self::Transport(Error::PeerError(c)), diff --git a/third_party/rust/neqo-transport/src/packet/mod.rs b/third_party/rust/neqo-transport/src/packet/mod.rs index ce611a9664..10d9b13208 100644 --- a/third_party/rust/neqo-transport/src/packet/mod.rs +++ b/third_party/rust/neqo-transport/src/packet/mod.rs @@ -740,6 +740,7 @@ impl<'a> PublicPacket<'a> { } #[must_use] + #[allow(clippy::len_without_is_empty)] // is_empty() would always return false in this case pub fn len(&self) -> usize { self.data.len() } diff --git a/third_party/rust/neqo-transport/src/path.rs b/third_party/rust/neqo-transport/src/path.rs index 50e458ff36..0e4c82b1ca 100644 --- a/third_party/rust/neqo-transport/src/path.rs +++ b/third_party/rust/neqo-transport/src/path.rs @@ -22,6 +22,7 @@ use crate::{ ackrate::{AckRate, PeerAckDelay}, cc::CongestionControlAlgorithm, cid::{ConnectionId, ConnectionIdRef, ConnectionIdStore, RemoteConnectionIdEntry}, + ecn::{EcnCount, EcnInfo}, frame::{FRAME_TYPE_PATH_CHALLENGE, FRAME_TYPE_PATH_RESPONSE, FRAME_TYPE_RETIRE_CONNECTION_ID}, packet::PacketBuilder, recovery::RecoveryToken, @@ -145,15 +146,8 @@ impl Paths { }) } - /// Get a reference to the primary path. This will assert if there is no primary - /// path, which happens at a server prior to receiving a valid Initial packet - /// from a client. So be careful using this method. - pub fn primary(&self) -> PathRef { - self.primary_fallible().unwrap() - } - - /// Get a reference to the primary path. Use this prior to handshake completion. - pub fn primary_fallible(&self) -> Option { + /// Get a reference to the primary path, if one exists. + pub fn primary(&self) -> Option { self.primary.clone() } @@ -242,6 +236,11 @@ impl Paths { /// Returns `true` if the path was migrated. pub fn migrate(&mut self, path: &PathRef, force: bool, now: Instant) -> bool { debug_assert!(!self.is_temporary(path)); + let baseline = self.primary().map_or_else( + || EcnInfo::default().baseline(), + |p| p.borrow().ecn_info.baseline(), + ); + path.borrow_mut().set_ecn_baseline(baseline); if force || path.borrow().is_valid() { path.borrow_mut().set_valid(now); mem::drop(self.select_primary(path)); @@ -307,7 +306,6 @@ impl Paths { /// Set the identified path to be primary. /// This panics if `make_permanent` hasn't been called. pub fn handle_migration(&mut self, path: &PathRef, remote: SocketAddr, now: Instant) { - qtrace!([self.primary().borrow()], "handle_migration"); // The update here needs to match the checks in `Path::received_on`. // Here, we update the remote port number to match the source port on the // datagram that was received. This ensures that we send subsequent @@ -425,10 +423,10 @@ impl Paths { stats.retire_connection_id += 1; } - // Write out any ACK_FREQUENCY frames. - self.primary() - .borrow_mut() - .write_cc_frames(builder, tokens, stats); + if let Some(path) = self.primary() { + // Write out any ACK_FREQUENCY frames. + path.borrow_mut().write_cc_frames(builder, tokens, stats); + } } pub fn lost_retire_cid(&mut self, lost: u64) { @@ -440,11 +438,15 @@ impl Paths { } pub fn lost_ack_frequency(&mut self, lost: &AckRate) { - self.primary().borrow_mut().lost_ack_frequency(lost); + if let Some(path) = self.primary() { + path.borrow_mut().lost_ack_frequency(lost); + } } pub fn acked_ack_frequency(&mut self, acked: &AckRate) { - self.primary().borrow_mut().acked_ack_frequency(acked); + if let Some(path) = self.primary() { + path.borrow_mut().acked_ack_frequency(acked); + } } /// Get an estimate of the RTT on the primary path. @@ -454,7 +456,7 @@ impl Paths { // make a new RTT esimate and interrogate that. // That is more expensive, but it should be rare and breaking encapsulation // is worse, especially as this is only used in tests. - self.primary_fallible() + self.primary() .map_or(RttEstimate::default().estimate(), |p| { p.borrow().rtt().estimate() }) @@ -532,8 +534,6 @@ pub struct Path { rtt: RttEstimate, /// A packet sender for the path, which includes congestion control and a pacer. sender: PacketSender, - /// The DSCP/ECN marking to use for outgoing packets on this path. - tos: IpTos, /// The IP TTL to use for outgoing packets on this path. ttl: u8, @@ -543,7 +543,8 @@ pub struct Path { received_bytes: usize, /// The number of bytes sent on this path. sent_bytes: usize, - + /// The ECN-related state for this path (see RFC9000, Section 13.4 and Appendix A.4) + ecn_info: EcnInfo, /// For logging of events. qlog: NeqoQlog, } @@ -572,14 +573,23 @@ impl Path { challenge: None, rtt: RttEstimate::default(), sender, - tos: IpTos::default(), // TODO: Default to Ect0 when ECN is supported. - ttl: 64, // This is the default TTL on many OSes. + ttl: 64, // This is the default TTL on many OSes. received_bytes: 0, sent_bytes: 0, + ecn_info: EcnInfo::default(), qlog, } } + pub fn set_ecn_baseline(&mut self, baseline: EcnCount) { + self.ecn_info.set_baseline(baseline); + } + + /// Return the DSCP/ECN marking to use for outgoing packets on this path. + pub fn tos(&self) -> IpTos { + self.ecn_info.ecn_mark().into() + } + /// Whether this path is the primary or current path for the connection. pub fn is_primary(&self) -> bool { self.primary @@ -695,8 +705,9 @@ impl Path { } /// Make a datagram. - pub fn datagram>>(&self, payload: V) -> Datagram { - Datagram::new(self.local, self.remote, self.tos, Some(self.ttl), payload) + pub fn datagram>>(&mut self, payload: V) -> Datagram { + self.ecn_info.on_packet_sent(); + Datagram::new(self.local, self.remote, self.tos(), Some(self.ttl), payload) } /// Get local address as `SocketAddr` @@ -959,8 +970,24 @@ impl Path { } /// Record packets as acknowledged with the sender. - pub fn on_packets_acked(&mut self, acked_pkts: &[SentPacket], now: Instant) { + pub fn on_packets_acked( + &mut self, + acked_pkts: &[SentPacket], + ack_ecn: Option, + now: Instant, + ) { debug_assert!(self.is_primary()); + + let ecn_ce_received = self.ecn_info.on_packets_acked(acked_pkts, ack_ecn); + if ecn_ce_received { + let cwnd_reduced = self + .sender + .on_ecn_ce_received(acked_pkts.first().expect("must be there")); + if cwnd_reduced { + self.rtt.update_ack_delay(self.sender.cwnd(), self.mtu()); + } + } + self.sender.on_packets_acked(acked_pkts, &self.rtt, now); } diff --git a/third_party/rust/neqo-transport/src/qlog.rs b/third_party/rust/neqo-transport/src/qlog.rs index a8ad986d2a..715ba85e81 100644 --- a/third_party/rust/neqo-transport/src/qlog.rs +++ b/third_party/rust/neqo-transport/src/qlog.rs @@ -11,7 +11,7 @@ use std::{ time::Duration, }; -use neqo_common::{hex, qinfo, qlog::NeqoQlog, Decoder}; +use neqo_common::{hex, qinfo, qlog::NeqoQlog, Decoder, IpTosEcn}; use qlog::events::{ connectivity::{ConnectionStarted, ConnectionState, ConnectionStateUpdated}, quic::{ @@ -205,7 +205,7 @@ pub fn packet_sent( let mut frames = SmallVec::new(); while d.remaining() > 0 { if let Ok(f) = Frame::decode(&mut d) { - frames.push(QuicFrame::from(&f)); + frames.push(QuicFrame::from(f)); } else { qinfo!("qlog: invalid frame"); break; @@ -293,7 +293,7 @@ pub fn packet_received( while d.remaining() > 0 { if let Ok(f) = Frame::decode(&mut d) { - frames.push(QuicFrame::from(&f)); + frames.push(QuicFrame::from(f)); } else { qinfo!("qlog: invalid frame"); break; @@ -387,21 +387,26 @@ pub fn metrics_updated(qlog: &mut NeqoQlog, updated_metrics: &[QlogMetric]) { #[allow(clippy::too_many_lines)] // Yeah, but it's a nice match. #[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)] // No choice here. -impl From<&Frame<'_>> for QuicFrame { - fn from(frame: &Frame) -> Self { +impl From> for QuicFrame { + fn from(frame: Frame) -> Self { match frame { - // TODO: Add payload length to `QuicFrame::Padding` once - // https://github.com/cloudflare/quiche/pull/1745 is available via the qlog crate. - Frame::Padding { .. } => QuicFrame::Padding, - Frame::Ping => QuicFrame::Ping, + Frame::Padding(len) => QuicFrame::Padding { + length: None, + payload_length: u32::from(len), + }, + Frame::Ping => QuicFrame::Ping { + length: None, + payload_length: None, + }, Frame::Ack { largest_acknowledged, ack_delay, first_ack_range, ack_ranges, + ecn_count, } => { let ranges = - Frame::decode_ack_frame(*largest_acknowledged, *first_ack_range, ack_ranges) + Frame::decode_ack_frame(largest_acknowledged, first_ack_range, &ack_ranges) .ok(); let acked_ranges = ranges.map(|all| { @@ -413,11 +418,13 @@ impl From<&Frame<'_>> for QuicFrame { }); QuicFrame::Ack { - ack_delay: Some(*ack_delay as f32 / 1000.0), + ack_delay: Some(ack_delay as f32 / 1000.0), acked_ranges, - ect1: None, - ect0: None, - ce: None, + ect1: ecn_count.map(|c| c[IpTosEcn::Ect1]), + ect0: ecn_count.map(|c| c[IpTosEcn::Ect0]), + ce: ecn_count.map(|c| c[IpTosEcn::Ce]), + length: None, + payload_length: None, } } Frame::ResetStream { @@ -426,18 +433,22 @@ impl From<&Frame<'_>> for QuicFrame { final_size, } => QuicFrame::ResetStream { stream_id: stream_id.as_u64(), - error_code: *application_error_code, - final_size: *final_size, + error_code: application_error_code, + final_size, + length: None, + payload_length: None, }, Frame::StopSending { stream_id, application_error_code, } => QuicFrame::StopSending { stream_id: stream_id.as_u64(), - error_code: *application_error_code, + error_code: application_error_code, + length: None, + payload_length: None, }, Frame::Crypto { offset, data } => QuicFrame::Crypto { - offset: *offset, + offset, length: data.len() as u64, }, Frame::NewToken { token } => QuicFrame::NewToken { @@ -459,20 +470,20 @@ impl From<&Frame<'_>> for QuicFrame { .. } => QuicFrame::Stream { stream_id: stream_id.as_u64(), - offset: *offset, + offset, length: data.len() as u64, - fin: Some(*fin), + fin: Some(fin), raw: None, }, Frame::MaxData { maximum_data } => QuicFrame::MaxData { - maximum: *maximum_data, + maximum: maximum_data, }, Frame::MaxStreamData { stream_id, maximum_stream_data, } => QuicFrame::MaxStreamData { stream_id: stream_id.as_u64(), - maximum: *maximum_stream_data, + maximum: maximum_stream_data, }, Frame::MaxStreams { stream_type, @@ -482,15 +493,15 @@ impl From<&Frame<'_>> for QuicFrame { NeqoStreamType::BiDi => StreamType::Bidirectional, NeqoStreamType::UniDi => StreamType::Unidirectional, }, - maximum: *maximum_streams, + maximum: maximum_streams, }, - Frame::DataBlocked { data_limit } => QuicFrame::DataBlocked { limit: *data_limit }, + Frame::DataBlocked { data_limit } => QuicFrame::DataBlocked { limit: data_limit }, Frame::StreamDataBlocked { stream_id, stream_data_limit, } => QuicFrame::StreamDataBlocked { stream_id: stream_id.as_u64(), - limit: *stream_data_limit, + limit: stream_data_limit, }, Frame::StreamsBlocked { stream_type, @@ -500,7 +511,7 @@ impl From<&Frame<'_>> for QuicFrame { NeqoStreamType::BiDi => StreamType::Bidirectional, NeqoStreamType::UniDi => StreamType::Unidirectional, }, - limit: *stream_limit, + limit: stream_limit, }, Frame::NewConnectionId { sequence_number, @@ -508,14 +519,14 @@ impl From<&Frame<'_>> for QuicFrame { connection_id, stateless_reset_token, } => QuicFrame::NewConnectionId { - sequence_number: *sequence_number as u32, - retire_prior_to: *retire_prior as u32, + sequence_number: sequence_number as u32, + retire_prior_to: retire_prior as u32, connection_id_length: Some(connection_id.len() as u8), connection_id: hex(connection_id), stateless_reset_token: Some(hex(stateless_reset_token)), }, Frame::RetireConnectionId { sequence_number } => QuicFrame::RetireConnectionId { - sequence_number: *sequence_number as u32, + sequence_number: sequence_number as u32, }, Frame::PathChallenge { data } => QuicFrame::PathChallenge { data: Some(hex(data)), @@ -534,8 +545,8 @@ impl From<&Frame<'_>> for QuicFrame { }, error_code: Some(error_code.code()), error_code_value: Some(0), - reason: Some(String::from_utf8_lossy(reason_phrase).to_string()), - trigger_frame_type: Some(*frame_type), + reason: Some(reason_phrase), + trigger_frame_type: Some(frame_type), }, Frame::HandshakeDone => QuicFrame::HandshakeDone, Frame::AckFrequency { .. } => QuicFrame::Unknown { diff --git a/third_party/rust/neqo-transport/src/recovery.rs b/third_party/rust/neqo-transport/src/recovery.rs index dbea3aaf57..22a635d9f3 100644 --- a/third_party/rust/neqo-transport/src/recovery.rs +++ b/third_party/rust/neqo-transport/src/recovery.rs @@ -21,6 +21,7 @@ use crate::{ ackrate::AckRate, cid::ConnectionIdEntry, crypto::CryptoRecoveryToken, + ecn::EcnCount, packet::PacketNumber, path::{Path, PathRef}, qlog::{self, QlogMetric}, @@ -665,12 +666,14 @@ impl LossRecovery { } /// Returns (acked packets, lost packets) + #[allow(clippy::too_many_arguments)] pub fn on_ack_received( &mut self, primary_path: &PathRef, pn_space: PacketNumberSpace, largest_acked: u64, acked_ranges: R, + ack_ecn: Option, ack_delay: Duration, now: Instant, ) -> (Vec, Vec) @@ -692,10 +695,10 @@ impl LossRecovery { let (acked_packets, any_ack_eliciting) = space.remove_acked(acked_ranges, &mut self.stats.borrow_mut()); - if acked_packets.is_empty() { + let Some(largest_acked_pkt) = acked_packets.first() else { // No new information. return (Vec::new(), Vec::new()); - } + }; // Track largest PN acked per space let prev_largest_acked = space.largest_acked_sent_time; @@ -704,7 +707,6 @@ impl LossRecovery { // If the largest acknowledged is newly acked and any newly acked // packet was ack-eliciting, update the RTT. (-recovery 5.1) - let largest_acked_pkt = acked_packets.first().expect("must be there"); space.largest_acked_sent_time = Some(largest_acked_pkt.time_sent); if any_ack_eliciting && largest_acked_pkt.on_primary_path() { self.rtt_sample( @@ -744,7 +746,7 @@ impl LossRecovery { // when it shouldn't. primary_path .borrow_mut() - .on_packets_acked(&acked_packets, now); + .on_packets_acked(&acked_packets, ack_ecn, now); self.pto_state = None; @@ -1022,7 +1024,7 @@ mod tests { time::{Duration, Instant}, }; - use neqo_common::qlog::NeqoQlog; + use neqo_common::{qlog::NeqoQlog, IpTosEcn}; use test_fixture::{now, DEFAULT_ADDR}; use super::{ @@ -1031,6 +1033,7 @@ mod tests { use crate::{ cc::CongestionControlAlgorithm, cid::{ConnectionId, ConnectionIdEntry}, + ecn::EcnCount, packet::PacketType, path::{Path, PathRef}, rtt::RttEstimate, @@ -1060,6 +1063,7 @@ mod tests { pn_space: PacketNumberSpace, largest_acked: u64, acked_ranges: Vec>, + ack_ecn: Option, ack_delay: Duration, now: Instant, ) -> (Vec, Vec) { @@ -1068,6 +1072,7 @@ mod tests { pn_space, largest_acked, acked_ranges, + ack_ecn, ack_delay, now, ) @@ -1208,6 +1213,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Short, pn, + IpTosEcn::default(), pn_time(pn), true, Vec::new(), @@ -1223,6 +1229,7 @@ mod tests { PacketNumberSpace::ApplicationData, pn, vec![pn..=pn], + None, ACK_DELAY, pn_time(pn) + delay, ); @@ -1233,6 +1240,7 @@ mod tests { lrs.on_packet_sent(SentPacket::new( PacketType::Short, pn, + IpTosEcn::default(), pn_time(pn), true, Vec::new(), @@ -1353,6 +1361,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Short, 0, + IpTosEcn::default(), pn_time(0), true, Vec::new(), @@ -1361,6 +1370,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Short, 1, + IpTosEcn::default(), pn_time(0) + TEST_RTT / 4, true, Vec::new(), @@ -1370,6 +1380,7 @@ mod tests { PacketNumberSpace::ApplicationData, 1, vec![1..=1], + None, ACK_DELAY, pn_time(0) + (TEST_RTT * 5 / 4), ); @@ -1393,6 +1404,7 @@ mod tests { PacketNumberSpace::ApplicationData, 2, vec![2..=2], + None, ACK_DELAY, pn2_ack_time, ); @@ -1422,6 +1434,7 @@ mod tests { PacketNumberSpace::ApplicationData, 4, vec![2..=4], + None, ACK_DELAY, pn_time(4), ); @@ -1450,6 +1463,7 @@ mod tests { PacketNumberSpace::Initial, 0, vec![], + None, Duration::from_millis(0), pn_time(0), ); @@ -1463,6 +1477,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Initial, 0, + IpTosEcn::default(), pn_time(0), true, Vec::new(), @@ -1471,6 +1486,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Handshake, 0, + IpTosEcn::default(), pn_time(1), true, Vec::new(), @@ -1479,6 +1495,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Short, 0, + IpTosEcn::default(), pn_time(2), true, Vec::new(), @@ -1491,10 +1508,25 @@ mod tests { PacketType::Handshake, PacketType::Short, ] { - let sent_pkt = SentPacket::new(*sp, 1, pn_time(3), true, Vec::new(), ON_SENT_SIZE); + let sent_pkt = SentPacket::new( + *sp, + 1, + IpTosEcn::default(), + pn_time(3), + true, + Vec::new(), + ON_SENT_SIZE, + ); let pn_space = PacketNumberSpace::from(sent_pkt.pt); lr.on_packet_sent(sent_pkt); - lr.on_ack_received(pn_space, 1, vec![1..=1], Duration::from_secs(0), pn_time(3)); + lr.on_ack_received( + pn_space, + 1, + vec![1..=1], + None, + Duration::from_secs(0), + pn_time(3), + ); let mut lost = Vec::new(); lr.spaces.get_mut(pn_space).unwrap().detect_lost_packets( pn_time(3), @@ -1516,6 +1548,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Initial, 0, + IpTosEcn::default(), pn_time(3), true, Vec::new(), @@ -1530,6 +1563,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Initial, 0, + IpTosEcn::default(), now(), true, Vec::new(), @@ -1542,6 +1576,7 @@ mod tests { PacketNumberSpace::Initial, 0, vec![0..=0], + None, Duration::new(0, 0), now() + rtt, ); @@ -1549,6 +1584,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Handshake, 0, + IpTosEcn::default(), now(), true, Vec::new(), @@ -1557,6 +1593,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Short, 0, + IpTosEcn::default(), now(), true, Vec::new(), @@ -1594,6 +1631,7 @@ mod tests { lr.on_packet_sent(SentPacket::new( PacketType::Initial, 1, + IpTosEcn::default(), now(), true, Vec::new(), diff --git a/third_party/rust/neqo-transport/src/send_stream.rs b/third_party/rust/neqo-transport/src/send_stream.rs index 8771ec7765..98476e9d18 100644 --- a/third_party/rust/neqo-transport/src/send_stream.rs +++ b/third_party/rust/neqo-transport/src/send_stream.rs @@ -1269,7 +1269,7 @@ impl SendStream { return Err(Error::FinalSizeError); } - let buf = if buf.is_empty() || (self.avail() == 0) { + let buf = if self.avail() == 0 { return Ok(0); } else if self.avail() < buf.len() { if atomic { @@ -1634,20 +1634,16 @@ impl SendStreams { } pub fn remove_terminal(&mut self) { - let map: &mut IndexMap = &mut self.map; - let regular: &mut OrderGroup = &mut self.regular; - let sendordered: &mut BTreeMap = &mut self.sendordered; - - // Take refs to all the items we need to modify instead of &mut - // self to keep the compiler happy (if we use self.map.retain it - // gets upset due to borrows) - map.retain(|stream_id, stream| { + self.map.retain(|stream_id, stream| { if stream.is_terminal() { if stream.is_fair() { match stream.sendorder() { - None => regular.remove(*stream_id), + None => self.regular.remove(*stream_id), Some(sendorder) => { - sendordered.get_mut(&sendorder).unwrap().remove(*stream_id); + self.sendordered + .get_mut(&sendorder) + .unwrap() + .remove(*stream_id); } }; } diff --git a/third_party/rust/neqo-transport/src/sender.rs b/third_party/rust/neqo-transport/src/sender.rs index 3a54851533..abb14d0a25 100644 --- a/third_party/rust/neqo-transport/src/sender.rs +++ b/third_party/rust/neqo-transport/src/sender.rs @@ -97,6 +97,11 @@ impl PacketSender { ) } + /// Called when ECN CE mark received. Returns true if the congestion window was reduced. + pub fn on_ecn_ce_received(&mut self, largest_acked_pkt: &SentPacket) -> bool { + self.cc.on_ecn_ce_received(largest_acked_pkt) + } + pub fn discard(&mut self, pkt: &SentPacket) { self.cc.discard(pkt); } diff --git a/third_party/rust/neqo-transport/src/server.rs b/third_party/rust/neqo-transport/src/server.rs index 96a6244ef1..60909d71e1 100644 --- a/third_party/rust/neqo-transport/src/server.rs +++ b/third_party/rust/neqo-transport/src/server.rs @@ -689,6 +689,13 @@ impl Server { mem::take(&mut self.active).into_iter().collect() } + /// Whether any connections have received new events as a result of calling + /// `process()`. + #[must_use] + pub fn has_active_connections(&self) -> bool { + !self.active.is_empty() + } + pub fn add_to_waiting(&mut self, c: &ActiveConnectionRef) { self.waiting.push_back(c.connection()); } diff --git a/third_party/rust/neqo-transport/src/tracking.rs b/third_party/rust/neqo-transport/src/tracking.rs index bdd0f250c7..6643d516e3 100644 --- a/third_party/rust/neqo-transport/src/tracking.rs +++ b/third_party/rust/neqo-transport/src/tracking.rs @@ -13,18 +13,21 @@ use std::{ time::{Duration, Instant}, }; -use neqo_common::{qdebug, qinfo, qtrace, qwarn}; +use enum_map::Enum; +use neqo_common::{qdebug, qinfo, qtrace, qwarn, IpTosEcn}; use neqo_crypto::{Epoch, TLS_EPOCH_HANDSHAKE, TLS_EPOCH_INITIAL}; use smallvec::{smallvec, SmallVec}; use crate::{ + ecn::EcnCount, + frame::{FRAME_TYPE_ACK, FRAME_TYPE_ACK_ECN}, packet::{PacketBuilder, PacketNumber, PacketType}, recovery::RecoveryToken, stats::FrameStats, }; // TODO(mt) look at enabling EnumMap for this: https://stackoverflow.com/a/44905797/1375574 -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Enum)] pub enum PacketNumberSpace { Initial, Handshake, @@ -134,6 +137,7 @@ impl std::fmt::Debug for PacketNumberSpaceSet { pub struct SentPacket { pub pt: PacketType, pub pn: PacketNumber, + pub ecn_mark: IpTosEcn, ack_eliciting: bool, pub time_sent: Instant, primary_path: bool, @@ -150,6 +154,7 @@ impl SentPacket { pub fn new( pt: PacketType, pn: PacketNumber, + ecn_mark: IpTosEcn, time_sent: Instant, ack_eliciting: bool, tokens: Vec, @@ -158,6 +163,7 @@ impl SentPacket { Self { pt, pn, + ecn_mark, time_sent, ack_eliciting, primary_path: true, @@ -377,6 +383,8 @@ pub struct RecvdPackets { /// Whether we are ignoring packets that arrive out of order /// for the purposes of generating immediate acknowledgment. ignore_order: bool, + // The counts of different ECN marks that have been received. + ecn_count: EcnCount, } impl RecvdPackets { @@ -394,9 +402,15 @@ impl RecvdPackets { unacknowledged_count: 0, unacknowledged_tolerance: DEFAULT_ACK_PACKET_TOLERANCE, ignore_order: false, + ecn_count: EcnCount::default(), } } + /// Get the ECN counts. + pub fn ecn_marks(&mut self) -> &mut EcnCount { + &mut self.ecn_count + } + /// Get the time at which the next ACK should be sent. pub fn ack_time(&self) -> Option { self.ack_time @@ -545,6 +559,10 @@ impl RecvdPackets { } } + /// Length of the worst possible ACK frame, assuming only one range and ECN counts. + /// Note that this assumes one byte for the type and count of extra ranges. + pub const USEFUL_ACK_LEN: usize = 1 + 8 + 8 + 1 + 8 + 3 * 8; + /// Generate an ACK frame for this packet number space. /// /// Unlike other frame generators this doesn't modify the underlying instance @@ -563,10 +581,6 @@ impl RecvdPackets { tokens: &mut Vec, stats: &mut FrameStats, ) { - // The worst possible ACK frame, assuming only one range. - // Note that this assumes one byte for the type and count of extra ranges. - const LONGEST_ACK_HEADER: usize = 1 + 8 + 8 + 1 + 8; - // Check that we aren't delaying ACKs. if !self.ack_now(now, rtt) { return; @@ -578,7 +592,10 @@ impl RecvdPackets { // When congestion limited, ACK-only packets are 255 bytes at most // (`recovery::ACK_ONLY_SIZE_LIMIT - 1`). This results in limiting the // ranges to 13 here. - let max_ranges = if let Some(avail) = builder.remaining().checked_sub(LONGEST_ACK_HEADER) { + let max_ranges = if let Some(avail) = builder + .remaining() + .checked_sub(RecvdPackets::USEFUL_ACK_LEN) + { // Apply a hard maximum to keep plenty of space for other stuff. min(1 + (avail / 16), MAX_ACKS_PER_FRAME) } else { @@ -593,7 +610,11 @@ impl RecvdPackets { .cloned() .collect::>(); - builder.encode_varint(crate::frame::FRAME_TYPE_ACK); + builder.encode_varint(if self.ecn_count.is_some() { + FRAME_TYPE_ACK_ECN + } else { + FRAME_TYPE_ACK + }); let mut iter = ranges.iter(); let Some(first) = iter.next() else { return }; builder.encode_varint(first.largest); @@ -617,6 +638,12 @@ impl RecvdPackets { last = r.smallest; } + if self.ecn_count.is_some() { + builder.encode_varint(self.ecn_count[IpTosEcn::Ect0]); + builder.encode_varint(self.ecn_count[IpTosEcn::Ect1]); + builder.encode_varint(self.ecn_count[IpTosEcn::Ce]); + } + // We've sent an ACK, reset the timer. self.ack_time = None; self.last_ack_time = Some(now); @@ -1134,7 +1161,9 @@ mod tests { .is_some()); let mut builder = PacketBuilder::short(Encoder::new(), false, []); - builder.set_limit(32); + // The code pessimistically assumes that each range needs 16 bytes to express. + // So this won't be enough for a second range. + builder.set_limit(RecvdPackets::USEFUL_ACK_LEN + 8); let mut stats = FrameStats::default(); tracker.write_frame( diff --git a/third_party/rust/neqo-transport/tests/common/mod.rs b/third_party/rust/neqo-transport/tests/common/mod.rs index e36e66f753..ecbbe1c3ce 100644 --- a/third_party/rust/neqo-transport/tests/common/mod.rs +++ b/third_party/rust/neqo-transport/tests/common/mod.rs @@ -84,114 +84,6 @@ pub fn connect(client: &mut Connection, server: &mut Server) -> ActiveConnection connected_server(server) } -// Decode the header of a client Initial packet, returning three values: -// * the entire header short of the packet number, -// * just the DCID, -// * just the SCID, and -// * the protected payload including the packet number. -// Any token is thrown away. -#[must_use] -pub fn decode_initial_header(dgram: &Datagram, role: Role) -> (&[u8], &[u8], &[u8], &[u8]) { - let mut dec = Decoder::new(&dgram[..]); - let type_and_ver = dec.decode(5).unwrap().to_vec(); - // The client sets the QUIC bit, the server might not. - match role { - Role::Client => assert_eq!(type_and_ver[0] & 0xf0, 0xc0), - Role::Server => assert_eq!(type_and_ver[0] & 0xb0, 0x80), - } - let dest_cid = dec.decode_vec(1).unwrap(); - let src_cid = dec.decode_vec(1).unwrap(); - dec.skip_vvec(); // Ignore any the token. - - // Need to read of the length separately so that we can find the packet number. - let payload_len = usize::try_from(dec.decode_varint().unwrap()).unwrap(); - let pn_offset = dgram.len() - dec.remaining(); - ( - &dgram[..pn_offset], - dest_cid, - src_cid, - dec.decode(payload_len).unwrap(), - ) -} - -/// Generate an AEAD and header protection object for a client Initial. -/// Note that this works for QUIC version 1 only. -#[must_use] -pub fn initial_aead_and_hp(dcid: &[u8], role: Role) -> (Aead, HpKey) { - const INITIAL_SALT: &[u8] = &[ - 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, - 0xad, 0xcc, 0xbb, 0x7f, 0x0a, - ]; - let initial_secret = hkdf::extract( - TLS_VERSION_1_3, - TLS_AES_128_GCM_SHA256, - Some( - hkdf::import_key(TLS_VERSION_1_3, INITIAL_SALT) - .as_ref() - .unwrap(), - ), - hkdf::import_key(TLS_VERSION_1_3, dcid).as_ref().unwrap(), - ) - .unwrap(); - - let secret = hkdf::expand_label( - TLS_VERSION_1_3, - TLS_AES_128_GCM_SHA256, - &initial_secret, - &[], - match role { - Role::Client => "client in", - Role::Server => "server in", - }, - ) - .unwrap(); - ( - Aead::new(TLS_VERSION_1_3, TLS_AES_128_GCM_SHA256, &secret, "quic ").unwrap(), - HpKey::extract(TLS_VERSION_1_3, TLS_AES_128_GCM_SHA256, &secret, "quic hp").unwrap(), - ) -} - -// Remove header protection, returning the unmasked header and the packet number. -#[must_use] -pub fn remove_header_protection(hp: &HpKey, header: &[u8], payload: &[u8]) -> (Vec, u64) { - // Make a copy of the header that can be modified. - let mut fixed_header = header.to_vec(); - let pn_offset = header.len(); - // Save 4 extra in case the packet number is that long. - fixed_header.extend_from_slice(&payload[..4]); - - // Sample for masking and apply the mask. - let mask = hp.mask(&payload[4..20]).unwrap(); - fixed_header[0] ^= mask[0] & 0xf; - let pn_len = 1 + usize::from(fixed_header[0] & 0x3); - for i in 0..pn_len { - fixed_header[pn_offset + i] ^= mask[1 + i]; - } - // Trim down to size. - fixed_header.truncate(pn_offset + pn_len); - // The packet number should be 1. - let pn = Decoder::new(&fixed_header[pn_offset..]) - .decode_uint(pn_len) - .unwrap(); - - (fixed_header, pn) -} - -pub fn apply_header_protection(hp: &HpKey, packet: &mut [u8], pn_bytes: Range) { - let sample_start = pn_bytes.start + 4; - let sample_end = sample_start + 16; - let mask = hp.mask(&packet[sample_start..sample_end]).unwrap(); - qtrace!( - "sample={} mask={}", - hex_with_len(&packet[sample_start..sample_end]), - hex_with_len(&mask) - ); - packet[0] ^= mask[0] & 0xf; - for i in 0..(pn_bytes.end - pn_bytes.start) { - packet[pn_bytes.start + i] ^= mask[1 + i]; - } -} - /// Scrub through client events to find a resumption token. pub fn find_ticket(client: &mut Connection) -> ResumptionToken { client diff --git a/third_party/rust/neqo-transport/tests/connection.rs b/third_party/rust/neqo-transport/tests/connection.rs index b8877b946d..3cc711f80b 100644 --- a/third_party/rust/neqo-transport/tests/connection.rs +++ b/third_party/rust/neqo-transport/tests/connection.rs @@ -6,12 +6,16 @@ mod common; -use common::{ - apply_header_protection, decode_initial_header, initial_aead_and_hp, remove_header_protection, -}; use neqo_common::{Datagram, Decoder, Encoder, Role}; -use neqo_transport::{ConnectionError, ConnectionParameters, Error, State, Version}; -use test_fixture::{default_client, default_server, new_client, now, split_datagram}; +use neqo_transport::{CloseReason, ConnectionParameters, Error, State, Version}; +use test_fixture::{ + default_client, default_server, + header_protection::{ + apply_header_protection, decode_initial_header, initial_aead_and_hp, + remove_header_protection, + }, + new_client, now, split_datagram, +}; #[test] fn connect() { @@ -58,8 +62,8 @@ fn truncate_long_packet() { /// Test that reordering parts of the server Initial doesn't change things. #[test] fn reorder_server_initial() { - // A simple ACK frame for a single packet with packet number 0. - const ACK_FRAME: &[u8] = &[0x02, 0x00, 0x00, 0x00, 0x00]; + // A simple ACK_ECN frame for a single packet with packet number 0 with a single ECT(0) mark. + const ACK_FRAME: &[u8] = &[0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00]; let mut client = new_client( ConnectionParameters::default().versions(Version::Version1, vec![Version::Version1]), @@ -68,12 +72,13 @@ fn reorder_server_initial() { let client_initial = client.process_output(now()); let (_, client_dcid, _, _) = - decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client); + decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap(); let client_dcid = client_dcid.to_owned(); let server_packet = server.process(client_initial.as_dgram_ref(), now()).dgram(); let (server_initial, server_hs) = split_datagram(server_packet.as_ref().unwrap()); - let (protected_header, _, _, payload) = decode_initial_header(&server_initial, Role::Server); + let (protected_header, _, _, payload) = + decode_initial_header(&server_initial, Role::Server).unwrap(); // Now decrypt the packet. let (aead, hp) = initial_aead_and_hp(&client_dcid, Role::Server); @@ -130,7 +135,7 @@ fn reorder_server_initial() { fn set_payload(server_packet: &Option, client_dcid: &[u8], payload: &[u8]) -> Datagram { let (server_initial, _server_hs) = split_datagram(server_packet.as_ref().unwrap()); let (protected_header, _, _, orig_payload) = - decode_initial_header(&server_initial, Role::Server); + decode_initial_header(&server_initial, Role::Server).unwrap(); // Now decrypt the packet. let (aead, hp) = initial_aead_and_hp(client_dcid, Role::Server); @@ -168,14 +173,14 @@ fn packet_without_frames() { let client_initial = client.process_output(now()); let (_, client_dcid, _, _) = - decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client); + decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap(); let server_packet = server.process(client_initial.as_dgram_ref(), now()).dgram(); let modified = set_payload(&server_packet, client_dcid, &[]); client.process_input(&modified, now()); assert_eq!( client.state(), - &State::Closed(ConnectionError::Transport(Error::ProtocolViolation)) + &State::Closed(CloseReason::Transport(Error::ProtocolViolation)) ); } @@ -189,7 +194,7 @@ fn packet_with_only_padding() { let client_initial = client.process_output(now()); let (_, client_dcid, _, _) = - decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client); + decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap(); let server_packet = server.process(client_initial.as_dgram_ref(), now()).dgram(); let modified = set_payload(&server_packet, client_dcid, &[0]); @@ -208,7 +213,7 @@ fn overflow_crypto() { let client_initial = client.process_output(now()).dgram(); let (_, client_dcid, _, _) = - decode_initial_header(client_initial.as_ref().unwrap(), Role::Client); + decode_initial_header(client_initial.as_ref().unwrap(), Role::Client).unwrap(); let client_dcid = client_dcid.to_owned(); let server_packet = server.process(client_initial.as_ref(), now()).dgram(); @@ -217,7 +222,8 @@ fn overflow_crypto() { // Now decrypt the server packet to get AEAD and HP instances. // We won't be using the packet, but making new ones. let (aead, hp) = initial_aead_and_hp(&client_dcid, Role::Server); - let (_, server_dcid, server_scid, _) = decode_initial_header(&server_initial, Role::Server); + let (_, server_dcid, server_scid, _) = + decode_initial_header(&server_initial, Role::Server).unwrap(); // Send in 100 packets, each with 1000 bytes of crypto frame data each, // eventually this will overrun the buffer we keep for crypto data. @@ -260,10 +266,7 @@ fn overflow_crypto() { client.process_input(&dgram, now()); if let State::Closing { error, .. } = client.state() { assert!( - matches!( - error, - ConnectionError::Transport(Error::CryptoBufferExceeded), - ), + matches!(error, CloseReason::Transport(Error::CryptoBufferExceeded),), "the connection need to abort on crypto buffer" ); assert!(pn > 64, "at least 64000 bytes of data is buffered"); diff --git a/third_party/rust/neqo-transport/tests/network.rs b/third_party/rust/neqo-transport/tests/network.rs index 27e5a83cd6..68a835a436 100644 --- a/third_party/rust/neqo-transport/tests/network.rs +++ b/third_party/rust/neqo-transport/tests/network.rs @@ -6,7 +6,7 @@ use std::{ops::Range, time::Duration}; -use neqo_transport::{ConnectionError, ConnectionParameters, Error, State}; +use neqo_transport::{CloseReason, ConnectionParameters, Error, State}; use test_fixture::{ boxed, sim::{ @@ -48,10 +48,10 @@ simulate!( idle_timeout, [ ConnectionNode::default_client(boxed![ReachState::new(State::Closed( - ConnectionError::Transport(Error::IdleTimeout) + CloseReason::Transport(Error::IdleTimeout) ))]), ConnectionNode::default_server(boxed![ReachState::new(State::Closed( - ConnectionError::Transport(Error::IdleTimeout) + CloseReason::Transport(Error::IdleTimeout) ))]), ] ); @@ -62,7 +62,7 @@ simulate!( ConnectionNode::new_client( ConnectionParameters::default().idle_timeout(weeks(1000)), boxed![ReachState::new(State::Confirmed),], - boxed![ReachState::new(State::Closed(ConnectionError::Transport( + boxed![ReachState::new(State::Closed(CloseReason::Transport( Error::IdleTimeout )))] ), @@ -71,7 +71,7 @@ simulate!( ConnectionNode::new_server( ConnectionParameters::default().idle_timeout(weeks(1000)), boxed![ReachState::new(State::Confirmed),], - boxed![ReachState::new(State::Closed(ConnectionError::Transport( + boxed![ReachState::new(State::Closed(CloseReason::Transport( Error::IdleTimeout )))] ), diff --git a/third_party/rust/neqo-transport/tests/retry.rs b/third_party/rust/neqo-transport/tests/retry.rs index 36eff71e7b..3f95511c3e 100644 --- a/third_party/rust/neqo-transport/tests/retry.rs +++ b/third_party/rust/neqo-transport/tests/retry.rs @@ -14,14 +14,18 @@ use std::{ time::Duration, }; -use common::{ - apply_header_protection, connected_server, decode_initial_header, default_server, - generate_ticket, initial_aead_and_hp, remove_header_protection, -}; +use common::{connected_server, default_server, generate_ticket}; use neqo_common::{hex_with_len, qdebug, qtrace, Datagram, Encoder, Role}; use neqo_crypto::AuthenticationStatus; -use neqo_transport::{server::ValidateAddress, ConnectionError, Error, State, StreamType}; -use test_fixture::{assertions, datagram, default_client, now, split_datagram}; +use neqo_transport::{server::ValidateAddress, CloseReason, Error, State, StreamType}; +use test_fixture::{ + assertions, datagram, default_client, + header_protection::{ + apply_header_protection, decode_initial_header, initial_aead_and_hp, + remove_header_protection, + }, + now, split_datagram, +}; #[test] fn retry_basic() { @@ -400,7 +404,7 @@ fn mitm_retry() { // rewriting the header to remove the token, and then re-encrypting. let client_initial2 = client_initial2.unwrap(); let (protected_header, d_cid, s_cid, payload) = - decode_initial_header(&client_initial2, Role::Client); + decode_initial_header(&client_initial2, Role::Client).unwrap(); // Now we have enough information to make keys. let (aead, hp) = initial_aead_and_hp(d_cid, Role::Client); @@ -465,7 +469,7 @@ fn mitm_retry() { assert!(matches!( *client.state(), State::Closing { - error: ConnectionError::Transport(Error::ProtocolViolation), + error: CloseReason::Transport(Error::ProtocolViolation), .. } )); diff --git a/third_party/rust/neqo-transport/tests/server.rs b/third_party/rust/neqo-transport/tests/server.rs index 7388e0fee7..4740d26ded 100644 --- a/third_party/rust/neqo-transport/tests/server.rs +++ b/third_party/rust/neqo-transport/tests/server.rs @@ -8,21 +8,22 @@ mod common; use std::{cell::RefCell, mem, net::SocketAddr, rc::Rc, time::Duration}; -use common::{ - apply_header_protection, connect, connected_server, decode_initial_header, default_server, - find_ticket, generate_ticket, initial_aead_and_hp, new_server, remove_header_protection, -}; +use common::{connect, connected_server, default_server, find_ticket, generate_ticket, new_server}; use neqo_common::{qtrace, Datagram, Decoder, Encoder, Role}; use neqo_crypto::{ generate_ech_keys, AllowZeroRtt, AuthenticationStatus, ZeroRttCheckResult, ZeroRttChecker, }; use neqo_transport::{ server::{ActiveConnectionRef, Server, ValidateAddress}, - Connection, ConnectionError, ConnectionParameters, Error, Output, State, StreamType, Version, + CloseReason, Connection, ConnectionParameters, Error, Output, State, StreamType, Version, }; use test_fixture::{ - assertions, datagram, default_client, new_client, now, split_datagram, - CountingConnectionIdGenerator, + assertions, datagram, default_client, + header_protection::{ + apply_header_protection, decode_initial_header, initial_aead_and_hp, + remove_header_protection, + }, + new_client, now, split_datagram, CountingConnectionIdGenerator, }; /// Take a pair of connections in any state and complete the handshake. @@ -389,7 +390,7 @@ fn bad_client_initial() { let mut server = default_server(); let dgram = client.process(None, now()).dgram().expect("a datagram"); - let (header, d_cid, s_cid, payload) = decode_initial_header(&dgram, Role::Client); + let (header, d_cid, s_cid, payload) = decode_initial_header(&dgram, Role::Client).unwrap(); let (aead, hp) = initial_aead_and_hp(d_cid, Role::Client); let (fixed_header, pn) = remove_header_protection(&hp, header, payload); let payload = &payload[(fixed_header.len() - header.len())..]; @@ -462,13 +463,13 @@ fn bad_client_initial() { assert_ne!(delay, Duration::from_secs(0)); assert!(matches!( *client.state(), - State::Draining { error: ConnectionError::Transport(Error::PeerError(code)), .. } if code == Error::ProtocolViolation.code() + State::Draining { error: CloseReason::Transport(Error::PeerError(code)), .. } if code == Error::ProtocolViolation.code() )); for server in server.active_connections() { assert_eq!( *server.borrow().state(), - State::Closed(ConnectionError::Transport(Error::ProtocolViolation)) + State::Closed(CloseReason::Transport(Error::ProtocolViolation)) ); } @@ -477,6 +478,65 @@ fn bad_client_initial() { assert_eq!(res, Output::None); } +#[test] +fn bad_client_initial_connection_close() { + let mut client = default_client(); + let mut server = default_server(); + + let dgram = client.process(None, now()).dgram().expect("a datagram"); + let (header, d_cid, s_cid, payload) = decode_initial_header(&dgram, Role::Client).unwrap(); + let (aead, hp) = initial_aead_and_hp(d_cid, Role::Client); + let (_, pn) = remove_header_protection(&hp, header, payload); + + let mut payload_enc = Encoder::with_capacity(1200); + payload_enc.encode(&[0x1c, 0x01, 0x00, 0x00]); // Add a CONNECTION_CLOSE frame. + + // Make a new header with a 1 byte packet number length. + let mut header_enc = Encoder::new(); + header_enc + .encode_byte(0xc0) // Initial with 1 byte packet number. + .encode_uint(4, Version::default().wire_version()) + .encode_vec(1, d_cid) + .encode_vec(1, s_cid) + .encode_vvec(&[]) + .encode_varint(u64::try_from(payload_enc.len() + aead.expansion() + 1).unwrap()) + .encode_byte(u8::try_from(pn).unwrap()); + + let mut ciphertext = header_enc.as_ref().to_vec(); + ciphertext.resize(header_enc.len() + payload_enc.len() + aead.expansion(), 0); + let v = aead + .encrypt( + pn, + header_enc.as_ref(), + payload_enc.as_ref(), + &mut ciphertext[header_enc.len()..], + ) + .unwrap(); + assert_eq!(header_enc.len() + v.len(), ciphertext.len()); + // Pad with zero to get up to 1200. + ciphertext.resize(1200, 0); + + apply_header_protection( + &hp, + &mut ciphertext, + (header_enc.len() - 1)..header_enc.len(), + ); + let bad_dgram = Datagram::new( + dgram.source(), + dgram.destination(), + dgram.tos(), + dgram.ttl(), + ciphertext, + ); + + // The server should ignore this and go to Draining. + let mut now = now(); + let response = server.process(Some(&bad_dgram), now); + now += response.callback(); + let response = server.process(None, now); + assert_eq!(response, Output::None); +} + #[test] fn version_negotiation_ignored() { let mut server = default_server(); @@ -774,3 +834,16 @@ fn ech() { .ech_accepted() .unwrap()); } + +#[test] +fn has_active_connections() { + let mut server = default_server(); + let mut client = default_client(); + + assert!(!server.has_active_connections()); + + let initial = client.process(None, now()); + let _ = server.process(initial.as_dgram_ref(), now()).dgram(); + + assert!(server.has_active_connections()); +} diff --git a/third_party/rust/nix/.cargo-checksum.json b/third_party/rust/nix/.cargo-checksum.json index d48e123da2..3cd04958ea 100644 --- a/third_party/rust/nix/.cargo-checksum.json +++ b/third_party/rust/nix/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"92468d08ccd20acf93bac25d983dbaedbd6dafbfdebf45d670a557e1dd993650","Cargo.toml":"8e68a73dcb2ac8fd7a01b714c3c08c0148d0cbeb1b8a2bbb30ff10cf0332b505","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"693748b472aa697105dbaf37ad95e41b9b3ed6480533e03a5a93b10ec70c987a","src/dir.rs":"d40e2bc1df553898e718de552ddb57a160b9957b7d6a0f7e27e3e7fe6af536ab","src/env.rs":"028bc5e20139ebba418a655a2978a53335dc7680bf1de43d2c8333dd72cfa5c4","src/errno.rs":"3c2935cc3238c13a545ab8ceb6a8aa9fd03a9cbf72be041e9ea032f6ee19c2f4","src/fcntl.rs":"8cda1abc82c562b2340b3d27176b674b65d0e1c4bf888e7700c6b50e63c3bf0d","src/features.rs":"5381d43a7759c0bf4a26fc25c602d507beafa85282764bdbae6eff59f98fd16d","src/ifaddrs.rs":"377865eb48040d28c392a1aec0221320108e3392ea285d23405ae2cfa5c54b20","src/kmod.rs":"d2ef26c35db790e589f6418c1631aa48b01d4ea5674e050c12d1cfa7a18681ef","src/lib.rs":"571f418caf6a9646939ae4976ec4bde5f9325e9b4320715c9586590b9d8d4963","src/macros.rs":"73ab3b56f4b7cd08d3c70f035cd74bcbdac17ff05946adc875e05fd93280eb7e","src/mount/bsd.rs":"9f12470d33d9b3d18fdba5a10952f6e76b254df3d8794f296437d266db9623c4","src/mount/linux.rs":"6b0ea0c4598f5537e2dc57bdad6d3acc86e29d258aef3a639e1a2308f38bdb0e","src/mount/mod.rs":"ba9f60eb831224ab73bdd87e00e15d13b9ce9efb70b18bf8f3fe60406d522b3e","src/mqueue.rs":"0c78ef1a52c2df05a48b390707764dfca27c056033e01d604a1aa91058c7e9b4","src/net/if_.rs":"fa7413a9676e552b3fa0576081b83ac91278bb0d7240b7cdd962ea911336bba0","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"8b26383af51ff0733e07e6a5a2e174462e8849b1118ca12bdf3540d40a298602","src/pty.rs":"6a1122c4e7ea236cc4e1e36e2eb587eddf1e323edacdbcdd3b3c1619a60eedbf","src/sched.rs":"217055e50a54398e5b75a247e1be9a81a764aadd0267bcf6367f633e9b277f84","src/sys/aio.rs":"3e2e93dff85180a98b2b09b1ea926f89ee17d235c60fd2a96adf0ff7db601e5c","src/sys/epoll.rs":"5c45733ea19802443cc3f9e21766013d4ff0125a52dbf5f5a13f10ff19914e1e","src/sys/event.rs":"9b3b02c42f471e3d9f974be1b60aab11ff4d1fc79692c3d40991f0c22ca9ea83","src/sys/eventfd.rs":"22c1205c948aeb29f7a8a0f298644eb393778585ecbd2091d40559e0ed2de06b","src/sys/inotify.rs":"68b80856937286a23917638ed8f5fc057e396fe7c4f4d1178865e720ba7dba95","src/sys/ioctl/bsd.rs":"bbd02e30b0a78c1cb22777d9b00cfcbba9c68505cffc06118ac68474cf6fea39","src/sys/ioctl/linux.rs":"2aec4b3b3beb8119b9bb0c8001b9bb66cba3f2ff778c432e62f2da4243787184","src/sys/ioctl/mod.rs":"80e683efac7d1e2bd88680f028370f7c778e6a5097cae7845566bc8f43f4ff4f","src/sys/memfd.rs":"e2653a3c476585e993d9e8551cd0f991ba141c6bb46d9ece7fa6fd5cdeb862ae","src/sys/mman.rs":"4604656656a061606f99ff2f117c8f7463cd87aedaa4b3de5de863056bec5499","src/sys/mod.rs":"f5a5f1b51bbd2c865bbda2652bf0d2fd38e0773bd1a37460869c5a7008d27f03","src/sys/personality.rs":"8fbd8b522b8be4591a4cf25cba023884d3ad39b26666708d43eb79b81bf1c203","src/sys/prctl.rs":"d5b695099d4ac1b44e552988f488d7b88d285e68968ac29b93c153da52acd2bf","src/sys/pthread.rs":"258cdf7ff0b61a4afa6d228109e4cb4fb88d859bb8dfe6c959d95130fb010906","src/sys/ptrace/bsd.rs":"4c590d8f023ff52f396f8b6f2150c08e5c9486d3088d9c173db33a70d616b800","src/sys/ptrace/linux.rs":"b14114c4cbefd58f9df48e93e47d8f82992167942d4e683018cd31ceed184bc6","src/sys/ptrace/mod.rs":"3b5e4cc9cf447e989f40c73cb1951a4705322852009023c5a3d7e39ec1e9c39b","src/sys/quota.rs":"421ff70a0749dd0cea37a22a971bf3e9474f627bfa0e37874d9893787271996b","src/sys/reboot.rs":"eacdf57694a6629fb05787e16450446102a62818274495f2ad4e445807d09221","src/sys/resource.rs":"84eba41f288c97b4ab9060a6046d0d34e66a1f8e12655032c60a703280cca832","src/sys/select.rs":"2520086330bc1978a7db183bee92d96ba2711a4505839179a5f082ad555045b2","src/sys/sendfile.rs":"2075cea1ea5967b5de18e5cecb94bc041ff2675f7eb9e223051aa8a52dd8f733","src/sys/signal.rs":"39492bd9a98a48616a2f66a717def527574c6429251b533d8406d2b25cc2cb3f","src/sys/signalfd.rs":"af9eee01d712e48609fddf6b0ec332cd5f80b9940081b4c2e16cc338e959b5f3","src/sys/socket/addr.rs":"1b6f4e1ca16004cd5fa511264076b2c24ccc9cf3d7727157a0fabc62c47fe94a","src/sys/socket/mod.rs":"e65112b3b54905166b7a412fd9811e1e123c5eb1b3b46286937082fa6e86973d","src/sys/socket/sockopt.rs":"386bc08c0faf49a9d0ef99c70538c66b7d426d3deeb7b0ebedee1ef917d7bafc","src/sys/stat.rs":"3928598e6428d7e44b42d36aeb59ac353eaf0270801a6ac72c511804c5fdf358","src/sys/statfs.rs":"852c7e68c094ea8b1f978ee811c1e0bf6a38661c7a07114527697e7aae584dff","src/sys/statvfs.rs":"f699280f3ee2645ce39631d404355e7b49818849c4afa0bdf4f5020931cb1bef","src/sys/sysinfo.rs":"b4519b1ca091c9dbe94d2a6fd6304944bf3df5626973d2c6884022559706f0d9","src/sys/termios.rs":"7c0d9f4bc0062a510cf0f799264f807530c3d1e9e23a0d405d595f395ad7e01c","src/sys/time.rs":"c991d69a892cd7201c53d1399533e45802d581a1afa109016014aa9872d8db53","src/sys/timer.rs":"8c10f0e7cfac857ad00460be30bc68b957909cc9296e70718d3b5d4a0babafde","src/sys/timerfd.rs":"8958120030ed7bb58028b75e7e1829d4d231fa0da2c65f9335df7b7f1e0f6074","src/sys/uio.rs":"0ed960748eb4a85ce8f8413ab478d451f4460e85130cc3b803c85d72c057a529","src/sys/utsname.rs":"0cdda0cc111caaa0e4ebe2d4588bdc825d878e5bcb7a9136073b15f87a20e11f","src/sys/wait.rs":"c4c19ce13ea96c47fd51e227a1982d2aaafdb6b75edd726159848dd617f70da8","src/time.rs":"d4e0872361a57810837f5bd790cbca3a2b9db1ac4694a3c52d1564ad3532d3be","src/ucontext.rs":"b8f2e04757a9c2bc38c3b1e259d3a013da8a730fe9bfbe5487637395681b43d3","src/unistd.rs":"e9d24b6490d0578fc3e31200023e131df9471c09b7553b452a9ad76399eea753","test/common/mod.rs":"1d7e28e3635754664cd056f3a1079232ff5c118df619e1d0551a9972eb0b3cd6","test/sys/mod.rs":"87b2891d83067ff21f72b8ff7fde3019dc45b6877282ac278b6da151de45c7a7","test/sys/test_aio.rs":"ea9c0af6632739439d7f8187d2c82aeca7ac177d817210815b1a3edcd7a84e9b","test/sys/test_aio_drop.rs":"614070155fa16a979b7341d001639c5ce24a1d6f632c3abce45a5a6d49c4039b","test/sys/test_epoll.rs":"c30b08d665a1fe7d7a04fe51d50ec78fc74c2ac707ae0f95f82104d5c76ceaf2","test/sys/test_inotify.rs":"a141b9a995892547b51ceeb6761a70a6b86d37e8f38d13ea2c497b81b4b0f49f","test/sys/test_ioctl.rs":"00ccc5afb665e533a0a4b6d6a6be438bcaea19fce335390feef4e91d17b3036c","test/sys/test_mman.rs":"fe9019927ed3ca51d2d59d3305a53cc31797a1460044d24e2631f120c9289552","test/sys/test_prctl.rs":"9c3d0fb16a41c3fd80541b313c2bb63de75634ad4711a71af106e58b0cec9ea8","test/sys/test_pthread.rs":"ace36a2f5587f1874854281b4fd84e4e4d892a1e3c5cc38ced57975739522ad6","test/sys/test_ptrace.rs":"0385eebc8b1b8c72f655b745769decd9143ad83018198375982da0896310456b","test/sys/test_select.rs":"2843bc2484d51ba335567cc50bbc4eb6848ac6c6702ced42b177ffe04b49f7f3","test/sys/test_signal.rs":"19c267ffe9a37452719c2b030c62ab8e123d20e3f6ba4da6902375283e3b9593","test/sys/test_signalfd.rs":"0e1060143e2612c490bc3d0168d0bbb042ef55e3f1d91d2578b9e42e4310a14d","test/sys/test_socket.rs":"de724f58d1d703d28be1d4e35fd72df41f835082cdcb4fb579330d0be31dc74f","test/sys/test_sockopt.rs":"4a7fbb08719ae99803280f8af94e134ad90d92bf3ca4fbee0ef0ab398aadecea","test/sys/test_stat.rs":"6630a28217fd708bb84cd4f7e7101836b74f2420f9888923fdab664ccc331c1d","test/sys/test_sysinfo.rs":"ffd49bc96375914a2c4a4a59730cae8072f85771e2c4a80d3403df38d967e272","test/sys/test_termios.rs":"f38dfe45ab4ac9760b1d8c49e18da900d544927080a4a0bbb02b0c854c130455","test/sys/test_timerfd.rs":"cfed3abf58118611d08f6985251a7739cff67108e11214222a1d2394a3a026ce","test/sys/test_uio.rs":"90d973858f3e303c9fb99bc49d8d9a2e184be17e4e771cf3682af80b2ebd1533","test/sys/test_wait.rs":"6fd59fffeeb09ff620c359baefd062ba777598982b6cb001ccc07b6bc7605493","test/test.rs":"58a302e9055555806942c35e0edd0aaa63b2ebb3205c9a7e29491b726a5e2abe","test/test_clearenv.rs":"45ca548035b3c20ec87314715feaba2be973709a635d85b8cde46fd1d9f1ecd4","test/test_dir.rs":"ae3c11c58cb06da6557aa2a839c6653c54cd7724283fffe9df5a5d3feabdd89a","test/test_fcntl.rs":"7a23635451ed4a7b061cdc3015723c803c901e665e2beffde726b7f20ddf61d2","test/test_kmod/hello_mod/Makefile":"0219f7bce0603f97d997fb377ca071966c90333ecc665e78a54dfeb97a9c811b","test/test_kmod/hello_mod/hello.c":"bcac6b19c5bd807e1f3878c15e426acc85785a8ade9840c3bb4d068635c9188c","test/test_kmod/mod.rs":"b4ae25841c2f06f32de9f1acd8230eeccd7095721302ebe78ad454e4e4f9c783","test/test_mount.rs":"7d04b7e0f0f56e8129a0e68a6a338d7d46fdedde863dae4732d3c899e7864c66","test/test_mq.rs":"84dffb2201e2a4bb19f476fa7c23bbc2615453d27e5b958d3841ff371b6faa81","test/test_net.rs":"f2912327ebb2a3d37e6cff02a5ac3106cf889cc5c74404db4ef0034059ba26f1","test/test_nix_path.rs":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","test/test_nmount.rs":"d6c112547bb80968170b5497cda4b6cbf69dabec6f51d494bd52298995ceff18","test/test_poll.rs":"d6eef82848734e47cc9e1f1ce521e35587e63f69876baea660ef22eebc2b1ea6","test/test_pty.rs":"4184e446af7a365ead628596cd77ad168c835a5dea6abca3ee614d86a4412dda","test/test_resource.rs":"40aef790ab745cec31a4b333d2ca406b462aa9bdf4a6d3756371e498b8d51e9a","test/test_sched.rs":"c4579bd376fab8816e63b07fa9ace31dc08e63ebb7c855a2c450698090d1d1e8","test/test_sendfile.rs":"f7d52f6aa680b5667b966d5c046917ba43924e9b9fca6adbcf68479459e06366","test/test_stat.rs":"c407ca47a5258750076d041afad2f6add4c3563be36628bde1c5b314f5d0765d","test/test_time.rs":"f7a21b1e279e60e84909d5dadda97ded66d3326b131fe317badf9af0a1b50335","test/test_timer.rs":"3ae20d364f075d2811f3ff94eda9886682cc21d8807656007d2464fe36d1e361","test/test_unistd.rs":"3ef7b335639747b6d57a04c2264a38ad379b680cebc0b8d8b8e247610630e58a"},"package":"2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"} \ No newline at end of file +{"files":{"CHANGELOG.md":"67c8efb2646c390f76029cf2fbb6205bd23e6e15c149ed32a1549e25bef1babe","Cargo.toml":"cd8795ba96b904a16c840e69c94b9493d8032b966579e4589b9adb35efdfec5a","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"de89eb5b6e00eff6eb3043475da16abf3ae63906cbe3103a450c4bf27cad3f3e","build.rs":"f4b3c533039fe39f167251372b4f378ebef43203654f0ac2340dc0e222206787","src/dir.rs":"10a6ff94e56b849ac8ea762905efa85d11812e5539587ce8e5cce932961c7141","src/env.rs":"9d1e7d52c6c5f46d790a8cbc6d5d2ff9097fb7728594c518d51824ebfb70c9b3","src/errno.rs":"204dd49244d461da6827142386a6b491aaeb6c4ca3760bbe9df5fd2f90e9f4ea","src/fcntl.rs":"1014853b9782285f1467dbe79cff435d0bb1d4122dca0b23d7872ddbeb7688c0","src/features.rs":"6edc53dbbadf56a193dc71053f6512b6cf0d09feb5efb8eb991877de1d70c43c","src/ifaddrs.rs":"40ed9c631b5bff403a697889971f44ad87d6fd6bebbd99cb047cf47c190ee87e","src/kmod.rs":"1e77141714fc7da27fcc59caaae0e31b5801f6e164a57f8d6d399a1b4051d5b1","src/lib.rs":"268b7ad111b99ceaf7c78a348824e8a2be84380bdfe8826e8378b6510eac6b9e","src/macros.rs":"ea6b3a5c117f82ab97d0a410501e7ec250ee11baf3c44b1f207ec404ea682d85","src/mount/bsd.rs":"47477e79ee2862b1d7a5afaf099884036fd81e6384624e60d5d2719a9ddbc112","src/mount/linux.rs":"57ada5949a7a393c427e8076e8556938104f70a73c51452d95ab3d78838f442b","src/mount/mod.rs":"8d8c51f25130e02c860f1d85959d02322b4d9ec748295dfc5a4544e6231725a0","src/mqueue.rs":"0c094b340c918796aff8aa43bc78da566c6203c779a41ce5f490fd41110628f1","src/net/if_.rs":"3d32aceb516606271d8edd2dffd5c710a11868aab54119aebec5a70b35cd963b","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"6d27611db0bc1a64bee80cc74155bb593b1e488092d753fdee102404e7e408ec","src/poll_timeout.rs":"c32412689fcafa561514df9d974206c11bb1276ef79fc10964f11b5416f51a00","src/pty.rs":"d30a7bb587bf727615fc505bc8987d5cae543be0d79d2a8f71a41d9cec2afb6e","src/sched.rs":"542bd9b1d8e1ed132c9a16c3485c70d3d47e30f702c4da1b39906fc64da4c308","src/sys/aio.rs":"b57cc89b70b1052c699264427661c293425536db9577f2fa2c6bdfc805fe06ae","src/sys/epoll.rs":"49ce070f560c8ac7a6f338b4b182f70049303c7d895320a7186fb98b666cafa9","src/sys/event.rs":"3e6e737a880f802644b7c5656a6579d747a66b595ba26ab6cb59df1141ac6eda","src/sys/eventfd.rs":"244ec41689cf90ba0527dd3501ea9f2623873b35cb66577dfc652c35e8492fe4","src/sys/fanotify.rs":"769282c558c7ceb3ea3f9661b6717d507641add46b8b033d4bd200c87df2a66d","src/sys/inotify.rs":"5ce6d83beb2f328c33acf0dd3639a1bdd7b5c2e362745b3cb0fa4c549a641e90","src/sys/ioctl/bsd.rs":"e6affc2babd4fa4539574426e416b330b7e32ba4fd2821899a67417261e7089e","src/sys/ioctl/linux.rs":"8c8bdfc239aa175efb4fc2f666a6ecc799b7d614f85e9143595fff05d37f76f0","src/sys/ioctl/mod.rs":"304a959e9eb24dccfd3fc6153719b417367d9208dc7e6859239fb020c407d103","src/sys/memfd.rs":"a7c2c446143f1dda5537a4342a84b83bb536072215ca973de71f87a33ed8bd37","src/sys/mman.rs":"e75b3ae89c18f541ba8fed01b9147661078f9d035eeb4eaf792ba0e4ff1167fe","src/sys/mod.rs":"30057a1c687859394f27581247ae9e412f5f68d4484bd5196797c1bc1939a6c7","src/sys/personality.rs":"f7fa4e97de0943aa6a969465ca7d2d69ac98015f7c339fdbb88d83ffe26db4ce","src/sys/prctl.rs":"785f97a545e010069d67ef11b22a70ca5000e131ee8ca990a2652a596ade77e5","src/sys/pthread.rs":"258cdf7ff0b61a4afa6d228109e4cb4fb88d859bb8dfe6c959d95130fb010906","src/sys/ptrace/bsd.rs":"54b92e1ffe6455a545f807ed7de9011be05251adfdc71a5823b1965579650939","src/sys/ptrace/linux.rs":"c347075fc8d9afd63d6eaf1acf84afb3a2c956b236eef9f17c19e883a6aaa73d","src/sys/ptrace/mod.rs":"a9aefa2b10cc63c8b40adcd3e7dd612a8f4677bf6f37420cdd09e7129ba02c95","src/sys/quota.rs":"1638e34bddd955c7f98f1814d239eb76647101295c8a1ae40c78dd7dd7638f20","src/sys/reboot.rs":"b748217e4877c94c1870885407b9ab1ab9e059c9fb7d04818a1b29477eac81c6","src/sys/resource.rs":"e701020b893666321f44c08df9e60f8927d00ac1035c89965e967dc0b44c6222","src/sys/select.rs":"9cfcb3a9d15a46b2f209e66cbaf136dab6894c711031313557bc58534ecedc70","src/sys/sendfile.rs":"fc7ac628424eb1132674c73bbe19f0d82a28d6752b0beffbf111965ea3885760","src/sys/signal.rs":"da1720190cdedc854649a525f2cd2556daec1c069d3fe32ad65c4302cca8efd9","src/sys/signalfd.rs":"f0b4d32e642a3a02d349b38d317a805eedc6e60e9e773f650fb0ee4ad7f655a7","src/sys/socket/addr.rs":"75d94b8404711b4ec08b44c3d43c7854f7cd9cf8e17665056dddaf6398d1df2a","src/sys/socket/mod.rs":"12c1a291648553516437bec168602fbebcae3d1ad657a7e55cd86f842db29d50","src/sys/socket/sockopt.rs":"69ab0440767e808c0fe2f2d269eae67653b4657e51b8fe356fab95b7ab26546a","src/sys/stat.rs":"074401a0b0fe74d9516640e0790fe67b7727213115accfdb331a9767ae20064c","src/sys/statfs.rs":"991370ce27196f8721a03a88c3b906cc248f46f147ebd6524d45c61433dc0239","src/sys/statvfs.rs":"526c2e69b640f49331e8ca7a2e59cdb803887c91a53fa41f866364fec93bce24","src/sys/sysinfo.rs":"b4519b1ca091c9dbe94d2a6fd6304944bf3df5626973d2c6884022559706f0d9","src/sys/termios.rs":"dd68b78e4a87786d22334c014d258e43d12f4e9370acda61209eb2c9ed176c86","src/sys/time.rs":"a63f6b5cf67a9323ccc3a225ffec88bb078c5dcf22d0eba78ae071db67aefc53","src/sys/timer.rs":"8c10f0e7cfac857ad00460be30bc68b957909cc9296e70718d3b5d4a0babafde","src/sys/timerfd.rs":"569d662725018427b517ffcfa78d8d03e150a344b8b8533d3f16e3bfd5c762da","src/sys/uio.rs":"d0886bf517e9b21af8ad6a25d332003fe9e132fed43cd642ec61b32d27622bd6","src/sys/utsname.rs":"e1f81d363621445633101800ba34debdb222eaf3a25553f8b486f74d49e4be41","src/sys/wait.rs":"338235d42a2ec29633cf64dada7b9b1d434ed0005776bffdecfd5c69922eed89","src/time.rs":"30038bbe683857469d106631cea13ee1e43f149cb4c947a8353824270ee4267c","src/ucontext.rs":"b8f2e04757a9c2bc38c3b1e259d3a013da8a730fe9bfbe5487637395681b43d3","src/unistd.rs":"5bb3b5ad2984793be4eed6adf653bbc52592c2459b9063009b92edb83ed562cf","test/common/mod.rs":"953155de9a50974fda7a43a66269211154bbb5898791e0abd97dc4184d482f23","test/sys/mod.rs":"f08046850a4b7a9bbf203d8eba0ee3ae9c32b6bd4d9c7bf52ca29efb3eb74f35","test/sys/test_aio.rs":"902ae4abda9286db551e65a7eccf267baee16eeefd1cdddac8399bef2ede0060","test/sys/test_aio_drop.rs":"e9e45333b24381bba99235372d5917a22fbd8692eddfbebcf519697c603de812","test/sys/test_epoll.rs":"c30b08d665a1fe7d7a04fe51d50ec78fc74c2ac707ae0f95f82104d5c76ceaf2","test/sys/test_event.rs":"be4b1b1abd25f87f00b3d115105ef832b2c654fd7028c42f1a304a935935b479","test/sys/test_fanotify.rs":"55b0917f8b85fdc8277e6a796d06251a39398b9f2da88d9eec98a763ff03e918","test/sys/test_inotify.rs":"a141b9a995892547b51ceeb6761a70a6b86d37e8f38d13ea2c497b81b4b0f49f","test/sys/test_ioctl.rs":"07d08a46c4ac84161974b655a0d040e03efc9338e7a7505e0d16826b7653b5c2","test/sys/test_mman.rs":"f129659d6995fcada15e7c923cb943d8dd4c6e4aaa141c6cc5bacfa3257793f5","test/sys/test_prctl.rs":"9c3d0fb16a41c3fd80541b313c2bb63de75634ad4711a71af106e58b0cec9ea8","test/sys/test_pthread.rs":"ace36a2f5587f1874854281b4fd84e4e4d892a1e3c5cc38ced57975739522ad6","test/sys/test_ptrace.rs":"ac4fff669bfc58955e94ed0171e4d47ecf2366fce62509c659e78192f9de7a6d","test/sys/test_resource.rs":"aa58f566efb8132b42ae98be6e50b72fee86ef50c4bcc4a7bf49b275f6762008","test/sys/test_select.rs":"09fe9d020e4f1cdb0951ebd27a6c3f408b23471ce2c51d2f1e4708500fc15261","test/sys/test_signal.rs":"ac6cbd345cbd93b1c9bead56794bd978dc44435beea921bedbdb8a2761e557d5","test/sys/test_signalfd.rs":"8db0c371d0cac7d68208505990291ebc2b2cb8671b0edba16ef22b6b9e56dab2","test/sys/test_socket.rs":"8c6190cbea80d5b2866d0891c6f44fddaba337b655af7e5628dc9537e1cbfab9","test/sys/test_sockopt.rs":"dd1839c495ce37535b2fbf78290dfbb1350f40ed7ed92c7fcedc16a88730ecf1","test/sys/test_stat.rs":"6630a28217fd708bb84cd4f7e7101836b74f2420f9888923fdab664ccc331c1d","test/sys/test_statfs.rs":"a32f6319ea7e989747707de27b06332e7942b07e07ab1602af408be91fae7e73","test/sys/test_statvfs.rs":"05cf8f1bcab0f0cd8fbefe8a2a72f9ac6d95aa760c355ac6d4b6f9c61649bc38","test/sys/test_sysinfo.rs":"ffd49bc96375914a2c4a4a59730cae8072f85771e2c4a80d3403df38d967e272","test/sys/test_termios.rs":"6c6897e0320d063a758f6702228c64ef2b459b4a5affa07ae7e76c1142432f0a","test/sys/test_time.rs":"aff97dd1bfc4aa9b616cc71e9cc11f25fb3ad983f1406c856648736847778c19","test/sys/test_timer.rs":"3ae20d364f075d2811f3ff94eda9886682cc21d8807656007d2464fe36d1e361","test/sys/test_timerfd.rs":"cfed3abf58118611d08f6985251a7739cff67108e11214222a1d2394a3a026ce","test/sys/test_uio.rs":"dda569818e3256ff45aa07b33cffb59828983c83b20266b864cdfa38103cffc9","test/sys/test_utsname.rs":"b8371dca02c9cdfc0c8e93df9b5cf5b5cb8a92b114977966854918abeb01ad73","test/sys/test_wait.rs":"c958e51b10a7d0396d0013e9d637a2848ad9d061d526408b40dfefb850c22beb","test/test.rs":"e1da3bf8ef929a9e4aca354bf72578f6649c80dd5f32400eb124b229bd4506f8","test/test_clearenv.rs":"45ca548035b3c20ec87314715feaba2be973709a635d85b8cde46fd1d9f1ecd4","test/test_dir.rs":"e6a100685f945b6007312d22575ac5e27363c649f3fed19fb10b18ac5d905449","test/test_errno.rs":"e7a1320e97350c2883368ffe9fc47fd041f4f9ecdee360d21d36254a63a305a3","test/test_fcntl.rs":"4467e1e8698256c982df17108dacd1fcb6ba0eda18044fe198eff25629827e66","test/test_kmod/hello_mod/Makefile":"0219f7bce0603f97d997fb377ca071966c90333ecc665e78a54dfeb97a9c811b","test/test_kmod/hello_mod/hello.c":"bcac6b19c5bd807e1f3878c15e426acc85785a8ade9840c3bb4d068635c9188c","test/test_kmod/mod.rs":"b4ae25841c2f06f32de9f1acd8230eeccd7095721302ebe78ad454e4e4f9c783","test/test_mount.rs":"9fc453613eab116841a7f2ba57098eebec853fc16ce0e59cb459a203e006115b","test/test_mq.rs":"d8ec2a3f3acad4369851663b3f7fef03177d9f8395b585dee8e2c53f6a2a9b4a","test/test_net.rs":"cfa1d3b4e252193a4b119141f8e93d637e3c32e9029aef72f8bb83e00be6c3b5","test/test_nix_path.rs":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","test/test_nmount.rs":"d6c112547bb80968170b5497cda4b6cbf69dabec6f51d494bd52298995ceff18","test/test_poll.rs":"25b4fa094bbcda5a5317a25d2f292465965dbe3e066374b04a9b27a8d55897ac","test/test_pty.rs":"ec54c5fe096396b5aed5677276acaf80b4c58be7222ee285cfd4eaadf7b34ce0","test/test_sched.rs":"c4579bd376fab8816e63b07fa9ace31dc08e63ebb7c855a2c450698090d1d1e8","test/test_sendfile.rs":"6f82e9f66359a85a7aa819ffd38c7c3326c1bb2384950d681085dc7823fc4a20","test/test_stat.rs":"dae37bd9b5e46e1a76696bed435d8bc4e98ecb91bb3476e7133a6197178d6644","test/test_time.rs":"6eb3536936c67bcfbc80a73a902b4a485943aab5375fc7e3880da6695a4eafce","test/test_unistd.rs":"828a990974b4d843d59f3d134758d4b6a9afa43da3d07dcaf314fcc1615bd732"},"package":"ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"} \ No newline at end of file diff --git a/third_party/rust/nix/CHANGELOG.md b/third_party/rust/nix/CHANGELOG.md index 3a171afd68..37e4ab2d4c 100644 --- a/third_party/rust/nix/CHANGELOG.md +++ b/third_party/rust/nix/CHANGELOG.md @@ -1,8 +1,205 @@ -# Change Log - All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +# Change Log + +## [0.28.0] - 2024-02-24 + + +### Added + +- Added `mkdtemp` wrapper ([#1297](https://github.com/nix-rust/nix/pull/1297)) +- Add associated constants `UTIME_OMIT` `UTIME_NOW` for `TimeSpec` + ([#1879](https://github.com/nix-rust/nix/pull/1879)) +- Added `EventFd` type. ([#1945](https://github.com/nix-rust/nix/pull/1945)) +- - Added `impl From for SigSet`. + - Added `impl std::ops::BitOr for SigSet`. + - Added `impl std::ops::BitOr for Signal`. + - Added `impl std::ops::BitOr for SigSet` + + ([#1959](https://github.com/nix-rust/nix/pull/1959)) +- Added `TlsGetRecordType` control message type and corresponding enum for + linux ([#2065](https://github.com/nix-rust/nix/pull/2065)) +- Added `Ipv6HopLimit` to `::nix::sys::socket::ControlMessage` for Linux, + MacOS, FreeBSD, DragonflyBSD, Android, iOS and Haiku. + ([#2074](https://github.com/nix-rust/nix/pull/2074)) +- Added `Icmp` and `IcmpV6` to `SockProtocol` + ([#2103](https://github.com/nix-rust/nix/pull/2103)) +- Added rfork support for FreeBSD in `unistd` + ([#2121](https://github.com/nix-rust/nix/pull/2121)) +- Added `MapFlags::map_hugetlb_with_size_log2` method for Linux targets + ([#2125](https://github.com/nix-rust/nix/pull/2125)) +- Added `mmap_anonymous` function + ([#2127](https://github.com/nix-rust/nix/pull/2127)) +- Added `mips32r6` and `mips64r6` support for signal, ioctl and ptrace + ([#2138](https://github.com/nix-rust/nix/pull/2138)) +- Added `F_GETPATH` FcntlFlags entry on Apple/NetBSD/DragonflyBSD for + `::nix::fcntl`. ([#2142](https://github.com/nix-rust/nix/pull/2142)) +- Added `F_KINFO` FcntlFlags entry on FreeBSD for `::nix::fcntl`. + ([#2152](https://github.com/nix-rust/nix/pull/2152)) +- Added `F_GETPATH_NOFIRMLINK` and `F_BARRIERFSYNC` FcntlFlags entry + on Apple for `::nix::fcntl`. + ([#2155](https://github.com/nix-rust/nix/pull/2155)) +- Added newtype `Flock` to automatically unlock a held flock upon drop. + Added `Flockable` trait to represent valid types for `Flock`. + ([#2170](https://github.com/nix-rust/nix/pull/2170)) +- Added `SetSockOpt` impls to enable Linux Kernel TLS on a TCP socket and to + import TLS parameters. ([#2175](https://github.com/nix-rust/nix/pull/2175)) +- - Added the `::nix::sys::socket::SocketTimestamp` enum for configuring the + `TsClock` (a.k.a `SO_TS_CLOCK`) sockopt + - Added FreeBSD's `ScmRealtime` and `ScmMonotonic` as new options in + `::nix::sys::socket::ControlMessageOwned` + + ([#2187](https://github.com/nix-rust/nix/pull/2187)) +- Added new fanotify API: wrappers for `fanotify_init` and `fanotify_mark` + ([#2194](https://github.com/nix-rust/nix/pull/2194)) +- Added `SpecialCharacterindices` support for haiku. + ([#2195](https://github.com/nix-rust/nix/pull/2195)) +- Added `sys::sendfile` support for solaris/illumos. + ([#2198](https://github.com/nix-rust/nix/pull/2198)) +- impl Display for InterfaceFlags + ([#2206](https://github.com/nix-rust/nix/pull/2206)) +- Added `sendfilev` in sys::sendfile for solarish + ([#2207](https://github.com/nix-rust/nix/pull/2207)) +- Added `fctrl::SealFlag::F_SEAL_FUTURE_WRITE` + ([#2213](https://github.com/nix-rust/nix/pull/2213)) +- Added `Ipv6MulticastHops` as socket option to set and read. + ([#2234](https://github.com/nix-rust/nix/pull/2234)) +- Enable `ControlMessageOwned::Ipv4RecvIf` and + `ControlMessageOwned::Ipv4RecvDstAddr` for DragonFlyBSD + ([#2240](https://github.com/nix-rust/nix/pull/2240)) +- `ClockId::set_time()` and `time::clock_settime()` are now enabled on macOS + ([#2241](https://github.com/nix-rust/nix/pull/2241)) +- Added `IpBindAddressNoPort` sockopt to support `IP_BIND_ADDRESS_NO_PORT` + available on linux. ([#2244](https://github.com/nix-rust/nix/pull/2244)) +- Enable `MapFlags::map_hugetlb_with_size_log2` method for Android/Fuchsia + ([#2245](https://github.com/nix-rust/nix/pull/2245)) +- Added `TcpFastOpenConnect` sockopt to support `TCP_FASTOPEN_CONNECT` + available on linux. ([#2247](https://github.com/nix-rust/nix/pull/2247)) +- Add `reboot(2)` for OpenBSD/NetBSD + ([#2251](https://github.com/nix-rust/nix/pull/2251)) +- Added new `MemFdCreateFlag` constants to `sys::memfd` on Linux and Android + related to hugetlbfs support. + ([#2252](https://github.com/nix-rust/nix/pull/2252)) +- Expose the inner fd of `Kqueue` through: + + * impl AsFd for Kqueue + * impl From\ for OwnedFd + + ([#2258](https://github.com/nix-rust/nix/pull/2258)) +- Added `sys::eventfd` support on FreeBSD + ([#2259](https://github.com/nix-rust/nix/pull/2259)) +- Added `MmapFlags::MAP_FIXED` constant in `sys::mman` for netbsd and openbsd + ([#2260](https://github.com/nix-rust/nix/pull/2260)) +- Added the `SO_LISTENQLIMIT` sockopt. + ([#2263](https://github.com/nix-rust/nix/pull/2263)) +- Enable the `AT_EMPTY_PATH` flag for the `fchownat()` function + ([#2267](https://github.com/nix-rust/nix/pull/2267)) +- Add `AtFlags::AT_EMPTY_PATH` for FreeBSD and Hurd + ([#2270](https://github.com/nix-rust/nix/pull/2270)) +- Enable `OFlag::O_DIRECTORY for Solarish + ([#2275](https://github.com/nix-rust/nix/pull/2275)) +- Added the `Backlog` wrapper type for the `listen` call. + ([#2276](https://github.com/nix-rust/nix/pull/2276)) +- Add `clock_nanosleep()` ([#2277](https://github.com/nix-rust/nix/pull/2277)) +- Enabled `O_DIRECT` in `fcntl::OFlags` for solarish + ([#2278](https://github.com/nix-rust/nix/pull/2278)) +- Added a new API sigsuspend. + ([#2279](https://github.com/nix-rust/nix/pull/2279)) +- - Added `errno::Errno::set` function + - Added `errno::Errno::set_raw` function + - Added `errno::Errno::last_raw` function + - Added `errno::Errno::from_raw` function + + ([#2283](https://github.com/nix-rust/nix/pull/2283)) +- Enable the `AT_EMPTY_PATH` flag for the `linkat()` function + ([#2284](https://github.com/nix-rust/nix/pull/2284)) +- Enable unistd::{sync, syncfs} for Android + ([#2296](https://github.com/nix-rust/nix/pull/2296)) + +### Changed + +- `poll` now takes `PollTimeout` replacing `libc::c_int`. + ([#1876](https://github.com/nix-rust/nix/pull/1876)) +- Deprecated `sys::eventfd::eventfd`. + ([#1945](https://github.com/nix-rust/nix/pull/1945)) +- `mmap`, `mmap_anonymous`, `munmap`, `mremap`, `madvise`, `msync`, `mprotect`, + `munlock` and `mlock` updated to use `NonNull`. + ([#2000](https://github.com/nix-rust/nix/pull/2000)) +- `mmap` function now accepts `F` instead of `Option` + ([#2127](https://github.com/nix-rust/nix/pull/2127)) +- `PollFd::new` now takes a `BorrowedFd` argument, with relaxed lifetime + requirements relative to the previous version. + ([#2134](https://github.com/nix-rust/nix/pull/2134)) +- `FdSet::{insert, remove, contains}` now take `BorrowedFd` arguments, and have + relaxed lifetime requirements relative to 0.27.1. + ([#2136](https://github.com/nix-rust/nix/pull/2136)) +- The following APIs now take an implementation of `AsFd` rather than a + `RawFd`: + + - `unistd::tcgetpgrp` + - `unistd::tcsetpgrp` + - `unistd::fpathconf` + - `unistd::ttyname` + - `unistd::getpeereid` ([#2137](https://github.com/nix-rust/nix/pull/2137)) +- Changed `openat()` and `Dir::openat()`, now take optional `dirfd`s + ([#2139](https://github.com/nix-rust/nix/pull/2139)) +- The MSRV is now 1.69 ([#2144](https://github.com/nix-rust/nix/pull/2144)) +- Changed function `SockaddrIn::ip()` to return `net::Ipv4Addr` and refactored + `SocketAddrV6::ip()` to be `const` + ([#2151](https://github.com/nix-rust/nix/pull/2151)) +- The following APIs now take optional `dirfd`s: + + - `readlinkat()` + - `fstatat()` + - `mknodat()` + - `mkdirat()` + - `execveat()` + + ([#2157](https://github.com/nix-rust/nix/pull/2157)) +- `Epoll::wait` now takes `EpollTimeout` replacing `isize`. + ([#2202](https://github.com/nix-rust/nix/pull/2202)) +- - Deprecated `errno::errno()` function (use `Errno::last_raw()`) + - Deprecated `errno::from_i32()` function (use `Errno::from_raw()`) + - Deprecated `errno::Errno::from_i32()` function (use `Errno::from_raw()`) + + ([#2283](https://github.com/nix-rust/nix/pull/2283)) + +### Fixed + +- Fix `SigSet` incorrect implementation of `Eq`, `PartialEq` and `Hash` + ([#1946](https://github.com/nix-rust/nix/pull/1946)) +- Fixed `::sys::socket::sockopt::IpMulticastTtl` by fixing the value of optlen + passed to `libc::setsockopt` and added tests. + ([#2072](https://github.com/nix-rust/nix/pull/2072)) +- Fixed the function signature of `recvmmsg`, potentially causing UB + ([#2119](https://github.com/nix-rust/nix/pull/2119)) +- Fix `SignalFd::set_mask`. In 0.27.0 it would actually close the file + descriptor. ([#2141](https://github.com/nix-rust/nix/pull/2141)) +- Fixed UnixAddr::new for haiku, it did not record the `sun_len` value as + needed. + Fixed `sys::socket::addr::from_raw_parts` and + `sys::socket::Sockaddrlike::len` build for solaris. + ([#2242](https://github.com/nix-rust/nix/pull/2242)) +- Fixed solaris build globally. + ([#2248](https://github.com/nix-rust/nix/pull/2248)) +- Changed the `dup3` wrapper to perform a real call to `dup3` instead of + emulating it via `dup2` and `fcntl` to get rid of race condition + ([#2268](https://github.com/nix-rust/nix/pull/2268)) +- Fixed `::unistd::Group::members` using read_unaligned to avoid crash on + misaligned pointers ([#2311](https://github.com/nix-rust/nix/pull/2311)) + +### Removed + +- The `FchownatFlags` type has been deprecated, please use `AtFlags` instead. + ([#2267](https://github.com/nix-rust/nix/pull/2267)) +- Removed the `dup3` wrapper on macOS, which was emulated via `dup2` and + `fcntl` and could cause a race condition. The `dup3` system call is not + supported on macOS. ([#2268](https://github.com/nix-rust/nix/pull/2268)) +- The `LinkatFlags` type has been deprecated, please use `AtFlags` instead. + ([#2284](https://github.com/nix-rust/nix/pull/2284)) + + ## [0.27.1] - 2023-08-28 ### Fixed @@ -99,7 +296,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [0.26.3] - 2023-08-27 ### Fixed -- Fix: send `ETH_P_ALL` in htons format +- Fix: send `ETH_P_ALL` in htons format ([#1925](https://github.com/nix-rust/nix/pull/1925)) - Fix: `recvmsg` now sets the length of the received `sockaddr_un` field correctly on Linux platforms. ([#2041](https://github.com/nix-rust/nix/pull/2041)) @@ -187,7 +384,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1824](https://github.com/nix-rust/nix/pull/1824)) - Workaround XNU bug causing netmasks returned by `getifaddrs` to misbehave. ([#1788](https://github.com/nix-rust/nix/pull/1788)) - + ### Removed - Removed deprecated error constants and conversions. diff --git a/third_party/rust/nix/Cargo.toml b/third_party/rust/nix/Cargo.toml index bb04ab2702..34bc897c54 100644 --- a/third_party/rust/nix/Cargo.toml +++ b/third_party/rust/nix/Cargo.toml @@ -11,11 +11,12 @@ [package] edition = "2021" -rust-version = "1.65" +rust-version = "1.69" name = "nix" -version = "0.27.1" +version = "0.28.0" authors = ["The nix-rust Project Developers"] include = [ + "build.rs", "src/**/*", "test/**/*", "LICENSE", @@ -60,11 +61,6 @@ path = "test/sys/test_aio_drop.rs" name = "test-clearenv" path = "test/test_clearenv.rs" -[[test]] -name = "test-mount" -path = "test/test_mount.rs" -harness = false - [[test]] name = "test-prctl" path = "test/sys/test_prctl.rs" @@ -76,7 +72,7 @@ version = "2.3.1" version = "1.0" [dependencies.libc] -version = "0.2.147" +version = "0.2.153" features = ["extra_traits"] [dependencies.memoffset] @@ -102,6 +98,9 @@ version = "1.0.7" [dev-dependencies.tempfile] version = "3.7.1" +[build-dependencies.cfg_aliases] +version = "0.1.1" + [features] acct = [] aio = ["pin-utils"] @@ -109,6 +108,7 @@ default = [] dir = ["fs"] env = [] event = [] +fanotify = [] feature = [] fs = [] hostname = [] diff --git a/third_party/rust/nix/README.md b/third_party/rust/nix/README.md index e172de2750..fb9f84ca44 100644 --- a/third_party/rust/nix/README.md +++ b/third_party/rust/nix/README.md @@ -2,6 +2,7 @@ [![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix) [![crates.io](https://img.shields.io/crates/v/nix.svg)](https://crates.io/crates/nix) +[![maintenance-status](https://img.shields.io/badge/maintenance-looking--for--maintainer-orange.svg)](https://github.com/nix-rust/nix/issues/2132) [Documentation (Releases)](https://docs.rs/nix/) @@ -98,13 +99,14 @@ The following targets are supported by `nix`:
  • x86_64-unknown-linux-gnux32
  • x86_64-unknown-openbsd
  • x86_64-unknown-redox
  • +
  • i686-unknown-hurd-gnu
  • ## Minimum Supported Rust Version (MSRV) -nix is supported on Rust 1.65 and higher. Its MSRV will not be +nix is supported on Rust 1.69 and higher. Its MSRV will not be changed in the future without bumping the major or minor version. ## Contributing diff --git a/third_party/rust/nix/build.rs b/third_party/rust/nix/build.rs new file mode 100644 index 0000000000..4535af1f04 --- /dev/null +++ b/third_party/rust/nix/build.rs @@ -0,0 +1,25 @@ +use cfg_aliases::cfg_aliases; + +fn main() { + cfg_aliases! { + android: { target_os = "android" }, + dragonfly: { target_os = "dragonfly" }, + ios: { target_os = "ios" }, + freebsd: { target_os = "freebsd" }, + illumos: { target_os = "illumos" }, + linux: { target_os = "linux" }, + macos: { target_os = "macos" }, + netbsd: { target_os = "netbsd" }, + openbsd: { target_os = "openbsd" }, + solaris: { target_os = "solaris" }, + watchos: { target_os = "watchos" }, + tvos: { target_os = "tvos" }, + + apple_targets: { any(ios, macos, watchos, tvos) }, + bsd: { any(freebsd, dragonfly, netbsd, openbsd, apple_targets) }, + linux_android: { any(android, linux) }, + freebsdlike: { any(dragonfly, freebsd) }, + netbsdlike: { any(netbsd, openbsd) }, + solarish: { any(illumos, solaris) }, + } +} diff --git a/third_party/rust/nix/src/dir.rs b/third_party/rust/nix/src/dir.rs index 96a5843bc6..ab70f064cc 100644 --- a/third_party/rust/nix/src/dir.rs +++ b/third_party/rust/nix/src/dir.rs @@ -44,7 +44,7 @@ impl Dir { /// Opens the given path as with `fcntl::openat`. pub fn openat( - dirfd: RawFd, + dirfd: Option, path: &P, oflag: OFlag, mode: sys::stat::Mode, @@ -225,16 +225,13 @@ impl Entry { pub fn ino(&self) -> u64 { cfg_if! { if #[cfg(any(target_os = "aix", - target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "ios", - target_os = "l4re", - target_os = "linux", - target_os = "macos", - target_os = "solaris"))] { + target_os = "hurd", + solarish, + linux_android, + apple_targets))] { self.0.d_ino as u64 } else { u64::from(self.0.d_fileno) @@ -253,12 +250,7 @@ impl Entry { /// notably, some Linux filesystems don't implement this. The caller should use `stat` or /// `fstat` if this returns `None`. pub fn file_type(&self) -> Option { - #[cfg(not(any( - target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - )))] + #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))] match self.0.d_type { libc::DT_FIFO => Some(Type::Fifo), libc::DT_CHR => Some(Type::CharacterDevice), @@ -271,12 +263,7 @@ impl Entry { } // illumos, Solaris, and Haiku systems do not have the d_type member at all: - #[cfg(any( - target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - ))] + #[cfg(any(solarish, target_os = "aix", target_os = "haiku"))] None } } diff --git a/third_party/rust/nix/src/env.rs b/third_party/rust/nix/src/env.rs index 95177a1d2a..510bbb0924 100644 --- a/third_party/rust/nix/src/env.rs +++ b/third_party/rust/nix/src/env.rs @@ -40,13 +40,12 @@ impl std::error::Error for ClearEnvError {} /// thread safety must still be upheld. pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> { cfg_if! { - if #[cfg(any(target_os = "fuchsia", + if #[cfg(any(linux_android, + target_os = "fuchsia", target_os = "wasi", target_env = "uclibc", - target_os = "linux", - target_os = "android", target_os = "emscripten"))] { - let ret = libc::clearenv(); + let ret = unsafe { libc::clearenv() }; } else { use std::env; for (name, _) in env::vars_os() { diff --git a/third_party/rust/nix/src/errno.rs b/third_party/rust/nix/src/errno.rs index 50b35248f8..2e74a84454 100644 --- a/third_party/rust/nix/src/errno.rs +++ b/third_party/rust/nix/src/errno.rs @@ -1,74 +1,127 @@ +//! Safe wrappers around errno functions +//! +//! # Example +//! ``` +//! use nix::errno::Errno; +//! +//! Errno::EIO.set(); +//! assert_eq!(Errno::last(), Errno::EIO); +//! +//! Errno::clear(); +//! assert_eq!(Errno::last(), Errno::from_raw(0)); +//! ``` + use crate::Result; use cfg_if::cfg_if; use libc::{c_int, c_void}; -use std::convert::TryFrom; use std::{error, fmt, io}; pub use self::consts::*; cfg_if! { if #[cfg(any(target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] { + apple_targets,))] { unsafe fn errno_location() -> *mut c_int { - libc::__error() + unsafe { libc::__error() } } - } else if #[cfg(any(target_os = "android", - target_os = "netbsd", - target_os = "openbsd"))] { + } else if #[cfg(any(target_os = "android", netbsdlike))] { unsafe fn errno_location() -> *mut c_int { - libc::__errno() + unsafe { libc::__errno() } } } else if #[cfg(any(target_os = "linux", target_os = "redox", target_os = "dragonfly", - target_os = "fuchsia"))] { + target_os = "fuchsia", + target_os = "hurd"))] { unsafe fn errno_location() -> *mut c_int { - libc::__errno_location() + unsafe { libc::__errno_location() } } - } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] { + } else if #[cfg(solarish)] { unsafe fn errno_location() -> *mut c_int { - libc::___errno() + unsafe { libc::___errno() } } } else if #[cfg(any(target_os = "haiku",))] { unsafe fn errno_location() -> *mut c_int { - libc::_errnop() + unsafe { libc::_errnop() } } } else if #[cfg(any(target_os = "aix"))] { unsafe fn errno_location() -> *mut c_int { - libc::_Errno() + unsafe { libc::_Errno() } } } } -/// Sets the platform-specific errno to no-error -fn clear() { - // Safe because errno is a thread-local variable - unsafe { - *errno_location() = 0; - } -} - /// Returns the platform-specific value of errno +#[deprecated(since = "0.28.0", note = "please use `Errno::last_raw()` instead")] pub fn errno() -> i32 { - unsafe { *errno_location() } + Errno::last_raw() } impl Errno { + /// Returns the current value of errno pub fn last() -> Self { - last() + Self::from_raw(Self::last_raw()) } - pub fn desc(self) -> &'static str { - desc(self) + /// Returns the current raw i32 value of errno + pub fn last_raw() -> i32 { + unsafe { *errno_location() } + } + + /// Sets the value of errno. + /// + /// # Example + /// ``` + /// use nix::errno::Errno; + /// + /// Errno::EIO.set(); + /// + /// assert_eq!(Errno::last(), Errno::EIO); + /// ``` + pub fn set(self) { + Self::set_raw(self as i32) } + /// Sets the raw i32 value of errno. + pub fn set_raw(errno: i32) { + // Safe because errno is a thread-local variable + unsafe { + *errno_location() = errno; + } + } + + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(err: i32) -> Errno { + Self::from_raw(err) + } + + pub const fn from_raw(err: i32) -> Errno { + #[allow(deprecated)] from_i32(err) } + pub fn desc(self) -> &'static str { + desc(self) + } + + /// Sets the platform-specific errno to no-error + /// + /// ``` + /// use nix::errno::Errno; + /// + /// Errno::EIO.set(); + /// + /// Errno::clear(); + /// + /// let err = Errno::last(); + /// assert_ne!(err, Errno::EIO); + /// assert_eq!(err, Errno::from_raw(0)); + /// ``` pub fn clear() { - clear() + Self::set_raw(0) } /// Returns `Ok(value)` if it does not contain the sentinel value. This @@ -137,14 +190,10 @@ impl TryFrom for Errno { type Error = io::Error; fn try_from(ioerror: io::Error) -> std::result::Result { - ioerror.raw_os_error().map(Errno::from_i32).ok_or(ioerror) + ioerror.raw_os_error().map(Errno::from_raw).ok_or(ioerror) } } -fn last() -> Errno { - Errno::from_i32(errno()) -} - fn desc(errno: Errno) -> &'static str { use self::Errno::*; match errno { @@ -225,467 +274,270 @@ fn desc(errno: Errno) -> &'static str { EHOSTUNREACH => "No route to host", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ECHRNG => "Channel number out of range", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EL2NSYNC => "Level 2 not synchronized", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EL3HLT => "Level 3 halted", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EL3RST => "Level 3 reset", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ELNRNG => "Link number out of range", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EUNATCH => "Protocol driver not attached", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ENOCSI => "No CSI structure available", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EL2HLT => "Level 2 halted", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADE => "Invalid exchange", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADR => "Invalid request descriptor", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EXFULL => "Exchange full", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ENOANO => "No anode", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADRQC => "Invalid request code", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADSLT => "Invalid slot", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBFONT => "Bad font file format", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ENOSTR => "Device not a stream", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ENODATA => "No data available", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ETIME => "Timer expired", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ENOSR => "Out of streams resources", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ENONET => "Machine is not on the network", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ENOPKG => "Package not installed", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] EREMOTE => "Object is remote", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ENOLINK => "Link has been severed", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EADV => "Advertise error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ESRMNT => "Srmount error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ECOMM => "Communication error on send", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + target_os = "fuchsia", ))] EPROTO => "Protocol error", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EMULTIHOP => "Multihop attempted", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EDOTDOT => "RFS specific error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "aix", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "aix", target_os = "fuchsia"))] EBADMSG => "Not a data message", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] EBADMSG => "Trying to read unreadable message", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "aix", target_os = "fuchsia", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] EOVERFLOW => "Value too large for defined data type", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ENOTUNIQ => "Name not unique on network", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADFD => "File descriptor in bad state", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EREMCHG => "Remote address changed", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ELIBACC => "Can not access a needed shared library", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ELIBBAD => "Accessing a corrupted shared library", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ELIBSCN => ".lib section in a.out corrupted", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ELIBMAX => "Attempting to link in too many shared libraries", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ELIBEXEC => "Cannot exec a shared library directly", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia", target_os = "openbsd" ))] EILSEQ => "Illegal byte sequence", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ERESTART => "Interrupted system call should be restarted", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ESTRPIPE => "Streams pipe error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EUSERS => "Too many users", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "fuchsia", target_os = "netbsd", target_os = "redox" ))] EOPNOTSUPP => "Operation not supported on transport endpoint", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia", target_os = "hurd"))] ESTALE => "Stale file handle", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EUCLEAN => "Structure needs cleaning", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] ENOTNAM => "Not a XENIX named type file", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] ENAVAIL => "No XENIX semaphores available", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EISNAM => "Is a named type file", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EREMOTEIO => "Remote I/O error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EDQUOT => "Quota exceeded", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "fuchsia", target_os = "openbsd", target_os = "dragonfly" @@ -693,71 +545,47 @@ fn desc(errno: Errno) -> &'static str { ENOMEDIUM => "No medium found", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "fuchsia", target_os = "openbsd" ))] EMEDIUMTYPE => "Wrong medium type", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", + linux_android, + solarish, target_os = "fuchsia", target_os = "haiku" ))] ECANCELED => "Operation canceled", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] ENOKEY => "Required key not available", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EKEYEXPIRED => "Key has expired", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EKEYREVOKED => "Key has been revoked", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EKEYREJECTED => "Key was rejected by service", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "aix", - target_os = "fuchsia" + target_os = "fuchsia", + target_os = "hurd" ))] EOWNERDEAD => "Owner died", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] EOWNERDEAD => "Process died with lock", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "aix", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "aix", target_os = "fuchsia"))] ENOTRECOVERABLE => "State not recoverable", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] ENOTRECOVERABLE => "Lock is not recoverable", #[cfg(any( @@ -772,21 +600,13 @@ fn desc(errno: Errno) -> &'static str { ))] EHWPOISON => "Memory page has hardware error", - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] EDOOFUS => "Programming error", - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "redox" - ))] + #[cfg(any(freebsdlike, target_os = "hurd", target_os = "redox"))] EMULTIHOP => "Multihop attempted", - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "redox" - ))] + #[cfg(any(freebsdlike, target_os = "hurd", target_os = "redox"))] ENOLINK => "Link has been severed", #[cfg(target_os = "freebsd")] @@ -795,300 +615,157 @@ fn desc(errno: Errno) -> &'static str { #[cfg(target_os = "freebsd")] ECAPMODE => "Not permitted in capability mode", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] ENEEDAUTH => "Need authenticator", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox", - target_os = "illumos", - target_os = "solaris" - ))] + #[cfg(any(bsd, target_os = "redox", solarish))] EOVERFLOW => "Value too large to be stored in data type", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "netbsd", target_os = "redox", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] EILSEQ => "Illegal byte sequence", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" - ))] + #[cfg(any(bsd, target_os = "haiku"))] ENOATTR => "Attribute not found", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", + bsd, target_os = "redox", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] EBADMSG => "Bad message", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox", - target_os = "haiku" + bsd, + target_os = "haiku", + target_os = "hurd", + target_os = "redox" ))] EPROTO => "Protocol error", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd" + freebsdlike, + apple_targets, + target_os = "openbsd", + target_os = "hurd" ))] ENOTRECOVERABLE => "State not recoverable", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd" - ))] + #[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] EOWNERDEAD => "Previous owner died", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", + bsd, target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" + solarish, + target_os = "haiku", + target_os = "hurd" ))] ENOTSUP => "Operation not supported", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "aix", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "aix", target_os = "hurd"))] EPROCLIM => "Too many processes", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", + bsd, target_os = "aix", - target_os = "openbsd", - target_os = "netbsd", + target_os = "hurd", target_os = "redox" ))] EUSERS => "Too many users", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", + bsd, + solarish, target_os = "redox", target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] EDQUOT => "Disc quota exceeded", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", + bsd, + solarish, target_os = "redox", target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "haiku" ))] ESTALE => "Stale NFS file handle", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "aix", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox" - ))] + #[cfg(any(bsd, target_os = "aix", target_os = "redox"))] EREMOTE => "Too many levels of remote in path", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EBADRPC => "RPC struct is bad", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] ERPCMISMATCH => "RPC version wrong", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EPROGUNAVAIL => "RPC prog. not avail", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EPROGMISMATCH => "Program version wrong", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EPROCUNAVAIL => "Bad procedure for program", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EFTYPE => "Inappropriate file type or format", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EAUTH => "Authentication error", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", + bsd, target_os = "aix", - target_os = "openbsd", - target_os = "netbsd", + target_os = "hurd", target_os = "redox" ))] ECANCELED => "Operation canceled", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EPWROFF => "Device power is off", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EDEVERR => "Device error, e.g. paper out", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EBADEXEC => "Bad executable", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EBADARCH => "Bad CPU type in executable", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] ESHLIBVERS => "Shared library version mismatch", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EBADMACHO => "Malformed Macho file", - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "haiku" - ))] + #[cfg(any(apple_targets, target_os = "netbsd", target_os = "haiku"))] EMULTIHOP => "Reserved", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", target_os = "netbsd", target_os = "redox" ))] ENODATA => "No message available on STREAM", - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "haiku" - ))] + #[cfg(any(apple_targets, target_os = "netbsd", target_os = "haiku"))] ENOLINK => "Reserved", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", target_os = "netbsd", target_os = "redox" @@ -1096,8 +773,7 @@ fn desc(errno: Errno) -> &'static str { ENOSR => "No STREAM resources", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", target_os = "netbsd", target_os = "redox" @@ -1105,30 +781,23 @@ fn desc(errno: Errno) -> &'static str { ENOSTR => "Not a STREAM", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", target_os = "netbsd", target_os = "redox" ))] ETIME => "STREAM ioctl timeout", - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "aix", - target_os = "illumos", - target_os = "solaris" - ))] + #[cfg(any(apple_targets, solarish, target_os = "aix"))] EOPNOTSUPP => "Operation not supported on socket", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] ENOPOLICY => "No such policy registered", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EQFULL => "Interface output queue is full", - #[cfg(target_os = "openbsd")] + #[cfg(any(target_os = "openbsd", target_os = "hurd"))] EOPNOTSUPP => "Operation not supported", #[cfg(target_os = "openbsd")] @@ -1137,18 +806,33 @@ fn desc(errno: Errno) -> &'static str { #[cfg(target_os = "dragonfly")] EASYNC => "Async", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] EDEADLOCK => "Resource deadlock would occur", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] ELOCKUNMAPPED => "Locked lock was unmapped", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] ENOTACTIVE => "Facility is not active", + + #[cfg(target_os = "hurd")] + EBACKGROUND => "Inappropriate operation for background process", + + #[cfg(target_os = "hurd")] + EDIED => "Translator died", + + #[cfg(target_os = "hurd")] + EGREGIOUS => "You really blew it this time", + + #[cfg(target_os = "hurd")] + EIEIO => "Computer bought the farm", + + #[cfg(target_os = "hurd")] + EGRATUITOUS => "Gratuitous error", } } -#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] @@ -1296,6 +980,10 @@ mod consts { pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -1438,7 +1126,7 @@ mod consts { } } -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(apple_targets)] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] @@ -1559,6 +1247,10 @@ mod consts { pub const EDEADLOCK: Errno = Errno::EDEADLK; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -1786,6 +1478,10 @@ mod consts { pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2003,6 +1699,10 @@ mod consts { pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2215,6 +1915,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2429,6 +2133,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2632,6 +2340,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2726,7 +2438,7 @@ mod consts { } } -#[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[cfg(solarish)] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] @@ -2861,6 +2573,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -3081,6 +2797,10 @@ mod consts { pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -3272,6 +2992,10 @@ mod consts { EOPNOTSUPP = libc::EOPNOTSUPP, } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -3378,3 +3102,235 @@ mod consts { } } } + +#[cfg(target_os = "hurd")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + EMFILE = libc::EMFILE, + ENFILE = libc::ENFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + EDESTADDRREQ = libc::EDESTADDRREQ, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + ENOSYS = libc::ENOSYS, + ELIBEXEC = libc::ELIBEXEC, + ENOTSUP = libc::ENOTSUP, + EILSEQ = libc::EILSEQ, + EBACKGROUND = libc::EBACKGROUND, + EDIED = libc::EDIED, + EGREGIOUS = libc::EGREGIOUS, + EIEIO = libc::EIEIO, + EGRATUITOUS = libc::EGRATUITOUS, + EBADMSG = libc::EBADMSG, + EIDRM = libc::EIDRM, + EMULTIHOP = libc::EMULTIHOP, + ENODATA = libc::ENODATA, + ENOLINK = libc::ENOLINK, + ENOMSG = libc::ENOMSG, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + EOVERFLOW = libc::EOVERFLOW, + EPROTO = libc::EPROTO, + ETIME = libc::ETIME, + ECANCELED = libc::ECANCELED, + EOWNERDEAD = libc::EOWNERDEAD, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + } + + impl Errno { + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + } + + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::EMFILE => EMFILE, + libc::ENFILE => ENFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::EOPNOTSUPP => EOPNOTSUPP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EPROCLIM => EPROCLIM, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::EBADRPC => EBADRPC, + libc::ERPCMISMATCH => ERPCMISMATCH, + libc::EPROGUNAVAIL => EPROGUNAVAIL, + libc::EPROGMISMATCH => EPROGMISMATCH, + libc::EPROCUNAVAIL => EPROCUNAVAIL, + libc::ENOLCK => ENOLCK, + libc::EFTYPE => EFTYPE, + libc::EAUTH => EAUTH, + libc::ENEEDAUTH => ENEEDAUTH, + libc::ENOSYS => ENOSYS, + libc::ELIBEXEC => ELIBEXEC, + libc::ENOTSUP => ENOTSUP, + libc::EILSEQ => EILSEQ, + libc::EBACKGROUND => EBACKGROUND, + libc::EDIED => EDIED, + libc::EGREGIOUS => EGREGIOUS, + libc::EIEIO => EIEIO, + libc::EGRATUITOUS => EGRATUITOUS, + libc::EBADMSG => EBADMSG, + libc::EIDRM => EIDRM, + libc::EMULTIHOP => EMULTIHOP, + libc::ENODATA => ENODATA, + libc::ENOLINK => ENOLINK, + libc::ENOMSG => ENOMSG, + libc::ENOSR => ENOSR, + libc::ENOSTR => ENOSTR, + libc::EOVERFLOW => EOVERFLOW, + libc::EPROTO => EPROTO, + libc::ETIME => ETIME, + libc::ECANCELED => ECANCELED, + libc::EOWNERDEAD => EOWNERDEAD, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + _ => UnknownErrno, + } + } +} diff --git a/third_party/rust/nix/src/fcntl.rs b/third_party/rust/nix/src/fcntl.rs index 9bfecda5ac..ccefe955de 100644 --- a/third_party/rust/nix/src/fcntl.rs +++ b/third_party/rust/nix/src/fcntl.rs @@ -1,27 +1,39 @@ +//! file control options use crate::errno::Errno; -use libc::{self, c_char, c_int, c_uint, size_t, ssize_t}; +#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] +use core::slice; +use libc::{c_int, c_uint, size_t, ssize_t}; +#[cfg(any( + target_os = "netbsd", + apple_targets, + target_os = "dragonfly", + all(target_os = "freebsd", target_arch = "x86_64"), +))] +use std::ffi::CStr; use std::ffi::OsString; +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +use std::ops::{Deref, DerefMut}; #[cfg(not(target_os = "redox"))] use std::os::raw; use std::os::unix::ffi::OsStringExt; use std::os::unix::io::RawFd; -// For splice and copy_file_range +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +use std::os::unix::io::{AsRawFd, OwnedFd}; #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "linux" + target_os = "netbsd", + apple_targets, + target_os = "dragonfly", + all(target_os = "freebsd", target_arch = "x86_64"), ))] -use std::{ - os::unix::io::{AsFd, AsRawFd}, - ptr, -}; +use std::path::PathBuf; +#[cfg(any(linux_android, target_os = "freebsd"))] +use std::{os::unix::io::AsFd, ptr}; #[cfg(feature = "fs")] use crate::{sys::stat::Mode, NixPath, Result}; #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", @@ -32,41 +44,58 @@ use crate::{sys::stat::Mode, NixPath, Result}; pub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice}; #[cfg(not(target_os = "redox"))] -#[cfg(any(feature = "fs", feature = "process"))] +#[cfg(any(feature = "fs", feature = "process", feature = "user"))] libc_bitflags! { + /// Flags that control how the various *at syscalls behave. #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))] pub struct AtFlags: c_int { + #[allow(missing_docs)] + #[doc(hidden)] + // Should not be used by the public API, but only internally. AT_REMOVEDIR; + /// Used with [`linkat`](crate::unistd::linkat`) to create a link to a symbolic link's + /// target, instead of to the symbolic link itself. AT_SYMLINK_FOLLOW; + /// Used with functions like [`fstatat`](crate::sys::stat::fstatat`) to operate on a link + /// itself, instead of the symbolic link's target. AT_SYMLINK_NOFOLLOW; - #[cfg(any(target_os = "android", target_os = "linux"))] + /// Don't automount the terminal ("basename") component of pathname if it is a directory + /// that is an automount point. + #[cfg(linux_android)] AT_NO_AUTOMOUNT; - #[cfg(any(target_os = "android", target_os = "linux"))] + /// If the provided path is an empty string, operate on the provided directory file + /// descriptor instead. + #[cfg(any(linux_android, target_os = "freebsd", target_os = "hurd"))] AT_EMPTY_PATH; + /// Used with [`faccessat`](crate::unistd::faccessat), the checks for accessibility are + /// performed using the effective user and group IDs instead of the real user and group ID #[cfg(not(target_os = "android"))] AT_EACCESS; } } -#[cfg(any(feature = "fs", feature = "term"))] +#[cfg(any( + feature = "fs", + feature = "term", + all(feature = "fanotify", target_os = "linux") +))] libc_bitflags!( /// Configuration options for opened files. - #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term"))))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term", all(feature = "fanotify", target_os = "linux")))))] pub struct OFlag: c_int { /// Mask for the access mode of the file. O_ACCMODE; /// Use alternate I/O semantics. #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] O_ALT_IO; /// Open the file in append-only mode. O_APPEND; /// Generate a signal when input or output becomes possible. - #[cfg(not(any(target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any( + solarish, + target_os = "aix", + target_os = "haiku" + )))] O_ASYNC; /// Closes the file descriptor once an `execve` call is made. /// @@ -75,68 +104,42 @@ libc_bitflags!( /// Create the file if it does not exist. O_CREAT; /// Try to minimize cache effects of the I/O for this file. - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any( + freebsdlike, + linux_android, + solarish, + target_os = "netbsd" + ))] O_DIRECT; /// If the specified path isn't a directory, fail. - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] O_DIRECTORY; /// Implicitly follow each `write()` with an `fdatasync()`. - #[cfg(any(target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets, netbsdlike))] O_DSYNC; /// Error out if a file was not created. O_EXCL; /// Open for execute only. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] O_EXEC; /// Open with an exclusive file lock. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "redox"))] O_EXLOCK; /// Same as `O_SYNC`. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - all(target_os = "linux", not(target_env = "musl")), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", + #[cfg(any(bsd, + all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos")), target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] O_FSYNC; /// Allow files whose sizes can't be represented in an `off_t` to be opened. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] O_LARGEFILE; /// Do not update the file last access time during `read(2)`s. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] O_NOATIME; /// Don't attach the device as the process' controlling terminal. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] O_NOCTTY; /// Same as `O_NONBLOCK`. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] O_NDELAY; /// `open()` will fail if the given path is a symbolic link. O_NOFOLLOW; @@ -144,13 +147,11 @@ libc_bitflags!( O_NONBLOCK; /// Don't deliver `SIGPIPE`. #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] O_NOSIGPIPE; /// Obtain a file descriptor for low-level access. /// /// The file itself is not opened and other file operations will fail. - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "redox"))] O_PATH; /// Only allow reading. /// @@ -161,36 +162,24 @@ libc_bitflags!( /// This should not be combined with `O_WRONLY` or `O_RDONLY`. O_RDWR; /// Similar to `O_DSYNC` but applies to `read`s instead. - #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(target_os = "linux", netbsdlike))] O_RSYNC; /// Skip search permission checks. #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] O_SEARCH; /// Open with a shared file lock. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "redox"))] O_SHLOCK; /// Implicitly follow each `write()` with an `fsync()`. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] O_SYNC; /// Create an unnamed temporary file. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] O_TMPFILE; /// Truncate an existing regular file to 0 length if it allows writing. O_TRUNC; /// Restore default TTY attributes. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] O_TTY_INIT; /// Only allow writing. /// @@ -199,9 +188,23 @@ libc_bitflags!( } ); +/// Computes the raw fd consumed by a function of the form `*at`. +#[cfg(any( + all(feature = "fs", not(target_os = "redox")), + all(feature = "process", linux_android), + all(feature = "fanotify", target_os = "linux") +))] +pub(crate) fn at_rawfd(fd: Option) -> raw::c_int { + fd.unwrap_or(libc::AT_FDCWD) +} + feature! { #![feature = "fs"] +/// open or create a file for reading, writing or executing +/// +/// # See Also +/// [`open`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html) // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] pub fn open( @@ -216,21 +219,37 @@ pub fn open( Errno::result(fd) } +/// open or create a file for reading, writing or executing +/// +/// The `openat` function is equivalent to the [`open`] function except in the case where the path +/// specifies a relative path. In that case, the file to be opened is determined relative to the +/// directory associated with the file descriptor `fd`. +/// +/// # See Also +/// [`openat`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/openat.html) // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] #[cfg(not(target_os = "redox"))] pub fn openat( - dirfd: RawFd, + dirfd: Option, path: &P, oflag: OFlag, mode: Mode, ) -> Result { let fd = path.with_nix_path(|cstr| unsafe { - libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) + libc::openat(at_rawfd(dirfd), cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) })?; Errno::result(fd) } +/// Change the name of a file. +/// +/// The `renameat` function is equivalent to `rename` except in the case where either `old_path` +/// or `new_path` specifies a relative path. In such cases, the file to be renamed (or the its new +/// name, respectively) is located relative to `old_dirfd` or `new_dirfd`, respectively +/// +/// # See Also +/// [`renameat`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html) #[cfg(not(target_os = "redox"))] pub fn renameat( old_dirfd: Option, @@ -255,16 +274,30 @@ pub fn renameat( #[cfg(all(target_os = "linux", target_env = "gnu"))] #[cfg(feature = "fs")] libc_bitflags! { + /// Flags for use with [`renameat2`]. #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct RenameFlags: u32 { + /// Atomically exchange `old_path` and `new_path`. RENAME_EXCHANGE; + /// Don't overwrite `new_path` of the rename. Return an error if `new_path` already + /// exists. RENAME_NOREPLACE; + /// creates a "whiteout" object at the source of the rename at the same time as performing + /// the rename. + /// + /// This operation makes sense only for overlay/union filesystem implementations. RENAME_WHITEOUT; } } feature! { #![feature = "fs"] +/// Like [`renameat`], but with an additional `flags` argument. +/// +/// A `renameat2` call with an empty flags argument is equivalent to `renameat`. +/// +/// # See Also +/// * [`rename`](https://man7.org/linux/man-pages/man2/rename.2.html) #[cfg(all(target_os = "linux", target_env = "gnu"))] pub fn renameat2( old_dirfd: Option, @@ -306,12 +339,12 @@ fn readlink_maybe_at( Some(dirfd) => libc::readlinkat( dirfd, cstr.as_ptr(), - v.as_mut_ptr() as *mut c_char, + v.as_mut_ptr().cast(), v.capacity() as size_t, ), None => libc::readlink( cstr.as_ptr(), - v.as_mut_ptr() as *mut c_char, + v.as_mut_ptr().cast(), v.capacity() as size_t, ), } @@ -322,7 +355,11 @@ fn inner_readlink( dirfd: Option, path: &P, ) -> Result { - let mut v = Vec::with_capacity(libc::PATH_MAX as usize); + #[cfg(not(target_os = "hurd"))] + const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first + let mut v = Vec::with_capacity(PATH_MAX); { // simple case: result is strictly less than `PATH_MAX` @@ -340,7 +377,7 @@ fn inner_readlink( let reported_size = match dirfd { #[cfg(target_os = "redox")] Some(_) => unreachable!(), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "hurd"))] Some(dirfd) => { let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH @@ -348,18 +385,19 @@ fn inner_readlink( AtFlags::empty() }; super::sys::stat::fstatat( - dirfd, + Some(dirfd), path, flags | AtFlags::AT_SYMLINK_NOFOLLOW, ) } #[cfg(not(any( - target_os = "android", - target_os = "linux", - target_os = "redox" + linux_android, + target_os = "redox", + target_os = "freebsd", + target_os = "hurd" )))] Some(dirfd) => super::sys::stat::fstatat( - dirfd, + Some(dirfd), path, AtFlags::AT_SYMLINK_NOFOLLOW, ), @@ -375,7 +413,7 @@ fn inner_readlink( } else { // If lstat doesn't cooperate, or reports an error, be a little less // precise. - (libc::PATH_MAX as usize).max(128) << 1 + PATH_MAX.max(128) << 1 } }; @@ -400,29 +438,32 @@ fn inner_readlink( } } +/// Read value of a symbolic link +/// +/// # See Also +/// * [`readlink`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html) pub fn readlink(path: &P) -> Result { inner_readlink(None, path) } +/// Read value of a symbolic link. +/// +/// Equivalent to [`readlink` ] except where `path` specifies a relative path. In that case, +/// interpret `path` relative to open file specified by `dirfd`. +/// +/// # See Also +/// * [`readlink`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html) #[cfg(not(target_os = "redox"))] pub fn readlinkat( - dirfd: RawFd, + dirfd: Option, path: &P, ) -> Result { + let dirfd = at_rawfd(dirfd); inner_readlink(Some(dirfd), path) } - -/// Computes the raw fd consumed by a function of the form `*at`. -#[cfg(not(target_os = "redox"))] -pub(crate) fn at_rawfd(fd: Option) -> raw::c_int { - match fd { - None => libc::AT_FDCWD, - Some(fd) => fd, - } -} } -#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "fs")] libc_bitflags!( /// Additional flags for file sealing, which allows for limiting operations on a file. @@ -436,6 +477,10 @@ libc_bitflags!( F_SEAL_GROW; /// The file contents cannot be modified. F_SEAL_WRITE; + /// The file contents cannot be modified, except via shared writable mappings that were + /// created prior to the seal being set. Since Linux 5.1. + #[cfg(linux_android)] + F_SEAL_FUTURE_WRITE; } ); @@ -452,59 +497,105 @@ libc_bitflags!( feature! { #![feature = "fs"] +/// Commands for use with [`fcntl`]. #[cfg(not(target_os = "redox"))] #[derive(Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum FcntlArg<'a> { + /// Duplicate the provided file descriptor F_DUPFD(RawFd), + /// Duplicate the provided file descriptor and set the `FD_CLOEXEC` flag on it. F_DUPFD_CLOEXEC(RawFd), + /// Get the close-on-exec flag associated with the file descriptor F_GETFD, + /// Set the close-on-exec flag associated with the file descriptor F_SETFD(FdFlag), // FD_FLAGS + /// Get descriptor status flags F_GETFL, + /// Set descriptor status flags F_SETFL(OFlag), // O_NONBLOCK + /// Set or clear a file segment lock F_SETLK(&'a libc::flock), + /// Like [`F_SETLK`](FcntlArg::F_SETLK) except that if a shared or exclusive lock is blocked by + /// other locks, the process waits until the request can be satisfied. F_SETLKW(&'a libc::flock), + /// Get the first lock that blocks the lock description F_GETLK(&'a mut libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Acquire or release an open file description lock + #[cfg(linux_android)] F_OFD_SETLK(&'a libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Like [`F_OFD_SETLK`](FcntlArg::F_OFD_SETLK) except that if a conflicting lock is held on + /// the file, then wait for that lock to be released. + #[cfg(linux_android)] F_OFD_SETLKW(&'a libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Determine whether it would be possible to create the given lock. If not, return details + /// about one existing lock that would prevent it. + #[cfg(linux_android)] F_OFD_GETLK(&'a mut libc::flock), + /// Add seals to the file #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_ADD_SEALS(SealFlag), + /// Get seals associated with the file #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_GET_SEALS, - #[cfg(any(target_os = "macos", target_os = "ios"))] + /// Asks the drive to flush all buffered data to permanent storage. + #[cfg(apple_targets)] F_FULLFSYNC, - #[cfg(any(target_os = "linux", target_os = "android"))] + /// fsync + issue barrier to drive + #[cfg(apple_targets)] + F_BARRIERFSYNC, + /// Return the capacity of a pipe + #[cfg(linux_android)] F_GETPIPE_SZ, - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Change the capacity of a pipe + #[cfg(linux_android)] F_SETPIPE_SZ(c_int), + /// Look up the path of an open file descriptor, if possible. + #[cfg(any( + target_os = "netbsd", + target_os = "dragonfly", + apple_targets, + ))] + F_GETPATH(&'a mut PathBuf), + /// Look up the path of an open file descriptor, if possible. + #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] + F_KINFO(&'a mut PathBuf), + /// Return the full path without firmlinks of the fd. + #[cfg(apple_targets)] + F_GETPATH_NOFIRMLINK(&'a mut PathBuf), // TODO: Rest of flags } +/// Commands for use with [`fcntl`]. #[cfg(target_os = "redox")] #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum FcntlArg { + /// Duplicate the provided file descriptor F_DUPFD(RawFd), + /// Duplicate the provided file descriptor and set the `FD_CLOEXEC` flag on it. F_DUPFD_CLOEXEC(RawFd), + /// Get the close-on-exec flag associated with the file descriptor F_GETFD, + /// Set the close-on-exec flag associated with the file descriptor F_SETFD(FdFlag), // FD_FLAGS + /// Get descriptor status flags F_GETFL, + /// Set descriptor status flags F_SETFL(OFlag), // O_NONBLOCK } pub use self::FcntlArg::*; +/// Perform various operations on open file descriptors. +/// +/// # See Also +/// * [`fcntl`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html) // TODO: Figure out how to handle value fcntl returns pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { let res = unsafe { @@ -523,51 +614,95 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock), #[cfg(not(target_os = "redox"))] F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock), #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_ADD_SEALS(flag) => { libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()) } #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(apple_targets)] + F_BARRIERFSYNC => libc::fcntl(fd, libc::F_BARRIERFSYNC), + #[cfg(linux_android)] F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ), - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(linux_android)] F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size), + #[cfg(any( + target_os = "dragonfly", + target_os = "netbsd", + apple_targets, + ))] + F_GETPATH(path) => { + let mut buffer = vec![0; libc::PATH_MAX as usize]; + let res = libc::fcntl(fd, libc::F_GETPATH, buffer.as_mut_ptr()); + let ok_res = Errno::result(res)?; + let optr = CStr::from_bytes_until_nul(&buffer).unwrap(); + *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); + return Ok(ok_res) + }, + #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] + F_KINFO(path) => { + let mut info: libc::kinfo_file = std::mem::zeroed(); + info.kf_structsize = std::mem::size_of::() as i32; + let res = libc::fcntl(fd, libc::F_KINFO, &mut info); + let ok_res = Errno::result(res)?; + let p = info.kf_path; + let u8_slice = slice::from_raw_parts(p.as_ptr().cast(), p.len()); + let optr = CStr::from_bytes_until_nul(u8_slice).unwrap(); + *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); + return Ok(ok_res) + }, + #[cfg(apple_targets)] + F_GETPATH_NOFIRMLINK(path) => { + let mut buffer = vec![0; libc::PATH_MAX as usize]; + let res = libc::fcntl(fd, libc::F_GETPATH_NOFIRMLINK, buffer.as_mut_ptr()); + let ok_res = Errno::result(res)?; + let optr = CStr::from_bytes_until_nul(&buffer).unwrap(); + *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); + return Ok(ok_res) + }, } }; Errno::result(res) } -// TODO: convert to libc_enum +/// Operations for use with [`Flock::lock`]. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum FlockArg { + /// shared file lock LockShared, + /// exclusive file lock LockExclusive, + /// Unlock file Unlock, + /// Shared lock. Do not block when locking. LockSharedNonblock, + /// Exclusive lock. Do not block when locking. LockExclusiveNonblock, + #[allow(missing_docs)] + #[deprecated(since = "0.28.0", note = "Use FlockArg::Unlock instead")] UnlockNonblock, } +#[allow(missing_docs)] #[cfg(not(any(target_os = "redox", target_os = "solaris")))] +#[deprecated(since = "0.28.0", note = "`fcntl::Flock` should be used instead.")] pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { use self::FlockArg::*; @@ -582,15 +717,133 @@ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { LockExclusiveNonblock => { libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) } + #[allow(deprecated)] UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB), } }; Errno::result(res).map(drop) } + +/// Represents valid types for flock. +/// +/// # Safety +/// Types implementing this must not be `Clone`. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +pub unsafe trait Flockable: AsRawFd {} + +/// Represents an owned flock, which unlocks on drop. +/// +/// See [flock(2)](https://linux.die.net/man/2/flock) for details on locking semantics. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +#[derive(Debug)] +pub struct Flock(T); + +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl Drop for Flock { + fn drop(&mut self) { + let res = Errno::result(unsafe { libc::flock(self.0.as_raw_fd(), libc::LOCK_UN) }); + if res.is_err() && !std::thread::panicking() { + panic!("Failed to remove flock: {}", res.unwrap_err()); + } + } +} + +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl Deref for Flock { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl DerefMut for Flock { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl Flock { + /// Obtain a/an flock. + /// + /// # Example + /// ``` + /// # use std::io::Write; + /// # use std::fs::File; + /// # use nix::fcntl::{Flock, FlockArg}; + /// # fn do_stuff(file: File) { + /// let mut file = match Flock::lock(file, FlockArg::LockExclusive) { + /// Ok(l) => l, + /// Err(_) => return, + /// }; + /// + /// // Do stuff + /// let data = "Foo bar"; + /// _ = file.write(data.as_bytes()); + /// _ = file.sync_data(); + /// # } + pub fn lock(t: T, args: FlockArg) -> std::result::Result { + let flags = match args { + FlockArg::LockShared => libc::LOCK_SH, + FlockArg::LockExclusive => libc::LOCK_EX, + FlockArg::LockSharedNonblock => libc::LOCK_SH | libc::LOCK_NB, + FlockArg::LockExclusiveNonblock => libc::LOCK_EX | libc::LOCK_NB, + #[allow(deprecated)] + FlockArg::Unlock | FlockArg::UnlockNonblock => return Err((t, Errno::EINVAL)), + }; + match Errno::result(unsafe { libc::flock(t.as_raw_fd(), flags) }) { + Ok(_) => Ok(Self(t)), + Err(errno) => Err((t, errno)), + } + } + + /// Remove the lock and return the object wrapped within. + /// + /// # Example + /// ``` + /// # use std::fs::File; + /// # use nix::fcntl::{Flock, FlockArg}; + /// fn do_stuff(file: File) -> nix::Result<()> { + /// let mut lock = match Flock::lock(file, FlockArg::LockExclusive) { + /// Ok(l) => l, + /// Err((_,e)) => return Err(e), + /// }; + /// + /// // Do critical section + /// + /// // Unlock + /// let file = match lock.unlock() { + /// Ok(f) => f, + /// Err((_, e)) => return Err(e), + /// }; + /// + /// // Do anything else + /// + /// Ok(()) + /// } + pub fn unlock(self) -> std::result::Result { + let inner = unsafe { match Errno::result(libc::flock(self.0.as_raw_fd(), libc::LOCK_UN)) { + Ok(_) => std::ptr::read(&self.0), + Err(errno) => return Err((self, errno)), + }}; + + std::mem::forget(self); + Ok(inner) + } +} + +// Safety: `File` is not [std::clone::Clone]. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +unsafe impl Flockable for std::fs::File {} + +// Safety: `OwnedFd` is not [std::clone::Clone]. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +unsafe impl Flockable for OwnedFd {} } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "zerocopy")] libc_bitflags! { /// Additional flags to `splice` and friends. @@ -636,7 +889,7 @@ feature! { // Note: FreeBSD defines the offset argument as "off_t". Linux and Android // define it as "loff_t". But on both OSes, on all supported platforms, those // are 64 bits. So Nix uses i64 to make the docs simple and consistent. -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] pub fn copy_file_range( fd_in: Fd1, off_in: Option<&mut i64>, @@ -669,7 +922,7 @@ pub fn copy_file_range( let ret = unsafe { libc::syscall( libc::SYS_copy_file_range, - fd_in, + fd_in.as_fd().as_raw_fd(), off_in, fd_out.as_fd().as_raw_fd(), off_out, @@ -682,7 +935,11 @@ pub fn copy_file_range( Errno::result(ret).map(|r| r as usize) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Splice data to/from a pipe +/// +/// # See Also +/// *[`splice`](https://man7.org/linux/man-pages/man2/splice.2.html) +#[cfg(linux_android)] pub fn splice( fd_in: RawFd, off_in: Option<&mut libc::loff_t>, @@ -704,7 +961,11 @@ pub fn splice( Errno::result(ret).map(|r| r as usize) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Duplicate pipe content +/// +/// # See Also +/// *[`tee`](https://man7.org/linux/man-pages/man2/tee.2.html) +#[cfg(linux_android)] pub fn tee( fd_in: RawFd, fd_out: RawFd, @@ -715,7 +976,11 @@ pub fn tee( Errno::result(ret).map(|r| r as usize) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Splice user pages to/from a pipe +/// +/// # See Also +/// *[`vmsplice`](https://man7.org/linux/man-pages/man2/vmsplice.2.html) +#[cfg(linux_android)] pub fn vmsplice( fd: RawFd, iov: &[std::io::IoSlice<'_>], @@ -724,7 +989,7 @@ pub fn vmsplice( let ret = unsafe { libc::vmsplice( fd, - iov.as_ptr() as *const libc::iovec, + iov.as_ptr().cast(), iov.len(), flags.bits(), ) @@ -793,16 +1058,22 @@ pub struct SpacectlRange(pub libc::off_t, pub libc::off_t); #[cfg(any(target_os = "freebsd"))] impl SpacectlRange { + /// Is the range empty? + /// + /// After a successful call to [`fspacectl`], A value of `true` for `SpacectlRange::is_empty` + /// indicates that the operation is complete. #[inline] pub fn is_empty(&self) -> bool { self.1 == 0 } + /// Remaining length of the range #[inline] pub fn len(&self) -> libc::off_t { self.1 } + /// Next file offset to operate on #[inline] pub fn offset(&self) -> libc::off_t { self.0 @@ -849,6 +1120,7 @@ impl SpacectlRange { /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); /// ``` #[cfg(target_os = "freebsd")] +#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { let mut rqsr = libc::spacectl_range { r_offset: range.0, @@ -897,6 +1169,7 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); /// ``` #[cfg(target_os = "freebsd")] +#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined pub fn fspacectl_all( fd: RawFd, offset: libc::off_t, @@ -922,8 +1195,7 @@ pub fn fspacectl_all( } #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", @@ -937,21 +1209,34 @@ mod posix_fadvise { #[cfg(feature = "fs")] libc_enum! { + /// The specific advice provided to [`posix_fadvise`]. #[repr(i32)] #[non_exhaustive] #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub enum PosixFadviseAdvice { + /// Revert to the default data access behavior. POSIX_FADV_NORMAL, + /// The file data will be accessed sequentially. POSIX_FADV_SEQUENTIAL, + /// A hint that file data will be accessed randomly, and prefetching is likely not + /// advantageous. POSIX_FADV_RANDOM, + /// The specified data will only be accessed once and then not reused. POSIX_FADV_NOREUSE, + /// The specified data will be accessed in the near future. POSIX_FADV_WILLNEED, + /// The specified data will not be accessed in the near future. POSIX_FADV_DONTNEED, } } feature! { #![feature = "fs"] + /// Allows a process to describe to the system its data access behavior for an open file + /// descriptor. + /// + /// # See Also + /// * [`posix_fadvise`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html) pub fn posix_fadvise( fd: RawFd, offset: libc::off_t, @@ -963,20 +1248,22 @@ mod posix_fadvise { if res == 0 { Ok(()) } else { - Err(Errno::from_i32(res)) + Err(Errno::from_raw(res)) } } } } +/// Pre-allocate storage for a range in a file +/// +/// # See Also +/// * [`posix_fallocate`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html) #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", - target_os = "freebsd" ))] pub fn posix_fallocate( fd: RawFd, @@ -987,7 +1274,7 @@ pub fn posix_fallocate( match Errno::result(res) { Err(err) => Err(err), Ok(0) => Ok(()), - Ok(errno) => Err(Errno::from_i32(errno)), + Ok(errno) => Err(Errno::from_raw(errno)), } } } diff --git a/third_party/rust/nix/src/features.rs b/third_party/rust/nix/src/features.rs index 9e292cbf5d..0a0c618096 100644 --- a/third_party/rust/nix/src/features.rs +++ b/third_party/rust/nix/src/features.rs @@ -1,7 +1,7 @@ //! Feature tests for OS functionality pub use self::os::*; -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] mod os { use crate::sys::utsname::uname; use crate::Result; @@ -98,11 +98,10 @@ mod os { } #[cfg(any( - target_os = "dragonfly", // Since ??? - target_os = "freebsd", // Since 10.0 + freebsdlike, // FreeBSD since 10.0 DragonFlyBSD since ??? + netbsdlike, // NetBSD since 6.0 OpenBSD since 5.7 + target_os = "hurd", // Since glibc 2.28 target_os = "illumos", // Since ??? - target_os = "netbsd", // Since 6.0 - target_os = "openbsd", // Since 5.7 target_os = "redox", // Since 1-july-2020 ))] mod os { @@ -114,8 +113,7 @@ mod os { #[cfg(any( target_os = "aix", - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "fuchsia", target_os = "haiku", target_os = "solaris" diff --git a/third_party/rust/nix/src/ifaddrs.rs b/third_party/rust/nix/src/ifaddrs.rs index 70b50b01eb..b3de64b01a 100644 --- a/third_party/rust/nix/src/ifaddrs.rs +++ b/third_party/rust/nix/src/ifaddrs.rs @@ -4,7 +4,7 @@ //! of interfaces and their associated addresses. use cfg_if::cfg_if; -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] use std::convert::TryFrom; use std::ffi; use std::iter::Iterator; @@ -33,7 +33,7 @@ pub struct InterfaceAddress { } cfg_if! { - if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] { + if #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] { fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { info.ifa_ifu } @@ -53,7 +53,7 @@ cfg_if! { /// ss_len field to sizeof(sockaddr_storage). This is supposedly valid as all /// members of the sockaddr_storage are "ok" with being zeroed out (there are /// no pointers). -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option { let src_sock = info.ifa_netmask; if src_sock.is_null() { @@ -62,22 +62,24 @@ unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option { let mut dst_sock = mem::MaybeUninit::::zeroed(); - // memcpy only sa_len bytes, assume the rest is zero - std::ptr::copy_nonoverlapping( - src_sock as *const u8, - dst_sock.as_mut_ptr() as *mut u8, - (*src_sock).sa_len.into(), - ); + let dst_sock = unsafe { + // memcpy only sa_len bytes, assume the rest is zero + std::ptr::copy_nonoverlapping( + src_sock as *const u8, + dst_sock.as_mut_ptr().cast(), + (*src_sock).sa_len.into(), + ); - // Initialize ss_len to sizeof(libc::sockaddr_storage). - (*dst_sock.as_mut_ptr()).ss_len = - u8::try_from(mem::size_of::()).unwrap(); - let dst_sock = dst_sock.assume_init(); + // Initialize ss_len to sizeof(libc::sockaddr_storage). + (*dst_sock.as_mut_ptr()).ss_len = + u8::try_from(mem::size_of::()).unwrap(); + dst_sock.assume_init() + }; let dst_sock_ptr = &dst_sock as *const libc::sockaddr_storage as *const libc::sockaddr; - SockaddrStorage::from_raw(dst_sock_ptr, None) + unsafe { SockaddrStorage::from_raw(dst_sock_ptr, None) } } impl InterfaceAddress { @@ -85,14 +87,16 @@ impl InterfaceAddress { fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) }; - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] let netmask = unsafe { workaround_xnu_bug(info) }; - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(apple_targets))] let netmask = unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; let mut addr = InterfaceAddress { interface_name: ifname.to_string_lossy().to_string(), - flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), + flags: InterfaceFlags::from_bits_truncate( + info.ifa_flags as IflagsType, + ), address, netmask, broadcast: None, diff --git a/third_party/rust/nix/src/kmod.rs b/third_party/rust/nix/src/kmod.rs index d3725c3f8a..5cf2ed2c39 100644 --- a/third_party/rust/nix/src/kmod.rs +++ b/third_party/rust/nix/src/kmod.rs @@ -102,7 +102,11 @@ libc_bitflags!( /// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) /// for a detailed description how these flags work. pub struct DeleteModuleFlags: libc::c_int { + /// `delete_module` will return immediately, with an error, if the module has a nonzero + /// reference count. O_NONBLOCK; + /// `delete_module` will unload the module immediately, regardless of whether it has a + /// nonzero reference count. O_TRUNC; } ); diff --git a/third_party/rust/nix/src/lib.rs b/third_party/rust/nix/src/lib.rs index af0c67b0f3..dffac29b54 100644 --- a/third_party/rust/nix/src/lib.rs +++ b/third_party/rust/nix/src/lib.rs @@ -12,6 +12,7 @@ //! * `dir` - Stuff relating to directory iteration //! * `env` - Manipulate environment variables //! * `event` - Event-driven APIs, like `kqueue` and `epoll` +//! * `fanotify` - Linux's `fanotify` filesystem events monitoring API //! * `feature` - Query characteristics of the OS at runtime //! * `fs` - File system functionality //! * `hostname` - Get and set the system's hostname @@ -41,7 +42,6 @@ //! * `zerocopy` - APIs like `sendfile` and `copy_file_range` #![crate_name = "nix"] #![cfg(unix)] -#![cfg_attr(docsrs, doc(cfg(all())))] #![allow(non_camel_case_types)] #![cfg_attr(test, deny(warnings))] #![recursion_limit = "500"] @@ -54,6 +54,7 @@ feature = "dir", feature = "env", feature = "event", + feature = "fanotify", feature = "feature", feature = "fs", feature = "hostname", @@ -90,6 +91,7 @@ #![warn(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(clippy::cast_ptr_alignment)] +#![deny(unsafe_op_in_unsafe_fn)] // Re-exported external crates pub use libc; @@ -116,42 +118,29 @@ feature! { #[deny(missing_docs)] pub mod features; } -#[allow(missing_docs)] pub mod fcntl; feature! { #![feature = "net"] - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] + #[cfg(any(linux_android, + bsd, + solarish))] #[deny(missing_docs)] pub mod ifaddrs; #[cfg(not(target_os = "redox"))] #[deny(missing_docs)] pub mod net; } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] feature! { #![feature = "kmod"] - #[allow(missing_docs)] pub mod kmod; } feature! { #![feature = "mount"] pub mod mount; } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd" -))] +#[cfg(any(freebsdlike, target_os = "linux", target_os = "netbsd"))] feature! { #![feature = "mqueue"] pub mod mqueue; @@ -173,7 +162,6 @@ feature! { pub mod sys; feature! { #![feature = "time"] - #[allow(missing_docs)] pub mod time; } // This can be implemented for other platforms as soon as libc @@ -192,9 +180,11 @@ feature! { #[allow(missing_docs)] pub mod ucontext; } -#[allow(missing_docs)] pub mod unistd; +#[cfg(any(feature = "poll", feature = "event"))] +mod poll_timeout; + use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; @@ -311,7 +301,7 @@ impl NixPath for [u8] { } let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); - let buf_ptr = buf.as_mut_ptr() as *mut u8; + let buf_ptr = buf.as_mut_ptr().cast(); unsafe { ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len()); diff --git a/third_party/rust/nix/src/macros.rs b/third_party/rust/nix/src/macros.rs index adff2bc6be..3010a1a053 100644 --- a/third_party/rust/nix/src/macros.rs +++ b/third_party/rust/nix/src/macros.rs @@ -27,9 +27,9 @@ macro_rules! feature { /// /// PROT_WRITE enables write protect /// PROT_WRITE; /// PROT_EXEC; -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSDOWN; -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSUP; /// } /// } @@ -89,9 +89,9 @@ macro_rules! libc_bitflags { /// PROT_READ, /// PROT_WRITE, /// PROT_EXEC, -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSDOWN, -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSUP, /// } /// } diff --git a/third_party/rust/nix/src/mount/bsd.rs b/third_party/rust/nix/src/mount/bsd.rs index 6ed2dc7fbf..248e0ab1d2 100644 --- a/third_party/rust/nix/src/mount/bsd.rs +++ b/third_party/rust/nix/src/mount/bsd.rs @@ -17,36 +17,29 @@ libc_bitflags!( pub struct MntFlags: c_int { /// ACL support enabled. #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] MNT_ACLS; /// All I/O to the file system should be done asynchronously. MNT_ASYNC; /// dir should instead be a file system ID encoded as “FSID:val0:val1”. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MNT_BYFSID; /// Force a read-write mount even if the file system appears to be /// unclean. MNT_FORCE; /// GEOM journal support enabled. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MNT_GJOURNAL; /// MAC support for objects. - #[cfg(any(target_os = "macos", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(apple_targets, target_os = "freebsd"))] MNT_MULTILABEL; /// Disable read clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MNT_NOCLUSTERR; /// Disable write clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MNT_NOCLUSTERW; /// Enable NFS version 4 ACLs. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MNT_NFS4ACLS; /// Do not update access times. MNT_NOATIME; @@ -55,8 +48,7 @@ libc_bitflags!( /// Do not honor setuid or setgid bits on files when executing them. MNT_NOSUID; /// Do not follow symlinks. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MNT_NOSYMFOLLOW; /// Mount read-only. MNT_RDONLY; @@ -66,39 +58,29 @@ libc_bitflags!( /// Create a snapshot of the file system. /// /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) - #[cfg(any(target_os = "macos", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(apple_targets, target_os = "freebsd"))] MNT_SNAPSHOT; /// Using soft updates. - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, netbsdlike))] MNT_SOFTDEP; /// Directories with the SUID bit set chown new files to their own /// owner. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MNT_SUIDDIR; /// All I/O to the file system should be done synchronously. MNT_SYNCHRONOUS; /// Union with underlying fs. #[cfg(any( - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] MNT_UNION; /// Indicates that the mount command is being applied to an already /// mounted file system. MNT_UPDATE; /// Check vnode use counts. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MNT_NONBUSY; } ); @@ -198,7 +180,6 @@ pub type NmountResult = std::result::Result<(), NmountError>; /// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) /// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) #[cfg(target_os = "freebsd")] -#[cfg_attr(docsrs, doc(cfg(all())))] #[derive(Debug, Default)] pub struct Nmount<'a> { // n.b. notgull: In reality, this is a list that contains @@ -210,12 +191,11 @@ pub struct Nmount<'a> { } #[cfg(target_os = "freebsd")] -#[cfg_attr(docsrs, doc(cfg(all())))] impl<'a> Nmount<'a> { /// Helper function to push a slice onto the `iov` array. fn push_slice(&mut self, val: &'a [u8], is_owned: bool) { self.iov.push(libc::iovec { - iov_base: val.as_ptr() as *mut _, + iov_base: val.as_ptr().cast_mut().cast(), iov_len: val.len(), }); self.is_owned.push(is_owned); @@ -386,7 +366,7 @@ impl<'a> Nmount<'a> { // SAFETY: we are pushing a mutable iovec here, so we can't use // the above method self.iov.push(libc::iovec { - iov_base: errmsg.as_mut_ptr() as *mut c_void, + iov_base: errmsg.as_mut_ptr().cast(), iov_len: errmsg.len(), }); @@ -396,13 +376,10 @@ impl<'a> Nmount<'a> { match Errno::result(res) { Ok(_) => Ok(()), Err(error) => { - let errmsg = match errmsg.iter().position(|&x| x == 0) { - None => None, - Some(0) => None, - Some(n) => { - let sl = &errmsg[0..n + 1]; - Some(CStr::from_bytes_with_nul(sl).unwrap()) - } + let errmsg = if errmsg[0] == 0 { + None + } else { + CStr::from_bytes_until_nul(&errmsg[..]).ok() }; Err(NmountError::new(error, errmsg)) } diff --git a/third_party/rust/nix/src/mount/linux.rs b/third_party/rust/nix/src/mount/linux.rs index e987603786..aa166bc9d3 100644 --- a/third_party/rust/nix/src/mount/linux.rs +++ b/third_party/rust/nix/src/mount/linux.rs @@ -85,7 +85,7 @@ libc_bitflags!( MNT_DETACH; /// Mark the mount point as expired. MNT_EXPIRE; - /// Don't dereference `target` if it is a symlink. + /// Don't dereference `target` if it is a symlink. UMOUNT_NOFOLLOW; } ); diff --git a/third_party/rust/nix/src/mount/mod.rs b/third_party/rust/nix/src/mount/mod.rs index e98b49c343..8caf27f7df 100644 --- a/third_party/rust/nix/src/mount/mod.rs +++ b/third_party/rust/nix/src/mount/mod.rs @@ -1,26 +1,12 @@ //! Mount file systems -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] mod linux; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use self::linux::*; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(bsd)] mod bsd; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] pub use self::bsd::*; diff --git a/third_party/rust/nix/src/mqueue.rs b/third_party/rust/nix/src/mqueue.rs index fb07d2accb..7f9d687521 100644 --- a/third_party/rust/nix/src/mqueue.rs +++ b/third_party/rust/nix/src/mqueue.rs @@ -35,7 +35,7 @@ use crate::NixPath; use crate::Result; use crate::sys::stat::Mode; -use libc::{self, c_char, mqd_t, size_t}; +use libc::{self, mqd_t, size_t}; use std::mem; #[cfg(any( target_os = "linux", @@ -88,11 +88,9 @@ pub struct MqdT(mqd_t); // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 /// Size of a message queue attribute member #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub type mq_attr_member_t = i64; /// Size of a message queue attribute member #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub type mq_attr_member_t = libc::c_long; impl MqAttr { @@ -205,7 +203,7 @@ pub fn mq_receive( let res = unsafe { libc::mq_receive( mqdes.0, - message.as_mut_ptr() as *mut c_char, + message.as_mut_ptr().cast(), len, msg_prio as *mut u32, ) @@ -229,7 +227,7 @@ feature! { let res = unsafe { libc::mq_timedreceive( mqdes.0, - message.as_mut_ptr() as *mut c_char, + message.as_mut_ptr().cast(), len, msg_prio as *mut u32, abstime.as_ref(), @@ -244,12 +242,7 @@ feature! { /// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> { let res = unsafe { - libc::mq_send( - mqdes.0, - message.as_ptr() as *const c_char, - message.len(), - msq_prio, - ) + libc::mq_send(mqdes.0, message.as_ptr().cast(), message.len(), msq_prio) }; Errno::result(res).map(drop) } diff --git a/third_party/rust/nix/src/net/if_.rs b/third_party/rust/nix/src/net/if_.rs index ec46260714..c66b5dc0b3 100644 --- a/third_party/rust/nix/src/net/if_.rs +++ b/third_party/rust/nix/src/net/if_.rs @@ -3,9 +3,17 @@ //! Uses Linux and/or POSIX functions to resolve interface names like "eth0" //! or "socan1" into device numbers. +use std::fmt; use crate::{Error, NixPath, Result}; use libc::c_uint; +#[cfg(not(solarish))] +/// type alias for InterfaceFlags +pub type IflagsType = libc::c_int; +#[cfg(solarish)] +/// type alias for InterfaceFlags +pub type IflagsType = libc::c_longlong; + /// Resolve an interface into a interface number. pub fn if_nametoindex(name: &P) -> Result { let if_index = name @@ -20,323 +28,236 @@ pub fn if_nametoindex(name: &P) -> Result { libc_bitflags!( /// Standard interface flags, used by `getifaddrs` - pub struct InterfaceFlags: libc::c_int { + pub struct InterfaceFlags: IflagsType { + /// Interface is running. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_UP; + IFF_UP as IflagsType; /// Valid broadcast address set. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_BROADCAST; + IFF_BROADCAST as IflagsType; /// Internal debugging flag. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(not(target_os = "haiku"))] - IFF_DEBUG; + IFF_DEBUG as IflagsType; /// Interface is a loopback interface. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_LOOPBACK; + IFF_LOOPBACK as IflagsType; /// Interface is a point-to-point link. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_POINTOPOINT; + IFF_POINTOPOINT as IflagsType; /// Avoid use of trailers. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", + #[cfg(any( + linux_android, + solarish, + apple_targets, target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOTRAILERS; + target_os = "netbsd"))] + IFF_NOTRAILERS as IflagsType; /// Interface manages own routes. #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_SMART; + IFF_SMART as IflagsType; /// Resources allocated. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_RUNNING; + #[cfg(any( + linux_android, + bsd, + solarish, + target_os = "fuchsia"))] + IFF_RUNNING as IflagsType; /// No arp protocol, L2 destination address not set. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_NOARP; + IFF_NOARP as IflagsType; /// Interface is in promiscuous mode. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_PROMISC; + IFF_PROMISC as IflagsType; /// Receive all multicast packets. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_ALLMULTI; + IFF_ALLMULTI as IflagsType; /// Master of a load balancing bundle. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] IFF_MASTER; /// transmission in progress, tx hardware queue is full - #[cfg(any(target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(target_os = "freebsd", apple_targets, netbsdlike))] IFF_OACTIVE; /// Protocol code on board. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_INTELLIGENT; + #[cfg(solarish)] + IFF_INTELLIGENT as IflagsType; /// Slave of a load balancing bundle. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] IFF_SLAVE; /// Can't hear own transmissions. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] IFF_SIMPLEX; /// Supports multicast. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_MULTICAST; + IFF_MULTICAST as IflagsType; /// Per link layer defined bit. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] IFF_LINK0; /// Multicast using broadcast. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_MULTI_BCAST; + #[cfg(solarish)] + IFF_MULTI_BCAST as IflagsType; /// Is able to select media type via ifmap. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] IFF_PORTSEL; /// Per link layer defined bit. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] IFF_LINK1; /// Non-unique address. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_UNNUMBERED; + #[cfg(solarish)] + IFF_UNNUMBERED as IflagsType; /// Auto media selection active. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] IFF_AUTOMEDIA; /// Per link layer defined bit. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] IFF_LINK2; /// Use alternate physical connection. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, apple_targets))] IFF_ALTPHYS; /// DHCP controls interface. - #[cfg(any(target_os = "solaris", target_os = "illumos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DHCPRUNNING; + #[cfg(solarish)] + IFF_DHCPRUNNING as IflagsType; /// The addresses are lost when the interface goes down. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] IFF_DYNAMIC; /// Do not advertise. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_PRIVATE; + #[cfg(solarish)] + IFF_PRIVATE as IflagsType; /// Driver signals L1 up. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_LOWER_UP; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_POLLING_COMPAT; /// Unconfigurable using ioctl(2). #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_CANTCONFIG; /// Do not transmit packets. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOXMIT; + #[cfg(solarish)] + IFF_NOXMIT as IflagsType; /// Driver signals dormant. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DORMANT; /// User-requested promisc mode. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] IFF_PPROMISC; /// Just on-link subnet. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOLOCAL; + #[cfg(solarish)] + IFF_NOLOCAL as IflagsType; /// Echo sent packets. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_ECHO; /// User-requested monitor mode. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] IFF_MONITOR; /// Address is deprecated. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DEPRECATED; + #[cfg(solarish)] + IFF_DEPRECATED as IflagsType; /// Static ARP. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] IFF_STATICARP; /// Address from stateless addrconf. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ADDRCONF; + #[cfg(solarish)] + IFF_ADDRCONF as IflagsType; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NPOLLING; /// Router on interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ROUTER; + #[cfg(solarish)] + IFF_ROUTER as IflagsType; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_IDIRECT; /// Interface is winding down #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DYING; /// No NUD on interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NONUD; + #[cfg(solarish)] + IFF_NONUD as IflagsType; /// Interface is being renamed #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IFF_RENAMING; /// Anycast address. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ANYCAST; + #[cfg(solarish)] + IFF_ANYCAST as IflagsType; /// Don't exchange routing info. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NORTEXCH; + #[cfg(solarish)] + IFF_NORTEXCH as IflagsType; /// Do not provide packet information - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NO_PI as libc::c_int; + #[cfg(any(linux_android, target_os = "fuchsia"))] + IFF_NO_PI as IflagsType; /// TUN device (no Ethernet headers) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_TUN as libc::c_int; + #[cfg(any(linux_android, target_os = "fuchsia"))] + IFF_TUN as IflagsType; /// TAP device - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_TAP as libc::c_int; + #[cfg(any(linux_android, target_os = "fuchsia"))] + IFF_TAP as IflagsType; /// IPv4 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPV4; + #[cfg(solarish)] + IFF_IPV4 as IflagsType; /// IPv6 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPV6; + #[cfg(solarish)] + IFF_IPV6 as IflagsType; /// in.mpathd test address - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOFAILOVER; + #[cfg(solarish)] + IFF_NOFAILOVER as IflagsType; /// Interface has failed - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_FAILED; + #[cfg(solarish)] + IFF_FAILED as IflagsType; /// Interface is a hot-spare - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_STANDBY; + #[cfg(solarish)] + IFF_STANDBY as IflagsType; /// Functioning but not used - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_INACTIVE; + #[cfg(solarish)] + IFF_INACTIVE as IflagsType; /// Interface is offline - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_OFFLINE; - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_COS_ENABLED; - /// Prefer as source addr. - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_PREFERRED; + #[cfg(solarish)] + IFF_OFFLINE as IflagsType; + /// Has CoS marking supported + #[cfg(solarish)] + IFF_COS_ENABLED as IflagsType; + /// Prefer as source addr + #[cfg(solarish)] + IFF_PREFERRED as IflagsType; /// RFC3041 - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_TEMPORARY; - /// MTU set with SIOCSLIFMTU - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_FIXEDMTU; - /// Cannot send / receive packets - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_VIRTUAL; + #[cfg(solarish)] + IFF_TEMPORARY as IflagsType; + /// MTU set + #[cfg(solarish)] + IFF_FIXEDMTU as IflagsType; + /// Cannot send/receive packets + #[cfg(solarish)] + IFF_VIRTUAL as IflagsType; /// Local address in use - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DUPLICATE; + #[cfg(solarish)] + IFF_DUPLICATE as IflagsType; /// IPMP IP interface - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPMP; + #[cfg(solarish)] + IFF_IPMP as IflagsType; } ); +impl fmt::Display for InterfaceFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + bitflags::parser::to_writer(self, f) + } +} + + #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "fuchsia", - target_os = "ios", target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", + solarish, ))] -#[cfg_attr(docsrs, doc(cfg(all())))] mod if_nameindex { use super::*; @@ -373,6 +294,7 @@ mod if_nameindex { } /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`]. + #[repr(transparent)] pub struct Interfaces { ptr: NonNull, } @@ -388,7 +310,7 @@ mod if_nameindex { /// null-terminated, so calling this calculates the length. If random access isn't needed, /// [`Interfaces::iter()`] should be used instead. pub fn to_slice(&self) -> &[Interface] { - let ifs = self.ptr.as_ptr() as *const Interface; + let ifs = self.ptr.as_ptr().cast(); let len = self.iter().count(); unsafe { std::slice::from_raw_parts(ifs, len) } } @@ -458,14 +380,9 @@ mod if_nameindex { } } #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "fuchsia", - target_os = "ios", target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", + solarish, ))] pub use if_nameindex::*; diff --git a/third_party/rust/nix/src/poll.rs b/third_party/rust/nix/src/poll.rs index 9181bf7f30..0ad9f40d3b 100644 --- a/third_party/rust/nix/src/poll.rs +++ b/third_party/rust/nix/src/poll.rs @@ -2,6 +2,7 @@ use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd}; use crate::errno::Errno; +pub use crate::poll_timeout::PollTimeout; use crate::Result; /// This is a wrapper around `libc::pollfd`. @@ -22,24 +23,35 @@ pub struct PollFd<'fd> { impl<'fd> PollFd<'fd> { /// Creates a new `PollFd` specifying the events of interest /// for a given file descriptor. - // - // Different from other I/O-safe interfaces, here, we have to take `AsFd` - // by reference to prevent the case where the `fd` is closed but it is - // still in use. For example: + /// + /// # Examples + /// ```no_run + /// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd}; + /// # use nix::{ + /// # poll::{PollTimeout, PollFd, PollFlags, poll}, + /// # unistd::{pipe, read} + /// # }; + /// let (r, w) = pipe().unwrap(); + /// let pfd = PollFd::new(r.as_fd(), PollFlags::POLLIN); + /// let mut fds = [pfd]; + /// poll(&mut fds, PollTimeout::NONE).unwrap(); + /// let mut buf = [0u8; 80]; + /// read(r.as_raw_fd(), &mut buf[..]); + /// ``` + // Unlike I/O functions, constructors like this must take `BorrowedFd` + // instead of AsFd or &AsFd. Otherwise, an `OwnedFd` argument would be + // dropped at the end of the method, leaving the structure referencing a + // closed file descriptor. For example: // // ```rust - // let (reader, _) = pipe().unwrap(); - // - // // If `PollFd::new()` takes `AsFd` by value, then `reader` will be consumed, - // // but the file descriptor of `reader` will still be in use. - // let pollfd = PollFd::new(reader, flag); - // + // let (r, _) = pipe().unwrap(); + // let pollfd = PollFd::new(r, flag); // Drops the OwnedFd // // Do something with `pollfd`, which uses the CLOSED fd. // ``` - pub fn new(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd> { + pub fn new(fd: BorrowedFd<'fd>, events: PollFlags) -> PollFd<'fd> { PollFd { pollfd: libc::pollfd { - fd: fd.as_fd().as_raw_fd(), + fd: fd.as_raw_fd(), events: events.bits(), revents: PollFlags::empty().bits(), }, @@ -133,19 +145,15 @@ libc_bitflags! { POLLOUT; /// Equivalent to [`POLLIN`](constant.POLLIN.html) #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] POLLRDNORM; #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Equivalent to [`POLLOUT`](constant.POLLOUT.html) POLLWRNORM; /// Priority band data can be read (generally unused on Linux). #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] POLLRDBAND; /// Priority data may be written. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] POLLWRBAND; /// Error condition (only returned in /// [`PollFd::revents`](struct.PollFd.html#method.revents); @@ -184,16 +192,19 @@ libc_bitflags! { /// /// Note that the timeout interval will be rounded up to the system clock /// granularity, and kernel scheduling delays mean that the blocking -/// interval may overrun by a small amount. Specifying a negative value -/// in timeout means an infinite timeout. Specifying a timeout of zero -/// causes `poll()` to return immediately, even if no file descriptors are -/// ready. -pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { +/// interval may overrun by a small amount. Specifying a [`PollTimeout::NONE`] +/// in timeout means an infinite timeout. Specifying a timeout of +/// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file +/// descriptors are ready. +pub fn poll>( + fds: &mut [PollFd], + timeout: T, +) -> Result { let res = unsafe { libc::poll( - fds.as_mut_ptr() as *mut libc::pollfd, + fds.as_mut_ptr().cast(), fds.len() as libc::nfds_t, - timeout, + i32::from(timeout.into()), ) }; @@ -213,7 +224,7 @@ feature! { /// so in that case `ppoll` differs from `poll` only in the precision of the /// timeout argument. /// -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, freebsdlike))] pub fn ppoll( fds: &mut [PollFd], timeout: Option, @@ -223,7 +234,7 @@ pub fn ppoll( let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); let res = unsafe { - libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, + libc::ppoll(fds.as_mut_ptr().cast(), fds.len() as libc::nfds_t, timeout, sigmask) diff --git a/third_party/rust/nix/src/poll_timeout.rs b/third_party/rust/nix/src/poll_timeout.rs new file mode 100644 index 0000000000..f7d9015f56 --- /dev/null +++ b/third_party/rust/nix/src/poll_timeout.rs @@ -0,0 +1,224 @@ +use std::time::Duration; + +/// PollTimeout argument for polling. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +pub struct PollTimeout(i32); + +impl PollTimeout { + /// Blocks indefinitely. + /// + /// > Specifying a negative value in timeout means an infinite timeout. + pub const NONE: Self = Self(-1); + /// Returns immediately. + /// + /// > Specifying a timeout of zero causes poll() to return immediately, even if no file + /// > descriptors are ready. + pub const ZERO: Self = Self(0); + /// Blocks for at most [`i32::MAX`] milliseconds. + pub const MAX: Self = Self(i32::MAX); + /// Returns if `self` equals [`PollTimeout::NONE`]. + pub fn is_none(&self) -> bool { + // > Specifying a negative value in timeout means an infinite timeout. + *self <= Self::NONE + } + /// Returns if `self` does not equal [`PollTimeout::NONE`]. + pub fn is_some(&self) -> bool { + !self.is_none() + } + /// Returns the timeout in milliseconds if there is some, otherwise returns `None`. + pub fn as_millis(&self) -> Option { + self.is_some().then_some(u32::try_from(self.0).unwrap()) + } + /// Returns the timeout as a `Duration` if there is some, otherwise returns `None`. + pub fn duration(&self) -> Option { + self.as_millis() + .map(|x| Duration::from_millis(u64::from(x))) + } +} + +/// Error type for integer conversions into `PollTimeout`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PollTimeoutTryFromError { + /// Passing a value less than -1 is invalid on some systems, see + /// . + TooNegative, + /// Passing a value greater than `i32::MAX` is invalid. + TooPositive, +} + +impl std::fmt::Display for PollTimeoutTryFromError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TooNegative => write!(f, "Passed a negative timeout less than -1."), + Self::TooPositive => write!(f, "Passed a positive timeout greater than `i32::MAX` milliseconds.") + } + } +} + +impl std::error::Error for PollTimeoutTryFromError {} + +impl> From> for PollTimeout { + fn from(x: Option) -> Self { + x.map_or(Self::NONE, |x| x.into()) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: Duration) -> std::result::Result { + Ok(Self( + i32::try_from(x.as_millis()) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u128) -> std::result::Result { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u64) -> std::result::Result { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u32) -> std::result::Result { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl From for PollTimeout { + fn from(x: u16) -> Self { + Self(i32::from(x)) + } +} +impl From for PollTimeout { + fn from(x: u8) -> Self { + Self(i32::from(x)) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i128) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i64) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i32) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(x)), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i16) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(i32::from(x))), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i8) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(i32::from(x))), + } + } +} +impl TryFrom for Duration { + type Error = (); + fn try_from(x: PollTimeout) -> std::result::Result { + x.duration().ok_or(()) + } +} +impl TryFrom for u128 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u64 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u32 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u16 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u8 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl From for i128 { + fn from(x: PollTimeout) -> Self { + Self::from(x.0) + } +} +impl From for i64 { + fn from(x: PollTimeout) -> Self { + Self::from(x.0) + } +} +impl From for i32 { + fn from(x: PollTimeout) -> Self { + x.0 + } +} +impl TryFrom for i16 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for i8 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} diff --git a/third_party/rust/nix/src/pty.rs b/third_party/rust/nix/src/pty.rs index 455828b703..74f8ecf0df 100644 --- a/third_party/rust/nix/src/pty.rs +++ b/third_party/rust/nix/src/pty.rs @@ -71,7 +71,7 @@ impl io::Read for PtyMaster { impl io::Write for PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::write(&self.0, buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -86,7 +86,7 @@ impl io::Read for &PtyMaster { impl io::Write for &PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::write(&self.0, buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -169,12 +169,12 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result { /// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`. #[inline] pub unsafe fn ptsname(fd: &PtyMaster) -> Result { - let name_ptr = libc::ptsname(fd.as_raw_fd()); + let name_ptr = unsafe { libc::ptsname(fd.as_raw_fd()) }; if name_ptr.is_null() { return Err(Errno::last()); } - let name = CStr::from_ptr(name_ptr); + let name = unsafe { CStr::from_ptr(name_ptr) }; Ok(name.to_string_lossy().into_owned()) } @@ -187,8 +187,7 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result { /// /// This value is useful for opening the slave ptty once the master has already been opened with /// `posix_openpt()`. -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] #[inline] pub fn ptsname_r(fd: &PtyMaster) -> Result { let mut name_buf = Vec::::with_capacity(64); @@ -342,7 +341,7 @@ pub unsafe fn forkpty<'a, 'b, T: Into>, U: Into ForkResult::Child, @@ -350,7 +349,7 @@ pub unsafe fn forkpty<'a, 'b, T: Into>, U: Into isize>) -> i32, - ), - ptr_aligned as *mut c_void, - combined, - &mut cb as *mut _ as *mut c_void, - ); + let res = unsafe { + let ptr = stack.as_mut_ptr().add(stack.len()); + let ptr_aligned = ptr.sub(ptr as usize % 16); + libc::clone( + mem::transmute( + callback + as extern "C" fn(*mut Box isize>) -> i32, + ), + ptr_aligned as *mut c_void, + combined, + &mut cb as *mut _ as *mut c_void, + ) + }; Errno::result(res).map(Pid::from_raw) } @@ -151,20 +152,10 @@ mod sched_linux_like { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] +#[cfg(any(linux_android, freebsdlike))] pub use self::sched_affinity::*; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] +#[cfg(any(linux_android, freebsdlike))] mod sched_affinity { use crate::errno::Errno; use crate::unistd::Pid; diff --git a/third_party/rust/nix/src/sys/aio.rs b/third_party/rust/nix/src/sys/aio.rs index 5471177e3e..e9213c6434 100644 --- a/third_party/rust/nix/src/sys/aio.rs +++ b/third_party/rust/nix/src/sys/aio.rs @@ -35,7 +35,7 @@ use std::{ ptr, thread, }; -use libc::{c_void, off_t}; +use libc::off_t; use pin_utils::unsafe_pinned; use crate::{ @@ -53,12 +53,9 @@ libc_enum! { /// do it like `fsync` O_SYNC, /// on supported operating systems only, do it like `fdatasync` - #[cfg(any(target_os = "ios", + #[cfg(any(apple_targets, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + netbsdlike))] O_DSYNC } impl TryFrom @@ -161,7 +158,7 @@ impl AioCb { let r = unsafe { libc::aio_error(&self.aiocb().0) }; match r { 0 => Ok(()), - num if num > 0 => Err(Errno::from_i32(num)), + num if num > 0 => Err(Errno::from_raw(num)), -1 => Err(Errno::last()), num => panic!("unknown aio_error return value {num:?}"), } @@ -581,7 +578,7 @@ impl<'a> AioRead<'a> { ) -> Self { let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); aiocb.aiocb.0.aio_nbytes = buf.len(); - aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void; + aiocb.aiocb.0.aio_buf = buf.as_mut_ptr().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ; aiocb.aiocb.0.aio_offset = offs; AioRead { @@ -702,7 +699,7 @@ impl<'a> AioReadv<'a> { // In vectored mode, aio_nbytes stores the length of the iovec array, // not the byte count. aiocb.aiocb.0.aio_nbytes = bufs.len(); - aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void; + aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV; aiocb.aiocb.0.aio_offset = offs; AioReadv { @@ -817,7 +814,7 @@ impl<'a> AioWrite<'a> { // but technically its only unsafe to dereference it, not to create // it. Type Safety guarantees that we'll never pass aiocb to // aio_read or aio_readv. - aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void; + aiocb.aiocb.0.aio_buf = buf.as_ptr().cast_mut().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE; aiocb.aiocb.0.aio_offset = offs; AioWrite { @@ -935,7 +932,7 @@ impl<'a> AioWritev<'a> { // but technically its only unsafe to dereference it, not to create // it. Type Safety guarantees that we'll never pass aiocb to // aio_read or aio_readv. - aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void; + aiocb.aiocb.0.aio_buf = bufs.as_ptr().cast_mut().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV; aiocb.aiocb.0.aio_offset = offs; AioWritev { @@ -1055,7 +1052,8 @@ pub fn aio_suspend( // generic, and accepting arguments like &[AioWrite]. But that would // prevent using aio_suspend to wait on a heterogeneous list of mixed // operations. - let v = list.iter() + let v = list + .iter() .map(|x| x.as_ref() as *const libc::aiocb) .collect::>(); let p = v.as_ptr(); @@ -1175,7 +1173,10 @@ pub fn aio_suspend( /// // notification, we know that all operations are complete. /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); /// ``` -#[deprecated(since = "0.27.0", note = "https://github.com/nix-rust/nix/issues/2017")] +#[deprecated( + since = "0.27.0", + note = "https://github.com/nix-rust/nix/issues/2017" +)] pub fn lio_listio( mode: LioMode, list: &mut [Pin<&mut dyn AsMut>], @@ -1190,56 +1191,3 @@ pub fn lio_listio( }) .map(drop) } - -#[cfg(test)] -mod t { - use super::*; - - /// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb - /// pointers. This test ensures that such casts are valid. - #[test] - fn casting() { - let sev = SigevNotify::SigevNone; - let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev); - assert_eq!( - aiof.as_ref() as *const libc::aiocb, - &aiof as *const AioFsync as *const libc::aiocb - ); - - let mut rbuf = []; - let aior = AioRead::new(666, 0, &mut rbuf, 0, sev); - assert_eq!( - aior.as_ref() as *const libc::aiocb, - &aior as *const AioRead as *const libc::aiocb - ); - - let wbuf = []; - let aiow = AioWrite::new(666, 0, &wbuf, 0, sev); - assert_eq!( - aiow.as_ref() as *const libc::aiocb, - &aiow as *const AioWrite as *const libc::aiocb - ); - } - - #[cfg(target_os = "freebsd")] - #[test] - fn casting_vectored() { - let sev = SigevNotify::SigevNone; - - let mut rbuf = []; - let mut rbufs = [IoSliceMut::new(&mut rbuf)]; - let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev); - assert_eq!( - aiorv.as_ref() as *const libc::aiocb, - &aiorv as *const AioReadv as *const libc::aiocb - ); - - let wbuf = []; - let wbufs = [IoSlice::new(&wbuf)]; - let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev); - assert_eq!( - aiowv.as_ref() as *const libc::aiocb, - &aiowv as *const AioWritev as *const libc::aiocb - ); - } -} diff --git a/third_party/rust/nix/src/sys/epoll.rs b/third_party/rust/nix/src/sys/epoll.rs index 36f9c17d0e..ec146a8c53 100644 --- a/third_party/rust/nix/src/sys/epoll.rs +++ b/third_party/rust/nix/src/sys/epoll.rs @@ -1,4 +1,5 @@ use crate::errno::Errno; +pub use crate::poll_timeout::PollTimeout as EpollTimeout; use crate::Result; use libc::{self, c_int}; use std::mem; @@ -71,32 +72,32 @@ impl EpollEvent { /// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html). /// ``` -/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}}; +/// # use nix::sys::{epoll::{EpollTimeout, Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{EventFd, EfdFlags}}; /// # use nix::unistd::write; -/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd}; +/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsFd}; /// # use std::time::{Instant, Duration}; /// # fn main() -> nix::Result<()> { /// const DATA: u64 = 17; -/// const MILLIS: u64 = 100; +/// const MILLIS: u8 = 100; /// /// // Create epoll /// let epoll = Epoll::new(EpollCreateFlags::empty())?; /// /// // Create eventfd & Add event -/// let eventfd = eventfd(0, EfdFlags::empty())?; +/// let eventfd = EventFd::new()?; /// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?; /// /// // Arm eventfd & Time wait -/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?; +/// eventfd.arm()?; /// let now = Instant::now(); /// /// // Wait on event /// let mut events = [EpollEvent::empty()]; -/// epoll.wait(&mut events, MILLIS as isize)?; +/// epoll.wait(&mut events, MILLIS)?; /// /// // Assert data correct & timeout didn't occur /// assert_eq!(events[0].data(), DATA); -/// assert!(now.elapsed() < Duration::from_millis(MILLIS)); +/// assert!(now.elapsed().as_millis() < MILLIS.into()); /// # Ok(()) /// # } /// ``` @@ -140,17 +141,17 @@ impl Epoll { /// (This can be thought of as fetching items from the ready list of the epoll instance.) /// /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html) - pub fn wait( + pub fn wait>( &self, events: &mut [EpollEvent], - timeout: isize, + timeout: T, ) -> Result { let res = unsafe { libc::epoll_wait( self.0.as_raw_fd(), - events.as_mut_ptr() as *mut libc::epoll_event, + events.as_mut_ptr().cast(), events.len() as c_int, - timeout as c_int, + timeout.into().into(), ) }; @@ -240,7 +241,7 @@ pub fn epoll_wait( let res = unsafe { libc::epoll_wait( epfd, - events.as_mut_ptr() as *mut libc::epoll_event, + events.as_mut_ptr().cast(), events.len() as c_int, timeout_ms as c_int, ) diff --git a/third_party/rust/nix/src/sys/event.rs b/third_party/rust/nix/src/sys/event.rs index ec7f7e277a..b294d27c70 100644 --- a/third_party/rust/nix/src/sys/event.rs +++ b/third_party/rust/nix/src/sys/event.rs @@ -10,6 +10,7 @@ use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; use std::convert::TryInto; use std::mem; +use std::os::fd::{AsFd, BorrowedFd}; use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; use std::ptr; @@ -29,6 +30,18 @@ pub struct KEvent { #[derive(Debug)] pub struct Kqueue(OwnedFd); +impl AsFd for Kqueue { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl From for OwnedFd { + fn from(value: Kqueue) -> Self { + value.0 + } +} + impl Kqueue { /// Create a new kernel event queue. pub fn new() -> Result { @@ -63,9 +76,9 @@ impl Kqueue { let res = unsafe { libc::kevent( self.0.as_raw_fd(), - changelist.as_ptr() as *const libc::kevent, + changelist.as_ptr().cast(), changelist.len() as type_of_nchanges, - eventlist.as_mut_ptr() as *mut libc::kevent, + eventlist.as_mut_ptr().cast(), eventlist.len() as type_of_nchanges, if let Some(ref timeout) = timeout_opt { timeout as *const timespec @@ -78,13 +91,7 @@ impl Kqueue { } } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] type type_of_udata = *mut libc::c_void; #[cfg(target_os = "netbsd")] type type_of_udata = intptr_t; @@ -109,10 +116,7 @@ libc_enum! { /// Takes a descriptor as the identifier, and returns whenever one of /// the specified exceptional conditions has occurred on the descriptor. EVFILT_EXCEPT, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] + #[cfg(any(freebsdlike, apple_targets))] /// Establishes a file system monitor. EVFILT_FS, #[cfg(target_os = "freebsd")] @@ -120,7 +124,7 @@ libc_enum! { /// # See Also /// [lio_listio(2)](https://www.freebsd.org/cgi/man.cgi?query=lio_listio) EVFILT_LIO, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] /// Mach portsets EVFILT_MACHPORT, /// Notifies when a process performs one or more of the requested @@ -144,13 +148,10 @@ libc_enum! { EVFILT_SIGNAL, /// Establishes a timer and notifies when the timer expires. EVFILT_TIMER, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] + #[cfg(any(freebsdlike, apple_targets))] /// Notifies only when explicitly requested by the user. EVFILT_USER, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] /// Virtual memory events EVFILT_VM, /// Notifies when a requested event happens on a specified file. @@ -162,13 +163,7 @@ libc_enum! { impl TryFrom } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] #[doc(hidden)] pub type type_of_event_flag = u16; #[cfg(target_os = "netbsd")] @@ -187,9 +182,7 @@ libc_bitflags! { EV_DELETE; #[allow(missing_docs)] EV_DISABLE; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] + #[cfg(bsd)] #[allow(missing_docs)] EV_DISPATCH; #[cfg(target_os = "freebsd")] @@ -201,7 +194,7 @@ libc_bitflags! { EV_EOF; #[allow(missing_docs)] EV_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] EV_FLAG0; #[allow(missing_docs)] @@ -211,15 +204,13 @@ libc_bitflags! { EV_NODATA; #[allow(missing_docs)] EV_ONESHOT; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] EV_OOBAND; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] EV_POLL; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] + #[cfg(bsd)] #[allow(missing_docs)] EV_RECEIPT; } @@ -231,7 +222,7 @@ libc_bitflags!( // that wouldn't simply be repeating the man page. #[allow(missing_docs)] pub struct FilterFlag: u32 { - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_ABSOLUTE; #[allow(missing_docs)] @@ -247,45 +238,27 @@ libc_bitflags!( NOTE_EXEC; #[allow(missing_docs)] NOTE_EXIT; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_EXITSTATUS; #[allow(missing_docs)] NOTE_EXTEND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFAND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFCOPY; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFCTRLMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFLAGSMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFNOP; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFOR; #[allow(missing_docs)] @@ -297,10 +270,12 @@ libc_bitflags!( #[cfg(target_os = "freebsd")] #[allow(missing_docs)] NOTE_MSECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_NONE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[cfg(any( + apple_targets, + target_os = "freebsd"))] #[allow(missing_docs)] NOTE_NSECONDS; #[cfg(target_os = "dragonfly")] @@ -314,38 +289,39 @@ libc_bitflags!( NOTE_RENAME; #[allow(missing_docs)] NOTE_REVOKE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[cfg(any( + apple_targets, + target_os = "freebsd"))] #[allow(missing_docs)] NOTE_SECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_SIGNAL; #[allow(missing_docs)] NOTE_TRACK; #[allow(missing_docs)] NOTE_TRACKERR; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_TRIGGER; #[cfg(target_os = "openbsd")] #[allow(missing_docs)] NOTE_TRUNCATE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[cfg(any( + apple_targets, + target_os = "freebsd"))] #[allow(missing_docs)] NOTE_USECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_PRESSURE; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_PRESSURE_SUDDEN_TERMINATE; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_PRESSURE_TERMINATE; #[allow(missing_docs)] @@ -443,13 +419,7 @@ pub fn kevent( kq.kevent(changelist, eventlist, Some(timeout)) } -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd" -))] +#[cfg(any(apple_targets, freebsdlike, target_os = "openbsd"))] type type_of_nchanges = c_int; #[cfg(target_os = "netbsd")] type type_of_nchanges = size_t; @@ -484,42 +454,3 @@ pub fn ev_set( ev.kevent.data = 0; ev.kevent.udata = udata as type_of_udata; } - -#[test] -fn test_struct_kevent() { - use std::mem; - - let udata: intptr_t = 12345; - - let actual = KEvent::new( - 0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata, - ); - assert_eq!(0xdead_beef, actual.ident()); - let filter = actual.kevent.filter; - assert_eq!(libc::EVFILT_READ, filter); - assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); - assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); - assert_eq!(0x1337, actual.data()); - assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); - assert_eq!(mem::size_of::(), mem::size_of::()); -} - -#[test] -fn test_kevent_filter() { - let udata: intptr_t = 12345; - - let actual = KEvent::new( - 0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata, - ); - assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); -} diff --git a/third_party/rust/nix/src/sys/eventfd.rs b/third_party/rust/nix/src/sys/eventfd.rs index f1723519cf..50a4f091bd 100644 --- a/third_party/rust/nix/src/sys/eventfd.rs +++ b/third_party/rust/nix/src/sys/eventfd.rs @@ -1,17 +1,84 @@ use crate::errno::Errno; -use crate::Result; -use std::os::unix::io::{FromRawFd, OwnedFd}; +use crate::{Result,unistd}; +use std::os::unix::io::{FromRawFd, OwnedFd, AsRawFd, AsFd, RawFd, BorrowedFd}; libc_bitflags! { pub struct EfdFlags: libc::c_int { - EFD_CLOEXEC; // Since Linux 2.6.27 - EFD_NONBLOCK; // Since Linux 2.6.27 - EFD_SEMAPHORE; // Since Linux 2.6.30 + EFD_CLOEXEC; // Since Linux 2.6.27/FreeBSD 13.0 + EFD_NONBLOCK; // Since Linux 2.6.27/FreeBSD 13.0 + EFD_SEMAPHORE; // Since Linux 2.6.30/FreeBSD 13.0 } } +#[deprecated(since = "0.28.0", note = "Use EventFd::from_value_and_flags() instead")] pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result { let res = unsafe { libc::eventfd(initval, flags.bits()) }; Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r) }) } + +#[derive(Debug)] +#[repr(transparent)] +pub struct EventFd(OwnedFd); +impl EventFd { + /// [`EventFd::from_value_and_flags`] with `init_val = 0` and `flags = EfdFlags::empty()`. + pub fn new() -> Result { + Self::from_value_and_flags(0, EfdFlags::empty()) + } + /// Constructs [`EventFd`] with the given `init_val` and `flags`. + /// + /// Wrapper around [`libc::eventfd`]. + pub fn from_value_and_flags(init_val: u32, flags: EfdFlags) -> Result { + let res = unsafe { libc::eventfd(init_val, flags.bits()) }; + Errno::result(res).map(|r| Self(unsafe { OwnedFd::from_raw_fd(r) })) + } + /// [`EventFd::from_value_and_flags`] with `init_val = 0` and given `flags`. + pub fn from_flags(flags: EfdFlags) -> Result { + Self::from_value_and_flags(0, flags) + } + /// [`EventFd::from_value_and_flags`] with given `init_val` and `flags = EfdFlags::empty()`. + pub fn from_value(init_val: u32) -> Result { + Self::from_value_and_flags(init_val, EfdFlags::empty()) + } + /// Arms `self`, a following call to `poll`, `select` or `epoll` will return immediately. + /// + /// [`EventFd::write`] with `1`. + pub fn arm(&self) -> Result { + self.write(1) + } + /// Defuses `self`, a following call to `poll`, `select` or `epoll` will block. + /// + /// [`EventFd::write`] with `0`. + pub fn defuse(&self) -> Result { + self.write(0) + } + /// Enqueues `value` triggers. + /// + /// The next `value` calls to `poll`, `select` or `epoll` will return immediately. + /// + /// [`EventFd::write`] with `value`. + pub fn write(&self, value: u64) -> Result { + unistd::write(&self.0,&value.to_ne_bytes()) + } + // Reads the value from the file descriptor. + pub fn read(&self) -> Result { + let mut arr = [0; std::mem::size_of::()]; + unistd::read(self.0.as_raw_fd(),&mut arr)?; + Ok(u64::from_ne_bytes(arr)) + } +} +impl AsFd for EventFd { + fn as_fd(&self) -> BorrowedFd { + self.0.as_fd() + } +} +impl AsRawFd for EventFd { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +impl From for OwnedFd { + fn from(x: EventFd) -> OwnedFd { + x.0 + } +} diff --git a/third_party/rust/nix/src/sys/fanotify.rs b/third_party/rust/nix/src/sys/fanotify.rs new file mode 100644 index 0000000000..e217406e02 --- /dev/null +++ b/third_party/rust/nix/src/sys/fanotify.rs @@ -0,0 +1,416 @@ +//! Monitoring API for filesystem events. +//! +//! Fanotify is a Linux-only API to monitor filesystems events. +//! +//! Additional capabilities compared to the `inotify` API include the ability to +//! monitor all of the objects in a mounted filesystem, the ability to make +//! access permission decisions, and the possibility to read or modify files +//! before access by other applications. +//! +//! For more documentation, please read +//! [fanotify(7)](https://man7.org/linux/man-pages/man7/fanotify.7.html). + +use crate::errno::Errno; +use crate::fcntl::{at_rawfd, OFlag}; +use crate::unistd::{close, read, write}; +use crate::{NixPath, Result}; +use std::marker::PhantomData; +use std::mem::{size_of, MaybeUninit}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; +use std::ptr; + +libc_bitflags! { + /// Mask for defining which events shall be listened with + /// [`fanotify_mark`](fn.fanotify_mark.html) and for querying notifications. + pub struct MaskFlags: u64 { + /// File was accessed. + FAN_ACCESS; + /// File was modified. + FAN_MODIFY; + /// Metadata has changed. Since Linux 5.1. + FAN_ATTRIB; + /// Writtable file was closed. + FAN_CLOSE_WRITE; + /// Unwrittable file was closed. + FAN_CLOSE_NOWRITE; + /// File was opened. + FAN_OPEN; + /// File was moved from X. Since Linux 5.1. + FAN_MOVED_FROM; + /// File was moved to Y. Since Linux 5.1. + FAN_MOVED_TO; + /// Subfile was created. Since Linux 5.1. + FAN_CREATE; + /// Subfile was deleted. Since Linux 5.1. + FAN_DELETE; + /// Self was deleted. Since Linux 5.1. + FAN_DELETE_SELF; + /// Self was moved. Since Linux 5.1. + FAN_MOVE_SELF; + /// File was opened for execution. Since Linux 5.0. + FAN_OPEN_EXEC; + + /// Event queue overflowed. + FAN_Q_OVERFLOW; + /// Filesystem error. Since Linux 5.16. + FAN_FS_ERROR; + + /// Permission to open file was requested. + FAN_OPEN_PERM; + /// Permission to access file was requested. + FAN_ACCESS_PERM; + /// Permission to open file for execution was requested. Since Linux + /// 5.0. + FAN_OPEN_EXEC_PERM; + + /// Interested in child events. + FAN_EVENT_ON_CHILD; + + /// File was renamed. Since Linux 5.17. + FAN_RENAME; + + /// Event occurred against dir. + FAN_ONDIR; + + /// Combination of `FAN_CLOSE_WRITE` and `FAN_CLOSE_NOWRITE`. + FAN_CLOSE; + /// Combination of `FAN_MOVED_FROM` and `FAN_MOVED_TO`. + FAN_MOVE; + } +} + +libc_bitflags! { + /// Configuration options for [`fanotify_init`](fn.fanotify_init.html). + pub struct InitFlags: libc::c_uint { + /// Close-on-exec flag set on the file descriptor. + FAN_CLOEXEC; + /// Nonblocking flag set on the file descriptor. + FAN_NONBLOCK; + + /// Receipt of events notifications. + FAN_CLASS_NOTIF; + /// Receipt of events for permission decisions, after they contain final + /// data. + FAN_CLASS_CONTENT; + /// Receipt of events for permission decisions, before they contain + /// final data. + FAN_CLASS_PRE_CONTENT; + + /// Remove the limit of 16384 events for the event queue. + FAN_UNLIMITED_QUEUE; + /// Remove the limit of 8192 marks. + FAN_UNLIMITED_MARKS; + + /// Make `FanotifyEvent::pid` return pidfd. Since Linux 5.15. + FAN_REPORT_PIDFD; + /// Make `FanotifyEvent::pid` return thread id. Since Linux 4.20. + FAN_REPORT_TID; + } +} + +libc_bitflags! { + /// File status flags for fanotify events file descriptors. + pub struct EventFFlags: libc::c_uint { + /// Read only access. + O_RDONLY as libc::c_uint; + /// Write only access. + O_WRONLY as libc::c_uint; + /// Read and write access. + O_RDWR as libc::c_uint; + /// Support for files exceeded 2 GB. + O_LARGEFILE as libc::c_uint; + /// Close-on-exec flag for the file descriptor. Since Linux 3.18. + O_CLOEXEC as libc::c_uint; + /// Append mode for the file descriptor. + O_APPEND as libc::c_uint; + /// Synchronized I/O data integrity completion. + O_DSYNC as libc::c_uint; + /// No file last access time update. + O_NOATIME as libc::c_uint; + /// Nonblocking mode for the file descriptor. + O_NONBLOCK as libc::c_uint; + /// Synchronized I/O file integrity completion. + O_SYNC as libc::c_uint; + } +} + +impl TryFrom for EventFFlags { + type Error = Errno; + + fn try_from(o_flag: OFlag) -> Result { + EventFFlags::from_bits(o_flag.bits() as u32).ok_or(Errno::EINVAL) + } +} + +impl From for OFlag { + fn from(event_f_flags: EventFFlags) -> Self { + OFlag::from_bits_retain(event_f_flags.bits() as i32) + } +} + +libc_bitflags! { + /// Configuration options for [`fanotify_mark`](fn.fanotify_mark.html). + pub struct MarkFlags: libc::c_uint { + /// Add the events to the marks. + FAN_MARK_ADD; + /// Remove the events to the marks. + FAN_MARK_REMOVE; + /// Don't follow symlinks, mark them. + FAN_MARK_DONT_FOLLOW; + /// Raise an error if filesystem to be marked is not a directory. + FAN_MARK_ONLYDIR; + /// Events added to or removed from the marks. + FAN_MARK_IGNORED_MASK; + /// Ignore mask shall survive modify events. + FAN_MARK_IGNORED_SURV_MODIFY; + /// Remove all marks. + FAN_MARK_FLUSH; + /// Do not pin inode object in the inode cache. Since Linux 5.19. + FAN_MARK_EVICTABLE; + /// Events added to or removed from the marks. Since Linux 6.0. + FAN_MARK_IGNORE; + + /// Default flag. + FAN_MARK_INODE; + /// Mark the mount specified by pathname. + FAN_MARK_MOUNT; + /// Mark the filesystem specified by pathname. Since Linux 4.20. + FAN_MARK_FILESYSTEM; + + /// Combination of `FAN_MARK_IGNORE` and `FAN_MARK_IGNORED_SURV_MODIFY`. + FAN_MARK_IGNORE_SURV; + } +} + +/// Compile version number of fanotify API. +pub const FANOTIFY_METADATA_VERSION: u8 = libc::FANOTIFY_METADATA_VERSION; + +/// Abstract over `libc::fanotify_event_metadata`, which represents an event +/// received via `Fanotify::read_events`. +// Is not Clone due to fd field, to avoid use-after-close scenarios. +#[derive(Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +#[allow(missing_copy_implementations)] +pub struct FanotifyEvent(libc::fanotify_event_metadata); + +impl FanotifyEvent { + /// Version number for the structure. It must be compared to + /// `FANOTIFY_METADATA_VERSION` to verify compile version and runtime + /// version does match. It can be done with the + /// `FanotifyEvent::check_version` method. + pub fn version(&self) -> u8 { + self.0.vers + } + + /// Checks that compile fanotify API version is equal to the version of the + /// event. + pub fn check_version(&self) -> bool { + self.version() == FANOTIFY_METADATA_VERSION + } + + /// Mask flags of the events. + pub fn mask(&self) -> MaskFlags { + MaskFlags::from_bits_truncate(self.0.mask) + } + + /// The file descriptor of the event. If the value is `None` when reading + /// from the fanotify group, this event is to notify that a group queue + /// overflow occured. + pub fn fd(&self) -> Option { + if self.0.fd == libc::FAN_NOFD { + None + } else { + // SAFETY: self.0.fd will be opened for the lifetime of `Self`, + // which is longer than the lifetime of the returned BorrowedFd, so + // it is safe. + Some(unsafe { BorrowedFd::borrow_raw(self.0.fd) }) + } + } + + /// PID of the process that caused the event. TID in case flag + /// `FAN_REPORT_TID` was set at group initialization. + pub fn pid(&self) -> i32 { + self.0.pid + } +} + +impl Drop for FanotifyEvent { + fn drop(&mut self) { + let e = close(self.0.fd); + if !std::thread::panicking() && e == Err(Errno::EBADF) { + panic!("Closing an invalid file descriptor!"); + }; + } +} + +/// Abstraction over the structure to be sent to allow or deny a given event. +#[derive(Debug)] +#[repr(transparent)] +pub struct FanotifyResponse<'a> { + inner: libc::fanotify_response, + _borrowed_fd: PhantomData>, +} + +impl<'a> FanotifyResponse<'a> { + /// Create a new response. + pub fn new(fd: BorrowedFd<'a>, response: Response) -> Self { + Self { + inner: libc::fanotify_response { + fd: fd.as_raw_fd(), + response: response.bits(), + }, + _borrowed_fd: PhantomData, + } + } +} + +libc_bitflags! { + /// Response to be wrapped in `FanotifyResponse` and sent to the `Fanotify` + /// group to allow or deny an event. + pub struct Response: u32 { + /// Allow the event. + FAN_ALLOW; + /// Deny the event. + FAN_DENY; + } +} + +/// A fanotify group. This is also a file descriptor that can feed to other +/// interfaces consuming file descriptors. +#[derive(Debug)] +pub struct Fanotify { + fd: OwnedFd, +} + +impl Fanotify { + /// Initialize a new fanotify group. + /// + /// Returns a Result containing a Fanotify instance. + /// + /// For more information, see [fanotify_init(2)](https://man7.org/linux/man-pages/man7/fanotify_init.2.html). + pub fn init( + flags: InitFlags, + event_f_flags: EventFFlags, + ) -> Result { + let res = Errno::result(unsafe { + libc::fanotify_init(flags.bits(), event_f_flags.bits()) + }); + res.map(|fd| Fanotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + }) + } + + /// Add, remove, or modify an fanotify mark on a filesystem object. + /// If `dirfd` is `None`, `AT_FDCWD` is used. + /// + /// Returns a Result containing either `()` on success or errno otherwise. + /// + /// For more information, see [fanotify_mark(2)](https://man7.org/linux/man-pages/man7/fanotify_mark.2.html). + pub fn mark( + &self, + flags: MarkFlags, + mask: MaskFlags, + dirfd: Option, + path: Option<&P>, + ) -> Result<()> { + fn with_opt_nix_path(p: Option<&P>, f: F) -> Result + where + P: ?Sized + NixPath, + F: FnOnce(*const libc::c_char) -> T, + { + match p { + Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())), + None => Ok(f(std::ptr::null())), + } + } + + let res = with_opt_nix_path(path, |p| unsafe { + libc::fanotify_mark( + self.fd.as_raw_fd(), + flags.bits(), + mask.bits(), + at_rawfd(dirfd), + p, + ) + })?; + + Errno::result(res).map(|_| ()) + } + + /// Read incoming events from the fanotify group. + /// + /// Returns a Result containing either a `Vec` of events on success or errno + /// otherwise. + /// + /// # Errors + /// + /// Possible errors can be those that are explicitly listed in + /// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in + /// addition to the possible errors caused by `read` call. + /// In particular, `EAGAIN` is returned when no event is available on a + /// group that has been initialized with the flag `InitFlags::FAN_NONBLOCK`, + /// thus making this method nonblocking. + pub fn read_events(&self) -> Result> { + let metadata_size = size_of::(); + const BUFSIZ: usize = 4096; + let mut buffer = [0u8; BUFSIZ]; + let mut events = Vec::new(); + let mut offset = 0; + + let nread = read(self.fd.as_raw_fd(), &mut buffer)?; + + while (nread - offset) >= metadata_size { + let metadata = unsafe { + let mut metadata = + MaybeUninit::::uninit(); + ptr::copy_nonoverlapping( + buffer.as_ptr().add(offset), + metadata.as_mut_ptr().cast(), + (BUFSIZ - offset).min(metadata_size), + ); + metadata.assume_init() + }; + + events.push(FanotifyEvent(metadata)); + offset += metadata.event_len as usize; + } + + Ok(events) + } + + /// Write an event response on the fanotify group. + /// + /// Returns a Result containing either `()` on success or errno otherwise. + /// + /// # Errors + /// + /// Possible errors can be those that are explicitly listed in + /// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in + /// addition to the possible errors caused by `write` call. + /// In particular, `EAGAIN` or `EWOULDBLOCK` is returned when no event is + /// available on a group that has been initialized with the flag + /// `InitFlags::FAN_NONBLOCK`, thus making this method nonblocking. + pub fn write_response(&self, response: FanotifyResponse) -> Result<()> { + write(self.fd.as_fd(), unsafe { + std::slice::from_raw_parts( + (&response.inner as *const libc::fanotify_response).cast(), + size_of::(), + ) + })?; + Ok(()) + } +} + +impl FromRawFd for Fanotify { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Fanotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + } + } +} + +impl AsFd for Fanotify { + fn as_fd(&'_ self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} diff --git a/third_party/rust/nix/src/sys/inotify.rs b/third_party/rust/nix/src/sys/inotify.rs index e5fe930f49..9cbeb53973 100644 --- a/third_party/rust/nix/src/sys/inotify.rs +++ b/third_party/rust/nix/src/sys/inotify.rs @@ -143,7 +143,9 @@ impl Inotify { pub fn init(flags: InitFlags) -> Result { let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); - res.map(|fd| Inotify { fd: unsafe { OwnedFd::from_raw_fd(fd) } }) + res.map(|fd| Inotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + }) } /// Adds a new watch on the target file or directory. @@ -157,7 +159,11 @@ impl Inotify { mask: AddWatchFlags, ) -> Result { let res = path.with_nix_path(|cstr| unsafe { - libc::inotify_add_watch(self.fd.as_raw_fd(), cstr.as_ptr(), mask.bits()) + libc::inotify_add_watch( + self.fd.as_raw_fd(), + cstr.as_ptr(), + mask.bits(), + ) })?; Errno::result(res).map(|wd| WatchDescriptor { wd }) @@ -202,7 +208,7 @@ impl Inotify { let mut event = MaybeUninit::::uninit(); ptr::copy_nonoverlapping( buffer.as_ptr().add(offset), - event.as_mut_ptr() as *mut u8, + event.as_mut_ptr().cast(), (BUFSIZ - offset).min(header_size), ); event.assume_init() @@ -237,7 +243,9 @@ impl Inotify { impl FromRawFd for Inotify { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Inotify { fd: OwnedFd::from_raw_fd(fd) } + Inotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + } } } diff --git a/third_party/rust/nix/src/sys/ioctl/bsd.rs b/third_party/rust/nix/src/sys/ioctl/bsd.rs index 307994cb96..cedc8e63fe 100644 --- a/third_party/rust/nix/src/sys/ioctl/bsd.rs +++ b/third_party/rust/nix/src/sys/ioctl/bsd.rs @@ -1,10 +1,10 @@ /// The datatype used for the ioctl number #[doc(hidden)] -#[cfg(not(target_os = "illumos"))] +#[cfg(not(solarish))] pub type ioctl_num_type = ::libc::c_ulong; #[doc(hidden)] -#[cfg(target_os = "illumos")] +#[cfg(solarish)] pub type ioctl_num_type = ::libc::c_int; /// The datatype used for the 3rd argument diff --git a/third_party/rust/nix/src/sys/ioctl/linux.rs b/third_party/rust/nix/src/sys/ioctl/linux.rs index 610b8ddac0..52312f4f04 100644 --- a/third_party/rust/nix/src/sys/ioctl/linux.rs +++ b/third_party/rust/nix/src/sys/ioctl/linux.rs @@ -19,7 +19,9 @@ pub const TYPEBITS: ioctl_num_type = 8; cfg_if! { if #[cfg(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64" diff --git a/third_party/rust/nix/src/sys/ioctl/mod.rs b/third_party/rust/nix/src/sys/ioctl/mod.rs index 0b3fe3e769..e1e808f19e 100644 --- a/third_party/rust/nix/src/sys/ioctl/mod.rs +++ b/third_party/rust/nix/src/sys/ioctl/mod.rs @@ -72,7 +72,7 @@ //! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h //! # const SPI_IOC_TYPE_MODE: u8 = 1; //! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result { -//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::()), data); +//! let res = unsafe { libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::()), data) }; //! Errno::result(res) //! } //! # fn main() {} @@ -121,11 +121,11 @@ //! //! ``` //! # #[macro_use] extern crate nix; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # #[cfg(linux_android)] //! # use nix::libc::TCGETS as TCGETS; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # #[cfg(linux_android)] //! # use nix::libc::termios as termios; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # #[cfg(linux_android)] //! ioctl_read_bad!(tcgets, TCGETS, termios); //! # fn main() {} //! ``` @@ -179,9 +179,13 @@ //! # const SPI_IOC_TYPE_MESSAGE: u8 = 0; //! # pub struct spi_ioc_transfer(u64); //! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result { -//! let res = libc::ioctl(fd, -//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::()), -//! data); +//! let res = unsafe { +//! libc::ioctl( +//! fd, +//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::()), +//! data +//! ) +//! }; //! Errno::result(res) //! } //! # fn main() {} @@ -223,40 +227,18 @@ //! ``` use cfg_if::cfg_if; -#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] +#[cfg(any(linux_android, target_os = "redox"))] #[macro_use] mod linux; -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "redox" -))] +#[cfg(any(linux_android, target_os = "redox"))] pub use self::linux::*; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] +#[cfg(any(bsd, solarish, target_os = "haiku",))] #[macro_use] mod bsd; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] +#[cfg(any(bsd, solarish, target_os = "haiku",))] pub use self::bsd::*; /// Convert raw ioctl return value to a Nix result @@ -305,7 +287,9 @@ macro_rules! ioctl_none { $(#[$attr])* pub unsafe fn $name(fd: $crate::libc::c_int) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type)) + } } ) } @@ -345,7 +329,9 @@ macro_rules! ioctl_none_bad { $(#[$attr])* pub unsafe fn $name(fd: $crate::libc::c_int) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type)) + } } ) } @@ -383,7 +369,9 @@ macro_rules! ioctl_read { pub unsafe fn $name(fd: $crate::libc::c_int, data: *mut $ty) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -408,7 +396,7 @@ macro_rules! ioctl_read { /// /// ``` /// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// # #[cfg(linux_android)] /// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); /// # fn main() {} /// ``` @@ -419,7 +407,9 @@ macro_rules! ioctl_read_bad { pub unsafe fn $name(fd: $crate::libc::c_int, data: *mut $ty) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -456,7 +446,9 @@ macro_rules! ioctl_write_ptr { pub unsafe fn $name(fd: $crate::libc::c_int, data: *const $ty) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -481,7 +473,7 @@ macro_rules! ioctl_write_ptr { /// /// ``` /// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// # #[cfg(linux_android)] /// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios); /// # fn main() {} /// ``` @@ -492,13 +484,15 @@ macro_rules! ioctl_write_ptr_bad { pub unsafe fn $name(fd: $crate::libc::c_int, data: *const $ty) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } cfg_if! { - if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] { + if #[cfg(freebsdlike)] { /// Generates a wrapper function for a ioctl that writes an integer to the kernel. /// /// The arguments to this macro are: @@ -533,7 +527,9 @@ cfg_if! { pub unsafe fn $name(fd: $crate::libc::c_int, data: $crate::sys::ioctl::ioctl_param_type) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -574,7 +570,9 @@ cfg_if! { pub unsafe fn $name(fd: $crate::libc::c_int, data: $crate::sys::ioctl::ioctl_param_type) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -600,7 +598,7 @@ cfg_if! { /// /// ``` /// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// # #[cfg(linux_android)] /// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK); /// # fn main() {} /// ``` @@ -618,7 +616,9 @@ macro_rules! ioctl_write_int_bad { pub unsafe fn $name(fd: $crate::libc::c_int, data: $crate::libc::c_int) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -655,7 +655,9 @@ macro_rules! ioctl_readwrite { pub unsafe fn $name(fd: $crate::libc::c_int, data: *mut $ty) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -683,7 +685,9 @@ macro_rules! ioctl_readwrite_bad { pub unsafe fn $name(fd: $crate::libc::c_int, data: *mut $ty) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -712,7 +716,9 @@ macro_rules! ioctl_read_buf { pub unsafe fn $name(fd: $crate::libc::c_int, data: &mut [$ty]) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr())) + } } ) } @@ -751,7 +757,9 @@ macro_rules! ioctl_write_buf { pub unsafe fn $name(fd: $crate::libc::c_int, data: &[$ty]) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_ptr())) + } } ) } @@ -780,7 +788,9 @@ macro_rules! ioctl_readwrite_buf { pub unsafe fn $name(fd: $crate::libc::c_int, data: &mut [$ty]) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr())) + } } ) } diff --git a/third_party/rust/nix/src/sys/memfd.rs b/third_party/rust/nix/src/sys/memfd.rs index 516ffd3262..22ee5fc5b7 100644 --- a/third_party/rust/nix/src/sys/memfd.rs +++ b/third_party/rust/nix/src/sys/memfd.rs @@ -29,6 +29,49 @@ libc_bitflags!( /// /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html MFD_ALLOW_SEALING; + /// Anonymous file will be created using huge pages. It should be safe now to + /// combine with [`MFD_ALLOW_SEALING`] too. + /// However, despite its presence, on FreeBSD it is unimplemented for now (ENOSYS). + /// + /// See also the hugetlb filesystem in [`memfd_create(2)`]. + /// + /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html + #[cfg(linux_android)] + MFD_HUGETLB; + /// Following are to be used with [`MFD_HUGETLB`], indicating the desired hugetlb size. + /// + /// See also the hugetlb filesystem in [`memfd_create(2)`]. + /// + /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html + #[cfg(linux_android)] + MFD_HUGE_1MB; + /// hugetlb size of 2MB. + #[cfg(linux_android)] + MFD_HUGE_2MB; + /// hugetlb size of 8MB. + #[cfg(linux_android)] + MFD_HUGE_8MB; + /// hugetlb size of 16MB. + #[cfg(linux_android)] + MFD_HUGE_16MB; + /// hugetlb size of 32MB. + #[cfg(linux_android)] + MFD_HUGE_32MB; + /// hugetlb size of 256MB. + #[cfg(linux_android)] + MFD_HUGE_256MB; + /// hugetlb size of 512MB. + #[cfg(linux_android)] + MFD_HUGE_512MB; + /// hugetlb size of 1GB. + #[cfg(linux_android)] + MFD_HUGE_1GB; + /// hugetlb size of 2GB. + #[cfg(linux_android)] + MFD_HUGE_2GB; + /// hugetlb size of 16GB. + #[cfg(linux_android)] + MFD_HUGE_16GB; } ); diff --git a/third_party/rust/nix/src/sys/mman.rs b/third_party/rust/nix/src/sys/mman.rs index 8cfd6d6d54..a64f14f588 100644 --- a/third_party/rust/nix/src/sys/mman.rs +++ b/third_party/rust/nix/src/sys/mman.rs @@ -8,7 +8,11 @@ use crate::Result; #[cfg(feature = "fs")] use crate::{fcntl::OFlag, sys::stat::Mode}; use libc::{self, c_int, c_void, off_t, size_t}; -use std::{num::NonZeroUsize, os::unix::io::{AsRawFd, AsFd}}; +use std::ptr::NonNull; +use std::{ + num::NonZeroUsize, + os::unix::io::{AsFd, AsRawFd}, +}; libc_bitflags! { /// Desired memory protection of a memory mapping. @@ -22,12 +26,10 @@ libc_bitflags! { /// Pages can be executed PROT_EXEC; /// Apply protection up to the end of a mapping that grows upwards. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] PROT_GROWSDOWN; /// Apply protection down to the beginning of a mapping that grows downwards. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] PROT_GROWSUP; } } @@ -45,145 +47,143 @@ libc_bitflags! { MAP_FIXED; /// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range. #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_FIXED_NOREPLACE; /// To be used with `MAP_FIXED`, to forbid the system /// to select a different address than the one specified. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_EXCL; /// Synonym for `MAP_ANONYMOUS`. MAP_ANON; /// The mapping is not backed by any file. MAP_ANONYMOUS; /// Put the mapping into the first 2GB of the process address space. - #[cfg(any(all(any(target_os = "android", target_os = "linux"), + #[cfg(any(all(linux_android, any(target_arch = "x86", target_arch = "x86_64")), all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")), all(target_os = "freebsd", target_pointer_width = "64")))] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_32BIT; /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_GROWSDOWN; /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_DENYWRITE; /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_EXECUTABLE; /// Mark the mmaped region to be locked in the same way as `mlock(2)`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_LOCKED; /// Do not reserve swap space for this mapping. /// /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(freebsdlike, target_os = "aix", target_os = "hurd")))] MAP_NORESERVE; /// Populate page tables for a mapping. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_POPULATE; /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_NONBLOCK; /// Allocate the mapping using "huge pages." - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_HUGETLB; /// Make use of 64KB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_64KB; /// Make use of 512KB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_512KB; /// Make use of 1MB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_1MB; /// Make use of 2MB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_2MB; /// Make use of 8MB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_8MB; /// Make use of 16MB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_16MB; /// Make use of 32MB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_32MB; /// Make use of 256MB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_256MB; /// Make use of 512MB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_512MB; /// Make use of 1GB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_1GB; /// Make use of 2GB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_2GB; /// Make use of 16GB huge page (must be supported by the system) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_16GB; /// Lock the mapped region into memory as with `mlock(2)`. #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_WIRED; /// Causes dirtied data in the specified range to be flushed to disk only when necessary. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MAP_NOSYNC; /// Rename private pages to a file. /// /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(netbsdlike)] MAP_RENAME; /// Region may contain semaphores. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, netbsdlike))] MAP_HASSEMAPHORE; /// Region grows down, like a stack. - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] MAP_STACK; /// Pages in this mapping are not retained in the kernel's memory cache. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MAP_NOCACHE; /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MAP_JIT; /// Allows to use large pages, underlying alignment based on size. #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_ALIGNED_SUPER; /// Pages will be discarded in the core dumps. #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_CONCEAL; + /// Attempt to place the mapping at exactly the address specified in `addr`. + /// it's a default behavior on OpenBSD. + #[cfg(netbsdlike)] + MAP_TRYFIXED; + } +} + +impl MapFlags { + /// Create `MAP_HUGETLB` with provided size of huge page. + /// + /// Under the hood it computes `MAP_HUGETLB | (huge_page_size_log2 << libc::MAP_HUGE_SHIFT`). + /// `huge_page_size_log2` denotes logarithm of huge page size to use and should be + /// between 16 and 63 (inclusively). + /// + /// ``` + /// # use nix::sys::mman::MapFlags; + /// let f = MapFlags::map_hugetlb_with_size_log2(30).unwrap(); + /// assert_eq!(f, MapFlags::MAP_HUGETLB | MapFlags::MAP_HUGE_1GB); + /// ``` + #[cfg(any(linux_android, target_os = "fuchsia"))] + pub fn map_hugetlb_with_size_log2( + huge_page_size_log2: u32, + ) -> Option { + if (16..=63).contains(&huge_page_size_log2) { + let flag = libc::MAP_HUGETLB + | (huge_page_size_log2 << libc::MAP_HUGE_SHIFT) as i32; + Some(Self(flag.into())) + } else { + None + } } } @@ -193,19 +193,15 @@ libc_bitflags! { pub struct MRemapFlags: c_int { /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MREMAP_MAYMOVE; /// Place the mapping at exactly the address specified in `new_address`. #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] MREMAP_FIXED; /// Place the mapping at exactly the address specified in `new_address`. #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_FIXED; /// Allows to duplicate the mapping to be able to apply different flags on the copy. #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] MAP_REMAPDUP; } } @@ -228,30 +224,24 @@ libc_enum! { /// Do not expect access in the near future. MADV_DONTNEED, /// Free up a given range of pages and its associated backing store. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_REMOVE, /// Do not make pages in this range available to the child after a `fork(2)`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_DONTFORK, /// Undo the effect of `MADV_DONTFORK`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_DOFORK, /// Poison the given pages. /// /// Subsequent references to those pages are treated like hardware memory corruption. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_HWPOISON, /// Enable Kernel Samepage Merging (KSM) for the given pages. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_MERGEABLE, /// Undo the effect of `MADV_MERGEABLE` - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_UNMERGEABLE, /// Preserve the memory of each page but offline the original page. #[cfg(any(target_os = "android", @@ -266,68 +256,52 @@ libc_enum! { target_arch = "sparc64"))))] MADV_SOFT_OFFLINE, /// Enable Transparent Huge Pages (THP) for pages in the given range. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_HUGEPAGE, /// Undo the effect of `MADV_HUGEPAGE`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_NOHUGEPAGE, /// Exclude the given range from a core dump. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_DONTDUMP, /// Undo the effect of an earlier `MADV_DONTDUMP`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_DODUMP, /// Specify that the application no longer needs the pages in the given range. - #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(target_os = "aix", target_os = "hurd")))] MADV_FREE, /// Request that the system not flush the current range to disk unless it needs to. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MADV_NOSYNC, /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MADV_AUTOSYNC, /// Region is not included in a core file. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MADV_NOCORE, /// Include region in a core file - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MADV_CORE, /// This process should not be killed when swap space is exhausted. #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] MADV_PROTECT, /// Invalidate the hardware page table for the given region. #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] MADV_INVAL, /// Set the offset of the page directory page to `value` for the virtual page table. #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] MADV_SETMAP, /// Indicates that the application will not need the data in the given range. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MADV_ZERO_WIRED_PAGES, /// Pages can be reused (by anyone). - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MADV_FREE_REUSABLE, /// Caller wants to reuse those pages. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MADV_FREE_REUSE, // Darwin doesn't document this flag's behavior. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] #[allow(missing_docs)] MADV_CAN_REUSE, } @@ -341,12 +315,10 @@ libc_bitflags! { /// Invalidate all cached data. MS_INVALIDATE; /// Invalidate pages, but leave them mapped. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MS_KILLPAGES; /// Deactivate pages, but leave them mapped. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MS_DEACTIVATE; /// Perform an update and wait for it to complete. MS_SYNC; @@ -374,8 +346,8 @@ libc_bitflags! { /// `addr` must meet all the requirements described in the [`mlock(2)`] man page. /// /// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html -pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { - Errno::result(libc::mlock(addr, length)).map(drop) +pub unsafe fn mlock(addr: NonNull, length: size_t) -> Result<()> { + unsafe { Errno::result(libc::mlock(addr.as_ptr(), length)).map(drop) } } /// Unlocks all memory pages that contain part of the address range with @@ -387,8 +359,8 @@ pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { /// page. /// /// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html -pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { - Errno::result(libc::munlock(addr, length)).map(drop) +pub unsafe fn munlock(addr: NonNull, length: size_t) -> Result<()> { + unsafe { Errno::result(libc::munlock(addr.as_ptr(), length)).map(drop) } } /// Locks all memory pages mapped into this process' address space. @@ -411,7 +383,9 @@ pub fn munlockall() -> Result<()> { unsafe { Errno::result(libc::munlockall()) }.map(drop) } -/// allocate memory, or map files or devices into memory +/// Allocate memory, or map files or devices into memory +/// +/// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see [mmap_anonymous]. /// /// # Safety /// @@ -423,20 +397,54 @@ pub unsafe fn mmap( length: NonZeroUsize, prot: ProtFlags, flags: MapFlags, - f: Option, + f: F, offset: off_t, -) -> Result<*mut c_void> { - let ptr = - addr.map_or(std::ptr::null_mut(), |a| usize::from(a) as *mut c_void); +) -> Result> { + let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void); - let fd = f.map(|f| f.as_fd().as_raw_fd()).unwrap_or(-1); - let ret = - libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); + let fd = f.as_fd().as_raw_fd(); + let ret = unsafe { + libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset) + }; + + if ret == libc::MAP_FAILED { + Err(Errno::last()) + } else { + // SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret` + // will be non-null here. + Ok(unsafe { NonNull::new_unchecked(ret) }) + } +} + +/// Create an anonymous memory mapping. +/// +/// This function is a wrapper around [`mmap`]: +/// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`. +/// +/// # Safety +/// +/// See the [`mmap(2)`] man page for detailed requirements. +/// +/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html +pub unsafe fn mmap_anonymous( + addr: Option, + length: NonZeroUsize, + prot: ProtFlags, + flags: MapFlags, +) -> Result> { + let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void); + + let flags = MapFlags::MAP_ANONYMOUS | flags; + let ret = unsafe { + libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), -1, 0) + }; if ret == libc::MAP_FAILED { Err(Errno::last()) } else { - Ok(ret) + // SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret` + // will be non-null here. + Ok(unsafe { NonNull::new_unchecked(ret) }) } } @@ -449,33 +457,43 @@ pub unsafe fn mmap( /// detailed requirements. #[cfg(any(target_os = "linux", target_os = "netbsd"))] pub unsafe fn mremap( - addr: *mut c_void, + addr: NonNull, old_size: size_t, new_size: size_t, flags: MRemapFlags, - new_address: Option<*mut c_void>, -) -> Result<*mut c_void> { + new_address: Option>, +) -> Result> { #[cfg(target_os = "linux")] - let ret = libc::mremap( - addr, - old_size, - new_size, - flags.bits(), - new_address.unwrap_or(std::ptr::null_mut()), - ); + let ret = unsafe { + libc::mremap( + addr.as_ptr(), + old_size, + new_size, + flags.bits(), + new_address + .map(NonNull::as_ptr) + .unwrap_or(std::ptr::null_mut()), + ) + }; #[cfg(target_os = "netbsd")] - let ret = libc::mremap( - addr, - old_size, - new_address.unwrap_or(std::ptr::null_mut()), - new_size, - flags.bits(), - ); + let ret = unsafe { + libc::mremap( + addr.as_ptr(), + old_size, + new_address + .map(NonNull::as_ptr) + .unwrap_or(std::ptr::null_mut()), + new_size, + flags.bits(), + ) + }; if ret == libc::MAP_FAILED { Err(Errno::last()) } else { - Ok(ret) + // SAFETY: `libc::mremap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret` + // will be non-null here. + Ok(unsafe { NonNull::new_unchecked(ret) }) } } @@ -487,8 +505,8 @@ pub unsafe fn mremap( /// page. /// /// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html -pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { - Errno::result(libc::munmap(addr, len)).map(drop) +pub unsafe fn munmap(addr: NonNull, len: size_t) -> Result<()> { + unsafe { Errno::result(libc::munmap(addr.as_ptr(), len)).map(drop) } } /// give advice about use of memory @@ -499,12 +517,16 @@ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { /// [`MmapAdvise::MADV_FREE`]. /// /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html +#[allow(rustdoc::broken_intra_doc_links)] // For Hurd as `MADV_FREE` is not available on it pub unsafe fn madvise( - addr: *mut c_void, + addr: NonNull, length: size_t, advise: MmapAdvise, ) -> Result<()> { - Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) + unsafe { + Errno::result(libc::madvise(addr.as_ptr(), length, advise as i32)) + .map(drop) + } } /// Set protection of memory mapping. @@ -519,27 +541,30 @@ pub unsafe fn madvise( /// /// ``` /// # use nix::libc::size_t; -/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; +/// # use nix::sys::mman::{mmap_anonymous, mprotect, MapFlags, ProtFlags}; /// # use std::ptr; /// # use std::os::unix::io::BorrowedFd; /// const ONE_K: size_t = 1024; /// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap(); /// let mut slice: &mut [u8] = unsafe { -/// let mem = mmap::(None, one_k_non_zero, ProtFlags::PROT_NONE, -/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, None, 0).unwrap(); +/// let mem = mmap_anonymous(None, one_k_non_zero, ProtFlags::PROT_NONE, MapFlags::MAP_PRIVATE) +/// .unwrap(); /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); -/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) +/// std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) /// }; /// assert_eq!(slice[0], 0x00); /// slice[0] = 0xFF; /// assert_eq!(slice[0], 0xFF); /// ``` pub unsafe fn mprotect( - addr: *mut c_void, + addr: NonNull, length: size_t, prot: ProtFlags, ) -> Result<()> { - Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) + unsafe { + Errno::result(libc::mprotect(addr.as_ptr(), length, prot.bits())) + .map(drop) + } } /// synchronize a mapped region @@ -551,11 +576,14 @@ pub unsafe fn mprotect( /// /// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html pub unsafe fn msync( - addr: *mut c_void, + addr: NonNull, length: size_t, flags: MsFlags, ) -> Result<()> { - Errno::result(libc::msync(addr, length, flags.bits())).map(drop) + unsafe { + Errno::result(libc::msync(addr.as_ptr(), length, flags.bits())) + .map(drop) + } } #[cfg(not(target_os = "android"))] @@ -576,11 +604,11 @@ pub fn shm_open

    ( use std::os::unix::io::{FromRawFd, OwnedFd}; let ret = name.with_nix_path(|cstr| { - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] unsafe { libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint) } - #[cfg(not(any(target_os = "macos", target_os = "ios")))] + #[cfg(not(apple_targets))] unsafe { libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t) } diff --git a/third_party/rust/nix/src/sys/mod.rs b/third_party/rust/nix/src/sys/mod.rs index bf047b3dda..93339d1935 100644 --- a/third_party/rust/nix/src/sys/mod.rs +++ b/third_party/rust/nix/src/sys/mod.rs @@ -1,10 +1,8 @@ //! Mostly platform-specific functionality #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", + apple_targets, target_os = "netbsd" ))] feature! { @@ -15,41 +13,31 @@ feature! { feature! { #![feature = "event"] - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[allow(missing_docs)] pub mod epoll; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(bsd)] pub mod event; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[allow(missing_docs)] pub mod eventfd; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" -))] +#[cfg(target_os = "linux")] +feature! { + #![feature = "fanotify"] + pub mod fanotify; +} + +#[cfg(any(bsd, linux_android, target_os = "redox", solarish))] #[cfg(feature = "ioctl")] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] #[macro_use] pub mod ioctl; -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] feature! { #![feature = "fs"] pub mod memfd; @@ -78,15 +66,7 @@ feature! { pub mod pthread; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(any(linux_android, bsd))] feature! { #![feature = "ptrace"] #[allow(missing_docs)] @@ -99,7 +79,7 @@ feature! { pub mod quota; } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", netbsdlike))] feature! { #![feature = "reboot"] pub mod reboot; @@ -108,7 +88,7 @@ feature! { #[cfg(not(any( target_os = "redox", target_os = "fuchsia", - target_os = "illumos", + solarish, target_os = "haiku" )))] feature! { @@ -121,14 +101,7 @@ feature! { pub mod select; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" -))] +#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))] feature! { #![feature = "zerocopy"] pub mod sendfile; @@ -136,7 +109,7 @@ feature! { pub mod signal; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] feature! { #![feature = "signal"] #[allow(missing_docs)] @@ -155,15 +128,7 @@ feature! { pub mod stat; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))] feature! { #![feature = "fs"] pub mod statfs; @@ -174,8 +139,7 @@ feature! { pub mod statvfs; } -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] #[allow(missing_docs)] pub mod sysinfo; @@ -203,13 +167,13 @@ feature! { pub mod wait; } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] feature! { #![feature = "inotify"] pub mod inotify; } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] feature! { #![feature = "time"] pub mod timerfd; @@ -218,7 +182,7 @@ feature! { #[cfg(all( any( target_os = "freebsd", - target_os = "illumos", + solarish, target_os = "linux", target_os = "netbsd" ), diff --git a/third_party/rust/nix/src/sys/personality.rs b/third_party/rust/nix/src/sys/personality.rs index 30231dd7b8..a4cfb5ef4f 100644 --- a/third_party/rust/nix/src/sys/personality.rs +++ b/third_party/rust/nix/src/sys/personality.rs @@ -21,7 +21,6 @@ libc_bitflags! { ADDR_LIMIT_3GB; /// User-space function pointers to signal handlers point to descriptors. #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] FDPIC_FUNCPTRS; /// Map page 0 as read-only. MMAP_PAGE_ZERO; @@ -43,7 +42,6 @@ libc_bitflags! { /// /// [`uname(2)`]: https://man7.org/linux/man-pages/man2/uname.2.html #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] UNAME26; /// No effects. WHOLE_SECONDS; diff --git a/third_party/rust/nix/src/sys/prctl.rs b/third_party/rust/nix/src/sys/prctl.rs index 995382cb0c..42324beab2 100644 --- a/third_party/rust/nix/src/sys/prctl.rs +++ b/third_party/rust/nix/src/sys/prctl.rs @@ -50,7 +50,9 @@ pub fn get_child_subreaper() -> Result { // prctl writes into this var let mut subreaper: c_int = 0; - let res = unsafe { libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0) }; + let res = unsafe { + libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0) + }; Errno::result(res).map(|_| subreaper != 0) } @@ -78,7 +80,9 @@ pub fn get_keepcaps() -> Result { /// Clear the thread memory corruption kill policy and use the system-wide default pub fn clear_mce_kill() -> Result<()> { - let res = unsafe { libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) }; + let res = unsafe { + libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) + }; Errno::result(res).map(drop) } @@ -151,10 +155,11 @@ pub fn get_name() -> Result { let res = unsafe { libc::prctl(libc::PR_GET_NAME, &buf, 0, 0, 0) }; - let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len()); - let name = CStr::from_bytes_with_nul(&buf[..=len]).map_err(|_| Errno::EINVAL)?; - - Errno::result(res).map(|_| name.to_owned()) + Errno::result(res).and_then(|_| { + CStr::from_bytes_until_nul(&buf) + .map(CStr::to_owned) + .map_err(|_| Errno::EINVAL) + }) } /// Sets the timer slack value for the calling thread. Timer slack is used by the kernel to group @@ -174,14 +179,16 @@ pub fn get_timerslack() -> Result { /// Disable all performance counters attached to the calling process. pub fn task_perf_events_disable() -> Result<()> { - let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) }; + let res = + unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) }; Errno::result(res).map(drop) } /// Enable all performance counters attached to the calling process. pub fn task_perf_events_enable() -> Result<()> { - let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) }; + let res = + unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) }; Errno::result(res).map(drop) } diff --git a/third_party/rust/nix/src/sys/ptrace/bsd.rs b/third_party/rust/nix/src/sys/ptrace/bsd.rs index ba267c6577..3dd486210c 100644 --- a/third_party/rust/nix/src/sys/ptrace/bsd.rs +++ b/third_party/rust/nix/src/sys/ptrace/bsd.rs @@ -9,10 +9,7 @@ use std::ptr; pub type RequestType = c_int; cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "openbsd"))] { + if #[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] { #[doc(hidden)] pub type AddressType = *mut ::libc::c_char; } else { @@ -29,33 +26,26 @@ libc_enum! { PT_TRACE_ME, PT_READ_I, PT_READ_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_READ_U, PT_WRITE_I, PT_WRITE_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_WRITE_U, PT_CONTINUE, PT_KILL, - #[cfg(any(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos"), + #[cfg(any(any(freebsdlike, apple_targets), all(target_os = "openbsd", target_arch = "x86_64"), all(target_os = "netbsd", any(target_arch = "x86_64", target_arch = "powerpc"))))] PT_STEP, PT_ATTACH, PT_DETACH, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_SIGEXC, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_THUPDATE, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_ATTACHEXC } } @@ -66,13 +56,15 @@ unsafe fn ptrace_other( addr: AddressType, data: c_int, ) -> Result { - Errno::result(libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - addr, - data, - )) - .map(|_| 0) + unsafe { + Errno::result(libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + addr, + data, + )) + .map(|_| 0) + } } /// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` @@ -157,7 +149,7 @@ pub fn kill(pid: Pid) -> Result<()> { /// } /// ``` #[cfg(any( - any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), + any(freebsdlike, apple_targets), all(target_os = "openbsd", target_arch = "x86_64"), all( target_os = "netbsd", diff --git a/third_party/rust/nix/src/sys/ptrace/linux.rs b/third_party/rust/nix/src/sys/ptrace/linux.rs index 8c134cf7ee..26544e134b 100644 --- a/third_party/rust/nix/src/sys/ptrace/linux.rs +++ b/third_party/rust/nix/src/sys/ptrace/linux.rs @@ -53,28 +53,36 @@ libc_enum! { #[cfg(any(all(target_os = "android", target_pointer_width = "32"), all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86_64", target_pointer_width = "32"))))] PTRACE_GETREGS, #[cfg(any(all(target_os = "android", target_pointer_width = "32"), all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86_64", target_pointer_width = "32"))))] PTRACE_SETREGS, #[cfg(any(all(target_os = "android", target_pointer_width = "32"), all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86_64", target_pointer_width = "32"))))] PTRACE_GETFPREGS, #[cfg(any(all(target_os = "android", target_pointer_width = "32"), all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86_64", target_pointer_width = "32"))))] PTRACE_SETFPREGS, @@ -82,13 +90,17 @@ libc_enum! { PTRACE_DETACH, #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86", target_arch = "x86_64")))] PTRACE_GETFPXREGS, #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86", target_arch = "x86_64")))] PTRACE_SETFPXREGS, @@ -98,22 +110,28 @@ libc_enum! { PTRACE_GETSIGINFO, PTRACE_SETSIGINFO, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] PTRACE_GETREGSET, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] PTRACE_SETREGSET, #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] PTRACE_SEIZE, #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] PTRACE_INTERRUPT, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] PTRACE_LISTEN, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] PTRACE_PEEKSIGINFO, #[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] @@ -241,13 +259,13 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { /// and therefore use the data field to return values. This function handles these /// requests. fn ptrace_get_data(request: Request, pid: Pid) -> Result { - let mut data = mem::MaybeUninit::uninit(); + let mut data = mem::MaybeUninit::::uninit(); let res = unsafe { libc::ptrace( request as RequestType, libc::pid_t::from(pid), ptr::null_mut::(), - data.as_mut_ptr() as *const _ as *const c_void, + data.as_mut_ptr(), ) }; Errno::result(res)?; @@ -260,13 +278,15 @@ unsafe fn ptrace_other( addr: AddressType, data: *mut c_void, ) -> Result { - Errno::result(libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - addr, - data, - )) - .map(|_| 0) + unsafe { + Errno::result(libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + addr, + data, + )) + .map(|_| 0) + } } /// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`. @@ -381,7 +401,6 @@ pub fn attach(pid: Pid) -> Result<()> { /// /// Attaches to the process specified in pid, making it a tracee of the calling process. #[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn seize(pid: Pid, options: Options) -> Result<()> { unsafe { ptrace_other( @@ -428,7 +447,6 @@ pub fn cont>>(pid: Pid, sig: T) -> Result<()> { /// /// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` #[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn interrupt(pid: Pid) -> Result<()> { unsafe { ptrace_other( @@ -535,7 +553,7 @@ pub unsafe fn write( addr: AddressType, data: *mut c_void, ) -> Result<()> { - ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) + unsafe { ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) } } /// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...). @@ -556,5 +574,7 @@ pub unsafe fn write_user( offset: AddressType, data: *mut c_void, ) -> Result<()> { - ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) + unsafe { + ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) + } } diff --git a/third_party/rust/nix/src/sys/ptrace/mod.rs b/third_party/rust/nix/src/sys/ptrace/mod.rs index 88648acabc..c059797df9 100644 --- a/third_party/rust/nix/src/sys/ptrace/mod.rs +++ b/third_party/rust/nix/src/sys/ptrace/mod.rs @@ -1,25 +1,13 @@ //! Provides helpers for making ptrace system calls -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod linux; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use self::linux::*; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] mod bsd; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] pub use self::bsd::*; diff --git a/third_party/rust/nix/src/sys/quota.rs b/third_party/rust/nix/src/sys/quota.rs index a32d07aa1e..2d12b858bf 100644 --- a/third_party/rust/nix/src/sys/quota.rs +++ b/third_party/rust/nix/src/sys/quota.rs @@ -264,7 +264,7 @@ pub fn quotactl_on( ) -> Result<()> { quota_file.with_nix_path(|path| { let mut path_copy = path.to_bytes_with_nul().to_owned(); - let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; + let p: *mut c_char = path_copy.as_mut_ptr().cast(); quotactl( QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), @@ -308,12 +308,12 @@ pub fn quotactl_get( special: &P, id: c_int, ) -> Result { - let mut dqblk = mem::MaybeUninit::uninit(); + let mut dqblk = mem::MaybeUninit::::uninit(); quotactl( QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, - dqblk.as_mut_ptr() as *mut c_char, + dqblk.as_mut_ptr().cast(), )?; Ok(unsafe { Dqblk(dqblk.assume_init()) }) } diff --git a/third_party/rust/nix/src/sys/reboot.rs b/third_party/rust/nix/src/sys/reboot.rs index 02d98162bd..2e4d888de4 100644 --- a/third_party/rust/nix/src/sys/reboot.rs +++ b/third_party/rust/nix/src/sys/reboot.rs @@ -1,48 +1,141 @@ -//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. +//! Reboot/shutdown +//! +//! On Linux, This can also be used to enable/disable Ctrl-Alt-Delete. use crate::errno::Errno; use crate::Result; +use cfg_if::cfg_if; use std::convert::Infallible; -use std::mem::drop; - -libc_enum! { - /// How exactly should the system be rebooted. - /// - /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for - /// enabling/disabling Ctrl-Alt-Delete. - #[repr(i32)] - #[non_exhaustive] - pub enum RebootMode { - /// Halt the system. - RB_HALT_SYSTEM, - /// Execute a kernel that has been loaded earlier with - /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html). - RB_KEXEC, - /// Stop the system and switch off power, if possible. - RB_POWER_OFF, - /// Restart the system. - RB_AUTOBOOT, - // we do not support Restart2. - /// Suspend the system using software suspend. - RB_SW_SUSPEND, - } -} -/// Reboots or shuts down the system. -pub fn reboot(how: RebootMode) -> Result { - unsafe { libc::reboot(how as libc::c_int) }; - Err(Errno::last()) -} +cfg_if! { + if #[cfg(target_os = "linux")] { + use std::mem::drop; + + libc_enum! { + /// How exactly should the system be rebooted. + /// + /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for + /// enabling/disabling Ctrl-Alt-Delete. + #[repr(i32)] + #[non_exhaustive] + pub enum RebootMode { + /// Halt the system. + RB_HALT_SYSTEM, + /// Execute a kernel that has been loaded earlier with + /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html). + RB_KEXEC, + /// Stop the system and switch off power, if possible. + RB_POWER_OFF, + /// Restart the system. + RB_AUTOBOOT, + // we do not support Restart2. + /// Suspend the system using software suspend. + RB_SW_SUSPEND, + } + } + + /// Reboots or shuts down the system. + pub fn reboot(how: RebootMode) -> Result { + unsafe { libc::reboot(how as libc::c_int) }; + Err(Errno::last()) + } -/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete). -/// -/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C. -pub fn set_cad_enabled(enable: bool) -> Result<()> { - let cmd = if enable { - libc::RB_ENABLE_CAD - } else { - libc::RB_DISABLE_CAD - }; - let res = unsafe { libc::reboot(cmd) }; - Errno::result(res).map(drop) + /// Enable or disable the reboot keystroke (Ctrl-Alt-Delete). + /// + /// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C. + pub fn set_cad_enabled(enable: bool) -> Result<()> { + let cmd = if enable { + libc::RB_ENABLE_CAD + } else { + libc::RB_DISABLE_CAD + }; + let res = unsafe { libc::reboot(cmd) }; + Errno::result(res).map(drop) + } + } else if #[cfg(netbsdlike)] { + use libc::c_int; + + libc_bitflags! { + /// How exactly should the system be rebooted. + pub struct RebootMode: c_int { + /// The default, causing the system to reboot in its usual fashion. + RB_AUTOBOOT; + /// Interpreted by the bootstrap program itself, causing it to + /// prompt on the console as to what file should be booted. + /// Normally, the system is booted from the file “xx(0,0)bsd”, + /// where xx is the default disk name, without prompting for + /// the file name. + RB_ASKNAME; + /// Dump kernel memory before rebooting; see `savecore(8)` for + /// more information. + RB_DUMP; + /// The processor is simply halted; no reboot takes place. + RB_HALT; + /// Power off the system if the system hardware supports the + /// function, otherwise it has no effect. + /// + /// Should be used in conjunction with `RB_HALT`. + RB_POWERDOWN; + /// By default, the system will halt if `reboot()` is called during + /// startup (before the system has finished autoconfiguration), even + /// if `RB_HALT` is not specified. This is because `panic(9)`s + /// during startup will probably just repeat on the next boot. + /// Use of this option implies that the user has requested the + /// action specified (for example, using the `ddb(4)` boot reboot + /// command), so the system will reboot if a halt is not explicitly + /// requested. + #[cfg(target_os = "openbsd")] + RB_USERREQ; + /// Load the symbol table and enable a built-in debugger in the + /// system. This option will have no useful function if the kernel + /// is not configured for debugging. Several other options have + /// different meaning if combined with this option, although their + /// use may not be possible via the `reboot()` call. See `ddb(4)` for + /// more information. + RB_KDB; + /// Normally, the disks are sync'd (see `sync(8)`) before the + /// processor is halted or rebooted. This option may be useful + /// if file system changes have been made manually or if the + /// processor is on fire. + RB_NOSYNC; + /// Normally, the reboot procedure involves an automatic disk + /// consistency check and then multi-user operations. `RB_SINGLE` + /// prevents this, booting the system with a single-user shell on + /// the console. `RB_SINGLE` is actually interpreted by the `init(8)` + /// program in the newly booted system. + /// + /// When no options are given (i.e., `RB_AUTOBOOT` is used), the + /// system is rebooted from file /bsd in the root file system of + /// unit 0 of a disk chosen in a processor specific way. An automatic + /// consistency check of the disks is normally performed (see `fsck(8)`). + RB_SINGLE; + /// Initially invoke the `userconf(4)` facility when the system + /// starts up again, if it has been compiled into the kernel + /// that is loaded. + #[cfg(target_os = "netbsd")] + RB_USERCONF; + /// Don't update the hardware clock from the system clock, presumably + /// because the system clock is suspect. + #[cfg(target_os = "openbsd")] + RB_TIMEBAD; + } + } + + /// Reboot system or halt processor + /// + /// For more information, see the man pages: + /// + /// * [NetBSD](https://man.netbsd.org/reboot.2) + /// * [OpenBSD](https://man.openbsd.org/reboot.2) + #[cfg(netbsdlike)] + pub fn reboot(how: RebootMode) -> Result { + #[cfg(target_os = "openbsd")] + unsafe { libc::reboot(how.bits()) }; + #[cfg(target_os = "netbsd")] + unsafe { libc::reboot(how.bits(), std::ptr::null_mut()) }; + + Err(Errno::last()) + } + } } + diff --git a/third_party/rust/nix/src/sys/resource.rs b/third_party/rust/nix/src/sys/resource.rs index f42d32e3ca..71315072d4 100644 --- a/third_party/rust/nix/src/sys/resource.rs +++ b/third_party/rust/nix/src/sys/resource.rs @@ -10,16 +10,14 @@ pub use libc::RLIM_INFINITY; use std::mem; cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + if #[cfg(any( + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd" + ))]{ use libc::{__rlimit_resource_t, rlimit}; } else if #[cfg(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", + bsd, target_os = "android", - target_os = "dragonfly", target_os = "aix", all(target_os = "linux", not(target_env = "gnu")) ))]{ @@ -43,22 +41,19 @@ libc_enum! { // // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs - #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))] #[cfg_attr(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd" + ), repr(u32))] + #[cfg_attr(any( + bsd, target_os = "android", - target_os = "dragonfly", target_os = "aix", all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))) ), repr(i32))] #[non_exhaustive] pub enum Resource { - #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(target_os = "freebsd", netbsdlike)))] /// The maximum amount (in bytes) of virtual memory the process is /// allowed to map. RLIMIT_AS, @@ -77,102 +72,78 @@ libc_enum! { RLIMIT_STACK, #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum number of kqueues this user id is allowed to create. RLIMIT_KQUEUES, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] /// A limit on the combined number of flock locks and fcntl leases that /// this process may establish. RLIMIT_LOCKS, - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "linux", - target_os = "netbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "freebsd", netbsdlike))] /// The maximum size (in bytes) which a process may lock into memory /// using the mlock(2) system call. RLIMIT_MEMLOCK, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] /// A limit on the number of bytes that can be allocated for POSIX /// message queues for the real user ID of the calling process. RLIMIT_MSGQUEUE, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] /// A ceiling to which the process's nice value can be raised using /// setpriority or nice. RLIMIT_NICE, #[cfg(any( - target_os = "android", + linux_android, target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", + netbsdlike, target_os = "aix", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum number of simultaneous processes for this user id. RLIMIT_NPROC, #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum number of pseudo-terminals this user id is allowed to /// create. RLIMIT_NPTS, - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", + netbsdlike, target_os = "aix", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// When there is memory pressure and swap is available, prioritize /// eviction of a process' resident pages beyond this amount (in bytes). RLIMIT_RSS, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] /// A ceiling on the real-time priority that may be set for this process /// using sched_setscheduler and sched_set‐ param. RLIMIT_RTPRIO, #[cfg(any(target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// A limit (in microseconds) on the amount of CPU time that a process /// scheduled under a real-time scheduling policy may con‐ sume without /// making a blocking system call. RLIMIT_RTTIME, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] /// A limit on the number of signals that may be queued for the real /// user ID of the calling process. RLIMIT_SIGPENDING, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] /// The maximum size (in bytes) of socket buffer usage for this user. RLIMIT_SBSIZE, #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum size (in bytes) of the swap space that may be reserved /// or used by all of this user id's processes. RLIMIT_SWAP, #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] /// An alias for RLIMIT_AS. RLIMIT_VMEM, } @@ -206,7 +177,10 @@ pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { let mut old_rlim = mem::MaybeUninit::::uninit(); cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + if #[cfg(any( + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd" + ))] { let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) }; } else { let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) }; @@ -259,7 +233,10 @@ pub fn setrlimit( rlim_max: hard_limit, }; cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + if #[cfg(any( + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd", + ))]{ let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) }; }else{ let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) }; @@ -281,7 +258,6 @@ libc_enum! { RUSAGE_CHILDREN, #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Resource usage for the calling thread. RUSAGE_THREAD, } @@ -420,28 +396,3 @@ pub fn getrusage(who: UsageWho) -> Result { Errno::result(res).map(|_| Usage(rusage.assume_init())) } } - -#[cfg(test)] -mod test { - use super::{getrusage, UsageWho}; - - #[test] - pub fn test_self_cpu_time() { - // Make sure some CPU time is used. - let mut numbers: Vec = (1..1_000_000).collect(); - numbers.iter_mut().for_each(|item| *item *= 2); - - // FIXME: this is here to help ensure the compiler does not optimize the whole - // thing away. Replace the assert with test::black_box once stabilized. - assert_eq!(numbers[100..200].iter().sum::(), 30_100); - - let usage = getrusage(UsageWho::RUSAGE_SELF) - .expect("Failed to call getrusage for SELF"); - let rusage = usage.as_ref(); - - let user = usage.user_time(); - assert!(user.tv_sec() > 0 || user.tv_usec() > 0); - assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec); - assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec); - } -} diff --git a/third_party/rust/nix/src/sys/select.rs b/third_party/rust/nix/src/sys/select.rs index 0e2193b130..64a8e258cf 100644 --- a/third_party/rust/nix/src/sys/select.rs +++ b/third_party/rust/nix/src/sys/select.rs @@ -7,7 +7,7 @@ use std::convert::TryFrom; use std::iter::FusedIterator; use std::mem; use std::ops::Range; -use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; +use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd}; use std::ptr::{null, null_mut}; pub use libc::FD_SETSIZE; @@ -41,21 +41,21 @@ impl<'fd> FdSet<'fd> { } /// Add a file descriptor to an `FdSet` - pub fn insert(&mut self, fd: &'fd Fd) { - assert_fd_valid(fd.as_fd().as_raw_fd()); - unsafe { libc::FD_SET(fd.as_fd().as_raw_fd(), &mut self.set) }; + pub fn insert(&mut self, fd: BorrowedFd<'fd>) { + assert_fd_valid(fd.as_raw_fd()); + unsafe { libc::FD_SET(fd.as_raw_fd(), &mut self.set) }; } /// Remove a file descriptor from an `FdSet` - pub fn remove(&mut self, fd: &'fd Fd) { - assert_fd_valid(fd.as_fd().as_raw_fd()); - unsafe { libc::FD_CLR(fd.as_fd().as_raw_fd(), &mut self.set) }; + pub fn remove(&mut self, fd: BorrowedFd<'fd>) { + assert_fd_valid(fd.as_raw_fd()); + unsafe { libc::FD_CLR(fd.as_raw_fd(), &mut self.set) }; } /// Test an `FdSet` for the presence of a certain file descriptor. - pub fn contains(&self, fd: &'fd Fd) -> bool { - assert_fd_valid(fd.as_fd().as_raw_fd()); - unsafe { libc::FD_ISSET(fd.as_fd().as_raw_fd(), &self.set) } + pub fn contains(&self, fd: BorrowedFd<'fd>) -> bool { + assert_fd_valid(fd.as_raw_fd()); + unsafe { libc::FD_ISSET(fd.as_raw_fd(), &self.set) } } /// Remove all file descriptors from this `FdSet`. @@ -77,8 +77,8 @@ impl<'fd> FdSet<'fd> { /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)}; /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)}; /// let mut set = FdSet::new(); - /// set.insert(&fd_four); - /// set.insert(&fd_nine); + /// set.insert(fd_four); + /// set.insert(fd_nine); /// assert_eq!(set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()), Some(9)); /// ``` /// @@ -101,8 +101,8 @@ impl<'fd> FdSet<'fd> { /// let mut set = FdSet::new(); /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)}; /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)}; - /// set.insert(&fd_four); - /// set.insert(&fd_nine); + /// set.insert(fd_four); + /// set.insert(fd_nine); /// let fds: Vec = set.fds(None).map(|borrowed_fd|borrowed_fd.as_raw_fd()).collect(); /// assert_eq!(fds, vec![4, 9]); /// ``` @@ -134,7 +134,7 @@ impl<'a, 'fd> Iterator for Fds<'a, 'fd> { fn next(&mut self) -> Option { for i in &mut self.range { let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - if self.set.contains(&borrowed_i) { + if self.set.contains(borrowed_i) { return Some(borrowed_i); } } @@ -153,7 +153,7 @@ impl<'a, 'fd> DoubleEndedIterator for Fds<'a, 'fd> { fn next_back(&mut self) -> Option> { while let Some(i) = self.range.next_back() { let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - if self.set.contains(&borrowed_i) { + if self.set.contains(borrowed_i) { return Some(borrowed_i); } } @@ -317,238 +317,3 @@ where Errno::result(res) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::sys::time::{TimeVal, TimeValLike}; - use crate::unistd::{close, pipe, write}; - use std::os::unix::io::{FromRawFd, OwnedFd, RawFd}; - - #[test] - fn fdset_insert() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - - let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; - fd_set.insert(&fd_seven); - - assert!(fd_set.contains(&fd_seven)); - } - - #[test] - fn fdset_remove() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - - let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; - fd_set.insert(&fd_seven); - fd_set.remove(&fd_seven); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - } - - #[test] - #[allow(non_snake_case)] - fn fdset_clear() { - let mut fd_set = FdSet::new(); - let fd_one = unsafe { BorrowedFd::borrow_raw(1) }; - let fd_FD_SETSIZE_devided_by_two = - unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) }; - let fd_FD_SETSIZE_minus_one = - unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) }; - fd_set.insert(&fd_one); - fd_set.insert(&fd_FD_SETSIZE_devided_by_two); - fd_set.insert(&fd_FD_SETSIZE_minus_one); - - fd_set.clear(); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - } - - #[test] - fn fdset_highest() { - let mut set = FdSet::new(); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - None - ); - let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; - let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; - set.insert(&fd_zero); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(0) - ); - set.insert(&fd_ninety); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(90) - ); - set.remove(&fd_zero); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(90) - ); - set.remove(&fd_ninety); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - None - ); - - let fd_four = unsafe { BorrowedFd::borrow_raw(4) }; - let fd_five = unsafe { BorrowedFd::borrow_raw(5) }; - let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; - set.insert(&fd_four); - set.insert(&fd_five); - set.insert(&fd_seven); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(7) - ); - } - - #[test] - fn fdset_fds() { - let mut set = FdSet::new(); - let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; - let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; - assert_eq!( - set.fds(None) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::>(), - vec![] - ); - set.insert(&fd_zero); - assert_eq!( - set.fds(None) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::>(), - vec![0] - ); - set.insert(&fd_ninety); - assert_eq!( - set.fds(None) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::>(), - vec![0, 90] - ); - - // highest limit - assert_eq!( - set.fds(Some(89)) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::>(), - vec![0] - ); - assert_eq!( - set.fds(Some(90)) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::>(), - vec![0, 90] - ); - } - - #[test] - fn test_select() { - let (r1, w1) = pipe().unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; - let w1 = unsafe { OwnedFd::from_raw_fd(w1) }; - let (r2, _w2) = pipe().unwrap(); - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; - - write(w1.as_raw_fd(), b"hi!").unwrap(); - let mut fd_set = FdSet::new(); - fd_set.insert(&r1); - fd_set.insert(&r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select(None, &mut fd_set, None, None, &mut timeout).unwrap() - ); - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); - close(_w2).unwrap(); - } - - #[test] - fn test_select_nfds() { - let (r1, w1) = pipe().unwrap(); - let (r2, _w2) = pipe().unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; - let w1 = unsafe { OwnedFd::from_raw_fd(w1) }; - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; - - write(w1.as_raw_fd(), b"hi!").unwrap(); - let mut fd_set = FdSet::new(); - fd_set.insert(&r1); - fd_set.insert(&r2); - - let mut timeout = TimeVal::seconds(10); - { - assert_eq!( - 1, - select( - Some( - fd_set - .highest() - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .unwrap() - + 1 - ), - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - } - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); - close(_w2).unwrap(); - } - - #[test] - fn test_select_nfds2() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; - let mut fd_set = FdSet::new(); - fd_set.insert(&r1); - fd_set.insert(&r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select( - std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1, - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); - close(_w2).unwrap(); - } -} diff --git a/third_party/rust/nix/src/sys/sendfile.rs b/third_party/rust/nix/src/sys/sendfile.rs index 9f3c333f97..d7452edd7c 100644 --- a/third_party/rust/nix/src/sys/sendfile.rs +++ b/third_party/rust/nix/src/sys/sendfile.rs @@ -20,9 +20,9 @@ use crate::Result; /// /// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. /// -/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) for Linux, +/// see [the sendfile(2) man page.](https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html) for Solaris. +#[cfg(any(linux_android, solarish))] pub fn sendfile( out_fd: F1, in_fd: F2, @@ -56,7 +56,6 @@ pub fn sendfile( /// /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn sendfile64( out_fd: F1, in_fd: F2, @@ -78,46 +77,82 @@ pub fn sendfile64( } cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] { + if #[cfg(any(freebsdlike, apple_targets))] { use std::io::IoSlice; #[derive(Clone, Debug)] - struct SendfileHeaderTrailer<'a>( - libc::sf_hdtr, - Option>>, - Option>>, - ); + struct SendfileHeaderTrailer<'a> { + raw: libc::sf_hdtr, + _headers: Option>>, + _trailers: Option>>, + } impl<'a> SendfileHeaderTrailer<'a> { fn new( headers: Option<&'a [&'a [u8]]>, trailers: Option<&'a [&'a [u8]]> ) -> SendfileHeaderTrailer<'a> { - let header_iovecs: Option>> = + let mut header_iovecs: Option>> = headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - let trailer_iovecs: Option>> = + let mut trailer_iovecs: Option>> = trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - SendfileHeaderTrailer( - libc::sf_hdtr { + + SendfileHeaderTrailer { + raw: libc::sf_hdtr { headers: { header_iovecs - .as_ref() - .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec + .as_mut() + .map_or(ptr::null_mut(), |v| v.as_mut_ptr()) + .cast() }, hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32, trailers: { trailer_iovecs - .as_ref() - .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec + .as_mut() + .map_or(ptr::null_mut(), |v| v.as_mut_ptr()) + .cast() }, trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32 }, - header_iovecs, - trailer_iovecs, - ) + _headers: header_iovecs, + _trailers: trailer_iovecs, + } + } + } + } else if #[cfg(solarish)] { + use std::os::unix::io::BorrowedFd; + use std::marker::PhantomData; + + #[derive(Debug, Copy, Clone)] + /// Mapping of the raw C sendfilevec_t struct + pub struct SendfileVec<'fd> { + raw: libc::sendfilevec_t, + phantom: PhantomData> + } + + impl<'fd> SendfileVec<'fd> { + /// initialises SendfileVec to send data directly from the process's address space + /// same in C with sfv_fd set to SFV_FD_SELF. + pub fn newself( + off: off_t, + len: usize + ) -> Self { + Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off, sfv_len: len}, phantom: PhantomData} + } + + /// initialises SendfileVec to send data from `fd`. + pub fn new( + fd: BorrowedFd<'fd>, + off: off_t, + len: usize + ) -> SendfileVec<'fd> { + Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off, sfv_len: len}, phantom: PhantomData} + } + } + + impl From> for libc::sendfilevec_t { + fn from<'fd>(vec: SendfileVec) -> libc::sendfilevec_t { + vec.raw } } } @@ -187,7 +222,7 @@ cfg_if! { let flags: u32 = (ra32 << 16) | (flags.bits() as u32); let mut bytes_sent: off_t = 0; let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); + let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr); let return_code = unsafe { libc::sendfile(in_fd.as_fd().as_raw_fd(), out_sock.as_fd().as_raw_fd(), @@ -230,7 +265,7 @@ cfg_if! { ) -> (Result<()>, off_t) { let mut bytes_sent: off_t = 0; let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); + let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr); let return_code = unsafe { libc::sendfile(in_fd.as_fd().as_raw_fd(), out_sock.as_fd().as_raw_fd(), @@ -242,7 +277,7 @@ cfg_if! { }; (Errno::result(return_code).and(Ok(())), bytes_sent) } - } else if #[cfg(any(target_os = "ios", target_os = "macos"))] { + } else if #[cfg(apple_targets)] { /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to /// `out_sock`. /// @@ -276,7 +311,7 @@ cfg_if! { ) -> (Result<()>, off_t) { let mut len = count.unwrap_or(0); let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); + let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr); let return_code = unsafe { libc::sendfile(in_fd.as_fd().as_raw_fd(), out_sock.as_fd().as_raw_fd(), @@ -287,5 +322,30 @@ cfg_if! { }; (Errno::result(return_code).and(Ok(())), len) } + } else if #[cfg(solarish)] { + /// Write data from the vec arrays to `out_sock` and returns a `Result` and a + /// count of bytes written. + /// + /// Each `SendfileVec` set needs to be instantiated either with `SendfileVec::new` or + /// `SendfileVec::newself`. + /// + /// The former allows to send data from a file descriptor through `fd`, + /// from an offset `off` and for a given amount of data `len`. + /// + /// The latter allows to send data from the process's address space, from an offset `off` + /// and for a given amount of data `len`. + /// + /// For more information, see + /// [the sendfilev(3) man page.](https://illumos.org/man/3EXT/sendfilev) + pub fn sendfilev( + out_sock: F, + vec: &[SendfileVec] + ) -> (Result<()>, usize) { + let mut len = 0usize; + let return_code = unsafe { + libc::sendfilev(out_sock.as_fd().as_raw_fd(), vec.as_ptr() as *const libc::sendfilevec_t, vec.len() as i32, &mut len) + }; + (Errno::result(return_code).and(Ok(())), len) + } } } diff --git a/third_party/rust/nix/src/sys/signal.rs b/third_party/rust/nix/src/sys/signal.rs index c946e4a0b1..c9b593d0db 100644 --- a/third_party/rust/nix/src/sys/signal.rs +++ b/third_party/rust/nix/src/sys/signal.rs @@ -7,14 +7,17 @@ use crate::errno::Errno; use crate::{Error, Result}; use cfg_if::cfg_if; use std::fmt; +use std::hash::{Hash, Hasher}; use std::mem; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] +use std::ops::BitOr; +#[cfg(freebsdlike)] use std::os::unix::io::RawFd; use std::ptr; use std::str::FromStr; #[cfg(not(any( target_os = "fuchsia", + target_os = "hurd", target_os = "openbsd", target_os = "redox" )))] @@ -63,9 +66,12 @@ libc_enum! { /// Software termination signal from kill SIGTERM, /// Stack fault (obsolete) - #[cfg(all(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"), - not(any(target_arch = "mips", target_arch = "mips64", + #[cfg(all(any(linux_android, target_os = "emscripten", + target_os = "fuchsia"), + not(any(target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64"))))] SIGSTKFLT, /// To parent on child stop or exit @@ -94,27 +100,21 @@ libc_enum! { SIGWINCH, /// Input/output possible signal #[cfg(not(target_os = "haiku"))] - #[cfg_attr(docsrs, doc(cfg(all())))] SIGIO, - #[cfg(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "emscripten", + target_os = "fuchsia", target_os = "aix"))] /// Power failure imminent. SIGPWR, /// Bad system call SIGSYS, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", + #[cfg(not(any(linux_android, target_os = "emscripten", + target_os = "fuchsia", target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Emulator trap SIGEMT, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku", - target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(linux_android, target_os = "emscripten", + target_os = "fuchsia", target_os = "redox", + target_os = "haiku", target_os = "aix")))] /// Information request SIGINFO, } @@ -143,14 +143,15 @@ impl FromStr for Signal { "SIGTERM" => Signal::SIGTERM, #[cfg(all( any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux" ), not(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64" )) ))] @@ -170,27 +171,24 @@ impl FromStr for Signal { #[cfg(not(target_os = "haiku"))] "SIGIO" => Signal::SIGIO, #[cfg(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux" ))] "SIGPWR" => Signal::SIGPWR, "SIGSYS" => Signal::SIGSYS, #[cfg(not(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux", target_os = "redox", target_os = "haiku" )))] "SIGEMT" => Signal::SIGEMT, #[cfg(not(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux", target_os = "redox", target_os = "aix", target_os = "haiku" @@ -227,14 +225,15 @@ impl Signal { Signal::SIGTERM => "SIGTERM", #[cfg(all( any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux" ), not(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64" )) ))] @@ -254,28 +253,25 @@ impl Signal { #[cfg(not(target_os = "haiku"))] Signal::SIGIO => "SIGIO", #[cfg(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "aix", - target_os = "linux" ))] Signal::SIGPWR => "SIGPWR", Signal::SIGSYS => "SIGSYS", #[cfg(not(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux", target_os = "redox", target_os = "haiku" )))] Signal::SIGEMT => "SIGEMT", #[cfg(not(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux", target_os = "redox", target_os = "aix", target_os = "haiku" @@ -319,15 +315,12 @@ const SIGNALS: [Signal; 28] = [ SIGPROF, SIGWINCH, SIGSYS, ]; #[cfg(all( - any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), + any(linux_android, target_os = "emscripten", target_os = "fuchsia"), not(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64" )) ))] @@ -339,13 +332,14 @@ const SIGNALS: [Signal; 31] = [ SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, ]; #[cfg(all( + any(linux_android, target_os = "emscripten", target_os = "fuchsia"), any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), - any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64") + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "sparc64" + ) ))] #[cfg(feature = "signal")] const SIGNALS: [Signal; 30] = [ @@ -363,8 +357,7 @@ const SIGNALS: [Signal; 30] = [ SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP, ]; #[cfg(not(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "fuchsia", target_os = "emscripten", target_os = "aix", @@ -439,6 +432,7 @@ libc_bitflags! { SA_NOCLDSTOP; /// When catching a [`Signal::SIGCHLD`] signal, the system will not /// create zombie processes when children of the calling process exit. + #[cfg(not(target_os = "hurd"))] SA_NOCLDWAIT; /// Further occurrences of the delivered signal are not masked during /// the execution of the handler. @@ -486,7 +480,7 @@ use std::iter::IntoIterator; // We are using `transparent` here to be super sure that `SigSet` // is represented exactly like the `sigset_t` struct from C. #[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq)] pub struct SigSet { sigset: libc::sigset_t } @@ -577,7 +571,6 @@ impl SigSet { /// Suspends execution of the calling thread until one of the signals in the /// signal mask becomes pending, and returns the accepted signal. #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn wait(&self) -> Result { use std::convert::TryFrom; @@ -589,6 +582,35 @@ impl SigSet { }) } + /// Wait for a signal + /// + /// # Return value + /// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`. + /// If `sigsuspend(2)` set other error, this function returns `Err`. + /// + /// For more information see the + /// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html). + #[cfg(any( + bsd, + linux_android, + solarish, + target_os = "haiku", + target_os = "hurd", + target_os = "aix", + target_os = "fushsia" + ))] + #[doc(alias("sigsuspend"))] + pub fn suspend(&self) -> Result<()> { + let res = unsafe { + libc::sigsuspend(&self.sigset as *const libc::sigset_t) + }; + match Errno::result(res).map(drop) { + Err(Errno::EINTR) => Ok(()), + Err(e) => Err(e), + Ok(_) => unreachable!("because this syscall always returns -1 if returns"), + } + } + /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the /// `libc::sigset_t` is already initialized. /// @@ -603,6 +625,42 @@ impl SigSet { } } +impl From for SigSet { + fn from(signal: Signal) -> SigSet { + let mut sigset = SigSet::empty(); + sigset.add(signal); + sigset + } +} + +impl BitOr for Signal { + type Output = SigSet; + + fn bitor(self, rhs: Self) -> Self::Output { + let mut sigset = SigSet::empty(); + sigset.add(self); + sigset.add(rhs); + sigset + } +} + +impl BitOr for SigSet { + type Output = SigSet; + + fn bitor(mut self, rhs: Signal) -> Self::Output { + self.add(rhs); + self + } +} + +impl BitOr for SigSet { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + self.iter().chain(rhs.iter()).collect() + } +} + impl AsRef for SigSet { fn as_ref(&self) -> &libc::sigset_t { &self.sigset @@ -628,6 +686,27 @@ impl FromIterator for SigSet { } } +impl PartialEq for SigSet { + fn eq(&self, other: &Self) -> bool { + for signal in Signal::iterator() { + if self.contains(signal) != other.contains(signal) { + return false; + } + } + true + } +} + +impl Hash for SigSet { + fn hash(&self, state: &mut H) { + for signal in Signal::iterator() { + if self.contains(signal) { + signal.hash(state); + } + } + } +} + /// Iterator for a [`SigSet`]. /// /// Call [`SigSet::iter`] to create an iterator. @@ -670,7 +749,6 @@ pub enum SigHandler { /// Use the given signal-catching function, which takes in the signal, information about how /// the signal was generated, and a pointer to the threads `ucontext_t`. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)) } @@ -689,23 +767,27 @@ impl SigAction { pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { #[cfg(not(target_os = "aix"))] unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { - (*p).sa_sigaction = match handler { - SigHandler::SigDfl => libc::SIG_DFL, - SigHandler::SigIgn => libc::SIG_IGN, - SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, - #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, - }; + unsafe { + (*p).sa_sigaction = match handler { + SigHandler::SigDfl => libc::SIG_DFL, + SigHandler::SigIgn => libc::SIG_IGN, + SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, + #[cfg(not(target_os = "redox"))] + SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, + }; + } } #[cfg(target_os = "aix")] unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { - (*p).sa_union.__su_sigaction = match handler { - SigHandler::SigDfl => mem::transmute::(libc::SIG_DFL), - SigHandler::SigIgn => mem::transmute::(libc::SIG_IGN), - SigHandler::Handler(f) => mem::transmute::(f), - SigHandler::SigAction(f) => f, - }; + unsafe { + (*p).sa_union.__su_sigaction = match handler { + SigHandler::SigDfl => unsafe { mem::transmute::(libc::SIG_DFL) }, + SigHandler::SigIgn => unsafe { mem::transmute::(libc::SIG_IGN) }, + SigHandler::Handler(f) => unsafe { mem::transmute::(f) }, + SigHandler::SigAction(f) => f, + }; + } } let mut s = mem::MaybeUninit::::uninit(); @@ -810,11 +892,11 @@ impl SigAction { pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result { let mut oldact = mem::MaybeUninit::::uninit(); - let res = libc::sigaction(signal as libc::c_int, + let res = unsafe { libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, - oldact.as_mut_ptr()); + oldact.as_mut_ptr()) }; - Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) + Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } }) } /// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) @@ -872,9 +954,9 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result Result { let signal = signal as libc::c_int; let res = match handler { - SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL), - SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN), - SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t), + SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) }, + SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) }, + SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) }, #[cfg(not(target_os = "redox"))] SigHandler::SigAction(_) => return Err(Errno::ENOTSUP), }; @@ -883,9 +965,7 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, p => SigHandler::Handler( - *(&p as *const usize - as *const extern fn(libc::c_int)) - as extern fn(libc::c_int)), + unsafe { *(&p as *const usize as *const extern fn(libc::c_int)) } as extern fn(libc::c_int)), } }) } @@ -1019,14 +1099,14 @@ feature! { #[cfg(target_os = "freebsd")] pub type type_of_thread_id = libc::lwpid_t; /// Identifies a thread for [`SigevNotify::SigevThreadId`] -#[cfg(any(target_env = "gnu", target_env = "uclibc"))] +#[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))] pub type type_of_thread_id = libc::pid_t; /// Specifies the notification method used by a [`SigEvent`] // sigval is actually a union of a int and a void*. But it's never really used // as a pointer, because neither libc nor the kernel ever dereference it. nix // therefore presents it as an intptr_t, which is how kevent uses it. -#[cfg(not(any(target_os = "fuchsia", target_os = "openbsd", target_os = "redox")))] +#[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum SigevNotify { /// No notification will be delivered @@ -1041,8 +1121,7 @@ pub enum SigevNotify { }, // Note: SIGEV_THREAD is not implemented, but could be if desired. /// Notify by delivering an event to a kqueue. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] SigevKevent { /// File descriptor of the kqueue to notify. kq: RawFd, @@ -1051,7 +1130,6 @@ pub enum SigevNotify { }, /// Notify by delivering an event to a kqueue, with optional event flags set #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] #[cfg(feature = "event")] SigevKeventFlags { /// File descriptor of the kqueue to notify. @@ -1067,7 +1145,6 @@ pub enum SigevNotify { target_env = "gnu", target_env = "uclibc", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SigevThreadId { /// Signal to send signal: Signal, @@ -1082,10 +1159,10 @@ pub enum SigevNotify { #[cfg(not(any( target_os = "fuchsia", + target_os = "hurd", target_os = "openbsd", target_os = "redox" )))] -#[cfg_attr(docsrs, doc(cfg(all())))] mod sigevent { feature! { #![any(feature = "aio", feature = "signal")] @@ -1251,7 +1328,7 @@ mod sigevent { sev.sigev_signo = signal as libc::c_int; sev.sigev_value.sival_ptr = si_value as *mut libc::c_void }, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg(freebsdlike)] SigevNotify::SigevKevent{kq, udata} => { sev.sigev_notify = libc::SIGEV_KEVENT; sev.sigev_signo = kq; @@ -1331,227 +1408,3 @@ mod sigevent { } } } - -#[cfg(test)] -mod tests { - use super::*; - #[cfg(not(target_os = "redox"))] - use std::thread; - - #[test] - fn test_contains() { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - assert!(mask.contains(SIGUSR1)); - assert!(!mask.contains(SIGUSR2)); - - let all = SigSet::all(); - assert!(all.contains(SIGUSR1)); - assert!(all.contains(SIGUSR2)); - } - - #[test] - fn test_clear() { - let mut set = SigSet::all(); - set.clear(); - for signal in Signal::iterator() { - assert!(!set.contains(signal)); - } - } - - #[test] - fn test_from_str_round_trips() { - for signal in Signal::iterator() { - assert_eq!(signal.as_ref().parse::().unwrap(), signal); - assert_eq!(signal.to_string().parse::().unwrap(), signal); - } - } - - #[test] - fn test_from_str_invalid_value() { - let errval = Err(Errno::EINVAL); - assert_eq!("NOSIGNAL".parse::(), errval); - assert_eq!("kill".parse::(), errval); - assert_eq!("9".parse::(), errval); - } - - #[test] - fn test_extend() { - let mut one_signal = SigSet::empty(); - one_signal.add(SIGUSR1); - - let mut two_signals = SigSet::empty(); - two_signals.add(SIGUSR2); - two_signals.extend(&one_signal); - - assert!(two_signals.contains(SIGUSR1)); - assert!(two_signals.contains(SIGUSR2)); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_set_mask() { - thread::spawn(|| { - let prev_mask = SigSet::thread_get_mask() - .expect("Failed to get existing signal mask!"); - - let mut test_mask = prev_mask; - test_mask.add(SIGUSR1); - - test_mask.thread_set_mask().expect("assertion failed"); - let new_mask = - SigSet::thread_get_mask().expect("Failed to get new mask!"); - - assert!(new_mask.contains(SIGUSR1)); - assert!(!new_mask.contains(SIGUSR2)); - - prev_mask - .thread_set_mask() - .expect("Failed to revert signal mask!"); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_block() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - mask.thread_block().expect("assertion failed"); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_unblock() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - mask.thread_unblock().expect("assertion failed"); - - assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_swap() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - mask.thread_block().unwrap(); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - - let mut mask2 = SigSet::empty(); - mask2.add(SIGUSR2); - - let oldmask = - mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap(); - - assert!(oldmask.contains(SIGUSR1)); - assert!(!oldmask.contains(SIGUSR2)); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2)); - }) - .join() - .unwrap(); - } - - #[test] - fn test_from_and_into_iterator() { - let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); - let signals = sigset.into_iter().collect::>(); - assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_sigaction() { - thread::spawn(|| { - extern "C" fn test_sigaction_handler(_: libc::c_int) {} - extern "C" fn test_sigaction_action( - _: libc::c_int, - _: *mut libc::siginfo_t, - _: *mut libc::c_void, - ) { - } - - let handler_sig = SigHandler::Handler(test_sigaction_handler); - - let flags = - SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO; - - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - let action_sig = SigAction::new(handler_sig, flags, mask); - - assert_eq!( - action_sig.flags(), - SaFlags::SA_ONSTACK | SaFlags::SA_RESTART - ); - assert_eq!(action_sig.handler(), handler_sig); - - mask = action_sig.mask(); - assert!(mask.contains(SIGUSR1)); - assert!(!mask.contains(SIGUSR2)); - - let handler_act = SigHandler::SigAction(test_sigaction_action); - let action_act = SigAction::new(handler_act, flags, mask); - assert_eq!(action_act.handler(), handler_act); - - let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask); - assert_eq!(action_dfl.handler(), SigHandler::SigDfl); - - let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask); - assert_eq!(action_ign.handler(), SigHandler::SigIgn); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_sigwait() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - mask.add(SIGUSR2); - mask.thread_block().unwrap(); - - raise(SIGUSR1).unwrap(); - assert_eq!(mask.wait().unwrap(), SIGUSR1); - }) - .join() - .unwrap(); - } - - #[test] - fn test_from_sigset_t_unchecked() { - let src_set = SigSet::empty(); - let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; - - for signal in Signal::iterator() { - assert!(!set.contains(signal)); - } - - let src_set = SigSet::all(); - let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; - - for signal in Signal::iterator() { - assert!(set.contains(signal)); - } - } -} diff --git a/third_party/rust/nix/src/sys/signalfd.rs b/third_party/rust/nix/src/sys/signalfd.rs index 2b80ea643f..ccba774d1a 100644 --- a/third_party/rust/nix/src/sys/signalfd.rs +++ b/third_party/rust/nix/src/sys/signalfd.rs @@ -21,7 +21,7 @@ use crate::Result; pub use libc::signalfd_siginfo as siginfo; use std::mem; -use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, OwnedFd, AsFd, BorrowedFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; libc_bitflags! { pub struct SfdFlags: libc::c_int { @@ -45,18 +45,23 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::(); /// /// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) #[deprecated(since = "0.27.0", note = "Use SignalFd instead")] -pub fn signalfd(fd: Option, mask: &SigSet, flags: SfdFlags) -> Result { +pub fn signalfd( + fd: Option, + mask: &SigSet, + flags: SfdFlags, +) -> Result { _signalfd(fd, mask, flags) } -fn _signalfd(fd: Option, mask: &SigSet, flags: SfdFlags) -> Result { - let raw_fd = fd.map_or(-1, |x|x.as_fd().as_raw_fd()); +fn _signalfd( + fd: Option, + mask: &SigSet, + flags: SfdFlags, +) -> Result { + let raw_fd = fd.map_or(-1, |x| x.as_fd().as_raw_fd()); unsafe { - Errno::result(libc::signalfd( - raw_fd, - mask.as_ref(), - flags.bits(), - )).map(|raw_fd|FromRawFd::from_raw_fd(raw_fd)) + Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits())) + .map(|raw_fd| FromRawFd::from_raw_fd(raw_fd)) } } @@ -101,7 +106,7 @@ impl SignalFd { } pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { - _signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop) + self.update(mask, SfdFlags::empty()) } pub fn read_signal(&mut self) -> Result> { @@ -109,7 +114,7 @@ impl SignalFd { let size = mem::size_of_val(&buffer); let res = Errno::result(unsafe { - libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr() as *mut libc::c_void, size) + libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr().cast(), size) }) .map(|r| r as usize); match res { @@ -119,6 +124,14 @@ impl SignalFd { Err(error) => Err(error), } } + + fn update(&self, mask: &SigSet, flags: SfdFlags) -> Result<()> { + let raw_fd = self.0.as_raw_fd(); + unsafe { + Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits())) + .map(drop) + } + } } impl AsFd for SignalFd { @@ -142,34 +155,3 @@ impl Iterator for SignalFd { } } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn create_signalfd() { - let mask = SigSet::empty(); - SignalFd::new(&mask).unwrap(); - } - - #[test] - fn create_signalfd_with_opts() { - let mask = SigSet::empty(); - SignalFd::with_flags( - &mask, - SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK, - ) - .unwrap(); - } - - #[test] - fn read_empty_signalfd() { - let mask = SigSet::empty(); - let mut fd = - SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); - - let res = fd.read_signal(); - assert!(res.unwrap().is_none()); - } -} diff --git a/third_party/rust/nix/src/sys/socket/addr.rs b/third_party/rust/nix/src/sys/socket/addr.rs index 1783531d49..f6800aa5d0 100644 --- a/third_party/rust/nix/src/sys/socket/addr.rs +++ b/third_party/rust/nix/src/sys/socket/addr.rs @@ -1,31 +1,22 @@ #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd", + bsd, + linux_android, + solarish, target_os = "haiku", target_os = "fuchsia", target_os = "aix", ))] #[cfg(feature = "net")] pub use self::datalink::LinkAddr; -#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] +#[cfg(any(linux_android, apple_targets))] pub use self::vsock::VsockAddr; use super::sa_family_t; use crate::errno::Errno; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") -))] +#[cfg(all(feature = "ioctl", apple_targets))] use crate::sys::socket::addr::sys_control::SysControlAddr; use crate::{NixPath, Result}; use cfg_if::cfg_if; @@ -33,6 +24,7 @@ use memoffset::offset_of; use std::convert::TryInto; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; +use std::net::{Ipv4Addr, Ipv6Addr}; use std::os::unix::ffi::OsStrExt; use std::path::Path; use std::{fmt, mem, net, ptr, slice}; @@ -41,7 +33,7 @@ use std::{fmt, mem, net, ptr, slice}; #[cfg(feature = "net")] pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { libc::in_addr { - s_addr: u32::from_ne_bytes(addr.octets()) + s_addr: u32::from_ne_bytes(addr.octets()), } } @@ -49,7 +41,7 @@ pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { #[cfg(feature = "net")] pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { libc::in6_addr { - s6_addr: addr.octets() + s6_addr: addr.octets(), } } @@ -71,346 +63,188 @@ pub enum AddressFamily { /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html)) Inet6 = libc::AF_INET6, /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Netlink = libc::AF_NETLINK, /// Kernel interface for interacting with the routing table - #[cfg(not(any( - target_os = "redox", - target_os = "linux", - target_os = "android" - )))] + #[cfg(not(any(linux_android, target_os = "redox")))] Route = libc::PF_ROUTE, /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "illumos", - target_os = "fuchsia", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] Packet = libc::AF_PACKET, /// KEXT Controls and Notifications - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] System = libc::AF_SYSTEM, /// Amateur radio AX.25 protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Ax25 = libc::AF_AX25, /// IPX - Novell protocols #[cfg(not(any(target_os = "aix", target_os = "redox")))] - #[cfg_attr(docsrs, doc(cfg(all())))] Ipx = libc::AF_IPX, /// AppleTalk #[cfg(not(target_os = "redox"))] AppleTalk = libc::AF_APPLETALK, /// AX.25 packet layer protocol. /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetRom = libc::AF_NETROM, /// Can't be used for creating sockets; mostly used for bridge /// links in /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) /// protocol commands. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Bridge = libc::AF_BRIDGE, /// Access to raw ATM PVCs - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] AtmPvc = libc::AF_ATMPVC, /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] X25 = libc::AF_X25, /// RATS (Radio Amateur Telecommunications Society) Open /// Systems environment (ROSE) AX.25 packet layer protocol. /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Rose = libc::AF_ROSE, /// DECet protocol sockets. #[cfg(not(any(target_os = "haiku", target_os = "redox")))] Decnet = libc::AF_DECnet, /// Reserved for "802.2LLC project"; never used. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetBeui = libc::AF_NETBEUI, /// This was a short-lived (between Linux 2.1.30 and /// 2.1.99pre2) protocol family for firewall upcalls. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Security = libc::AF_SECURITY, /// Key management protocol. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Key = libc::AF_KEY, #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Ash = libc::AF_ASH, /// Acorn Econet protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Econet = libc::AF_ECONET, /// Access to ATM Switched Virtual Circuits - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] AtmSvc = libc::AF_ATMSVC, /// Reliable Datagram Sockets (RDS) protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Rds = libc::AF_RDS, /// IBM SNA #[cfg(not(any(target_os = "haiku", target_os = "redox")))] Sna = libc::AF_SNA, /// Socket interface over IrDA - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Irda = libc::AF_IRDA, /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Pppox = libc::AF_PPPOX, /// Legacy protocol for wide area network (WAN) connectivity that was used /// by Sangoma WAN cards - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Wanpipe = libc::AF_WANPIPE, /// Logical link control (IEEE 802.2 LLC) protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Llc = libc::AF_LLC, /// InfiniBand native addressing #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] Ib = libc::AF_IB, /// Multiprotocol Label Switching #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] Mpls = libc::AF_MPLS, /// Controller Area Network automotive bus protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Can = libc::AF_CAN, /// TIPC, "cluster domain sockets" protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Tipc = libc::AF_TIPC, /// Bluetooth low-level socket protocol #[cfg(not(any( target_os = "aix", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "solaris", + solarish, + apple_targets, + target_os = "hurd", target_os = "redox", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] Bluetooth = libc::AF_BLUETOOTH, /// IUCV (inter-user communication vehicle) z/VM protocol for /// hypervisor-guest interaction - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Iucv = libc::AF_IUCV, /// Rx, Andrew File System remote procedure call protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] RxRpc = libc::AF_RXRPC, /// New "modular ISDN" driver interface protocol #[cfg(not(any( target_os = "aix", - target_os = "illumos", - target_os = "solaris", + solarish, target_os = "haiku", + target_os = "hurd", target_os = "redox", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] Isdn = libc::AF_ISDN, /// Nokia cellular modem IPC/RPC interface - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Phonet = libc::AF_PHONET, /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Ieee802154 = libc::AF_IEEE802154, /// Ericsson's Communication CPU to Application CPU interface (CAIF) /// protocol. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Caif = libc::AF_CAIF, /// Interface to kernel crypto API - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Alg = libc::AF_ALG, /// Near field communication #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] Nfc = libc::AF_NFC, /// VMWare VSockets protocol for hypervisor-guest interaction. - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets))] Vsock = libc::AF_VSOCK, /// ARPANet IMP addresses - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] ImpLink = libc::AF_IMPLINK, /// PUP protocols, e.g. BSP - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Pup = libc::AF_PUP, /// MIT CHAOS protocols - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Chaos = libc::AF_CHAOS, /// Novell and Xerox protocol - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(apple_targets, netbsdlike))] Ns = libc::AF_NS, #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Iso = libc::AF_ISO, /// Bell Labs virtual circuit switch ? - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Datakit = libc::AF_DATAKIT, /// CCITT protocols, X.25 etc - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Ccitt = libc::AF_CCITT, /// DEC Direct data link interface - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Dli = libc::AF_DLI, #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Lat = libc::AF_LAT, /// NSC Hyperchannel - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Hylink = libc::AF_HYLINK, /// Link layer interface - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish))] Link = libc::AF_LINK, /// connection-oriented IP, aka ST II - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Coip = libc::AF_COIP, /// Computer Network Technology - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Cnt = libc::AF_CNT, /// Native ATM access - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] Natm = libc::AF_NATM, /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Unspec = libc::AF_UNSPEC, } @@ -425,29 +259,17 @@ impl AddressFamily { libc::AF_UNIX => Some(AddressFamily::Unix), libc::AF_INET => Some(AddressFamily::Inet), libc::AF_INET6 => Some(AddressFamily::Inet6), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_NETLINK => Some(AddressFamily::Netlink), - #[cfg(any(target_os = "macos", target_os = "macos"))] + #[cfg(apple_targets)] libc::AF_SYSTEM => Some(AddressFamily::System), - #[cfg(not(any( - target_os = "redox", - target_os = "linux", - target_os = "android" - )))] + #[cfg(not(any(linux_android, target_os = "redox")))] libc::PF_ROUTE => Some(AddressFamily::Route), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_PACKET => Some(AddressFamily::Packet), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] + #[cfg(any(bsd, solarish))] libc::AF_LINK => Some(AddressFamily::Link), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] libc::AF_VSOCK => Some(AddressFamily::Vsock), _ => None, } @@ -463,13 +285,7 @@ pub struct UnixAddr { /// The length of the valid part of `sun`, including the sun_family field /// but excluding any trailing nul. // On the BSDs, this field is built into sun - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "redox", - ))] + #[cfg(not(any(bsd, target_os = "haiku", target_os = "hurd")))] sun_len: u8, } @@ -483,12 +299,12 @@ pub struct UnixAddr { enum UnixAddrKind<'a> { Pathname(&'a Path), Unnamed, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] Abstract(&'a [u8]), } impl<'a> UnixAddrKind<'a> { /// Safety: sun & sun_len must be valid - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); let path_len = @@ -496,16 +312,19 @@ impl<'a> UnixAddrKind<'a> { if path_len == 0 { return Self::Unnamed; } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] if sun.sun_path[0] == 0 { - let name = slice::from_raw_parts( - sun.sun_path.as_ptr().add(1) as *const u8, - path_len - 1, - ); + let name = unsafe { + slice::from_raw_parts( + sun.sun_path.as_ptr().add(1).cast(), + path_len - 1, + ) + }; return Self::Abstract(name); } - let pathname = - slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); + let pathname = unsafe { + slice::from_raw_parts(sun.sun_path.as_ptr().cast(), path_len) + }; if pathname.last() == Some(&0) { // A trailing NUL is not considered part of the path, and it does // not need to be included in the addrlen passed to functions like @@ -525,7 +344,7 @@ impl<'a> UnixAddrKind<'a> { impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pub fn new(path: &P) -> Result { path.with_nix_path(|cstr| unsafe { let mut ret = libc::sockaddr_un { @@ -544,20 +363,13 @@ impl UnixAddr { .try_into() .unwrap(); - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] + #[cfg(any(bsd, target_os = "haiku", target_os = "hurd"))] { ret.sun_len = sun_len; } ptr::copy_nonoverlapping( bytes.as_ptr(), - ret.sun_path.as_mut_ptr() as *mut u8, + ret.sun_path.as_mut_ptr().cast(), bytes.len(), ); @@ -571,9 +383,8 @@ impl UnixAddr { /// thus the input `path` is expected to be the bare name, not NUL-prefixed. /// This is a Linux-specific extension, primarily used to allow chrooted /// processes to communicate with processes having a different filesystem view. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms + #[cfg(linux_android)] + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pub fn new_abstract(path: &[u8]) -> Result { unsafe { let mut ret = libc::sockaddr_un { @@ -593,7 +404,7 @@ impl UnixAddr { // b'\0', so copy starting one byte in. ptr::copy_nonoverlapping( path.as_ptr(), - ret.sun_path.as_mut_ptr().offset(1) as *mut u8, + ret.sun_path.as_mut_ptr().offset(1).cast(), path.len(), ); @@ -602,8 +413,7 @@ impl UnixAddr { } /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] pub fn new_unnamed() -> UnixAddr { let ret = libc::sockaddr_un { sun_family: AddressFamily::Unix as sa_family_t, @@ -632,10 +442,9 @@ impl UnixAddr { sun_len: u8, ) -> UnixAddr { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { @@ -664,8 +473,7 @@ impl UnixAddr { /// /// For abstract sockets only the bare name is returned, without the /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] pub fn as_abstract(&self) -> Option<&[u8]> { match self.kind() { UnixAddrKind::Abstract(name) => Some(name), @@ -674,8 +482,7 @@ impl UnixAddr { } /// Check if this address is an "unnamed" unix socket address. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] #[inline] pub fn is_unnamed(&self) -> bool { matches!(self.kind(), UnixAddrKind::Unnamed) @@ -699,10 +506,9 @@ impl UnixAddr { fn sun_len(&self) -> u8 { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { @@ -717,10 +523,10 @@ impl UnixAddr { impl private::SockaddrLikePriv for UnixAddr {} impl SockaddrLike for UnixAddr { #[cfg(any( - target_os = "android", + linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, + target_os = "redox" ))] fn len(&self) -> libc::socklen_t { self.sun_len.into() @@ -740,27 +546,26 @@ impl SockaddrLike for UnixAddr { return None; } } - if (*addr).sa_family as i32 != libc::AF_UNIX { + if unsafe { (*addr).sa_family as i32 != libc::AF_UNIX } { return None; } - let mut su: libc::sockaddr_un = mem::zeroed(); + let mut su: libc::sockaddr_un = unsafe { mem::zeroed() }; let sup = &mut su as *mut libc::sockaddr_un as *mut u8; cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { let su_len = len.unwrap_or( mem::size_of::() as libc::socklen_t ); } else { - let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t); + let su_len = unsafe { len.unwrap_or((*addr).sa_len as libc::socklen_t) }; } - }; - ptr::copy(addr as *const u8, sup, su_len as usize); - Some(Self::from_raw_parts(su, su_len as u8)) + } + unsafe { ptr::copy(addr as *const u8, sup, su_len as usize) }; + Some(unsafe { Self::from_raw_parts(su, su_len as u8) }) } fn size() -> libc::socklen_t @@ -770,14 +575,16 @@ impl SockaddrLike for UnixAddr { mem::size_of::() as libc::socklen_t } - unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + unsafe fn set_length( + &mut self, + new_length: usize, + ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { // `new_length` is only used on some platforms, so it must be provided even when not used #![allow(unused_variables)] cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { self.sun_len = new_length as u8; @@ -793,7 +600,7 @@ impl AsRef for UnixAddr { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { use fmt::Write; f.write_str("@\"")?; @@ -810,7 +617,7 @@ impl fmt::Display for UnixAddr { match self.kind() { UnixAddrKind::Pathname(path) => path.display().fmt(f), UnixAddrKind::Unnamed => f.pad(""), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] UnixAddrKind::Abstract(name) => fmt_abstract(name, f), } } @@ -894,12 +701,7 @@ pub trait SockaddrLike: private::SockaddrLikePriv { } cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] { + if #[cfg(bsd)] { /// Return the length of valid data in the sockaddr structure. /// /// For fixed-size sockaddrs, this should be the size of the @@ -946,7 +748,10 @@ pub trait SockaddrLike: private::SockaddrLikePriv { /// `new_length` must be a valid length for this type of address. Specifically, reads of that /// length from `self` must be valid. #[doc(hidden)] - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + unsafe fn set_length( + &mut self, + _new_length: usize, + ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { Err(SocketAddressLengthNotDynamic) } } @@ -1006,22 +811,20 @@ pub struct SockaddrIn(libc::sockaddr_in); impl SockaddrIn { /// Returns the IP address associated with this socket address, in native /// endian. - pub const fn ip(&self) -> libc::in_addr_t { - u32::from_be(self.0.sin_addr.s_addr) + pub const fn ip(&self) -> net::Ipv4Addr { + let bytes = self.0.sin_addr.s_addr.to_ne_bytes(); + let (a, b, c, d) = (bytes[0], bytes[1], bytes[2], bytes[3]); + Ipv4Addr::new(a, b, c, d) } /// Creates a new socket address from IPv4 octets and a port number. pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { Self(libc::sockaddr_in { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", + bsd, target_os = "aix", target_os = "haiku", - target_os = "openbsd" + target_os = "hurd" ))] sin_len: Self::size() as u8, sin_family: AddressFamily::Inet as sa_family_t, @@ -1056,10 +859,10 @@ impl SockaddrLike for SockaddrIn { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET { + if unsafe { (*addr).sa_family as i32 != libc::AF_INET } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1092,14 +895,10 @@ impl From for SockaddrIn { fn from(addr: net::SocketAddrV4) -> Self { Self(libc::sockaddr_in { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "haiku", target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" + target_os = "hurd" ))] sin_len: mem::size_of::() as u8, sin_family: AddressFamily::Inet as sa_family_t, @@ -1143,8 +942,19 @@ impl SockaddrIn6 { } /// Returns the IP address associated with this socket address. - pub fn ip(&self) -> net::Ipv6Addr { - net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) + pub const fn ip(&self) -> net::Ipv6Addr { + let bytes = self.0.sin6_addr.s6_addr; + let (a, b, c, d, e, f, g, h) = ( + ((bytes[0] as u16) << 8) | bytes[1] as u16, + ((bytes[2] as u16) << 8) | bytes[3] as u16, + ((bytes[4] as u16) << 8) | bytes[5] as u16, + ((bytes[6] as u16) << 8) | bytes[7] as u16, + ((bytes[8] as u16) << 8) | bytes[9] as u16, + ((bytes[10] as u16) << 8) | bytes[11] as u16, + ((bytes[12] as u16) << 8) | bytes[13] as u16, + ((bytes[14] as u16) << 8) | bytes[15] as u16, + ); + Ipv6Addr::new(a, b, c, d, e, f, g, h) } /// Returns the port number associated with this socket address, in native @@ -1175,10 +985,10 @@ impl SockaddrLike for SockaddrIn6 { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET6 { + if unsafe { (*addr).sa_family as i32 != libc::AF_INET6 } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1210,14 +1020,10 @@ impl From for SockaddrIn6 { #[allow(clippy::needless_update)] // It isn't needless on Illumos Self(libc::sockaddr_in6 { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "haiku", target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" + target_os = "hurd" ))] sin6_len: mem::size_of::() as u8, sin6_family: AddressFamily::Inet6 as sa_family_t, @@ -1273,18 +1079,17 @@ impl std::str::FromStr for SockaddrIn6 { #[derive(Clone, Copy, Eq)] #[repr(C)] pub union SockaddrStorage { - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] alg: AlgAddr, - #[cfg(all(feature = "net", not(target_os = "redox")))] + #[cfg(all( + feature = "net", + not(any(target_os = "hurd", target_os = "redox")) + ))] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] dl: LinkAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] nl: NetlinkAddr, - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] + #[cfg(all(feature = "ioctl", apple_targets))] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] sctl: SysControlAddr, #[cfg(feature = "net")] @@ -1293,8 +1098,7 @@ pub union SockaddrStorage { sin6: SockaddrIn6, ss: libc::sockaddr_storage, su: UnixAddr, - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets))] vsock: VsockAddr, } impl private::SockaddrLikePriv for SockaddrStorage {} @@ -1316,21 +1120,22 @@ impl SockaddrLike for SockaddrStorage { { None } else { - let mut ss: libc::sockaddr_storage = mem::zeroed(); + let mut ss: libc::sockaddr_storage = unsafe { mem::zeroed() }; let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; - ptr::copy(addr as *const u8, ssp, len as usize); + unsafe { ptr::copy(addr as *const u8, ssp, len as usize) }; #[cfg(any( - target_os = "android", + linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, ))] if i32::from(ss.ss_family) == libc::AF_UNIX { // Safe because we UnixAddr is strictly smaller than // SockaddrStorage, and we just initialized the structure. - (*(&mut ss as *mut libc::sockaddr_storage - as *mut UnixAddr)) - .sun_len = len as u8; + unsafe { + (*(&mut ss as *mut libc::sockaddr_storage + as *mut UnixAddr)) + .sun_len = len as u8; + } } Some(Self { ss }) } @@ -1338,68 +1143,47 @@ impl SockaddrLike for SockaddrStorage { // If length is not available and addr is of a fixed-length type, // copy it. If addr is of a variable length type and len is not // available, then there's nothing we can do. - match (*addr).sa_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => { + match unsafe { (*addr).sa_family as i32 } { + #[cfg(linux_android)] + libc::AF_ALG => unsafe { AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) - } + }, #[cfg(feature = "net")] - libc::AF_INET => { + libc::AF_INET => unsafe { SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) - } + }, #[cfg(feature = "net")] - libc::AF_INET6 => { + libc::AF_INET6 => unsafe { SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 }) - } - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" - ))] + }, + #[cfg(any(bsd, solarish, target_os = "haiku"))] #[cfg(feature = "net")] - libc::AF_LINK => { + libc::AF_LINK => unsafe { LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => { + }, + #[cfg(linux_android)] + libc::AF_NETLINK => unsafe { NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) - } - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] + }, + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] - libc::AF_PACKET => { + libc::AF_PACKET => unsafe { LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - libc::AF_SYSTEM => { + }, + #[cfg(all(feature = "ioctl", apple_targets))] + libc::AF_SYSTEM => unsafe { SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) - } - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] - libc::AF_VSOCK => { + }, + #[cfg(any(linux_android, apple_targets))] + libc::AF_VSOCK => unsafe { VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) - } + }, _ => None, } } } - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] + #[cfg(any(linux_android, target_os = "fuchsia", solarish))] fn len(&self) -> libc::socklen_t { match self.as_unix_addr() { // The UnixAddr type knows its own length @@ -1409,11 +1193,12 @@ impl SockaddrLike for SockaddrStorage { } } - unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + unsafe fn set_length( + &mut self, + new_length: usize, + ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { match self.as_unix_addr_mut() { - Some(addr) => { - addr.set_length(new_length) - }, + Some(addr) => unsafe { addr.set_length(new_length) }, None => Err(SocketAddressLengthNotDynamic), } } @@ -1457,10 +1242,9 @@ impl SockaddrStorage { /// Downcast to an immutable `[UnixAddr]` reference. pub fn as_unix_addr(&self) -> Option<&UnixAddr> { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, ))] { let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; @@ -1487,10 +1271,9 @@ impl SockaddrStorage { /// Downcast to a mutable `[UnixAddr]` reference. pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, ))] { let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; @@ -1514,29 +1297,17 @@ impl SockaddrStorage { } } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, AddressFamily::Alg, libc::sockaddr_alg, alg} - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] accessors! { as_link_addr, as_link_addr_mut, LinkAddr, AddressFamily::Packet, libc::sockaddr_ll, dl} - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] + #[cfg(any(bsd, solarish))] #[cfg(feature = "net")] accessors! { as_link_addr, as_link_addr_mut, LinkAddr, @@ -1552,17 +1323,16 @@ impl SockaddrStorage { as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, AddressFamily::Inet6, libc::sockaddr_in6, sin6} - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, AddressFamily::Netlink, libc::sockaddr_nl, nl} - #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg(all(feature = "ioctl", apple_targets))] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, AddressFamily::System, libc::sockaddr_ctl, sctl} - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets))] accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, AddressFamily::Vsock, libc::sockaddr_vm, vsock} } @@ -1581,37 +1351,25 @@ impl fmt::Display for SockaddrStorage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { match self.ss.ss_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_ALG => self.alg.fmt(f), #[cfg(feature = "net")] libc::AF_INET => self.sin.fmt(f), #[cfg(feature = "net")] libc::AF_INET6 => self.sin6.fmt(f), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] + #[cfg(any(bsd, solarish))] #[cfg(feature = "net")] libc::AF_LINK => self.dl.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_NETLINK => self.nl.fmt(f), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] libc::AF_PACKET => self.dl.fmt(f), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[cfg(feature = "ioctl")] libc::AF_SYSTEM => self.sctl.fmt(f), libc::AF_UNIX => self.su.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] libc::AF_VSOCK => self.vsock.fmt(f), _ => "

    ".fmt(f), } @@ -1655,37 +1413,25 @@ impl Hash for SockaddrStorage { fn hash(&self, s: &mut H) { unsafe { match self.ss.ss_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_ALG => self.alg.hash(s), #[cfg(feature = "net")] libc::AF_INET => self.sin.hash(s), #[cfg(feature = "net")] libc::AF_INET6 => self.sin6.hash(s), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] + #[cfg(any(bsd, solarish))] #[cfg(feature = "net")] libc::AF_LINK => self.dl.hash(s), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_NETLINK => self.nl.hash(s), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] libc::AF_PACKET => self.dl.hash(s), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[cfg(feature = "ioctl")] libc::AF_SYSTEM => self.sctl.hash(s), libc::AF_UNIX => self.su.hash(s), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] libc::AF_VSOCK => self.vsock.hash(s), _ => self.ss.hash(s), } @@ -1697,37 +1443,25 @@ impl PartialEq for SockaddrStorage { fn eq(&self, other: &Self) -> bool { unsafe { match (self.ss.ss_family as i32, other.ss.ss_family as i32) { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, #[cfg(feature = "net")] (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, #[cfg(feature = "net")] (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] + #[cfg(any(bsd, solarish))] #[cfg(feature = "net")] (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[cfg(feature = "ioctl")] (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, _ => false, } @@ -1751,8 +1485,7 @@ pub(super) mod private { } } -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] pub mod netlink { use super::*; use crate::sys::socket::addr::AddressFamily; @@ -1805,10 +1538,10 @@ pub mod netlink { return None; } } - if (*addr).sa_family as i32 != libc::AF_NETLINK { + if unsafe { (*addr).sa_family as i32 != libc::AF_NETLINK } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1825,11 +1558,10 @@ pub mod netlink { } } -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] pub mod alg { use super::*; - use libc::{c_char, sockaddr_alg, AF_ALG}; + use libc::{sockaddr_alg, AF_ALG}; use std::ffi::CStr; use std::hash::{Hash, Hasher}; use std::{fmt, mem, str}; @@ -1854,10 +1586,10 @@ pub mod alg { return None; } } - if (*addr).sa_family as i32 != libc::AF_ALG { + if unsafe { (*addr).sa_family as i32 != libc::AF_ALG } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1918,16 +1650,12 @@ pub mod alg { /// Return the socket's cipher type, for example `hash` or `aead`. pub fn alg_type(&self) -> &CStr { - unsafe { - CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) - } + unsafe { CStr::from_ptr(self.0.salg_type.as_ptr().cast()) } } /// Return the socket's cipher name, for example `sha1`. pub fn alg_name(&self) -> &CStr { - unsafe { - CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) - } + unsafe { CStr::from_ptr(self.0.salg_name.as_ptr().cast()) } } } @@ -1951,7 +1679,7 @@ pub mod alg { feature! { #![feature = "ioctl"] -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] pub mod sys_control { use crate::sys::socket::addr::AddressFamily; use libc::{self, c_uchar}; @@ -1994,10 +1722,10 @@ pub mod sys_control { return None; } } - if (*addr).sa_family as i32 != libc::AF_SYSTEM { + if unsafe { (*addr).sa_family as i32 != libc::AF_SYSTEM } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) } )) } } @@ -2058,8 +1786,7 @@ pub mod sys_control { } } -#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(linux_android, target_os = "fuchsia"))] mod datalink { feature! { #![feature = "net"] @@ -2136,10 +1863,10 @@ mod datalink { return None; } } - if (*addr).sa_family as i32 != libc::AF_PACKET { + if unsafe { (*addr).sa_family as i32 != libc::AF_PACKET } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -2152,18 +1879,7 @@ mod datalink { } } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "aix", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(bsd, solarish, target_os = "haiku", target_os = "aix"))] mod datalink { feature! { #![feature = "net"] @@ -2261,10 +1977,10 @@ mod datalink { return None; } } - if (*addr).sa_family as i32 != libc::AF_LINK { + if unsafe { (*addr).sa_family as i32 != libc::AF_LINK } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -2276,8 +1992,7 @@ mod datalink { } } -#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(linux_android, apple_targets))] pub mod vsock { use super::*; use crate::sys::socket::addr::AddressFamily; @@ -2308,10 +2023,10 @@ pub mod vsock { return None; } } - if (*addr).sa_family as i32 != libc::AF_VSOCK { + if unsafe { (*addr).sa_family as i32 != libc::AF_VSOCK } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + unsafe { Some(Self(ptr::read_unaligned(addr as *const _))) } } } @@ -2322,32 +2037,47 @@ pub mod vsock { } impl PartialEq for VsockAddr { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); (inner.svm_family, inner.svm_cid, inner.svm_port) == (other.svm_family, other.svm_cid, other.svm_port) } - #[cfg(target_os = "macos")] + #[cfg(apple_targets)] fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); - (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len) - == (other.svm_family, other.svm_cid, other.svm_port, inner.svm_len) + ( + inner.svm_family, + inner.svm_cid, + inner.svm_port, + inner.svm_len, + ) == ( + other.svm_family, + other.svm_cid, + other.svm_port, + inner.svm_len, + ) } } impl Eq for VsockAddr {} impl Hash for VsockAddr { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] fn hash(&self, s: &mut H) { let inner = self.0; (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); } - #[cfg(target_os = "macos")] + #[cfg(apple_targets)] fn hash(&self, s: &mut H) { let inner = self.0; - (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len).hash(s); + ( + inner.svm_family, + inner.svm_cid, + inner.svm_port, + inner.svm_len, + ) + .hash(s); } } @@ -2363,9 +2093,9 @@ pub mod vsock { addr.svm_cid = cid; addr.svm_port = port; - #[cfg(target_os = "macos")] + #[cfg(apple_targets)] { - addr.svm_len = std::mem::size_of::() as u8; + addr.svm_len = std::mem::size_of::() as u8; } VsockAddr(addr) } @@ -2419,27 +2149,16 @@ mod tests { } } - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "hurd", target_os = "redox")))] mod link { #![allow(clippy::cast_ptr_alignment)] - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "illumos" - ))] + #[cfg(any(apple_targets, solarish))] use super::super::super::socklen_t; use super::*; /// Don't panic when trying to display an empty datalink address - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] + #[cfg(bsd)] #[test] fn test_datalink_display() { use super::super::LinkAddr; @@ -2459,11 +2178,7 @@ mod tests { } #[cfg(all( - any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ), + any(linux_android, target_os = "fuchsia"), target_endian = "little" ))] #[test] @@ -2474,7 +2189,7 @@ mod tests { let bytes = Raw([ 17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0, ]); - let sa = bytes.0.as_ptr() as *const libc::sockaddr; + let sa = bytes.0.as_ptr().cast(); let len = None; let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); @@ -2485,12 +2200,12 @@ mod tests { } } - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[test] fn macos_loopback() { let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; - let sa = bytes.as_ptr() as *const libc::sockaddr; + let sa = bytes.as_ptr().cast(); let len = Some(bytes.len() as socklen_t); let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); @@ -2503,7 +2218,7 @@ mod tests { } } - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[test] fn macos_tap() { let bytes = [ @@ -2525,9 +2240,9 @@ mod tests { } } - #[cfg(target_os = "illumos")] + #[cfg(solarish)] #[test] - fn illumos_tap() { + fn solarish_tap() { let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; let ptr = bytes.as_ptr(); let sa = ptr as *const libc::sockaddr; @@ -2548,23 +2263,9 @@ mod tests { #[test] fn size() { - #[cfg(any( - target_os = "aix", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd", - target_os = "haiku" - ))] + #[cfg(any(bsd, target_os = "aix", solarish, target_os = "haiku"))] let l = mem::size_of::(); - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] let l = mem::size_of::(); assert_eq!(LinkAddr::size() as usize, l); } @@ -2588,6 +2289,13 @@ mod tests { SockaddrIn::size() as usize ); } + + #[test] + fn ip() { + let s = "127.0.0.1:8082"; + let ip = SockaddrIn::from_str(s).unwrap().ip(); + assert_eq!("127.0.0.1", format!("{ip}")); + } } mod sockaddr_in6 { @@ -2609,6 +2317,13 @@ mod tests { ); } + #[test] + fn ip() { + let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; + let ip = SockaddrIn6::from_str(s).unwrap().ip(); + assert_eq!("1234:5678:90ab:cdef::1111:2222", format!("{ip}")); + } + #[test] // Ensure that we can convert to-and-from std::net variants without change. fn to_and_from() { @@ -2628,28 +2343,28 @@ mod tests { #[test] fn from_sockaddr_un_named() { let ua = UnixAddr::new("/var/run/mysock").unwrap(); - let ptr = ua.as_ptr() as *const libc::sockaddr; + let ptr = ua.as_ptr().cast(); let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } .unwrap(); assert_eq!(ss.len(), ua.len()); } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[test] fn from_sockaddr_un_abstract_named() { let name = String::from("nix\0abstract\0test"); let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let ptr = ua.as_ptr() as *const libc::sockaddr; + let ptr = ua.as_ptr().cast(); let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } .unwrap(); assert_eq!(ss.len(), ua.len()); } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[test] fn from_sockaddr_un_abstract_unnamed() { let ua = UnixAddr::new_unnamed(); - let ptr = ua.as_ptr() as *const libc::sockaddr; + let ptr = ua.as_ptr().cast(); let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } .unwrap(); assert_eq!(ss.len(), ua.len()); @@ -2659,7 +2374,7 @@ mod tests { mod unixaddr { use super::*; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[test] fn abstract_sun_path() { let name = String::from("nix\0abstract\0test"); diff --git a/third_party/rust/nix/src/sys/socket/mod.rs b/third_party/rust/nix/src/sys/socket/mod.rs index 78dd617c55..3d1651bd3f 100644 --- a/third_party/rust/nix/src/sys/socket/mod.rs +++ b/third_party/rust/nix/src/sys/socket/mod.rs @@ -1,7 +1,7 @@ //! Socket interface functions //! //! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "freebsd", linux_android))] #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; #[cfg(not(target_os = "redox"))] @@ -9,16 +9,16 @@ use crate::sys::time::TimeSpec; use crate::sys::time::TimeVal; use crate::{errno::Errno, Result}; use cfg_if::cfg_if; -use libc::{self, c_int, c_void, size_t, socklen_t}; +use libc::{self, c_int, size_t, socklen_t}; #[cfg(all(feature = "uio", not(target_os = "redox")))] use libc::{ - iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE, + c_void, iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE, }; #[cfg(not(target_os = "redox"))] use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; -use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, RawFd, OwnedFd}; +use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd}; use std::{mem, ptr}; #[deny(missing_docs)] @@ -34,35 +34,25 @@ pub mod sockopt; pub use self::addr::{SockaddrLike, SockaddrStorage}; -#[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[cfg(solarish)] pub use self::addr::{AddressFamily, UnixAddr}; -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[cfg(not(solarish))] pub use self::addr::{AddressFamily, UnixAddr}; -#[cfg(not(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku", - target_os = "redox", -)))] +#[cfg(not(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox")))] #[cfg(feature = "net")] pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6}; -#[cfg(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku", - target_os = "redox", -))] +#[cfg(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox"))] #[cfg(feature = "net")] pub use self::addr::{SockaddrIn, SockaddrIn6}; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] #[cfg(feature = "ioctl")] pub use crate::sys::socket::addr::sys_control::SysControlAddr; -#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] +#[cfg(any(linux_android, apple_targets))] pub use crate::sys::socket::addr::vsock::VsockAddr; #[cfg(all(feature = "uio", not(target_os = "redox")))] @@ -132,121 +122,108 @@ pub enum SockProtocol { Udp = libc::IPPROTO_UDP, /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html)) Raw = libc::IPPROTO_RAW, - /// Allows applications and other KEXTs to be notified when certain kernel events occur - /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - KextEvent = libc::SYSPROTO_EVENT, /// Allows applications to configure and control a KEXT /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] KextControl = libc::SYSPROTO_CONTROL, /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkRoute = libc::NETLINK_ROUTE, /// Reserved for user-mode socket protocols /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkUserSock = libc::NETLINK_USERSOCK, /// Query information about sockets of various protocol families from the kernel /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, /// Netfilter/iptables ULOG. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkNFLOG = libc::NETLINK_NFLOG, /// SELinux event notifications. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkSELinux = libc::NETLINK_SELINUX, /// Open-iSCSI /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkISCSI = libc::NETLINK_ISCSI, /// Auditing /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkAudit = libc::NETLINK_AUDIT, /// Access to FIB lookup from user space /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP, /// Netfilter subsystem /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkNetFilter = libc::NETLINK_NETFILTER, /// SCSI Transports /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT, /// Infiniband RDMA /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkRDMA = libc::NETLINK_RDMA, /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkIPv6Firewall = libc::NETLINK_IP6_FW, /// DECnet routing messages /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG, /// Kernel messages to user space /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, /// Generic netlink family for simplified netlink usage. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkGeneric = libc::NETLINK_GENERIC, /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow /// configuration of the kernel crypto API. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] NetlinkCrypto = libc::NETLINK_CRYPTO, /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols /// defined in the interface to be received. /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html)) // The protocol number is fed into the socket syscall in network byte order. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] EthAll = (libc::ETH_P_ALL as u16).to_be() as i32, + /// ICMP protocol ([icmp(7)](https://man7.org/linux/man-pages/man7/icmp.7.html)) + Icmp = libc::IPPROTO_ICMP, + /// ICMPv6 protocol (ICMP over IPv6) + IcmpV6 = libc::IPPROTO_ICMPV6, +} + +impl SockProtocol { /// The Controller Area Network raw socket protocol /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan)) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - CanRaw = libc::CAN_RAW, -} + #[allow(non_upper_case_globals)] + pub const CanRaw: SockProtocol = SockProtocol::Icmp; // Matches libc::CAN_RAW -impl SockProtocol { /// The Controller Area Network broadcast manager protocol /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan)) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] #[allow(non_upper_case_globals)] pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM + + /// Allows applications and other KEXTs to be notified when certain kernel events occur + /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) + #[cfg(apple_targets)] + #[allow(non_upper_case_globals)] + pub const KextEvent: SockProtocol = SockProtocol::Icmp; // Matches libc::SYSPROTO_EVENT } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] libc_bitflags! { /// Configuration flags for `SO_TIMESTAMPING` interface /// @@ -276,33 +253,23 @@ libc_bitflags! { /// Additional socket options pub struct SockFlag: c_int { /// Set non-blocking mode on the new socket - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, + freebsdlike, + netbsdlike, + solarish))] SOCK_NONBLOCK; /// Set close-on-exec on the new descriptor - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, + freebsdlike, + netbsdlike, + solarish))] SOCK_CLOEXEC; /// Return `EPIPE` instead of raising `SIGPIPE` #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] SOCK_NOSIGPIPE; /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` /// to the DNS port (typically 53) #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] SOCK_DNS; } } @@ -333,7 +300,6 @@ libc_bitflags! { /// the calling process and as well as other processes that hold /// file descriptors referring to the same open file description. #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] MSG_DONTWAIT; /// Receive flags: Control Data was discarded (buffer too small) MSG_CTRUNC; @@ -352,8 +318,7 @@ libc_bitflags! { /// This flag specifies that queued errors should be received from /// the socket error queue. (For more details, see /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MSG_ERRQUEUE; /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain /// file descriptor using the `SCM_RIGHTS` operation (described in @@ -362,44 +327,48 @@ libc_bitflags! { /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). /// /// Only used in [`recvmsg`](fn.recvmsg.html) function. - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, freebsdlike, netbsdlike))] MSG_CMSG_CLOEXEC; /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", + #[cfg(any(linux_android, + freebsdlike, + solarish, + netbsdlike, target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + target_os = "haiku"))] MSG_NOSIGNAL; /// Turns on [`MSG_DONTWAIT`] after the first message has been received (only for /// `recvmmsg()`). - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + netbsdlike, target_os = "fuchsia", - target_os = "linux", - target_os = "netbsd", - target_os = "freebsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + target_os = "freebsd"))] MSG_WAITFORONE; } } +#[cfg(target_os = "freebsd")] +libc_enum! { + /// A selector for which clock to use when generating packet timestamps. + /// Used when setting [`TsClock`](crate::sys::socket::sockopt::TsClock) on a socket. + /// (For more details, see [setsockopt(2)](https://man.freebsd.org/cgi/man.cgi?setsockopt)). + #[repr(i32)] + #[non_exhaustive] + pub enum SocketTimestamp { + /// Microsecond resolution, realtime. This is the default. + SO_TS_REALTIME_MICRO, + /// Sub-nanosecond resolution, realtime. + SO_TS_BINTIME, + /// Nanosecond resolution, realtime. + SO_TS_REALTIME, + /// Nanosecond resolution, monotonic. + SO_TS_MONOTONIC, + } +} + cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { /// Unix credentials of the sending process. /// /// This struct is used with the `SO_PEERCRED` ancillary message @@ -454,7 +423,7 @@ cfg_if! { uc.0 } } - } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { + } else if #[cfg(freebsdlike)] { /// Unix credentials of the sending process. /// /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets. @@ -487,7 +456,7 @@ cfg_if! { pub fn groups(&self) -> &[libc::gid_t] { unsafe { std::slice::from_raw_parts( - self.0.cmcred_groups.as_ptr() as *const libc::gid_t, + self.0.cmcred_groups.as_ptr(), self.0.cmcred_ngroups as _ ) } @@ -503,12 +472,7 @@ cfg_if! { } cfg_if! { - if #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" - ))] { + if #[cfg(any(freebsdlike, apple_targets))] { /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -603,8 +567,6 @@ feature! { /// let _ = cmsg_space!(RawFd, TimeVal); /// # } /// ``` -// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a -// stack-allocated array. #[macro_export] macro_rules! cmsg_space { ( $( $x:ty ),* ) => { @@ -617,7 +579,7 @@ macro_rules! cmsg_space { #[inline] #[doc(hidden)] -pub fn cmsg_space() -> usize { +pub const fn cmsg_space() -> usize { // SAFETY: CMSG_SPACE is always safe unsafe { libc::CMSG_SPACE(mem::size_of::() as libc::c_uint) as usize } } @@ -677,7 +639,7 @@ impl<'a> Iterator for CmsgIterator<'a> { } /// A type-safe wrapper around a single control message, as used with -/// [`recvmsg`](#fn.recvmsg). +/// [`recvmsg`]. /// /// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) // Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and @@ -692,12 +654,10 @@ pub enum ControlMessageOwned { /// Received version of [`ControlMessage::ScmRights`] ScmRights(Vec), /// Received version of [`ControlMessage::ScmCredentials`] - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ScmCredentials(UnixCredentials), /// Received version of [`ControlMessage::ScmCreds`] - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] ScmCreds(UnixCredentials), /// A message of type `SCM_TIMESTAMP`, containing the time the /// packet was received by the kernel. @@ -760,62 +720,44 @@ pub enum ControlMessageOwned { /// A set of nanosecond resolution timestamps /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ScmTimestampsns(Timestamps), /// Nanoseconds resolution timestamp /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ScmTimestampns(TimeSpec), - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - ))] + /// Realtime clock timestamp + /// + /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt) + #[cfg(target_os = "freebsd")] + ScmRealtime(TimeSpec), + /// Monotonic clock timestamp + /// + /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt) + #[cfg(target_os = "freebsd")] + ScmMonotonic(TimeSpec), + #[cfg(any(linux_android, apple_targets, target_os = "netbsd"))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4PacketInfo(libc::in_pktinfo), - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, bsd))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6PacketInfo(libc::in6_pktinfo), - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(bsd)] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4RecvIf(libc::sockaddr_dl), - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(bsd)] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4RecvDstAddr(libc::in_addr), - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4OrigDstAddr(libc::sockaddr_in), - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6OrigDstAddr(libc::sockaddr_in6), @@ -841,28 +783,31 @@ pub enum ControlMessageOwned { /// /// `RxqOvfl` socket option should be enabled on a socket /// to allow receiving the drop counter. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] RxqOvfl(u32), /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4RecvErr(libc::sock_extended_err, Option), /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6RecvErr(libc::sock_extended_err, Option), + /// `SOL_TLS` messages of type `TLS_GET_RECORD_TYPE` + #[cfg(any(target_os = "linux"))] + TlsGetRecordType(TlsGetRecordType), + /// Catch-all variant for unimplemented cmsg types. #[doc(hidden)] Unknown(UnknownCmsg), } /// For representing packet timestamps via `SO_TIMESTAMPING` interface -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Timestamps { /// software based timestamp, usually one containing data @@ -873,6 +818,33 @@ pub struct Timestamps { pub hw_raw: TimeSpec, } +/// These constants correspond to TLS 1.2 message types, as defined in +/// RFC 5246, Appendix A.1 +#[cfg(any(target_os = "linux"))] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(u8)] +#[non_exhaustive] +pub enum TlsGetRecordType { + ChangeCipherSpec , + Alert, + Handshake, + ApplicationData, + Unknown(u8), +} + +#[cfg(any(target_os = "linux"))] +impl From for TlsGetRecordType { + fn from(x: u8) -> Self { + match x { + 20 => TlsGetRecordType::ChangeCipherSpec, + 21 => TlsGetRecordType::Alert, + 22 => TlsGetRecordType::Handshake, + 23 => TlsGetRecordType::ApplicationData, + _ => TlsGetRecordType::Unknown(x), + } + } +} + impl ControlMessageOwned { /// Decodes a `ControlMessageOwned` from raw bytes. /// @@ -885,7 +857,7 @@ impl ControlMessageOwned { #[allow(clippy::cast_ptr_alignment)] unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned { - let p = CMSG_DATA(header); + let p = unsafe { CMSG_DATA(header) }; // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] let len = header as *const _ as usize + header.cmsg_len as usize @@ -895,158 +867,151 @@ impl ControlMessageOwned { let n = len / mem::size_of::(); let mut fds = Vec::with_capacity(n); for i in 0..n { - let fdp = (p as *const RawFd).add(i); - fds.push(ptr::read_unaligned(fdp)); + unsafe { + let fdp = (p as *const RawFd).add(i); + fds.push(ptr::read_unaligned(fdp)); + } } ControlMessageOwned::ScmRights(fds) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { - let cred: libc::ucred = ptr::read_unaligned(p as *const _); + let cred: libc::ucred = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmCredentials(cred.into()) } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] (libc::SOL_SOCKET, libc::SCM_CREDS) => { - let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); + let cred: libc::cmsgcred = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmCreds(cred.into()) } #[cfg(not(any(target_os = "aix", target_os = "haiku")))] (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { - let tv: libc::timeval = ptr::read_unaligned(p as *const _); + let tv: libc::timeval = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { - let ts: libc::timespec = ptr::read_unaligned(p as *const _); + let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(target_os = "freebsd")] + (libc::SOL_SOCKET, libc::SCM_REALTIME) => { + let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) }; + ControlMessageOwned::ScmRealtime(TimeSpec::from(ts)) + } + #[cfg(target_os = "freebsd")] + (libc::SOL_SOCKET, libc::SCM_MONOTONIC) => { + let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) }; + ControlMessageOwned::ScmMonotonic(TimeSpec::from(ts)) + } + #[cfg(linux_android)] (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { let tp = p as *const libc::timespec; - let ts: libc::timespec = ptr::read_unaligned(tp); + let ts: libc::timespec = unsafe { ptr::read_unaligned(tp) }; let system = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(1)); + let ts: libc::timespec = unsafe { ptr::read_unaligned(tp.add(1)) }; let hw_trans = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(2)); + let ts: libc::timespec = unsafe { ptr::read_unaligned(tp.add(2)) }; let hw_raw = TimeSpec::from(ts); let timestamping = Timestamps { system, hw_trans, hw_raw }; ControlMessageOwned::ScmTimestampsns(timestamping) } - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" - ))] + #[cfg(any(target_os = "freebsd", linux_android, apple_targets))] #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); + let info = unsafe { ptr::read_unaligned(p as *const libc::in6_pktinfo) }; ControlMessageOwned::Ipv6PacketInfo(info) } - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, apple_targets, target_os = "netbsd"))] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in_pktinfo); + let info = unsafe { ptr::read_unaligned(p as *const libc::in_pktinfo) }; ControlMessageOwned::Ipv4PacketInfo(info) } - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(bsd)] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVIF) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); + let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_dl) }; ControlMessageOwned::Ipv4RecvIf(dl) }, - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(bsd)] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::in_addr); + let dl = unsafe { ptr::read_unaligned(p as *const libc::in_addr) }; ControlMessageOwned::Ipv4RecvDstAddr(dl) }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); + let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_in) }; ControlMessageOwned::Ipv4OrigDstAddr(dl) }, #[cfg(target_os = "linux")] #[cfg(feature = "net")] (libc::SOL_UDP, libc::UDP_GRO) => { - let gso_size: u16 = ptr::read_unaligned(p as *const _); + let gso_size: u16 = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::UdpGroSegments(gso_size) }, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "fuchsia"))] (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { - let drop_counter = ptr::read_unaligned(p as *const u32); + let drop_counter = unsafe { ptr::read_unaligned(p as *const u32) }; ControlMessageOwned::RxqOvfl(drop_counter) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVERR) => { - let (err, addr) = Self::recv_err_helper::(p, len); + let (err, addr) = unsafe { Self::recv_err_helper::(p, len) }; ControlMessageOwned::Ipv4RecvErr(err, addr) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { - let (err, addr) = Self::recv_err_helper::(p, len); + let (err, addr) = unsafe { Self::recv_err_helper::(p, len) }; ControlMessageOwned::Ipv6RecvErr(err, addr) }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); + let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_in6) }; ControlMessageOwned::Ipv6OrigDstAddr(dl) }, + #[cfg(any(target_os = "linux"))] + (libc::SOL_TLS, libc::TLS_GET_RECORD_TYPE) => { + let content_type = unsafe { ptr::read_unaligned(p as *const u8) }; + ControlMessageOwned::TlsGetRecordType(content_type.into()) + }, (_, _) => { - let sl = std::slice::from_raw_parts(p, len); + let sl = unsafe { std::slice::from_raw_parts(p, len) }; let ucmsg = UnknownCmsg(*header, Vec::::from(sl)); ControlMessageOwned::Unknown(ucmsg) } } } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[cfg(feature = "net")] #[allow(clippy::cast_ptr_alignment)] // False positive unsafe fn recv_err_helper(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option) { let ee = p as *const libc::sock_extended_err; - let err = ptr::read_unaligned(ee); + let err = unsafe { ptr::read_unaligned(ee) }; // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len] // CMSG_DATA buffer. For local errors, there is no address included in the control // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to // validate that the address object is in-bounds before we attempt to copy it. - let addrp = libc::SO_EE_OFFENDER(ee) as *const T; + let addrp = unsafe { libc::SO_EE_OFFENDER(ee) as *const T }; - if addrp.offset(1) as usize - (p as usize) > len { + if unsafe { addrp.offset(1) } as usize - (p as usize) > len { (err, None) } else { - (err, Some(ptr::read_unaligned(addrp))) + (err, Some(unsafe { ptr::read_unaligned(addrp) })) } } } -/// A type-safe zero-copy wrapper around a single control message, as used wih -/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not -/// exhaustively pattern-match it. +/// A type-safe zero-copy wrapper around a single control message, as used with +/// [`sendmsg`]. More types may be added to this enum; do not exhaustively +/// pattern-match it. /// /// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -1074,8 +1039,7 @@ pub enum ControlMessage<'a> { /// /// For further information, please refer to the /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ScmCredentials(&'a UnixCredentials), /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of /// a process connected to the socket. @@ -1089,41 +1053,28 @@ pub enum ControlMessage<'a> { /// /// For further information, please refer to the /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] ScmCreds, /// Set IV for `AF_ALG` crypto API. /// /// For further information, please refer to the /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] AlgSetIv(&'a [u8]), /// Set crypto operation for `AF_ALG` crypto API. It may be one of /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` /// /// For further information, please refer to the /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] AlgSetOp(&'a libc::c_int), /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) /// for `AF_ALG` crypto API. /// /// For further information, please refer to the /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] AlgSetAeadAssoclen(&'a u32), /// UDP GSO makes it possible for applications to generate network packets @@ -1139,51 +1090,52 @@ pub enum ControlMessage<'a> { #[cfg_attr(docsrs, doc(cfg(feature = "net")))] UdpGsoSegments(&'a u16), - /// Configure the sending addressing and interface for v4 + /// Configure the sending addressing and interface for v4. /// /// For further information, please refer to the /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page. - #[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "android", - target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", apple_targets))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4PacketInfo(&'a libc::in_pktinfo), - /// Configure the sending addressing and interface for v6 + /// Configure the sending addressing and interface for v6. /// /// For further information, please refer to the /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. - #[cfg(any(target_os = "linux", - target_os = "macos", + #[cfg(any(linux_android, target_os = "netbsd", target_os = "freebsd", - target_os = "android", - target_os = "ios",))] + apple_targets))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6PacketInfo(&'a libc::in6_pktinfo), /// Configure the IPv4 source address with `IP_SENDSRCADDR`. - #[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - ))] + #[cfg(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4SendSrcAddr(&'a libc::in_addr), + /// Configure the hop limit for v6 multicast traffic. + /// + /// Set the IPv6 hop limit for this message. The argument is an integer + /// between 0 and 255. A value of -1 will set the hop limit to the route + /// default if possible on the interface. Without this cmsg, packets sent + /// with sendmsg have a hop limit of 1 and will not leave the local network. + /// For further information, please refer to the + /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv6HopLimit(&'a libc::c_int), + /// SO_RXQ_OVFL indicates that an unsigned 32 bit value /// ancilliary msg (cmsg) should be attached to recieved /// skbs indicating the number of packets dropped by the /// socket between the last recieved packet and this /// received packet. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] RxqOvfl(&'a u32), /// Configure the transmission time of packets. @@ -1227,18 +1179,18 @@ impl<'a> ControlMessage<'a> { ControlMessage::ScmRights(fds) => { fds as *const _ as *const u8 }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(creds) => { &creds.0 as *const libc::ucred as *const u8 } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessage::ScmCreds => { // The kernel overwrites the data, we just zero it // to make sure it's not uninitialized memory unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) }; return } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetIv(iv) => { #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 let af_alg_iv = libc::af_alg_iv { @@ -1263,11 +1215,11 @@ impl<'a> ControlMessage<'a> { return }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetOp(op) => { op as *const _ as *const u8 }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetAeadAssoclen(len) => { len as *const _ as *const u8 }, @@ -1276,21 +1228,20 @@ impl<'a> ControlMessage<'a> { ControlMessage::UdpGsoSegments(gso_size) => { gso_size as *const _ as *const u8 }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(limit) => limit as *const _ as *const u8, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(drop_count) => { drop_count as *const _ as *const u8 }, @@ -1314,23 +1265,23 @@ impl<'a> ControlMessage<'a> { ControlMessage::ScmRights(fds) => { mem::size_of_val(fds) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(creds) => { mem::size_of_val(creds) } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessage::ScmCreds => { mem::size_of::() } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetIv(iv) => { mem::size_of::<&[u8]>() + iv.len() }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetOp(op) => { mem::size_of_val(op) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetAeadAssoclen(len) => { mem::size_of_val(len) }, @@ -1339,21 +1290,22 @@ impl<'a> ControlMessage<'a> { ControlMessage::UdpGsoSegments(gso_size) => { mem::size_of_val(gso_size) }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info), - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr), - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(limit) => { + mem::size_of_val(limit) + }, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(drop_count) => { mem::size_of_val(drop_count) }, @@ -1368,31 +1320,30 @@ impl<'a> ControlMessage<'a> { fn cmsg_level(&self) -> libc::c_int { match *self { ControlMessage::ScmRights(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessage::ScmCreds => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) | ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, #[cfg(target_os = "linux")] #[cfg(feature = "net")] ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(_) => libc::IPPROTO_IPV6, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, #[cfg(target_os = "linux")] ControlMessage::TxTime(_) => libc::SOL_SOCKET, @@ -1403,19 +1354,19 @@ impl<'a> ControlMessage<'a> { fn cmsg_type(&self) -> libc::c_int { match *self { ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessage::ScmCreds => libc::SCM_CREDS, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetIv(_) => { libc::ALG_SET_IV }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetOp(_) => { libc::ALG_SET_OP }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetAeadAssoclen(_) => { libc::ALG_SET_AEAD_ASSOCLEN }, @@ -1424,21 +1375,20 @@ impl<'a> ControlMessage<'a> { ControlMessage::UdpGsoSegments(_) => { libc::UDP_SEGMENT }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(_) => libc::IPV6_HOPLIMIT, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(_) => { libc::SO_RXQ_OVFL }, @@ -1452,10 +1402,12 @@ impl<'a> ControlMessage<'a> { // Unsafe: cmsg must point to a valid cmsghdr with enough space to // encode self. unsafe fn encode_into(&self, cmsg: *mut cmsghdr) { - (*cmsg).cmsg_level = self.cmsg_level(); - (*cmsg).cmsg_type = self.cmsg_type(); - (*cmsg).cmsg_len = self.cmsg_len(); - self.copy_to_cmsg_data(CMSG_DATA(cmsg)); + unsafe { + (*cmsg).cmsg_level = self.cmsg_level(); + (*cmsg).cmsg_type = self.cmsg_type(); + (*cmsg).cmsg_len = self.cmsg_len(); + self.copy_to_cmsg_data( CMSG_DATA(cmsg) ); + } } } @@ -1479,7 +1431,7 @@ impl<'a> ControlMessage<'a> { /// let (r, w) = pipe().unwrap(); /// /// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; +/// let fds = [r.as_raw_fd()]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg::<()>(fd1.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); /// ``` @@ -1496,7 +1448,7 @@ impl<'a> ControlMessage<'a> { /// let (r, w) = pipe().unwrap(); /// /// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; +/// let fds = [r.as_raw_fd()]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg(fd.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); /// ``` @@ -1535,12 +1487,7 @@ pub fn sendmsg(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], /// /// # References /// [`sendmsg`](fn.sendmsg.html) -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] pub fn sendmmsg<'a, XS, AS, C, I, S>( fd: RawFd, data: &'a mut MultiHeaders, @@ -1556,7 +1503,7 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( AS: AsRef<[Option]>, I: AsRef<[IoSlice<'a>]> + 'a, C: AsRef<[ControlMessage<'a>]> + 'a, - S: SockaddrLike + 'a + S: SockaddrLike + 'a, { let mut count = 0; @@ -1564,11 +1511,11 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { let p = &mut mmsghdr.msg_hdr; - p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; + p.msg_iov = slice.as_ref().as_ptr().cast_mut().cast(); p.msg_iovlen = slice.as_ref().len() as _; p.msg_namelen = addr.as_ref().map_or(0, S::len); - p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _; + p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr).cast_mut().cast(); // Encode each cmsg. This must happen after initializing the header because // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. @@ -1583,9 +1530,16 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) }; } - count = i+1; + // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders` + // is through the `preallocate` function, which takes an `usize` as an argument to define its size, + // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in + // other words: `count` doesn't overflow + count = i + 1; } + // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the + // maximum number of messages that can be sent safely (i.e. `count` is the minimum of the sizes of `slices`, + // `data.items` and `addrs`) let sent = Errno::result(unsafe { libc::sendmmsg( fd, @@ -1604,12 +1558,7 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[derive(Debug)] /// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions pub struct MultiHeaders { @@ -1622,12 +1571,7 @@ pub struct MultiHeaders { msg_controllen: usize, } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] impl MultiHeaders { /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate /// @@ -1652,7 +1596,7 @@ impl MultiHeaders { .enumerate() .map(|(ix, address)| { let (ptr, cap) = match &mut cmsg_buffers { - Some(v) => ((&mut v[ix * msg_controllen] as *mut u8), msg_controllen), + Some(v) => (&mut v[ix * msg_controllen] as *mut u8, msg_controllen), None => (std::ptr::null_mut(), 0), }; let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null_mut(), 0, ptr, cap, address.as_mut_ptr()) }; @@ -1697,12 +1641,7 @@ impl MultiHeaders { // always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more // details -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] pub fn recvmmsg<'a, XS, S, I>( fd: RawFd, data: &'a mut MultiHeaders, @@ -1711,14 +1650,19 @@ pub fn recvmmsg<'a, XS, S, I>( mut timeout: Option, ) -> crate::Result> where - XS: IntoIterator, - I: AsRef<[IoSliceMut<'a>]> + 'a, + XS: IntoIterator, + I: AsMut<[IoSliceMut<'a>]> + 'a, { let mut count = 0; for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { let p = &mut mmsghdr.msg_hdr; - p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; - p.msg_iovlen = slice.as_ref().len() as _; + p.msg_iov = slice.as_mut().as_mut_ptr().cast(); + p.msg_iovlen = slice.as_mut().len() as _; + + // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders` + // is through the `preallocate` function, which takes an `usize` as an argument to define its size, + // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in + // other words: `count` doesn't overflow count = i + 1; } @@ -1726,6 +1670,8 @@ where .as_mut() .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); + // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the + // maximum number of messages that can be received safely (i.e. `count` is the minimum of the sizes of `slices` and `data.items`) let received = Errno::result(unsafe { libc::recvmmsg( fd, @@ -1743,16 +1689,9 @@ where }) } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -#[derive(Debug)] /// Iterator over results of [`recvmmsg`]/[`sendmmsg`] -/// -/// +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] +#[derive(Debug)] pub struct MultiResults<'a, S> { // preallocated structures rmm: &'a MultiHeaders, @@ -1760,12 +1699,7 @@ pub struct MultiResults<'a, S> { received: usize, } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] impl<'a, S> Iterator for MultiResults<'a, S> where S: Copy + SockaddrLike, @@ -1838,108 +1772,6 @@ impl<'a> Iterator for IoSliceIterator<'a> { } } -// test contains both recvmmsg and timestaping which is linux only -// there are existing tests for recvmmsg only in tests/ -#[cfg(target_os = "linux")] -#[cfg(test)] -mod test { - use crate::sys::socket::{AddressFamily, ControlMessageOwned}; - use crate::*; - use std::str::FromStr; - use std::os::unix::io::AsRawFd; - - #[cfg_attr(qemu, ignore)] - #[test] - fn test_recvmm2() -> crate::Result<()> { - use crate::sys::socket::{ - sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType, - SockaddrIn, TimestampingFlag, - }; - use std::io::{IoSlice, IoSliceMut}; - - let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); - - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - )?; - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::SOCK_NONBLOCK, - None, - )?; - - crate::sys::socket::bind(rsock.as_raw_fd(), &sock_addr)?; - - setsockopt(&rsock, Timestamping, &TimestampingFlag::all())?; - - let sbuf = (0..400).map(|i| i as u8).collect::>(); - - let mut recv_buf = vec![0; 1024]; - - let mut recv_iovs = Vec::new(); - let mut pkt_iovs = Vec::new(); - - for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { - pkt_iovs.push(IoSliceMut::new(chunk)); - if ix % 2 == 1 { - recv_iovs.push(pkt_iovs); - pkt_iovs = Vec::new(); - } - } - drop(pkt_iovs); - - let flags = MsgFlags::empty(); - let iov1 = [IoSlice::new(&sbuf)]; - - let cmsg = cmsg_space!(crate::sys::socket::Timestamps); - sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); - - let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); - - let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10)); - - let recv = super::recvmmsg(rsock.as_raw_fd(), &mut data, recv_iovs.iter(), flags, Some(t))?; - - for rmsg in recv { - #[cfg(not(any(qemu, target_arch = "aarch64")))] - let mut saw_time = false; - let mut recvd = 0; - for cmsg in rmsg.cmsgs() { - if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { - let ts = timestamps.system; - - let sys_time = - crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?; - let diff = if ts > sys_time { - ts - sys_time - } else { - sys_time - ts - }; - assert!(std::time::Duration::from(diff).as_secs() < 60); - #[cfg(not(any(qemu, target_arch = "aarch64")))] - { - saw_time = true; - } - } - } - - #[cfg(not(any(qemu, target_arch = "aarch64")))] - assert!(saw_time); - - for iov in rmsg.iovs() { - recvd += iov.len(); - } - assert_eq!(recvd, 400); - } - - Ok(()) - } -} unsafe fn read_mhdr<'a, 'i, S>( mhdr: msghdr, r: isize, @@ -1951,19 +1783,23 @@ unsafe fn read_mhdr<'a, 'i, S>( // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] let cmsghdr = { - if mhdr.msg_controllen > 0 { + let ptr = if mhdr.msg_controllen > 0 { debug_assert!(!mhdr.msg_control.is_null()); debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); - CMSG_FIRSTHDR(&mhdr as *const msghdr) + unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) } } else { ptr::null() - }.as_ref() + }; + + unsafe { + ptr.as_ref() + } }; // Ignore errors if this socket address has statically-known length // // This is to ensure that unix socket addresses have their length set appropriately. - let _ = address.set_length(mhdr.msg_namelen as usize); + let _ = unsafe { address.set_length(mhdr.msg_namelen as usize) }; RecvMsg { bytes: r as usize, @@ -2000,14 +1836,16 @@ unsafe fn pack_mhdr_to_receive( // initialize it. let mut mhdr = mem::MaybeUninit::::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = address as *mut c_void; - (*p).msg_namelen = S::size(); - (*p).msg_iov = iov_buffer as *mut iovec; - (*p).msg_iovlen = iov_buffer_len as _; - (*p).msg_control = cmsg_buffer as *mut c_void; - (*p).msg_controllen = cmsg_capacity as _; - (*p).msg_flags = 0; - mhdr.assume_init() + unsafe { + (*p).msg_name = address as *mut c_void; + (*p).msg_namelen = S::size(); + (*p).msg_iov = iov_buffer as *mut iovec; + (*p).msg_iovlen = iov_buffer_len as _; + (*p).msg_control = cmsg_buffer as *mut c_void; + (*p).msg_controllen = cmsg_capacity as _; + (*p).msg_flags = 0; + mhdr.assume_init() + } } fn pack_mhdr_to_send<'a, I, C, S>( @@ -2025,7 +1863,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( // The message header must be initialized before the individual cmsgs. let cmsg_ptr = if capacity > 0 { - cmsg_buffer.as_mut_ptr() as *mut c_void + cmsg_buffer.as_mut_ptr().cast() } else { ptr::null_mut() }; @@ -2035,11 +1873,11 @@ fn pack_mhdr_to_send<'a, I, C, S>( // initialize it. let mut mhdr = mem::MaybeUninit::::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _; + (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()).cast_mut().cast(); (*p).msg_namelen = addr.map(S::len).unwrap_or(0); // transmute iov into a mutable pointer. sendmsg doesn't really mutate // the buffer, but the standard says that it takes a mutable pointer - (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; + (*p).msg_iov = iov.as_ref().as_ptr().cast_mut().cast(); (*p).msg_iovlen = iov.as_ref().len() as _; (*p).msg_control = cmsg_ptr; (*p).msg_controllen = capacity as _; @@ -2166,17 +2004,51 @@ pub fn socketpair>>( Errno::result(res)?; // Safe because socketpair returned success. - unsafe { - Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) + unsafe { Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Backlog(i32); + +impl Backlog { + /// Sets the listen queue size to system `SOMAXCONN` value + pub const MAXCONN: Self = Self(libc::SOMAXCONN); + /// Sets the listen queue size to -1 for system supporting it + #[cfg(any(target_os = "linux", target_os = "freebsd"))] + pub const MAXALLOWABLE: Self = Self(-1); + + /// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid. + pub fn new>(val: I) -> Result { + cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { + const MIN: i32 = -1; + } else { + const MIN: i32 = 0; + } + } + + let val = val.into(); + + if !(MIN..Self::MAXCONN.0).contains(&val) { + return Err(Errno::EINVAL); + } + + Ok(Self(val)) + } +} + +impl From for i32 { + fn from(backlog: Backlog) -> Self { + backlog.0 } } /// Listen for connections on a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) -pub fn listen(sock: &F, backlog: usize) -> Result<()> { +pub fn listen(sock: &F, backlog: Backlog) -> Result<()> { let fd = sock.as_fd().as_raw_fd(); - let res = unsafe { libc::listen(fd, backlog as c_int) }; + let res = unsafe { libc::listen(fd, backlog.into()) }; Errno::result(res).map(drop) } @@ -2211,14 +2083,12 @@ pub fn accept(sockfd: RawFd) -> Result { target_arch = "x86_64" ) ), - target_os = "dragonfly", + freebsdlike, + netbsdlike, target_os = "emscripten", - target_os = "freebsd", target_os = "fuchsia", - target_os = "illumos", + solarish, target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" ))] pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result { let res = unsafe { @@ -2245,7 +2115,7 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result { unsafe { let ret = libc::recv( sockfd, - buf.as_mut_ptr() as *mut c_void, + buf.as_mut_ptr().cast(), buf.len() as size_t, flags.bits(), ); @@ -2269,20 +2139,14 @@ pub fn recvfrom( let ret = Errno::result(libc::recvfrom( sockfd, - buf.as_mut_ptr() as *mut c_void, + buf.as_mut_ptr().cast(), buf.len() as size_t, 0, - addr.as_mut_ptr() as *mut sockaddr, + addr.as_mut_ptr().cast(), &mut len as *mut socklen_t, ))? as usize; - Ok(( - ret, - T::from_raw( - addr.assume_init().as_ptr(), - Some(len), - ), - )) + Ok((ret, T::from_raw(addr.assume_init().as_ptr(), Some(len)))) } } @@ -2298,7 +2162,7 @@ pub fn sendto( let ret = unsafe { libc::sendto( fd, - buf.as_ptr() as *const c_void, + buf.as_ptr().cast(), buf.len() as size_t, flags.bits(), addr.as_ptr(), @@ -2314,12 +2178,7 @@ pub fn sendto( /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result { let ret = unsafe { - libc::send( - fd, - buf.as_ptr() as *const c_void, - buf.len() as size_t, - flags.bits(), - ) + libc::send(fd, buf.as_ptr().cast(), buf.len() as size_t, flags.bits()) }; Errno::result(ret).map(|r| r as usize) @@ -2386,8 +2245,7 @@ pub fn getpeername(fd: RawFd) -> Result { let mut addr = mem::MaybeUninit::::uninit(); let mut len = T::size(); - let ret = - libc::getpeername(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); + let ret = libc::getpeername(fd, addr.as_mut_ptr().cast(), &mut len); Errno::result(ret)?; @@ -2403,8 +2261,7 @@ pub fn getsockname(fd: RawFd) -> Result { let mut addr = mem::MaybeUninit::::uninit(); let mut len = T::size(); - let ret = - libc::getsockname(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); + let ret = libc::getsockname(fd, addr.as_mut_ptr().cast(), &mut len); Errno::result(ret)?; @@ -2439,27 +2296,3 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { } } -#[cfg(test)] -mod tests { - #[cfg(not(target_os = "redox"))] - #[test] - fn can_use_cmsg_space() { - let _ = cmsg_space!(u8); - } - - #[cfg(not(any( - target_os = "redox", - target_os = "linux", - target_os = "android" - )))] - #[test] - fn can_open_routing_socket() { - let _ = super::socket( - super::AddressFamily::Route, - super::SockType::Raw, - super::SockFlag::empty(), - None, - ) - .expect("Failed to open routing socket"); - } -} diff --git a/third_party/rust/nix/src/sys/socket/sockopt.rs b/third_party/rust/nix/src/sys/socket/sockopt.rs index 44f3ebbc1d..4357695f56 100644 --- a/third_party/rust/nix/src/sys/socket/sockopt.rs +++ b/third_party/rust/nix/src/sys/socket/sockopt.rs @@ -7,7 +7,6 @@ use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; use std::ffi::{OsStr, OsString}; use std::mem::{self, MaybeUninit}; -#[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; use std::os::unix::io::{AsFd, AsRawFd}; @@ -128,7 +127,7 @@ macro_rules! getsockopt_impl { /// both of them. /// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. /// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* -/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), +/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), /// and more. Please refer to your system manual for more options. Will be passed as the second /// argument (`level`) to the `getsockopt`/`setsockopt` call. /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, @@ -261,7 +260,7 @@ sockopt_impl!( libc::SO_REUSEADDR, bool ); -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[cfg(not(solarish))] sockopt_impl!( /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an /// identical socket address. @@ -318,7 +317,7 @@ sockopt_impl!( super::IpMembershipRequest ); cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -329,14 +328,7 @@ cfg_if! { #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Leave an IPv6 multicast group. Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); - } else if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { + } else if #[cfg(any(bsd, solarish))] { #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -363,6 +355,17 @@ sockopt_impl!( u8 ); #[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set or read the hop limit value of outgoing IPv6 multicast packets for + /// this socket. + Ipv6MulticastHops, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_MULTICAST_HOPS, + libc::c_int +); +#[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Set or read a boolean integer argument that determines whether sent @@ -408,7 +411,7 @@ sockopt_impl!( libc::IPV6_TCLASS, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -420,6 +423,20 @@ sockopt_impl!( libc::IP_FREEBIND, bool ); +#[cfg(linux_android)] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// If enabled, the kernel will not reserve an ephemeral port when binding + /// socket with a port number of 0. The port will later be automatically + /// chosen at connect time, in a way that allows sharing a source port as + /// long as the 4-tuple is unique. + IpBindAddressNoPort, + Both, + libc::IPPROTO_IP, + libc::IP_BIND_ADDRESS_NO_PORT, + bool +); sockopt_impl!( /// Specify the receiving timeout until reporting an error. ReceiveTimeout, @@ -477,12 +494,7 @@ sockopt_impl!( libc::SO_KEEPALIVE, bool ); -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] +#[cfg(any(freebsdlike, apple_targets))] sockopt_impl!( /// Get the credentials of the peer process of a connected unix domain /// socket. @@ -492,7 +504,7 @@ sockopt_impl!( libc::LOCAL_PEERCRED, super::XuCred ); -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(apple_targets)] sockopt_impl!( /// Get the PID of the peer process of a connected unix domain socket. LocalPeerPid, @@ -501,7 +513,7 @@ sockopt_impl!( libc::LOCAL_PEERPID, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Return the credentials of the foreign process connected to this socket. PeerCredentials, @@ -510,7 +522,18 @@ sockopt_impl!( libc::SO_PEERCRED, super::UnixCredentials ); -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_os = "freebsd")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Get backlog limit of the socket + ListenQLimit, + GetOnly, + libc::SOL_SOCKET, + libc::SO_LISTENQLIMIT, + u32 +); +#[cfg(apple_targets)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -522,12 +545,7 @@ sockopt_impl!( libc::TCP_KEEPALIVE, u32 ); -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] +#[cfg(any(freebsdlike, linux_android))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -540,7 +558,7 @@ sockopt_impl!( u32 ); cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { sockopt_impl!( /// The maximum segment size for outgoing TCP packets. TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); @@ -550,7 +568,11 @@ cfg_if! { TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); } } -#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))] +#[cfg(not(any( + target_os = "openbsd", + target_os = "haiku", + target_os = "redox" +)))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -562,7 +584,7 @@ sockopt_impl!( libc::TCP_KEEPCNT, u32 ); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! @@ -572,7 +594,11 @@ sockopt_impl!( libc::TCP_REPAIR, u32 ); -#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))] +#[cfg(not(any( + target_os = "openbsd", + target_os = "haiku", + target_os = "redox" +)))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -596,6 +622,26 @@ sockopt_impl!( libc::TCP_USER_TIMEOUT, u32 ); +#[cfg(linux_android)] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Enables TCP Fast Open (RFC 7413) on a connecting socket. If a fast open + /// cookie is not available (first attempt to connect), `connect` syscall + /// will behave as usual, except for internally trying to solicit a cookie + /// from remote peer. When cookie is available, the next `connect` syscall + /// will immediately succeed without actually establishing TCP connection. + /// The connection establishment will be defered till the next `write` or + /// `sendmsg` syscalls on the socket, allowing TCP prtocol to establish + /// connection and send data in the same packets. Note: calling `read` right + /// after `connect` without `write` on the socket will cause the blocking + /// socket to be blocked forever. + TcpFastOpenConnect, + Both, + libc::IPPROTO_TCP, + libc::TCP_FASTOPEN_CONNECT, + bool +); sockopt_impl!( /// Sets or gets the maximum socket receive buffer in bytes. RcvBuf, @@ -612,7 +658,7 @@ sockopt_impl!( libc::SO_SNDBUF, usize ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be @@ -623,7 +669,7 @@ sockopt_impl!( libc::SO_RCVBUFFORCE, usize ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be @@ -652,7 +698,7 @@ sockopt_impl!( libc::SO_ACCEPTCONN, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Bind this socket to a particular device like “eth0”. BindToDevice, @@ -661,7 +707,7 @@ sockopt_impl!( libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]> ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -673,7 +719,7 @@ sockopt_impl!( libc::SO_ORIGINAL_DST, libc::sockaddr_in ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! @@ -683,7 +729,7 @@ sockopt_impl!( libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6 ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Specifies exact type of timestamping information collected by the kernel /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) @@ -693,7 +739,7 @@ sockopt_impl!( libc::SO_TIMESTAMPING, super::TimestampingFlag ); -#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "redox")))] +#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "hurd", target_os = "redox")))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. ReceiveTimestamp, @@ -702,7 +748,7 @@ sockopt_impl!( libc::SO_TIMESTAMP, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. ReceiveTimestampns, @@ -719,9 +765,9 @@ sockopt_impl!( Both, libc::SOL_SOCKET, libc::SO_TS_CLOCK, - i32 + super::SocketTimestamp ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -806,7 +852,7 @@ sockopt_impl!( libc::SO_MARK, u32 ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Enable or disable the receiving of the `SCM_CREDENTIALS` control /// message. @@ -828,13 +874,7 @@ sockopt_impl!( libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]> ); -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", -))] +#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -846,15 +886,7 @@ sockopt_impl!( libc::IP_PKTINFO, bool ); -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -866,13 +898,7 @@ sockopt_impl!( libc::IPV6_RECVPKTINFO, bool ); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(bsd)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -884,13 +910,7 @@ sockopt_impl!( libc::IP_RECVIF, bool ); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(bsd)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -902,7 +922,7 @@ sockopt_impl!( libc::IP_RECVDSTADDR, bool ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -948,7 +968,7 @@ sockopt_impl!( libc::SO_TXTIME, libc::sock_txtime ); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] sockopt_impl!( /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should /// be attached to received skbs indicating the number of packets dropped by @@ -969,7 +989,7 @@ sockopt_impl!( libc::IPV6_V6ONLY, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Enable extended reliable error message passing. Ipv4RecvErr, @@ -978,7 +998,7 @@ sockopt_impl!( libc::IP_RECVERR, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Control receiving of asynchronous error options. Ipv6RecvErr, @@ -987,7 +1007,7 @@ sockopt_impl!( libc::IPV6_RECVERR, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Fetch the current system-estimated Path MTU. IpMtu, @@ -996,7 +1016,7 @@ sockopt_impl!( libc::IP_MTU, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] sockopt_impl!( /// Set or retrieve the current time-to-live field that is used in every /// packet sent from this socket. @@ -1006,7 +1026,7 @@ sockopt_impl!( libc::IP_TTL, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] sockopt_impl!( /// Set the unicast hop limit for the socket. Ipv6Ttl, @@ -1015,7 +1035,7 @@ sockopt_impl!( libc::IPV6_UNICAST_HOPS, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -1027,7 +1047,7 @@ sockopt_impl!( libc::IPV6_ORIGDSTADDR, bool ); -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] sockopt_impl!( /// Set "don't fragment packet" flag on the IP packet. IpDontFrag, @@ -1036,12 +1056,7 @@ sockopt_impl!( libc::IP_DONTFRAG, bool ); -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", -))] +#[cfg(any(linux_android, apple_targets))] sockopt_impl!( /// Set "don't fragment packet" flag on the IPv6 packet. Ipv6DontFrag, @@ -1053,13 +1068,13 @@ sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[derive(Copy, Clone, Debug)] pub struct AlgSetAeadAuthSize; // ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len` // See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222 -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] impl SetSockOpt for AlgSetAeadAuthSize { type Val = usize; @@ -1079,18 +1094,18 @@ impl SetSockOpt for AlgSetAeadAuthSize { #[allow(missing_docs)] // Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[derive(Clone, Debug)] pub struct AlgSetKey(::std::marker::PhantomData); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] impl Default for AlgSetKey { fn default() -> Self { AlgSetKey(Default::default()) } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] impl SetSockOpt for AlgSetKey where T: AsRef<[u8]> + Clone, @@ -1103,7 +1118,54 @@ where fd.as_fd().as_raw_fd(), libc::SOL_ALG, libc::ALG_SET_KEY, - val.as_ref().as_ptr() as *const _, + val.as_ref().as_ptr().cast(), + val.as_ref().len() as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + +/// Set the Upper Layer Protocol (ULP) on the TCP socket. +/// +/// For example, to enable the TLS ULP on a socket, the C function call would be: +/// +/// ```c +/// setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls")); +/// ``` +/// +/// ... and the `nix` equivalent is: +/// +/// ```ignore,rust +/// setsockopt(sock, TcpUlp::default(), b"tls"); +/// ``` +/// +/// Note that the ULP name does not need a trailing NUL terminator (`\0`). +#[cfg(linux_android)] +#[derive(Clone, Debug)] +pub struct TcpUlp(::std::marker::PhantomData); + +#[cfg(linux_android)] +impl Default for TcpUlp { + fn default() -> Self { + TcpUlp(Default::default()) + } +} + +#[cfg(linux_android)] +impl SetSockOpt for TcpUlp +where + T: AsRef<[u8]> + Clone, +{ + type Val = T; + + fn set(&self, fd: &F, val: &Self::Val) -> Result<()> { + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_TCP, + libc::TCP_ULP, + val.as_ref().as_ptr().cast(), val.as_ref().len() as libc::socklen_t, ); Errno::result(res).map(drop) @@ -1111,6 +1173,113 @@ where } } +/// Value used with the [`TcpTlsTx`] and [`TcpTlsRx`] socket options. +#[cfg(target_os = "linux")] +#[derive(Copy, Clone, Debug)] +pub enum TlsCryptoInfo { + /// AES-128-GCM + Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128), + + /// AES-256-GCM + Aes256Gcm(libc::tls12_crypto_info_aes_gcm_256), + + /// CHACHA20-POLY1305 + Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305), +} + +/// Set the Kernel TLS write parameters on the TCP socket. +/// +/// For example, the C function call would be: +/// +/// ```c +/// setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info)); +/// ``` +/// +/// ... and the `nix` equivalent is: +/// +/// ```ignore,rust +/// setsockopt(sock, TcpTlsTx, &crypto_info); +/// ``` +#[cfg(target_os = "linux")] +#[derive(Copy, Clone, Debug)] +pub struct TcpTlsTx; + +#[cfg(target_os = "linux")] +impl SetSockOpt for TcpTlsTx { + type Val = TlsCryptoInfo; + + fn set(&self, fd: &F, val: &Self::Val) -> Result<()> { + let (ffi_ptr, ffi_len) = match val { + TlsCryptoInfo::Aes128Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Aes256Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Chacha20Poly1305(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + }; + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_TLS, + libc::TLS_TX, + ffi_ptr, + ffi_len as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + +/// Set the Kernel TLS read parameters on the TCP socket. +/// +/// For example, the C function call would be: +/// +/// ```c +/// setsockopt(sock, SOL_TLS, TLS_RX, &crypto_info, sizeof(crypto_info)); +/// ``` +/// +/// ... and the `nix` equivalent is: +/// +/// ```ignore,rust +/// setsockopt(sock, TcpTlsRx, &crypto_info); +/// ``` +#[cfg(target_os = "linux")] +#[derive(Copy, Clone, Debug)] +pub struct TcpTlsRx; + +#[cfg(target_os = "linux")] +impl SetSockOpt for TcpTlsRx { + type Val = TlsCryptoInfo; + + fn set(&self, fd: &F, val: &Self::Val) -> Result<()> { + let (ffi_ptr, ffi_len) = match val { + TlsCryptoInfo::Aes128Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Aes256Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Chacha20Poly1305(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + }; + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_TLS, + libc::TLS_RX, + ffi_ptr, + ffi_len as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + + /* * * ===== Accessor helpers ===== @@ -1158,7 +1327,7 @@ impl Get for GetStruct { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1171,7 +1340,7 @@ impl Get for GetStruct { mem::size_of::(), "invalid getsockopt implementation" ); - self.val.assume_init() + unsafe { self.val.assume_init() } } } @@ -1209,7 +1378,7 @@ impl Get for GetBool { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1222,7 +1391,7 @@ impl Get for GetBool { mem::size_of::(), "invalid getsockopt implementation" ); - self.val.assume_init() != 0 + unsafe { self.val.assume_init() != 0 } } } @@ -1243,7 +1412,7 @@ impl<'a> Set<'a, bool> for SetBool { } fn ffi_len(&self) -> socklen_t { - mem::size_of::() as socklen_t + mem::size_of_val(&self.val) as socklen_t } } @@ -1262,7 +1431,7 @@ impl Get for GetU8 { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1275,7 +1444,7 @@ impl Get for GetU8 { mem::size_of::(), "invalid getsockopt implementation" ); - self.val.assume_init() + unsafe { self.val.assume_init() } } } @@ -1294,7 +1463,7 @@ impl<'a> Set<'a, u8> for SetU8 { } fn ffi_len(&self) -> socklen_t { - mem::size_of::() as socklen_t + mem::size_of_val(&self.val) as socklen_t } } @@ -1313,7 +1482,7 @@ impl Get for GetUsize { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1326,7 +1495,7 @@ impl Get for GetUsize { mem::size_of::(), "invalid getsockopt implementation" ); - self.val.assume_init() as usize + unsafe { self.val.assume_init() as usize } } } @@ -1345,7 +1514,7 @@ impl<'a> Set<'a, usize> for SetUsize { } fn ffi_len(&self) -> socklen_t { - mem::size_of::() as socklen_t + mem::size_of_val(&self.val) as socklen_t } } @@ -1364,7 +1533,7 @@ impl> Get for GetOsString { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1373,7 +1542,7 @@ impl> Get for GetOsString { unsafe fn assume_init(self) -> OsString { let len = self.len as usize; - let mut v = self.val.assume_init(); + let mut v = unsafe { self.val.assume_init() }; OsStr::from_bytes(&v.as_mut()[0..len]).to_owned() } } @@ -1391,7 +1560,7 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> { } fn ffi_ptr(&self) -> *const c_void { - self.val.as_bytes().as_ptr() as *const c_void + self.val.as_bytes().as_ptr().cast() } fn ffi_len(&self) -> socklen_t { @@ -1399,72 +1568,3 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> { } } -#[cfg(test)] -mod test { - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn can_get_peercred_on_unix_socket() { - use super::super::*; - - let (a, b) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let a_cred = getsockopt(&a, super::PeerCredentials).unwrap(); - let b_cred = getsockopt(&b, super::PeerCredentials).unwrap(); - assert_eq!(a_cred, b_cred); - assert_ne!(a_cred.pid(), 0); - } - - #[test] - fn is_socket_type_unix() { - use super::super::*; - - let (a, _b) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let a_type = getsockopt(&a, super::SockType).unwrap(); - assert_eq!(a_type, SockType::Stream); - } - - #[test] - fn is_socket_type_dgram() { - use super::super::*; - - let s = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - let s_type = getsockopt(&s, super::SockType).unwrap(); - assert_eq!(s_type, SockType::Datagram); - } - - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - #[test] - fn can_get_listen_on_tcp_socket() { - use super::super::*; - - let s = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - None, - ) - .unwrap(); - let s_listening = getsockopt(&s, super::AcceptConn).unwrap(); - assert!(!s_listening); - listen(&s, 10).unwrap(); - let s_listening2 = getsockopt(&s, super::AcceptConn).unwrap(); - assert!(s_listening2); - } -} diff --git a/third_party/rust/nix/src/sys/stat.rs b/third_party/rust/nix/src/sys/stat.rs index 7e51c03a3f..c5854eec01 100644 --- a/third_party/rust/nix/src/sys/stat.rs +++ b/third_party/rust/nix/src/sys/stat.rs @@ -1,10 +1,6 @@ -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +#[cfg(any(apple_targets, target_os = "openbsd"))] pub use libc::c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(target_os = "netbsd", freebsdlike))] pub use libc::c_ulong; pub use libc::stat as FileStat; pub use libc::{dev_t, mode_t}; @@ -43,7 +39,7 @@ libc_bitflags! { S_IXUSR; /// Read write and execute for group. S_IRWXG; - /// Read fr group. + /// Read for group. S_IRGRP; /// Write for group. S_IWGRP; @@ -65,26 +61,14 @@ libc_bitflags! { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +#[cfg(any(apple_targets, target_os = "openbsd"))] pub type type_of_file_flag = c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(freebsdlike, target_os = "netbsd"))] pub type type_of_file_flag = c_ulong; -#[cfg(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" -))] +#[cfg(bsd)] libc_bitflags! { /// File flags. - #[cfg_attr(docsrs, doc(cfg(all())))] pub struct FileFlag: type_of_file_flag { /// The file may only be appended to. SF_APPEND; @@ -101,7 +85,7 @@ libc_bitflags! { #[cfg(any(target_os = "dragonfly"))] SF_NOHISTORY; /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] SF_NOUNLINK; /// Mask of superuser changeable flags SF_SETTABLE; @@ -121,14 +105,13 @@ libc_bitflags! { #[cfg(any(target_os = "dragonfly"))] UF_CACHE; /// File is compressed at the file system level. - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] UF_COMPRESSED; /// The file may be hidden from directory listings at the application's /// discretion. #[cfg(any( target_os = "freebsd", - target_os = "macos", - target_os = "ios", + apple_targets, ))] UF_HIDDEN; /// The file may not be changed. @@ -138,7 +121,7 @@ libc_bitflags! { #[cfg(any(target_os = "dragonfly"))] UF_NOHISTORY; /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] UF_NOUNLINK; /// The file is offline, or has the Windows and CIFS /// `FILE_ATTRIBUTE_OFFLINE` attribute. @@ -162,7 +145,7 @@ libc_bitflags! { #[cfg(any(target_os = "freebsd"))] UF_SYSTEM; /// File renames and deletes are tracked. - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] UF_TRACKED; #[cfg(any(target_os = "dragonfly"))] UF_XLINK; @@ -184,20 +167,15 @@ pub fn mknod( } /// Create a special or ordinary file, relative to a given directory. -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "haiku" -)))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))] pub fn mknodat( - dirfd: RawFd, + dirfd: Option, path: &P, kind: SFlag, perm: Mode, dev: dev_t, ) -> Result<()> { + let dirfd = at_rawfd(dirfd); let res = path.with_nix_path(|cstr| unsafe { libc::mknodat( dirfd, @@ -211,19 +189,16 @@ pub fn mknodat( } #[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub const fn major(dev: dev_t) -> u64 { ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) } #[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub const fn minor(dev: dev_t) -> u64 { ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff) } #[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub const fn makedev(major: u64, minor: u64) -> dev_t { ((major & 0xffff_f000) << 32) | ((major & 0x0000_0fff) << 8) @@ -268,12 +243,12 @@ pub fn fstat(fd: RawFd) -> Result { } #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn fstatat( - dirfd: RawFd, + dirfd: Option, pathname: &P, f: AtFlags, ) -> Result { + let dirfd = at_rawfd(dirfd); let mut dst = mem::MaybeUninit::uninit(); let res = pathname.with_nix_path(|cstr| unsafe { libc::fstatat( @@ -324,7 +299,6 @@ pub enum FchmodatFlags { /// /// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn fchmodat( dirfd: Option, path: &P, @@ -383,12 +357,10 @@ pub fn utimes( #[cfg(any( target_os = "linux", target_os = "haiku", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn lutimes( path: &P, atime: &TimeVal, @@ -404,6 +376,9 @@ pub fn lutimes( /// Change the access and modification times of the file specified by a file descriptor. /// +/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use +/// `TimeSpec::UTIME_OMIT` if you don't want to change it. +/// /// # References /// /// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). @@ -436,11 +411,13 @@ pub enum UtimensatFlags { /// `utimes(path, times)`. The latter is a deprecated API so prefer using the /// former if the platforms you care about support it. /// +/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use +/// `TimeSpec::UTIME_OMIT` if you don't want to change it. +/// /// # References /// /// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn utimensat( dirfd: Option, path: &P, @@ -466,12 +443,12 @@ pub fn utimensat( } #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn mkdirat( - fd: RawFd, + fd: Option, path: &P, mode: Mode, ) -> Result<()> { + let fd = at_rawfd(fd); let res = path.with_nix_path(|cstr| unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) })?; diff --git a/third_party/rust/nix/src/sys/statfs.rs b/third_party/rust/nix/src/sys/statfs.rs index 5111df2e6e..b2315f4ceb 100644 --- a/third_party/rust/nix/src/sys/statfs.rs +++ b/third_party/rust/nix/src/sys/statfs.rs @@ -1,7 +1,7 @@ //! Get filesystem statistics, non-portably //! //! See [`statvfs`](crate::sys::statvfs) for a portable alternative. -#[cfg(not(any(target_os = "linux", target_os = "android")))] +#[cfg(not(linux_android))] use std::ffi::CStr; use std::fmt::{self, Debug}; use std::mem; @@ -9,16 +9,7 @@ use std::os::unix::io::{AsFd, AsRawFd}; use cfg_if::cfg_if; -#[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) -))] +#[cfg(all(feature = "mount", bsd))] use crate::mount::MntFlags; #[cfg(target_os = "linux")] use crate::sys::statvfs::FsFlags; @@ -26,15 +17,13 @@ use crate::{errno::Errno, NixPath, Result}; /// Identifies a mounted file system #[cfg(target_os = "android")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub type fsid_t = libc::__fsid_t; /// Identifies a mounted file system #[cfg(not(target_os = "android"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub type fsid_t = libc::fsid_t; cfg_if! { - if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] { + if #[cfg(any(linux_android, target_os = "fuchsia"))] { type type_of_statfs = libc::statfs64; const LIBC_FSTATFS: unsafe extern fn (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int @@ -62,10 +51,12 @@ pub struct Statfs(type_of_statfs); type fs_type_t = u32; #[cfg(target_os = "android")] type fs_type_t = libc::c_ulong; -#[cfg(all(target_os = "linux", target_arch = "s390x"))] +#[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] type fs_type_t = libc::c_uint; #[cfg(all(target_os = "linux", target_env = "musl"))] type fs_type_t = libc::c_ulong; +#[cfg(all(target_os = "linux", target_env = "ohos"))] +type fs_type_t = libc::c_ulong; #[cfg(all(target_os = "linux", target_env = "uclibc"))] type fs_type_t = libc::c_int; #[cfg(all( @@ -73,6 +64,7 @@ type fs_type_t = libc::c_int; not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", target_env = "uclibc" )) ))] @@ -84,6 +76,7 @@ type fs_type_t = libc::__fsword_t; target_os = "android", all(target_os = "linux", target_arch = "s390x"), all(target_os = "linux", target_env = "musl"), + all(target_os = "linux", target_env = "ohos"), all( target_os = "linux", not(any(target_arch = "s390x", target_env = "musl")) @@ -94,206 +87,203 @@ pub struct FsType(pub fs_type_t); // These constants are defined without documentation in the Linux headers, so we // can't very well document them here. -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const AUTOFS_SUPER_MAGIC: FsType = FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const BTRFS_SUPER_MAGIC: FsType = FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const DEVPTS_SUPER_MAGIC: FsType = FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const ECRYPTFS_SUPER_MAGIC: FsType = FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const F2FS_SUPER_MAGIC: FsType = FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const FUSE_SUPER_MAGIC: FsType = FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const FUTEXFS_SUPER_MAGIC: FsType = FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const HOSTFS_SUPER_MAGIC: FsType = FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const MINIX3_SUPER_MAGIC: FsType = FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const NILFS_SUPER_MAGIC: FsType = FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const OCFS2_SUPER_MAGIC: FsType = FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const QNX6_SUPER_MAGIC: FsType = FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const RDTGROUP_SUPER_MAGIC: FsType = FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const SECURITYFS_MAGIC: FsType = FsType(libc::SECURITYFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const XENFS_SUPER_MAGIC: FsType = FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[allow(missing_docs)] pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t); -#[cfg(all( - any(target_os = "linux", target_os = "android"), - not(target_env = "musl") -))] +#[cfg(all(linux_android, not(target_env = "musl"), not(target_env = "ohos")))] #[allow(missing_docs)] pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t); @@ -302,39 +292,33 @@ impl Statfs { #[cfg(not(any( target_os = "openbsd", target_os = "dragonfly", - target_os = "ios", - target_os = "macos" + apple_targets, )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn filesystem_type(&self) -> FsType { FsType(self.0.f_type) } /// Magic code defining system type - #[cfg(not(any(target_os = "linux", target_os = "android")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(linux_android))] pub fn filesystem_type_name(&self) -> &str { let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) }; c_str.to_str().unwrap() } /// Optimal transfer block size - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] pub fn optimal_transfer_size(&self) -> i32 { self.0.f_iosize } /// Optimal transfer block size #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> u32 { self.0.f_iosize } /// Optimal transfer block size - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] pub fn optimal_transfer_size(&self) -> u32 { self.0.f_bsize } @@ -342,9 +326,9 @@ impl Statfs { /// Optimal transfer block size #[cfg(any( target_os = "android", - all(target_os = "linux", target_env = "musl") + all(target_os = "linux", target_env = "musl"), + all(target_os = "linux", target_env = "ohos") ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::c_ulong { self.0.f_bsize } @@ -355,46 +339,41 @@ impl Statfs { not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", target_env = "uclibc" )) ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::__fsword_t { self.0.f_bsize } /// Optimal transfer block size #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::c_int { self.0.f_bsize } /// Optimal transfer block size #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::c_long { self.0.f_iosize } /// Optimal transfer block size #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> u64 { self.0.f_iosize } /// Size of a block - #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(apple_targets, target_os = "openbsd"))] pub fn block_size(&self) -> u32 { self.0.f_bsize } /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] pub fn block_size(&self) -> u32 { self.0.f_bsize } @@ -402,7 +381,13 @@ impl Statfs { /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 #[cfg(all(target_os = "linux", target_env = "musl"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> libc::c_ulong { + self.0.f_bsize + } + + /// Size of a block + // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 + #[cfg(all(target_os = "linux", target_env = "ohos"))] pub fn block_size(&self) -> libc::c_ulong { self.0.f_bsize } @@ -410,7 +395,6 @@ impl Statfs { /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::c_int { self.0.f_bsize } @@ -422,47 +406,34 @@ impl Statfs { not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", target_env = "uclibc" )) ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::__fsword_t { self.0.f_bsize } /// Size of a block #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> u64 { self.0.f_bsize } /// Size of a block #[cfg(target_os = "android")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::c_ulong { self.0.f_bsize } /// Size of a block #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::c_long { self.0.f_bsize } /// Get the mount flags - #[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(all(feature = "mount", bsd))] #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches pub fn flags(&self) -> MntFlags { MntFlags::from_bits_truncate(self.0.f_flags as i32) @@ -472,35 +443,30 @@ impl Statfs { // The f_flags field exists on Android and Fuchsia too, but without man // pages I can't tell if it can be cast to FsFlags. #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn flags(&self) -> FsFlags { FsFlags::from_bits_truncate(self.0.f_flags as libc::c_ulong) } /// Maximum length of filenames #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> u32 { self.0.f_namemax } /// Maximum length of filenames - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] pub fn maximum_name_length(&self) -> u32 { self.0.f_namelen } /// Maximum length of filenames #[cfg(all(target_os = "linux", target_env = "musl"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::c_ulong { self.0.f_namelen } /// Maximum length of filenames #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::c_int { self.0.f_namelen } @@ -511,173 +477,141 @@ impl Statfs { not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", target_env = "uclibc" )) ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::__fsword_t { self.0.f_namelen } /// Maximum length of filenames #[cfg(target_os = "android")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::c_ulong { self.0.f_namelen } /// Total data blocks in filesystem #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", + apple_targets, + linux_android, target_os = "freebsd", target_os = "fuchsia", target_os = "openbsd", - target_os = "linux", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> u64 { self.0.f_blocks } /// Total data blocks in filesystem #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> libc::c_long { self.0.f_blocks } /// Total data blocks in filesystem #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> u32 { self.0.f_blocks } /// Free blocks in filesystem #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", + apple_targets, + linux_android, target_os = "freebsd", target_os = "fuchsia", target_os = "openbsd", - target_os = "linux", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> u64 { self.0.f_bfree } /// Free blocks in filesystem #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> libc::c_long { self.0.f_bfree } /// Free blocks in filesystem #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> u32 { self.0.f_bfree } /// Free blocks available to unprivileged user - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "fuchsia", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(apple_targets, linux_android, target_os = "fuchsia"))] pub fn blocks_available(&self) -> u64 { self.0.f_bavail } /// Free blocks available to unprivileged user #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> libc::c_long { self.0.f_bavail } /// Free blocks available to unprivileged user #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> i64 { self.0.f_bavail } /// Free blocks available to unprivileged user #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> u32 { self.0.f_bavail } /// Total file nodes in filesystem #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", + apple_targets, + linux_android, target_os = "freebsd", target_os = "fuchsia", target_os = "openbsd", - target_os = "linux", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> u64 { self.0.f_files } /// Total file nodes in filesystem #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> libc::c_long { self.0.f_files } /// Total file nodes in filesystem #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> u32 { self.0.f_files } /// Free file nodes in filesystem #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", + apple_targets, + linux_android, target_os = "fuchsia", target_os = "openbsd", - target_os = "linux", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> u64 { self.0.f_ffree } /// Free file nodes in filesystem #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> libc::c_long { self.0.f_ffree } /// Free file nodes in filesystem #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> i64 { self.0.f_ffree } /// Free file nodes in filesystem #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> u32 { self.0.f_ffree } @@ -699,16 +633,7 @@ impl Debug for Statfs { ds.field("files", &self.files()); ds.field("files_free", &self.files_free()); ds.field("filesystem_id", &self.filesystem_id()); - #[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))] + #[cfg(all(feature = "mount", bsd))] ds.field("flags", &self.flags()); ds.finish() } @@ -747,107 +672,3 @@ pub fn fstatfs(fd: Fd) -> Result { .map(|_| Statfs(stat.assume_init())) } } - -#[cfg(test)] -mod test { - use std::fs::File; - - use crate::sys::statfs::*; - use crate::sys::statvfs::*; - use std::path::Path; - - #[test] - fn statfs_call() { - check_statfs("/tmp"); - check_statfs("/dev"); - check_statfs("/run"); - check_statfs("/"); - } - - #[test] - fn fstatfs_call() { - check_fstatfs("/tmp"); - check_fstatfs("/dev"); - check_fstatfs("/run"); - check_fstatfs("/"); - } - - fn check_fstatfs(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()).unwrap(); - let file = File::open(path).unwrap(); - let fs = fstatfs(&file).unwrap(); - assert_fs_equals(fs, vfs); - } - - fn check_statfs(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()).unwrap(); - let fs = statfs(path.as_bytes()).unwrap(); - assert_fs_equals(fs, vfs); - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn assert_fs_equals(fs: Statfs, vfs: Statvfs) { - assert_eq!(fs.files() as u64, vfs.files() as u64); - assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); - assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); - } - - // This test is ignored because files_free/blocks_free can change after statvfs call and before - // statfs call. - #[test] - #[ignore] - fn statfs_call_strict() { - check_statfs_strict("/tmp"); - check_statfs_strict("/dev"); - check_statfs_strict("/run"); - check_statfs_strict("/"); - } - - // This test is ignored because files_free/blocks_free can change after statvfs call and before - // fstatfs call. - #[test] - #[ignore] - fn fstatfs_call_strict() { - check_fstatfs_strict("/tmp"); - check_fstatfs_strict("/dev"); - check_fstatfs_strict("/run"); - check_fstatfs_strict("/"); - } - - fn check_fstatfs_strict(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()); - let file = File::open(path).unwrap(); - let fs = fstatfs(&file); - assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) - } - - fn check_statfs_strict(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()); - let fs = statfs(path.as_bytes()); - assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) { - assert_eq!(fs.files_free() as u64, vfs.files_free() as u64); - assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64); - assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64); - assert_eq!(fs.files() as u64, vfs.files() as u64); - assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); - assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); - } -} diff --git a/third_party/rust/nix/src/sys/statvfs.rs b/third_party/rust/nix/src/sys/statvfs.rs index 35424e5e27..db1abdd4fe 100644 --- a/third_party/rust/nix/src/sys/statvfs.rs +++ b/third_party/rust/nix/src/sys/statvfs.rs @@ -21,44 +21,34 @@ libc_bitflags!( #[cfg(not(target_os = "haiku"))] ST_NOSUID; /// Do not interpret character or block-special devices - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ST_NODEV; /// Do not allow execution of binaries on the filesystem - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ST_NOEXEC; /// All IO should be done synchronously - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ST_SYNCHRONOUS; /// Allow mandatory locks on the filesystem - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ST_MANDLOCK; /// Write on file/directory/symlink #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] ST_WRITE; /// Append-only file #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] ST_APPEND; /// Immutable file #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] ST_IMMUTABLE; /// Do not update access times on files - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ST_NOATIME; /// Do not update access times on files - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ST_NODIRATIME; /// Update access time relative to modify/change time - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos"))))] ST_RELATIME; } ); @@ -114,13 +104,18 @@ impl Statvfs { } /// Get the file system id + #[cfg(not(target_os = "hurd"))] pub fn filesystem_id(&self) -> c_ulong { self.0.f_fsid } + /// Get the file system id + #[cfg(target_os = "hurd")] + pub fn filesystem_id(&self) -> u64 { + self.0.f_fsid + } /// Get the mount flags #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn flags(&self) -> FsFlags { FsFlags::from_bits_truncate(self.0.f_flag) } @@ -153,20 +148,3 @@ pub fn fstatvfs(fd: Fd) -> Result { .map(|_| Statvfs(stat.assume_init())) } } - -#[cfg(test)] -mod test { - use crate::sys::statvfs::*; - use std::fs::File; - - #[test] - fn statvfs_call() { - statvfs(&b"/"[..]).unwrap(); - } - - #[test] - fn fstatvfs_call() { - let root = File::open("/").unwrap(); - fstatvfs(&root).unwrap(); - } -} diff --git a/third_party/rust/nix/src/sys/termios.rs b/third_party/rust/nix/src/sys/termios.rs index ecaa3eaf8f..e006c2f1b0 100644 --- a/third_party/rust/nix/src/sys/termios.rs +++ b/third_party/rust/nix/src/sys/termios.rs @@ -85,28 +85,8 @@ //! //! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`: //! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust,ignore" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust" -)] +#![cfg_attr(bsd, doc = " ```rust,ignore")] +#![cfg_attr(not(bsd), doc = " ```rust")] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -118,28 +98,8 @@ //! //! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s: //! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] +#![cfg_attr(bsd, doc = " ```rust")] +#![cfg_attr(not(bsd), doc = " ```rust,ignore")] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -151,28 +111,8 @@ //! //! It's trivial to convert from a `BaudRate` to a `u32` on BSDs: //! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] +#![cfg_attr(bsd, doc = " ```rust")] +#![cfg_attr(not(bsd), doc = " ```rust,ignore")] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -185,28 +125,8 @@ //! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support) //! by specifying baud rates directly using `u32`s: //! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] +#![cfg_attr(bsd, doc = " ```rust")] +#![cfg_attr(not(bsd), doc = " ```rust,ignore")] //! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -246,7 +166,7 @@ pub struct Termios { /// Control characters (see `termios.c_cc` documentation) pub control_chars: [libc::cc_t; NCCS], /// Line discipline (see `termios.c_line` documentation) - #[cfg(any(target_os = "linux", target_os = "android",))] + #[cfg(linux_android)] pub line_discipline: libc::cc_t, /// Line discipline (see `termios.c_line` documentation) #[cfg(target_os = "haiku")] @@ -266,11 +186,7 @@ impl Termios { termios.c_cflag = self.control_flags.bits(); termios.c_lflag = self.local_flags.bits(); termios.c_cc = self.control_chars; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] { termios.c_line = self.line_discipline; } @@ -292,11 +208,7 @@ impl Termios { termios.c_cflag = self.control_flags.bits(); termios.c_lflag = self.local_flags.bits(); termios.c_cc = self.control_chars; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] { termios.c_line = self.line_discipline; } @@ -312,11 +224,7 @@ impl Termios { self.control_flags = ControlFlags::from_bits_retain(termios.c_cflag); self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); self.control_chars = termios.c_cc; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] { self.line_discipline = termios.c_line; } @@ -332,11 +240,7 @@ impl From for Termios { control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), local_flags: LocalFlags::from_bits_truncate(termios.c_lflag), control_chars: termios.c_cc, - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] line_discipline: termios.c_line, } } @@ -356,8 +260,13 @@ libc_enum! { /// /// B0 is special and will disable the port. #[cfg_attr(target_os = "haiku", repr(u8))] - #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] - #[cfg_attr(all(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), not(target_os = "haiku")), repr(u32))] + #[cfg_attr(target_os = "hurd", repr(i32))] + #[cfg_attr(all(apple_targets, target_pointer_width = "64"), repr(u64))] + #[cfg_attr(all( + not(all(apple_targets, target_pointer_width = "64")), + not(target_os = "haiku"), + not(target_os = "hurd") + ), repr(u32))] #[non_exhaustive] pub enum BaudRate { B0, @@ -373,110 +282,62 @@ libc_enum! { B1800, B2400, B4800, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] B7200, B9600, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] B14400, B19200, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] B28800, B38400, #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] B57600, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] B76800, #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] B115200, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(solarish)] B153600, #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] B230400, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(solarish)] B307200, - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + solarish, target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + target_os = "netbsd"))] B460800, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B576000, - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + solarish, target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + target_os = "netbsd"))] B921600, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B1000000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B1152000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B1500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B2000000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] B2500000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] B3000000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] B3500000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] B4000000, } impl TryFrom } -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] impl From for u32 { fn from(b: BaudRate) -> u32 { b as u32 @@ -542,80 +403,57 @@ libc_enum! { } // TODO: Make this usable directly as a slice index. -#[cfg(not(target_os = "haiku"))] libc_enum! { /// Indices into the `termios.c_cc` array for special characters. #[repr(usize)] #[non_exhaustive] pub enum SpecialCharacterIndices { - #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(target_os = "aix", target_os = "haiku")))] VDISCARD, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "aix", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, + solarish, + target_os = "aix"))] VDSUSP, VEOF, VEOL, VEOL2, VERASE, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, solarish))] VERASE2, VINTR, VKILL, + #[cfg(not(target_os = "haiku"))] VLNEXT, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + solarish, target_os = "aix", target_os = "haiku")))] VMIN, VQUIT, + #[cfg(not(target_os = "haiku"))] VREPRINT, VSTART, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish))] VSTATUS, VSTOP, VSUSP, #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] VSWTC, - #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(solarish, target_os = "haiku"))] VSWTCH, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + solarish, target_os = "aix", target_os = "haiku")))] VTIME, - #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(target_os = "aix", target_os = "haiku")))] VWERASE, #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] VCHECKPT, } } #[cfg(any( all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", - target_os = "solaris", + solarish, target_os = "aix", + target_os = "haiku", ))] impl SpecialCharacterIndices { pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; @@ -623,17 +461,7 @@ impl SpecialCharacterIndices { } pub use libc::NCCS; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "aix", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(linux_android, target_os = "aix", bsd))] pub use libc::_POSIX_VDISABLE; libc_bitflags! { @@ -651,13 +479,10 @@ libc_bitflags! { IXON; IXOFF; #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IXANY; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] IMAXBEL; - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets))] IUTF8; } } @@ -666,209 +491,119 @@ libc_bitflags! { /// Flags for configuring the output mode of a terminal pub struct OutputFlags: tcflag_t { OPOST; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "linux", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] OLCUC; ONLCR; OCRNL as tcflag_t; ONOCR as tcflag_t; ONLRET as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OFILL as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] OFDEL as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] NL0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] NL1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR2 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR3 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB2 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB3 as tcflag_t; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] XTABS; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] BS0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] BS1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] VT0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] VT1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] FF0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] FF1 as tcflag_t; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] OXTABS; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] ONOEOT as tcflag_t; // Bitmasks for use with OutputFlags to select specific settings // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 // is resolved. - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CRDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TABDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] BSDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] VTDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] FFDLY as tcflag_t; } } @@ -876,13 +611,7 @@ libc_bitflags! { libc_bitflags! { /// Flags for setting the control mode of a terminal pub struct ControlFlags: tcflag_t { - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] CIGNORE; CS5; CS6; @@ -895,54 +624,30 @@ libc_bitflags! { HUPCL; CLOCAL; #[cfg(not(any(target_os = "redox", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] CRTSCTS; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] CBAUD; #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] CMSPAR; #[cfg(any(target_os = "android", all(target_os = "linux", not(any(target_arch = "powerpc", target_arch = "powerpc64")))))] CIBAUD; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] CBAUDEX; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] MDMBUF; - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(netbsdlike)] CHWFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, netbsdlike))] CCTS_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, netbsdlike))] CRTS_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] CDTR_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] CDSR_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] CCAR_OFLOW; // Bitmasks for use with ControlFlags to select specific settings @@ -957,58 +662,35 @@ libc_bitflags! { /// Flags for setting any local modes pub struct LocalFlags: tcflag_t { #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] ECHOKE; ECHOE; ECHOK; ECHO; ECHONL; #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] ECHOPRT; #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] ECHOCTL; ISIG; ICANON; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] ALTWERASE; IEXTEN; #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] EXTPROC; TOSTOP; #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] FLUSHO; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] NOKERNINFO; #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] PENDIN; NOFLSH; } } cfg_if! { - if #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] { + if #[cfg(bsd)] { /// Get input baud rate (see /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). /// @@ -1141,7 +823,6 @@ pub fn cfmakeraw(termios: &mut Termios) { /// /// Note that this is a non-standard function, available on FreeBSD. #[cfg(target_os = "freebsd")] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn cfmakesane(termios: &mut Termios) { let inner_termios = unsafe { termios.get_libc_termios_mut() }; unsafe { @@ -1242,18 +923,3 @@ pub fn tcgetsid(fd: Fd) -> Result { Errno::result(res).map(Pid::from_raw) } } - -#[cfg(test)] -mod test { - use super::*; - use std::convert::TryFrom; - - #[test] - fn try_from() { - assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); - #[cfg(not(target_os = "haiku"))] - BaudRate::try_from(999999999).expect_err("assertion failed"); - #[cfg(target_os = "haiku")] - BaudRate::try_from(99).expect_err("assertion failed"); - } -} diff --git a/third_party/rust/nix/src/sys/time.rs b/third_party/rust/nix/src/sys/time.rs index a0160e21ff..af436cabd5 100644 --- a/third_party/rust/nix/src/sys/time.rs +++ b/third_party/rust/nix/src/sys/time.rs @@ -2,7 +2,6 @@ // https://github.com/rust-lang/libc/issues/1848 pub use libc::{suseconds_t, time_t}; use libc::{timespec, timeval}; -use std::convert::From; use std::time::Duration; use std::{cmp, fmt, ops}; @@ -18,7 +17,7 @@ const fn zero_init_timespec() -> timespec { all( any( target_os = "freebsd", - target_os = "illumos", + solarish, target_os = "linux", target_os = "netbsd" ), @@ -88,7 +87,7 @@ pub(crate) mod timer { Interval(TimeSpec), } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] bitflags! { /// Flags that are used for arming the timer. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -97,12 +96,7 @@ pub(crate) mod timer { const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET; } } - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "dragonfly", - target_os = "illumos" - ))] + #[cfg(any(freebsdlike, target_os = "netbsd", solarish))] bitflags! { /// Flags that are used for arming the timer. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -334,6 +328,17 @@ impl TimeValLike for TimeSpec { } impl TimeSpec { + /// Leave the timestamp unchanged. + #[cfg(not(target_os = "redox"))] + // At the time of writing this PR, redox does not support this feature + pub const UTIME_OMIT: TimeSpec = + TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t); + /// Update the timestamp to `Now` + // At the time of writing this PR, redox does not support this feature + #[cfg(not(target_os = "redox"))] + pub const UTIME_NOW: TimeSpec = + TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t); + /// Construct a new `TimeSpec` from its components #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { @@ -712,101 +717,3 @@ fn mod_floor_64(this: i64, other: i64) -> i64 { fn div_rem_64(this: i64, other: i64) -> (i64, i64) { (this / other, this % other) } - -#[cfg(test)] -mod test { - use super::{TimeSpec, TimeVal, TimeValLike}; - use std::time::Duration; - - #[test] - pub fn test_timespec() { - assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); - assert_eq!( - TimeSpec::seconds(1) + TimeSpec::seconds(2), - TimeSpec::seconds(3) - ); - assert_eq!( - TimeSpec::minutes(3) + TimeSpec::seconds(2), - TimeSpec::seconds(182) - ); - } - - #[test] - pub fn test_timespec_from() { - let duration = Duration::new(123, 123_456_789); - let timespec = TimeSpec::nanoseconds(123_123_456_789); - - assert_eq!(TimeSpec::from(duration), timespec); - assert_eq!(Duration::from(timespec), duration); - } - - #[test] - pub fn test_timespec_neg() { - let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); - let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); - - assert_eq!(a, -b); - } - - #[test] - pub fn test_timespec_ord() { - assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); - assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); - assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); - assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); - assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); - } - - #[test] - pub fn test_timespec_fmt() { - assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); - assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); - assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); - assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); - assert_eq!( - TimeSpec::nanoseconds(42).to_string(), - "0.000000042 seconds" - ); - assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); - } - - #[test] - pub fn test_timeval() { - assert_ne!(TimeVal::seconds(1), TimeVal::zero()); - assert_eq!( - TimeVal::seconds(1) + TimeVal::seconds(2), - TimeVal::seconds(3) - ); - assert_eq!( - TimeVal::minutes(3) + TimeVal::seconds(2), - TimeVal::seconds(182) - ); - } - - #[test] - pub fn test_timeval_ord() { - assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); - assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); - assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); - assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); - assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); - } - - #[test] - pub fn test_timeval_neg() { - let a = TimeVal::seconds(1) + TimeVal::microseconds(123); - let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); - - assert_eq!(a, -b); - } - - #[test] - pub fn test_timeval_fmt() { - assert_eq!(TimeVal::zero().to_string(), "0 seconds"); - assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); - assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); - assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); - assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); - assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); - } -} diff --git a/third_party/rust/nix/src/sys/timerfd.rs b/third_party/rust/nix/src/sys/timerfd.rs index c4337c9dfa..68b06d6322 100644 --- a/third_party/rust/nix/src/sys/timerfd.rs +++ b/third_party/rust/nix/src/sys/timerfd.rs @@ -53,7 +53,7 @@ impl AsFd for TimerFd { impl FromRawFd for TimerFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { TimerFd { - fd: OwnedFd::from_raw_fd(fd), + fd: unsafe { OwnedFd::from_raw_fd(fd) }, } } } diff --git a/third_party/rust/nix/src/sys/uio.rs b/third_party/rust/nix/src/sys/uio.rs index eaf61edfd4..cdf380dd11 100644 --- a/third_party/rust/nix/src/sys/uio.rs +++ b/third_party/rust/nix/src/sys/uio.rs @@ -2,7 +2,7 @@ use crate::errno::Errno; use crate::Result; -use libc::{self, c_int, c_void, off_t, size_t}; +use libc::{self, c_int, off_t, size_t}; use std::io::{IoSlice, IoSliceMut}; use std::os::unix::io::{AsFd, AsRawFd}; @@ -18,7 +18,11 @@ pub fn writev(fd: Fd, iov: &[IoSlice<'_>]) -> Result { // // Because it is ABI compatible, a pointer cast here is valid let res = unsafe { - libc::writev(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + libc::writev( + fd.as_fd().as_raw_fd(), + iov.as_ptr().cast(), + iov.len() as c_int, + ) }; Errno::result(res).map(|r| r as usize) @@ -33,7 +37,11 @@ pub fn writev(fd: Fd, iov: &[IoSlice<'_>]) -> Result { pub fn readv(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result { // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec let res = unsafe { - libc::readv(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + libc::readv( + fd.as_fd().as_raw_fd(), + iov.as_ptr().cast(), + iov.len() as c_int, + ) }; Errno::result(res).map(|r| r as usize) @@ -45,9 +53,12 @@ pub fn readv(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result { /// or an error occurs. The file offset is not changed. /// /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn pwritev(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result { +#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "solaris")))] +pub fn pwritev( + fd: Fd, + iov: &[IoSlice<'_>], + offset: off_t, +) -> Result { #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t @@ -55,7 +66,7 @@ pub fn pwritev(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result( let res = unsafe { libc::preadv( fd.as_fd().as_raw_fd(), - iov.as_ptr() as *const libc::iovec, + iov.as_ptr().cast(), iov.len() as c_int, offset, ) @@ -105,7 +115,7 @@ pub fn pwrite(fd: Fd, buf: &[u8], offset: off_t) -> Result { let res = unsafe { libc::pwrite( fd.as_fd().as_raw_fd(), - buf.as_ptr() as *const c_void, + buf.as_ptr().cast(), buf.len() as size_t, offset, ) @@ -122,7 +132,7 @@ pub fn pread(fd: Fd, buf: &mut [u8], offset: off_t) -> Result { let res = unsafe { libc::pread( fd.as_fd().as_raw_fd(), - buf.as_mut_ptr() as *mut c_void, + buf.as_mut_ptr().cast(), buf.len() as size_t, offset, ) @@ -139,8 +149,7 @@ pub fn pread(fd: Fd, buf: &mut [u8], offset: off_t) -> Result { /// therefore not represented in Rust by an actual slice as `IoSlice` is. It /// is used with [`process_vm_readv`](fn.process_vm_readv.html) /// and [`process_vm_writev`](fn.process_vm_writev.html). -#[cfg(any(target_os = "linux", target_os = "android"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] #[repr(C)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct RemoteIoVec { @@ -173,7 +182,7 @@ feature! { /// [ptrace]: ../ptrace/index.html /// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] +#[cfg(all(linux_android, not(target_env = "uclibc")))] pub fn process_vm_writev( pid: crate::unistd::Pid, local_iov: &[IoSlice<'_>], @@ -181,8 +190,8 @@ pub fn process_vm_writev( { let res = unsafe { libc::process_vm_writev(pid.into(), - local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, - remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) + local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong, + remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0) }; Errno::result(res).map(|r| r as usize) @@ -208,7 +217,7 @@ pub fn process_vm_writev( /// [`ptrace`]: ../ptrace/index.html /// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] +#[cfg(all(linux_android, not(target_env = "uclibc")))] pub fn process_vm_readv( pid: crate::unistd::Pid, local_iov: &mut [IoSliceMut<'_>], @@ -216,8 +225,8 @@ pub fn process_vm_readv( { let res = unsafe { libc::process_vm_readv(pid.into(), - local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, - remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) + local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong, + remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0) }; Errno::result(res).map(|r| r as usize) diff --git a/third_party/rust/nix/src/sys/utsname.rs b/third_party/rust/nix/src/sys/utsname.rs index b48ed9f45e..cf4e6cc738 100644 --- a/third_party/rust/nix/src/sys/utsname.rs +++ b/third_party/rust/nix/src/sys/utsname.rs @@ -37,7 +37,7 @@ impl UtsName { } /// NIS or YP domain name of this machine. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] pub fn domainname(&self) -> &OsStr { cast_and_trim(&self.0.domainname) } @@ -62,24 +62,3 @@ fn cast_and_trim(slice: &[c_char]) -> &OsStr { OsStr::from_bytes(bytes) } - -#[cfg(test)] -mod test { - #[cfg(target_os = "linux")] - #[test] - pub fn test_uname_linux() { - assert_eq!(super::uname().unwrap().sysname(), "Linux"); - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - #[test] - pub fn test_uname_darwin() { - assert_eq!(super::uname().unwrap().sysname(), "Darwin"); - } - - #[cfg(target_os = "freebsd")] - #[test] - pub fn test_uname_freebsd() { - assert_eq!(super::uname().unwrap().sysname(), "FreeBSD"); - } -} diff --git a/third_party/rust/nix/src/sys/wait.rs b/third_party/rust/nix/src/sys/wait.rs index f7a63ffcd2..844e165c18 100644 --- a/third_party/rust/nix/src/sys/wait.rs +++ b/third_party/rust/nix/src/sys/wait.rs @@ -24,53 +24,41 @@ libc_bitflags!( /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal. WUNTRACED; /// Report the status of selected processes which have terminated. - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + apple_targets, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", target_os = "redox", - target_os = "macos", target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] WEXITED; /// Report the status of selected processes that have continued from a /// job control stop by receiving a /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal. WCONTINUED; /// An alias for WUNTRACED. - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + apple_targets, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", target_os = "redox", - target_os = "macos", target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] WSTOPPED; /// Don't reap, just poll status. - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + apple_targets, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", target_os = "redox", - target_os = "macos", target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] WNOWAIT; /// Don't wait on children of other threads in this group - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "redox"))] __WNOTHREAD; /// Wait on all children, regardless of type - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "redox"))] __WALL; /// Wait for "clone" children only. - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "redox"))] __WCLONE; } ); @@ -107,16 +95,14 @@ pub enum WaitStatus { /// /// [`nix::sys::ptrace`]: ../ptrace/index.html /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html - #[cfg(any(target_os = "linux", target_os = "android"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] PtraceEvent(Pid, Signal, c_int), /// The traced process was stopped by execution of a system call, /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for /// more information. /// /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html - #[cfg(any(target_os = "linux", target_os = "android"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] PtraceSyscall(Pid), /// The process was previously stopped but has resumed execution /// after receiving a `SIGCONT` signal. This is only reported if @@ -139,7 +125,7 @@ impl WaitStatus { Some(p) } StillAlive => None, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), } } @@ -173,7 +159,7 @@ fn stop_signal(status: i32) -> Result { Signal::try_from(libc::WSTOPSIG(status)) } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn syscall_stop(status: i32) -> bool { // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect // of delivering SIGTRAP | 0x80 as the signal number for syscall @@ -182,7 +168,7 @@ fn syscall_stop(status: i32) -> bool { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn stop_additional(status: i32) -> c_int { (status >> 16) as c_int } @@ -216,7 +202,7 @@ impl WaitStatus { WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status)) } else if stopped(status) { cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { fn decode_stopped(pid: Pid, status: i32) -> Result { let status_additional = stop_additional(status); Ok(if syscall_stop(status) { @@ -259,7 +245,7 @@ impl WaitStatus { all(target_os = "linux", not(target_env = "uclibc")), ))] unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result { - let si_pid = siginfo.si_pid(); + let si_pid = unsafe { siginfo.si_pid() }; if si_pid == 0 { return Ok(WaitStatus::StillAlive); } @@ -267,7 +253,7 @@ impl WaitStatus { assert_eq!(siginfo.si_signo, libc::SIGCHLD); let pid = Pid::from_raw(si_pid); - let si_status = siginfo.si_status(); + let si_status = unsafe { siginfo.si_status() }; let status = match siginfo.si_code { libc::CLD_EXITED => WaitStatus::Exited(pid, si_status), @@ -280,7 +266,7 @@ impl WaitStatus { WaitStatus::Stopped(pid, Signal::try_from(si_status)?) } libc::CLD_CONTINUED => WaitStatus::Continued(pid), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::CLD_TRAPPED => { if si_status == libc::SIGTRAP | 0x80 { WaitStatus::PtraceSyscall(pid) @@ -354,7 +340,7 @@ pub enum Id<'fd> { /// If the PID is zero, the caller's process group is used since Linux 5.4. PGid(Pid), /// Wait for the child referred to by the given PID file descriptor - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] PIDFd(BorrowedFd<'fd>), /// A helper variant to resolve the unused parameter (`'fd`) problem on platforms /// other than Linux and Android. @@ -376,9 +362,11 @@ pub fn waitid(id: Id, flags: WaitPidFlag) -> Result { Id::All => (libc::P_ALL, 0), Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t), Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] Id::PIDFd(fd) => (libc::P_PIDFD, fd.as_raw_fd() as libc::id_t), - Id::_Unreachable(_) => unreachable!("This variant could never be constructed"), + Id::_Unreachable(_) => { + unreachable!("This variant could never be constructed") + } }; let siginfo = unsafe { diff --git a/third_party/rust/nix/src/time.rs b/third_party/rust/nix/src/time.rs index 2e03c46cf4..195df71211 100644 --- a/third_party/rust/nix/src/time.rs +++ b/third_party/rust/nix/src/time.rs @@ -1,11 +1,6 @@ +//! Sleep, query system clocks, and set system clock use crate::sys::time::TimeSpec; -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] #[cfg(feature = "process")] use crate::unistd::Pid; use crate::{Errno, Result}; @@ -14,8 +9,7 @@ use std::mem::MaybeUninit; /// Clock identifier /// -/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by -/// accidentally passing wrong value. +/// Newtype pattern around [`libc::clockid_t`]. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ClockId(clockid_t); @@ -28,14 +22,7 @@ impl ClockId { feature! { #![feature = "process"] /// Returns `ClockId` of a `pid` CPU-time clock - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] pub fn pid_cpu_clock_id(pid: Pid) -> Result { clock_getcpuclockid(pid) } @@ -43,7 +30,6 @@ impl ClockId { /// Returns resolution of the clock id #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn res(self) -> Result { clock_getres(self) } @@ -55,12 +41,12 @@ impl ClockId { /// Sets time to `timespec` on the clock id #[cfg(not(any( - target_os = "macos", target_os = "ios", + target_os = "tvos", + target_os = "watchos", target_os = "redox", - target_os = "hermit", + target_os = "hermit" )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn set_time(self, timespec: TimeSpec) -> Result<()> { clock_settime(self, timespec) } @@ -70,135 +56,103 @@ impl ClockId { self.0 } - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] + /// Starts at zero when the kernel boots and increments monotonically in SI seconds while the + /// machine is running. pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Like [`CLOCK_BOOTTIME`](ClockId::CLOCK_BOOTTIME), but will wake the system if it is + /// suspended.. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); + /// Increments in SI seconds. pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy. pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for accuracy at the expense of execution time. pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Similar to [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but provides access to a raw + /// hardware-based time that is not subject to NTP adjustments. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); #[cfg(any( - target_os = "android", + linux_android, + apple_targets, + freebsdlike, target_os = "emscripten", target_os = "fuchsia", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", target_os = "redox", - target_os = "linux" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Returns the execution time of the calling process. pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Increments when the CPU is running in user or kernel mode pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); + /// Increments as a wall clock should. pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but not settable. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy. pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for accuracy at the expense of execution time. pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Returns the current second without performing a full time counter query, using an in-kernel + /// cached value of the current second. pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); + #[allow(missing_docs)] // Undocumented on Linux! #[cfg(any( target_os = "emscripten", target_os = "fuchsia", all(target_os = "linux", target_env = "musl") ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// International Atomic Time. + /// + /// A nonsettable system-wide clock derived from wall-clock time but ignoring leap seconds. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); #[cfg(any( - target_os = "android", + linux_android, + apple_targets, + freebsdlike, target_os = "emscripten", target_os = "fuchsia", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Returns the execution time of the calling thread. pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Starts at zero when the kernel boots and increments monotonically in SI seconds while the + /// machine is running. pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for execution time at the expense of accuracy. pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for accuracy at the expense of execution time. pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Increments only when the CPU is running in user mode on behalf of the calling process. pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); } @@ -223,7 +177,6 @@ impl std::fmt::Display for ClockId { /// Get the resolution of the specified clock, (see /// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)). #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn clock_getres(clock_id: ClockId) -> Result { let mut c_time: MaybeUninit = MaybeUninit::uninit(); let ret = @@ -247,12 +200,12 @@ pub fn clock_gettime(clock_id: ClockId) -> Result { /// Set the time of the specified clock, (see /// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)). #[cfg(not(any( - target_os = "macos", target_os = "ios", + target_os = "tvos", + target_os = "watchos", target_os = "redox", - target_os = "hermit", + target_os = "hermit" )))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; @@ -261,13 +214,7 @@ pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { /// Get the clock id of the specified process id, (see /// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)). -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] #[cfg(feature = "process")] #[cfg_attr(docsrs, doc(cfg(feature = "process")))] pub fn clock_getcpuclockid(pid: Pid) -> Result { @@ -278,6 +225,61 @@ pub fn clock_getcpuclockid(pid: Pid) -> Result { let res = unsafe { clk_id.assume_init() }; Ok(ClockId::from(res)) } else { - Err(Errno::from_i32(ret)) + Err(Errno::from_raw(ret)) + } +} + +#[cfg(any( + linux_android, + solarish, + freebsdlike, + target_os = "netbsd", + target_os = "hurd", + target_os = "aix" +))] +libc_bitflags! { + /// Flags that are used for arming the timer. + pub struct ClockNanosleepFlags: libc::c_int { + /// Indicates that a requested time value should be treated as absolute instead of + /// relative. + TIMER_ABSTIME; + } +} + +/// Suspend execution of this thread for the amount of time specified by `request` +/// and measured against the clock speficied by `clock_id`. +/// +/// If `flags` is [`TIMER_ABSTIME`](ClockNanosleepFlags::TIMER_ABSTIME), this function will suspend +/// execution until the time value of clock_id reaches the absolute time specified by `request`. If +/// a signal is caught by a signal-catching function, or a signal causes the process to terminate, +/// this sleep is interrrupted. +/// +/// see also [man 3 clock_nanosleep](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_nanosleep.html) +#[cfg(any( + linux_android, + solarish, + freebsdlike, + target_os = "netbsd", + target_os = "hurd", + target_os = "aix" +))] +pub fn clock_nanosleep( + clock_id: ClockId, + flags: ClockNanosleepFlags, + request: &TimeSpec, +) -> Result { + let mut remain = TimeSpec::new(0, 0); + let ret = unsafe { + libc::clock_nanosleep( + clock_id.as_raw(), + flags.bits(), + request.as_ref() as *const _, + remain.as_mut() as *mut _, + ) + }; + if ret == 0 { + Ok(remain) + } else { + Err(Errno::from_raw(ret)) } } diff --git a/third_party/rust/nix/src/unistd.rs b/third_party/rust/nix/src/unistd.rs index bb9f1c1f67..4502766c5d 100644 --- a/third_party/rust/nix/src/unistd.rs +++ b/third_party/rust/nix/src/unistd.rs @@ -1,22 +1,29 @@ //! Safe wrappers around functions found in libc "unistd.h" header -use crate::errno::{self, Errno}; +use crate::errno::Errno; + +#[cfg(any( + all(feature = "fs", not(target_os = "redox")), + all(feature = "process", linux_android) +))] +use crate::fcntl::at_rawfd; #[cfg(not(target_os = "redox"))] #[cfg(feature = "fs")] -use crate::fcntl::{at_rawfd, AtFlags}; +use crate::fcntl::AtFlags; + #[cfg(feature = "fs")] -use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; -#[cfg(all( - feature = "fs", - any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" - ) +#[cfg(any( + linux_android, + freebsdlike, + solarish, + netbsdlike, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "hurd", + target_os = "redox", ))] +use crate::fcntl::OFlag; +#[cfg(all(feature = "fs", bsd))] use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] use crate::sys::stat::Mode; @@ -24,43 +31,27 @@ use crate::{Error, NixPath, Result}; #[cfg(not(target_os = "redox"))] use cfg_if::cfg_if; use libc::{ - self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t, - size_t, uid_t, PATH_MAX, + c_char, c_int, c_long, c_uint, gid_t, mode_t, off_t, pid_t, size_t, uid_t, }; use std::convert::Infallible; -use std::ffi::{CStr, OsString}; #[cfg(not(target_os = "redox"))] -use std::ffi::{CString, OsStr}; -#[cfg(not(target_os = "redox"))] -use std::os::unix::ffi::OsStrExt; -use std::os::unix::ffi::OsStringExt; -use std::os::unix::io::RawFd; -use std::os::unix::io::{AsFd, AsRawFd}; +use std::ffi::CString; +use std::ffi::{CStr, OsStr, OsString}; +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +use std::os::unix::io::{AsFd, AsRawFd, OwnedFd, RawFd}; use std::path::PathBuf; use std::{fmt, mem, ptr}; feature! { #![feature = "fs"] - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] pub use self::pivot_root::*; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))] pub use self::setres::*; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))] pub use self::getres::*; feature! { @@ -225,7 +216,12 @@ impl fmt::Display for Pid { /// you are now executing in the parent process or in the child. #[derive(Clone, Copy, Debug)] pub enum ForkResult { - Parent { child: Pid }, + /// This is the parent process of the fork. + Parent { + /// The PID of the fork's child process + child: Pid + }, + /// This is the child process of the fork. Child, } @@ -260,7 +256,7 @@ impl ForkResult { /// } /// Ok(ForkResult::Child) => { /// // Unsafe to use `println!` (or `unwrap`) here. See Safety. -/// write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok(); +/// write(std::io::stdout(), "I'm a new child process\n".as_bytes()).ok(); /// unsafe { libc::_exit(0) }; /// } /// Err(_) => println!("Fork failed"), @@ -290,7 +286,7 @@ impl ForkResult { #[inline] pub unsafe fn fork() -> Result { use self::ForkResult::*; - let res = libc::fork(); + let res = unsafe { libc::fork() }; Errno::result(res).map(|res| match res { 0 => Child, @@ -332,6 +328,9 @@ pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; Errno::result(res).map(drop) } +/// Get process group +/// +/// See Also [`getpgid`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html) #[inline] pub fn getpgid(pid: Option) -> Result { let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; @@ -366,8 +365,8 @@ feature! { /// Get the group process id (GPID) of the foreground process group on the /// terminal associated to file descriptor (FD). #[inline] -pub fn tcgetpgrp(fd: c_int) -> Result { - let res = unsafe { libc::tcgetpgrp(fd) }; +pub fn tcgetpgrp(fd: F) -> Result { + let res = unsafe { libc::tcgetpgrp(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(Pid) } /// Set the terminal foreground process group (see @@ -376,8 +375,8 @@ pub fn tcgetpgrp(fd: c_int) -> Result { /// Get the group process id (PGID) to the foreground process group on the /// terminal associated to file descriptor (FD). #[inline] -pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { - let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; +pub fn tcsetpgrp(fd: F, pgrp: Pid) -> Result<()> { + let res = unsafe { libc::tcsetpgrp(fd.as_fd().as_raw_fd(), pgrp.into()) }; Errno::result(res).map(drop) } } @@ -404,7 +403,7 @@ pub fn getpgrp() -> Pid { /// /// No error handling is required as a thread id should always exist for any /// process, even if threads are not being used. -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[inline] pub fn gettid() -> Pid { Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) @@ -444,30 +443,22 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result { } /// Create a new copy of the specified file descriptor using the specified fd -/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)). +/// and flags (see [`dup(2)`](https://man7.org/linux/man-pages/man2/dup.2.html)). /// /// This function behaves similar to `dup2()` but allows for flags to be /// specified. +#[cfg(any( + netbsdlike, + solarish, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux" +))] pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { - dup3_polyfill(oldfd, newfd, flags) -} - -#[inline] -fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { - if oldfd == newfd { - return Err(Errno::EINVAL); - } + let res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) }; - let fd = dup2(oldfd, newfd)?; - - if flags.contains(OFlag::O_CLOEXEC) { - if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { - let _ = close(fd); - return Err(e); - } - } - - Ok(fd) + Errno::result(res) } /// Change the current working directory of the calling process (see @@ -583,8 +574,7 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { // mkfifoat is not implemented in OSX or android #[inline] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "haiku", target_os = "android", target_os = "redox" @@ -664,17 +654,17 @@ feature! { /// ``` #[inline] pub fn getcwd() -> Result { - let mut buf = Vec::with_capacity(512); + let mut buf = Vec::::with_capacity(512); loop { unsafe { - let ptr = buf.as_mut_ptr() as *mut c_char; + let ptr = buf.as_mut_ptr().cast(); // The buffer must be large enough to store the absolute pathname plus // a terminating null byte, or else null is returned. // To safely handle this we start with a reasonable size (512 bytes) // and double the buffer size upon every error if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const c_char) + let len = CStr::from_ptr(buf.as_ptr().cast()) .to_bytes() .len(); buf.set_len(len); @@ -688,8 +678,13 @@ pub fn getcwd() -> Result { } } + #[cfg(not(target_os = "hurd"))] + const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first + // Trigger the internal buffer resizing logic. - reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; + reserve_double_buffer_size(&mut buf, PATH_MAX)?; } } } @@ -749,11 +744,19 @@ pub fn fchown(fd: RawFd, owner: Option, group: Option) -> Result<()> { Errno::result(res).map(drop) } -/// Flags for `fchownat` function. -#[derive(Clone, Copy, Debug)] -pub enum FchownatFlags { - FollowSymlink, - NoFollowSymlink, +// Just a wrapper around `AtFlags` so that we can help our users migrate. +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +pub type FchownatFlags = AtFlags; +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +impl FchownatFlags { + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const FollowSymlink: FchownatFlags = FchownatFlags::empty(); + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const NoFollowSymlink: FchownatFlags = FchownatFlags::AT_SYMLINK_NOFOLLOW; } /// Change the ownership of the file at `path` to be owned by the specified @@ -767,10 +770,10 @@ pub enum FchownatFlags { /// with the file descriptor `dirfd` or the current working directory /// if `dirfd` is `None`. /// -/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// If `flag` is `AtFlags::AT_SYMLINK_NOFOLLOW` and `path` names a symbolic link, /// then the mode of the symbolic link is changed. /// -/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to +/// `fchownat(None, path, owner, group, AtFlags::AT_SYMLINK_NOFOLLOW)` is identical to /// a call `libc::lchown(path, owner, group)`. That's why `lchown` is unimplemented in /// the `nix` crate. /// @@ -783,12 +786,8 @@ pub fn fchownat( path: &P, owner: Option, group: Option, - flag: FchownatFlags, + flag: AtFlags, ) -> Result<()> { - let atflag = match flag { - FchownatFlags::FollowSymlink => AtFlags::empty(), - FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; let res = path.with_nix_path(|cstr| unsafe { let (uid, gid) = chown_raw_ids(owner, group); libc::fchownat( @@ -796,7 +795,7 @@ pub fn fchownat( cstr.as_ptr(), uid, gid, - atflag.bits() as libc::c_int, + flag.bits() ) })?; @@ -883,7 +882,7 @@ pub fn execvp>( /// This functions like a combination of `execvp(2)` and `execve(2)` to pass an /// environment and have a search path. See these two for additional /// information. -#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] +#[cfg(any(target_os = "haiku", target_os = "hurd", target_os = "linux", target_os = "openbsd"))] pub fn execvpe, SE: AsRef>( filename: &CStr, args: &[SA], @@ -909,12 +908,7 @@ pub fn execvpe, SE: AsRef>( /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor instead of a path. -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "hurd"))] #[inline] pub fn fexecve, SE: AsRef>( fd: RawFd, @@ -939,15 +933,16 @@ pub fn fexecve, SE: AsRef>( /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor to the base directory plus a path. -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[inline] pub fn execveat, SE: AsRef>( - dirfd: RawFd, + dirfd: Option, pathname: &CStr, args: &[SA], env: &[SE], flags: super::fcntl::AtFlags, ) -> Result { + let dirfd = at_rawfd(dirfd); let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -991,14 +986,10 @@ pub fn execveat, SE: AsRef>( /// * `noclose = false`: The process' stdin, stdout, and stderr will point to /// `/dev/null` after daemonizing. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" + linux_android, + freebsdlike, + solarish, + netbsdlike ))] pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; @@ -1020,19 +1011,16 @@ feature! { pub fn sethostname>(name: S) -> Result<()> { // Handle some differences in type of the len arg across platforms. cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "aix", - target_os = "solaris", ))] { + if #[cfg(any(freebsdlike, + solarish, + apple_targets, + target_os = "aix"))] { type sethostname_len_t = c_int; } else { type sethostname_len_t = size_t; } } - let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char; + let ptr = name.as_ref().as_bytes().as_ptr().cast(); let len = name.as_ref().len() as sethostname_len_t; let res = unsafe { libc::sethostname(ptr, len) }; @@ -1056,14 +1044,14 @@ pub fn sethostname>(name: S) -> Result<()> { pub fn gethostname() -> Result { // The capacity is the max length of a hostname plus the NUL terminator. let mut buffer: Vec = Vec::with_capacity(256); - let ptr = buffer.as_mut_ptr() as *mut c_char; + let ptr = buffer.as_mut_ptr().cast(); let len = buffer.capacity() as size_t; let res = unsafe { libc::gethostname(ptr, len) }; Errno::result(res).map(|_| { unsafe { buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated - let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len(); + let len = CStr::from_ptr(buffer.as_ptr().cast()).len(); buffer.set_len(len); } OsString::from_vec(buffer) @@ -1105,9 +1093,8 @@ pub fn close(fd: RawFd) -> Result<()> { /// /// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { - let res = unsafe { - libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) - }; + let res = + unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as size_t) }; Errno::result(res).map(|r| r as usize) } @@ -1115,9 +1102,13 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { /// Write to a raw file descriptor. /// /// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) -pub fn write(fd: RawFd, buf: &[u8]) -> Result { +pub fn write(fd: Fd, buf: &[u8]) -> Result { let res = unsafe { - libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) + libc::write( + fd.as_fd().as_raw_fd(), + buf.as_ptr().cast(), + buf.len() as size_t, + ) }; Errno::result(res).map(|r| r as usize) @@ -1143,11 +1134,9 @@ pub enum Whence { /// equal to offset that contains some data. If offset points to /// some data, then the file offset is set to offset. #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", + freebsdlike, + solarish, target_os = "linux", - target_os = "solaris" ))] SeekData = libc::SEEK_DATA, /// Specify an offset relative to the next hole in the file greater than @@ -1156,11 +1145,9 @@ pub enum Whence { /// then the file offset should be adjusted to the end of the file (i.e., there /// is an implicit hole at the end of any file). #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", + freebsdlike, + solarish, target_os = "linux", - target_os = "solaris" ))] SeekHole = libc::SEEK_HOLE, } @@ -1174,7 +1161,11 @@ pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result { Errno::result(res).map(|r| r as off_t) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Move the read/write file offset. +/// +/// Unlike [`lseek`], it takes a 64-bit argument even on platforms where [`libc::off_t`] is +/// 32 bits. +#[cfg(linux_android)] pub fn lseek64( fd: RawFd, offset: libc::off64_t, @@ -1189,14 +1180,15 @@ pub fn lseek64( /// Create an interprocess channel. /// /// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) -pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); +pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> { + let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit(); - let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) }; + let res = unsafe { libc::pipe(fds.as_mut_ptr().cast()) }; Error::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + let [read, write] = unsafe { fds.assume_init() }; + Ok((read, write)) } feature! { @@ -1219,26 +1211,24 @@ feature! { /// /// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) #[cfg(any( - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, + solarish, target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", + target_os = "hurd", target_os = "redox", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" + netbsdlike, ))] -pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); +pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> { + let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit(); let res = - unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) }; + unsafe { libc::pipe2(fds.as_mut_ptr().cast(), flags.bits()) }; Errno::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + let [read, write] = unsafe { fds.assume_init() }; + Ok((read, write)) } /// Truncate a file to a specified length @@ -1261,6 +1251,7 @@ pub fn ftruncate(fd: Fd, len: off_t) -> Result<()> { Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop) } +/// Determines if the file descriptor refers to a valid terminal type device. pub fn isatty(fd: RawFd) -> Result { unsafe { // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so @@ -1276,11 +1267,18 @@ pub fn isatty(fd: RawFd) -> Result { } } -/// Flags for `linkat` function. -#[derive(Clone, Copy, Debug)] -pub enum LinkatFlags { - SymlinkFollow, - NoSymlinkFollow, +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +pub type LinkatFlags = AtFlags; +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +impl LinkatFlags { + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const SymlinkFollow: LinkatFlags = LinkatFlags::AT_SYMLINK_FOLLOW; + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const NoSymlinkFollow: LinkatFlags = LinkatFlags::empty(); } /// Link one file to another file @@ -1288,7 +1286,7 @@ pub enum LinkatFlags { /// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the /// case of a relative `oldpath`, the path is interpreted relative to the directory associated /// with file descriptor `olddirfd` instead of the current working directory and similiarly for -/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and +/// `newpath` and file descriptor `newdirfd`. In case `flag` is `AtFlags::AT_SYMLINK_FOLLOW` and /// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created. /// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath` /// and/or `newpath` is then interpreted relative to the current working directory of the calling @@ -1302,13 +1300,8 @@ pub fn linkat( oldpath: &P, newdirfd: Option, newpath: &P, - flag: LinkatFlags, + flag: AtFlags, ) -> Result<()> { - let atflag = match flag { - LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, - LinkatFlags::NoSymlinkFollow => AtFlags::empty(), - }; - let res = oldpath.with_nix_path(|oldcstr| { newpath.with_nix_path(|newcstr| unsafe { libc::linkat( @@ -1316,7 +1309,7 @@ pub fn linkat( oldcstr.as_ptr(), at_rawfd(newdirfd), newcstr.as_ptr(), - atflag.bits() as libc::c_int, + flag.bits(), ) }) })??; @@ -1335,7 +1328,9 @@ pub fn unlink(path: &P) -> Result<()> { /// Flags for `unlinkat` function. #[derive(Clone, Copy, Debug)] pub enum UnlinkatFlags { + /// Remove the directory entry as a directory, not a normal file RemoveDir, + /// Remove the directory entry as a normal file, not a directory NoRemoveDir, } @@ -1369,6 +1364,7 @@ pub fn unlinkat( Errno::result(res).map(drop) } +/// Change a process's root directory #[inline] #[cfg(not(target_os = "fuchsia"))] pub fn chroot(path: &P) -> Result<()> { @@ -1381,13 +1377,7 @@ pub fn chroot(path: &P) -> Result<()> { /// Commit filesystem caches to disk /// /// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, netbsdlike))] pub fn sync() { unsafe { libc::sync() }; } @@ -1396,7 +1386,7 @@ pub fn sync() { /// descriptor `fd` to disk /// /// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html) -#[cfg(target_os = "linux")] +#[cfg(linux_android)] pub fn syncfs(fd: RawFd) -> Result<()> { let res = unsafe { libc::syncfs(fd) }; @@ -1418,15 +1408,12 @@ pub fn fsync(fd: RawFd) -> Result<()> { /// See also /// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", + linux_android, + solarish, + netbsdlike, target_os = "freebsd", + target_os = "emscripten", target_os = "fuchsia", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", - target_os = "solaris" ))] #[inline] pub fn fdatasync(fd: RawFd) -> Result<()> { @@ -1527,7 +1514,7 @@ feature! { /// ID of the caller. /// /// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html) -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] pub fn setfsuid(uid: Uid) -> Uid { let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; Uid::from_raw(prev_fsuid as uid_t) @@ -1538,7 +1525,7 @@ pub fn setfsuid(uid: Uid) -> Uid { /// ID of the caller. /// /// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html) -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] pub fn setfsgid(gid: Gid) -> Gid { let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; Gid::from_raw(prev_fsgid as gid_t) @@ -1555,14 +1542,14 @@ feature! { /// **Note:** This function is not available for Apple platforms. On those /// platforms, checking group membership should be achieved via communication /// with the `opendirectoryd` service. -#[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[cfg(not(apple_targets))] pub fn getgroups() -> Result> { // First get the maximum number of groups. The value returned // shall always be greater than or equal to one and less than or // equal to the value of {NGROUPS_MAX} + 1. let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { Ok(Some(n)) => (n + 1) as usize, - Ok(None) | Err(_) => ::max_value(), + Ok(None) | Err(_) => usize::MAX, }; // Next, get the number of groups so we can size our Vec @@ -1588,7 +1575,7 @@ pub fn getgroups() -> Result> { let ngroups = unsafe { libc::getgroups( groups.capacity() as c_int, - groups.as_mut_ptr() as *mut gid_t, + groups.as_mut_ptr().cast(), ) }; @@ -1640,22 +1627,15 @@ pub fn getgroups() -> Result> { /// # try_main().unwrap(); /// ``` #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "haiku" )))] pub fn setgroups(groups: &[Gid]) -> Result<()> { cfg_if! { - if #[cfg(any(target_os = "aix", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { + if #[cfg(any(bsd, + solarish, + target_os = "aix"))] { type setgroups_ngroups_t = c_int; } else { type setgroups_ngroups_t = size_t; @@ -1667,7 +1647,7 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { let res = unsafe { libc::setgroups( groups.len() as setgroups_ngroups_t, - groups.as_ptr() as *const gid_t, + groups.as_ptr().cast(), ) }; @@ -1696,20 +1676,19 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { /// will only ever return the complete list or else an error. #[cfg(not(any( target_os = "aix", - target_os = "illumos", - target_os = "ios", - target_os = "macos", + solarish, + apple_targets, target_os = "redox" )))] pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { Ok(Some(n)) => n as c_int, - Ok(None) | Err(_) => ::max_value(), + Ok(None) | Err(_) => c_int::MAX, }; use std::cmp::min; let mut groups = Vec::::with_capacity(min(ngroups_max, 8) as usize); cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { + if #[cfg(apple_targets)] { type getgrouplist_group_t = c_int; } else { type getgrouplist_group_t = gid_t; @@ -1722,7 +1701,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { libc::getgrouplist( user.as_ptr(), gid as getgrouplist_group_t, - groups.as_mut_ptr() as *mut getgrouplist_group_t, + groups.as_mut_ptr().cast(), &mut ngroups, ) }; @@ -1781,14 +1760,13 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { /// # try_main().unwrap(); /// ``` #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "haiku" )))] pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { + if #[cfg(apple_targets)] { type initgroups_group_t = c_int; } else { type initgroups_group_t = gid_t; @@ -1915,6 +1893,7 @@ pub fn sleep(seconds: c_uint) -> c_uint { feature! { #![feature = "acct"] +/// Process accounting #[cfg(not(any(target_os = "redox", target_os = "haiku")))] pub mod acct { use crate::errno::Errno; @@ -1970,7 +1949,7 @@ feature! { pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { let mut path = template.with_nix_path(|path| path.to_bytes_with_nul().to_owned())?; - let p = path.as_mut_ptr() as *mut _; + let p = path.as_mut_ptr().cast(); let fd = unsafe { libc::mkstemp(p) }; let last = path.pop(); // drop the trailing nul debug_assert!(last == Some(b'\0')); @@ -1983,6 +1962,38 @@ pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { feature! { #![all(feature = "fs", feature = "feature")] +/// Creates a directory which persists even after process termination +/// +/// * `template`: a path whose rightmost characters contain some number of X, e.g. `/tmp/tmpdir_XXXXXX` +/// * returns: filename +/// +/// Err is returned either if no temporary filename could be created or the template had insufficient X +/// +/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html) +/// +/// ``` +/// use nix::unistd; +/// +/// match unistd::mkdtemp("/tmp/tempdir_XXXXXX") { +/// Ok(_path) => { +/// // do something with directory +/// } +/// Err(e) => panic!("mkdtemp failed: {}", e) +/// }; +/// ``` +pub fn mkdtemp(template: &P) -> Result { + let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; + let p = path.as_mut_ptr() as *mut _; + let p = unsafe { libc::mkdtemp(p) }; + if p.is_null() { + return Err(Errno::last()); + } + let last = path.pop(); // drop the trailing nul + debug_assert!(last == Some(b'\0')); + let pathname = OsString::from_vec(path); + Ok(PathBuf::from(pathname)) +} + /// Variable names for `pathconf` /// /// Nix uses the same naming convention for these variables as the @@ -2004,16 +2015,13 @@ feature! { #[non_exhaustive] pub enum PathconfVar { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + freebsdlike, + netbsdlike, target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", target_os = "redox" ))] /// Minimum number of bits needed to represent, as a signed integer value, /// the maximum size of a regular file allowed in the specified directory. - #[cfg_attr(docsrs, doc(cfg(all())))] FILESIZEBITS = libc::_PC_FILESIZEBITS, /// Maximum number of links to a single file. LINK_MAX = libc::_PC_LINK_MAX, @@ -2035,86 +2043,62 @@ pub enum PathconfVar { /// a pipe. PIPE_BUF = libc::_PC_PIPE_BUF, #[cfg(any( - target_os = "android", + linux_android, + solarish, + netbsdlike, target_os = "dragonfly", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Symbolic links can be created. POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum number of bytes of storage actually allocated for any portion of /// a file. POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + freebsdlike, + linux_android, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended increment for file transfer sizes between the /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum recommended file transfer size. POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum recommended file transfer size. POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended file transfer buffer alignment. POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", + linux_android, + freebsdlike, + solarish, + netbsdlike, target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum number of bytes in a symbolic link. SYMLINK_MAX = libc::_PC_SYMLINK_MAX, /// The use of `chown` and `fchown` is restricted to a process with @@ -2128,50 +2112,36 @@ pub enum PathconfVar { /// disable terminal special character handling. _POSIX_VDISABLE = libc::_PC_VDISABLE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", + linux_android, + freebsdlike, + solarish, target_os = "openbsd", target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Asynchronous input or output operations may be performed for the /// associated file. _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", + linux_android, + freebsdlike, + solarish, target_os = "openbsd", target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Prioritized input or output operations may be performed for the /// associated file. _POSIX_PRIO_IO = libc::_PC_PRIO_IO, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", + linux_android, + freebsdlike, + solarish, + netbsdlike, target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Synchronized input or output operations may be performed for the /// associated file. _POSIX_SYNC_IO = libc::_PC_SYNC_IO, #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The resolution in nanoseconds for all file timestamps. _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION, } @@ -2192,13 +2162,13 @@ pub enum PathconfVar { /// - `Ok(None)`: the variable has no limit (for limit variables) or is /// unsupported (for option variables) /// - `Err(x)`: an error occurred -pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result> { +pub fn fpathconf(fd: F, var: PathconfVar) -> Result> { let raw = unsafe { Errno::clear(); - libc::fpathconf(fd, var as c_int) + libc::fpathconf(fd.as_fd().as_raw_fd(), var as c_int) }; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -2238,7 +2208,7 @@ pub fn pathconf( libc::pathconf(cstr.as_ptr(), var as c_int) })?; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -2275,23 +2245,17 @@ pub enum SysconfVar { /// Maximum number of I/O operations in a single list I/O call supported by /// the implementation. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, /// Maximum number of outstanding asynchronous I/O operations supported by /// the implementation. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] AIO_MAX = libc::_SC_AIO_MAX, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum amount by which a process can decrease its asynchronous I/O /// priority level from its own scheduling priority. AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX, @@ -2299,68 +2263,47 @@ pub enum SysconfVar { ARG_MAX = libc::_SC_ARG_MAX, /// Maximum number of functions that may be registered with `atexit`. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] ATEXIT_MAX = libc::_SC_ATEXIT_MAX, /// Maximum obase values allowed by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_BASE_MAX = libc::_SC_BC_BASE_MAX, /// Maximum number of elements permitted in an array by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_DIM_MAX = libc::_SC_BC_DIM_MAX, /// Maximum scale value allowed by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, /// Maximum length of a string constant accepted by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_STRING_MAX = libc::_SC_BC_STRING_MAX, /// Maximum number of simultaneous processes per real user ID. CHILD_MAX = libc::_SC_CHILD_MAX, - // The number of clock ticks per second. + /// The frequency of the statistics clock in ticks per second. CLK_TCK = libc::_SC_CLK_TCK, /// Maximum number of weights that can be assigned to an entry of the /// LC_COLLATE order keyword in the locale definition file #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, /// Maximum number of timer expiration overruns. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, /// Maximum number of expressions that can be nested within parentheses by /// the expr utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// Maximum length of a host name (not including the terminating null) as /// returned from the `gethostname` function HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, /// Maximum number of iovec structures that one process has available for /// use with `readv` or `writev`. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IOV_MAX = libc::_SC_IOV_MAX, /// Unless otherwise noted, the maximum length, in bytes, of a utility's /// input line (either standard input or another file), when the utility is /// described as processing text files. The length includes room for the /// trailing newline. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] LINE_MAX = libc::_SC_LINE_MAX, /// Maximum length of a login name. #[cfg(not(target_os = "haiku"))] @@ -2369,308 +2312,176 @@ pub enum SysconfVar { NGROUPS_MAX = libc::_SC_NGROUPS_MAX, /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, /// The maximum number of open message queue descriptors a process may hold. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, /// The maximum number of message priorities supported by the implementation. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, /// A value one greater than the maximum value that the system may assign to /// a newly-created file descriptor. OPEN_MAX = libc::_SC_OPEN_MAX, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Advisory Information option. _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// The implementation supports barriers. _POSIX_BARRIERS = libc::_SC_BARRIERS, /// The implementation supports asynchronous input and output. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// The implementation supports clock selection. _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// The implementation supports the Process CPU-Time Clocks option. _POSIX_CPUTIME = libc::_SC_CPUTIME, /// The implementation supports the File Synchronization option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_FSYNC = libc::_SC_FSYNC, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + freebsdlike, + apple_targets, + solarish, target_os = "linux", - target_os = "macos", target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the IPv6 option. _POSIX_IPV6 = libc::_SC_IPV6, /// The implementation supports job control. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, /// The implementation supports memory mapped Files. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, /// The implementation supports the Process Memory Locking option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK = libc::_SC_MEMLOCK, /// The implementation supports the Range Memory Locking option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, /// The implementation supports memory protection. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, /// The implementation supports the Message Passing option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, /// The implementation supports the Monotonic Clock option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + solarish, + apple_targets, target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Prioritized Input and Output option. _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, /// The implementation supports the Process Scheduling option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + freebsdlike, + solarish, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Raw Sockets option. _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + bsd, + solarish, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports read-write locks. _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports realtime signals. _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + bsd, + solarish, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Regular Expression Handling option. _POSIX_REGEXP = libc::_SC_REGEXP, /// Each process has a saved set-user-ID and a saved set-group-ID. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, /// The implementation supports semaphores. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, /// The implementation supports the Shared Memory Objects option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux",))] /// The implementation supports the POSIX shell. _POSIX_SHELL = libc::_SC_SHELL, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux",))] /// The implementation supports the Spawn option. _POSIX_SPAWN = libc::_SC_SPAWN, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux",))] /// The implementation supports spin locks. _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Process Sporadic Server option. _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, + /// The number of replenishment operations that can be simultaneously pending for a particular + /// sporadic server scheduler. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, /// The implementation supports the Synchronized Input and Output option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, /// The implementation supports the Thread Stack Address Attribute option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, /// The implementation supports the Thread Stack Size Attribute option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" + netbsdlike, ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread CPU-Time Clocks option. _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, /// The implementation supports the Non-Robust Mutex Priority Inheritance /// option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, /// The implementation supports the Non-Robust Mutex Priority Protection option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, /// The implementation supports the Thread Execution Scheduling option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Thread Process-Shared Synchronization /// option. _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, @@ -2679,7 +2490,6 @@ pub enum SysconfVar { target_os = "linux", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Inheritance option. _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, #[cfg(any( @@ -2687,484 +2497,319 @@ pub enum SysconfVar { target_os = "linux", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Protection option. _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, /// The implementation supports thread-safe functions. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread Sporadic Server option. _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, /// The implementation supports threads. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREADS = libc::_SC_THREADS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports timeouts. _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, /// The implementation supports timers. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TIMERS = libc::_SC_TIMERS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace option. _POSIX_TRACE = libc::_SC_TRACE, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Event Filter option. _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, + /// Maximum size of a trace event name in characters. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Inherit option. _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Log option. _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, + /// The length in bytes of a trace generation version string or a trace stream name. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, + /// Maximum number of times `posix_trace_create` may be called from the same or different + /// processes. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, + /// Maximum number of user trace event type identifiers for a single process. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Typed Memory Objects option. _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, /// Integer value indicating version of this standard (C-language binding) /// to which the implementation conforms. For implementations conforming to /// POSIX.1-2008, the value shall be 200809L. _POSIX_VERSION = libc::_SC_VERSION, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, `pointer`, and `off_t` types. _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at /// least 64 bits. _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with an /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types /// using at least 64 bits. _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, /// The implementation supports the C-Language Binding option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_BIND = libc::_SC_2_C_BIND, /// The implementation supports the C-Language Development Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_DEV = libc::_SC_2_C_DEV, /// The implementation supports the Terminal Characteristics option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, /// The implementation supports the FORTRAN Development Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, /// The implementation supports the FORTRAN Runtime Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, /// The implementation supports the creation of locales by the localedef /// utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Environment Services and Utilities /// option. _POSIX2_PBS = libc::_SC_2_PBS, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Accounting option. _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Checkpoint/Restart option. _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Locate Batch Job Request option. _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Job Message Request option. _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Track Batch Job Request option. _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, /// The implementation supports the Software Development Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, /// The implementation supports the User Portability Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_UPE = libc::_SC_2_UPE, /// Integer value indicating version of the Shell and Utilities volume of /// POSIX.1 to which the implementation conforms. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_VERSION = libc::_SC_2_VERSION, /// The size of a system page in bytes. /// /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two /// enum constants to have the same value, so nix omits `PAGESIZE`. PAGE_SIZE = libc::_SC_PAGE_SIZE, + /// Maximum number of attempts made to destroy a thread's thread-specific data values on thread + /// exit. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, + /// Maximum number of data keys that can be created by a process. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, + /// Minimum size in bytes of thread stack storage. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, + /// Maximum number of threads that can be created per process. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, + /// The maximum number of repeated occurrences of a regular expression permitted when using + /// interval notation. #[cfg(not(target_os = "haiku"))] RE_DUP_MAX = libc::_SC_RE_DUP_MAX, + /// Maximum number of realtime signals reserved for application use. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] RTSIG_MAX = libc::_SC_RTSIG_MAX, + /// Maximum number of semaphores that a process may have. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, + /// The maximum value a semaphore may have. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, + /// Maximum number of queued signals that a process may send and have pending at the + /// receiver(s) at any time. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, + /// The minimum maximum number of streams that a process may have open at any one time. STREAM_MAX = libc::_SC_STREAM_MAX, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Maximum number of symbolic links that can be reliably traversed in the resolution of a + /// pathname in the absence of a loop. + #[cfg(any(bsd, target_os = "linux"))] SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, + /// Maximum number of timers per process supported. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] TIMER_MAX = libc::_SC_TIMER_MAX, + /// Maximum length of terminal device name. TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, + /// The minimum maximum number of types supported for the name of a timezone. TZNAME_MAX = libc::_SC_TZNAME_MAX, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Encryption Option Group. _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Issue 4, Version 2 Enhanced /// Internationalization Option Group. _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the XOpen Legacy Option group. + /// + /// See Also _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Option Group. _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Threads Option Group. _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, /// The implementation supports the Issue 4, Version 2 Shared Memory Option /// Group. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _XOPEN_SHM = libc::_SC_XOPEN_SHM, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI STREAMS Option Group. _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI option _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Integer value indicating version of the X/Open Portability Guide to /// which the implementation conforms. _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, /// The number of pages of physical memory. Note that it is possible for /// the product of this value to overflow. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _PHYS_PAGES = libc::_SC_PHYS_PAGES, /// The number of currently available pages of physical memory. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES, /// The number of processors configured. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF, /// The number of processors currently online (available). - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN, } @@ -3190,7 +2835,7 @@ pub fn sysconf(var: SysconfVar) -> Result> { libc::sysconf(var as c_int) }; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -3201,12 +2846,15 @@ pub fn sysconf(var: SysconfVar) -> Result> { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "fs")] mod pivot_root { use crate::errno::Errno; use crate::{NixPath, Result}; + /// Change the root file system. + /// + /// See Also [`pivot_root`](https://man7.org/linux/man-pages/man2/pivot_root.2.html) pub fn pivot_root( new_root: &P1, put_old: &P2, @@ -3225,13 +2873,7 @@ mod pivot_root { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] mod setres { feature! { #![feature = "user"] @@ -3276,13 +2918,7 @@ mod setres { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] mod getres { feature! { #![feature = "user"] @@ -3294,16 +2930,22 @@ mod getres { /// Real, effective and saved user IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ResUid { + /// Real UID pub real: Uid, + /// Effective UID pub effective: Uid, + /// Saved UID pub saved: Uid, } /// Real, effective and saved group IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ResGid { + /// Real GID pub real: Gid, + /// Effective GID pub effective: Gid, + /// Saved GID pub saved: Gid, } @@ -3318,9 +2960,9 @@ mod getres { /// #[inline] pub fn getresuid() -> Result { - let mut ruid = libc::uid_t::max_value(); - let mut euid = libc::uid_t::max_value(); - let mut suid = libc::uid_t::max_value(); + let mut ruid = libc::uid_t::MAX; + let mut euid = libc::uid_t::MAX; + let mut suid = libc::uid_t::MAX; let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) }; Errno::result(res).map(|_| ResUid { @@ -3341,9 +2983,9 @@ mod getres { /// #[inline] pub fn getresgid() -> Result { - let mut rgid = libc::gid_t::max_value(); - let mut egid = libc::gid_t::max_value(); - let mut sgid = libc::gid_t::max_value(); + let mut rgid = libc::gid_t::MAX; + let mut egid = libc::gid_t::MAX; + let mut sgid = libc::gid_t::MAX; let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) }; Errno::result(res).map(|_| ResGid { @@ -3355,6 +2997,62 @@ mod getres { } } +#[cfg(feature = "process")] +#[cfg(target_os = "freebsd")] +libc_bitflags! { + /// Flags for [`rfork`] + /// + /// subset of flags supported by FreeBSD 12.x and onwards + /// with a safe outcome, thus as `RFMEM` can possibly lead to undefined behavior, + /// it is not in the list. And `rfork_thread` is deprecated. + pub struct RforkFlags: libc::c_int { + /// creates a new process. + RFPROC; + /// the child process will detach from the parent. + /// however, no status will be emitted at child's exit. + RFNOWAIT; + /// the file descriptor's table will be copied + RFFDG; + /// a new file descriptor's table will be created + RFCFDG; + /// force sharing the sigacts structure between + /// the child and the parent. + RFSIGSHARE; + /// enables kernel thread support. + RFTHREAD; + /// sets a status to emit at child's exit. + RFTSIGZMB; + /// linux's behavior compatibility setting. + /// emits SIGUSR1 as opposed to SIGCHLD upon child's exit. + RFLINUXTHPN; + } +} + +feature! { +#![feature = "process"] +#[cfg(target_os = "freebsd")] +/// Like [`fork`], `rfork` can be used to have a tigher control about which +/// resources child and parent process will be sharing, file descriptors, +/// address spaces and child exit's behavior. +/// +/// # Safety +/// +/// The same restrictions apply as for [`fork`]. +/// +/// # See Also +/// +/// * [rfork(2)](https://man.freebsd.org/cgi/man.cgi?query=rfork) +pub unsafe fn rfork(flags: RforkFlags) -> Result { + use ForkResult::*; + let res = unsafe { libc::rfork(flags.bits()) }; + + Errno::result(res).map(|res| match res { + 0 => Child, + res => Parent { child: Pid(res) }, + }) +} +} + #[cfg(feature = "fs")] libc_bitflags! { /// Options for access() @@ -3419,9 +3117,8 @@ pub fn faccessat( /// * [FreeBSD man page](https://www.freebsd.org/cgi/man.cgi?query=eaccess&sektion=2&n=1) /// * [Linux man page](https://man7.org/linux/man-pages/man3/euidaccess.3.html) #[cfg(any( + freebsdlike, all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" ))] pub fn eaccess(path: &P, mode: AccessFlags) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { @@ -3460,39 +3157,33 @@ pub struct User { pub shell: PathBuf, /// Login class #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub class: CString, /// Last password change #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub change: libc::time_t, /// Expiration time of account #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub expire: libc::time_t, } @@ -3539,34 +3230,31 @@ impl From<&libc::passwd> for User { uid: Uid::from_raw(pw.pw_uid), gid: Gid::from_raw(pw.pw_gid), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()) .unwrap(), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] change: pw.pw_change, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] expire: pw.pw_expire, } @@ -3602,40 +3290,37 @@ impl From for libc::passwd { pw_uid: u.uid.0, pw_gid: u.gid.0, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_class: u.class.into_raw(), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_change: u.change, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_expire: u.expire, - #[cfg(target_os = "illumos")] + #[cfg(solarish)] pw_age: CString::new("").unwrap().into_raw(), - #[cfg(target_os = "illumos")] + #[cfg(solarish)] pw_comment: CString::new("").unwrap().into_raw(), - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg(freebsdlike)] pw_fields: 0, } } @@ -3680,7 +3365,7 @@ impl User { } else { // SAFETY: `f` guarantees that `pwd` is initialized if `res` // is not null. - let pwd = pwd.assume_init(); + let pwd = unsafe { pwd.assume_init() }; return Ok(Some(User::from(&pwd))); } } else if Errno::last() == Errno::ERANGE { @@ -3790,18 +3475,17 @@ impl Group { let mut ret = Vec::new(); for i in 0.. { - let u = mem.offset(i); - if (*u).is_null() { + let u = unsafe { mem.offset(i).read_unaligned() }; + if u.is_null() { break; } else { - let s = CStr::from_ptr(*u).to_string_lossy().into_owned(); + let s = unsafe {CStr::from_ptr(u).to_string_lossy().into_owned()}; ret.push(s); } } ret } - /// # Safety /// /// If `f` writes to its `*mut *mut libc::group` parameter, then it must @@ -3839,7 +3523,7 @@ impl Group { } else { // SAFETY: `f` guarantees that `grp` is initialized if `res` // is not null. - let grp = grp.assume_init(); + let grp = unsafe { grp.assume_init() }; return Ok(Some(Group::from(&grp))); } } else if Errno::last() == Errno::ERANGE { @@ -3913,19 +3597,22 @@ feature! { /// Get the name of the terminal device that is open on file descriptor fd /// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)). #[cfg(not(target_os = "fuchsia"))] -pub fn ttyname(fd: RawFd) -> Result { +pub fn ttyname(fd: F) -> Result { + #[cfg(not(target_os = "hurd"))] const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first let mut buf = vec![0_u8; PATH_MAX]; - let c_buf = buf.as_mut_ptr() as *mut libc::c_char; + let c_buf = buf.as_mut_ptr().cast(); - let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; + let ret = unsafe { libc::ttyname_r(fd.as_fd().as_raw_fd(), c_buf, buf.len()) }; if ret != 0 { - return Err(Errno::from_i32(ret)); + return Err(Errno::from_raw(ret)); } - let nul = buf.iter().position(|c| *c == b'\0').unwrap(); - buf.truncate(nul); - Ok(OsString::from_vec(buf).into()) + CStr::from_bytes_until_nul(&buf[..]) + .map(|s| OsStr::from_bytes(s.to_bytes()).into()) + .map_err(|_| Errno::EINVAL) } } @@ -3935,19 +3622,12 @@ feature! { /// Get the effective user ID and group ID associated with a Unix domain socket. /// /// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid) -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", -))] -pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { +#[cfg(bsd)] +pub fn getpeereid(fd: F) -> Result<(Uid, Gid)> { let mut uid = 1; let mut gid = 1; - let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) }; + let ret = unsafe { libc::getpeereid(fd.as_fd().as_raw_fd(), &mut uid, &mut gid) }; Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) } @@ -3959,14 +3639,7 @@ feature! { /// Set the file flags. /// /// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2) -#[cfg(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" -))] +#[cfg(bsd)] pub fn chflags(path: &P, flags: FileFlag) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::chflags(cstr.as_ptr(), flags.bits()) diff --git a/third_party/rust/nix/test/common/mod.rs b/third_party/rust/nix/test/common/mod.rs index bb056aab87..db4aed2598 100644 --- a/third_party/rust/nix/test/common/mod.rs +++ b/third_party/rust/nix/test/common/mod.rs @@ -2,18 +2,18 @@ use cfg_if::cfg_if; #[macro_export] macro_rules! skip { - ($($reason: expr),+) => { + ($($reason: expr),+) => {{ use ::std::io::{self, Write}; let stderr = io::stderr(); let mut handle = stderr.lock(); writeln!(handle, $($reason),+).unwrap(); return; - } + }} } cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { #[macro_export] macro_rules! require_capability { ($name:expr, $capname:ident) => { use ::caps::{Capability, CapSet, has_cap}; @@ -51,7 +51,7 @@ macro_rules! require_mount { }; } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[macro_export] macro_rules! skip_if_cirrus { ($reason:expr) => { @@ -87,7 +87,7 @@ macro_rules! skip_if_not_root { } cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { #[macro_export] macro_rules! skip_if_seccomp { ($name:expr) => { if let Ok(s) = std::fs::read_to_string("/proc/self/status") { diff --git a/third_party/rust/nix/test/sys/mod.rs b/third_party/rust/nix/test/sys/mod.rs index 20312120a6..fb3f6be0e5 100644 --- a/third_party/rust/nix/test/sys/mod.rs +++ b/third_party/rust/nix/test/sys/mod.rs @@ -7,16 +7,16 @@ mod test_signal; // cases on DragonFly. #[cfg(any( target_os = "freebsd", - target_os = "ios", + apple_targets, all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", target_os = "netbsd" ))] mod test_aio; #[cfg(not(any( target_os = "redox", target_os = "fuchsia", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" )))] mod test_ioctl; #[cfg(not(target_os = "redox"))] @@ -30,7 +30,7 @@ mod test_socket; #[cfg(not(any(target_os = "redox")))] mod test_sockopt; mod test_stat; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_sysinfo; #[cfg(not(any( target_os = "redox", @@ -41,20 +41,44 @@ mod test_termios; mod test_uio; mod test_wait; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_epoll; #[cfg(target_os = "linux")] +mod test_fanotify; +#[cfg(target_os = "linux")] mod test_inotify; mod test_pthread; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] + +#[cfg(any(linux_android, freebsdlike, netbsdlike, apple_targets))] mod test_ptrace; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_timerfd; + +#[cfg(all( + any( + target_os = "freebsd", + solarish, + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" +))] +mod test_timer; + +#[cfg(bsd)] +mod test_event; +mod test_statvfs; +mod test_time; +mod test_utsname; + +#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))] +mod test_statfs; + +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + solarish, + target_os = "haiku" +)))] +mod test_resource; diff --git a/third_party/rust/nix/test/sys/test_aio.rs b/third_party/rust/nix/test/sys/test_aio.rs index 5035b5a08f..ba5ad02ec3 100644 --- a/third_party/rust/nix/test/sys/test_aio.rs +++ b/third_party/rust/nix/test/sys/test_aio.rs @@ -67,7 +67,7 @@ mod aio_fsync { // Skip on Linux, because Linux's AIO implementation can't detect errors // synchronously #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] + #[cfg(any(target_os = "freebsd", apple_targets))] fn error() { use std::mem; @@ -157,7 +157,7 @@ mod aio_read { // Skip on Linux, because Linux's AIO implementation can't detect errors // synchronously #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] + #[cfg(any(target_os = "freebsd", apple_targets))] fn error() { const INITIAL: &[u8] = b"abcdef123456"; let mut rbuf = vec![0; 4]; @@ -411,7 +411,7 @@ mod aio_write { // Skip on Linux, because Linux's AIO implementation can't detect errors // synchronously #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] + #[cfg(any(target_os = "freebsd", apple_targets))] fn error() { let wbuf = "CDEF".to_string().into_bytes(); let mut aiow = Box::pin(AioWrite::new( @@ -498,7 +498,9 @@ mod aio_writev { any( all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", - target_arch = "mips64" + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" ), ignore )] @@ -567,12 +569,6 @@ fn test_aio_cancel_all() { } #[test] -// On Cirrus on Linux, this test fails due to a glibc bug. -// https://github.com/nix-rust/nix/issues/1099 -#[cfg_attr(target_os = "linux", ignore)] -// On Cirrus, aio_suspend is failing with EINVAL -// https://github.com/nix-rust/nix/issues/1361 -#[cfg_attr(target_os = "macos", ignore)] fn test_aio_suspend() { const INITIAL: &[u8] = b"abcdef123456"; const WBUF: &[u8] = b"CDEFG"; @@ -622,3 +618,53 @@ fn test_aio_suspend() { assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len()); assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen); } + +/// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb +/// pointers. This test ensures that such casts are valid. +#[test] +fn casting() { + let sev = SigevNotify::SigevNone; + let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev); + assert_eq!( + aiof.as_ref() as *const libc::aiocb, + &aiof as *const AioFsync as *const libc::aiocb + ); + + let mut rbuf = []; + let aior = AioRead::new(666, 0, &mut rbuf, 0, sev); + assert_eq!( + aior.as_ref() as *const libc::aiocb, + &aior as *const AioRead as *const libc::aiocb + ); + + let wbuf = []; + let aiow = AioWrite::new(666, 0, &wbuf, 0, sev); + assert_eq!( + aiow.as_ref() as *const libc::aiocb, + &aiow as *const AioWrite as *const libc::aiocb + ); +} + +#[cfg(target_os = "freebsd")] +#[test] +fn casting_vectored() { + use std::io::{IoSlice, IoSliceMut}; + + let sev = SigevNotify::SigevNone; + + let mut rbuf = []; + let mut rbufs = [IoSliceMut::new(&mut rbuf)]; + let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev); + assert_eq!( + aiorv.as_ref() as *const libc::aiocb, + &aiorv as *const AioReadv as *const libc::aiocb + ); + + let wbuf = []; + let wbufs = [IoSlice::new(&wbuf)]; + let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev); + assert_eq!( + aiowv.as_ref() as *const libc::aiocb, + &aiowv as *const AioWritev as *const libc::aiocb + ); +} diff --git a/third_party/rust/nix/test/sys/test_aio_drop.rs b/third_party/rust/nix/test/sys/test_aio_drop.rs index bbe6623fd7..54106dd168 100644 --- a/third_party/rust/nix/test/sys/test_aio_drop.rs +++ b/third_party/rust/nix/test/sys/test_aio_drop.rs @@ -8,8 +8,7 @@ not(target_env = "uclibc"), any( target_os = "linux", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ) diff --git a/third_party/rust/nix/test/sys/test_event.rs b/third_party/rust/nix/test/sys/test_event.rs new file mode 100644 index 0000000000..a10b1e5d12 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_event.rs @@ -0,0 +1,41 @@ +use libc::intptr_t; +use nix::sys::event::{EventFilter, EventFlag, FilterFlag, KEvent}; + +#[test] +fn test_struct_kevent() { + use std::mem; + + let udata: intptr_t = 12345; + let data: intptr_t = 0x1337; + + let actual = KEvent::new( + 0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + data, + udata, + ); + assert_eq!(0xdead_beef, actual.ident()); + assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); + assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); + assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); + assert_eq!(data, actual.data()); + assert_eq!(udata, actual.udata()); + assert_eq!(mem::size_of::(), mem::size_of::()); +} + +#[test] +fn test_kevent_filter() { + let udata: intptr_t = 12345; + + let actual = KEvent::new( + 0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + 0x1337, + udata, + ); + assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); +} diff --git a/third_party/rust/nix/test/sys/test_fanotify.rs b/third_party/rust/nix/test/sys/test_fanotify.rs new file mode 100644 index 0000000000..20226c272a --- /dev/null +++ b/third_party/rust/nix/test/sys/test_fanotify.rs @@ -0,0 +1,149 @@ +use crate::*; +use nix::sys::fanotify::{ + EventFFlags, Fanotify, FanotifyResponse, InitFlags, MarkFlags, MaskFlags, + Response, +}; +use std::fs::{read_link, File, OpenOptions}; +use std::io::ErrorKind; +use std::io::{Read, Write}; +use std::os::fd::AsRawFd; +use std::thread; + +#[test] +/// Run fanotify tests sequentially to avoid tmp files races +pub fn test_fanotify() { + require_capability!("test_fanotify", CAP_SYS_ADMIN); + + test_fanotify_notifications(); + test_fanotify_responses(); +} + +fn test_fanotify_notifications() { + let group = + Fanotify::init(InitFlags::FAN_CLASS_NOTIF, EventFFlags::O_RDONLY) + .unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + let tempfile = tempdir.path().join("test"); + OpenOptions::new() + .write(true) + .create_new(true) + .open(&tempfile) + .unwrap(); + + group + .mark( + MarkFlags::FAN_MARK_ADD, + MaskFlags::FAN_OPEN | MaskFlags::FAN_MODIFY | MaskFlags::FAN_CLOSE, + None, + Some(&tempfile), + ) + .unwrap(); + + // modify test file + { + let mut f = OpenOptions::new().write(true).open(&tempfile).unwrap(); + f.write_all(b"hello").unwrap(); + } + + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!( + event.mask(), + MaskFlags::FAN_OPEN + | MaskFlags::FAN_MODIFY + | MaskFlags::FAN_CLOSE_WRITE + ); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); + + // read test file + { + let mut f = File::open(&tempfile).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + } + + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!( + event.mask(), + MaskFlags::FAN_OPEN | MaskFlags::FAN_CLOSE_NOWRITE + ); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); +} + +fn test_fanotify_responses() { + let group = + Fanotify::init(InitFlags::FAN_CLASS_CONTENT, EventFFlags::O_RDONLY) + .unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + let tempfile = tempdir.path().join("test"); + OpenOptions::new() + .write(true) + .create_new(true) + .open(&tempfile) + .unwrap(); + + group + .mark( + MarkFlags::FAN_MARK_ADD, + MaskFlags::FAN_OPEN_PERM, + None, + Some(&tempfile), + ) + .unwrap(); + + let file_thread = thread::spawn({ + let tempfile = tempfile.clone(); + + move || { + // first open, should fail + let Err(e) = File::open(&tempfile) else { + panic!("The first open should fail"); + }; + assert_eq!(e.kind(), ErrorKind::PermissionDenied); + + // second open, should succeed + File::open(&tempfile).unwrap(); + } + }); + + // Deny the first open try + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); + group + .write_response(FanotifyResponse::new(*fd, Response::FAN_DENY)) + .unwrap(); + + // Allow the second open try + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); + group + .write_response(FanotifyResponse::new(*fd, Response::FAN_ALLOW)) + .unwrap(); + + file_thread.join().unwrap(); +} diff --git a/third_party/rust/nix/test/sys/test_ioctl.rs b/third_party/rust/nix/test/sys/test_ioctl.rs index 40f60cfdbc..08843bf61c 100644 --- a/third_party/rust/nix/test/sys/test_ioctl.rs +++ b/third_party/rust/nix/test/sys/test_ioctl.rs @@ -28,7 +28,7 @@ ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); // TODO: Need a way to compute these constants at test time. Using precomputed // values is fragile and needs to be maintained. -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] mod linux { // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] @@ -36,7 +36,9 @@ mod linux { fn test_op_none() { if cfg!(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64" )) { @@ -54,7 +56,9 @@ mod linux { fn test_op_write() { if cfg!(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64" )) { @@ -69,7 +73,11 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_write_64() { - if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + if cfg!(any( + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "powerpc64" + )) { assert_eq!( request_code_write!(b'z', 10, 1u64 << 32) as u32, 0x8000_7A0A @@ -88,7 +96,9 @@ mod linux { fn test_op_read() { if cfg!(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64" )) { @@ -103,7 +113,11 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_read_64() { - if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + if cfg!(any( + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "powerpc64" + )) { assert_eq!( request_code_read!(b'z', 10, 1u64 << 32) as u32, 0x4000_7A0A @@ -134,14 +148,7 @@ mod linux { } } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] mod bsd { #[test] fn test_op_none() { @@ -149,7 +156,7 @@ mod bsd { assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); } - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg(freebsdlike)] #[test] fn test_op_write_int() { assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604); @@ -193,7 +200,7 @@ mod bsd { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod linux_ioctls { use std::mem; use std::os::unix::io::AsRawFd; diff --git a/third_party/rust/nix/test/sys/test_mman.rs b/third_party/rust/nix/test/sys/test_mman.rs index b4674e53fa..3689f642be 100644 --- a/third_party/rust/nix/test/sys/test_mman.rs +++ b/third_party/rust/nix/test/sys/test_mman.rs @@ -1,44 +1,44 @@ -use nix::sys::mman::{mmap, MapFlags, ProtFlags}; -use std::{num::NonZeroUsize, os::unix::io::BorrowedFd}; +#![allow(clippy::redundant_slicing)] + +use nix::sys::mman::{mmap_anonymous, MapFlags, ProtFlags}; +use std::num::NonZeroUsize; #[test] fn test_mmap_anonymous() { unsafe { - let ptr = mmap::( + let mut ptr = mmap_anonymous( None, NonZeroUsize::new(1).unwrap(), ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, - None, - 0, + MapFlags::MAP_PRIVATE, ) - .unwrap() as *mut u8; - assert_eq!(*ptr, 0x00u8); - *ptr = 0xffu8; - assert_eq!(*ptr, 0xffu8); + .unwrap() + .cast::(); + assert_eq!(*ptr.as_ref(), 0x00u8); + *ptr.as_mut() = 0xffu8; + assert_eq!(*ptr.as_ref(), 0xffu8); } } #[test] #[cfg(any(target_os = "linux", target_os = "netbsd"))] fn test_mremap_grow() { - use nix::libc::{c_void, size_t}; + use nix::libc::size_t; use nix::sys::mman::{mremap, MRemapFlags}; + use std::ptr::NonNull; const ONE_K: size_t = 1024; let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap(); let slice: &mut [u8] = unsafe { - let mem = mmap::( + let mem = mmap_anonymous( None, one_k_non_zero, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - None, - 0, + MapFlags::MAP_PRIVATE, ) .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) }; assert_eq!(slice[ONE_K - 1], 0x00); slice[ONE_K - 1] = 0xFF; @@ -47,7 +47,7 @@ fn test_mremap_grow() { let slice: &mut [u8] = unsafe { #[cfg(target_os = "linux")] let mem = mremap( - slice.as_mut_ptr() as *mut c_void, + NonNull::from(&mut slice[..]).cast(), ONE_K, 10 * ONE_K, MRemapFlags::MREMAP_MAYMOVE, @@ -56,14 +56,14 @@ fn test_mremap_grow() { .unwrap(); #[cfg(target_os = "netbsd")] let mem = mremap( - slice.as_mut_ptr() as *mut c_void, + NonNull::from(&mut slice[..]).cast(), ONE_K, 10 * ONE_K, MRemapFlags::MAP_REMAPDUP, None, ) .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K) + std::slice::from_raw_parts_mut(mem.cast().as_ptr(), 10 * ONE_K) }; // The first KB should still have the old data in it. @@ -80,23 +80,22 @@ fn test_mremap_grow() { // Segfaults for unknown reasons under QEMU for 32-bit targets #[cfg_attr(all(target_pointer_width = "32", qemu), ignore)] fn test_mremap_shrink() { - use nix::libc::{c_void, size_t}; + use nix::libc::size_t; use nix::sys::mman::{mremap, MRemapFlags}; use std::num::NonZeroUsize; + use std::ptr::NonNull; const ONE_K: size_t = 1024; let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap(); let slice: &mut [u8] = unsafe { - let mem = mmap::( + let mem = mmap_anonymous( None, ten_one_k, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - None, - 0, + MapFlags::MAP_PRIVATE, ) .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) }; assert_eq!(slice[ONE_K - 1], 0x00); slice[ONE_K - 1] = 0xFF; @@ -104,7 +103,7 @@ fn test_mremap_shrink() { let slice: &mut [u8] = unsafe { let mem = mremap( - slice.as_mut_ptr() as *mut c_void, + NonNull::from(&mut slice[..]).cast(), ten_one_k.into(), ONE_K, MRemapFlags::empty(), @@ -113,8 +112,8 @@ fn test_mremap_shrink() { .unwrap(); // Since we didn't supply MREMAP_MAYMOVE, the address should be the // same. - assert_eq!(mem, slice.as_mut_ptr() as *mut c_void); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + assert_eq!(mem.as_ptr(), NonNull::from(&mut slice[..]).cast().as_ptr()); + std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) }; // The first KB should still be accessible and have the old data in it. diff --git a/third_party/rust/nix/test/sys/test_ptrace.rs b/third_party/rust/nix/test/sys/test_ptrace.rs index 530560fe17..246b35445d 100644 --- a/third_party/rust/nix/test/sys/test_ptrace.rs +++ b/third_party/rust/nix/test/sys/test_ptrace.rs @@ -6,11 +6,11 @@ use memoffset::offset_of; use nix::errno::Errno; use nix::sys::ptrace; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use nix::sys::ptrace::Options; use nix::unistd::getpid; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use std::mem; use crate::*; @@ -28,7 +28,7 @@ fn test_ptrace() { // Just make sure ptrace_setoptions can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_setoptions() { require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD) @@ -38,7 +38,7 @@ fn test_ptrace_setoptions() { // Just make sure ptrace_getevent can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_getevent() { require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE); let err = ptrace::getevent(getpid()).unwrap_err(); @@ -47,7 +47,7 @@ fn test_ptrace_getevent() { // Just make sure ptrace_getsiginfo can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_getsiginfo() { require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE); if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) { @@ -57,7 +57,7 @@ fn test_ptrace_getsiginfo() { // Just make sure ptrace_setsiginfo can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_setsiginfo() { require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE); let siginfo = unsafe { mem::zeroed() }; diff --git a/third_party/rust/nix/test/sys/test_resource.rs b/third_party/rust/nix/test/sys/test_resource.rs new file mode 100644 index 0000000000..8b12a9495b --- /dev/null +++ b/third_party/rust/nix/test/sys/test_resource.rs @@ -0,0 +1,43 @@ +use nix::sys::resource::{getrlimit, setrlimit, Resource}; +use nix::sys::resource::{getrusage, UsageWho}; + +/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers +/// to the maximum file descriptor number that can be opened by the process (aka the maximum number +/// of file descriptors that the process can open, since Linux 4.5). +/// +/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the +/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit() +/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have +/// been updated. +#[test] +pub fn test_resource_limits_nofile() { + let (mut soft_limit, hard_limit) = + getrlimit(Resource::RLIMIT_NOFILE).unwrap(); + + soft_limit -= 1; + assert_ne!(soft_limit, hard_limit); + setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); + + let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); + assert_eq!(new_soft_limit, soft_limit); +} + +#[test] +pub fn test_self_cpu_time() { + // Make sure some CPU time is used. + let mut numbers: Vec = (1..1_000_000).collect(); + numbers.iter_mut().for_each(|item| *item *= 2); + + // FIXME: this is here to help ensure the compiler does not optimize the whole + // thing away. Replace the assert with test::black_box once stabilized. + assert_eq!(numbers[100..200].iter().sum::(), 30_100); + + let usage = getrusage(UsageWho::RUSAGE_SELF) + .expect("Failed to call getrusage for SELF"); + let rusage = usage.as_ref(); + + let user = usage.user_time(); + assert!(user.tv_sec() > 0 || user.tv_usec() > 0); + assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec); + assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec); +} diff --git a/third_party/rust/nix/test/sys/test_select.rs b/third_party/rust/nix/test/sys/test_select.rs index 79f75de3b4..e39a31923a 100644 --- a/third_party/rust/nix/test/sys/test_select.rs +++ b/third_party/rust/nix/test/sys/test_select.rs @@ -1,22 +1,20 @@ use nix::sys::select::*; use nix::sys::signal::SigSet; -use nix::sys::time::{TimeSpec, TimeValLike}; +use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; use nix::unistd::{pipe, write}; -use std::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; #[test] pub fn test_pselect() { let _mtx = crate::SIGNAL_MTX.lock(); let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; let mut fd_set = FdSet::new(); - fd_set.insert(&r1); - fd_set.insert(&r2); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); let timeout = TimeSpec::seconds(10); let sigmask = SigSet::empty(); @@ -24,21 +22,19 @@ pub fn test_pselect() { 1, pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap() ); - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); } #[test] pub fn test_pselect_nfds2() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; let mut fd_set = FdSet::new(); - fd_set.insert(&r1); - fd_set.insert(&r2); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); let timeout = TimeSpec::seconds(10); assert_eq!( @@ -53,8 +49,8 @@ pub fn test_pselect_nfds2() { ) .unwrap() ); - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); } macro_rules! generate_fdset_bad_fd_tests { @@ -64,7 +60,7 @@ macro_rules! generate_fdset_bad_fd_tests { #[should_panic] fn $method() { let bad_fd = unsafe{BorrowedFd::borrow_raw($fd)}; - FdSet::new().$method(&bad_fd); + FdSet::new().$method(bad_fd); } )* } @@ -72,7 +68,6 @@ macro_rules! generate_fdset_bad_fd_tests { mod test_fdset_too_large_fd { use super::*; - use std::convert::TryInto; generate_fdset_bad_fd_tests!( FD_SETSIZE.try_into().unwrap(), insert, @@ -80,3 +75,219 @@ mod test_fdset_too_large_fd { contains, ); } + +#[test] +fn fdset_insert() { + let mut fd_set = FdSet::new(); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } + + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + fd_set.insert(fd_seven); + + assert!(fd_set.contains(fd_seven)); +} + +#[test] +fn fdset_remove() { + let mut fd_set = FdSet::new(); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } + + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + fd_set.insert(fd_seven); + fd_set.remove(fd_seven); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } +} + +#[test] +#[allow(non_snake_case)] +fn fdset_clear() { + let mut fd_set = FdSet::new(); + let fd_one = unsafe { BorrowedFd::borrow_raw(1) }; + let fd_FD_SETSIZE_divided_by_two = + unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) }; + let fd_FD_SETSIZE_minus_one = + unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) }; + fd_set.insert(fd_one); + fd_set.insert(fd_FD_SETSIZE_divided_by_two); + fd_set.insert(fd_FD_SETSIZE_minus_one); + + fd_set.clear(); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } +} + +#[test] +fn fdset_highest() { + let mut set = FdSet::new(); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + None + ); + let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; + let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; + set.insert(fd_zero); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(0) + ); + set.insert(fd_ninety); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(90) + ); + set.remove(fd_zero); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(90) + ); + set.remove(fd_ninety); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + None + ); + + let fd_four = unsafe { BorrowedFd::borrow_raw(4) }; + let fd_five = unsafe { BorrowedFd::borrow_raw(5) }; + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + set.insert(fd_four); + set.insert(fd_five); + set.insert(fd_seven); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(7) + ); +} + +#[test] +fn fdset_fds() { + let mut set = FdSet::new(); + let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; + let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![] + ); + set.insert(fd_zero); + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0] + ); + set.insert(fd_ninety); + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0, 90] + ); + + // highest limit + assert_eq!( + set.fds(Some(89)) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0] + ); + assert_eq!( + set.fds(Some(90)) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0, 90] + ); +} + +#[test] +fn test_select() { + let (r1, w1) = pipe().unwrap(); + let (r2, _w2) = pipe().unwrap(); + + write(&w1, b"hi!").unwrap(); + let mut fd_set = FdSet::new(); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); + + let mut timeout = TimeVal::seconds(10); + assert_eq!( + 1, + select(None, &mut fd_set, None, None, &mut timeout).unwrap() + ); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); +} + +#[test] +fn test_select_nfds() { + let (r1, w1) = pipe().unwrap(); + let (r2, _w2) = pipe().unwrap(); + + write(&w1, b"hi!").unwrap(); + let mut fd_set = FdSet::new(); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); + + let mut timeout = TimeVal::seconds(10); + { + assert_eq!( + 1, + select( + Some( + fd_set + .highest() + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .unwrap() + + 1 + ), + &mut fd_set, + None, + None, + &mut timeout + ) + .unwrap() + ); + } + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); +} + +#[test] +fn test_select_nfds2() { + let (r1, w1) = pipe().unwrap(); + write(&w1, b"hi!").unwrap(); + let (r2, _w2) = pipe().unwrap(); + let mut fd_set = FdSet::new(); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); + + let mut timeout = TimeVal::seconds(10); + assert_eq!( + 1, + select( + std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1, + &mut fd_set, + None, + None, + &mut timeout + ) + .unwrap() + ); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); +} diff --git a/third_party/rust/nix/test/sys/test_signal.rs b/third_party/rust/nix/test/sys/test_signal.rs index ca25ff9ab0..bf607497be 100644 --- a/third_party/rust/nix/test/sys/test_signal.rs +++ b/third_party/rust/nix/test/sys/test_signal.rs @@ -1,9 +1,10 @@ -#[cfg(not(target_os = "redox"))] use nix::errno::Errno; use nix::sys::signal::*; use nix::unistd::*; -use std::convert::TryFrom; +use std::hash::{Hash, Hasher}; use std::sync::atomic::{AtomicBool, Ordering}; +#[cfg(not(target_os = "redox"))] +use std::thread; #[test] fn test_kill_none() { @@ -124,7 +125,7 @@ fn test_signal() { raise(Signal::SIGINT).unwrap(); assert!(SIGNALED.load(Ordering::Relaxed)); - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg(not(solarish))] assert_eq!( unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler @@ -132,7 +133,7 @@ fn test_signal() { // System V based OSes (e.g. illumos and Solaris) always resets the // disposition to SIG_DFL prior to calling the signal handler - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] assert_eq!( unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigDfl @@ -141,3 +142,314 @@ fn test_signal() { // Restore default signal handler unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); } + +#[test] +fn test_contains() { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + assert!(mask.contains(SIGUSR1)); + assert!(!mask.contains(SIGUSR2)); + + let all = SigSet::all(); + assert!(all.contains(SIGUSR1)); + assert!(all.contains(SIGUSR2)); +} + +#[test] +fn test_clear() { + let mut set = SigSet::all(); + set.clear(); + for signal in Signal::iterator() { + assert!(!set.contains(signal)); + } +} + +#[test] +fn test_from_str_round_trips() { + for signal in Signal::iterator() { + assert_eq!(signal.as_ref().parse::().unwrap(), signal); + assert_eq!(signal.to_string().parse::().unwrap(), signal); + } +} + +#[test] +fn test_from_str_invalid_value() { + let errval = Err(Errno::EINVAL); + assert_eq!("NOSIGNAL".parse::(), errval); + assert_eq!("kill".parse::(), errval); + assert_eq!("9".parse::(), errval); +} + +#[test] +fn test_extend() { + let mut one_signal = SigSet::empty(); + one_signal.add(SIGUSR1); + + let mut two_signals = SigSet::empty(); + two_signals.add(SIGUSR2); + two_signals.extend(&one_signal); + + assert!(two_signals.contains(SIGUSR1)); + assert!(two_signals.contains(SIGUSR2)); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_thread_signal_set_mask() { + thread::spawn(|| { + let prev_mask = SigSet::thread_get_mask() + .expect("Failed to get existing signal mask!"); + + let mut test_mask = prev_mask; + test_mask.add(SIGUSR1); + + test_mask.thread_set_mask().expect("assertion failed"); + let new_mask = + SigSet::thread_get_mask().expect("Failed to get new mask!"); + + assert!(new_mask.contains(SIGUSR1)); + assert!(!new_mask.contains(SIGUSR2)); + + prev_mask + .thread_set_mask() + .expect("Failed to revert signal mask!"); + }) + .join() + .unwrap(); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_thread_signal_block() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + mask.thread_block().expect("assertion failed"); + + assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); + }) + .join() + .unwrap(); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_thread_signal_unblock() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + mask.thread_unblock().expect("assertion failed"); + + assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); + }) + .join() + .unwrap(); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_thread_signal_swap() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + mask.thread_block().unwrap(); + + assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); + + let mut mask2 = SigSet::empty(); + mask2.add(SIGUSR2); + + let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap(); + + assert!(oldmask.contains(SIGUSR1)); + assert!(!oldmask.contains(SIGUSR2)); + + assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2)); + }) + .join() + .unwrap(); +} + +#[test] +fn test_from_and_into_iterator() { + let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); + let signals = sigset.into_iter().collect::>(); + assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_sigaction() { + thread::spawn(|| { + extern "C" fn test_sigaction_handler(_: libc::c_int) {} + extern "C" fn test_sigaction_action( + _: libc::c_int, + _: *mut libc::siginfo_t, + _: *mut libc::c_void, + ) { + } + + let handler_sig = SigHandler::Handler(test_sigaction_handler); + + let flags = + SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO; + + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + let action_sig = SigAction::new(handler_sig, flags, mask); + + assert_eq!( + action_sig.flags(), + SaFlags::SA_ONSTACK | SaFlags::SA_RESTART + ); + assert_eq!(action_sig.handler(), handler_sig); + + mask = action_sig.mask(); + assert!(mask.contains(SIGUSR1)); + assert!(!mask.contains(SIGUSR2)); + + let handler_act = SigHandler::SigAction(test_sigaction_action); + let action_act = SigAction::new(handler_act, flags, mask); + assert_eq!(action_act.handler(), handler_act); + + let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask); + assert_eq!(action_dfl.handler(), SigHandler::SigDfl); + + let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask); + assert_eq!(action_ign.handler(), SigHandler::SigIgn); + }) + .join() + .unwrap(); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_sigwait() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + mask.add(SIGUSR2); + mask.thread_block().unwrap(); + + raise(SIGUSR1).unwrap(); + assert_eq!(mask.wait().unwrap(), SIGUSR1); + }) + .join() + .unwrap(); +} + +#[cfg(any( + bsd, + linux_android, + solarish, + target_os = "haiku", + target_os = "hurd", + target_os = "aix", + target_os = "fushsia" +))] +#[test] +fn test_sigsuspend() { + // This test change signal handler + let _m = crate::SIGNAL_MTX.lock(); + static SIGNAL_RECIEVED: AtomicBool = AtomicBool::new(false); + extern "C" fn test_sigsuspend_handler(_: libc::c_int) { + assert!(!SIGNAL_RECIEVED.swap(true, Ordering::SeqCst)); + } + thread::spawn(|| { + const SIGNAL: Signal = Signal::SIGUSR1; + + // Add signal mask to this thread + let mut signal_set = SigSet::empty(); + signal_set.add(SIGNAL); + signal_set.thread_block().unwrap(); + + // Set signal handler and save old one. + let act = SigAction::new( + SigHandler::Handler(test_sigsuspend_handler), + SaFlags::empty(), + SigSet::empty(), + ); + let old_act = unsafe { sigaction(SIGNAL, &act) } + .expect("expect to be able to set new action and get old action"); + + raise(SIGNAL).expect("expect be able to send signal"); + // Now `SIGNAL` was sended but it is blocked. + let mut not_wait_set = SigSet::all(); + not_wait_set.remove(SIGNAL); + // signal handler must run in SigSet::suspend() + assert!(!SIGNAL_RECIEVED.load(Ordering::SeqCst)); + not_wait_set.suspend().unwrap(); + assert!(SIGNAL_RECIEVED.load(Ordering::SeqCst)); + + // Restore the signal handler. + unsafe { sigaction(SIGNAL, &old_act) } + .expect("expect to be able to restore old action "); + }) + .join() + .unwrap(); +} + +#[test] +fn test_from_sigset_t_unchecked() { + let src_set = SigSet::empty(); + let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) }; + + for signal in Signal::iterator() { + assert!(!set.contains(signal)); + } + + let src_set = SigSet::all(); + let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) }; + + for signal in Signal::iterator() { + assert!(set.contains(signal)); + } +} + +#[test] +fn test_eq_empty() { + let set0 = SigSet::empty(); + let set1 = SigSet::empty(); + assert_eq!(set0, set1); +} + +#[test] +fn test_eq_all() { + let set0 = SigSet::all(); + let set1 = SigSet::all(); + assert_eq!(set0, set1); +} + +#[test] +fn test_hash_empty() { + use std::collections::hash_map::DefaultHasher; + + let set0 = SigSet::empty(); + let mut h0 = DefaultHasher::new(); + set0.hash(&mut h0); + + let set1 = SigSet::empty(); + let mut h1 = DefaultHasher::new(); + set1.hash(&mut h1); + + assert_eq!(h0.finish(), h1.finish()); +} + +#[test] +fn test_hash_all() { + use std::collections::hash_map::DefaultHasher; + + let set0 = SigSet::all(); + let mut h0 = DefaultHasher::new(); + set0.hash(&mut h0); + + let set1 = SigSet::all(); + let mut h1 = DefaultHasher::new(); + set1.hash(&mut h1); + + assert_eq!(h0.finish(), h1.finish()); +} diff --git a/third_party/rust/nix/test/sys/test_signalfd.rs b/third_party/rust/nix/test/sys/test_signalfd.rs index 87153c9572..4e0971aba7 100644 --- a/third_party/rust/nix/test/sys/test_signalfd.rs +++ b/third_party/rust/nix/test/sys/test_signalfd.rs @@ -1,5 +1,39 @@ use std::convert::TryFrom; +#[test] +fn create_signalfd() { + use nix::sys::{signal::SigSet, signalfd::SignalFd}; + + let mask = SigSet::empty(); + SignalFd::new(&mask).unwrap(); +} + +#[test] +fn create_signalfd_with_opts() { + use nix::sys::{ + signal::SigSet, + signalfd::{SfdFlags, SignalFd}, + }; + + let mask = SigSet::empty(); + SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK) + .unwrap(); +} + +#[test] +fn read_empty_signalfd() { + use nix::sys::{ + signal::SigSet, + signalfd::{SfdFlags, SignalFd}, + }; + + let mask = SigSet::empty(); + let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); + + let res = fd.read_signal(); + assert!(res.unwrap().is_none()); +} + #[test] fn test_signalfd() { use nix::sys::signal::{self, raise, SigSet, Signal}; @@ -25,3 +59,32 @@ fn test_signalfd() { let signo = Signal::try_from(res.ssi_signo as i32).unwrap(); assert_eq!(signo, signal::SIGUSR1); } + +/// Update the signal mask of an already existing signalfd. +#[test] +fn test_signalfd_setmask() { + use nix::sys::signal::{self, raise, SigSet, Signal}; + use nix::sys::signalfd::SignalFd; + + // Grab the mutex for altering signals so we don't interfere with other tests. + let _m = crate::SIGNAL_MTX.lock(); + + // Block the SIGUSR1 signal from automatic processing for this thread + let mut mask = SigSet::empty(); + + let mut fd = SignalFd::new(&mask).unwrap(); + + mask.add(signal::SIGUSR1); + mask.thread_block().unwrap(); + fd.set_mask(&mask).unwrap(); + + // Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill` + // because `kill` with `getpid` isn't correct during multi-threaded execution like during a + // cargo test session. Instead use `raise` which does the correct thing by default. + raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed"); + + // And now catch that same signal. + let res = fd.read_signal().unwrap().unwrap(); + let signo = Signal::try_from(res.ssi_signo as i32).unwrap(); + assert_eq!(signo, signal::SIGUSR1); +} diff --git a/third_party/rust/nix/test/sys/test_socket.rs b/third_party/rust/nix/test/sys/test_socket.rs index ed1686e87d..90b8a6f528 100644 --- a/third_party/rust/nix/test/sys/test_socket.rs +++ b/third_party/rust/nix/test/sys/test_socket.rs @@ -1,4 +1,4 @@ -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] use crate::*; use libc::c_char; use nix::sys::socket::{getsockname, AddressFamily, UnixAddr}; @@ -21,7 +21,7 @@ pub fn test_timestamping() { }; use std::io::{IoSlice, IoSliceMut}; - let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); + let sock_addr = SockaddrIn::from_str("127.0.0.1:6797").unwrap(); let ssock = socket( AddressFamily::Inet, @@ -72,15 +72,134 @@ pub fn test_timestamping() { assert!(std::time::Duration::from(diff).as_secs() < 60); } +#[cfg(target_os = "freebsd")] +#[test] +pub fn test_timestamping_realtime() { + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp, + sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType, + SockaddrIn, SocketTimestamp, + }; + use std::io::{IoSlice, IoSliceMut}; + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6792").unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap(); + + setsockopt(&rsock, ReceiveTimestamp, &true).unwrap(); + setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_REALTIME).unwrap(); + + let sbuf = [0u8; 2048]; + let mut rbuf = [0u8; 2048]; + let flags = MsgFlags::empty(); + let iov1 = [IoSlice::new(&sbuf)]; + let mut iov2 = [IoSliceMut::new(&mut rbuf)]; + + let mut cmsg = cmsg_space!(nix::sys::time::TimeVal); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); + let recv = + recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags) + .unwrap(); + + let mut ts = None; + for c in recv.cmsgs() { + if let ControlMessageOwned::ScmRealtime(timeval) = c { + ts = Some(timeval); + } + } + let ts = ts.expect("ScmRealtime is present"); + let sys_time = + ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME) + .unwrap(); + let diff = if ts > sys_time { + ts - sys_time + } else { + sys_time - ts + }; + assert!(std::time::Duration::from(diff).as_secs() < 60); +} + +#[cfg(target_os = "freebsd")] +#[test] +pub fn test_timestamping_monotonic() { + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp, + sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType, + SockaddrIn, SocketTimestamp, + }; + use std::io::{IoSlice, IoSliceMut}; + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6803").unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap(); + + setsockopt(&rsock, ReceiveTimestamp, &true).unwrap(); + setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_MONOTONIC).unwrap(); + + let sbuf = [0u8; 2048]; + let mut rbuf = [0u8; 2048]; + let flags = MsgFlags::empty(); + let iov1 = [IoSlice::new(&sbuf)]; + let mut iov2 = [IoSliceMut::new(&mut rbuf)]; + + let mut cmsg = cmsg_space!(nix::sys::time::TimeVal); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); + let recv = + recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags) + .unwrap(); + + let mut ts = None; + for c in recv.cmsgs() { + if let ControlMessageOwned::ScmMonotonic(timeval) = c { + ts = Some(timeval); + } + } + let ts = ts.expect("ScmMonotonic is present"); + let sys_time = + ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_MONOTONIC) + .unwrap(); + let diff = sys_time - ts; // Monotonic clock sys_time must be greater + assert!(std::time::Duration::from(diff).as_secs() < 60); +} + #[test] pub fn test_path_to_sock_addr() { let path = "/foo/bar"; let actual = Path::new(path); let addr = UnixAddr::new(actual).unwrap(); - let expect: &[c_char] = unsafe { - slice::from_raw_parts(path.as_ptr() as *const c_char, path.len()) - }; + let expect: &[c_char] = + unsafe { slice::from_raw_parts(path.as_ptr().cast(), path.len()) }; assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect); assert_eq!(addr.path(), Some(actual)); @@ -105,7 +224,7 @@ pub fn test_addr_equality_path() { assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_abstract_sun_path_too_long() { let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough"); @@ -113,7 +232,7 @@ pub fn test_abstract_sun_path_too_long() { addr.expect_err("assertion failed"); } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_addr_equality_abstract() { let name = String::from("nix\0abstract\0test"); @@ -129,7 +248,7 @@ pub fn test_addr_equality_abstract() { } // Test getting/setting abstract addresses (without unix socket creation) -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_abstract_uds_addr() { let empty = String::new(); @@ -151,7 +270,7 @@ pub fn test_abstract_uds_addr() { } // Test getting an unnamed address (without unix socket creation) -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_unnamed_uds_addr() { use crate::nix::sys::socket::SockaddrLike; @@ -200,7 +319,7 @@ pub fn test_socketpair() { SockFlag::empty(), ) .unwrap(); - write(fd1.as_raw_fd(), b"hello").unwrap(); + write(&fd1, b"hello").unwrap(); let mut buf = [0; 5]; read(fd2.as_raw_fd(), &mut buf).unwrap(); @@ -315,7 +434,7 @@ mod recvfrom { #[test] pub fn udp() { - let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); + let std_sa = SocketAddrV4::from_str("127.0.0.1:6795").unwrap(); let sock_addr = SockaddrIn::from(std_sa); let rsock = socket( AddressFamily::Inet, @@ -437,12 +556,7 @@ mod recvfrom { } } - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[test] pub fn udp_sendmmsg() { use std::io::IoSlice; @@ -504,12 +618,7 @@ mod recvfrom { assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[test] pub fn udp_recvmmsg() { use nix::sys::socket::{recvmmsg, MsgFlags}; @@ -565,7 +674,7 @@ mod recvfrom { let res: Vec> = recvmmsg( rsock.as_raw_fd(), &mut data, - msgs.iter(), + msgs.iter_mut(), MsgFlags::empty(), None, ) @@ -585,12 +694,7 @@ mod recvfrom { send_thread.join().unwrap(); } - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[test] pub fn udp_recvmmsg_dontwait_short_read() { use nix::sys::socket::{recvmmsg, MsgFlags}; @@ -653,7 +757,7 @@ mod recvfrom { let res: Vec> = recvmmsg( rsock.as_raw_fd(), &mut data, - msgs.iter(), + msgs.iter_mut(), MsgFlags::MSG_DONTWAIT, None, ) @@ -674,10 +778,10 @@ mod recvfrom { #[test] pub fn udp_inet6() { let addr = std::net::Ipv6Addr::from_str("::1").unwrap(); - let rport = 6789; + let rport = 6796; let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0); let raddr = SockaddrIn6::from(rstd_sa); - let sport = 6790; + let sport = 6798; let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0); let saddr = SockaddrIn6::from(sstd_sa); let rsock = socket( @@ -757,7 +861,7 @@ pub fn test_scm_rights() { { let iov = [IoSlice::new(b"hello")]; - let fds = [r]; + let fds = [r.as_raw_fd()]; let cmsg = ControlMessage::ScmRights(&fds); assert_eq!( sendmsg::<()>( @@ -770,7 +874,6 @@ pub fn test_scm_rights() { .unwrap(), 5 ); - close(r).unwrap(); } { @@ -803,16 +906,15 @@ pub fn test_scm_rights() { let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w.as_raw_fd(), b"world").unwrap(); + write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; read(received_r.as_raw_fd(), &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); - close(w).unwrap(); } // Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_cipher() { @@ -905,7 +1007,7 @@ pub fn test_af_alg_cipher() { // Disable the test on emulated platforms due to not enabled support of AF_ALG // in QEMU from rust cross -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_aead() { @@ -1039,7 +1141,7 @@ pub fn test_af_alg_aead() { // This would be a more interesting test if we could assume that the test host // has more than one IP address (since we could select a different address to // test from). -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))] +#[cfg(any(target_os = "linux", apple_targets, target_os = "netbsd"))] #[test] pub fn test_sendmsg_ipv4packetinfo() { use cfg_if::cfg_if; @@ -1101,7 +1203,7 @@ pub fn test_sendmsg_ipv4packetinfo() { // test from). #[cfg(any( target_os = "linux", - target_os = "macos", + apple_targets, target_os = "netbsd", target_os = "freebsd" ))] @@ -1158,12 +1260,7 @@ pub fn test_sendmsg_ipv6packetinfo() { // // Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg // returns EINVAL otherwise. (See FreeBSD's ip(4) man page.) -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", -))] +#[cfg(any(freebsdlike, netbsdlike))] #[test] pub fn test_sendmsg_ipv4sendsrcaddr() { use nix::sys::socket::{ @@ -1302,7 +1399,7 @@ pub fn test_sendmsg_empty_cmsgs() { ) .unwrap(); - for _ in msg.cmsgs() { + if msg.cmsgs().next().is_some() { panic!("unexpected cmsg"); } assert!(!msg @@ -1312,19 +1409,14 @@ pub fn test_sendmsg_empty_cmsgs() { } } -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", -))] +#[cfg(any(linux_android, freebsdlike))] #[test] fn test_scm_credentials() { use nix::sys::socket::{ recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials, }; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] use nix::sys::socket::{setsockopt, sockopt::PassCred}; use nix::unistd::{getgid, getpid, getuid}; use std::io::{IoSlice, IoSliceMut}; @@ -1336,16 +1428,16 @@ fn test_scm_credentials() { SockFlag::empty(), ) .unwrap(); - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] setsockopt(&recv, PassCred, &true).unwrap(); { let iov = [IoSlice::new(b"hello")]; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] let cred = UnixCredentials::new(); - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] let cmsg = ControlMessage::ScmCredentials(&cred); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] let cmsg = ControlMessage::ScmCreds; assert_eq!( sendmsg::<()>( @@ -1376,9 +1468,9 @@ fn test_scm_credentials() { for cmsg in msg.cmsgs() { let cred = match cmsg { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessageOwned::ScmCredentials(cred) => cred, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessageOwned::ScmCreds(cred) => cred, other => panic!("unexpected cmsg {other:?}"), }; @@ -1398,7 +1490,7 @@ fn test_scm_credentials() { /// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single /// `sendmsg` call. -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation // see https://bugs.launchpad.net/qemu/+bug/1781280 #[cfg_attr(qemu, ignore)] @@ -1410,7 +1502,7 @@ fn test_scm_credentials_and_rights() { /// Ensure that passing a an oversized control message buffer to recvmsg /// still works. -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation // see https://bugs.launchpad.net/qemu/+bug/1781280 #[cfg_attr(qemu, ignore)] @@ -1420,7 +1512,7 @@ fn test_too_large_cmsgspace() { test_impl_scm_credentials_and_rights(space); } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_impl_scm_credentials_and_rights(mut space: Vec) { use libc::ucred; use nix::sys::socket::sockopt::PassCred; @@ -1451,7 +1543,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { gid: getgid().as_raw(), } .into(); - let fds = [r]; + let fds = [r.as_raw_fd()]; let cmsgs = [ ControlMessage::ScmCredentials(&cred), ControlMessage::ScmRights(&fds), @@ -1467,7 +1559,6 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { .unwrap(), 5 ); - close(r).unwrap(); } { @@ -1510,18 +1601,19 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w.as_raw_fd(), b"world").unwrap(); + write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; read(received_r.as_raw_fd(), &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); - close(w).unwrap(); } // Test creating and using named unix domain sockets #[test] pub fn test_named_unixdomain() { - use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; + use nix::sys::socket::{ + accept, bind, connect, listen, socket, Backlog, UnixAddr, + }; use nix::sys::socket::{SockFlag, SockType}; use nix::unistd::{read, write}; use std::thread; @@ -1537,7 +1629,7 @@ pub fn test_named_unixdomain() { .expect("socket failed"); let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(s1.as_raw_fd(), &sockaddr).expect("bind failed"); - listen(&s1, 10).expect("listen failed"); + listen(&s1, Backlog::new(10).unwrap()).expect("listen failed"); let thr = thread::spawn(move || { let s2 = socket( @@ -1548,7 +1640,7 @@ pub fn test_named_unixdomain() { ) .expect("socket failed"); connect(s2.as_raw_fd(), &sockaddr).expect("connect failed"); - write(s2.as_raw_fd(), b"hello").expect("write failed"); + write(&s2, b"hello").expect("write failed"); }); let s3 = accept(s1.as_raw_fd()).expect("accept failed"); @@ -1560,8 +1652,16 @@ pub fn test_named_unixdomain() { assert_eq!(&buf[..], b"hello"); } +#[test] +pub fn test_listen_wrongbacklog() { + use nix::sys::socket::Backlog; + + assert!(Backlog::new(libc::SOMAXCONN + 1).is_err()); + assert!(Backlog::new(-2).is_err()); +} + // Test using unnamed unix domain addresses -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_unnamed_unixdomain() { use nix::sys::socket::{getsockname, socketpair}; @@ -1581,7 +1681,7 @@ pub fn test_unnamed_unixdomain() { } // Test creating and using unnamed unix domain addresses for autobinding sockets -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_unnamed_unixdomain_autobind() { use nix::sys::socket::{bind, getsockname, socket}; @@ -1609,7 +1709,7 @@ pub fn test_unnamed_unixdomain_autobind() { } // Test creating and using named system control sockets -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(apple_targets)] #[test] pub fn test_syscontrol() { use nix::errno::Errno; @@ -1635,15 +1735,7 @@ pub fn test_syscontrol() { // connect(fd.as_raw_fd(), &sockaddr).expect("connect failed"); } -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(bsd, linux_android))] fn loopback_address( family: AddressFamily, ) -> Option { @@ -1670,20 +1762,16 @@ fn loopback_address( }) } -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", -))] +#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))] // qemu doesn't seem to be emulating this correctly in these architectures #[cfg_attr( all( qemu, any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc64", ) ), @@ -1765,20 +1853,16 @@ pub fn test_recv_ipv4pktinfo() { } } -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(bsd)] // qemu doesn't seem to be emulating this correctly in these architectures #[cfg_attr( all( qemu, any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc64", ) ), @@ -1883,7 +1967,7 @@ pub fn test_recvif() { } } -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg_attr(qemu, ignore)] #[test] pub fn test_recvif_ipv4() { @@ -1969,7 +2053,7 @@ pub fn test_recvif_ipv4() { } } -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg_attr(qemu, ignore)] #[test] pub fn test_recvif_ipv6() { @@ -2055,22 +2139,16 @@ pub fn test_recvif_ipv6() { } } -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))] // qemu doesn't seem to be emulating this correctly in these architectures #[cfg_attr( all( qemu, any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc64", ) ), @@ -2152,7 +2230,7 @@ pub fn test_recv_ipv6pktinfo() { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_vsock() { use nix::sys::socket::SockaddrLike; @@ -2192,7 +2270,7 @@ pub fn test_vsock() { assert_eq!(addr3.as_ref().svm_port, addr1.port()); } -#[cfg(target_os = "macos")] +#[cfg(apple_targets)] #[test] pub fn test_vsock() { use nix::sys::socket::SockaddrLike; @@ -2329,12 +2407,17 @@ fn test_recvmmsg_timestampns() { // Receive the message let mut buffer = vec![0u8; message.len()]; let cmsgspace = nix::cmsg_space!(TimeSpec); - let iov = vec![[IoSliceMut::new(&mut buffer)]]; + let mut iov = vec![[IoSliceMut::new(&mut buffer)]]; let mut data = MultiHeaders::preallocate(1, Some(cmsgspace)); - let r: Vec> = - recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None) - .unwrap() - .collect(); + let r: Vec> = recvmmsg( + in_socket.as_raw_fd(), + &mut data, + iov.iter_mut(), + flags, + None, + ) + .unwrap() + .collect(); let rtime = match r[0].cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -2353,7 +2436,7 @@ fn test_recvmmsg_timestampns() { // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack // of QEMU support is suspected. #[cfg_attr(qemu, ignore)] -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] #[test] fn test_recvmsg_rxq_ovfl() { use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl}; @@ -2447,7 +2530,7 @@ fn test_recvmsg_rxq_ovfl() { assert_eq!(drop_counter, 1); } -#[cfg(any(target_os = "linux", target_os = "android",))] +#[cfg(linux_android)] mod linux_errqueue { use super::FromStr; use nix::sys::socket::*; @@ -2685,3 +2768,160 @@ pub fn test_txtime() { recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty()) .unwrap(); } + +// cfg needed for capability check. +#[cfg(linux_android)] +#[test] +fn test_icmp_protocol() { + use nix::sys::socket::{ + sendto, socket, AddressFamily, MsgFlags, SockFlag, SockProtocol, + SockType, SockaddrIn, + }; + + require_capability!("test_icmp_protocol", CAP_NET_RAW); + + let owned_fd = socket( + AddressFamily::Inet, + SockType::Raw, + SockFlag::empty(), + SockProtocol::Icmp, + ) + .unwrap(); + + // Send a minimal ICMP packet with no payload. + let packet = [ + 0x08, // Type + 0x00, // Code + 0x84, 0x85, // Checksum + 0x73, 0x8a, // ID + 0x00, 0x00, // Sequence Number + ]; + + let dest_addr = SockaddrIn::new(127, 0, 0, 1, 0); + sendto(owned_fd.as_raw_fd(), &packet, &dest_addr, MsgFlags::empty()) + .unwrap(); +} + +// test contains both recvmmsg and timestaping which is linux only +// there are existing tests for recvmmsg only in tests/ +#[cfg_attr(qemu, ignore)] +#[cfg(target_os = "linux")] +#[test] +fn test_recvmm2() -> nix::Result<()> { + use nix::sys::{ + socket::{ + bind, recvmmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, + AddressFamily, ControlMessageOwned, MsgFlags, MultiHeaders, + SockFlag, SockType, SockaddrIn, TimestampingFlag, Timestamps, + }, + time::TimeSpec, + }; + use std::io::{IoSlice, IoSliceMut}; + use std::os::unix::io::AsRawFd; + use std::str::FromStr; + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + )?; + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::SOCK_NONBLOCK, + None, + )?; + + bind(rsock.as_raw_fd(), &sock_addr)?; + + setsockopt(&rsock, Timestamping, &TimestampingFlag::all())?; + + let sbuf = (0..400).map(|i| i as u8).collect::>(); + + let mut recv_buf = vec![0; 1024]; + + let mut recv_iovs = Vec::new(); + let mut pkt_iovs = Vec::new(); + + for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { + pkt_iovs.push(IoSliceMut::new(chunk)); + if ix % 2 == 1 { + recv_iovs.push(pkt_iovs); + pkt_iovs = Vec::new(); + } + } + drop(pkt_iovs); + + let flags = MsgFlags::empty(); + let iov1 = [IoSlice::new(&sbuf)]; + + let cmsg = cmsg_space!(Timestamps); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); + + let mut data = MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); + + let t = TimeSpec::from_duration(std::time::Duration::from_secs(10)); + + let recv = recvmmsg( + rsock.as_raw_fd(), + &mut data, + recv_iovs.iter_mut(), + flags, + Some(t), + )?; + + for rmsg in recv { + #[cfg(not(any(qemu, target_arch = "aarch64")))] + let mut saw_time = false; + let mut recvd = 0; + for cmsg in rmsg.cmsgs() { + if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { + let ts = timestamps.system; + + let sys_time = nix::time::clock_gettime( + nix::time::ClockId::CLOCK_REALTIME, + )?; + let diff = if ts > sys_time { + ts - sys_time + } else { + sys_time - ts + }; + assert!(std::time::Duration::from(diff).as_secs() < 60); + #[cfg(not(any(qemu, target_arch = "aarch64")))] + { + saw_time = true; + } + } + } + + #[cfg(not(any(qemu, target_arch = "aarch64")))] + assert!(saw_time); + + for iov in rmsg.iovs() { + recvd += iov.len(); + } + assert_eq!(recvd, 400); + } + + Ok(()) +} + +#[cfg(not(target_os = "redox"))] +#[test] +fn can_use_cmsg_space() { + let _ = cmsg_space!(u8); +} + +#[cfg(not(any(linux_android, target_os = "redox", target_os = "haiku")))] +#[test] +fn can_open_routing_socket() { + use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType}; + + let _ = + socket(AddressFamily::Route, SockType::Raw, SockFlag::empty(), None) + .expect("Failed to open routing socket"); +} diff --git a/third_party/rust/nix/test/sys/test_sockopt.rs b/third_party/rust/nix/test/sys/test_sockopt.rs index 0e34917325..a99d4e39ed 100644 --- a/third_party/rust/nix/test/sys/test_sockopt.rs +++ b/third_party/rust/nix/test/sys/test_sockopt.rs @@ -1,14 +1,14 @@ -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use crate::*; use nix::sys::socket::{ getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag, SockProtocol, SockType, }; use rand::{thread_rng, Rng}; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; // NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not. -#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))] +#[cfg(freebsdlike)] #[test] pub fn test_local_peercred_seqpacket() { use nix::{ @@ -29,12 +29,7 @@ pub fn test_local_peercred_seqpacket() { assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] +#[cfg(any(freebsdlike, apple_targets))] #[test] pub fn test_local_peercred_stream() { use nix::{ @@ -55,7 +50,7 @@ pub fn test_local_peercred_stream() { assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] #[test] pub fn test_local_peer_pid() { use nix::sys::socket::socketpair; @@ -108,15 +103,42 @@ fn test_so_buf() { assert!(actual >= bufsize); } +#[cfg(target_os = "freebsd")] +#[test] +fn test_so_listen_q_limit() { + use nix::sys::socket::{bind, listen, Backlog, SockaddrIn}; + use std::net::SocketAddrV4; + use std::str::FromStr; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:4004").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + + let rsock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); + let pre_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap(); + assert_eq!(pre_limit, 0); + listen(&rsock, Backlog::new(42).unwrap()).unwrap(); + let post_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap(); + assert_eq!(post_limit, 42); +} + #[test] fn test_so_tcp_maxseg() { - use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; + use nix::sys::socket::{ + accept, bind, connect, getsockname, listen, Backlog, SockaddrIn, + }; use nix::unistd::write; use std::net::SocketAddrV4; use std::str::FromStr; - let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); - let sock_addr = SockaddrIn::from(std_sa); + let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap(); + let mut sock_addr = SockaddrIn::from(std_sa); let rsock = socket( AddressFamily::Inet, @@ -126,13 +148,14 @@ fn test_so_tcp_maxseg() { ) .unwrap(); bind(rsock.as_raw_fd(), &sock_addr).unwrap(); - listen(&rsock, 10).unwrap(); + sock_addr = getsockname(rsock.as_raw_fd()).unwrap(); + listen(&rsock, Backlog::new(10).unwrap()).unwrap(); let initial = getsockopt(&rsock, sockopt::TcpMaxSeg).unwrap(); // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger // than 700 cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { let segsize: u32 = 873; assert!(initial < segsize); setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap(); @@ -151,12 +174,13 @@ fn test_so_tcp_maxseg() { .unwrap(); connect(ssock.as_raw_fd(), &sock_addr).unwrap(); let rsess = accept(rsock.as_raw_fd()).unwrap(); - write(rsess, b"hello").unwrap(); + let rsess = unsafe { OwnedFd::from_raw_fd(rsess) }; + write(&rsess, b"hello").unwrap(); let actual = getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap(); // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary. cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { assert!((segsize - 100) <= actual); assert!(actual <= segsize); } else { @@ -181,11 +205,10 @@ fn test_so_type() { /// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket /// types. Regression test for https://github.com/nix-rust/nix/issues/1819 -#[cfg(any(target_os = "android", target_os = "linux",))] +#[cfg(linux_android)] #[test] fn test_so_type_unknown() { use nix::errno::Errno; - use std::os::unix::io::{FromRawFd, OwnedFd}; require_capability!("test_so_type", CAP_NET_RAW); let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) }; @@ -229,7 +252,7 @@ fn test_tcp_congestion() { } #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_bindtodevice() { skip_if_not_root!("test_bindtodevice"); @@ -259,12 +282,7 @@ fn test_so_tcp_keepalive() { setsockopt(&fd, sockopt::KeepAlive, &true).unwrap(); assert!(getsockopt(&fd, sockopt::KeepAlive).unwrap()); - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" - ))] + #[cfg(any(linux_android, freebsdlike))] { let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap(); setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); @@ -281,14 +299,14 @@ fn test_so_tcp_keepalive() { } #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg_attr(qemu, ignore)] fn test_get_mtu() { use nix::sys::socket::{bind, connect, SockaddrIn}; use std::net::SocketAddrV4; use std::str::FromStr; - let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); + let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap(); let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap(); let usock = socket( @@ -308,7 +326,7 @@ fn test_get_mtu() { } #[test] -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] fn test_ttl_opts() { let fd4 = socket( AddressFamily::Inet, @@ -331,7 +349,48 @@ fn test_ttl_opts() { } #[test] -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(any(linux_android, target_os = "freebsd"))] +fn test_multicast_ttl_opts_ipv4() { + let fd4 = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd4, sockopt::IpMulticastTtl, &2) + .expect("setting ipmulticastttl on an inet socket should succeed"); +} + +#[test] +#[cfg(linux_android)] +fn test_multicast_ttl_opts_ipv6() { + let fd6 = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd6, sockopt::IpMulticastTtl, &2) + .expect("setting ipmulticastttl on an inet6 socket should succeed"); +} + +#[test] +fn test_ipv6_multicast_hops() { + let fd6 = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd6, sockopt::Ipv6MulticastHops, &7) + .expect("setting ipv6multicasthops on an inet6 socket should succeed"); +} + +#[test] +#[cfg(apple_targets)] fn test_dontfrag_opts() { let fd4 = socket( AddressFamily::Inet, @@ -361,12 +420,7 @@ fn test_dontfrag_opts() { } #[test] -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", -))] +#[cfg(any(linux_android, apple_targets))] // Disable the test under emulation because it fails in Cirrus-CI. Lack // of QEMU support is suspected. #[cfg_attr(qemu, ignore)] @@ -446,3 +500,331 @@ fn test_ipv6_tclass() { setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap(); assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class); } + +#[test] +#[cfg(target_os = "freebsd")] +fn test_receive_timestamp() { + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + assert!(getsockopt(&fd, sockopt::ReceiveTimestamp).unwrap()); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_realtime_micro() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt( + &fd, + sockopt::TsClock, + &SocketTimestamp::SO_TS_REALTIME_MICRO, + ) + .unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_REALTIME_MICRO + ); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_bintime() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_BINTIME).unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_BINTIME + ); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_realtime() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_REALTIME) + .unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_REALTIME + ); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_monotonic() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_MONOTONIC) + .unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_MONOTONIC + ); +} + +#[test] +#[cfg(linux_android)] +// Disable the test under emulation because it fails with ENOPROTOOPT in CI +// on cross target. Lack of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +fn test_ip_bind_address_no_port() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(&fd, sockopt::IpBindAddressNoPort, &true).expect( + "setting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + ); + assert!(getsockopt(&fd, sockopt::IpBindAddressNoPort).expect( + "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + )); + setsockopt(&fd, sockopt::IpBindAddressNoPort, &false).expect( + "unsetting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + ); + assert!(!getsockopt(&fd, sockopt::IpBindAddressNoPort).expect( + "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + )); +} + +#[test] +#[cfg(linux_android)] +fn test_tcp_fast_open_connect() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(&fd, sockopt::TcpFastOpenConnect, &true).expect( + "setting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + ); + assert!(getsockopt(&fd, sockopt::TcpFastOpenConnect).expect( + "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + )); + setsockopt(&fd, sockopt::TcpFastOpenConnect, &false).expect( + "unsetting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + ); + assert!(!getsockopt(&fd, sockopt::TcpFastOpenConnect).expect( + "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + )); +} + +#[cfg(linux_android)] +#[test] +fn can_get_peercred_on_unix_socket() { + use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType}; + + let (a, b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let a_cred = getsockopt(&a, sockopt::PeerCredentials).unwrap(); + let b_cred = getsockopt(&b, sockopt::PeerCredentials).unwrap(); + assert_eq!(a_cred, b_cred); + assert_ne!(a_cred.pid(), 0); +} + +#[test] +fn is_socket_type_unix() { + use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType}; + + let (a, _b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let a_type = getsockopt(&a, sockopt::SockType).unwrap(); + assert_eq!(a_type, SockType::Stream); +} + +#[test] +fn is_socket_type_dgram() { + use nix::sys::socket::{ + getsockopt, sockopt, AddressFamily, SockFlag, SockType, + }; + + let s = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + let s_type = getsockopt(&s, sockopt::SockType).unwrap(); + assert_eq!(s_type, SockType::Datagram); +} + +#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[test] +fn can_get_listen_on_tcp_socket() { + use nix::sys::socket::{ + getsockopt, listen, socket, sockopt, AddressFamily, Backlog, SockFlag, + SockType, + }; + + let s = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + let s_listening = getsockopt(&s, sockopt::AcceptConn).unwrap(); + assert!(!s_listening); + listen(&s, Backlog::new(10).unwrap()).unwrap(); + let s_listening2 = getsockopt(&s, sockopt::AcceptConn).unwrap(); + assert!(s_listening2); +} + +#[cfg(target_os = "linux")] +// Some architectures running under cross don't support `setsockopt(SOL_TCP, TCP_ULP)` +// because the cross image is based on Ubuntu 16.04 which predates TCP ULP support +// (it was added in kernel v4.13 released in 2017). For these architectures, +// the `setsockopt(SOL_TCP, TCP_ULP, "tls", sizeof("tls"))` call succeeds +// but the subsequent `setsockopt(SOL_TLS, TLS_TX, ...)` call fails with `ENOPROTOOPT`. +// It's as if the first `setsockopt` call enabled some other option, not `TCP_ULP`. +// For example, `strace` says: +// +// [pid 813] setsockopt(4, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0 +// +// It's not clear why `setsockopt(SOL_TCP, TCP_ULP)` succeeds if the container image libc doesn't support it, +// but in any case we can't run the test on such an architecture, so skip it. +#[cfg_attr(qemu, ignore)] +#[test] +fn test_ktls() { + use nix::sys::socket::{ + accept, bind, connect, getsockname, listen, Backlog, SockaddrIn, + }; + use std::net::SocketAddrV4; + use std::str::FromStr; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap(); + let mut sock_addr = SockaddrIn::from(std_sa); + + let rsock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); + sock_addr = getsockname(rsock.as_raw_fd()).unwrap(); + listen(&rsock, Backlog::new(10).unwrap()).unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + connect(ssock.as_raw_fd(), &sock_addr).unwrap(); + + let _rsess = accept(rsock.as_raw_fd()).unwrap(); + + match setsockopt(&ssock, sockopt::TcpUlp::default(), b"tls") { + Ok(()) => (), + + // TLS ULP is not enabled, so we can't test kTLS. + Err(nix::Error::ENOENT) => skip!("TLS ULP is not enabled"), + + Err(err) => panic!("{err:?}"), + } + + // In real life we would do a TLS handshake and extract the protocol version and secrets. + // For this test we just make some up. + + let tx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 { + info: libc::tls_crypto_info { + version: libc::TLS_1_2_VERSION, + cipher_type: libc::TLS_CIPHER_AES_GCM_128, + }, + iv: *b"\x04\x05\x06\x07\x08\x09\x0a\x0b", + key: *b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + salt: *b"\x00\x01\x02\x03", + rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00", + }); + setsockopt(&ssock, sockopt::TcpTlsTx, &tx) + .expect("setting TLS_TX after enabling TLS ULP should succeed"); + + let rx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 { + info: libc::tls_crypto_info { + version: libc::TLS_1_2_VERSION, + cipher_type: libc::TLS_CIPHER_AES_GCM_128, + }, + iv: *b"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb", + key: *b"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef", + salt: *b"\xf0\xf1\xf2\xf3", + rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00", + }); + match setsockopt(&ssock, sockopt::TcpTlsRx, &rx) { + Ok(()) => (), + Err(nix::Error::ENOPROTOOPT) => { + // TLS_TX was added in v4.13 and TLS_RX in v4.17, so we appear to be between that range. + // It's good enough that TLS_TX worked, so let the test succeed. + } + Err(err) => panic!("{err:?}"), + } +} diff --git a/third_party/rust/nix/test/sys/test_statfs.rs b/third_party/rust/nix/test/sys/test_statfs.rs new file mode 100644 index 0000000000..66b3f2ce96 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_statfs.rs @@ -0,0 +1,99 @@ +use nix::sys::statfs::*; +use nix::sys::statvfs::*; +use std::fs::File; +use std::path::Path; + +fn check_fstatfs(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()).unwrap(); + let file = File::open(path).unwrap(); + let fs = fstatfs(&file).unwrap(); + assert_fs_equals(fs, vfs); +} + +fn check_statfs(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()).unwrap(); + let fs = statfs(path.as_bytes()).unwrap(); + assert_fs_equals(fs, vfs); +} + +fn check_fstatfs_strict(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()); + let file = File::open(path).unwrap(); + let fs = fstatfs(&file); + assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) +} + +fn check_statfs_strict(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()); + let fs = statfs(path.as_bytes()); + assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) +} + +// The cast is not unnecessary on all platforms. +#[allow(clippy::unnecessary_cast)] +fn assert_fs_equals(fs: Statfs, vfs: Statvfs) { + assert_eq!(fs.files() as u64, vfs.files() as u64); + assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); + assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); +} + +#[test] +fn statfs_call() { + check_statfs("/tmp"); + check_statfs("/dev"); + check_statfs("/run"); + check_statfs("/"); +} + +#[test] +fn fstatfs_call() { + check_fstatfs("/tmp"); + check_fstatfs("/dev"); + check_fstatfs("/run"); + check_fstatfs("/"); +} + +// This test is ignored because files_free/blocks_free can change after statvfs call and before +// statfs call. +#[test] +#[ignore] +fn statfs_call_strict() { + check_statfs_strict("/tmp"); + check_statfs_strict("/dev"); + check_statfs_strict("/run"); + check_statfs_strict("/"); +} + +// This test is ignored because files_free/blocks_free can change after statvfs call and before +// fstatfs call. +#[test] +#[ignore] +fn fstatfs_call_strict() { + check_fstatfs_strict("/tmp"); + check_fstatfs_strict("/dev"); + check_fstatfs_strict("/run"); + check_fstatfs_strict("/"); +} + +// The cast is not unnecessary on all platforms. +#[allow(clippy::unnecessary_cast)] +fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) { + assert_eq!(fs.files_free() as u64, vfs.files_free() as u64); + assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64); + assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64); + assert_eq!(fs.files() as u64, vfs.files() as u64); + assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); + assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); +} diff --git a/third_party/rust/nix/test/sys/test_statvfs.rs b/third_party/rust/nix/test/sys/test_statvfs.rs new file mode 100644 index 0000000000..5c80965253 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_statvfs.rs @@ -0,0 +1,13 @@ +use nix::sys::statvfs::*; +use std::fs::File; + +#[test] +fn statvfs_call() { + statvfs(&b"/"[..]).unwrap(); +} + +#[test] +fn fstatvfs_call() { + let root = File::open("/").unwrap(); + fstatvfs(&root).unwrap(); +} diff --git a/third_party/rust/nix/test/sys/test_termios.rs b/third_party/rust/nix/test/sys/test_termios.rs index 83919378a7..35cc7ab739 100644 --- a/third_party/rust/nix/test/sys/test_termios.rs +++ b/third_party/rust/nix/test/sys/test_termios.rs @@ -4,17 +4,26 @@ use tempfile::tempfile; use nix::errno::Errno; use nix::fcntl; use nix::pty::openpty; -use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; +use nix::sys::termios::{self, tcgetattr, BaudRate, LocalFlags, OutputFlags}; use nix::unistd::{read, write}; /// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s fn write_all(f: Fd, buf: &[u8]) { let mut len = 0; while len < buf.len() { - len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap(); + len += write(f.as_fd(), &buf[len..]).unwrap(); } } +#[test] +fn test_baudrate_try_from() { + assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); + #[cfg(not(target_os = "haiku"))] + BaudRate::try_from(999999999).expect_err("assertion failed"); + #[cfg(target_os = "haiku")] + BaudRate::try_from(99).expect_err("assertion failed"); +} + // Test tcgetattr on a terminal #[test] fn test_tcgetattr_pty() { diff --git a/third_party/rust/nix/test/sys/test_time.rs b/third_party/rust/nix/test/sys/test_time.rs new file mode 100644 index 0000000000..0510225a92 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_time.rs @@ -0,0 +1,91 @@ +use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; +use std::time::Duration; + +#[test] +pub fn test_timespec() { + assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); + assert_eq!( + TimeSpec::seconds(1) + TimeSpec::seconds(2), + TimeSpec::seconds(3) + ); + assert_eq!( + TimeSpec::minutes(3) + TimeSpec::seconds(2), + TimeSpec::seconds(182) + ); +} + +#[test] +pub fn test_timespec_from() { + let duration = Duration::new(123, 123_456_789); + let timespec = TimeSpec::nanoseconds(123_123_456_789); + + assert_eq!(TimeSpec::from(duration), timespec); + assert_eq!(Duration::from(timespec), duration); +} + +#[test] +pub fn test_timespec_neg() { + let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); + let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); + + assert_eq!(a, -b); +} + +#[test] +pub fn test_timespec_ord() { + assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); + assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); + assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); + assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); + assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); +} + +#[test] +pub fn test_timespec_fmt() { + assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); + assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); + assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); + assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); + assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds"); + assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); +} + +#[test] +pub fn test_timeval() { + assert_ne!(TimeVal::seconds(1), TimeVal::zero()); + assert_eq!( + TimeVal::seconds(1) + TimeVal::seconds(2), + TimeVal::seconds(3) + ); + assert_eq!( + TimeVal::minutes(3) + TimeVal::seconds(2), + TimeVal::seconds(182) + ); +} + +#[test] +pub fn test_timeval_ord() { + assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); + assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); + assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); + assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); + assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); +} + +#[test] +pub fn test_timeval_neg() { + let a = TimeVal::seconds(1) + TimeVal::microseconds(123); + let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); + + assert_eq!(a, -b); +} + +#[test] +pub fn test_timeval_fmt() { + assert_eq!(TimeVal::zero().to_string(), "0 seconds"); + assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); + assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); + assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); + assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); + assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); +} diff --git a/third_party/rust/nix/test/sys/test_timer.rs b/third_party/rust/nix/test/sys/test_timer.rs new file mode 100644 index 0000000000..ffd146867b --- /dev/null +++ b/third_party/rust/nix/test/sys/test_timer.rs @@ -0,0 +1,102 @@ +use nix::sys::signal::{ + sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, + Signal, +}; +use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; +use nix::time::ClockId; +use std::convert::TryFrom; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +const SIG: Signal = Signal::SIGALRM; +static ALARM_CALLED: AtomicBool = AtomicBool::new(false); + +pub extern "C" fn handle_sigalarm(raw_signal: libc::c_int) { + let signal = Signal::try_from(raw_signal).unwrap(); + if signal == SIG { + ALARM_CALLED.store(true, Ordering::Release); + } +} + +#[test] +fn alarm_fires() { + // Avoid interfering with other signal using tests by taking a mutex shared + // among other tests in this crate. + let _m = crate::SIGNAL_MTX.lock(); + const TIMER_PERIOD: Duration = Duration::from_millis(100); + + // + // Setup + // + + // Create a handler for the test signal, `SIG`. The handler is responsible + // for flipping `ALARM_CALLED`. + let handler = SigHandler::Handler(handle_sigalarm); + let signal_action = + SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); + let old_handler = unsafe { + sigaction(SIG, &signal_action) + .expect("unable to set signal handler for alarm") + }; + + // Create the timer. We use the monotonic clock here, though any would do + // really. The timer is set to fire every 250 milliseconds with no delay for + // the initial firing. + let clockid = ClockId::CLOCK_MONOTONIC; + let sigevent = SigEvent::new(SigevNotify::SigevSignal { + signal: SIG, + si_value: 0, + }); + let mut timer = + Timer::new(clockid, sigevent).expect("failed to create timer"); + let expiration = Expiration::Interval(TIMER_PERIOD.into()); + let flags = TimerSetTimeFlags::empty(); + timer.set(expiration, flags).expect("could not set timer"); + + // + // Test + // + + // Determine that there's still an expiration tracked by the + // timer. Depending on when this runs either an `Expiration::Interval` or + // `Expiration::IntervalDelayed` will be present. That is, if the timer has + // not fired yet we'll get our original `expiration`, else the one that + // represents a delay to the next expiration. We're only interested in the + // timer still being extant. + match timer.get() { + Ok(Some(exp)) => assert!(matches!( + exp, + Expiration::Interval(..) | Expiration::IntervalDelayed(..) + )), + _ => panic!("timer lost its expiration"), + } + + // Wait for 2 firings of the alarm before checking that it has fired and + // been handled at least the once. If we wait for 3 seconds and the handler + // is never called something has gone sideways and the test fails. + let starttime = Instant::now(); + loop { + thread::sleep(2 * TIMER_PERIOD); + if ALARM_CALLED.load(Ordering::Acquire) { + break; + } + if starttime.elapsed() > Duration::from_secs(3) { + panic!("Timeout waiting for SIGALRM"); + } + } + + // Cleanup: + // 1) deregister the OS's timer. + // 2) Wait for a full timer period, since POSIX does not require that + // disabling the timer will clear pending signals, and on NetBSD at least + // it does not. + // 2) Replace the old signal handler now that we've completed the test. If + // the test fails this process panics, so the fact we might not get here + // is okay. + drop(timer); + thread::sleep(TIMER_PERIOD); + unsafe { + sigaction(SIG, &old_handler).expect("unable to reset signal handler"); + } +} diff --git a/third_party/rust/nix/test/sys/test_uio.rs b/third_party/rust/nix/test/sys/test_uio.rs index fc09465f19..d035a7bb04 100644 --- a/third_party/rust/nix/test/sys/test_uio.rs +++ b/third_party/rust/nix/test/sys/test_uio.rs @@ -4,7 +4,7 @@ use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use std::fs::OpenOptions; use std::io::IoSlice; -use std::os::unix::io::{FromRawFd, OwnedFd}; +use std::os::unix::io::AsRawFd; use std::{cmp, iter}; #[cfg(not(target_os = "redox"))] @@ -44,22 +44,17 @@ fn test_writev() { // FileDesc will close its filedesc (reader). let mut read_buf: Vec = iter::repeat(0u8).take(128 * 16).collect(); - // Temporary workaround to cope with the existing RawFd pipe(2), should be - // removed when pipe(2) becomes I/O-safe. - let writer = unsafe { OwnedFd::from_raw_fd(writer) }; - // Blocking io, should write all data. let write_res = writev(&writer, &iovecs); let written = write_res.expect("couldn't write"); // Check whether we written all data assert_eq!(to_write.len(), written); - let read_res = read(reader, &mut read_buf[..]); + let read_res = read(reader.as_raw_fd(), &mut read_buf[..]); let read = read_res.expect("couldn't read"); // Check we have read as much as we written assert_eq!(read, written); // Check equality of written and read data assert_eq!(&to_write, &read_buf); - close(reader).expect("closed reader"); } #[test] @@ -92,10 +87,6 @@ fn test_readv() { // Blocking io, should write all data. write(writer, &to_write).expect("write failed"); - // Temporary workaround to cope with the existing RawFd pipe(2), should be - // removed when pipe(2) becomes I/O-safe. - let reader = unsafe { OwnedFd::from_raw_fd(reader) }; - let read = readv(&reader, &mut iovecs[..]).expect("read failed"); // Check whether we've read all data assert_eq!(to_write.len(), read); @@ -108,7 +99,6 @@ fn test_readv() { assert_eq!(read_buf.len(), to_write.len()); // Check equality of written and read data assert_eq!(&read_buf, &to_write); - close(writer).expect("couldn't close writer"); } #[test] @@ -150,7 +140,11 @@ fn test_pread() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "haiku", + target_os = "solaris" +)))] fn test_pwritev() { use std::io::Read; @@ -185,7 +179,11 @@ fn test_pwritev() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "haiku", + target_os = "solaris" +)))] fn test_preadv() { use std::io::Write; @@ -230,6 +228,7 @@ fn test_process_vm_readv() { use nix::sys::signal::*; use nix::sys::wait::*; use nix::unistd::ForkResult::*; + use std::os::unix::io::AsRawFd; require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock(); @@ -241,10 +240,10 @@ fn test_process_vm_readv() { let (r, w) = pipe().unwrap(); match unsafe { fork() }.expect("Error: Fork Failed") { Parent { child } => { - close(w).unwrap(); + drop(w); // wait for child - read(r, &mut [0u8]).unwrap(); - close(r).unwrap(); + read(r.as_raw_fd(), &mut [0u8]).unwrap(); + drop(r); let ptr = vector.as_ptr() as usize; let remote_iov = RemoteIoVec { base: ptr, len: 5 }; @@ -263,12 +262,11 @@ fn test_process_vm_readv() { assert_eq!(20u8, buf.iter().sum()); } Child => { - let _ = close(r); + drop(r); for i in &mut vector { *i += 1; } let _ = write(w, b"\0"); - let _ = close(w); loop { pause(); } diff --git a/third_party/rust/nix/test/sys/test_utsname.rs b/third_party/rust/nix/test/sys/test_utsname.rs new file mode 100644 index 0000000000..8f84ac074f --- /dev/null +++ b/third_party/rust/nix/test/sys/test_utsname.rs @@ -0,0 +1,17 @@ +#[cfg(target_os = "linux")] +#[test] +pub fn test_uname_linux() { + assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Linux"); +} + +#[cfg(apple_targets)] +#[test] +pub fn test_uname_darwin() { + assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Darwin"); +} + +#[cfg(target_os = "freebsd")] +#[test] +pub fn test_uname_freebsd() { + assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "FreeBSD"); +} diff --git a/third_party/rust/nix/test/sys/test_wait.rs b/third_party/rust/nix/test/sys/test_wait.rs index d472f1ec19..365b0165f8 100644 --- a/third_party/rust/nix/test/sys/test_wait.rs +++ b/third_party/rust/nix/test/sys/test_wait.rs @@ -33,7 +33,12 @@ fn test_wait_signal() { //target_os = "haiku", all(target_os = "linux", not(target_env = "uclibc")), ))] -#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +#[cfg(not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" +)))] fn test_waitid_signal() { let _m = crate::FORK_MTX.lock(); @@ -76,7 +81,12 @@ fn test_wait_exit() { target_os = "haiku", all(target_os = "linux", not(target_env = "uclibc")), ))] -#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +#[cfg(not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" +)))] fn test_waitid_exit() { let _m = crate::FORK_MTX.lock(); @@ -140,7 +150,7 @@ fn test_waitid_pid() { } } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] // FIXME: qemu-user doesn't implement ptrace on most arches #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod ptrace { diff --git a/third_party/rust/nix/test/test.rs b/third_party/rust/nix/test/test.rs index 7e73bb3056..c7231426c2 100644 --- a/third_party/rust/nix/test/test.rs +++ b/third_party/rust/nix/test/test.rs @@ -7,12 +7,14 @@ mod common; mod sys; #[cfg(not(target_os = "redox"))] mod test_dir; +mod test_errno; mod test_fcntl; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_kmod; +#[cfg(target_os = "linux")] +mod test_mount; #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + freebsdlike, target_os = "fushsia", target_os = "linux", target_os = "netbsd" @@ -30,36 +32,16 @@ mod test_poll; target_os = "haiku" )))] mod test_pty; -mod test_resource; #[cfg(any( - target_os = "android", + linux_android, target_os = "dragonfly", all(target_os = "freebsd", fbsd14), - target_os = "linux" ))] mod test_sched; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" -))] +#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))] mod test_sendfile; mod test_stat; mod test_time; -#[cfg(all( - any( - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd" - ), - feature = "time", - feature = "signal" -))] -mod test_timer; mod test_unistd; use nix::unistd::{chdir, getcwd, read}; diff --git a/third_party/rust/nix/test/test_dir.rs b/third_party/rust/nix/test/test_dir.rs index 2af4aa5c0a..24ecd6963e 100644 --- a/third_party/rust/nix/test/test_dir.rs +++ b/third_party/rust/nix/test/test_dir.rs @@ -6,10 +6,10 @@ use tempfile::tempdir; #[cfg(test)] fn flags() -> OFlag { - #[cfg(target_os = "illumos")] + #[cfg(solarish)] let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC; - #[cfg(not(target_os = "illumos"))] + #[cfg(not(solarish))] let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC | OFlag::O_DIRECTORY; f diff --git a/third_party/rust/nix/test/test_errno.rs b/third_party/rust/nix/test/test_errno.rs new file mode 100644 index 0000000000..750fc924ff --- /dev/null +++ b/third_party/rust/nix/test/test_errno.rs @@ -0,0 +1,16 @@ +use nix::errno::Errno; + +#[test] +fn errno_set_and_read() { + Errno::ENFILE.set(); + assert_eq!(Errno::last(), Errno::ENFILE); +} + +#[test] +fn errno_set_and_clear() { + Errno::ENFILE.set(); + assert_eq!(Errno::last(), Errno::ENFILE); + + Errno::clear(); + assert_eq!(Errno::last(), Errno::from_raw(0)); +} diff --git a/third_party/rust/nix/test/test_fcntl.rs b/third_party/rust/nix/test/test_fcntl.rs index 5fef04ba9b..6572e8af8d 100644 --- a/third_party/rust/nix/test/test_fcntl.rs +++ b/third_party/rust/nix/test/test_fcntl.rs @@ -42,7 +42,7 @@ fn test_openat() { open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty()) .unwrap(); let fd = openat( - dirfd, + Some(dirfd), tmp.path().file_name().unwrap(), OFlag::O_RDONLY, Mode::empty(), @@ -222,7 +222,7 @@ fn test_readlink() { assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); assert_eq!( - readlinkat(dirfd, "b").unwrap().to_str().unwrap(), + readlinkat(Some(dirfd), "b").unwrap().to_str().unwrap(), expected_dir ); } @@ -234,10 +234,9 @@ fn test_readlink() { /// The from_offset should be updated by the call to reflect /// the 3 bytes read (6). #[cfg(any( - target_os = "linux", + linux_android, // Not available until FreeBSD 13.0 all(target_os = "freebsd", fbsd14), - target_os = "android" ))] #[test] // QEMU does not support copy_file_range. Skip under qemu @@ -272,7 +271,7 @@ fn test_copy_file_range() { assert_eq!(from_offset, 6); } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] mod linux_android { use libc::loff_t; use std::io::prelude::*; @@ -280,7 +279,7 @@ mod linux_android { use std::os::unix::prelude::*; use nix::fcntl::*; - use nix::unistd::{close, pipe, read, write}; + use nix::unistd::{pipe, read, write}; use tempfile::tempfile; #[cfg(target_os = "linux")] @@ -299,7 +298,7 @@ mod linux_android { let res = splice( tmp.as_raw_fd(), Some(&mut offset), - wr, + wr.as_raw_fd(), None, 2, SpliceFFlags::empty(), @@ -309,12 +308,9 @@ mod linux_android { assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); } #[test] @@ -323,24 +319,21 @@ mod linux_android { let (rd2, wr2) = pipe().unwrap(); write(wr1, b"abc").unwrap(); - let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap(); + let res = + tee(rd1.as_raw_fd(), wr2.as_raw_fd(), 2, SpliceFFlags::empty()) + .unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; // Check the tee'd bytes are at rd2. - assert_eq!(2, read(rd2, &mut buf).unwrap()); + assert_eq!(2, read(rd2.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"ab", &buf[0..2]); // Check all the bytes are still at rd1. - assert_eq!(3, read(rd1, &mut buf).unwrap()); + assert_eq!(3, read(rd1.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"abc", &buf[0..3]); - - close(rd1).unwrap(); - close(wr1).unwrap(); - close(rd2).unwrap(); - close(wr2).unwrap(); } #[test] @@ -351,17 +344,15 @@ mod linux_android { let buf2 = b"defghi"; let iovecs = [IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; - let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); + let res = vmsplice(wr.as_raw_fd(), &iovecs[..], SpliceFFlags::empty()) + .unwrap(); assert_eq!(6, res); // Check the bytes can be read at rd. let mut buf = [0u8; 32]; - assert_eq!(6, read(rd, &mut buf).unwrap()); + assert_eq!(6, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"abcdef", &buf[0..6]); - - close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "linux")] @@ -481,8 +472,7 @@ mod linux_android { } #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", @@ -494,7 +484,7 @@ mod test_posix_fadvise { use nix::errno::Errno; use nix::fcntl::*; use nix::unistd::pipe; - use std::os::unix::io::{AsRawFd, RawFd}; + use std::os::unix::io::AsRawFd; use tempfile::NamedTempFile; #[test] @@ -509,7 +499,7 @@ mod test_posix_fadvise { fn test_errno() { let (rd, _wr) = pipe().unwrap(); let res = posix_fadvise( - rd as RawFd, + rd.as_raw_fd(), 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED, @@ -519,23 +509,18 @@ mod test_posix_fadvise { } #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", - target_os = "freebsd" ))] mod test_posix_fallocate { use nix::errno::Errno; use nix::fcntl::*; use nix::unistd::pipe; - use std::{ - io::Read, - os::unix::io::{AsRawFd, RawFd}, - }; + use std::{io::Read, os::unix::io::AsRawFd}; use tempfile::NamedTempFile; #[test] @@ -565,10 +550,133 @@ mod test_posix_fallocate { #[test] fn errno() { let (rd, _wr) = pipe().unwrap(); - let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); + let err = posix_fallocate(rd.as_raw_fd(), 0, 100).unwrap_err(); match err { Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), errno => panic!("unexpected errno {errno}",), } } } + +#[cfg(any(target_os = "dragonfly", target_os = "netbsd", apple_targets))] +#[test] +fn test_f_get_path() { + use nix::fcntl::*; + use std::{os::unix::io::AsRawFd, path::PathBuf}; + + let tmp = NamedTempFile::new().unwrap(); + let fd = tmp.as_raw_fd(); + let mut path = PathBuf::new(); + let res = + fcntl(fd, FcntlArg::F_GETPATH(&mut path)).expect("get path failed"); + assert_ne!(res, -1); + assert_eq!( + path.as_path().canonicalize().unwrap(), + tmp.path().canonicalize().unwrap() + ); +} + +#[cfg(apple_targets)] +#[test] +fn test_f_get_path_nofirmlink() { + use nix::fcntl::*; + use std::{os::unix::io::AsRawFd, path::PathBuf}; + + let tmp = NamedTempFile::new().unwrap(); + let fd = tmp.as_raw_fd(); + let mut path = PathBuf::new(); + let res = fcntl(fd, FcntlArg::F_GETPATH_NOFIRMLINK(&mut path)) + .expect("get path failed"); + let mut tmpstr = String::from("/System/Volumes/Data"); + tmpstr.push_str( + &tmp.path() + .canonicalize() + .unwrap() + .into_os_string() + .into_string() + .unwrap(), + ); + assert_ne!(res, -1); + assert_eq!( + path.as_path() + .canonicalize() + .unwrap() + .into_os_string() + .into_string() + .unwrap(), + tmpstr + ); +} + +#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] +#[test] +fn test_f_kinfo() { + use nix::fcntl::*; + use std::{os::unix::io::AsRawFd, path::PathBuf}; + + let tmp = NamedTempFile::new().unwrap(); + // With TMPDIR set with UFS, the vnode name is not entered + // into the name cache thus path is always empty. + // Therefore, we reopen the tempfile a second time for the test + // to pass. + let tmp2 = File::open(tmp.path()).unwrap(); + let fd = tmp2.as_raw_fd(); + let mut path = PathBuf::new(); + let res = fcntl(fd, FcntlArg::F_KINFO(&mut path)).expect("get path failed"); + assert_ne!(res, -1); + assert_eq!(path, tmp.path()); +} + +/// Test `Flock` and associated functions. +/// +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +mod test_flock { + use nix::fcntl::*; + use tempfile::NamedTempFile; + + /// Verify that `Flock::lock()` correctly obtains a lock, and subsequently unlocks upon drop. + #[test] + fn verify_lock_and_drop() { + // Get 2 `File` handles to same underlying file. + let file1 = NamedTempFile::new().unwrap(); + let file2 = file1.reopen().unwrap(); + let file1 = file1.into_file(); + + // Lock first handle + let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap(); + + // Attempt to lock second handle + let file2 = match Flock::lock(file2, FlockArg::LockExclusiveNonblock) { + Ok(_) => panic!("Expected second exclusive lock to fail."), + Err((f, _)) => f, + }; + + // Drop first lock + std::mem::drop(lock1); + + // Attempt to lock second handle again (but successfully) + if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() { + panic!("Expected locking to be successful."); + } + } + + /// Verify that `Flock::unlock()` correctly obtains unlocks. + #[test] + fn verify_unlock() { + // Get 2 `File` handles to same underlying file. + let file1 = NamedTempFile::new().unwrap(); + let file2 = file1.reopen().unwrap(); + let file1 = file1.into_file(); + + // Lock first handle + let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap(); + + // Unlock and retain file so any erroneous flocks also remain present. + let _file1 = lock1.unlock().unwrap(); + + // Attempt to lock second handle. + if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() { + panic!("Expected locking to be successful."); + } + } +} diff --git a/third_party/rust/nix/test/test_mount.rs b/third_party/rust/nix/test/test_mount.rs index 5cf00408e8..a4f0903dba 100644 --- a/third_party/rust/nix/test/test_mount.rs +++ b/third_party/rust/nix/test/test_mount.rs @@ -1,267 +1,183 @@ -mod common; - -// Implementation note: to allow unprivileged users to run it, this test makes -// use of user and mount namespaces. On systems that allow unprivileged user -// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run -// without root. - -#[cfg(target_os = "linux")] -mod test_mount { - use std::fs::{self, File}; - use std::io::{self, Read, Write}; - use std::os::unix::fs::OpenOptionsExt; - use std::os::unix::fs::PermissionsExt; - use std::process::{self, Command}; - - use libc::{EACCES, EROFS}; - - use nix::errno::Errno; - use nix::mount::{mount, umount, MsFlags}; - use nix::sched::{unshare, CloneFlags}; - use nix::sys::stat::{self, Mode}; - use nix::unistd::getuid; - - static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh +use std::fs::{self, File}; +use std::io::{Read, Write}; +use std::os::unix::fs::OpenOptionsExt; +use std::os::unix::fs::PermissionsExt; +use std::process::Command; + +use libc::{EACCES, EROFS}; + +use nix::mount::{mount, umount, MsFlags}; +use nix::sys::stat::{self, Mode}; + +use crate::*; + +static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh exit 23"; - const EXPECTED_STATUS: i32 = 23; +const EXPECTED_STATUS: i32 = 23; - const NONE: Option<&'static [u8]> = None; - #[allow(clippy::bind_instead_of_map)] // False positive - pub fn test_mount_tmpfs_without_flags_allows_rwx() { - let tempdir = tempfile::tempdir().unwrap(); +const NONE: Option<&'static [u8]> = None; - mount( - NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::empty(), - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {e}")); +#[test] +fn test_mount_tmpfs_without_flags_allows_rwx() { + require_capability!( + "test_mount_tmpfs_without_flags_allows_rwx", + CAP_SYS_ADMIN + ); + let tempdir = tempfile::tempdir().unwrap(); + + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::empty(), + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {e}")); + + let test_path = tempdir.path().join("test"); + + // Verify write. + fs::OpenOptions::new() + .create(true) + .write(true) + .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) + .open(&test_path) + .and_then(|mut f| f.write(SCRIPT_CONTENTS)) + .unwrap_or_else(|e| panic!("write failed: {e}")); + + // Verify read. + let mut buf = Vec::new(); + File::open(&test_path) + .and_then(|mut f| f.read_to_end(&mut buf)) + .unwrap_or_else(|e| panic!("read failed: {e}")); + assert_eq!(buf, SCRIPT_CONTENTS); + + // Verify execute. + assert_eq!( + EXPECTED_STATUS, + Command::new(&test_path) + .status() + .unwrap_or_else(|e| panic!("exec failed: {e}")) + .code() + .unwrap_or_else(|| panic!("child killed by signal")) + ); - let test_path = tempdir.path().join("test"); + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); +} - // Verify write. - fs::OpenOptions::new() - .create(true) - .write(true) - .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) - .open(&test_path) - .or_else(|e| { - if Errno::from_i32(e.raw_os_error().unwrap()) - == Errno::EOVERFLOW - { - // Skip tests on certain Linux kernels which have a bug - // regarding tmpfs in namespaces. - // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is - // not. There is no legitimate reason for open(2) to return - // EOVERFLOW here. - // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087 - let stderr = io::stderr(); - let mut handle = stderr.lock(); - writeln!( - handle, - "Buggy Linux kernel detected. Skipping test." - ) - .unwrap(); - process::exit(0); - } else { - panic!("open failed: {e}"); - } - }) - .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {e}")); +#[test] +fn test_mount_rdonly_disallows_write() { + require_capability!("test_mount_rdonly_disallows_write", CAP_SYS_ADMIN); + let tempdir = tempfile::tempdir().unwrap(); + + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::MS_RDONLY, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {e}")); + + // EROFS: Read-only file system + assert_eq!( + EROFS, + File::create(tempdir.path().join("test")) + .unwrap_err() + .raw_os_error() + .unwrap() + ); - // Verify read. - let mut buf = Vec::new(); - File::open(&test_path) - .and_then(|mut f| f.read_to_end(&mut buf)) - .unwrap_or_else(|e| panic!("read failed: {e}")); - assert_eq!(buf, SCRIPT_CONTENTS); - - // Verify execute. - assert_eq!( - EXPECTED_STATUS, - Command::new(&test_path) - .status() - .unwrap_or_else(|e| panic!("exec failed: {e}")) - .code() - .unwrap_or_else(|| panic!("child killed by signal")) - ); - - umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); - } + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); +} - pub fn test_mount_rdonly_disallows_write() { - let tempdir = tempfile::tempdir().unwrap(); +#[test] +fn test_mount_noexec_disallows_exec() { + require_capability!("test_mount_noexec_disallows_exec", CAP_SYS_ADMIN); + let tempdir = tempfile::tempdir().unwrap(); + + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::MS_NOEXEC, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {e}")); + + let test_path = tempdir.path().join("test"); + + fs::OpenOptions::new() + .create(true) + .write(true) + .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) + .open(&test_path) + .and_then(|mut f| f.write(SCRIPT_CONTENTS)) + .unwrap_or_else(|e| panic!("write failed: {e}")); + + // Verify that we cannot execute despite a+x permissions being set. + let mode = stat::Mode::from_bits_truncate( + fs::metadata(&test_path) + .map(|md| md.permissions().mode()) + .unwrap_or_else(|e| panic!("metadata failed: {e}")), + ); - mount( - NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_RDONLY, - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {e}")); + assert!( + mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH), + "{:?} did not have execute permissions", + &test_path + ); + + // EACCES: Permission denied + assert_eq!( + EACCES, + Command::new(&test_path) + .status() + .unwrap_err() + .raw_os_error() + .unwrap() + ); - // EROFS: Read-only file system - assert_eq!( - EROFS, - File::create(tempdir.path().join("test")) - .unwrap_err() - .raw_os_error() - .unwrap() - ); + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); +} - umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); - } +#[test] +fn test_mount_bind() { + require_capability!("test_mount_bind", CAP_SYS_ADMIN); + let tempdir = tempfile::tempdir().unwrap(); + let file_name = "test"; - pub fn test_mount_noexec_disallows_exec() { - let tempdir = tempfile::tempdir().unwrap(); + { + let mount_point = tempfile::tempdir().unwrap(); mount( + Some(tempdir.path()), + mount_point.path(), NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_NOEXEC, + MsFlags::MS_BIND, NONE, ) .unwrap_or_else(|e| panic!("mount failed: {e}")); - let test_path = tempdir.path().join("test"); - fs::OpenOptions::new() .create(true) .write(true) .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) - .open(&test_path) + .open(mount_point.path().join(file_name)) .and_then(|mut f| f.write(SCRIPT_CONTENTS)) .unwrap_or_else(|e| panic!("write failed: {e}")); - // Verify that we cannot execute despite a+x permissions being set. - let mode = stat::Mode::from_bits_truncate( - fs::metadata(&test_path) - .map(|md| md.permissions().mode()) - .unwrap_or_else(|e| panic!("metadata failed: {e}")), - ); - - assert!( - mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH), - "{:?} did not have execute permissions", - &test_path - ); - - // EACCES: Permission denied - assert_eq!( - EACCES, - Command::new(&test_path) - .status() - .unwrap_err() - .raw_os_error() - .unwrap() - ); - - umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); + umount(mount_point.path()) + .unwrap_or_else(|e| panic!("umount failed: {e}")); } - pub fn test_mount_bind() { - let tempdir = tempfile::tempdir().unwrap(); - let file_name = "test"; - - { - let mount_point = tempfile::tempdir().unwrap(); - - mount( - Some(tempdir.path()), - mount_point.path(), - NONE, - MsFlags::MS_BIND, - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {e}")); - - fs::OpenOptions::new() - .create(true) - .write(true) - .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) - .open(mount_point.path().join(file_name)) - .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {e}")); - - umount(mount_point.path()) - .unwrap_or_else(|e| panic!("umount failed: {e}")); - } - - // Verify the file written in the mount shows up in source directory, even - // after unmounting. - - let mut buf = Vec::new(); - File::open(tempdir.path().join(file_name)) - .and_then(|mut f| f.read_to_end(&mut buf)) - .unwrap_or_else(|e| panic!("read failed: {e}")); - assert_eq!(buf, SCRIPT_CONTENTS); - } + // Verify the file written in the mount shows up in source directory, even + // after unmounting. - pub fn setup_namespaces() { - // Hold on to the uid in the parent namespace. - let uid = getuid(); - - unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| { - let stderr = io::stderr(); - let mut handle = stderr.lock(); - writeln!(handle, - "unshare failed: {e}. Are unprivileged user namespaces available?").unwrap(); - writeln!(handle, "mount is not being tested").unwrap(); - // Exit with success because not all systems support unprivileged user namespaces, and - // that's not what we're testing for. - process::exit(0); - }); - - // Map user as uid 1000. - fs::OpenOptions::new() - .write(true) - .open("/proc/self/uid_map") - .and_then(|mut f| f.write(format!("1000 {uid} 1\n").as_bytes())) - .unwrap_or_else(|e| panic!("could not write uid map: {e}")); - } + let mut buf = Vec::new(); + File::open(tempdir.path().join(file_name)) + .and_then(|mut f| f.read_to_end(&mut buf)) + .unwrap_or_else(|e| panic!("read failed: {e}")); + assert_eq!(buf, SCRIPT_CONTENTS); } - -// Test runner - -/// Mimic normal test output (hackishly). -#[cfg(target_os = "linux")] -macro_rules! run_tests { - ( $($test_fn:ident),* ) => {{ - println!(); - - $( - print!("test test_mount::{} ... ", stringify!($test_fn)); - $test_fn(); - println!("ok"); - )* - - println!(); - }} -} - -#[cfg(target_os = "linux")] -fn main() { - use test_mount::{ - setup_namespaces, test_mount_bind, test_mount_noexec_disallows_exec, - test_mount_rdonly_disallows_write, - test_mount_tmpfs_without_flags_allows_rwx, - }; - skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351"); - setup_namespaces(); - - run_tests!( - test_mount_tmpfs_without_flags_allows_rwx, - test_mount_rdonly_disallows_write, - test_mount_noexec_disallows_exec, - test_mount_bind - ); -} - -#[cfg(not(target_os = "linux"))] -fn main() {} diff --git a/third_party/rust/nix/test/test_mq.rs b/third_party/rust/nix/test/test_mq.rs index 1fd8929c17..874a72b44d 100644 --- a/third_party/rust/nix/test/test_mq.rs +++ b/third_party/rust/nix/test/test_mq.rs @@ -112,7 +112,15 @@ fn test_mq_getattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg_attr( - all(qemu, any(target_arch = "mips", target_arch = "mips64")), + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + ) + ), ignore )] fn test_mq_setattr() { @@ -162,7 +170,15 @@ fn test_mq_setattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg_attr( - all(qemu, any(target_arch = "mips", target_arch = "mips64")), + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + ) + ), ignore )] fn test_mq_set_nonblocking() { diff --git a/third_party/rust/nix/test/test_net.rs b/third_party/rust/nix/test/test_net.rs index c44655a4c9..faba8503fe 100644 --- a/third_party/rust/nix/test/test_net.rs +++ b/third_party/rust/nix/test/test_net.rs @@ -1,13 +1,9 @@ use nix::net::if_::*; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] const LOOPBACK: &[u8] = b"lo"; -#[cfg(not(any( - target_os = "android", - target_os = "linux", - target_os = "haiku" -)))] +#[cfg(not(any(linux_android, target_os = "haiku")))] const LOOPBACK: &[u8] = b"lo0"; #[cfg(target_os = "haiku")] diff --git a/third_party/rust/nix/test/test_poll.rs b/third_party/rust/nix/test/test_poll.rs index 045ccd3df1..fcb325494e 100644 --- a/third_party/rust/nix/test/test_poll.rs +++ b/third_party/rust/nix/test/test_poll.rs @@ -1,9 +1,9 @@ use nix::{ errno::Errno, - poll::{poll, PollFd, PollFlags}, - unistd::{close, pipe, write}, + poll::{poll, PollFd, PollFlags, PollTimeout}, + unistd::{pipe, write}, }; -use std::os::unix::io::{BorrowedFd, FromRawFd, OwnedFd}; +use std::os::unix::io::{AsFd, BorrowedFd}; macro_rules! loop_while_eintr { ($poll_expr: expr) => { @@ -20,32 +20,25 @@ macro_rules! loop_while_eintr { #[test] fn test_poll() { let (r, w) = pipe().unwrap(); - let r = unsafe { OwnedFd::from_raw_fd(r) }; - let mut fds = [PollFd::new(&r, PollFlags::POLLIN)]; + let mut fds = [PollFd::new(r.as_fd(), PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout - let nfds = loop_while_eintr!(poll(&mut fds, 100)); + let nfds = loop_while_eintr!(poll(&mut fds, PollTimeout::from(100u8))); assert_eq!(nfds, 0); assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - write(w, b".").unwrap(); + write(&w, b".").unwrap(); // Poll a readable pipe. Should return an event. - let nfds = poll(&mut fds, 100).unwrap(); + let nfds = poll(&mut fds, PollTimeout::from(100u8)).unwrap(); assert_eq!(nfds, 1); assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - close(w).unwrap(); } // ppoll(2) is the same as poll except for how it handles timeouts and signals. // Repeating the test for poll(2) should be sufficient to check that our // bindings are correct. -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] +#[cfg(any(linux_android, freebsdlike))] #[test] fn test_ppoll() { use nix::poll::ppoll; @@ -54,8 +47,7 @@ fn test_ppoll() { let timeout = TimeSpec::milliseconds(1); let (r, w) = pipe().unwrap(); - let r = unsafe { OwnedFd::from_raw_fd(r) }; - let mut fds = [PollFd::new(&r, PollFlags::POLLIN)]; + let mut fds = [PollFd::new(r.as_fd(), PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout let sigset = SigSet::empty(); @@ -63,19 +55,18 @@ fn test_ppoll() { assert_eq!(nfds, 0); assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - write(w, b".").unwrap(); + write(&w, b".").unwrap(); // Poll a readable pipe. Should return an event. let nfds = ppoll(&mut fds, Some(timeout), None).unwrap(); assert_eq!(nfds, 1); assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - close(w).unwrap(); } #[test] fn test_pollfd_events() { let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; - let mut pfd = PollFd::new(&fd_zero, PollFlags::POLLIN); + let mut pfd = PollFd::new(fd_zero.as_fd(), PollFlags::POLLIN); assert_eq!(pfd.events(), PollFlags::POLLIN); pfd.set_events(PollFlags::POLLOUT); assert_eq!(pfd.events(), PollFlags::POLLOUT); diff --git a/third_party/rust/nix/test/test_pty.rs b/third_party/rust/nix/test/test_pty.rs index 4cc6620c3c..368ec129b0 100644 --- a/third_party/rust/nix/test/test_pty.rs +++ b/third_party/rust/nix/test/test_pty.rs @@ -1,9 +1,9 @@ use std::fs::File; -use std::io::{Read, Write}; +use std::io::{stdout, Read, Write}; use std::os::unix::prelude::*; use std::path::Path; -use libc::{_exit, STDOUT_FILENO}; +use libc::_exit; use nix::fcntl::{open, OFlag}; use nix::pty::*; use nix::sys::stat; @@ -12,7 +12,7 @@ use nix::unistd::{pause, write}; /// Test equivalence of `ptsname` and `ptsname_r` #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptsname_equivalence() { let _m = crate::PTSNAME_MTX.lock(); @@ -29,7 +29,7 @@ fn test_ptsname_equivalence() { /// Test data copying of `ptsname` // TODO need to run in a subprocess, since ptsname is non-reentrant #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptsname_copy() { let _m = crate::PTSNAME_MTX.lock(); @@ -47,7 +47,7 @@ fn test_ptsname_copy() { /// Test data copying of `ptsname_r` #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptsname_r_copy() { // Open a new PTTY master let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); @@ -61,7 +61,7 @@ fn test_ptsname_r_copy() { /// Test that `ptsname` returns different names for different devices #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptsname_unique() { let _m = crate::PTSNAME_MTX.lock(); @@ -96,7 +96,7 @@ fn open_ptty_pair() -> (PtyMaster, File) { open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()) .unwrap(); - #[cfg(target_os = "illumos")] + #[cfg(solarish)] // TODO: rewrite using ioctl! #[allow(clippy::comparison_chain)] { @@ -185,7 +185,7 @@ fn test_openpty() { // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master.as_raw_fd(), string.as_bytes()).unwrap(); + write(&pty.master, string.as_bytes()).unwrap(); crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -199,7 +199,7 @@ fn test_openpty() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\r\n"; let mut buf = [0u8; 14]; - write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + write(&pty.slave, string2.as_bytes()).unwrap(); crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -224,7 +224,7 @@ fn test_openpty_with_termios() { // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master.as_raw_fd(), string.as_bytes()).unwrap(); + write(&pty.master, string.as_bytes()).unwrap(); crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -237,7 +237,7 @@ fn test_openpty_with_termios() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\n"; let mut buf = [0u8; 13]; - write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + write(&pty.slave, string2.as_bytes()).unwrap(); crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -258,7 +258,7 @@ fn test_forkpty() { let pty = unsafe { forkpty(None, None).unwrap() }; match pty.fork_result { Child => { - write(STDOUT_FILENO, string.as_bytes()).unwrap(); + write(stdout(), string.as_bytes()).unwrap(); pause(); // we need the child to stay alive until the parent calls read unsafe { _exit(0); diff --git a/third_party/rust/nix/test/test_resource.rs b/third_party/rust/nix/test/test_resource.rs deleted file mode 100644 index 2ab581ba29..0000000000 --- a/third_party/rust/nix/test/test_resource.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "illumos", - target_os = "haiku" -)))] -use nix::sys::resource::{getrlimit, setrlimit, Resource}; - -/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers -/// to the maximum file descriptor number that can be opened by the process (aka the maximum number -/// of file descriptors that the process can open, since Linux 4.5). -/// -/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the -/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit() -/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have -/// been updated. -#[test] -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "illumos", - target_os = "haiku" -)))] -pub fn test_resource_limits_nofile() { - let (mut soft_limit, hard_limit) = - getrlimit(Resource::RLIMIT_NOFILE).unwrap(); - - soft_limit -= 1; - assert_ne!(soft_limit, hard_limit); - setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); - - let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); - assert_eq!(new_soft_limit, soft_limit); -} diff --git a/third_party/rust/nix/test/test_sendfile.rs b/third_party/rust/nix/test/test_sendfile.rs index b85e030fd3..6333bf8662 100644 --- a/third_party/rust/nix/test/test_sendfile.rs +++ b/third_party/rust/nix/test/test_sendfile.rs @@ -1,21 +1,20 @@ use std::io::prelude::*; -#[cfg(any(target_os = "android", target_os = "linux"))] -use std::os::unix::io::{FromRawFd, OwnedFd}; use libc::off_t; use nix::sys::sendfile::*; use tempfile::tempfile; cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - use nix::unistd::{close, pipe, read}; - } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] { + if #[cfg(linux_android)] { + use nix::unistd::{pipe, read}; + use std::os::unix::io::AsRawFd; + } else if #[cfg(any(freebsdlike, apple_targets, solarish))] { use std::net::Shutdown; use std::os::unix::net::UnixStream; } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] fn test_sendfile_linux() { const CONTENTS: &[u8] = b"abcdef123456"; @@ -24,21 +23,14 @@ fn test_sendfile_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: off_t = 5; - // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` - // becomes I/O-safe: - // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> - // then it is no longer needed. - let wr = unsafe { OwnedFd::from_raw_fd(wr) }; let res = sendfile(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); } #[cfg(target_os = "linux")] @@ -50,21 +42,14 @@ fn test_sendfile64_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: libc::off64_t = 5; - // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` - // becomes I/O-safe: - // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> - // then it is no longer needed. - let wr = unsafe { OwnedFd::from_raw_fd(wr) }; let res = sendfile64(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); } #[cfg(target_os = "freebsd")] @@ -167,7 +152,7 @@ fn test_sendfile_dragonfly() { assert_eq!(expected_string, read_string); } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] #[test] fn test_sendfile_darwin() { // Declare the content @@ -215,3 +200,62 @@ fn test_sendfile_darwin() { assert_eq!(bytes_written as usize, bytes_read); assert_eq!(expected_string, read_string); } + +#[cfg(solarish)] +#[test] +fn test_sendfilev() { + use std::os::fd::AsFd; + // Declare the content + let header_strings = + ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let body = "Xabcdef123456"; + let body_offset = 1usize; + let trailer_strings = ["\n", "Served by Make Believe\n"]; + + // Write data to files + let mut header_data = tempfile().unwrap(); + header_data + .write_all(header_strings.concat().as_bytes()) + .unwrap(); + let mut body_data = tempfile().unwrap(); + body_data.write_all(body.as_bytes()).unwrap(); + let mut trailer_data = tempfile().unwrap(); + trailer_data + .write_all(trailer_strings.concat().as_bytes()) + .unwrap(); + let (mut rd, wr) = UnixStream::pair().unwrap(); + let vec: &[SendfileVec] = &[ + SendfileVec::new( + header_data.as_fd(), + 0, + header_strings.iter().map(|s| s.len()).sum(), + ), + SendfileVec::new( + body_data.as_fd(), + body_offset as off_t, + body.len() - body_offset, + ), + SendfileVec::new( + trailer_data.as_fd(), + 0, + trailer_strings.iter().map(|s| s.len()).sum(), + ), + ]; + + let (res, bytes_written) = sendfilev(&wr, vec); + assert!(res.is_ok()); + wr.shutdown(Shutdown::Both).unwrap(); + + // Prepare the expected result + let expected_string = header_strings.concat() + + &body[body_offset..] + + &trailer_strings.concat(); + + // Verify the message that was sent + assert_eq!(bytes_written, expected_string.as_bytes().len()); + + let mut read_string = String::new(); + let bytes_read = rd.read_to_string(&mut read_string).unwrap(); + assert_eq!(bytes_written, bytes_read); + assert_eq!(expected_string, read_string); +} diff --git a/third_party/rust/nix/test/test_stat.rs b/third_party/rust/nix/test/test_stat.rs index 55f15c0771..386f1084cc 100644 --- a/third_party/rust/nix/test/test_stat.rs +++ b/third_party/rust/nix/test/test_stat.rs @@ -21,8 +21,7 @@ use nix::errno::Errno; use nix::fcntl; #[cfg(any( target_os = "linux", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ))] @@ -117,7 +116,7 @@ fn test_fstatat() { fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()); let result = - stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty()); + stat::fstatat(Some(dirfd.unwrap()), &filename, fcntl::AtFlags::empty()); assert_stat_results(result); } @@ -235,8 +234,7 @@ fn test_utimes() { #[test] #[cfg(any( target_os = "linux", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ))] @@ -323,7 +321,7 @@ fn test_mkdirat_success_path() { let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed"); assert!(Path::exists(&tempdir.path().join(filename))); } @@ -337,7 +335,7 @@ fn test_mkdirat_success_mode() { let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed"); let permissions = fs::metadata(tempdir.path().join(filename)) .unwrap() .permissions(); @@ -357,16 +355,14 @@ fn test_mkdirat_fail() { stat::Mode::empty(), ) .unwrap(); - let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); + let result = mkdirat(Some(dirfd), filename, Mode::S_IRWXU).unwrap_err(); assert_eq!(result, Errno::ENOTDIR); } #[test] #[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", + freebsdlike, + apple_targets, target_os = "haiku", target_os = "redox" )))] @@ -384,11 +380,9 @@ fn test_mknod() { #[test] #[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", + solarish, + freebsdlike, + apple_targets, target_os = "haiku", target_os = "redox" )))] @@ -402,7 +396,7 @@ fn test_mknodat() { let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); mknodat( - target_dir.as_raw_fd(), + Some(target_dir.as_raw_fd()), file_name, SFlag::S_IFREG, Mode::S_IRWXU, @@ -410,7 +404,7 @@ fn test_mknodat() { ) .unwrap(); let mode = fstatat( - target_dir.as_raw_fd(), + Some(target_dir.as_raw_fd()), file_name, AtFlags::AT_SYMLINK_NOFOLLOW, ) @@ -419,3 +413,75 @@ fn test_mknodat() { assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); } + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_futimens_unchanged() { + let tempdir = tempfile::tempdir().unwrap(); + let fullpath = tempdir.path().join("file"); + drop(File::create(&fullpath).unwrap()); + let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + let old_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let old_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + + futimens(fd, &TimeSpec::UTIME_OMIT, &TimeSpec::UTIME_OMIT).unwrap(); + + let new_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let new_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + assert_eq!(old_atime, new_atime); + assert_eq!(old_mtime, new_mtime); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_utimensat_unchanged() { + let _dr = crate::DirRestore::new(); + let tempdir = tempfile::tempdir().unwrap(); + let filename = "foo.txt"; + let fullpath = tempdir.path().join(filename); + drop(File::create(&fullpath).unwrap()); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + let old_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let old_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + utimensat( + Some(dirfd), + filename, + &TimeSpec::UTIME_OMIT, + &TimeSpec::UTIME_OMIT, + UtimensatFlags::NoFollowSymlink, + ) + .unwrap(); + let new_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let new_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + assert_eq!(old_atime, new_atime); + assert_eq!(old_mtime, new_mtime); +} diff --git a/third_party/rust/nix/test/test_time.rs b/third_party/rust/nix/test/test_time.rs index 5f76e61a2d..64c8161dbf 100644 --- a/third_party/rust/nix/test/test_time.rs +++ b/third_party/rust/nix/test/test_time.rs @@ -1,10 +1,4 @@ -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] use nix::time::clock_getcpuclockid; use nix::time::{clock_gettime, ClockId}; @@ -19,13 +13,7 @@ pub fn test_clock_gettime() { clock_gettime(ClockId::CLOCK_REALTIME).expect("assertion failed"); } -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] #[test] pub fn test_clock_getcpuclockid() { let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); @@ -43,13 +31,7 @@ pub fn test_clock_id_now() { ClockId::CLOCK_REALTIME.now().unwrap(); } -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] #[test] pub fn test_clock_id_pid_cpu_clock_id() { ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) @@ -57,3 +39,28 @@ pub fn test_clock_id_pid_cpu_clock_id() { .unwrap() .unwrap(); } + +#[cfg(any( + linux_android, + solarish, + freebsdlike, + target_os = "netbsd", + target_os = "hurd", + target_os = "aix" +))] +#[test] +pub fn test_clock_nanosleep() { + use nix::{ + sys::time::{TimeSpec, TimeValLike}, + time::{clock_nanosleep, ClockNanosleepFlags}, + }; + + let sleep_time = TimeSpec::microseconds(1); + let res = clock_nanosleep( + ClockId::CLOCK_MONOTONIC, + ClockNanosleepFlags::empty(), + &sleep_time, + ); + let expected = TimeSpec::microseconds(0); + assert_eq!(res, Ok(expected)); +} diff --git a/third_party/rust/nix/test/test_timer.rs b/third_party/rust/nix/test/test_timer.rs deleted file mode 100644 index ffd146867b..0000000000 --- a/third_party/rust/nix/test/test_timer.rs +++ /dev/null @@ -1,102 +0,0 @@ -use nix::sys::signal::{ - sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, - Signal, -}; -use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; -use nix::time::ClockId; -use std::convert::TryFrom; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::thread; -use std::time::{Duration, Instant}; - -const SIG: Signal = Signal::SIGALRM; -static ALARM_CALLED: AtomicBool = AtomicBool::new(false); - -pub extern "C" fn handle_sigalarm(raw_signal: libc::c_int) { - let signal = Signal::try_from(raw_signal).unwrap(); - if signal == SIG { - ALARM_CALLED.store(true, Ordering::Release); - } -} - -#[test] -fn alarm_fires() { - // Avoid interfering with other signal using tests by taking a mutex shared - // among other tests in this crate. - let _m = crate::SIGNAL_MTX.lock(); - const TIMER_PERIOD: Duration = Duration::from_millis(100); - - // - // Setup - // - - // Create a handler for the test signal, `SIG`. The handler is responsible - // for flipping `ALARM_CALLED`. - let handler = SigHandler::Handler(handle_sigalarm); - let signal_action = - SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); - let old_handler = unsafe { - sigaction(SIG, &signal_action) - .expect("unable to set signal handler for alarm") - }; - - // Create the timer. We use the monotonic clock here, though any would do - // really. The timer is set to fire every 250 milliseconds with no delay for - // the initial firing. - let clockid = ClockId::CLOCK_MONOTONIC; - let sigevent = SigEvent::new(SigevNotify::SigevSignal { - signal: SIG, - si_value: 0, - }); - let mut timer = - Timer::new(clockid, sigevent).expect("failed to create timer"); - let expiration = Expiration::Interval(TIMER_PERIOD.into()); - let flags = TimerSetTimeFlags::empty(); - timer.set(expiration, flags).expect("could not set timer"); - - // - // Test - // - - // Determine that there's still an expiration tracked by the - // timer. Depending on when this runs either an `Expiration::Interval` or - // `Expiration::IntervalDelayed` will be present. That is, if the timer has - // not fired yet we'll get our original `expiration`, else the one that - // represents a delay to the next expiration. We're only interested in the - // timer still being extant. - match timer.get() { - Ok(Some(exp)) => assert!(matches!( - exp, - Expiration::Interval(..) | Expiration::IntervalDelayed(..) - )), - _ => panic!("timer lost its expiration"), - } - - // Wait for 2 firings of the alarm before checking that it has fired and - // been handled at least the once. If we wait for 3 seconds and the handler - // is never called something has gone sideways and the test fails. - let starttime = Instant::now(); - loop { - thread::sleep(2 * TIMER_PERIOD); - if ALARM_CALLED.load(Ordering::Acquire) { - break; - } - if starttime.elapsed() > Duration::from_secs(3) { - panic!("Timeout waiting for SIGALRM"); - } - } - - // Cleanup: - // 1) deregister the OS's timer. - // 2) Wait for a full timer period, since POSIX does not require that - // disabling the timer will clear pending signals, and on NetBSD at least - // it does not. - // 2) Replace the old signal handler now that we've completed the test. If - // the test fails this process panics, so the fact we might not get here - // is okay. - drop(timer); - thread::sleep(TIMER_PERIOD); - unsafe { - sigaction(SIG, &old_handler).expect("unable to reset signal handler"); - } -} diff --git a/third_party/rust/nix/test/test_unistd.rs b/third_party/rust/nix/test/test_unistd.rs index 10284e4127..aa2e5e56d7 100644 --- a/third_party/rust/nix/test/test_unistd.rs +++ b/third_party/rust/nix/test/test_unistd.rs @@ -66,6 +66,37 @@ fn test_fork_and_waitpid() { } } +#[test] +#[cfg(target_os = "freebsd")] +fn test_rfork_and_waitpid() { + let _m = crate::FORK_MTX.lock(); + + // Safe: Child only calls `_exit`, which is signal-safe + match unsafe { rfork(RforkFlags::RFPROC | RforkFlags::RFTHREAD) } + .expect("Error: Rfork Failed") + { + Child => unsafe { _exit(0) }, + Parent { child } => { + // assert that child was created and pid > 0 + let child_raw: ::libc::pid_t = child.into(); + assert!(child_raw > 0); + let wait_status = waitpid(child, None); + match wait_status { + // assert that waitpid returned correct status and the pid is the one of the child + Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child), + + // panic, must never happen + s @ Ok(_) => { + panic!("Child exited {s:?}, should never happen") + } + + // panic, waitpid should never fail + Err(s) => panic!("Error: waitpid returned Err({s:?}"), + } + } + } +} + #[test] fn test_wait() { // Grab FORK_MTX so wait doesn't reap a different test's child process @@ -126,8 +157,7 @@ fn test_mkfifo_directory() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -147,8 +177,7 @@ fn test_mkfifoat_none() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -163,15 +192,15 @@ fn test_mkfifoat() { mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); let stats = - stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); + stat::fstatat(Some(dirfd), mkfifoat_name, fcntl::AtFlags::empty()) + .unwrap(); let typ = stat::SFlag::from_bits_truncate(stats.st_mode); assert_eq!(typ, SFlag::S_IFIFO); } #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -186,8 +215,7 @@ fn test_mkfifoat_directory_none() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -197,7 +225,7 @@ fn test_mkfifoat_directory() { let tempdir = tempdir().unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let mkfifoat_dir = "mkfifoat_dir"; - stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); + stat::mkdirat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).unwrap(); mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR) .expect_err("assertion failed"); @@ -220,7 +248,7 @@ fn test_getsid() { assert_eq!(none_sid, pid_sid); } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] mod linux_android { use nix::unistd::gettid; @@ -234,8 +262,7 @@ mod linux_android { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "fuchsia", target_os = "haiku" @@ -263,12 +290,11 @@ fn test_setgroups() { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos" + solarish )))] fn test_initgroups() { // Skip this test when not run as root as `initgroups()` and `setgroups()` @@ -356,7 +382,7 @@ macro_rules! execve_test_factory ( match unsafe{fork()}.unwrap() { Child => { // Make `writer` be the stdout of the new process. - dup2(writer, 1).unwrap(); + dup2(writer.as_raw_fd(), 1).unwrap(); let r = syscall(); let _ = std::io::stderr() .write_all(format!("{:?}", r).as_bytes()); @@ -370,7 +396,7 @@ macro_rules! execve_test_factory ( assert_eq!(ws, Ok(WaitStatus::Exited(child, 0))); // Read 1024 bytes. let mut buf = [0u8; 1024]; - read(reader, &mut buf).unwrap(); + read(reader.as_raw_fd(), &mut buf).unwrap(); // It should contain the things we printed using `/bin/sh`. let string = String::from_utf8_lossy(&buf); assert!(string.contains("nix!!!")); @@ -404,46 +430,44 @@ cfg_if! { if #[cfg(target_os = "android")] { execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str()); execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux"))] { + } else if #[cfg(any(freebsdlike, target_os = "linux", target_os = "hurd"))] { // These tests frequently fail on musl, probably due to // https://github.com/nix-rust/nix/issues/555 execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { + } else if #[cfg(any(solarish, apple_targets, netbsdlike))] { execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); // No fexecve() on ios, macos, NetBSD, OpenBSD. } } -#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] +#[cfg(any( + target_os = "haiku", + target_os = "hurd", + target_os = "linux", + target_os = "openbsd" +))] execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap()); cfg_if! { if #[cfg(target_os = "android")] { use nix::fcntl::AtFlags; execve_test_factory!(test_execveat_empty, execveat, - File::open("/system/bin/sh").unwrap().into_raw_fd(), + Some(File::open("/system/bin/sh").unwrap().into_raw_fd()), "", AtFlags::AT_EMPTY_PATH); execve_test_factory!(test_execveat_relative, execveat, - File::open("/system/bin/").unwrap().into_raw_fd(), + Some(File::open("/system/bin/").unwrap().into_raw_fd()), "./sh", AtFlags::empty()); execve_test_factory!(test_execveat_absolute, execveat, - File::open("/").unwrap().into_raw_fd(), + Some(File::open("/").unwrap().into_raw_fd()), "/system/bin/sh", AtFlags::empty()); } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] { use nix::fcntl::AtFlags; - execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(), + execve_test_factory!(test_execveat_empty, execveat, Some(File::open("/bin/sh").unwrap().into_raw_fd()), "", AtFlags::AT_EMPTY_PATH); - execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(), + execve_test_factory!(test_execveat_relative, execveat, Some(File::open("/bin/").unwrap().into_raw_fd()), "./sh", AtFlags::empty()); - execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), + execve_test_factory!(test_execveat_absolute, execveat, Some(File::open("/").unwrap().into_raw_fd()), "/bin/sh", AtFlags::empty()); } } @@ -527,6 +551,8 @@ fn test_fchown() { #[test] #[cfg(not(target_os = "redox"))] fn test_fchownat() { + use nix::fcntl::AtFlags; + let _dr = crate::DirRestore::new(); // Testing for anything other than our own UID/GID is hard. let uid = Some(getuid()); @@ -540,14 +566,13 @@ fn test_fchownat() { let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink) - .unwrap(); + fchownat(Some(dirfd), "file", uid, gid, AtFlags::empty()).unwrap(); chdir(tempdir.path()).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); + fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap(); fs::remove_file(&path).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err(); + fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap_err(); } #[test] @@ -564,7 +589,7 @@ fn test_lseek() { assert_eq!(b"f123456", &buf); } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[test] fn test_lseek64() { const CONTENTS: &[u8] = b"abcdef123456"; @@ -579,7 +604,7 @@ fn test_lseek64() { } cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { macro_rules! require_acct{ () => { require_capability!("test_acct", CAP_SYS_PACCT); @@ -631,11 +656,12 @@ fn test_acct() { acct::disable().unwrap(); } +#[cfg_attr(target_os = "hurd", ignore)] #[test] fn test_fpathconf_limited() { let f = tempfile().unwrap(); - // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test - let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX); + // PATH_MAX is limited on most platforms, so it makes a good test + let path_max = fpathconf(f, PathconfVar::PATH_MAX); assert!( path_max .expect("fpathconf failed") @@ -644,9 +670,10 @@ fn test_fpathconf_limited() { ); } +#[cfg_attr(target_os = "hurd", ignore)] #[test] fn test_pathconf_limited() { - // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test + // PATH_MAX is limited on most platforms, so it makes a good test let path_max = pathconf("/", PathconfVar::PATH_MAX); assert!( path_max @@ -656,9 +683,10 @@ fn test_pathconf_limited() { ); } +#[cfg_attr(target_os = "hurd", ignore)] #[test] fn test_sysconf_limited() { - // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test + // OPEN_MAX is limited on most platforms, so it makes a good test let open_max = sysconf(SysconfVar::OPEN_MAX); assert!( open_max @@ -678,13 +706,7 @@ fn test_sysconf_unsupported() { assert!(open_max.expect("sysconf failed").is_none()) } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] #[test] fn test_getresuid() { let resuids = getresuid().unwrap(); @@ -693,13 +715,7 @@ fn test_getresuid() { assert_ne!(resuids.saved.as_raw(), libc::uid_t::MAX); } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] #[test] fn test_getresgid() { let resgids = getresgid().unwrap(); @@ -714,12 +730,12 @@ fn test_getresgid() { fn test_pipe() { let (fd0, fd1) = pipe().unwrap(); let m0 = stat::SFlag::from_bits_truncate( - stat::fstat(fd0).unwrap().st_mode as mode_t, + stat::fstat(fd0.as_raw_fd()).unwrap().st_mode as mode_t, ); // S_IFIFO means it's a pipe assert_eq!(m0, SFlag::S_IFIFO); let m1 = stat::SFlag::from_bits_truncate( - stat::fstat(fd1).unwrap().st_mode as mode_t, + stat::fstat(fd1.as_raw_fd()).unwrap().st_mode as mode_t, ); assert_eq!(m1, SFlag::S_IFIFO); } @@ -727,25 +743,25 @@ fn test_pipe() { // pipe2(2) is the same as pipe(2), except it allows setting some flags. Check // that we can set a flag. #[cfg(any( - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, + solarish, + netbsdlike, target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", target_os = "redox", - target_os = "solaris" ))] #[test] fn test_pipe2() { use nix::fcntl::{fcntl, FcntlArg, FdFlag}; let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap(); - let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap()); + let f0 = FdFlag::from_bits_truncate( + fcntl(fd0.as_raw_fd(), FcntlArg::F_GETFD).unwrap(), + ); assert!(f0.contains(FdFlag::FD_CLOEXEC)); - let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap()); + let f1 = FdFlag::from_bits_truncate( + fcntl(fd1.as_raw_fd(), FcntlArg::F_GETFD).unwrap(), + ); assert!(f1.contains(FdFlag::FD_CLOEXEC)); } @@ -881,6 +897,8 @@ fn test_symlinkat() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_file() { + use nix::fcntl::AtFlags; + let tempdir = tempdir().unwrap(); let oldfilename = "foo.txt"; let oldfilepath = tempdir.path().join(oldfilename); @@ -902,7 +920,7 @@ fn test_linkat_file() { oldfilename, Some(dirfd), newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); assert!(newfilepath.exists()); @@ -911,6 +929,8 @@ fn test_linkat_file() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_olddirfd_none() { + use nix::fcntl::AtFlags; + let _dr = crate::DirRestore::new(); let tempdir_oldfile = tempdir().unwrap(); @@ -939,7 +959,7 @@ fn test_linkat_olddirfd_none() { oldfilename, Some(dirfd), newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); assert!(newfilepath.exists()); @@ -948,6 +968,8 @@ fn test_linkat_olddirfd_none() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_newdirfd_none() { + use nix::fcntl::AtFlags; + let _dr = crate::DirRestore::new(); let tempdir_oldfile = tempdir().unwrap(); @@ -976,20 +998,17 @@ fn test_linkat_newdirfd_none() { oldfilename, None, newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); assert!(newfilepath.exists()); } #[test] -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "haiku" -)))] +#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))] fn test_linkat_no_follow_symlink() { + use nix::fcntl::AtFlags; + let _m = crate::CWD_LOCK.read(); let tempdir = tempdir().unwrap(); @@ -1019,7 +1038,7 @@ fn test_linkat_no_follow_symlink() { symoldfilename, Some(dirfd), newfilename, - LinkatFlags::NoSymlinkFollow, + AtFlags::empty(), ) .unwrap(); @@ -1033,6 +1052,8 @@ fn test_linkat_no_follow_symlink() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_follow_symlink() { + use nix::fcntl::AtFlags; + let _m = crate::CWD_LOCK.read(); let tempdir = tempdir().unwrap(); @@ -1062,7 +1083,7 @@ fn test_linkat_follow_symlink() { symoldfilename, Some(dirfd), newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); @@ -1070,8 +1091,8 @@ fn test_linkat_follow_symlink() { // Check the file type of the new link assert_eq!( - (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) - & SFlag::S_IFMT), + stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) + & SFlag::S_IFMT, SFlag::S_IFREG ); @@ -1159,8 +1180,6 @@ fn test_access_file_exists() { .expect("assertion failed"); } -//Clippy false positive https://github.com/rust-lang/rust-clippy/issues/9111 -#[allow(clippy::needless_borrow)] #[cfg(not(target_os = "redox"))] #[test] fn test_user_into_passwd() { @@ -1177,7 +1196,7 @@ fn test_user_into_passwd() { } /// Tests setting the filesystem UID with `setfsuid`. -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[test] fn test_setfsuid() { use std::os::unix::fs::PermissionsExt; @@ -1230,9 +1249,11 @@ fn test_ttyname() { grantpt(&fd).expect("grantpt failed"); unlockpt(&fd).expect("unlockpt failed"); let sname = unsafe { ptsname(&fd) }.expect("ptsname failed"); - let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty()) + let fds = fs::OpenOptions::new() + .read(true) + .write(true) + .open(Path::new(&sname)) .expect("open failed"); - assert!(fds > 0); let name = ttyname(fds).expect("ttyname failed"); assert!(name.starts_with("/dev")); @@ -1242,35 +1263,17 @@ fn test_ttyname() { #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] fn test_ttyname_not_pty() { let fd = File::open("/dev/zero").unwrap(); - assert!(fd.as_raw_fd() > 0); - assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY)); + assert_eq!(ttyname(fd), Err(Errno::ENOTTY)); } #[test] -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -fn test_ttyname_invalid_fd() { - assert_eq!(ttyname(-1), Err(Errno::EBADF)); -} - -#[test] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", -))] +#[cfg(bsd)] fn test_getpeereid() { use std::os::unix::net::UnixStream; let (sock_a, sock_b) = UnixStream::pair().unwrap(); - let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap(); - let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap(); + let (uid_a, gid_a) = getpeereid(sock_a).unwrap(); + let (uid_b, gid_b) = getpeereid(sock_b).unwrap(); let uid = geteuid(); let gid = getegid(); @@ -1281,20 +1284,6 @@ fn test_getpeereid() { assert_eq!(gid_a, gid_b); } -#[test] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", -))] -fn test_getpeereid_invalid_fd() { - // getpeereid is not POSIX, so error codes are inconsistent between different Unices. - getpeereid(-1).expect_err("assertion failed"); -} - #[test] #[cfg(not(target_os = "redox"))] fn test_faccessat_none_not_existing() { @@ -1364,11 +1353,7 @@ fn test_faccessat_file_exists() { } #[test] -#[cfg(any( - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(all(target_os = "linux", not(target_env = "uclibc")), freebsdlike))] fn test_eaccess_not_existing() { let tempdir = tempdir().unwrap(); let dir = tempdir.path().join("does_not_exist.txt"); @@ -1379,11 +1364,7 @@ fn test_eaccess_not_existing() { } #[test] -#[cfg(any( - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(all(target_os = "linux", not(target_env = "uclibc")), freebsdlike))] fn test_eaccess_file_exists() { let tempdir = tempdir().unwrap(); let path = tempdir.path().join("does_exist.txt"); @@ -1391,3 +1372,14 @@ fn test_eaccess_file_exists() { eaccess(&path, AccessFlags::R_OK | AccessFlags::W_OK) .expect("assertion failed"); } + +#[test] +#[cfg(bsd)] +fn test_group_from() { + let group = Group::from_name("wheel").unwrap().unwrap(); + assert!(group.name == "wheel"); + let group_id = group.gid; + let group = Group::from_gid(group_id).unwrap().unwrap(); + assert_eq!(group.gid, group_id); + assert_eq!(group.name, "wheel"); +} diff --git a/third_party/rust/objc_exception/.cargo-checksum.json b/third_party/rust/objc_exception/.cargo-checksum.json deleted file mode 100644 index ac8ccd308e..0000000000 --- a/third_party/rust/objc_exception/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"4c7727c5464280a94b263b3fbabd775838ce86794834b1adab9bfeefc8a2b731","build.rs":"6734724a6f3c46150f5a6a2adf07b9003ae6f1627fa0ee8fcafa28e9d4aafc15","extern/exception.m":"a6ee21d820126e98ee49ac34db1a6770cfd01f0fb0f71d03127e7eeff91a47c5","src/lib.rs":"24f3b04002dbf24397cc4fd2da7045d49c8b3a06101bab1918d007f7ae9b2207"},"package":"ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"} \ No newline at end of file diff --git a/third_party/rust/objc_exception/Cargo.toml b/third_party/rust/objc_exception/Cargo.toml deleted file mode 100644 index 7cdfacb7f7..0000000000 --- a/third_party/rust/objc_exception/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "objc_exception" -version = "0.1.2" -authors = ["Steven Sheldon"] -build = "build.rs" -exclude = [".gitignore"] -description = "Rust interface for Objective-C's throw and try/catch statements." -documentation = "http://ssheldon.github.io/rust-objc/objc_exception/" -keywords = ["objective-c", "osx", "ios"] -license = "MIT" -repository = "http://github.com/SSheldon/rust-objc-exception" -[build-dependencies.cc] -version = "1" diff --git a/third_party/rust/objc_exception/build.rs b/third_party/rust/objc_exception/build.rs deleted file mode 100644 index ba728b6e16..0000000000 --- a/third_party/rust/objc_exception/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -extern crate cc; - -fn main() { - cc::Build::new() - .file("extern/exception.m") - .compile("libexception.a"); -} diff --git a/third_party/rust/objc_exception/extern/exception.m b/third_party/rust/objc_exception/extern/exception.m deleted file mode 100644 index 700439ecf7..0000000000 --- a/third_party/rust/objc_exception/extern/exception.m +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -void RustObjCExceptionThrow(id exception) { - @throw exception; -} - -int RustObjCExceptionTryCatch(void (*try)(void *), void *context, id *error) { - @try { - try(context); - if (error) { - *error = nil; - } - return 0; - } @catch (id exception) { - if (error) { - *error = [exception retain]; - } - return 1; - } -} diff --git a/third_party/rust/objc_exception/src/lib.rs b/third_party/rust/objc_exception/src/lib.rs deleted file mode 100644 index d381f60c70..0000000000 --- a/third_party/rust/objc_exception/src/lib.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! Rust interface for Objective-C's `@throw` and `@try`/`@catch` statements. - -use std::mem; -use std::os::raw::{c_int, c_void}; -use std::ptr; - -#[link(name = "objc", kind = "dylib")] -extern { } - -extern { - fn RustObjCExceptionThrow(exception: *mut c_void); - fn RustObjCExceptionTryCatch(try: extern fn(*mut c_void), - context: *mut c_void, error: *mut *mut c_void) -> c_int; -} - -/// An opaque type representing any Objective-C object thrown as an exception. -pub enum Exception { } - -/// Throws an Objective-C exception. -/// The argument must be a pointer to an Objective-C object. -/// -/// Unsafe because this unwinds from Objective-C. -pub unsafe fn throw(exception: *mut Exception) -> ! { - RustObjCExceptionThrow(exception as *mut _); - unreachable!(); -} - -unsafe fn try_no_ret(closure: F) -> Result<(), *mut Exception> - where F: FnOnce() { - extern fn try_objc_execute_closure(closure: &mut Option) - where F: FnOnce() { - // This is always passed Some, so it's safe to unwrap - let closure = closure.take().unwrap(); - closure(); - } - - let f: extern fn(&mut Option) = try_objc_execute_closure; - let f: extern fn(*mut c_void) = mem::transmute(f); - // Wrap the closure in an Option so it can be taken - let mut closure = Some(closure); - let context = &mut closure as *mut _ as *mut c_void; - - let mut exception = ptr::null_mut(); - let success = RustObjCExceptionTryCatch(f, context, &mut exception); - - if success == 0 { - Ok(()) - } else { - Err(exception as *mut _) - } -} - -/// Tries to execute the given closure and catches an Objective-C exception -/// if one is thrown. -/// -/// Returns a `Result` that is either `Ok` if the closure succeeded without an -/// exception being thrown, or an `Err` with a pointer to an exception if one -/// was thrown. The exception is retained and so must be released. -/// -/// Unsafe because this encourages unwinding through the closure from -/// Objective-C, which is not safe. -pub unsafe fn try(closure: F) -> Result - where F: FnOnce() -> R { - let mut value = None; - let result = { - let value_ref = &mut value; - try_no_ret(move || { - *value_ref = Some(closure()); - }) - }; - // If the try succeeded, this was set so it's safe to unwrap - result.map(|_| value.unwrap()) -} - -#[cfg(test)] -mod tests { - use std::ptr; - use super::{throw, try}; - - #[test] - fn test_try() { - unsafe { - let s = "Hello".to_string(); - let result = try(move || { - if s.len() > 0 { - throw(ptr::null_mut()); - } - s.len() - }); - assert!(result.unwrap_err() == ptr::null_mut()); - - let mut s = "Hello".to_string(); - let result = try(move || { - s.push_str(", World!"); - s - }); - assert!(result.unwrap() == "Hello, World!"); - } - } -} diff --git a/third_party/rust/owning_ref/.cargo-checksum.json b/third_party/rust/owning_ref/.cargo-checksum.json deleted file mode 100644 index 274171be15..0000000000 --- a/third_party/rust/owning_ref/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"9a3880e4d5435ca03c0197c45d4ce6b6db6d3fb7eda855f297bafc2ec28af836","Cargo.toml":"91184e6b143ddf621fe7e6757fb28d8eb4c0e01f541fbd0dc440bf076ebfd20d","LICENSE":"90bc15ed094593083fd129fdd1a03607be80fe8839c5564616a5961ab7f7a194","README.md":"0dfea39ad1662ed0a61bb1453eafc207a53dfe577e7846c87d3a5161574fdb12","src/lib.rs":"2e423e210bf2e3ee5e4c426b9a3c9b7756fc434beff1ccf9afa48704e4ac993d"},"package":"6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"} \ No newline at end of file diff --git a/third_party/rust/owning_ref/CHANGELOG.md b/third_party/rust/owning_ref/CHANGELOG.md deleted file mode 100644 index a5d24e8c82..0000000000 --- a/third_party/rust/owning_ref/CHANGELOG.md +++ /dev/null @@ -1,8 +0,0 @@ -# Changelog - -## [0.4.1] - 2020-02-27 -### Added -- `map_with_owner` (#51) - -### Changed -- Use dyn for trait objects (#53) diff --git a/third_party/rust/owning_ref/Cargo.toml b/third_party/rust/owning_ref/Cargo.toml deleted file mode 100644 index 057fd5c1bb..0000000000 --- a/third_party/rust/owning_ref/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "owning_ref" -version = "0.4.1" -authors = ["Marvin Löbel "] -description = "A library for creating references that carry their owner with them." -documentation = "http://kimundi.github.io/owning-ref-rs/owning_ref/index.html" -readme = "README.md" -keywords = ["reference", "sibling", "field", "owning"] -license = "MIT" -repository = "https://github.com/Kimundi/owning-ref-rs" -[dependencies.stable_deref_trait] -version = "1.0.0" diff --git a/third_party/rust/owning_ref/LICENSE b/third_party/rust/owning_ref/LICENSE deleted file mode 100644 index dff72d1e43..0000000000 --- a/third_party/rust/owning_ref/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Marvin Löbel - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/third_party/rust/owning_ref/README.md b/third_party/rust/owning_ref/README.md deleted file mode 100644 index ad32ac24fd..0000000000 --- a/third_party/rust/owning_ref/README.md +++ /dev/null @@ -1,64 +0,0 @@ -[![Build Status](https://travis-ci.org/Kimundi/owning-ref-rs.svg)](https://travis-ci.org/Kimundi/owning-ref-rs) -[![Crate](https://img.shields.io/crates/v/owning_ref.svg)](https://crates.io/crates/owning_ref) -[![Docs](https://docs.rs/owning_ref/badge.svg)](https://docs.rs/owning_ref) - -owning-ref-rs -============== - -A library for creating references that carry their owner with them. - -This can sometimes be useful because Rust borrowing rules normally prevent -moving a type that has been borrowed from. For example, this kind of code gets rejected: - -```rust -fn return_owned_and_referenced<'a>() -> (Vec, &'a [u8]) { - let v = vec![1, 2, 3, 4]; - let s = &v[1..3]; - (v, s) -} -``` - -This library enables this safe usage by keeping the owner and the reference -bundled together in a wrapper type that ensure that lifetime constraint: - -```rust -fn return_owned_and_referenced() -> OwningRef, [u8]> { - let v = vec![1, 2, 3, 4]; - let or = OwningRef::new(v); - let or = or.map(|v| &v[1..3]); - or -} -``` - -## Getting Started - -To get started, add the following to `Cargo.toml`. - -```toml -owning_ref = "0.4.1" -``` - -...and see the [docs](http://kimundi.github.io/owning-ref-rs/owning_ref/index.html) for how to use it. - - -## Example - -```rust -extern crate owning_ref; -use owning_ref::BoxRef; - -fn main() { - // Create an array owned by a Box. - let arr = Box::new([1, 2, 3, 4]) as Box<[i32]>; - - // Transfer into a BoxRef. - let arr: BoxRef<[i32]> = BoxRef::new(arr); - assert_eq!(&*arr, &[1, 2, 3, 4]); - - // We can slice the array without losing ownership or changing type. - let arr: BoxRef<[i32]> = arr.map(|arr| &arr[1..3]); - assert_eq!(&*arr, &[2, 3]); - - // Also works for Arc, Rc, String and Vec! -} -``` diff --git a/third_party/rust/owning_ref/src/lib.rs b/third_party/rust/owning_ref/src/lib.rs deleted file mode 100644 index fa2f15a220..0000000000 --- a/third_party/rust/owning_ref/src/lib.rs +++ /dev/null @@ -1,2016 +0,0 @@ -#![warn(missing_docs)] - -/*! -# An owning reference. - -This crate provides the _owning reference_ types `OwningRef` and `OwningRefMut` -that enables it to bundle a reference together with the owner of the data it points to. -This allows moving and dropping of a `OwningRef` without needing to recreate the reference. - -This can sometimes be useful because Rust borrowing rules normally prevent -moving a type that has been moved from. For example, this kind of code gets rejected: - -```rust,ignore -fn return_owned_and_referenced<'a>() -> (Vec, &'a [u8]) { - let v = vec![1, 2, 3, 4]; - let s = &v[1..3]; - (v, s) -} -``` - -Even though, from a memory-layout point of view, this can be entirely safe -if the new location of the vector still lives longer than the lifetime `'a` -of the reference because the backing allocation of the vector does not change. - -This library enables this safe usage by keeping the owner and the reference -bundled together in a wrapper type that ensure that lifetime constraint: - -```rust -# extern crate owning_ref; -# use owning_ref::OwningRef; -# fn main() { -fn return_owned_and_referenced() -> OwningRef, [u8]> { - let v = vec![1, 2, 3, 4]; - let or = OwningRef::new(v); - let or = or.map(|v| &v[1..3]); - or -} -# } -``` - -It works by requiring owner types to dereference to stable memory locations -and preventing mutable access to root containers, which in practice requires heap allocation -as provided by `Box`, `Rc`, etc. - -Also provided are typedefs for common owner type combinations, -which allow for less verbose type signatures. For example, `BoxRef` instead of `OwningRef, T>`. - -The crate also provides the more advanced `OwningHandle` type, -which allows more freedom in bundling a dependent handle object -along with the data it depends on, at the cost of some unsafe needed in the API. -See the documentation around `OwningHandle` for more details. - -# Examples - -## Basics - -``` -extern crate owning_ref; -use owning_ref::BoxRef; - -fn main() { - // Create an array owned by a Box. - let arr = Box::new([1, 2, 3, 4]) as Box<[i32]>; - - // Transfer into a BoxRef. - let arr: BoxRef<[i32]> = BoxRef::new(arr); - assert_eq!(&*arr, &[1, 2, 3, 4]); - - // We can slice the array without losing ownership or changing type. - let arr: BoxRef<[i32]> = arr.map(|arr| &arr[1..3]); - assert_eq!(&*arr, &[2, 3]); - - // Also works for Arc, Rc, String and Vec! -} -``` - -## Caching a reference to a struct field - -``` -extern crate owning_ref; -use owning_ref::BoxRef; - -fn main() { - struct Foo { - tag: u32, - x: u16, - y: u16, - z: u16, - } - let foo = Foo { tag: 1, x: 100, y: 200, z: 300 }; - - let or = BoxRef::new(Box::new(foo)).map(|foo| { - match foo.tag { - 0 => &foo.x, - 1 => &foo.y, - 2 => &foo.z, - _ => panic!(), - } - }); - - assert_eq!(*or, 200); -} -``` - -## Caching a reference to an entry in a vector - -``` -extern crate owning_ref; -use owning_ref::VecRef; - -fn main() { - let v = VecRef::new(vec![1, 2, 3, 4, 5]).map(|v| &v[3]); - assert_eq!(*v, 4); -} -``` - -## Caching a subslice of a String - -``` -extern crate owning_ref; -use owning_ref::StringRef; - -fn main() { - let s = StringRef::new("hello world".to_owned()) - .map(|s| s.split(' ').nth(1).unwrap()); - - assert_eq!(&*s, "world"); -} -``` - -## Reference counted slices that share ownership of the backing storage - -``` -extern crate owning_ref; -use owning_ref::RcRef; -use std::rc::Rc; - -fn main() { - let rc: RcRef<[i32]> = RcRef::new(Rc::new([1, 2, 3, 4]) as Rc<[i32]>); - assert_eq!(&*rc, &[1, 2, 3, 4]); - - let rc_a: RcRef<[i32]> = rc.clone().map(|s| &s[0..2]); - let rc_b = rc.clone().map(|s| &s[1..3]); - let rc_c = rc.clone().map(|s| &s[2..4]); - assert_eq!(&*rc_a, &[1, 2]); - assert_eq!(&*rc_b, &[2, 3]); - assert_eq!(&*rc_c, &[3, 4]); - - let rc_c_a = rc_c.clone().map(|s| &s[1]); - assert_eq!(&*rc_c_a, &4); -} -``` - -## Atomic reference counted slices that share ownership of the backing storage - -``` -extern crate owning_ref; -use owning_ref::ArcRef; -use std::sync::Arc; - -fn main() { - use std::thread; - - fn par_sum(rc: ArcRef<[i32]>) -> i32 { - if rc.len() == 0 { - return 0; - } else if rc.len() == 1 { - return rc[0]; - } - let mid = rc.len() / 2; - let left = rc.clone().map(|s| &s[..mid]); - let right = rc.map(|s| &s[mid..]); - - let left = thread::spawn(move || par_sum(left)); - let right = thread::spawn(move || par_sum(right)); - - left.join().unwrap() + right.join().unwrap() - } - - let rc: Arc<[i32]> = Arc::new([1, 2, 3, 4]); - let rc: ArcRef<[i32]> = rc.into(); - - assert_eq!(par_sum(rc), 10); -} -``` - -## References into RAII locks - -``` -extern crate owning_ref; -use owning_ref::RefRef; -use std::cell::{RefCell, Ref}; - -fn main() { - let refcell = RefCell::new((1, 2, 3, 4)); - // Also works with Mutex and RwLock - - let refref = { - let refref = RefRef::new(refcell.borrow()).map(|x| &x.3); - assert_eq!(*refref, 4); - - // We move the RAII lock and the reference to one of - // the subfields in the data it guards here: - refref - }; - - assert_eq!(*refref, 4); - - drop(refref); - - assert_eq!(*refcell.borrow(), (1, 2, 3, 4)); -} -``` - -## Mutable reference - -When the owned container implements `DerefMut`, it is also possible to make -a _mutable owning reference_. (E.g. with `Box`, `RefMut`, `MutexGuard`) - -``` -extern crate owning_ref; -use owning_ref::RefMutRefMut; -use std::cell::{RefCell, RefMut}; - -fn main() { - let refcell = RefCell::new((1, 2, 3, 4)); - - let mut refmut_refmut = { - let mut refmut_refmut = RefMutRefMut::new(refcell.borrow_mut()).map_mut(|x| &mut x.3); - assert_eq!(*refmut_refmut, 4); - *refmut_refmut *= 2; - - refmut_refmut - }; - - assert_eq!(*refmut_refmut, 8); - *refmut_refmut *= 2; - - drop(refmut_refmut); - - assert_eq!(*refcell.borrow(), (1, 2, 3, 16)); -} -``` -*/ - -extern crate stable_deref_trait; -pub use stable_deref_trait::{StableDeref as StableAddress, CloneStableDeref as CloneStableAddress}; - -/// An owning reference. -/// -/// This wraps an owner `O` and a reference `&T` pointing -/// at something reachable from `O::Target` while keeping -/// the ability to move `self` around. -/// -/// The owner is usually a pointer that points at some base type. -/// -/// For more details and examples, see the module and method docs. -pub struct OwningRef { - owner: O, - reference: *const T, -} - -/// An mutable owning reference. -/// -/// This wraps an owner `O` and a reference `&mut T` pointing -/// at something reachable from `O::Target` while keeping -/// the ability to move `self` around. -/// -/// The owner is usually a pointer that points at some base type. -/// -/// For more details and examples, see the module and method docs. -pub struct OwningRefMut { - owner: O, - reference: *mut T, -} - -/// Helper trait for an erased concrete type an owner dereferences to. -/// This is used in form of a trait object for keeping -/// something around to (virtually) call the destructor. -pub trait Erased {} -impl Erased for T {} - -/// Helper trait for erasing the concrete type of what an owner derferences to, -/// for example `Box -> Box`. This would be unneeded with -/// higher kinded types support in the language. -pub unsafe trait IntoErased<'a> { - /// Owner with the dereference type substituted to `Erased`. - type Erased; - /// Perform the type erasure. - fn into_erased(self) -> Self::Erased; -} - -///////////////////////////////////////////////////////////////////////////// -// OwningRef -///////////////////////////////////////////////////////////////////////////// - -impl OwningRef { - /// Creates a new owning reference from a owner - /// initialized to the direct dereference of it. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new(42)); - /// assert_eq!(*owning_ref, 42); - /// } - /// ``` - pub fn new(o: O) -> Self - where O: StableAddress, - O: Deref, - { - OwningRef { - reference: &*o, - owner: o, - } - } - - /// Like `new`, but doesn’t require `O` to implement the `StableAddress` trait. - /// Instead, the caller is responsible to make the same promises as implementing the trait. - /// - /// This is useful for cases where coherence rules prevents implementing the trait - /// without adding a dependency to this crate in a third-party library. - pub unsafe fn new_assert_stable_address(o: O) -> Self - where O: Deref, - { - OwningRef { - reference: &*o, - owner: o, - } - } - - /// Converts `self` into a new owning reference that points at something reachable - /// from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); - /// - /// // create a owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref.map(|array| &array[2]); - /// assert_eq!(*owning_ref, 3); - /// } - /// ``` - pub fn map(self, f: F) -> OwningRef - where O: StableAddress, - F: FnOnce(&T) -> &U - { - OwningRef { - reference: f(&self), - owner: self.owner, - } - } - - /// Converts `self` into a new owning reference that points at something reachable - /// from the previous one or from the owner itself. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U` or from the owner `O`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); - /// let owning_ref = owning_ref.map(|array| &array[2]); - /// assert_eq!(*owning_ref, 3); - /// - /// // create a owning reference that points at the - /// // second element of the array from the owning ref that was pointing to the third - /// let owning_ref = owning_ref.map_with_owner(|array, _prev| &array[1]); - /// assert_eq!(*owning_ref, 2); - /// } - /// ``` - pub fn map_with_owner(self, f: F) -> OwningRef - where O: StableAddress, - F: for<'a> FnOnce(&'a O, &'a T) -> &'a U - { - OwningRef { - reference: f(&self.owner, &self), - owner: self.owner, - } - } - - /// Tries to convert `self` into a new owning reference that points - /// at something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); - /// - /// // create a owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref.try_map(|array| { - /// if array[2] == 3 { Ok(&array[2]) } else { Err(()) } - /// }); - /// assert_eq!(*owning_ref.unwrap(), 3); - /// } - /// ``` - pub fn try_map(self, f: F) -> Result, E> - where O: StableAddress, - F: FnOnce(&T) -> Result<&U, E> - { - Ok(OwningRef { - reference: f(&self)?, - owner: self.owner, - }) - } - - /// Tries to convert `self` into a new owning reference that points - /// at something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); - /// let owning_ref = owning_ref.map(|array| &array[2]); - /// - /// // create a owning reference that points at the - /// // second element of the array from the owning ref that was pointing to the third - /// let owning_ref = owning_ref.try_map_with_owner(|array, _prev| { - /// if array[1] == 2 { Ok(&array[1]) } else { Err(()) } - /// }); - /// assert_eq!(*owning_ref.unwrap(), 2); - /// } - /// ``` - pub fn try_map_with_owner(self, f: F) -> Result, E> - where O: StableAddress, - F: for<'a> FnOnce(&'a O, &'a T) -> Result<&'a U, E> - { - Ok(OwningRef { - reference: f(&self.owner, &self)?, - owner: self.owner, - }) - } - - /// Converts `self` into a new owning reference with a different owner type. - /// - /// The new owner type needs to still contain the original owner in some way - /// so that the reference into it remains valid. This function is marked unsafe - /// because the user needs to manually uphold this guarantee. - pub unsafe fn map_owner(self, f: F) -> OwningRef - where O: StableAddress, - P: StableAddress, - F: FnOnce(O) -> P - { - OwningRef { - reference: self.reference, - owner: f(self.owner), - } - } - - /// Converts `self` into a new owning reference where the owner is wrapped - /// in an additional `Box`. - /// - /// This can be used to safely erase the owner of any `OwningRef` - /// to a `OwningRef, T>`. - pub fn map_owner_box(self) -> OwningRef, T> { - OwningRef { - reference: self.reference, - owner: Box::new(self.owner), - } - } - - /// Erases the concrete base type of the owner with a trait object. - /// - /// This allows mixing of owned references with different owner base types. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::{OwningRef, Erased}; - /// - /// fn main() { - /// // NB: Using the concrete types here for explicitnes. - /// // For less verbose code type aliases like `BoxRef` are provided. - /// - /// let owning_ref_a: OwningRef, [i32; 4]> - /// = OwningRef::new(Box::new([1, 2, 3, 4])); - /// - /// let owning_ref_b: OwningRef>, Vec<(i32, bool)>> - /// = OwningRef::new(Box::new(vec![(0, false), (1, true)])); - /// - /// let owning_ref_a: OwningRef, i32> - /// = owning_ref_a.map(|a| &a[0]); - /// - /// let owning_ref_b: OwningRef>, i32> - /// = owning_ref_b.map(|a| &a[1].0); - /// - /// let owning_refs: [OwningRef, i32>; 2] - /// = [owning_ref_a.erase_owner(), owning_ref_b.erase_owner()]; - /// - /// assert_eq!(*owning_refs[0], 1); - /// assert_eq!(*owning_refs[1], 1); - /// } - /// ``` - pub fn erase_owner<'a>(self) -> OwningRef - where O: IntoErased<'a>, - { - OwningRef { - reference: self.reference, - owner: self.owner.into_erased(), - } - } - - // TODO: wrap_owner - - /// A reference to the underlying owner. - pub fn as_owner(&self) -> &O { - &self.owner - } - - /// Discards the reference and retrieves the owner. - pub fn into_owner(self) -> O { - self.owner - } -} - -impl OwningRefMut { - /// Creates a new owning reference from a owner - /// initialized to the direct dereference of it. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new(42)); - /// assert_eq!(*owning_ref_mut, 42); - /// } - /// ``` - pub fn new(mut o: O) -> Self - where O: StableAddress, - O: DerefMut, - { - OwningRefMut { - reference: &mut *o, - owner: o, - } - } - - /// Like `new`, but doesn’t require `O` to implement the `StableAddress` trait. - /// Instead, the caller is responsible to make the same promises as implementing the trait. - /// - /// This is useful for cases where coherence rules prevents implementing the trait - /// without adding a dependency to this crate in a third-party library. - pub unsafe fn new_assert_stable_address(mut o: O) -> Self - where O: DerefMut, - { - OwningRefMut { - reference: &mut *o, - owner: o, - } - } - - /// Converts `self` into a new _shared_ owning reference that points at - /// something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create a owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref_mut.map(|array| &array[2]); - /// assert_eq!(*owning_ref, 3); - /// } - /// ``` - pub fn map(mut self, f: F) -> OwningRef - where O: StableAddress, - F: FnOnce(&mut T) -> &U - { - OwningRef { - reference: f(&mut self), - owner: self.owner, - } - } - - /// Converts `self` into a new _mutable_ owning reference that points at - /// something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create a owning reference that points at the - /// // third element of the array. - /// let owning_ref_mut = owning_ref_mut.map_mut(|array| &mut array[2]); - /// assert_eq!(*owning_ref_mut, 3); - /// } - /// ``` - pub fn map_mut(mut self, f: F) -> OwningRefMut - where O: StableAddress, - F: FnOnce(&mut T) -> &mut U - { - OwningRefMut { - reference: f(&mut self), - owner: self.owner, - } - } - - /// Tries to convert `self` into a new _shared_ owning reference that points - /// at something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create a owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref_mut.try_map(|array| { - /// if array[2] == 3 { Ok(&array[2]) } else { Err(()) } - /// }); - /// assert_eq!(*owning_ref.unwrap(), 3); - /// } - /// ``` - pub fn try_map(mut self, f: F) -> Result, E> - where O: StableAddress, - F: FnOnce(&mut T) -> Result<&U, E> - { - Ok(OwningRef { - reference: f(&mut self)?, - owner: self.owner, - }) - } - - /// Tries to convert `self` into a new _mutable_ owning reference that points - /// at something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create a owning reference that points at the - /// // third element of the array. - /// let owning_ref_mut = owning_ref_mut.try_map_mut(|array| { - /// if array[2] == 3 { Ok(&mut array[2]) } else { Err(()) } - /// }); - /// assert_eq!(*owning_ref_mut.unwrap(), 3); - /// } - /// ``` - pub fn try_map_mut(mut self, f: F) -> Result, E> - where O: StableAddress, - F: FnOnce(&mut T) -> Result<&mut U, E> - { - Ok(OwningRefMut { - reference: f(&mut self)?, - owner: self.owner, - }) - } - - /// Converts `self` into a new owning reference with a different owner type. - /// - /// The new owner type needs to still contain the original owner in some way - /// so that the reference into it remains valid. This function is marked unsafe - /// because the user needs to manually uphold this guarantee. - pub unsafe fn map_owner(self, f: F) -> OwningRefMut - where O: StableAddress, - P: StableAddress, - F: FnOnce(O) -> P - { - OwningRefMut { - reference: self.reference, - owner: f(self.owner), - } - } - - /// Converts `self` into a new owning reference where the owner is wrapped - /// in an additional `Box`. - /// - /// This can be used to safely erase the owner of any `OwningRefMut` - /// to a `OwningRefMut, T>`. - pub fn map_owner_box(self) -> OwningRefMut, T> { - OwningRefMut { - reference: self.reference, - owner: Box::new(self.owner), - } - } - - /// Erases the concrete base type of the owner with a trait object. - /// - /// This allows mixing of owned references with different owner base types. - /// - /// # Example - /// ``` - /// extern crate owning_ref; - /// use owning_ref::{OwningRefMut, Erased}; - /// - /// fn main() { - /// // NB: Using the concrete types here for explicitnes. - /// // For less verbose code type aliases like `BoxRef` are provided. - /// - /// let owning_ref_mut_a: OwningRefMut, [i32; 4]> - /// = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// let owning_ref_mut_b: OwningRefMut>, Vec<(i32, bool)>> - /// = OwningRefMut::new(Box::new(vec![(0, false), (1, true)])); - /// - /// let owning_ref_mut_a: OwningRefMut, i32> - /// = owning_ref_mut_a.map_mut(|a| &mut a[0]); - /// - /// let owning_ref_mut_b: OwningRefMut>, i32> - /// = owning_ref_mut_b.map_mut(|a| &mut a[1].0); - /// - /// let owning_refs_mut: [OwningRefMut, i32>; 2] - /// = [owning_ref_mut_a.erase_owner(), owning_ref_mut_b.erase_owner()]; - /// - /// assert_eq!(*owning_refs_mut[0], 1); - /// assert_eq!(*owning_refs_mut[1], 1); - /// } - /// ``` - pub fn erase_owner<'a>(self) -> OwningRefMut - where O: IntoErased<'a>, - { - OwningRefMut { - reference: self.reference, - owner: self.owner.into_erased(), - } - } - - // TODO: wrap_owner - - /// A reference to the underlying owner. - pub fn as_owner(&self) -> &O { - &self.owner - } - - /// A mutable reference to the underlying owner. - pub fn as_owner_mut(&mut self) -> &mut O { - &mut self.owner - } - - /// Discards the reference and retrieves the owner. - pub fn into_owner(self) -> O { - self.owner - } -} - -///////////////////////////////////////////////////////////////////////////// -// OwningHandle -///////////////////////////////////////////////////////////////////////////// - -use std::ops::{Deref, DerefMut}; - -/// `OwningHandle` is a complement to `OwningRef`. Where `OwningRef` allows -/// consumers to pass around an owned object and a dependent reference, -/// `OwningHandle` contains an owned object and a dependent _object_. -/// -/// `OwningHandle` can encapsulate a `RefMut` along with its associated -/// `RefCell`, or an `RwLockReadGuard` along with its associated `RwLock`. -/// However, the API is completely generic and there are no restrictions on -/// what types of owning and dependent objects may be used. -/// -/// `OwningHandle` is created by passing an owner object (which dereferences -/// to a stable address) along with a callback which receives a pointer to -/// that stable location. The callback may then dereference the pointer and -/// mint a dependent object, with the guarantee that the returned object will -/// not outlive the referent of the pointer. -/// -/// Since the callback needs to dereference a raw pointer, it requires `unsafe` -/// code. To avoid forcing this unsafety on most callers, the `ToHandle` trait is -/// implemented for common data structures. Types that implement `ToHandle` can -/// be wrapped into an `OwningHandle` without passing a callback. -pub struct OwningHandle - where O: StableAddress, H: Deref, -{ - handle: H, - _owner: O, -} - -impl Deref for OwningHandle - where O: StableAddress, H: Deref, -{ - type Target = H::Target; - fn deref(&self) -> &H::Target { - self.handle.deref() - } -} - -unsafe impl StableAddress for OwningHandle - where O: StableAddress, H: StableAddress, -{} - -impl DerefMut for OwningHandle - where O: StableAddress, H: DerefMut, -{ - fn deref_mut(&mut self) -> &mut H::Target { - self.handle.deref_mut() - } -} - -/// Trait to implement the conversion of owner to handle for common types. -pub trait ToHandle { - /// The type of handle to be encapsulated by the OwningHandle. - type Handle: Deref; - - /// Given an appropriately-long-lived pointer to ourselves, create a - /// handle to be encapsulated by the `OwningHandle`. - unsafe fn to_handle(x: *const Self) -> Self::Handle; -} - -/// Trait to implement the conversion of owner to mutable handle for common types. -pub trait ToHandleMut { - /// The type of handle to be encapsulated by the OwningHandle. - type HandleMut: DerefMut; - - /// Given an appropriately-long-lived pointer to ourselves, create a - /// mutable handle to be encapsulated by the `OwningHandle`. - unsafe fn to_handle_mut(x: *const Self) -> Self::HandleMut; -} - -impl OwningHandle - where O: StableAddress, O::Target: ToHandle, H: Deref, -{ - /// Create a new `OwningHandle` for a type that implements `ToHandle`. For types - /// that don't implement `ToHandle`, callers may invoke `new_with_fn`, which accepts - /// a callback to perform the conversion. - pub fn new(o: O) -> Self { - OwningHandle::new_with_fn(o, |x| unsafe { O::Target::to_handle(x) }) - } -} - -impl OwningHandle - where O: StableAddress, O::Target: ToHandleMut, H: DerefMut, -{ - /// Create a new mutable `OwningHandle` for a type that implements `ToHandleMut`. - pub fn new_mut(o: O) -> Self { - OwningHandle::new_with_fn(o, |x| unsafe { O::Target::to_handle_mut(x) }) - } -} - -impl OwningHandle - where O: StableAddress, H: Deref, -{ - /// Create a new OwningHandle. The provided callback will be invoked with - /// a pointer to the object owned by `o`, and the returned value is stored - /// as the object to which this `OwningHandle` will forward `Deref` and - /// `DerefMut`. - pub fn new_with_fn(o: O, f: F) -> Self - where F: FnOnce(*const O::Target) -> H - { - let h: H; - { - h = f(o.deref() as *const O::Target); - } - - OwningHandle { - handle: h, - _owner: o, - } - } - - /// Create a new OwningHandle. The provided callback will be invoked with - /// a pointer to the object owned by `o`, and the returned value is stored - /// as the object to which this `OwningHandle` will forward `Deref` and - /// `DerefMut`. - pub fn try_new(o: O, f: F) -> Result - where F: FnOnce(*const O::Target) -> Result - { - let h: H; - { - h = f(o.deref() as *const O::Target)?; - } - - Ok(OwningHandle { - handle: h, - _owner: o, - }) - } - - /// A getter for the underlying owner. - pub fn as_owner(&self) -> &O { - &self._owner - } - - /// Discards the dependent object and returns the owner. - pub fn into_owner(self) -> O { - self._owner - } -} - -///////////////////////////////////////////////////////////////////////////// -// std traits -///////////////////////////////////////////////////////////////////////////// - -use std::convert::From; -use std::fmt::{self, Debug}; -use std::marker::{Send, Sync}; -use std::cmp::{Eq, PartialEq, Ord, PartialOrd, Ordering}; -use std::hash::{Hash, Hasher}; -use std::borrow::Borrow; - -impl Deref for OwningRef { - type Target = T; - - fn deref(&self) -> &T { - unsafe { - &*self.reference - } - } -} - -impl Deref for OwningRefMut { - type Target = T; - - fn deref(&self) -> &T { - unsafe { - &*self.reference - } - } -} - -impl DerefMut for OwningRefMut { - fn deref_mut(&mut self) -> &mut T { - unsafe { - &mut *self.reference - } - } -} - -unsafe impl StableAddress for OwningRef {} - -unsafe impl StableAddress for OwningRefMut {} - -impl AsRef for OwningRef { - fn as_ref(&self) -> &T { - &*self - } -} - -impl AsRef for OwningRefMut { - fn as_ref(&self) -> &T { - &*self - } -} - -impl AsMut for OwningRefMut { - fn as_mut(&mut self) -> &mut T { - &mut *self - } -} - -impl Borrow for OwningRef { - fn borrow(&self) -> &T { - &*self - } -} - -impl From for OwningRef - where O: StableAddress, - O: Deref, -{ - fn from(owner: O) -> Self { - OwningRef::new(owner) - } -} - -impl From for OwningRefMut - where O: StableAddress, - O: DerefMut -{ - fn from(owner: O) -> Self { - OwningRefMut::new(owner) - } -} - -impl From> for OwningRef - where O: StableAddress, - O: DerefMut -{ - fn from(other: OwningRefMut) -> Self { - OwningRef { - owner: other.owner, - reference: other.reference, - } - } -} - -// ^ FIXME: Is a Into impl for calling into_owner() possible as well? - -impl Debug for OwningRef - where O: Debug, - T: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, - "OwningRef {{ owner: {:?}, reference: {:?} }}", - self.as_owner(), - &**self) - } -} - -impl Debug for OwningRefMut - where O: Debug, - T: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, - "OwningRefMut {{ owner: {:?}, reference: {:?} }}", - self.as_owner(), - &**self) - } -} - -impl Clone for OwningRef - where O: CloneStableAddress, -{ - fn clone(&self) -> Self { - OwningRef { - owner: self.owner.clone(), - reference: self.reference, - } - } -} - -unsafe impl CloneStableAddress for OwningRef - where O: CloneStableAddress {} - -unsafe impl Send for OwningRef - where O: Send, for<'a> (&'a T): Send {} -unsafe impl Sync for OwningRef - where O: Sync, for<'a> (&'a T): Sync {} - -unsafe impl Send for OwningRefMut - where O: Send, for<'a> (&'a mut T): Send {} -unsafe impl Sync for OwningRefMut - where O: Sync, for<'a> (&'a mut T): Sync {} - -impl Debug for dyn Erased { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "",) - } -} - -impl PartialEq for OwningRef where T: PartialEq { - fn eq(&self, other: &Self) -> bool { - (&*self as &T).eq(&*other as &T) - } -} - -impl Eq for OwningRef where T: Eq {} - -impl PartialOrd for OwningRef where T: PartialOrd { - fn partial_cmp(&self, other: &Self) -> Option { - (&*self as &T).partial_cmp(&*other as &T) - } -} - -impl Ord for OwningRef where T: Ord { - fn cmp(&self, other: &Self) -> Ordering { - (&*self as &T).cmp(&*other as &T) - } -} - -impl Hash for OwningRef where T: Hash { - fn hash(&self, state: &mut H) { - (&*self as &T).hash(state); - } -} - -impl PartialEq for OwningRefMut where T: PartialEq { - fn eq(&self, other: &Self) -> bool { - (&*self as &T).eq(&*other as &T) - } -} - -impl Eq for OwningRefMut where T: Eq {} - -impl PartialOrd for OwningRefMut where T: PartialOrd { - fn partial_cmp(&self, other: &Self) -> Option { - (&*self as &T).partial_cmp(&*other as &T) - } -} - -impl Ord for OwningRefMut where T: Ord { - fn cmp(&self, other: &Self) -> Ordering { - (&*self as &T).cmp(&*other as &T) - } -} - -impl Hash for OwningRefMut where T: Hash { - fn hash(&self, state: &mut H) { - (&*self as &T).hash(state); - } -} - -///////////////////////////////////////////////////////////////////////////// -// std types integration and convenience type defs -///////////////////////////////////////////////////////////////////////////// - -use std::boxed::Box; -use std::rc::Rc; -use std::sync::Arc; -use std::sync::{MutexGuard, RwLockReadGuard, RwLockWriteGuard}; -use std::cell::{Ref, RefCell, RefMut}; - -impl ToHandle for RefCell { - type Handle = Ref<'static, T>; - unsafe fn to_handle(x: *const Self) -> Self::Handle { (*x).borrow() } -} - -impl ToHandleMut for RefCell { - type HandleMut = RefMut<'static, T>; - unsafe fn to_handle_mut(x: *const Self) -> Self::HandleMut { (*x).borrow_mut() } -} - -// NB: Implementing ToHandle{,Mut} for Mutex and RwLock requires a decision -// about which handle creation to use (i.e. read() vs try_read()) as well as -// what to do with error results. - -/// Typedef of a owning reference that uses a `Box` as the owner. -pub type BoxRef = OwningRef, U>; -/// Typedef of a owning reference that uses a `Vec` as the owner. -pub type VecRef = OwningRef, U>; -/// Typedef of a owning reference that uses a `String` as the owner. -pub type StringRef = OwningRef; - -/// Typedef of a owning reference that uses a `Rc` as the owner. -pub type RcRef = OwningRef, U>; -/// Typedef of a owning reference that uses a `Arc` as the owner. -pub type ArcRef = OwningRef, U>; - -/// Typedef of a owning reference that uses a `Ref` as the owner. -pub type RefRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of a owning reference that uses a `RefMut` as the owner. -pub type RefMutRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of a owning reference that uses a `MutexGuard` as the owner. -pub type MutexGuardRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of a owning reference that uses a `RwLockReadGuard` as the owner. -pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of a owning reference that uses a `RwLockWriteGuard` as the owner. -pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef, U>; - -/// Typedef of a mutable owning reference that uses a `Box` as the owner. -pub type BoxRefMut = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `Vec` as the owner. -pub type VecRefMut = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `String` as the owner. -pub type StringRefMut = OwningRefMut; - -/// Typedef of a mutable owning reference that uses a `RefMut` as the owner. -pub type RefMutRefMut<'a, T, U = T> = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `MutexGuard` as the owner. -pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `RwLockWriteGuard` as the owner. -pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRefMut, U>; - -unsafe impl<'a, T: 'a> IntoErased<'a> for Box { - type Erased = Box; - fn into_erased(self) -> Self::Erased { - self - } -} -unsafe impl<'a, T: 'a> IntoErased<'a> for Rc { - type Erased = Rc; - fn into_erased(self) -> Self::Erased { - self - } -} -unsafe impl<'a, T: 'a> IntoErased<'a> for Arc { - type Erased = Arc; - fn into_erased(self) -> Self::Erased { - self - } -} - -/// Typedef of a owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRef = OwningRef, U>; -/// Typedef of a owning reference that uses an erased `Rc` as the owner. -pub type ErasedRcRef = OwningRef, U>; -/// Typedef of a owning reference that uses an erased `Arc` as the owner. -pub type ErasedArcRef = OwningRef, U>; - -/// Typedef of a mutable owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRefMut = OwningRefMut, U>; - -#[cfg(test)] -mod tests { - mod owning_ref { - use super::super::OwningRef; - use super::super::{RcRef, BoxRef, Erased, ErasedBoxRef}; - use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; - use std::hash::{Hash, Hasher}; - use std::collections::hash_map::DefaultHasher; - use std::collections::HashMap; - use std::rc::Rc; - - #[derive(Debug, PartialEq)] - struct Example(u32, String, [u8; 3]); - fn example() -> Example { - Example(42, "hello world".to_string(), [1, 2, 3]) - } - - #[test] - fn new_deref() { - let or: OwningRef, ()> = OwningRef::new(Box::new(())); - assert_eq!(&*or, &()); - } - - #[test] - fn into() { - let or: OwningRef, ()> = Box::new(()).into(); - assert_eq!(&*or, &()); - } - - #[test] - fn map_offset_ref() { - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, u32> = or.map(|x| &x.0); - assert_eq!(&*or, &42); - - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, u8> = or.map(|x| &x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_heap_ref() { - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, str> = or.map(|x| &x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_static_ref() { - let or: BoxRef<()> = Box::new(()).into(); - let or: BoxRef<_, str> = or.map(|_| "hello"); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_chained() { - let or: BoxRef = Box::new(example().1).into(); - let or: BoxRef<_, str> = or.map(|x| &x[1..5]); - let or: BoxRef<_, str> = or.map(|x| &x[..2]); - assert_eq!(&*or, "el"); - } - - #[test] - fn map_chained_inference() { - let or = BoxRef::new(Box::new(example().1)) - .map(|x| &x[..5]) - .map(|x| &x[1..3]); - assert_eq!(&*or, "el"); - } - - #[test] - fn as_owner() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - assert_eq!(&*or, "hello"); - assert_eq!(&**or.as_owner(), "hello world"); - } - - #[test] - fn into_owner() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - assert_eq!(&*or, "hello"); - let s = *or.into_owner(); - assert_eq!(&s, "hello world"); - } - - #[test] - fn fmt_debug() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - let s = format!("{:?}", or); - assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }"); - } - - #[test] - fn erased_owner() { - let o1: BoxRef = BoxRef::new(Box::new(example())) - .map(|x| &x.1[..]); - - let o2: BoxRef = BoxRef::new(Box::new(example().1)) - .map(|x| &x[..]); - - let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; - assert!(os.iter().all(|e| &e[..] == "hello world")); - } - - #[test] - fn non_static_erased_owner() { - let foo = [413, 612]; - let bar = &foo; - - // FIXME: lifetime inference fails us, and we can't easily define a lifetime for a closure - // (see https://github.com/rust-lang/rust/issues/22340) - // So we use a function to identify the lifetimes instead. - fn borrow<'a>(a: &'a &[i32; 2]) -> &'a i32 { - &a[0] - } - - let o: BoxRef<&[i32; 2]> = Box::new(bar).into(); - let o: BoxRef<&[i32; 2], i32> = o.map(borrow); - let o: BoxRef = o.erase_owner(); - - assert_eq!(*o, 413); - } - - #[test] - fn raii_locks() { - use super::super::{RefRef, RefMutRef}; - use std::cell::RefCell; - use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef}; - use std::sync::{Mutex, RwLock}; - - { - let a = RefCell::new(1); - let a = { - let a = RefRef::new(a.borrow()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RefCell::new(1); - let a = { - let a = RefMutRef::new(a.borrow_mut()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = Mutex::new(1); - let a = { - let a = MutexGuardRef::new(a.lock().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockReadGuardRef::new(a.read().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockWriteGuardRef::new(a.write().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - } - - #[test] - fn eq() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.eq(&or2), true); - } - - #[test] - fn cmp() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); - assert_eq!(or1.cmp(&or2), Ordering::Less); - } - - #[test] - fn partial_cmp() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); - } - - #[test] - fn hash() { - let mut h1 = DefaultHasher::new(); - let mut h2 = DefaultHasher::new(); - - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - - or1.hash(&mut h1); - or2.hash(&mut h2); - - assert_eq!(h1.finish(), h2.finish()); - } - - #[test] - fn borrow() { - let mut hash = HashMap::new(); - let key = RcRef::::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]); - - hash.insert(key.clone().map(|s| &s[..3]), 42); - hash.insert(key.clone().map(|s| &s[4..]), 23); - - assert_eq!(hash.get("foo"), Some(&42)); - assert_eq!(hash.get("bar"), Some(&23)); - } - - #[test] - fn total_erase() { - let a: OwningRef, [u8]> - = OwningRef::new(vec![]).map(|x| &x[..]); - let b: OwningRef, [u8]> - = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); - - let c: OwningRef>, [u8]> = unsafe {a.map_owner(Rc::new)}; - let d: OwningRef>, [u8]> = unsafe {b.map_owner(Rc::new)}; - - let e: OwningRef, [u8]> = c.erase_owner(); - let f: OwningRef, [u8]> = d.erase_owner(); - - let _g = e.clone(); - let _h = f.clone(); - } - - #[test] - fn total_erase_box() { - let a: OwningRef, [u8]> - = OwningRef::new(vec![]).map(|x| &x[..]); - let b: OwningRef, [u8]> - = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); - - let c: OwningRef>, [u8]> = a.map_owner_box(); - let d: OwningRef>, [u8]> = b.map_owner_box(); - - let _e: OwningRef, [u8]> = c.erase_owner(); - let _f: OwningRef, [u8]> = d.erase_owner(); - } - - #[test] - fn try_map1() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).unwrap(); - } - - #[test] - fn try_map2() { - use std::any::Any; - - let x = Box::new(123_u32); - let y: Box = x; - - OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).unwrap_err(); - } - - #[test] - fn map_with_owner() { - let owning_ref: BoxRef = Box::new(example()).into(); - let owning_ref = owning_ref.map(|owner| &owner.1); - - owning_ref.map_with_owner(|owner, ref_field| { - assert_eq!(owner.1, *ref_field); - ref_field - }); - } - - #[test] - fn try_map_with_owner_ok() { - let owning_ref: BoxRef = Box::new(example()).into(); - let owning_ref = owning_ref.map(|owner| &owner.1); - - owning_ref.try_map_with_owner(|owner, ref_field| { - assert_eq!(owner.1, *ref_field); - Ok(ref_field) as Result<_, ()> - }).unwrap(); - } - - #[test] - fn try_map_with_owner_err() { - let owning_ref: BoxRef = Box::new(example()).into(); - let owning_ref = owning_ref.map(|owner| &owner.1); - - owning_ref.try_map_with_owner(|owner, ref_field| { - assert_eq!(owner.1, *ref_field); - Err(()) as Result<&(), _> - }).unwrap_err(); - } - } - - mod owning_handle { - use super::super::OwningHandle; - use super::super::RcRef; - use std::rc::Rc; - use std::cell::RefCell; - use std::sync::Arc; - use std::sync::RwLock; - - #[test] - fn owning_handle() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn try_owning_handle_ok() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { - Ok(unsafe { - x.as_ref() - }.unwrap().borrow_mut()) - }).unwrap(); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn try_owning_handle_err() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { - if false { - return Ok(unsafe { - x.as_ref() - }.unwrap().borrow_mut()) - } - Err(()) - }); - assert!(handle.is_err()); - } - - #[test] - fn nested() { - use std::cell::RefCell; - use std::sync::{Arc, RwLock}; - - let result = { - let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); - let curr = RcRef::new(complex); - let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); - assert_eq!(*curr, "someString"); - *curr = "someOtherString"; - curr - }; - assert_eq!(*result, "someOtherString"); - } - - #[test] - fn owning_handle_safe() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let handle = OwningHandle::new(cell_ref); - assert_eq!(*handle, 2); - } - - #[test] - fn owning_handle_mut_safe() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::new_mut(cell_ref); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn owning_handle_safe_2() { - let result = { - let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); - let curr = RcRef::new(complex); - let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); - assert_eq!(*curr, "someString"); - *curr = "someOtherString"; - curr - }; - assert_eq!(*result, "someOtherString"); - } - } - - mod owning_ref_mut { - use super::super::{OwningRefMut, BoxRefMut, Erased, ErasedBoxRefMut}; - use super::super::BoxRef; - use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; - use std::hash::{Hash, Hasher}; - use std::collections::hash_map::DefaultHasher; - use std::collections::HashMap; - - #[derive(Debug, PartialEq)] - struct Example(u32, String, [u8; 3]); - fn example() -> Example { - Example(42, "hello world".to_string(), [1, 2, 3]) - } - - #[test] - fn new_deref() { - let or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); - assert_eq!(&*or, &()); - } - - #[test] - fn new_deref_mut() { - let mut or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); - assert_eq!(&mut *or, &mut ()); - } - - #[test] - fn mutate() { - let mut or: OwningRefMut, usize> = OwningRefMut::new(Box::new(0)); - assert_eq!(&*or, &0); - *or = 1; - assert_eq!(&*or, &1); - } - - #[test] - fn into() { - let or: OwningRefMut, ()> = Box::new(()).into(); - assert_eq!(&*or, &()); - } - - #[test] - fn map_offset_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, u32> = or.map(|x| &mut x.0); - assert_eq!(&*or, &42); - - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_heap_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_static_ref() { - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRef<_, str> = or.map(|_| "hello"); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_mut_offset_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0); - assert_eq!(&*or, &42); - - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_mut_heap_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_mut_static_ref() { - static mut MUT_S: [u8; 5] = *b"hello"; - - let mut_s: &'static mut [u8] = unsafe { &mut MUT_S }; - - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s); - assert_eq!(&*or, b"hello"); - } - - #[test] - fn map_mut_chained() { - let or: BoxRefMut = Box::new(example().1).into(); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]); - assert_eq!(&*or, "el"); - } - - #[test] - fn map_chained_inference() { - let or = BoxRefMut::new(Box::new(example().1)) - .map_mut(|x| &mut x[..5]) - .map_mut(|x| &mut x[1..3]); - assert_eq!(&*or, "el"); - } - - #[test] - fn try_map_mut() { - let or: BoxRefMut = Box::new(example().1).into(); - let or: Result, ()> = or.try_map_mut(|x| Ok(&mut x[1..5])); - assert_eq!(&*or.unwrap(), "ello"); - - let or: BoxRefMut = Box::new(example().1).into(); - let or: Result, ()> = or.try_map_mut(|_| Err(())); - assert!(or.is_err()); - } - - #[test] - fn as_owner() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - assert_eq!(&*or, "hello"); - assert_eq!(&**or.as_owner(), "hello world"); - } - - #[test] - fn into_owner() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - assert_eq!(&*or, "hello"); - let s = *or.into_owner(); - assert_eq!(&s, "hello world"); - } - - #[test] - fn fmt_debug() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - let s = format!("{:?}", or); - assert_eq!(&s, - "OwningRefMut { owner: \"hello world\", reference: \"hello\" }"); - } - - #[test] - fn erased_owner() { - let o1: BoxRefMut = BoxRefMut::new(Box::new(example())) - .map_mut(|x| &mut x.1[..]); - - let o2: BoxRefMut = BoxRefMut::new(Box::new(example().1)) - .map_mut(|x| &mut x[..]); - - let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; - assert!(os.iter().all(|e| &e[..] == "hello world")); - } - - #[test] - fn non_static_erased_owner() { - let mut foo = [413, 612]; - let bar = &mut foo; - - // FIXME: lifetime inference fails us, and we can't easily define a lifetime for a closure - // (see https://github.com/rust-lang/rust/issues/22340) - // So we use a function to identify the lifetimes instead. - fn borrow<'a>(a: &'a mut &mut [i32; 2]) -> &'a mut i32 { - &mut a[0] - } - - let o: BoxRefMut<&mut [i32; 2]> = Box::new(bar).into(); - let o: BoxRefMut<&mut [i32; 2], i32> = o.map_mut(borrow); - let o: BoxRefMut = o.erase_owner(); - - assert_eq!(*o, 413); - } - - #[test] - fn raii_locks() { - use super::super::RefMutRefMut; - use std::cell::RefCell; - use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut}; - use std::sync::{Mutex, RwLock}; - - { - let a = RefCell::new(1); - let a = { - let a = RefMutRefMut::new(a.borrow_mut()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = Mutex::new(1); - let a = { - let a = MutexGuardRefMut::new(a.lock().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockWriteGuardRefMut::new(a.write().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - } - - #[test] - fn eq() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.eq(&or2), true); - } - - #[test] - fn cmp() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); - assert_eq!(or1.cmp(&or2), Ordering::Less); - } - - #[test] - fn partial_cmp() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); - } - - #[test] - fn hash() { - let mut h1 = DefaultHasher::new(); - let mut h2 = DefaultHasher::new(); - - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - - or1.hash(&mut h1); - or2.hash(&mut h2); - - assert_eq!(h1.finish(), h2.finish()); - } - - #[test] - fn borrow() { - let mut hash = HashMap::new(); - let key1 = BoxRefMut::::new(Box::new("foo".to_string())).map(|s| &s[..]); - let key2 = BoxRefMut::::new(Box::new("bar".to_string())).map(|s| &s[..]); - - hash.insert(key1, 42); - hash.insert(key2, 23); - - assert_eq!(hash.get("foo"), Some(&42)); - assert_eq!(hash.get("bar"), Some(&23)); - } - - #[test] - fn total_erase() { - let a: OwningRefMut, [u8]> - = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); - let b: OwningRefMut, [u8]> - = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); - - let c: OwningRefMut>, [u8]> = unsafe {a.map_owner(Box::new)}; - let d: OwningRefMut>, [u8]> = unsafe {b.map_owner(Box::new)}; - - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); - } - - #[test] - fn total_erase_box() { - let a: OwningRefMut, [u8]> - = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); - let b: OwningRefMut, [u8]> - = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); - - let c: OwningRefMut>, [u8]> = a.map_owner_box(); - let d: OwningRefMut>, [u8]> = b.map_owner_box(); - - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); - } - - #[test] - fn try_map1() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).unwrap(); - } - - #[test] - fn try_map2() { - use std::any::Any; - - let x = Box::new(123_u32); - let y: Box = x; - - OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).unwrap_err(); - } - - #[test] - fn try_map3() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).unwrap(); - } - - #[test] - fn try_map4() { - use std::any::Any; - - let x = Box::new(123_u32); - let y: Box = x; - - OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).unwrap_err(); - } - - #[test] - fn into_owning_ref() { - use super::super::BoxRef; - - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRef<()> = or.into(); - assert_eq!(&*or, &()); - } - - struct Foo { - u: u32, - } - struct Bar { - f: Foo, - } - - #[test] - fn ref_mut() { - use std::cell::RefCell; - - let a = RefCell::new(Bar { f: Foo { u: 42 } }); - let mut b = OwningRefMut::new(a.borrow_mut()); - assert_eq!(b.f.u, 42); - b.f.u = 43; - let mut c = b.map_mut(|x| &mut x.f); - assert_eq!(c.u, 43); - c.u = 44; - let mut d = c.map_mut(|x| &mut x.u); - assert_eq!(*d, 44); - *d = 45; - assert_eq!(*d, 45); - } - } -} diff --git a/third_party/rust/packed_simd/.cargo-checksum.json b/third_party/rust/packed_simd/.cargo-checksum.json deleted file mode 100644 index 0d75492f06..0000000000 --- a/third_party/rust/packed_simd/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"ae219b55eab1f8cd8c3497d7327ea0e5426dba23d2446f7981ca799ad80b6a52","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"c4ac7027a9ab7d7858aa8957d7454dbfcdbb81e605b6a171f05310cc3cad3762","bors.toml":"dee881dc69b9b7834e4eba5d95c3ed5a416d4628815a167d6a22d4cb4fb064b8","build.rs":"019ed29c43989782d8eec3a961654cfc172d7a7898da4eca8f654700af7e1988","ci/all.sh":"2ae6b2445b4db83833e40b37efd0016c6b9879ee988b9b3ef94db5439a3e1606","ci/android-install-ndk.sh":"bdcf93ba9043ac1184e2c504a3d40c47c6c1601d882e0f0a27a8eb56fbabcb5f","ci/android-install-sdk.sh":"3490432022c5c8f5a115c084f7a9aca1626f96c0c87ffb62019228c4346b47e4","ci/android-sysimage.sh":"ebf4e5daa1f0fe1b2092b79f0f3f161c4c4275cb744e52352c4d81ab451e4c5a","ci/benchmark.sh":"b61d19ef6b90deba8fb79dee74c8b062d94844676293da346da87bb78a9a49a4","ci/deploy_and_run_on_ios_simulator.rs":"ec8ecf82d92072676aa47f0d1a3d021b60a7ae3531153ef12d2ff4541fc294dc","ci/docker/aarch64-linux-android/Dockerfile":"ace2e7d33c87bc0f6d3962a4a3408c04557646f7f51ab99cfbf574906796b016","ci/docker/aarch64-unknown-linux-gnu/Dockerfile":"da88c0d50f16dc08448c7fdf1fa5ed2cbe576acf9e7dd85b5b818621b2a8c702","ci/docker/arm-unknown-linux-gnueabi/Dockerfile":"bb5f8ae890707c128652290ffc544447643bf12037ddd73c6ad6989f848cb380","ci/docker/arm-unknown-linux-gnueabihf/Dockerfile":"1afaefcbc05b740859acd4e067bc92439be6bcbe8f2e9678474fb434bcd398d9","ci/docker/armv7-linux-androideabi/Dockerfile":"370e55d3330a413a3ccf677b3afb3e0ef9018a5fab263faa97ae8ac017fc2286","ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile":"8282ea707a94109beed47a57574755e2d58401735904a03f85fb64c578c53b4f","ci/docker/i586-unknown-linux-gnu/Dockerfile":"49792922269f371bd29da4727e9085101b27be67a6b97755d0196c63317f7abb","ci/docker/i686-unknown-linux-gnu/Dockerfile":"49792922269f371bd29da4727e9085101b27be67a6b97755d0196c63317f7abb","ci/docker/mips-unknown-linux-gnu/Dockerfile":"b2ebc25797612c4f8395fe9d407725156044955bfbcf442036b7f55b43a5f9da","ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile":"b0c1692ac65bc56dd30494b1993d8e929c48cc9c4b92029b7c7592af6d4f9220","ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile":"4e9249c179300138141d0b2b7401b11897f64aed69f541f078c1db4594df2827","ci/docker/mipsel-unknown-linux-musl/Dockerfile":"3164c52b0dcbb01afa78292b15b5c43503ccf0491cf6eb801ec2bf22ae274e52","ci/docker/powerpc-unknown-linux-gnu/Dockerfile":"ae8274309928620a5dd232a46264e05399bb746288ebee3843a71c4162208cc3","ci/docker/powerpc64-unknown-linux-gnu/Dockerfile":"ba5fbc4bf3bb91cd50b407248da31225681efc8f2be7618f4a0ab1219b389508","ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile":"53f97f8b9b5aca7534b9bf9ea48f35175052cd2a560a107e01ad270731c032fc","ci/docker/s390x-unknown-linux-gnu/Dockerfile":"89f5421cf06d817ae94092987e914472ef384ad2d1fff2735be3d8786ba11214","ci/docker/sparc64-unknown-linux-gnu/Dockerfile":"83eba19576486f9d10d7c037d669d72b31a65565a479f30b22aab36aaa2ff8dc","ci/docker/thumbv7neon-linux-androideabi/Dockerfile":"c2decd5591bd7a09378901bef629cd944acf052eb55e4f35b79eb9cb4d62246a","ci/docker/thumbv7neon-unknown-linux-gnueabihf/Dockerfile":"51955a8bf3c4d440f47382af6f5426ebff94ab01a04da36175babda9a057740f","ci/docker/wasm32-unknown-unknown/Dockerfile":"b982b421c70db476900df5b60e19ef8815e6c7dae22687225002780cab7b0a76","ci/docker/x86_64-linux-android/Dockerfile":"a17ebdb186ce2dd6b62100b5a439e05a1ab9adab113e2508843e121aaea52992","ci/docker/x86_64-unknown-linux-gnu-emulated/Dockerfile":"44b6203d9290bfdc53d81219f0937e1110847a23dd982ec8c4de388354f01536","ci/docker/x86_64-unknown-linux-gnu/Dockerfile":"7f4e3ca5fa288ea70edb4d1f75309708cd30b192e2e4444e61c4d5b3b58f89cf","ci/dox.sh":"434e9611c52e389312d2b03564adf09429f10cc76fe66a8644adb104903b87b7","ci/linux-s390x.sh":"d6b732d7795b4ba131326aff893bca6228a7d2eb0e9402f135705413dbbe0dce","ci/linux-sparc64.sh":"c92966838b1ab7ad3b7a344833ee726aba6b647cf5952e56f0ad1ba420b13325","ci/lld-shim.rs":"3d7f71ec23a49e2b67f694a0168786f9a954dda15f5a138815d966643fd3fcc3","ci/max_line_width.sh":"0a1518bba4c9ecaa55694cb2e9930d0e19c265baabf73143f17f9cf285aaa5bb","ci/run-docker.sh":"92e036390ad9b0d16f109579df1b5ced2e72e9afea40c7d011400ebd3a2a90de","ci/run.sh":"9afabc961e0ee83b87201f3fd554c19e5b0c36f3a95d013595e276c9882dd0a4","ci/run_examples.sh":"d1a23c6c35374a0678ba5114b9b8fefd8be0a79e774872a8bf0898d1baca18d0","ci/runtest-android.rs":"145a8e9799a5223975061fe7e586ade5669ee4877a7d7a4cf6b4ab48e8e36c7c","ci/setup_benchmarks.sh":"fae3960023f6f3d1388cd2ad22fdbab4b075f1f29dd4292d7994a20783beb6cf","ci/test-runner-linux":"c8aa6025cff5306f4f31d0c61dc5f9d4dd5a1d189ab613ef8d4c367c694d9ccd","contributing.md":"2d2629310ad4d464c482bdbb5819f0d6ce223c576aeef2cdce6a1f6857085ea5","perf-guide/book.toml":"115a98284126c6b180178b44713314cc494f08a71662ee2ce15cf67f17a51064","perf-guide/src/SUMMARY.md":"3e03bffc991fdc2050f3d51842d72d9d21ea6abab56a3baf3b2d5973a78b89e1","perf-guide/src/ascii.css":"29afb08833b2fe2250f0412e1fa1161a2432a0820a14953c87124407417c741a","perf-guide/src/bound_checks.md":"5e4991ff58a183ef0cd9fdc1feb4cd12d083b44bdf87393bbb0927808ef3ce7d","perf-guide/src/float-math/approx.md":"8c09032fa2d795a0c5db1775826c850d28eb2627846d0965c60ee72de63735ad","perf-guide/src/float-math/fma.md":"311076ba4b741d604a82e74b83a8d7e8c318fcbd7f64c4392d1cf5af95c60243","perf-guide/src/float-math/fp.md":"04153e775ab6e4f0d7837bcc515230d327b04edfa34c84ce9c9e10ebaeef2be8","perf-guide/src/float-math/svml.md":"0798873b8eedaeda5fed62dc91645b57c20775a02d3cd74d8bd06958f1516506","perf-guide/src/introduction.md":"9f5a19e9e6751f25d2daad39891a0cc600974527ec4c8305843f9618910671bd","perf-guide/src/prof/linux.md":"447731eb5de7d69166728fdbc5ecb0c0c9db678ea493b45a592d67dd002184c0","perf-guide/src/prof/mca.md":"f56d54f3d20e7aa4d32052186e8237b03d65971eb5d112802b442570ff11d344","perf-guide/src/prof/profiling.md":"8a650c0fd6ede0964789bb6577557eeef1d8226a896788602ce61528e260e43c","perf-guide/src/target-feature/attribute.md":"615f88dca0a707b6c416fa605435dd6e1fb5361cc639429cbf68cd87624bd78b","perf-guide/src/target-feature/features.md":"17077760ff24c006b606dd21889c53d87228f4311f3ba3a574f9afdeacd86165","perf-guide/src/target-feature/inlining.md":"7ed1d7068d8173a00d84c16cfe5871cd68b9f04f8d0cca2d01ebc84957ebf2f6","perf-guide/src/target-feature/practice.md":"c4b371842e0086df178488fec97f20def8f0c62ee588bcd25fd948b9b1fa227e","perf-guide/src/target-feature/runtime.md":"835425f5ee597fb3e51d36e725a81ebee29f4561231d19563cd4da81dbb1cfcb","perf-guide/src/target-feature/rustflags.md":"01197acf6f0adec8db32b8591811f69cecb6555a2b05dc5d5ec27d0e3f7b065e","perf-guide/src/vert-hor-ops.md":"c6211c0ee91e60552ec592d89d9d957eedc21dee3cbd89e1ad6765ea06a27471","rust-toolchain":"58bea07cb6d97f9cfcd5c8f98b1feca0fb81cce5b0bf29a8e70ed2641956e9a6","rustfmt.toml":"d99a43f3f8ef9e425cf01c333fba9f0051f888f5d87ab4e8f63c2f7d0fe6620f","src/api.rs":"45508c6c0241519fc01a7f00c9105554c24c312c4e46900ef9c75139ea438305","src/api/bit_manip.rs":"27f3097fc0a11e3c4107049d9779e680dcd67407a066704008a6b9c4fd529e05","src/api/bitmask.rs":"058ebc38a2e0363f07a441d3e9a4775aaec57ccb170a0e5d5efa5dc4743ab07b","src/api/cast.rs":"03b94a3d316ac7b7be7068810044911e965e889a0ace7bae762749ca74a92747","src/api/cast/macros.rs":"b0a14d0c83ad2ebb7a275180f6d9e3f2bc312ba57a7d3d6c39fad4e0f20f9408","src/api/cast/v128.rs":"edd0994efac4379dff26e178423a52dbb3ffeb38b1fc97cae975d744c00b4fb6","src/api/cast/v16.rs":"96bd98c2d21b0663abe6c0ab33005b1fa693f3db7ee6795351391343863484da","src/api/cast/v256.rs":"8c31fe91f5e78ef737dfba6979cc1240210cb094a89d284fe459bf8a991ca24b","src/api/cast/v32.rs":"a99a79dd84d2a5e6adf9db98705675915bd03fd1287d489c7fe38e84d7e4a086","src/api/cast/v512.rs":"c0dd526f41ed7b8a71c3743d91267554ec0a0c75834ccc2e3ecb0ef3004af642","src/api/cast/v64.rs":"6572fdba2a1241a6cd666d3f0cce3306cd2cb7e5e236172e59d5d4351c8a88af","src/api/cmp.rs":"357c3a2a09c6d4611c32dd7fa95be2fae933d513e229026ec9b44451a77b884e","src/api/cmp/eq.rs":"60f70f355bae4cb5b17db53204cacc3890f70670611c17df638d4c04f7cc8075","src/api/cmp/ord.rs":"589f7234761c294fa5df8f525bc4acd5a47cdb602207d524a0d4e19804cd9695","src/api/cmp/partial_eq.rs":"902ccb8aa01fd5738b30ba0b712669c21d4801958907e03bad23432c7dba0198","src/api/cmp/partial_ord.rs":"9db0c37d7434cdfc62d8d66912e972fa3d8c115ab2af051a6f45e414bd3e4f1c","src/api/cmp/vertical.rs":"de3d62f38eba817299aa16f1e1939954c9a447e316509397465c2830852ba053","src/api/default.rs":"67bf21c134127d12a7028c8b88a57f0ceee8ccbd74976da8ca74eb9f16a174d5","src/api/fmt.rs":"67fb804bb86b6cd77cf8cd492b5733ce437071b66fe3297278b8a6552c325dda","src/api/fmt/binary.rs":"02b2b287f7404f8a983813cf70c87108c8da3835578b63ab303116885f609413","src/api/fmt/debug.rs":"56e1c3bdc092747344fffaafff9da7163ee7827857f6fb7cb1c9923eca4f6fa0","src/api/fmt/lower_hex.rs":"558fd592f7f485712fb051509cecc7174a21e6bf62e5ce64766e75afc97bb8e1","src/api/fmt/octal.rs":"3b2e70877a4f368c7704f8e254236c014c365c74d93371c1feb5f030e6c66422","src/api/fmt/upper_hex.rs":"2a442f666bc80e22d41f903f881238fe114dd49344c3ed69849250e853cafc5d","src/api/from.rs":"2e599d8329cb05eaf06224cc441355c4b7b51254fc19256619333be8c149d444","src/api/from/from_array.rs":"5d2cc700568376bf6ee1fe5e406da3bc2d488ff155644bf73d06a1349b73fc53","src/api/from/from_vector.rs":"9764371aa9e6005aace74dea14f59e5611a095b7cf42707940924749282c52f0","src/api/hash.rs":"5076ece87969592c876486f5b1ea8affbeaec379d1a14a30859e0aa5592019de","src/api/into_bits.rs":"8f8011627250e23e66b5c0ca641afb079d8232674bb1354140b536bdbea63e55","src/api/into_bits/arch_specific.rs":"e7445021f3908326bfee758835e5fc5ad56aa1baa77fc1c58abe4350c66c670a","src/api/into_bits/macros.rs":"bb4fe99be2af6a21d805efab44c8e4e61a7b2adb42a65504a0cf26d13efdadcd","src/api/into_bits/v128.rs":"145a44922b09a5ca5b62d88a461d327d399a997a15db4b11d7b17e554a9fa4c0","src/api/into_bits/v16.rs":"f4f4f61ba88aa51b158ec56ca3dce234349aea0daf2b3029a14ab5125d1e41e5","src/api/into_bits/v256.rs":"8cea9c5d9809f11323cb7cdc53b83df593fd17caf926251e412ae9777bed547f","src/api/into_bits/v32.rs":"905ba683d342fa32f4202b80bb46530807bd0a5b588f6c2e8c9f475223c47775","src/api/into_bits/v512.rs":"e25afa1fbf088a5d58e7d75d197b6cd4c56637ea28542ba18e46a451f29d04e7","src/api/into_bits/v64.rs":"d6238022ccff7b92e55b3f6017fc269acb6f36330a6d7e8fb389853a0f1b6478","src/api/math.rs":"8b2a2fc651917a850539f993aa0b9e5bf4da67b11685285b8de8cdca311719ec","src/api/math/float.rs":"969a75cdb3743c5ac7cde653d1a7f659ac65f2a5afb004c9928a7b34b79c3e39","src/api/math/float/abs.rs":"5b6b2701e2e11135b7ce58a05052ea8120e10e4702c95d046b9d21b827b26bf8","src/api/math/float/consts.rs":"6302c9261da4291d144d5bb53493cdd073498feb40955fb6860ea3c4d06c978a","src/api/math/float/cos.rs":"4c2dd7173728ef189314f1576c9486e03be21b7da98843b2f9011282a7979e31","src/api/math/float/exp.rs":"7c6d5f1e304f498a01cfa23b92380c815d7da0ad94eae3483783bc377d287eef","src/api/math/float/ln.rs":"54c7583f3df793b39ff57534fade27b41bb992439e5dc178252f5ca3190a3e54","src/api/math/float/mul_add.rs":"62cac77660d20159276d4c9ef066eb90c81cbddb808e8e157182c607625ad2eb","src/api/math/float/mul_adde.rs":"bae056ee9f3a70df39ec3c3b2f6437c65303888a7b843ef1a5bcf1f5aca0e602","src/api/math/float/powf.rs":"9ddb938984b36d39d82a82f862f80df8f7fb013f1d222d45698d41d88472f568","src/api/math/float/recpre.rs":"589225794ff1dbf31158dff660e6d4509ecc8befbb57c633900dea5ac0b840d6","src/api/math/float/rsqrte.rs":"a32abdcc318d7ccc8448231f54d75b884b7cbeb03a7d595713ab6243036f4dbf","src/api/math/float/sin.rs":"cbd3622b7df74f19691743001c8cf747a201f8977ad90542fee915f37dcd1e49","src/api/math/float/sqrt.rs":"0c66d5d63fb08e4d99c6b82a8828e41173aff1ac9fa1a2764a11fac217ccf2ac","src/api/math/float/sqrte.rs":"731e1c9f321b662accdd27dacb3aac2e8043b7aecb2f2161dde733bd9f025362","src/api/math/float/tanh.rs":"e57940434cc05981b086f0f3b92d32caceb38d67b90aebce5d3ed8e07c80538f","src/api/minimal.rs":"1f22bcc528555444e76de569ec0ae2029b9ae9d04805efeafa93369c8098036b","src/api/minimal/iuf.rs":"819cff26d3e196f807645bcc1d79eb27d9f175edb89910f2274d52a1e913cd11","src/api/minimal/mask.rs":"0cae10ae1fc65f5070e686c0c79bfba27b86b33d6c399367bd4848fb367dcec4","src/api/minimal/ptr.rs":"f74d7a4925d7209faebc26ea8315259cb2c08ec65789a70869e595649a9bc39a","src/api/ops.rs":"3e273b277a0f3019d42c3c59ca94a5afd4885d5ae6d2182e5089bbeec9de42ee","src/api/ops/scalar_arithmetic.rs":"d2d5ad897a59dd0787544f927e0e7ca4072c3e58b0f4a2324083312b0d5a21d7","src/api/ops/scalar_bitwise.rs":"482204e459ca6be79568e1c9f70adbe2d2151412ddf122fb2161be8ebb51c40c","src/api/ops/scalar_mask_bitwise.rs":"c250f52042e37b22d57256c80d4604104cfd2fbe2a2e127c676267270ca5d350","src/api/ops/scalar_shifts.rs":"c4773d435c3f9da4454327e6fbb2b5b41a1c0ebb1cca7372e69dc7a344a1b6e4","src/api/ops/vector_arithmetic.rs":"ddca15d09ddeef502c2ed66117a62300ca65d87e959e8b622d767bdf1c307910","src/api/ops/vector_bitwise.rs":"b3968f7005b649edcc22a54e2379b14d5ee19045f2e784029805781ae043b5ee","src/api/ops/vector_float_min_max.rs":"76bf8cb607e2c442923c1da1061a6b80d742d607408033c2a3761161114cf2a0","src/api/ops/vector_int_min_max.rs":"a378789c6ff9b32a51fbd0a97ffd36ed102cd1fe6a067d2b02017c1df342def6","src/api/ops/vector_mask_bitwise.rs":"5052d18517d765415d40327e6e8e55a312daaca0a5e2aec959bfa54b1675f9c8","src/api/ops/vector_neg.rs":"5c62f6b0221983cdbd23cd0a3af3672e6ba1255f0dfe8b19aae6fbd6503e231b","src/api/ops/vector_rotates.rs":"6c3f761d9d551f6365a8a95539ceace4b1a02e0b12d144f34ed68db94e88cff4","src/api/ops/vector_shifts.rs":"e510be14127c0ffd58a2573a39701da3557d66bedec09837ac8bbd44d579da00","src/api/ptr.rs":"8a793251bed6130dcfb2f1519ceaa18b751bbb15875928d0fb6deb5a5e07523a","src/api/ptr/gather_scatter.rs":"3d614f9d5b4ca201a9f7e46af4405e1d2c28ecee1620297c23b52e37b92cc0ea","src/api/reductions.rs":"ae5baca81352ecd44526d6c30c0a1feeda475ec73ddd3c3ec6b14e944e5448ee","src/api/reductions/bitwise.rs":"8bf910ae226188bd15fc7e125f058cd2566b6186fcd0cd8fd020f352c39ce139","src/api/reductions/float_arithmetic.rs":"47a5679896db2cbb56c31372fe42143da015b6beae7db5d2f3a0309ddf427ae1","src/api/reductions/integer_arithmetic.rs":"c2df3cf7493cca4174f2c65aea422a3d20d8a23af03f8d57cef72c19fee8f20d","src/api/reductions/mask.rs":"db83327a950e33a317f37fd33ca4e20c347fb415975ec024f3e23da8509425af","src/api/reductions/min_max.rs":"6af8c9aa45c69961b1b6fc205395f4767d4421869fb105fb3d563c5605fc13cd","src/api/select.rs":"6b07e7e8026df561f7307221a896f0fbb272536f41b9109040ac094c24c69331","src/api/shuffle.rs":"be7faff9b59654926df12897b2f98a4baa7d6acf2af1aaf93d388ba6e96f83ec","src/api/shuffle1_dyn.rs":"bfea5a91905b31444e9ef7ca6eddb7a9606b7e22d3f71bb842eb2795a0346620","src/api/slice.rs":"ee87484e8af329547b9a5d4f2a69e8bed6ea10bbd96270d706083843d4eea2ac","src/api/slice/from_slice.rs":"3735363000737104a8fc5f394ad8c31ec14e885952bd57647dd2a84001aee0a6","src/api/slice/write_to_slice.rs":"79d09c64d00724783c77c42e4583eeec97b18db94cf2ae146b564c3f85cfefd6","src/api/swap_bytes.rs":"05b4262eaade2f63e6cd3b780c19a03aecd2459d4cc4360051fc088887179a6e","src/codegen.rs":"db4f232fb9f5728db310b87dc8c4733be48afacab1053798c06106bef9a42b05","src/codegen/bit_manip.rs":"525ea6ff7ad1e043b6f6136992166f1803ed5563b7f6fc292c1c40257d20e264","src/codegen/llvm.rs":"12e748b4928c3be6cc12b4165c3041a3d0efccf6195338ecd3d88b8fdb0bbcc7","src/codegen/math.rs":"dfcf02ad34e2fdfe22c3f1cc2822001cc895e65031b4d06e585e5047839febb7","src/codegen/math/float.rs":"b2f31f479c5c70a6ff9ad33872c1e65506f72882b77a2e3f9e71c42e92af9355","src/codegen/math/float/abs.rs":"d5aaadcf540bdb9b4264dca6471a255fd7bf509e763bef0239c0144a68466fea","src/codegen/math/float/cos.rs":"17f28d2900c852dca221fa9c92a9cd5fe7fd2df8d427bbc60216c749b2be013d","src/codegen/math/float/cos_pi.rs":"dbaf9f443f9846a491d4ec52210a7b5835dd593b03366e3135b05c37d70f9d6c","src/codegen/math/float/exp.rs":"d300058a4bcc7ae7976f216f81902cd73a9e603ad63880dff3bbc866c27a9f37","src/codegen/math/float/ln.rs":"c851e211e43f8256093ba75b03ae0c307c9962ee66d94f09b4dd80068190cbdf","src/codegen/math/float/macros.rs":"fc9924869ed85e4795983af228cacf23158f4f35919adce16c920ad4a3f0a009","src/codegen/math/float/mul_add.rs":"041a5b69d5991d93ef795351b17560c10faf80b78fd26ad7df42a239b32cf9de","src/codegen/math/float/mul_adde.rs":"d71d5f0f3333b62a7439b823cb7adf5340ea1555ce820fb4a3f4cb922f73f5f5","src/codegen/math/float/powf.rs":"9742c3877f1a5509ca5c9492a40884b6579ba6dd11c26b7112e63f70666b395d","src/codegen/math/float/sin.rs":"0e9868d35531566509f3a01d85d5253045eb4afa8525d8407dcc1f5f33c56036","src/codegen/math/float/sin_cos_pi.rs":"8e6b6142d7dd240cdb36669722e82ab9810a2261e86e659f7d97a942ad8b1258","src/codegen/math/float/sin_pi.rs":"bb6d39db8f921e03a301fc5206ac1a61a97def8a2cb83b87ccf189f3fc48d548","src/codegen/math/float/sqrt.rs":"e6ebb0c5f428efad1f672b9a8fe4e58534dbf1ea5a8fe092ce5ce76b52fe89cb","src/codegen/math/float/sqrte.rs":"23acfaea38d0e081a6d9021c1094e813d0cfd12c58c1eca9662aade5e625d51c","src/codegen/math/float/tanh.rs":"816fd107f134920fb1a21cd792029d4b89306f6cf16d6f030cc1136823b033e7","src/codegen/pointer_sized_int.rs":"6ca13c214b6cf7e0929dbe18e96a16fc0bb7d8799608df29c4c8115490f99e01","src/codegen/reductions.rs":"8eb18ebac76985d2aa30262a2edd8cb004230b511a765d657525f677a585c12c","src/codegen/reductions/mask.rs":"e67f35a1f4d156a4894a2d6ea5a935b4d898cf70eefb2715f5c1cc165e776c11","src/codegen/reductions/mask/aarch64.rs":"84b101c17cad1ede4eb6d38cada0ac7da239dba8cea3badd3829b967e558431f","src/codegen/reductions/mask/arm.rs":"aaa07129bd078ae7e677cf8b8e67ec9f30536606a0c7ed1baaa18fd1793bb218","src/codegen/reductions/mask/fallback.rs":"3eb9319d2c7cf19216b607b8459612c4e027b643cf11b036937d36896bf76786","src/codegen/reductions/mask/fallback_impl.rs":"76547f396e55ef403327c77c314cf8db8c7a5c9b9819bfb925abeacf130249e5","src/codegen/reductions/mask/x86.rs":"36dcd8af4ab99730a078ed113d3955f74eb1a2876e2e6d9f224e0ff462c216d1","src/codegen/reductions/mask/x86/avx.rs":"3a40868b38c86e35aefb96d7578de6322efe89d8135e0366359b54ddd06f861a","src/codegen/reductions/mask/x86/avx2.rs":"677aed3f056285285daa3adff8bc65e739630b4424defa6d9665e160f027507e","src/codegen/reductions/mask/x86/sse.rs":"8522f6ed03f6c32dd577d4298df477c08aeaaa38563706f29096e1911ed731f2","src/codegen/reductions/mask/x86/sse2.rs":"54ec56e49b0c6841eccb719e4f310d65fe767c04136b2ec20bd8b9d7d9897b9e","src/codegen/shuffle.rs":"1ec2930f4e1acc43ac30b518af298d466a79e9e75734a51c380b7810efd1a27f","src/codegen/shuffle1_dyn.rs":"3f13ca1597378758d05106bf5ff3715eee531f3cb6d88f48b9182bd6c9386b51","src/codegen/swap_bytes.rs":"c67c86e91ca3fc77539e0efcea081a3c62548cccf503963ae408f2e86f4e6a21","src/codegen/v128.rs":"94226b31ec403d18d9d2fe06713f147c9c79e9b5f9105089088266313f843185","src/codegen/v16.rs":"ddec4ffb66b6f7aaffb9a1780c5ddba82557abd74f45073d335047e04cf74924","src/codegen/v256.rs":"6b63917f0444118d6b1595bff2045e59b97c4d24012bd575f69f1f0efc5a0241","src/codegen/v32.rs":"3477b3c5540aed86e61e2f5807dd31db947413cec9181c587d93ed6ec74f0eba","src/codegen/v512.rs":"5854f99d3aabc4cd42b28a20d9ce447756dc2ba024a409a69b6a8ae1f1842fc5","src/codegen/v64.rs":"e9e89caebfe63d10c0cbca61e4dfdba3b7e02ee0989170f80beed23237ddd950","src/codegen/vPtr.rs":"f0753b405cdc865bdf8e82c6505f299ea1f96136239ebbaf7f9ce93d310764b8","src/codegen/vSize.rs":"c89f5fdeb28ac4c8272ed1816fce03d9d95308cc32bb2533bd8b20cd5ac102ac","src/lib.rs":"05048c6a85ec65cf902d9dd8f757a3f76392b703a6794ea71f0d41500a89f78f","src/masks.rs":"70fc0abe4c2907ce2a491c574e1cfb9f3423385da2e1a923a48c9c13f8ba6ed8","src/sealed.rs":"ae7fdeaf5d84cd7710ed730ca72ca7eaba93df6cb0acb183e5c0a7327acf197f","src/testing.rs":"896669c08d8c801448a4d2fadc9d633eda0fbe879d229997e2a182e31278e469","src/testing/macros.rs":"403bbc5ecb7c786fe36156df302d0c07a8122408dbb15f7474d7682224ba1106","src/testing/utils.rs":"41912a92266dfe884647fc035e4242fd746100df8e839808ae0397af3759a3c8","src/v128.rs":"16cf9a8e7156b899ee9b9cd3f2dba9d13ec63289bea8c3ee9ae2e43ad9510288","src/v16.rs":"cb6465cf1e00bf530183af1819b9fe3d7eec978f8765d5e85d9b58a39a4b4045","src/v256.rs":"fe235017da18c7f3c361831c60e3173ad304d8ea1e95d64ebebc79da2d708511","src/v32.rs":"145d347855bac59b2de6508f9e594654e6c330423af9edc0e2ac8f4d1abdf45e","src/v512.rs":"f372f277f3e62eb5c945bb1c460333fdb17b6974fcc876633788ff53bded9599","src/v64.rs":"0b8079881b71575e3414be0b7f8f7eaba65281ba6732f2b2f61f73e95b6f48f7","src/vPtr.rs":"8b3e433d487180bb4304ff71245ecad90f0010f43e139a72027b672abe58facc","src/vSize.rs":"eda5aa020706cbf94d15bada41a0c2a35fc8f3f37cb7c2cd6f34d201399a495e","tests/endianness.rs":"5147f86d224c4c540b772033da2f994cad9bc9c035f38ec21e23bc4e55f8a759"},"package":"1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d"} \ No newline at end of file diff --git a/third_party/rust/packed_simd/Cargo.toml b/third_party/rust/packed_simd/Cargo.toml deleted file mode 100644 index 77fc096b05..0000000000 --- a/third_party/rust/packed_simd/Cargo.toml +++ /dev/null @@ -1,83 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -name = "packed_simd" -version = "0.3.9" -build = "build.rs" -description = "Portable Packed SIMD vectors" -homepage = "https://github.com/rust-lang/packed_simd" -documentation = "https://docs.rs/crate/packed_simd/" -readme = "README.md" -keywords = [ - "simd", - "vector", - "portability", -] -categories = [ - "hardware-support", - "concurrency", - "no-std", - "data-structures", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang/packed_simd" - -[package.metadata.docs.rs] -features = ["into_bits"] -rustdoc-args = [ - "--cfg", - "doc_cfg", -] - -[dependencies.cfg-if] -version = "1.0.0" - -[dependencies.core_arch] -version = "0.1.5" -optional = true - -[dependencies.num-traits] -version = "0.2.14" -features = ["libm"] -default-features = false - -[dev-dependencies.arrayvec] -version = "^0.5" -default-features = false - -[dev-dependencies.paste] -version = "^1" - -[features] -default = [] -into_bits = [] -libcore_neon = [] - -[target."cfg(target_arch = \"x86_64\")".dependencies.sleef-sys] -version = "0.1.2" -optional = true - -[target.wasm32-unknown-unknown.dev-dependencies.wasm-bindgen] -version = "=0.2.87" - -[target.wasm32-unknown-unknown.dev-dependencies.wasm-bindgen-test] -version = "=0.3.37" - -[badges.is-it-maintained-issue-resolution] -repository = "rust-lang/packed_simd" - -[badges.is-it-maintained-open-issues] -repository = "rust-lang/packed_simd" - -[badges.maintenance] -status = "experimental" diff --git a/third_party/rust/packed_simd/LICENSE-APACHE b/third_party/rust/packed_simd/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e..0000000000 --- a/third_party/rust/packed_simd/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/third_party/rust/packed_simd/LICENSE-MIT b/third_party/rust/packed_simd/LICENSE-MIT deleted file mode 100644 index 39d4bdb5ac..0000000000 --- a/third_party/rust/packed_simd/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2014 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/packed_simd/README.md b/third_party/rust/packed_simd/README.md deleted file mode 100644 index 59db13fe4f..0000000000 --- a/third_party/rust/packed_simd/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# `Simd<[T; N]>` - -## Implementation of [Rust RFC #2366: `std::simd`][rfc2366] - -[![Latest Version]][crates.io] [![docs]][master_docs] - -**WARNING**: this crate only supports the most recent nightly Rust toolchain -and will be superseded by [`#![feature(portable_simd)]`](https://github.com/rust-lang/portable-simd). - -## Documentation - -* [API docs (`master` branch)][master_docs] -* [Performance guide][perf_guide] -* [API docs (`docs.rs`)][docs.rs] -* [RFC2366 `std::simd`][rfc2366]: - contains motivation, design rationale, - discussion, etc. - -## Examples - -Most of the examples come with both a scalar and a vectorized implementation. - -* [`aobench`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/aobench) -* [`fannkuch_redux`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/fannkuch_redux) -* [`matrix inverse`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/matrix_inverse) -* [`mandelbrot`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/mandelbrot) -* [`n-body`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/nbody) -* [`options_pricing`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/options_pricing) -* [`spectral_norm`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/spectral_norm) -* [`triangle transform`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/triangle_xform) -* [`stencil`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/stencil) -* [`vector dot product`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/dot_product) - -## Cargo features - -* `into_bits` (default: disabled): enables `FromBits`/`IntoBits` trait - implementations for the vector types. These allow reinterpreting the bits of a - vector type as those of another vector type safely by just using the - `.into_bits()` method. - -## Performance - -The following [ISPC] examples are also part of `packed_simd`'s -[`examples/`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples/) -directory, where `packed_simd`+[`rayon`][rayon] are used to emulate [ISPC]'s -Single-Program-Multiple-Data (SPMD) programming model. The performance results -on different hardware is shown in the `readme.md` of each example. The following -table summarizes the performance ranges, where `+` means speed-up and `-` -slowdown: - -* `aobench`: `[-1.02x, +1.53x]`, -* `stencil`: `[+1.06x, +1.72x]`, -* `mandelbrot`: `[-1.74x, +1.2x]`, -* `options_pricing`: - * `black_scholes`: `+1.0x` - * `binomial_put`: `+1.4x` - - While SPMD is not the intended use case for `packed_simd`, it is possible to - combine the library with [`rayon`][rayon] to poorly emulate [ISPC]'s SPMD programming - model in Rust. Writing performant code is not as straightforward as with - [ISPC], but with some care (e.g. see the [Performance Guide][perf_guide]) one - can easily match and often out-perform [ISPC]'s "default performance". - -## Platform support - -The following table describes the supported platforms: `build` shows whether -the library compiles without issues for a given target, while `run` shows -whether the test suite passes for a given target. - -| **Linux** | **build** | **run** | -|---------------------------------------|-----------|---------| -| `i586-unknown-linux-gnu` | ✓ | ✗ | -| `i686-unknown-linux-gnu` | ✓ | ✗ | -| `x86_64-unknown-linux-gnu` | ✓ | ✓ | -| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | -| `armv7-unknown-linux-gnueabi` | ✓ | ✓ | -| `aarch64-unknown-linux-gnu` | ✓ | ✓ | -| `powerpc-unknown-linux-gnu` | ✓ | ✗ | -| `powerpc64-unknown-linux-gnu` | ✓ | ✗ | -| `powerpc64le-unknown-linux-gnu` | ✓ | ✓ | -| `s390x-unknown-linux-gnu` | ✓ | ✗ | -| `sparc64-unknown-linux-gnu` | ✓ | ✗ | -| `thumbv7neon-unknown-linux-gnueabihf` | ✓ | ✓ | -| **MacOSX** | **build** | **run** | -| `x86_64-apple-darwin` | ✓ | ✓ | -| **Android** | **build** | **run** | -| `x86_64-linux-android` | ✓ | ✓ | -| `armv7-linux-androideabi` | ✓ | ✗ | -| `aarch64-linux-android` | ✓ | ✗ | -| `thumbv7neon-linux-androideabi` | ✓ | ✗ | -| **iOS** | **build** | **run** | -| `x86_64-apple-ios` | ✗ | ✗ | -| `aarch64-apple-ios` | ✗ | ✗ | - - -## Machine code verification - -The -[`verify/`](https://github.com/rust-lang-nursery/packed_simd/tree/master/verify) -crate tests disassembles the portable packed vector APIs at run-time and -compares the generated machine code against the desired one to make sure that -this crate remains efficient. - -## License - -This project is licensed under either of - -* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) - ([LICENSE-APACHE](LICENSE-APACHE)) - -* [MIT License](http://opensource.org/licenses/MIT) - ([LICENSE-MIT](LICENSE-MIT)) - -at your option. - -## Contributing - -We welcome all people who want to contribute. -Please see the [contributing instructions] for more information. - -Contributions in any form (issues, pull requests, etc.) to this project -must adhere to Rust's [Code of Conduct]. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in `packed_simd` by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. - -[travis]: https://travis-ci.com/rust-lang/packed_simd -[Travis-CI Status]: https://travis-ci.com/rust-lang/packed_simd.svg?branch=master -[appveyor]: https://ci.appveyor.com/project/gnzlbg/packed-simd -[Appveyor Status]: https://ci.appveyor.com/api/projects/status/hd7v9dvr442hgdix?svg=true -[Latest Version]: https://img.shields.io/crates/v/packed_simd.svg -[crates.io]: https://crates.io/crates/packed_simd -[docs]: https://docs.rs/packed_simd/badge.svg -[docs.rs]: https://docs.rs/packed_simd -[master_docs]: https://rust-lang-nursery.github.io/packed_simd/packed_simd/ -[perf_guide]: https://rust-lang-nursery.github.io/packed_simd/perf-guide/ -[rfc2366]: https://github.com/rust-lang/rfcs/pull/2366 -[ISPC]: https://ispc.github.io/ -[rayon]: https://crates.io/crates/rayon -[boost_license]: https://www.boost.org/LICENSE_1_0.txt -[SLEEF]: https://sleef.org/ -[sleef_sys]: https://crates.io/crates/sleef-sys -[contributing instructions]: contributing.md -[Code of Conduct]: https://www.rust-lang.org/en-US/conduct.html diff --git a/third_party/rust/packed_simd/bors.toml b/third_party/rust/packed_simd/bors.toml deleted file mode 100644 index 6d302dc85c..0000000000 --- a/third_party/rust/packed_simd/bors.toml +++ /dev/null @@ -1,3 +0,0 @@ -status = [ - "continuous-integration/travis-ci/push" -] \ No newline at end of file diff --git a/third_party/rust/packed_simd/build.rs b/third_party/rust/packed_simd/build.rs deleted file mode 100644 index e87298a2de..0000000000 --- a/third_party/rust/packed_simd/build.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let target = std::env::var("TARGET").expect("TARGET environment variable not defined"); - if target.contains("neon") { - println!("cargo:rustc-cfg=libcore_neon"); - } -} diff --git a/third_party/rust/packed_simd/ci/all.sh b/third_party/rust/packed_simd/ci/all.sh deleted file mode 100755 index 55a1fa2efe..0000000000 --- a/third_party/rust/packed_simd/ci/all.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -# -# Performs an operation on all targets - -set -ex - -: "${1?The all.sh script requires one argument.}" - -op=$1 - -cargo_clean() { - cargo clean -} - -cargo_check_fmt() { - cargo fmt --all -- --check -} - -cargo_fmt() { - cargo fmt --all -} - -cargo_clippy() { - cargo clippy --all -- -D clippy::perf -} - -CMD="-1" - -case $op in - clean*) - CMD=cargo_clean - ;; - check_fmt*) - CMD=cargo_check_fmt - ;; - fmt*) - CMD=cargo_fmt - ;; - clippy) - CMD=cargo_clippy - ;; - *) - echo "Unknown operation: \"${op}\"" - exit 1 - ;; -esac - -echo "Operation is: ${CMD}" - -# On src/ -$CMD - -# Check examples/ -for dir in examples/*/ -do - dir=${dir%*/} - ( - cd "${dir%*/}" - $CMD - ) -done - -( - cd verify/verify - $CMD -) - -( - cd micro_benchmarks - $CMD -) diff --git a/third_party/rust/packed_simd/ci/android-install-ndk.sh b/third_party/rust/packed_simd/ci/android-install-ndk.sh deleted file mode 100644 index 5370853937..0000000000 --- a/third_party/rust/packed_simd/ci/android-install-ndk.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env sh -# Copyright 2016 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex - -ANDROID_NDK_URL=https://dl.google.com/android/repository -ANDROID_NDK_ARCHIVE=android-ndk-r25b-linux.zip - -curl -fO "$ANDROID_NDK_URL/$ANDROID_NDK_ARCHIVE" -unzip -q $ANDROID_NDK_ARCHIVE -rm $ANDROID_NDK_ARCHIVE -mv android-ndk-* ndk -rm -rf android-ndk-* diff --git a/third_party/rust/packed_simd/ci/android-install-sdk.sh b/third_party/rust/packed_simd/ci/android-install-sdk.sh deleted file mode 100644 index 6b5ac09ab0..0000000000 --- a/third_party/rust/packed_simd/ci/android-install-sdk.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env sh -# Copyright 2016 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex - -# Prep the SDK and emulator -# -# Note that the update process requires that we accept a bunch of licenses, and -# we can't just pipe `yes` into it for some reason, so we take the same strategy -# located in https://github.com/appunite/docker by just wrapping it in a script -# which apparently magically accepts the licenses. - -mkdir sdk -curl --retry 5 https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip -O -unzip -d sdk sdk-tools-linux-3859397.zip - -case "$1" in - arm | armv7) - abi=armeabi-v7a - ;; - - aarch64) - abi=arm64-v8a - ;; - - i686) - abi=x86 - ;; - - x86_64) - abi=x86_64 - ;; - - *) - echo "invalid arch: $1" - exit 1 - ;; -esac; - -# --no_https avoids - # javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found -yes | ./sdk/tools/bin/sdkmanager --licenses --no_https -yes | ./sdk/tools/bin/sdkmanager --no_https \ - "emulator" \ - "platform-tools" \ - "platforms;android-24" \ - "system-images;android-24;default;$abi" - -echo "no" | - ./sdk/tools/bin/avdmanager create avd \ - --name "${1}" \ - --package "system-images;android-24;default;$abi" diff --git a/third_party/rust/packed_simd/ci/android-sysimage.sh b/third_party/rust/packed_simd/ci/android-sysimage.sh deleted file mode 100644 index 9eabd7c8d9..0000000000 --- a/third_party/rust/packed_simd/ci/android-sysimage.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex - -URL=https://dl.google.com/android/repository/sys-img/android - -main() { - local arch="${1}" - local name="${2}" - local dest=/system - local td - td="$(mktemp -d)" - - apt-get install --no-install-recommends e2tools - - pushd "${td}" - curl --retry 5 -O "${URL}/${name}" - unzip -q "${name}" - - local system - system="$(find . -name system.img)" - mkdir -p ${dest}/{bin,lib,lib64} - - # Extract android linker and libraries to /system - # This allows android executables to be run directly (or with qemu) - if [ "${arch}" = "x86_64" ] || [ "${arch}" = "arm64" ]; then - e2cp -p "${system}:/bin/linker64" "${dest}/bin/" - e2cp -p "${system}:/lib64/libdl.so" "${dest}/lib64/" - e2cp -p "${system}:/lib64/libc.so" "${dest}/lib64/" - e2cp -p "${system}:/lib64/libm.so" "${dest}/lib64/" - else - e2cp -p "${system}:/bin/linker" "${dest}/bin/" - e2cp -p "${system}:/lib/libdl.so" "${dest}/lib/" - e2cp -p "${system}:/lib/libc.so" "${dest}/lib/" - e2cp -p "${system}:/lib/libm.so" "${dest}/lib/" - fi - - # clean up - apt-get purge --auto-remove -y e2tools - - popd - - rm -rf "${td}" -} - -main "${@}" diff --git a/third_party/rust/packed_simd/ci/benchmark.sh b/third_party/rust/packed_simd/ci/benchmark.sh deleted file mode 100755 index 3635b9e371..0000000000 --- a/third_party/rust/packed_simd/ci/benchmark.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# -# Runs all benchmarks. Controlled by the following environment variables: -# -# FEATURES={} - cargo features to pass to all benchmarks (e.g. core_arch,sleef-sys,ispc) -# NORUN={1} - only builds the benchmarks - -set -ex - -if [[ ${NORUN} != 1 ]]; then - # Most benchmarks require hyperfine; require it upfront. - hash hyperfine 2>/dev/null || { echo >&2 "hyperfine is not in PATH."; exit 1; } -fi - - -# If the ispc benchmark feature is enabled, ispc must be in the path of the -# benchmarks. -if echo "$FEATURES" | grep -q "ispc"; then - hash ispc 2>/dev/null || { echo >&2 "ispc is not in PATH."; exit 1; } -fi - -# An example with a benchmark.sh is a benchmark: -for dir in examples/*/ -do - dir=${dir%*/} - cd ${dir%*/} - if [ -f "benchmark.sh" ]; then - ./benchmark.sh - fi - cd - -done - diff --git a/third_party/rust/packed_simd/ci/deploy_and_run_on_ios_simulator.rs b/third_party/rust/packed_simd/ci/deploy_and_run_on_ios_simulator.rs deleted file mode 100644 index c0fe52c356..0000000000 --- a/third_party/rust/packed_simd/ci/deploy_and_run_on_ios_simulator.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This is a script to deploy and execute a binary on an iOS simulator. -// The primary use of this is to be able to run unit tests on the simulator and -// retrieve the results. -// -// To do this through Cargo instead, use Dinghy -// (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy -// test. - -use std::env; -use std::fs::{self, File}; -use std::io::Write; -use std::path::Path; -use std::process; -use std::process::Command; - -macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with: {}", stringify!($e), e), - }) -} - -// Step one: Wrap as an app -fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) { - println!("Packaging simulator app"); - drop(fs::remove_dir_all("ios_simulator_app")); - t!(fs::create_dir("ios_simulator_app")); - t!(fs::copy(test_binary_path, - Path::new("ios_simulator_app").join(crate_name))); - - let mut f = t!(File::create("ios_simulator_app/Info.plist")); - t!(f.write_all(format!(r#" - - - - - CFBundleExecutable - {} - CFBundleIdentifier - com.rust.unittests - - - "#, crate_name).as_bytes())); -} - -// Step two: Start the iOS simulator -fn start_simulator() { - println!("Looking for iOS simulator"); - let output = t!(Command::new("xcrun").arg("simctl").arg("list").output()); - assert!(output.status.success()); - let mut simulator_exists = false; - let mut simulator_booted = false; - let mut found_rust_sim = false; - let stdout = t!(String::from_utf8(output.stdout)); - for line in stdout.lines() { - if line.contains("rust_ios") { - if found_rust_sim { - panic!("Duplicate rust_ios simulators found. Please \ - double-check xcrun simctl list."); - } - simulator_exists = true; - simulator_booted = line.contains("(Booted)"); - found_rust_sim = true; - } - } - - if simulator_exists == false { - println!("Creating iOS simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("create") - .arg("rust_ios") - .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE") - .arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2") - .check_status(); - } else if simulator_booted == true { - println!("Shutting down already-booted simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("shutdown") - .arg("rust_ios") - .check_status(); - } - - println!("Starting iOS simulator"); - // We can't uninstall the app (if present) as that will hang if the - // simulator isn't completely booted; just erase the simulator instead. - Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status(); - Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status(); -} - -// Step three: Install the app -fn install_app_to_simulator() { - println!("Installing app to simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("install") - .arg("booted") - .arg("ios_simulator_app/") - .check_status(); -} - -// Step four: Run the app -fn run_app_on_simulator() { - println!("Running app"); - let output = t!(Command::new("xcrun") - .arg("simctl") - .arg("launch") - .arg("--console") - .arg("booted") - .arg("com.rust.unittests") - .output()); - - println!("stdout --\n{}\n", String::from_utf8_lossy(&output.stdout)); - println!("stderr --\n{}\n", String::from_utf8_lossy(&output.stderr)); - - let stdout = String::from_utf8_lossy(&output.stdout); - let failed = stdout.lines() - .find(|l| l.contains("FAILED")) - .map(|l| l.contains("FAILED")) - .unwrap_or(false); - - let passed = stdout.lines() - .find(|l| l.contains("test result: ok")) - .map(|l| l.contains("test result: ok")) - .unwrap_or(false); - - println!("Shutting down simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("shutdown") - .arg("rust_ios") - .check_status(); - if !(passed && !failed) { - panic!("tests didn't pass"); - } -} - -trait CheckStatus { - fn check_status(&mut self); -} - -impl CheckStatus for Command { - fn check_status(&mut self) { - println!("\trunning: {:?}", self); - assert!(t!(self.status()).success()); - } -} - -fn main() { - let args: Vec = env::args().collect(); - if args.len() != 2 { - println!("Usage: {} ", args[0]); - process::exit(-1); - } - - let test_binary_path = Path::new(&args[1]); - let crate_name = test_binary_path.file_name().unwrap(); - - package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path); - start_simulator(); - install_app_to_simulator(); - run_app_on_simulator(); -} diff --git a/third_party/rust/packed_simd/ci/docker/aarch64-linux-android/Dockerfile b/third_party/rust/packed_simd/ci/docker/aarch64-linux-android/Dockerfile deleted file mode 100644 index 27bde89c5a..0000000000 --- a/third_party/rust/packed_simd/ci/docker/aarch64-linux-android/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -FROM ubuntu:16.04 - -RUN dpkg --add-architecture i386 && \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - file \ - make \ - curl \ - ca-certificates \ - python \ - unzip \ - expect \ - openjdk-9-jre \ - libstdc++6:i386 \ - libpulse0 \ - gcc \ - libc6-dev - -WORKDIR /android/ -COPY android* /android/ - -ENV ANDROID_ARCH=aarch64 -ENV PATH=$PATH:/android/ndk-$ANDROID_ARCH/bin:/android/sdk/tools:/android/sdk/platform-tools - -RUN sh /android/android-install-ndk.sh $ANDROID_ARCH -RUN sh /android/android-install-sdk.sh $ANDROID_ARCH -RUN mv /root/.android /tmp -RUN chmod 777 -R /tmp/.android -RUN chmod 755 /android/sdk/tools/* /android/sdk/emulator/qemu/linux-x86_64/* - -ENV PATH=$PATH:/rust/bin \ - CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android-gcc \ - CARGO_TARGET_AARCH64_LINUX_ANDROID_RUNNER=/tmp/runtest \ - OBJDUMP=aarch64-linux-android-objdump \ - HOME=/tmp - -ADD runtest-android.rs /tmp/runtest.rs -ENTRYPOINT [ \ - "bash", \ - "-c", \ - # set SHELL so android can detect a 64bits system, see - # http://stackoverflow.com/a/41789144 - "SHELL=/bin/dash /android/sdk/emulator/emulator @aarch64 -no-window & \ - rustc /tmp/runtest.rs -o /tmp/runtest && \ - exec \"$@\"", \ - "--" \ -] diff --git a/third_party/rust/packed_simd/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/aarch64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 41ff4729ac..0000000000 --- a/third_party/rust/packed_simd/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - ca-certificates \ - libc6-dev \ - gcc-aarch64-linux-gnu \ - libc6-dev-arm64-cross \ - qemu-user \ - make \ - file - -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu" \ - OBJDUMP=aarch64-linux-gnu-objdump diff --git a/third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabi/Dockerfile deleted file mode 100644 index e1c591dd97..0000000000 --- a/third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - ca-certificates \ - libc6-dev \ - libc6-armel-cross \ - libc6-dev-armel-cross \ - binutils-arm-linux-gnueabi \ - gcc-arm-linux-gnueabi \ - qemu-user \ - make \ - file -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER="qemu-arm -L /usr/arm-linux-gnueabi" \ - OBJDUMP=arm-linux-gnueabi-objdump diff --git a/third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 757b79e7ec..0000000000 --- a/third_party/rust/packed_simd/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - ca-certificates \ - libc6-dev \ - gcc-arm-linux-gnueabihf \ - libc6-dev-armhf-cross \ - qemu-user \ - make \ - file -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf" \ - OBJDUMP=arm-linux-gnueabihf-objdump diff --git a/third_party/rust/packed_simd/ci/docker/armv7-linux-androideabi/Dockerfile b/third_party/rust/packed_simd/ci/docker/armv7-linux-androideabi/Dockerfile deleted file mode 100644 index 995a9e30e6..0000000000 --- a/third_party/rust/packed_simd/ci/docker/armv7-linux-androideabi/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -FROM ubuntu:16.04 - -RUN dpkg --add-architecture i386 && \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - file \ - make \ - curl \ - ca-certificates \ - python \ - unzip \ - expect \ - openjdk-9-jre \ - libstdc++6:i386 \ - libpulse0 \ - gcc \ - libc6-dev - -WORKDIR /android/ -COPY android* /android/ - -ENV ANDROID_ARCH=arm -ENV PATH=$PATH:/android/ndk-$ANDROID_ARCH/bin:/android/sdk/tools:/android/sdk/platform-tools - -RUN sh /android/android-install-ndk.sh $ANDROID_ARCH -RUN sh /android/android-install-sdk.sh $ANDROID_ARCH -RUN mv /root/.android /tmp -RUN chmod 777 -R /tmp/.android -RUN chmod 755 /android/sdk/tools/* /android/sdk/emulator/qemu/linux-x86_64/* - -ENV PATH=$PATH:/rust/bin \ - CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \ - CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER=/tmp/runtest \ - OBJDUMP=arm-linux-androideabi-objdump \ - HOME=/tmp - -ADD runtest-android.rs /tmp/runtest.rs -ENTRYPOINT [ \ - "bash", \ - "-c", \ - # set SHELL so android can detect a 64bits system, see - # http://stackoverflow.com/a/41789144 - "SHELL=/bin/dash /android/sdk/emulator/emulator @arm -no-window & \ - rustc /tmp/runtest.rs -o /tmp/runtest && \ - exec \"$@\"", \ - "--" \ -] diff --git a/third_party/rust/packed_simd/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/third_party/rust/packed_simd/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 2539062933..0000000000 --- a/third_party/rust/packed_simd/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - ca-certificates \ - libc6-dev \ - gcc-arm-linux-gnueabihf \ - libc6-dev-armhf-cross \ - qemu-user \ - make \ - file -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ - CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf" \ - OBJDUMP=arm-linux-gnueabihf-objdump diff --git a/third_party/rust/packed_simd/ci/docker/i586-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/i586-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 01093698f6..0000000000 --- a/third_party/rust/packed_simd/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc-multilib \ - libc6-dev \ - file \ - make \ - ca-certificates diff --git a/third_party/rust/packed_simd/ci/docker/i686-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/i686-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 01093698f6..0000000000 --- a/third_party/rust/packed_simd/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc-multilib \ - libc6-dev \ - file \ - make \ - ca-certificates diff --git a/third_party/rust/packed_simd/ci/docker/mips-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/mips-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 3bd471e87d..0000000000 --- a/third_party/rust/packed_simd/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:18.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user ca-certificates \ - gcc-mips-linux-gnu libc6-dev-mips-cross \ - qemu-system-mips \ - qemu-user \ - make \ - file - -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ - CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER="qemu-mips -L /usr/mips-linux-gnu" \ - OBJDUMP=mips-linux-gnu-objdump \ No newline at end of file diff --git a/third_party/rust/packed_simd/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/third_party/rust/packed_simd/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index f26f1f38eb..0000000000 --- a/third_party/rust/packed_simd/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user ca-certificates \ - gcc-mips64-linux-gnuabi64 libc6-dev-mips64-cross \ - qemu-system-mips64 qemu-user - -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ - CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER="qemu-mips64 -L /usr/mips64-linux-gnuabi64" \ - OBJDUMP=mips64-linux-gnuabi64-objdump \ No newline at end of file diff --git a/third_party/rust/packed_simd/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/third_party/rust/packed_simd/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index 7d9f0bd992..0000000000 --- a/third_party/rust/packed_simd/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user ca-certificates \ - gcc-mips64el-linux-gnuabi64 libc6-dev-mips64el-cross \ - qemu-system-mips64el - -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ - CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER="qemu-mips64el -L /usr/mips64el-linux-gnuabi64" \ - OBJDUMP=mips64el-linux-gnuabi64-objdump \ No newline at end of file diff --git a/third_party/rust/packed_simd/ci/docker/mipsel-unknown-linux-musl/Dockerfile b/third_party/rust/packed_simd/ci/docker/mipsel-unknown-linux-musl/Dockerfile deleted file mode 100644 index 7488662ef2..0000000000 --- a/third_party/rust/packed_simd/ci/docker/mipsel-unknown-linux-musl/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM ubuntu:18.10 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - libc6-dev \ - make \ - qemu-user \ - qemu-system-mips \ - bzip2 \ - curl \ - file - -RUN mkdir /toolchain - -# Note that this originally came from: -# https://downloads.openwrt.org/snapshots/trunk/malta/generic/OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 -RUN curl -L https://ci-mirrors.rust-lang.org/libc/OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 | \ - tar xjf - -C /toolchain --strip-components=2 - -ENV PATH=$PATH:/rust/bin:/toolchain/bin \ - CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ - CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER=mipsel-openwrt-linux-gcc \ - CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_RUNNER="qemu-mipsel -L /toolchain" diff --git a/third_party/rust/packed_simd/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/powerpc-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 15ba58e60c..0000000000 --- a/third_party/rust/packed_simd/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:22.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user ca-certificates \ - gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ - qemu-system-ppc \ - make \ - file - -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ - CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER="qemu-ppc -cpu Vger -L /usr/powerpc-linux-gnu" \ - CC=powerpc-linux-gnu-gcc \ - OBJDUMP=powerpc-linux-gnu-objdump diff --git a/third_party/rust/packed_simd/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 21c296dc44..0000000000 --- a/third_party/rust/packed_simd/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM ubuntu:22.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - ca-certificates \ - libc6-dev \ - gcc-powerpc64-linux-gnu \ - libc6-dev-ppc64-cross \ - qemu-user \ - qemu-system-ppc \ - make \ - file - -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ - CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER="qemu-ppc64 -L /usr/powerpc64-linux-gnu" \ - CC=powerpc64-linux-gnu-gcc \ - OBJDUMP=powerpc64-linux-gnu-objdump diff --git a/third_party/rust/packed_simd/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 8034145fc0..0000000000 --- a/third_party/rust/packed_simd/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM ubuntu:22.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user ca-certificates \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ - qemu-system-ppc file make - -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ - CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER="qemu-ppc64le -L /usr/powerpc64le-linux-gnu" \ - CC=powerpc64le-linux-gnu-gcc \ - OBJDUMP=powerpc64le-linux-gnu-objdump diff --git a/third_party/rust/packed_simd/ci/docker/s390x-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/s390x-unknown-linux-gnu/Dockerfile deleted file mode 100644 index e785ca370c..0000000000 --- a/third_party/rust/packed_simd/ci/docker/s390x-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM ubuntu:22.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - curl \ - cmake \ - gcc \ - libc6-dev \ - g++-s390x-linux-gnu \ - libc6-dev-s390x-cross \ - qemu-user \ - make \ - file - -ENV CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc \ - CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="qemu-s390x -L /usr/s390x-linux-gnu" \ - CC_s390x_unknown_linux_gnu=s390x-linux-gnu-gcc \ - CXX_s390x_unknown_linux_gnu=s390x-linux-gnu-g++ \ - OBJDUMP=s390x-linux-gnu-objdump diff --git a/third_party/rust/packed_simd/ci/docker/sparc64-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/sparc64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index c35f4d8f31..0000000000 --- a/third_party/rust/packed_simd/ci/docker/sparc64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM debian:bookworm - -RUN apt-get update && apt-get install -y --no-install-recommends \ - curl ca-certificates \ - gcc libc6-dev \ - gcc-sparc64-linux-gnu libc6-dev-sparc64-cross \ - qemu-system-sparc64 openbios-sparc seabios ipxe-qemu \ - p7zip-full cpio - -COPY linux-sparc64.sh / -RUN bash /linux-sparc64.sh - -COPY test-runner-linux / - -ENV CARGO_TARGET_SPARC64_UNKNOWN_LINUX_GNU_LINKER=sparc64-linux-gnu-gcc \ - CARGO_TARGET_SPARC64_UNKNOWN_LINUX_GNU_RUNNER="/test-runner-linux sparc64" \ - CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \ - PATH=$PATH:/rust/bin diff --git a/third_party/rust/packed_simd/ci/docker/thumbv7neon-linux-androideabi/Dockerfile b/third_party/rust/packed_simd/ci/docker/thumbv7neon-linux-androideabi/Dockerfile deleted file mode 100644 index c1da77109c..0000000000 --- a/third_party/rust/packed_simd/ci/docker/thumbv7neon-linux-androideabi/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -FROM ubuntu:16.04 - -RUN dpkg --add-architecture i386 && \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - file \ - make \ - curl \ - ca-certificates \ - python \ - unzip \ - expect \ - openjdk-9-jre \ - libstdc++6:i386 \ - libpulse0 \ - gcc \ - libc6-dev - -WORKDIR /android/ -COPY android* /android/ - -ENV ANDROID_ARCH=arm -ENV PATH=$PATH:/android/ndk-$ANDROID_ARCH/bin:/android/sdk/tools:/android/sdk/platform-tools - -RUN sh /android/android-install-ndk.sh $ANDROID_ARCH -RUN sh /android/android-install-sdk.sh $ANDROID_ARCH -RUN mv /root/.android /tmp -RUN chmod 777 -R /tmp/.android -RUN chmod 755 /android/sdk/tools/* /android/sdk/emulator/qemu/linux-x86_64/* - -ENV PATH=$PATH:/rust/bin \ - CARGO_TARGET_THUMBV7NEON_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \ - CARGO_TARGET_THUMBV7NEON_LINUX_ANDROIDEABI_RUNNER=/tmp/runtest \ - OBJDUMP=arm-linux-androideabi-objdump \ - HOME=/tmp - -ADD runtest-android.rs /tmp/runtest.rs -ENTRYPOINT [ \ - "bash", \ - "-c", \ - # set SHELL so android can detect a 64bits system, see - # http://stackoverflow.com/a/41789144 - "SHELL=/bin/dash /android/sdk/emulator/emulator @arm -no-window & \ - rustc /tmp/runtest.rs -o /tmp/runtest && \ - exec \"$@\"", \ - "--" \ -] diff --git a/third_party/rust/packed_simd/ci/docker/thumbv7neon-unknown-linux-gnueabihf/Dockerfile b/third_party/rust/packed_simd/ci/docker/thumbv7neon-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 588d23c65a..0000000000 --- a/third_party/rust/packed_simd/ci/docker/thumbv7neon-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - ca-certificates \ - libc6-dev \ - gcc-arm-linux-gnueabihf \ - libc6-dev-armhf-cross \ - qemu-user \ - make \ - file -ENV CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ - CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf" \ - OBJDUMP=arm-linux-gnueabihf-objdump diff --git a/third_party/rust/packed_simd/ci/docker/wasm32-unknown-unknown/Dockerfile b/third_party/rust/packed_simd/ci/docker/wasm32-unknown-unknown/Dockerfile deleted file mode 100644 index 51ee13e6c9..0000000000 --- a/third_party/rust/packed_simd/ci/docker/wasm32-unknown-unknown/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM ubuntu:22.04 - -RUN apt-get update -y && apt-get install -y --no-install-recommends \ - ca-certificates \ - clang \ - cmake \ - curl \ - git \ - libc6-dev \ - make \ - ninja-build \ - python-is-python3 \ - xz-utils - -# Install `wasm2wat` -RUN git clone --recursive https://github.com/WebAssembly/wabt -RUN make -C wabt -j$(nproc) -ENV PATH=$PATH:/wabt/bin - -# Install `wasm-bindgen-test-runner` -RUN curl -L https://github.com/rustwasm/wasm-bindgen/releases/download/0.2.87/wasm-bindgen-0.2.87-x86_64-unknown-linux-musl.tar.gz \ - | tar xzf - -# Keep in sync with the version on Cargo.toml. -ENV PATH=$PATH:/wasm-bindgen-0.2.87-x86_64-unknown-linux-musl -ENV CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasm-bindgen-test-runner - -# Install `node` -RUN curl https://nodejs.org/dist/v14.16.0/node-v14.16.0-linux-x64.tar.xz | tar xJf - -ENV PATH=$PATH:/node-v14.16.0-linux-x64/bin - -# We use a shim linker that removes `--strip-debug` when passed to LLD. While -# this typically results in invalid debug information in release mode it doesn't -# result in an invalid names section which is what we're interested in. -COPY lld-shim.rs / -ENV CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_LINKER=/tmp/lld-shim - -# Rustc isn't available until this container starts, so defer compilation of the -# shim. -ENTRYPOINT /rust/bin/rustc /lld-shim.rs -o /tmp/lld-shim && exec bash "$@" diff --git a/third_party/rust/packed_simd/ci/docker/x86_64-linux-android/Dockerfile b/third_party/rust/packed_simd/ci/docker/x86_64-linux-android/Dockerfile deleted file mode 100644 index 785936d347..0000000000 --- a/third_party/rust/packed_simd/ci/docker/x86_64-linux-android/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -FROM ubuntu:20.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - curl \ - gcc \ - libc-dev \ - python \ - unzip \ - file \ - make - -WORKDIR /android/ -ENV ANDROID_ARCH=x86_64 -COPY android-install-ndk.sh /android/ -RUN sh /android/android-install-ndk.sh - -ENV STDARCH_ASSERT_INSTR_LIMIT=30 - -# We do not run x86_64-linux-android tests on an android emulator. -# See ci/android-sysimage.sh for informations about how tests are run. -COPY android-sysimage.sh /android/ -RUN bash /android/android-sysimage.sh x86_64 x86_64-24_r07.zip - -ENV PATH=$PATH:/rust/bin:/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin \ - CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android21-clang \ - CC_x86_64_linux_android=x86_64-linux-android21-clang \ - CXX_x86_64_linux_android=x86_64-linux-android21-clang++ \ - OBJDUMP=llvm-objdump \ - HOME=/tmp diff --git a/third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu-emulated/Dockerfile b/third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu-emulated/Dockerfile deleted file mode 100644 index a6bbe66539..0000000000 --- a/third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu-emulated/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - libc6-dev \ - file \ - make \ - ca-certificates \ - wget \ - bzip2 \ - cmake \ - libclang-dev \ - clang - -RUN wget https://github.com/gnzlbg/intel_sde/raw/master/sde-external-8.16.0-2018-01-30-lin.tar.bz2 -RUN tar -xjf sde-external-8.16.0-2018-01-30-lin.tar.bz2 -ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/sde-external-8.16.0-2018-01-30-lin/sde64 --" diff --git a/third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index ce5bb88e62..0000000000 --- a/third_party/rust/packed_simd/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - libc6-dev \ - file \ - make \ - ca-certificates \ - cmake \ - libclang-dev \ - clang diff --git a/third_party/rust/packed_simd/ci/dox.sh b/third_party/rust/packed_simd/ci/dox.sh deleted file mode 100755 index 560eaadcc8..0000000000 --- a/third_party/rust/packed_simd/ci/dox.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -set -ex - -rm -rf target/doc -mkdir -p target/doc - -# Build API documentation -cargo doc --features=into_bits - -# Build Performance Guide -# FIXME: https://github.com/rust-lang-nursery/mdBook/issues/780 -# mdbook build perf-guide -d target/doc/perf-guide -cd perf-guide -mdbook build -cd - -cp -r perf-guide/book target/doc/perf-guide - -# If we're on travis, not a PR, and on the right branch, publish! -if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_BRANCH" = "master" ]; then - python3 -vV - pip -vV - python3.9 -vV - pip install ghp_import --user - ghp-import -n target/doc - git push -qf https://${GH_PAGES}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages -fi diff --git a/third_party/rust/packed_simd/ci/linux-s390x.sh b/third_party/rust/packed_simd/ci/linux-s390x.sh deleted file mode 100644 index 972abeec56..0000000000 --- a/third_party/rust/packed_simd/ci/linux-s390x.sh +++ /dev/null @@ -1,18 +0,0 @@ -set -ex - -mkdir -m 777 /qemu -cd /qemu - -curl -LO https://github.com/qemu/qemu/raw/master/pc-bios/s390-ccw.img -curl -LO http://ftp.debian.org/debian/dists/testing/main/installer-s390x/20170828/images/generic/kernel.debian -curl -LO http://ftp.debian.org/debian/dists/testing/main/installer-s390x/20170828/images/generic/initrd.debian - -mv kernel.debian kernel -mv initrd.debian initrd.gz - -mkdir init -cd init -gunzip -c ../initrd.gz | cpio -id -rm ../initrd.gz -cp /usr/s390x-linux-gnu/lib/libgcc_s.so.1 usr/lib/ -chmod a+w . diff --git a/third_party/rust/packed_simd/ci/linux-sparc64.sh b/third_party/rust/packed_simd/ci/linux-sparc64.sh deleted file mode 100644 index 4452b120e1..0000000000 --- a/third_party/rust/packed_simd/ci/linux-sparc64.sh +++ /dev/null @@ -1,17 +0,0 @@ -set -ex - -mkdir -m 777 /qemu -cd /qemu - -curl -LO https://cdimage.debian.org/cdimage/ports/9.0/sparc64/iso-cd/debian-9.0-sparc64-NETINST-1.iso -7z e debian-9.0-sparc64-NETINST-1.iso boot/initrd.gz -7z e debian-9.0-sparc64-NETINST-1.iso boot/sparc64 -mv sparc64 kernel -rm debian-9.0-sparc64-NETINST-1.iso - -mkdir init -cd init -gunzip -c ../initrd.gz | cpio -id -rm ../initrd.gz -cp /usr/sparc64-linux-gnu/lib/libgcc_s.so.1 usr/lib/ -chmod a+w . diff --git a/third_party/rust/packed_simd/ci/lld-shim.rs b/third_party/rust/packed_simd/ci/lld-shim.rs deleted file mode 100644 index 10263869e8..0000000000 --- a/third_party/rust/packed_simd/ci/lld-shim.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::os::unix::prelude::*; -use std::process::Command; -use std::env; - -fn main() { - let args = env::args() - .skip(1) - .filter(|s| s != "--strip-debug") - .collect::>(); - panic!("failed to exec: {}", Command::new("rust-lld").args(&args).exec()); -} diff --git a/third_party/rust/packed_simd/ci/max_line_width.sh b/third_party/rust/packed_simd/ci/max_line_width.sh deleted file mode 100755 index f70639b6f8..0000000000 --- a/third_party/rust/packed_simd/ci/max_line_width.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env sh - -set -x - -export success=true - -find . -iname '*.rs' | while read -r file; do - result=$(grep '.\{79\}' "${file}" | grep --invert 'http') - if [ "${result}" = "" ] - then - : - else - echo "file \"${file}\": $result" - exit 1 - fi -done - diff --git a/third_party/rust/packed_simd/ci/run-docker.sh b/third_party/rust/packed_simd/ci/run-docker.sh deleted file mode 100755 index abdd6852fc..0000000000 --- a/third_party/rust/packed_simd/ci/run-docker.sh +++ /dev/null @@ -1,38 +0,0 @@ -# Small script to run tests for a target (or all targets) inside all the -# respective docker images. - -set -ex - -run() { - echo "Building docker container for TARGET=${TARGET} RUSTFLAGS=${RUSTFLAGS}" - docker build -t packed_simd -f ci/docker/${TARGET}/Dockerfile ci/ - mkdir -p target - target=$(echo "${TARGET}" | sed 's/-emulated//') - echo "Running docker" - docker run \ - --user `id -u`:`id -g` \ - --rm \ - --init \ - --volume $HOME/.cargo:/cargo \ - --env CARGO_HOME=/cargo \ - --volume `rustc --print sysroot`:/rust:ro \ - --env TARGET=$target \ - --env NORUN \ - --env NOVERIFY \ - --env RUSTFLAGS \ - --volume `pwd`:/checkout:ro \ - --volume `pwd`/target:/checkout/target \ - --workdir /checkout \ - --privileged \ - packed_simd \ - bash \ - -c 'PATH=$PATH:/rust/bin exec ci/run.sh' -} - -if [ -z "${TARGET}" ]; then - for d in `ls ci/docker/`; do - run $d - done -else - run ${TARGET} -fi diff --git a/third_party/rust/packed_simd/ci/run.sh b/third_party/rust/packed_simd/ci/run.sh deleted file mode 100755 index b1b22ebd7c..0000000000 --- a/third_party/rust/packed_simd/ci/run.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -: ${TARGET?"The TARGET environment variable must be set."} - -# Tests are all super fast anyway, and they fault often enough on travis that -# having only one thread increases debuggability to be worth it. -#export RUST_TEST_THREADS=1 -#export RUST_BACKTRACE=full -#export RUST_TEST_NOCAPTURE=1 - -# Some appveyor builds run out-of-memory; this attempts to mitigate that: -# https://github.com/rust-lang-nursery/packed_simd/issues/39 -# export RUSTFLAGS="${RUSTFLAGS} -C codegen-units=1" -# export CARGO_BUILD_JOBS=1 - -export CARGO_SUBCMD=test -if [[ "${NORUN}" == "1" ]]; then - export CARGO_SUBCMD=build -fi - -if [[ ${TARGET} == "x86_64-apple-ios" ]] || [[ ${TARGET} == "i386-apple-ios" ]]; then - export RUSTFLAGS="${RUSTFLAGS} -Clink-arg=-mios-simulator-version-min=7.0" - rustc ./ci/deploy_and_run_on_ios_simulator.rs -o $HOME/runtest - export CARGO_TARGET_X86_64_APPLE_IOS_RUNNER=$HOME/runtest - export CARGO_TARGET_I386_APPLE_IOS_RUNNER=$HOME/runtest -fi - -# The source directory is read-only. Need to copy internal crates to the target -# directory for their Cargo.lock to be properly written. -mkdir target || true - -rustc --version -cargo --version -echo "TARGET=${TARGET}" -echo "HOST=${HOST}" -echo "RUSTFLAGS=${RUSTFLAGS}" -echo "NORUN=${NORUN}" -echo "NOVERIFY=${NOVERIFY}" -echo "CARGO_SUBCMD=${CARGO_SUBCMD}" -echo "CARGO_BUILD_JOBS=${CARGO_BUILD_JOBS}" -echo "CARGO_INCREMENTAL=${CARGO_INCREMENTAL}" -echo "RUST_TEST_THREADS=${RUST_TEST_THREADS}" -echo "RUST_BACKTRACE=${RUST_BACKTRACE}" -echo "RUST_TEST_NOCAPTURE=${RUST_TEST_NOCAPTURE}" - -cargo_test() { - cmd="cargo ${CARGO_SUBCMD} --verbose --target=${TARGET} ${@}" - if [ "${NORUN}" != "1" ] - then - if [ "$TARGET" != "wasm32-unknown-unknown" ] - then - cmd="$cmd -- --quiet" - fi - fi - mkdir target || true - ${cmd} 2>&1 | tee > target/output - if [[ ${PIPESTATUS[0]} != 0 ]]; then - cat target/output - return 1 - fi -} - -cargo_test_impl() { - ORIGINAL_RUSTFLAGS=${RUSTFLAGS} - RUSTFLAGS="${ORIGINAL_RUSTFLAGS} --cfg test_v16 --cfg test_v32 --cfg test_v64" cargo_test ${@} - RUSTFLAGS="${ORIGINAL_RUSTFLAGS} --cfg test_v128 --cfg test_v256" cargo_test ${@} - RUSTFLAGS="${ORIGINAL_RUSTFLAGS} --cfg test_v512" cargo_test ${@} - RUSTFLAGS=${ORIGINAL_RUSTFLAGS} -} - -# Debug run: -if [[ "${TARGET}" != "wasm32-unknown-unknown" ]]; then - # Run wasm32-unknown-unknown in release mode only - cargo_test_impl -fi - -if [[ "${TARGET}" == "x86_64-unknown-linux-gnu" ]] || [[ "${TARGET}" == "x86_64-pc-windows-msvc" ]]; then - # use sleef on linux and windows x86_64 builds - # FIXME: Use `core_arch,sleef-sys` features once they works again - cargo_test_impl --release --features=into_bits -else - # FIXME: Use `core_arch` feature once it works again - cargo_test_impl --release --features=into_bits -fi - -# Verify code generation -if [[ "${NOVERIFY}" != "1" ]]; then - cp -r verify/verify target/verify - export STDSIMD_ASSERT_INSTR_LIMIT=30 - if [[ "${TARGET}" == "i586-unknown-linux-gnu" ]]; then - export STDSIMD_ASSERT_INSTR_LIMIT=50 - fi - cargo_test --release --manifest-path=target/verify/Cargo.toml -fi - -# FIXME: Figure out which examples take too long to run and ignore or adjust those -#. ci/run_examples.sh diff --git a/third_party/rust/packed_simd/ci/run_examples.sh b/third_party/rust/packed_simd/ci/run_examples.sh deleted file mode 100644 index 5b26b18afb..0000000000 --- a/third_party/rust/packed_simd/ci/run_examples.sh +++ /dev/null @@ -1,51 +0,0 @@ -# Runs all examples. - -# FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/55 -# All examples fail to build for `armv7-apple-ios`. -if [[ ${TARGET} == "armv7-apple-ios" ]]; then - exit 0 -fi - -# FIXME: travis exceeds 50 minutes on these targets -# Skipping the examples is an attempt at preventing travis from timing-out -if [[ ${TARGET} == "arm-linux-androidabi" ]] || [[ ${TARGET} == "aarch64-linux-androidabi" ]] \ - || [[ ${TARGET} == "sparc64-unknown-linux-gnu" ]]; then - exit 0 -fi - -if [[ ${TARGET} == "wasm32-unknown-unknown" ]]; then - exit 0 -fi - -cp -r examples/aobench target/aobench -cargo_test --manifest-path=target/aobench/Cargo.toml --release --no-default-features -cargo_test --manifest-path=target/aobench/Cargo.toml --release --features=256bit - -cp -r examples/dot_product target/dot_product -cargo_test --manifest-path=target/dot_product/Cargo.toml --release - -cp -r examples/fannkuch_redux target/fannkuch_redux -cargo_test --manifest-path=target/fannkuch_redux/Cargo.toml --release - -# FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/56 -if [[ ${TARGET} != "i586-unknown-linux-gnu" ]]; then - cp -r examples/mandelbrot target/mandelbrot - cargo_test --manifest-path=target/mandelbrot/Cargo.toml --release -fi - -cp -r examples/matrix_inverse target/matrix_inverse -cargo_test --manifest-path=target/matrix_inverse/Cargo.toml --release - -cp -r examples/nbody target/nbody -cargo_test --manifest-path=target/nbody/Cargo.toml --release - -cp -r examples/spectral_norm target/spectral_norm -cargo_test --manifest-path=target/spectral_norm/Cargo.toml --release - -if [[ ${TARGET} != "i586-unknown-linux-gnu" ]]; then - cp -r examples/stencil target/stencil - cargo_test --manifest-path=target/stencil/Cargo.toml --release -fi - -cp -r examples/triangle_xform target/triangle_xform -cargo_test --manifest-path=target/triangle_xform/Cargo.toml --release diff --git a/third_party/rust/packed_simd/ci/runtest-android.rs b/third_party/rust/packed_simd/ci/runtest-android.rs deleted file mode 100644 index ed1cd80c83..0000000000 --- a/third_party/rust/packed_simd/ci/runtest-android.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::env; -use std::process::Command; -use std::path::{Path, PathBuf}; - -fn main() { - let args = env::args_os() - .skip(1) - .filter(|arg| arg != "--quiet") - .collect::>(); - assert_eq!(args.len(), 1); - let test = PathBuf::from(&args[0]); - let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap()); - - let status = Command::new("adb") - .arg("wait-for-device") - .status() - .expect("failed to run: adb wait-for-device"); - assert!(status.success()); - - let status = Command::new("adb") - .arg("push") - .arg(&test) - .arg(&dst) - .status() - .expect("failed to run: adb pushr"); - assert!(status.success()); - - let output = Command::new("adb") - .arg("shell") - .arg(&dst) - .output() - .expect("failed to run: adb shell"); - assert!(status.success()); - - println!("status: {}\nstdout ---\n{}\nstderr ---\n{}", - output.status, - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr)); - - let stdout = String::from_utf8_lossy(&output.stdout); - let mut lines = stdout.lines().filter(|l| l.starts_with("test result")); - if !lines.all(|l| l.contains("test result: ok") && l.contains("0 failed")) { - panic!("failed to find successful test run"); - } -} diff --git a/third_party/rust/packed_simd/ci/setup_benchmarks.sh b/third_party/rust/packed_simd/ci/setup_benchmarks.sh deleted file mode 100755 index cd41a78513..0000000000 --- a/third_party/rust/packed_simd/ci/setup_benchmarks.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -# Get latest ISPC binary for the target and put it in the path -git clone https://github.com/gnzlbg/ispc-binaries -cp ispc-binaries/ispc-${TARGET} ispc diff --git a/third_party/rust/packed_simd/ci/test-runner-linux b/third_party/rust/packed_simd/ci/test-runner-linux deleted file mode 100755 index 0654f63bfd..0000000000 --- a/third_party/rust/packed_simd/ci/test-runner-linux +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -set -e - -arch=$1 -prog=$2 - -cd /qemu/init -cp -f $2 prog -find . | cpio --create --format='newc' --quiet | gzip > ../initrd.gz -cd .. - -timeout 30s qemu-system-$arch \ - -m 1024 \ - -nographic \ - -kernel kernel \ - -initrd initrd.gz \ - -append init=/prog > output || true - -# remove kernel messages -tr -d '\r' < output | egrep -v '^\[' - -# if the output contains a failure, return error -! grep FAILED output > /dev/null diff --git a/third_party/rust/packed_simd/contributing.md b/third_party/rust/packed_simd/contributing.md deleted file mode 100644 index 79af8c199e..0000000000 --- a/third_party/rust/packed_simd/contributing.md +++ /dev/null @@ -1,67 +0,0 @@ -# Contributing to `packed_simd` - -Welcome! If you are reading this document, it means you are interested in contributing -to the `packed_simd` crate. - -## Reporting issues - -All issues with this crate are tracked using GitHub's [Issue Tracker]. - -You can use issues to bring bugs to the attention of the maintainers, to discuss -certain problems encountered with the crate, or to request new features (although -feature requests should be limited to things mentioned in the [RFC]). - -One thing to keep in mind is to always use the **latest** nightly toolchain when -working on this crate. Due to the nature of this project, we use a lot of unstable -features, meaning breakage happens often. - -[Issue Tracker]: https://github.com/rust-lang-nursery/packed_simd/issues -[RFC]: https://github.com/rust-lang/rfcs/pull/2366 - -### LLVM issues - -The Rust compiler relies on [LLVM](https://llvm.org/) for machine code generation, -and quite a few LLVM bugs have been discovered during the development of this project. - -If you encounter issues with incorrect/suboptimal codegen, which you do not encounter -when using the [SIMD vendor intrinsics](https://doc.rust-lang.org/nightly/std/arch/), -it is likely the issue is with LLVM, or this crate's interaction with it. - -You should first open an issue **in this repo** to help us track the problem, and we -will help determine what is the exact cause of the problem. -If LLVM is indeed the cause, the issue will be reported upstream to the -[LLVM bugtracker](https://bugs.llvm.org/). - -## Submitting Pull Requests - -New code is submitted to the crate using GitHub's [pull request] mechanism. -You should first fork this repository, make your changes (preferably in a new -branch), then use GitHub's web UI to create a new PR. - -[pull request]: https://help.github.com/articles/about-pull-requests/ - -### Examples - -The `examples` directory contains code showcasing SIMD code written with this crate, -usually in comparison to scalar or ISPC code. If you have a project / idea which -uses SIMD, we'd love to add it to the examples list. - -Every example should include a small `README`, describing the example code's purpose. -If your example could potentially work as a benchmark, then add a `benchmark.sh` -script to allow running the example benchmark code in CI. See an existing example's -[`benchmark.sh`](examples/aobench/benchmark.sh) for a sample. - -Don't forget to update the crate's top-level `README` with a link to your example. - -### Perf guide - -The objective of the [performance guide][perf-guide] is to be a comprehensive -resource detailing the process of optimizing Rust code with SIMD support. - -If you believe a certain section could be reworded, or if you have any tips & tricks -related to SIMD which you'd like to share, please open a PR. - -[mdBook] is used to manage the formatting of the guide as a book. - -[perf-guide]: https://rust-lang-nursery.github.io/packed_simd/perf-guide/ -[mdBook]: https://github.com/rust-lang-nursery/mdBook diff --git a/third_party/rust/packed_simd/perf-guide/book.toml b/third_party/rust/packed_simd/perf-guide/book.toml deleted file mode 100644 index 69ba3053ca..0000000000 --- a/third_party/rust/packed_simd/perf-guide/book.toml +++ /dev/null @@ -1,12 +0,0 @@ -[book] -authors = ["Gonzalo Brito Gadeschi", "Gabriel Majeri"] -multilingual = false -src = "src" -title = "Rust SIMD Performance Guide" -description = "This book describes how to write performant SIMD code in Rust." - -[build] -create-missing = false - -[output.html] -additional-css = ["./src/ascii.css"] diff --git a/third_party/rust/packed_simd/perf-guide/src/SUMMARY.md b/third_party/rust/packed_simd/perf-guide/src/SUMMARY.md deleted file mode 100644 index 1e76898865..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/SUMMARY.md +++ /dev/null @@ -1,21 +0,0 @@ -# Summary - -[Introduction](./introduction.md) - -- [Floating-point Math](./float-math/fp.md) - - [Short-vector Math Library](./float-math/svml.md) - - [Approximate functions](./float-math/approx.md) - - [Fused multiply-accumulate](./float-math/fma.md) - -- [Target features](./target-feature/features.md) - - [Using `RUSTFLAGS`](./target-feature/rustflags.md) - - [Using the `target_feature` attribute](./target-feature/attribute.md) - - [Interaction with inlining](./target-feature/inlining.md) - - [Detecting features at runtime](./target-feature/runtime.md) - -- [Bounds checking](./bound_checks.md) -- [Vertical and horizontal operations](./vert-hor-ops.md) - -- [Performance profiling](./prof/profiling.md) - - [Profiling on Linux](./prof/linux.md) - - [Using machine code analyzers](./prof/mca.md) diff --git a/third_party/rust/packed_simd/perf-guide/src/ascii.css b/third_party/rust/packed_simd/perf-guide/src/ascii.css deleted file mode 100644 index 4c02651195..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/ascii.css +++ /dev/null @@ -1,4 +0,0 @@ -code { - /* "Source Code Pro" breaks ASCII art */ - font-family: Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace; -} diff --git a/third_party/rust/packed_simd/perf-guide/src/bound_checks.md b/third_party/rust/packed_simd/perf-guide/src/bound_checks.md deleted file mode 100644 index 2eeedb5ac8..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/bound_checks.md +++ /dev/null @@ -1,22 +0,0 @@ -# Bounds checking - -Reading and writing packed vectors to/from slices is checked by default. -Independently of the configuration options used, the safe functions: - -* `Simd<[T; N]>::from_slice_aligned(& s[..])` -* `Simd<[T; N]>::write_to_slice_aligned(&mut s[..])` - -always check that: - -* the slice is big enough to hold the vector -* the slice is suitably aligned to perform an aligned load/store for a `Simd<[T; - N]>` (this alignment is often much larger than that of `T`). - -There are `_unaligned` versions that use unaligned load and stores, as well as -`unsafe` `_unchecked` that do not perform any checks iff `debug-assertions = -false` / `debug = false`. That is, the `_unchecked` methods do still assert size -and alignment in debug builds and could also do so in release builds depending -on the configuration options. - -These assertions do often significantly impact performance and you should be -aware of them. diff --git a/third_party/rust/packed_simd/perf-guide/src/float-math/approx.md b/third_party/rust/packed_simd/perf-guide/src/float-math/approx.md deleted file mode 100644 index 2237c67ec4..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/float-math/approx.md +++ /dev/null @@ -1,8 +0,0 @@ -# Approximate functions - - diff --git a/third_party/rust/packed_simd/perf-guide/src/float-math/fma.md b/third_party/rust/packed_simd/perf-guide/src/float-math/fma.md deleted file mode 100644 index 357748383d..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/float-math/fma.md +++ /dev/null @@ -1,6 +0,0 @@ -# Fused Multiply Add - - diff --git a/third_party/rust/packed_simd/perf-guide/src/float-math/fp.md b/third_party/rust/packed_simd/perf-guide/src/float-math/fp.md deleted file mode 100644 index 711fcc4fd5..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/float-math/fp.md +++ /dev/null @@ -1,3 +0,0 @@ -# Floating-point math - -This chapter contains information pertaining to working with floating-point numbers. diff --git a/third_party/rust/packed_simd/perf-guide/src/float-math/svml.md b/third_party/rust/packed_simd/perf-guide/src/float-math/svml.md deleted file mode 100644 index 266c2531cc..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/float-math/svml.md +++ /dev/null @@ -1,7 +0,0 @@ -# Short Vector Math Library - - diff --git a/third_party/rust/packed_simd/perf-guide/src/introduction.md b/third_party/rust/packed_simd/perf-guide/src/introduction.md deleted file mode 100644 index 7243e19c8a..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/introduction.md +++ /dev/null @@ -1,26 +0,0 @@ -# Introduction - -## What is SIMD - - - -## History of SIMD in Rust - - - -## Discover packed_simd - - - -Writing fast and portable SIMD algorithms using `packed_simd` is, unfortunately, -not trivial. There are many pitfals that one should be aware of, and some idioms -that help avoid those pitfalls. - -This book attempts to document these best practices and provides practical examples -on how to apply the tips to _your_ code. diff --git a/third_party/rust/packed_simd/perf-guide/src/prof/linux.md b/third_party/rust/packed_simd/perf-guide/src/prof/linux.md deleted file mode 100644 index 96c7d67bc4..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/prof/linux.md +++ /dev/null @@ -1,107 +0,0 @@ -# Performance profiling on Linux - -## Using `perf` - -[perf](https://perf.wiki.kernel.org/) is the most powerful performance profiler -for Linux, featuring support for various hardware Performance Monitoring Units, -as well as integration with the kernel's performance events framework. - -We will only look at how can the `perf` command can be used to profile SIMD code. -Full system profiling is outside of the scope of this book. - -### Recording - -The first step is to record a program's execution during an average workload. -It helps if you can isolate the parts of your program which have performance -issues, and set up a benchmark which can be easily (re)run. - -Build the benchmark binary in release mode, after having enabled debug info: - -```sh -$ cargo build --release -Finished release [optimized + debuginfo] target(s) in 0.02s -``` - -Then use the `perf record` subcommand: - -```sh -$ perf record --call-graph=dwarf ./target/release/my-program -[ perf record: Woken up 10 times to write data ] -[ perf record: Captured and wrote 2,356 MB perf.data (292 samples) ] -``` - -Instead of using `--call-graph=dwarf`, which can become pretty slow, you can use -`--call-graph=lbr` if you have a processor with support for Last Branch Record -(i.e. Intel Haswell and newer). - -`perf` will, by default, record the count of CPU cycles it takes to execute -various parts of your program. You can use the `-e` command line option -to enable other performance events, such as `cache-misses`. Use `perf list` -to get a list of all hardware counters supported by your CPU. - -### Viewing the report - -The next step is getting a bird's eye view of the program's execution. -`perf` provides a `ncurses`-based interface which will get you started. - -Use `perf report` to open a visualization of your program's performance: - -```sh -perf report --hierarchy -M intel -``` - -`--hierarchy` will display a tree-like structure of where your program spent -most of its time. `-M intel` enables disassembly output with Intel syntax, which -is subjectively more readable than the default AT&T syntax. - -Here is the output from profiling the `nbody` benchmark: - -``` -- 100,00% nbody - - 94,18% nbody - + 93,48% [.] nbody_lib::simd::advance - + 0,70% [.] nbody_lib::run - + 5,06% libc-2.28.so -``` - -If you move with the arrow keys to any node in the tree, you can the press `a` -to have `perf` _annotate_ that node. This means it will: - -- disassemble the function - -- associate every instruction with the percentage of time which was spent executing it - -- interleaves the disassembly with the source code, - assuming it found the debug symbols - (you can use `s` to toggle this behaviour) - -`perf` will, by default, open the instruction which it identified as being the -hottest spot in the function: - -``` -0,76 │ movapd xmm2,xmm0 -0,38 │ movhlps xmm2,xmm0 - │ addpd xmm2,xmm0 - │ unpcklpd xmm1,xmm2 -12,50 │ sqrtpd xmm0,xmm1 -1,52 │ mulpd xmm0,xmm1 -``` - -In this case, `sqrtpd` will be highlighted in red, since that's the instruction -which the CPU spends most of its time executing. - -## Using Valgrind - -Valgrind is a set of tools which initially helped C/C++ programmers find unsafe -memory accesses in their code. Nowadays the project also has - -- a heap profiler called `massif` - -- a cache utilization profiler called `cachegrind` - -- a call-graph performance profiler called `callgrind` - - diff --git a/third_party/rust/packed_simd/perf-guide/src/prof/mca.md b/third_party/rust/packed_simd/perf-guide/src/prof/mca.md deleted file mode 100644 index 65ddf1a4eb..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/prof/mca.md +++ /dev/null @@ -1,100 +0,0 @@ -# Machine code analysis tools - -## The microarchitecture of modern CPUs - -While you might have heard of Instruction Set Architectures, such as `x86` or -`arm` or `mips`, the term _microarchitecture_ (also written here as _µ-arch_), -refers to the internal details of an actual family of CPUs, such as Intel's -_Haswell_ or AMD's _Jaguar_. - -Replacing scalar code with SIMD code will improve performance on all CPUs -supporting the required vector extensions. -However, due to microarchitectural differences, the actual speed-up at -runtime might vary. - -**Example**: a simple example arises when optimizing for AMD K8 CPUs. -The assembly generated for an empty function should look like this: - -```asm -nop -ret -``` - -The `nop` is used to align the `ret` instruction for better performance. -However, the compiler will actually generated the following code: - -```asm -repz ret -``` - -The `repz` instruction will repeat the following instruction until a certain -condition. Of course, in this situation, the function will simply immediately -return, and the `ret` instruction is still aligned. -However, AMD K8's branch predictor performs better with the latter code. - -For those looking to absolutely maximize performance for a certain target µ-arch, -you will have to read some CPU manuals, or ask the compiler to do it for you -with `-C target-cpu`. - -### Summary of CPU internals - -Modern processors are able to execute instructions out-of-order for better performance, -by utilizing tricks such as [branch prediction], [instruction pipelining], -or [superscalar execution]. - -[branch prediction]: https://en.wikipedia.org/wiki/Branch_predictor -[instruction pipelining]: https://en.wikipedia.org/wiki/Instruction_pipelining -[superscalar execution]: https://en.wikipedia.org/wiki/Superscalar_processor - -SIMD instructions are also subject to these optimizations, meaning it can get pretty -difficult to determine where the slowdown happens. -For example, if the profiler reports a store operation is slow, one of two things -could be happening: - -- the store is limited by the CPU's memory bandwidth, which is actually an ideal - scenario, all things considered; - -- memory bandwidth is nowhere near its peak, but the value to be stored is at the - end of a long chain of operations, and this store is where the profiler - encountered the pipeline stall; - -Since most profilers are simple tools which don't understand the subtleties of -instruction scheduling, you - -## Analyzing the machine code - -Certain tools have knowledge of internal CPU microarchitecture, i.e. they know - -- how many physical [register files] a CPU actually has - -- what is the latency / throughtput of an instruction - -- what [µ-ops] are generated for a set of instructions - -and many other architectural details. - -[register files]: https://en.wikipedia.org/wiki/Register_file -[µ-ops]: https://en.wikipedia.org/wiki/Micro-operation - -These tools are therefore able to provide accurate information as to why some -instructions are inefficient, and where the bottleneck is. - -The disadvantage is that the output of these tools requires advanced knowledge -of the target architecture to understand, i.e. they **cannot** point out what -the cause of the issue is explicitly. - -## Intel's Architecture Code Analyzer (IACA) - -[IACA] is a free tool offered by Intel for analyzing the performance of various -computational kernels. - -Being a proprietary, closed source tool, it _only_ supports Intel's µ-arches. - -[IACA]: https://software.intel.com/en-us/articles/intel-architecture-code-analyzer - -## llvm-mca - - diff --git a/third_party/rust/packed_simd/perf-guide/src/prof/profiling.md b/third_party/rust/packed_simd/perf-guide/src/prof/profiling.md deleted file mode 100644 index 02ba78d2f2..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/prof/profiling.md +++ /dev/null @@ -1,14 +0,0 @@ -# Performance profiling - -While the rest of the book provides practical advice on how to improve the performance -of SIMD code, this chapter is dedicated to [**performance profiling**][profiling]. -Profiling consists of recording a program's execution in order to identify program -hotspots. - -**Important**: most profilers require debug information in order to accurately -link the program hotspots back to the corresponding source code lines. Rust will -disable debug info generation by default for optimized builds, but you can change -that [in your `Cargo.toml`][cargo-ref]. - -[profiling]: https://en.wikipedia.org/wiki/Profiling_(computer_programming) -[cargo-ref]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-profile-sections diff --git a/third_party/rust/packed_simd/perf-guide/src/target-feature/attribute.md b/third_party/rust/packed_simd/perf-guide/src/target-feature/attribute.md deleted file mode 100644 index ee670fea5b..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/target-feature/attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -# The `target_feature` attribute - - diff --git a/third_party/rust/packed_simd/perf-guide/src/target-feature/features.md b/third_party/rust/packed_simd/perf-guide/src/target-feature/features.md deleted file mode 100644 index b93030ca67..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/target-feature/features.md +++ /dev/null @@ -1,13 +0,0 @@ -# Enabling target features - -Not all processors of a certain architecture will have SIMD processing units, -and using a SIMD instruction which is not supported will trigger undefined behavior. - -To allow building safe, portable programs, the Rust compiler will **not**, by default, -generate any sort of vector instructions, unless it can statically determine -they are supported. For example, on AMD64, SSE2 support is architecturally guaranteed. -The `x86_64-apple-darwin` target enables up to SSSE3. The get a defintive list of -which features are enabled by default on various platforms, refer to the target -specifications [in the compiler's source code][targets]. - -[targets]: https://github.com/rust-lang/rust/tree/master/src/librustc_target/spec diff --git a/third_party/rust/packed_simd/perf-guide/src/target-feature/inlining.md b/third_party/rust/packed_simd/perf-guide/src/target-feature/inlining.md deleted file mode 100644 index 86705102a7..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/target-feature/inlining.md +++ /dev/null @@ -1,5 +0,0 @@ -# Inlining - - diff --git a/third_party/rust/packed_simd/perf-guide/src/target-feature/practice.md b/third_party/rust/packed_simd/perf-guide/src/target-feature/practice.md deleted file mode 100644 index 5b55c61c26..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/target-feature/practice.md +++ /dev/null @@ -1,31 +0,0 @@ -# Target features in practice - -Using `RUSTFLAGS` will allow the crate being compiled, as well as all its -transitive dependencies to use certain target features. - -A tehnique used to avoid undefined behavior at runtime is to compile and -ship multiple binaries, each compiled with a certain set of features. -This might not be feasible in some cases, and can quickly get out of hand -as more and more vector extensions are added to an architecture. - -Rust can be more flexible: you can build a single binary/library which automatically -picks the best supported vector instructions depending on the host machine. -The trick consists of monomorphizing parts of the code during building, and then -using run-time feature detection to select the right code path when running. - - - -**NOTE** (x86 specific): because the AVX (256-bit) registers extend the existing -SSE (128-bit) registers, mixing SSE and AVX instructions in a program can cause -performance issues. - -The solution is to compile all code, even the code written with 128-bit vectors, -with the AVX target feature enabled. This will cause the compiler to prefix the -generated instructions with the [VEX] prefix. - -[VEX]: https://en.wikipedia.org/wiki/VEX_prefix diff --git a/third_party/rust/packed_simd/perf-guide/src/target-feature/runtime.md b/third_party/rust/packed_simd/perf-guide/src/target-feature/runtime.md deleted file mode 100644 index 47ddcc8660..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/target-feature/runtime.md +++ /dev/null @@ -1,5 +0,0 @@ -# Detecting host features at runtime - - diff --git a/third_party/rust/packed_simd/perf-guide/src/target-feature/rustflags.md b/third_party/rust/packed_simd/perf-guide/src/target-feature/rustflags.md deleted file mode 100644 index f4c1d1304a..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/target-feature/rustflags.md +++ /dev/null @@ -1,77 +0,0 @@ -# Using RUSTFLAGS - -One of the easiest ways to benefit from SIMD is to allow the compiler -to generate code using certain vector instruction extensions. - -The environment variable `RUSTFLAGS` can be used to pass options for code -generation to the Rust compiler. These flags will affect **all** compiled crates. - -There are two flags which can be used to enable specific vector extensions: - -## target-feature - -- Syntax: `-C target-feature=` - -- Provides the compiler with a comma-separated set of instruction extensions - to enable. - - **Example**: Use `-C target-feature=+sse3,+avx` to enable generating instructions - for [Streaming SIMD Extensions 3](https://en.wikipedia.org/wiki/SSE3) and - [Advanced Vector Extensions](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions). - -- To list target triples for all targets supported by Rust, use: - - ```sh - rustc --print target-list - ``` - -- To list all support target features for a certain target triple, use: - - ```sh - rustc --target=${TRIPLE} --print target-features - ``` - -- Note that all CPU features are independent, and will have to be enabled individually. - - **Example**: Setting `-C target-feature=+avx2` will _not_ enable `fma`, even though - all CPUs which support AVX2 also support FMA. To enable both, one has to use - `-C target-feature=+avx2,+fma` - -- Some features also depend on other features, which need to be enabled for the - target instructions to be generated. - - **Example**: Unless `v7` is specified as the target CPU (see below), to enable - NEON on ARM it is necessary to use `-C target-feature=+v7,+neon`. - -## target-cpu - -- Syntax: `-C target-cpu=` - -- Sets the identifier of a CPU family / model for which to build and optimize the code. - - **Example**: `RUSTFLAGS='-C target-cpu=cortex-a75'` - -- To list all supported target CPUs for a certain target triple, use: - - ```sh - rustc --target=${TRIPLE} --print target-cpus - ``` - - **Example**: - - ```sh - rustc --target=i686-pc-windows-msvc --print target-cpus - ``` - -- The compiler will translate this into a list of target features. Therefore, - individual feature checks (`#[cfg(target_feature = "...")]`) will still - work properly. - -- It will cause the code generator to optimize the generated code for that - specific CPU model. - -- Using `native` as the CPU model will cause Rust to generate and optimize code - for the CPU running the compiler. It is useful when building programs which you - plan to only use locally. This should never be used when the generated programs - are meant to be run on other computers, such as when packaging for distribution - or cross-compiling. diff --git a/third_party/rust/packed_simd/perf-guide/src/vert-hor-ops.md b/third_party/rust/packed_simd/perf-guide/src/vert-hor-ops.md deleted file mode 100644 index d0dd1be12a..0000000000 --- a/third_party/rust/packed_simd/perf-guide/src/vert-hor-ops.md +++ /dev/null @@ -1,76 +0,0 @@ -# Vertical and horizontal operations - -In SIMD terminology, each vector has a certain "width" (number of lanes). -A vector processor is able to perform two kinds of operations on a vector: - -- Vertical operations: - operate on two vectors of the same width, result has same width - -**Example**: vertical addition of two `f32x4` vectors - - %0 == | 2 | -3.5 | 0 | 7 | - + + + + - %1 == | 4 | 1.5 | -1 | 0 | - = = = = - %0 + %1 == | 6 | -2 | -1 | 7 | - -- Horizontal operations: - reduce the elements of two vectors in some way, - the result's elements combine information from the two original ones - -**Example**: horizontal addition of two `u64x2` vectors - - %0 == | 1 | 3 | - └─+───┘ - └───────┐ - │ - %1 == | 4 | -1 | │ - └─+──┘ │ - └───┐ │ - │ │ - ┌─────│───┘ - ▼ ▼ - %0 + %1 == | 4 | 3 | - -## Performance consideration of horizontal operations - -The result of vertical operations, like vector negation: `-a`, for a given lane, -does not depend on the result of the operation for the other lanes. The result -of horizontal operations, like the vector `sum` reduction: `a.sum()`, depends on -the value of all vector lanes. - -In virtually all architectures vertical operations are fast, while horizontal -operations are, by comparison, very slow. - -Consider the following two functions for computing the sum of all `f32` values -in a slice: - -```rust -fn fast_sum(x: &[f32]) -> f32 { - assert!(x.len() % 4 == 0); - let mut sum = f32x4::splat(0.); // [0., 0., 0., 0.] - for i in (0..x.len()).step_by(4) { - sum += f32x4::from_slice_unaligned(&x[i..]); - } - sum.sum() -} - -fn slow_sum(x: &[f32]) -> f32 { - assert!(x.len() % 4 == 0); - let mut sum: f32 = 0.; - for i in (0..x.len()).step_by(4) { - sum += f32x4::from_slice_unaligned(&x[i..]).sum(); - } - sum -} -``` - -The inner loop over the slice is where the bulk of the work actually happens. -There, the `fast_sum` function perform vertical operations into a vector, doing -a single horizontal reduction at the end, while the `slow_sum` function performs -horizontal vector operations inside of the loop. - -On all widely-used architectures, `fast_sum` is a large constant factor faster -than `slow_sum`. You can run the [slice_sum]() example and see for yourself. On -the particular machine tested there the algorithm using the horizontal vector -addition is 2.7x slower than the one using vertical vector operations! diff --git a/third_party/rust/packed_simd/rust-toolchain b/third_party/rust/packed_simd/rust-toolchain deleted file mode 100644 index bf867e0ae5..0000000000 --- a/third_party/rust/packed_simd/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly diff --git a/third_party/rust/packed_simd/rustfmt.toml b/third_party/rust/packed_simd/rustfmt.toml deleted file mode 100644 index 7316518b99..0000000000 --- a/third_party/rust/packed_simd/rustfmt.toml +++ /dev/null @@ -1,5 +0,0 @@ -max_width = 110 -use_small_heuristics = "Max" -wrap_comments = true -edition = "2018" -error_on_line_overflow = true \ No newline at end of file diff --git a/third_party/rust/packed_simd/src/api.rs b/third_party/rust/packed_simd/src/api.rs deleted file mode 100644 index 262fc4ee69..0000000000 --- a/third_party/rust/packed_simd/src/api.rs +++ /dev/null @@ -1,309 +0,0 @@ -//! Implements the Simd<[T; N]> APIs - -#[macro_use] -mod bitmask; -pub(crate) mod cast; -#[macro_use] -mod cmp; -#[macro_use] -mod default; -#[macro_use] -mod fmt; -#[macro_use] -mod from; -#[macro_use] -mod hash; -#[macro_use] -mod math; -#[macro_use] -mod minimal; -#[macro_use] -mod ops; -#[macro_use] -mod ptr; -#[macro_use] -mod reductions; -#[macro_use] -mod select; -#[macro_use] -mod shuffle; -#[macro_use] -mod shuffle1_dyn; -#[macro_use] -mod slice; -#[macro_use] -mod swap_bytes; -#[macro_use] -mod bit_manip; - -#[cfg(feature = "into_bits")] -pub(crate) mod into_bits; - -macro_rules! impl_i { - ([$elem_ty:ident; $elem_n:expr]: $tuple_id:ident, $mask_ty:ident - | $ielem_ty:ident, $ibitmask_ty:ident | $test_tt:tt | $($elem_ids:ident),* - | From: $($from_vec_ty:ident),* | $(#[$doc:meta])*) => { - impl_minimal_iuf!([$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - | $($elem_ids),* | $(#[$doc])*); - impl_ops_vector_arithmetic!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_scalar_arithmetic!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (!(0 as $elem_ty), 0) - ); - impl_ops_scalar_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (!(0 as $elem_ty), 0) - ); - impl_ops_vector_shifts!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_scalar_shifts!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_rotates!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_neg!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_int_min_max!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt - ); - impl_reduction_integer_arithmetic!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - ); - impl_reduction_min_max!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - ); - impl_reduction_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - | (|x|{ x as $elem_ty }) | (!(0 as $elem_ty), 0) - ); - impl_fmt_debug!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_lower_hex!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_upper_hex!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_octal!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_binary!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_from_array!([$elem_ty; $elem_n]: $tuple_id | $test_tt | (1, 1)); - impl_from_vectors!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | $($from_vec_ty),* - ); - impl_default!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_hash!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_slice_from_slice!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_slice_write_to_slice!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_swap_bytes!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_bit_manip!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_shuffle1_dyn!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_partial_eq!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (0, 1) - ); - impl_cmp_eq!([$elem_ty; $elem_n]: $tuple_id | $test_tt | (0, 1)); - impl_cmp_vertical!( - [$elem_ty; $elem_n]: $tuple_id, $mask_ty, false, (1, 0) | $test_tt - ); - impl_cmp_partial_ord!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_ord!([$elem_ty; $elem_n]: $tuple_id | $test_tt | (0, 1)); - impl_bitmask!($tuple_id | $ibitmask_ty | (-1, 0) | $test_tt); - - test_select!($elem_ty, $mask_ty, $tuple_id, (1, 2) | $test_tt); - test_cmp_partial_ord_int!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - test_shuffle1_dyn!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - } -} - -macro_rules! impl_u { - ([$elem_ty:ident; $elem_n:expr]: $tuple_id:ident, $mask_ty:ident - | $ielem_ty:ident, $ibitmask_ty:ident | $test_tt:tt | $($elem_ids:ident),* - | From: $($from_vec_ty:ident),* | $(#[$doc:meta])*) => { - impl_minimal_iuf!([$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - | $($elem_ids),* | $(#[$doc])*); - impl_ops_vector_arithmetic!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_scalar_arithmetic!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (!(0 as $elem_ty), 0) - ); - impl_ops_scalar_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (!(0 as $elem_ty), 0) - ); - impl_ops_vector_shifts!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_scalar_shifts!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_rotates!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_int_min_max!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt - ); - impl_reduction_integer_arithmetic!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - ); - impl_reduction_min_max!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - ); - impl_reduction_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - | (|x|{ x as $elem_ty }) | (!(0 as $elem_ty), 0) - ); - impl_fmt_debug!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_lower_hex!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_upper_hex!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_octal!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_binary!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_from_array!([$elem_ty; $elem_n]: $tuple_id | $test_tt | (1, 1)); - impl_from_vectors!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | $($from_vec_ty),* - ); - impl_default!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_hash!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_slice_from_slice!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_slice_write_to_slice!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_swap_bytes!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_bit_manip!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_shuffle1_dyn!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_partial_eq!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (1, 0) - ); - impl_cmp_eq!([$elem_ty; $elem_n]: $tuple_id | $test_tt | (0, 1)); - impl_cmp_vertical!( - [$elem_ty; $elem_n]: $tuple_id, $mask_ty, false, (1, 0) | $test_tt - ); - impl_cmp_partial_ord!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_ord!([$elem_ty; $elem_n]: $tuple_id | $test_tt | (0, 1)); - impl_bitmask!($tuple_id | $ibitmask_ty | ($ielem_ty::max_value(), 0) | - $test_tt); - - test_select!($elem_ty, $mask_ty, $tuple_id, (1, 2) | $test_tt); - test_cmp_partial_ord_int!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - test_shuffle1_dyn!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - } -} - -macro_rules! impl_f { - ([$elem_ty:ident; $elem_n:expr]: $tuple_id:ident, $mask_ty:ident - | $ielem_ty:ident | $test_tt:tt | $($elem_ids:ident),* - | From: $($from_vec_ty:ident),* | $(#[$doc:meta])*) => { - impl_minimal_iuf!([$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - | $($elem_ids),* | $(#[$doc])*); - impl_ops_vector_arithmetic!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_scalar_arithmetic!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_neg!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_ops_vector_float_min_max!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt - ); - impl_reduction_float_arithmetic!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_reduction_min_max!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - ); - impl_fmt_debug!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_from_array!([$elem_ty; $elem_n]: $tuple_id | $test_tt | (1., 1.)); - impl_from_vectors!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | $($from_vec_ty),* - ); - impl_default!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_partial_eq!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (1., 0.) - ); - impl_slice_from_slice!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_slice_write_to_slice!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_shuffle1_dyn!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - - impl_float_consts!([$elem_ty; $elem_n]: $tuple_id); - impl_float_category!([$elem_ty; $elem_n]: $tuple_id, $mask_ty); - - // floating-point math - impl_math_float_abs!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_cos!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_exp!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_ln!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_mul_add!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_mul_adde!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_powf!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_recpre!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_rsqrte!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_sin!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_sqrt!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_sqrte!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_math_float_tanh!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_vertical!( - [$elem_ty; $elem_n]: $tuple_id, $mask_ty, false, (1., 0.) - | $test_tt - ); - - test_select!($elem_ty, $mask_ty, $tuple_id, (1., 2.) | $test_tt); - test_reduction_float_min_max!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt - ); - test_shuffle1_dyn!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - } -} - -macro_rules! impl_m { - ([$elem_ty:ident; $elem_n:expr]: $tuple_id:ident - | $ielem_ty:ident, $ibitmask_ty:ident - | $test_tt:tt | $($elem_ids:ident),* | From: $($from_vec_ty:ident),* - | $(#[$doc:meta])*) => { - impl_minimal_mask!( - [$elem_ty; $elem_n]: $tuple_id | $ielem_ty | $test_tt - | $($elem_ids),* | $(#[$doc])* - ); - impl_ops_vector_mask_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (true, false) - ); - impl_ops_scalar_mask_bitwise!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (true, false) - ); - impl_reduction_bitwise!( - [bool; $elem_n]: $tuple_id | $ielem_ty | $test_tt - | (|x|{ x != 0 }) | (true, false) - ); - impl_reduction_mask!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_fmt_debug!([bool; $elem_n]: $tuple_id | $test_tt); - impl_from_array!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt - | (crate::$elem_ty::new(true), true) - ); - impl_from_vectors!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | $($from_vec_ty),* - ); - impl_default!([bool; $elem_n]: $tuple_id | $test_tt); - impl_cmp_partial_eq!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (true, false) - ); - impl_cmp_eq!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (true, false) - ); - impl_cmp_vertical!( - [$elem_ty; $elem_n]: $tuple_id, $tuple_id, true, (true, false) - | $test_tt - ); - impl_select!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_partial_ord!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_cmp_ord!( - [$elem_ty; $elem_n]: $tuple_id | $test_tt | (false, true) - ); - impl_shuffle1_dyn!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - impl_bitmask!($tuple_id | $ibitmask_ty | (true, false) | $test_tt); - - test_cmp_partial_ord_mask!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - test_shuffle1_dyn_mask!([$elem_ty; $elem_n]: $tuple_id | $test_tt); - } -} - -macro_rules! impl_const_p { - ([$elem_ty:ty; $elem_n:expr]: $tuple_id:ident, $mask_ty:ident, - $usize_ty:ident, $isize_ty:ident - | $test_tt:tt | $($elem_ids:ident),* - | From: $($from_vec_ty:ident),* | $(#[$doc:meta])*) => { - impl_minimal_p!( - [$elem_ty; $elem_n]: $tuple_id, $mask_ty, $usize_ty, $isize_ty - | ref_ | $test_tt | $($elem_ids),* - | (1 as $elem_ty, 0 as $elem_ty) | $(#[$doc])* - ); - impl_ptr_read!([$elem_ty; $elem_n]: $tuple_id, $mask_ty | $test_tt); - } -} - -macro_rules! impl_mut_p { - ([$elem_ty:ty; $elem_n:expr]: $tuple_id:ident, $mask_ty:ident, - $usize_ty:ident, $isize_ty:ident - | $test_tt:tt | $($elem_ids:ident),* - | From: $($from_vec_ty:ident),* | $(#[$doc:meta])*) => { - impl_minimal_p!( - [$elem_ty; $elem_n]: $tuple_id, $mask_ty, $usize_ty, $isize_ty - | ref_mut_ | $test_tt | $($elem_ids),* - | (1 as $elem_ty, 0 as $elem_ty) | $(#[$doc])* - ); - impl_ptr_read!([$elem_ty; $elem_n]: $tuple_id, $mask_ty | $test_tt); - impl_ptr_write!([$elem_ty; $elem_n]: $tuple_id, $mask_ty | $test_tt); - } -} diff --git a/third_party/rust/packed_simd/src/api/bit_manip.rs b/third_party/rust/packed_simd/src/api/bit_manip.rs deleted file mode 100644 index c1e90bb0fb..0000000000 --- a/third_party/rust/packed_simd/src/api/bit_manip.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Bit manipulations. - -macro_rules! impl_bit_manip { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Returns the number of ones in the binary representation of - /// the lanes of `self`. - #[inline] - pub fn count_ones(self) -> Self { - super::codegen::bit_manip::BitManip::ctpop(self) - } - - /// Returns the number of zeros in the binary representation of - /// the lanes of `self`. - #[inline] - pub fn count_zeros(self) -> Self { - super::codegen::bit_manip::BitManip::ctpop(!self) - } - - /// Returns the number of leading zeros in the binary - /// representation of the lanes of `self`. - #[inline] - pub fn leading_zeros(self) -> Self { - super::codegen::bit_manip::BitManip::ctlz(self) - } - - /// Returns the number of trailing zeros in the binary - /// representation of the lanes of `self`. - #[inline] - pub fn trailing_zeros(self) -> Self { - super::codegen::bit_manip::BitManip::cttz(self) - } - } - - test_if! { - $test_tt: - paste::item! { - #[allow(overflowing_literals)] - pub mod [<$id _bit_manip>] { - #![allow(const_item_mutation)] - use super::*; - - const LANE_WIDTH: usize = mem::size_of::<$elem_ty>() * 8; - - macro_rules! test_func { - ($x:expr, $func:ident) => {{ - let mut actual = $x; - for i in 0..$id::lanes() { - actual = actual.replace( - i, - $x.extract(i).$func() as $elem_ty - ); - } - let expected = $x.$func(); - assert_eq!(actual, expected); - }}; - } - - const BYTES: [u8; 64] = [ - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - ]; - - fn load_bytes() -> $id { - let elems: &mut [$elem_ty] = unsafe { - slice::from_raw_parts_mut( - BYTES.as_mut_ptr() as *mut $elem_ty, - $id::lanes(), - ) - }; - $id::from_slice_unaligned(elems) - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn count_ones() { - test_func!($id::splat(0), count_ones); - test_func!($id::splat(!0), count_ones); - test_func!(load_bytes(), count_ones); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn count_zeros() { - test_func!($id::splat(0), count_zeros); - test_func!($id::splat(!0), count_zeros); - test_func!(load_bytes(), count_zeros); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn leading_zeros() { - test_func!($id::splat(0), leading_zeros); - test_func!($id::splat(1), leading_zeros); - // some implementations use `pshufb` which has unique - // behavior when the 8th bit is set. - test_func!($id::splat(0b1000_0010), leading_zeros); - test_func!($id::splat(!0), leading_zeros); - test_func!( - $id::splat(1 << (LANE_WIDTH - 1)), - leading_zeros - ); - test_func!(load_bytes(), leading_zeros); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn trailing_zeros() { - test_func!($id::splat(0), trailing_zeros); - test_func!($id::splat(1), trailing_zeros); - test_func!($id::splat(0b1000_0010), trailing_zeros); - test_func!($id::splat(!0), trailing_zeros); - test_func!( - $id::splat(1 << (LANE_WIDTH - 1)), - trailing_zeros - ); - test_func!(load_bytes(), trailing_zeros); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/bitmask.rs b/third_party/rust/packed_simd/src/api/bitmask.rs deleted file mode 100644 index 8f4868f328..0000000000 --- a/third_party/rust/packed_simd/src/api/bitmask.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Bitmask API - -macro_rules! impl_bitmask { - ($id:ident | $ibitmask_ty:ident | ($set:expr, $clear:expr) - | $test_tt:tt) => { - impl $id { - /// Creates a bitmask with the MSB of each vector lane. - /// - /// If the vector has less than 8 lanes, the bits that do not - /// correspond to any vector lanes are cleared. - #[inline] - pub fn bitmask(self) -> $ibitmask_ty { - unsafe { codegen::llvm::simd_bitmask(self.0) } - } - } - - test_if! { - $test_tt: - paste::item! { - #[cfg(not( - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/210 - target_endian = "big" - ))] - pub mod [<$id _bitmask>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn bitmask() { - // clear all lanes - let vec = $id::splat($clear as _); - let bitmask: $ibitmask_ty = 0; - assert_eq!(vec.bitmask(), bitmask); - - // set even lanes - let mut vec = $id::splat($clear as _); - for i in 0..$id::lanes() { - if i % 2 == 0 { - vec = vec.replace(i, $set as _); - } - } - // create bitmask with even lanes set: - let mut bitmask: $ibitmask_ty = 0; - for i in 0..$id::lanes() { - if i % 2 == 0 { - bitmask |= 1 << i; - } - } - assert_eq!(vec.bitmask(), bitmask); - - - // set odd lanes - let mut vec = $id::splat($clear as _); - for i in 0..$id::lanes() { - if i % 2 != 0 { - vec = vec.replace(i, $set as _); - } - } - // create bitmask with odd lanes set: - let mut bitmask: $ibitmask_ty = 0; - for i in 0..$id::lanes() { - if i % 2 != 0 { - bitmask |= 1 << i; - } - } - assert_eq!(vec.bitmask(), bitmask); - - // set all lanes - let vec = $id::splat($set as _); - let mut bitmask: $ibitmask_ty = 0; - for i in 0..$id::lanes() { - bitmask |= 1 << i; - } - assert_eq!(vec.bitmask(), bitmask); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/cast.rs b/third_party/rust/packed_simd/src/api/cast.rs deleted file mode 100644 index f1c32ca1a3..0000000000 --- a/third_party/rust/packed_simd/src/api/cast.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Implementation of `FromCast` and `IntoCast`. -#![allow(clippy::module_name_repetitions)] - -/// Numeric cast from `T` to `Self`. -/// -/// > Note: This is a temporary workaround until the conversion traits -/// specified > in [RFC2484] are implemented. -/// -/// Numeric cast between vectors with the same number of lanes, such that: -/// -/// * casting integer vectors whose lane types have the same size (e.g. `i32xN` -/// -> `u32xN`) is a **no-op**, -/// -/// * casting from a larger integer to a smaller integer (e.g. `u32xN` -> -/// `u8xN`) will **truncate**, -/// -/// * casting from a smaller integer to a larger integer (e.g. `u8xN` -> -/// `u32xN`) will: -/// * **zero-extend** if the source is unsigned, or -/// * **sign-extend** if the source is signed, -/// -/// * casting from a float to an integer will **round the float towards zero**, -/// -/// * casting from an integer to float will produce the floating point -/// representation of the integer, **rounding to nearest, ties to even**, -/// -/// * casting from an `f32` to an `f64` is perfect and lossless, -/// -/// * casting from an `f64` to an `f32` **rounds to nearest, ties to even**. -/// -/// [RFC2484]: https://github.com/rust-lang/rfcs/pull/2484 -pub trait FromCast: crate::marker::Sized { - /// Numeric cast from `T` to `Self`. - fn from_cast(_: T) -> Self; -} - -/// Numeric cast from `Self` to `T`. -/// -/// > Note: This is a temporary workaround until the conversion traits -/// specified > in [RFC2484] are implemented. -/// -/// Numeric cast between vectors with the same number of lanes, such that: -/// -/// * casting integer vectors whose lane types have the same size (e.g. `i32xN` -/// -> `u32xN`) is a **no-op**, -/// -/// * casting from a larger integer to a smaller integer (e.g. `u32xN` -> -/// `u8xN`) will **truncate**, -/// -/// * casting from a smaller integer to a larger integer (e.g. `u8xN` -> -/// `u32xN`) will: -/// * **zero-extend** if the source is unsigned, or -/// * **sign-extend** if the source is signed, -/// -/// * casting from a float to an integer will **round the float towards zero**, -/// -/// * casting from an integer to float will produce the floating point -/// representation of the integer, **rounding to nearest, ties to even**, -/// -/// * casting from an `f32` to an `f64` is perfect and lossless, -/// -/// * casting from an `f64` to an `f32` **rounds to nearest, ties to even**. -/// -/// [RFC2484]: https://github.com/rust-lang/rfcs/pull/2484 -pub trait Cast: crate::marker::Sized { - /// Numeric cast from `self` to `T`. - fn cast(self) -> T; -} - -/// `FromCast` implies `Cast`. -impl Cast for T -where - U: FromCast, -{ - #[inline] - fn cast(self) -> U { - U::from_cast(self) - } -} - -/// `FromCast` and `Cast` are reflexive -impl FromCast for T { - #[inline] - fn from_cast(t: Self) -> Self { - t - } -} - -#[macro_use] -mod macros; - -mod v16; -pub use self::v16::*; - -mod v32; -pub use self::v32::*; - -mod v64; -pub use self::v64::*; - -mod v128; -pub use self::v128::*; - -mod v256; -pub use self::v256::*; - -mod v512; -pub use self::v512::*; diff --git a/third_party/rust/packed_simd/src/api/cast/macros.rs b/third_party/rust/packed_simd/src/api/cast/macros.rs deleted file mode 100644 index 3bb29f0b80..0000000000 --- a/third_party/rust/packed_simd/src/api/cast/macros.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Macros implementing `FromCast` - -macro_rules! impl_from_cast_ { - ($id:ident[$test_tt:tt]: $from_ty:ident) => { - impl crate::api::cast::FromCast<$from_ty> for $id { - #[inline] - fn from_cast(x: $from_ty) -> Self { - use crate::llvm::simd_cast; - debug_assert_eq!($from_ty::lanes(), $id::lanes()); - Simd(unsafe { simd_cast(x.0) }) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _from_cast_ $from_ty>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test() { - assert_eq!($id::lanes(), $from_ty::lanes()); - } - } - } - } - }; -} - -macro_rules! impl_from_cast { - ($id:ident[$test_tt:tt]: $($from_ty:ident),*) => { - $( - impl_from_cast_!($id[$test_tt]: $from_ty); - )* - } -} - -macro_rules! impl_from_cast_mask_ { - ($id:ident[$test_tt:tt]: $from_ty:ident) => { - impl crate::api::cast::FromCast<$from_ty> for $id { - #[inline] - fn from_cast(x: $from_ty) -> Self { - debug_assert_eq!($from_ty::lanes(), $id::lanes()); - x.ne($from_ty::default()) - .select($id::splat(true), $id::splat(false)) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _from_cast_ $from_ty>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test() { - assert_eq!($id::lanes(), $from_ty::lanes()); - - let x = $from_ty::default(); - let m: $id = x.cast(); - assert!(m.none()); - } - } - } - } - }; -} - -macro_rules! impl_from_cast_mask { - ($id:ident[$test_tt:tt]: $($from_ty:ident),*) => { - $( - impl_from_cast_mask_!($id[$test_tt]: $from_ty); - )* - } -} - -#[allow(unused)] -macro_rules! impl_into_cast { - ($id:ident[$test_tt:tt]: $($from_ty:ident),*) => { - $( - impl_from_cast_!($from_ty[$test_tt]: $id); - )* - } -} diff --git a/third_party/rust/packed_simd/src/api/cast/v128.rs b/third_party/rust/packed_simd/src/api/cast/v128.rs deleted file mode 100644 index 2e10b97b77..0000000000 --- a/third_party/rust/packed_simd/src/api/cast/v128.rs +++ /dev/null @@ -1,302 +0,0 @@ -//! `FromCast` and `IntoCast` implementations for portable 128-bit wide vectors -#[rustfmt::skip] - -use crate::*; - -impl_from_cast!(i8x16[test_v128]: u8x16, m8x16, i16x16, u16x16, m16x16, i32x16, u32x16, f32x16, m32x16); -impl_from_cast!(u8x16[test_v128]: i8x16, m8x16, i16x16, u16x16, m16x16, i32x16, u32x16, f32x16, m32x16); -impl_from_cast_mask!(m8x16[test_v128]: i8x16, u8x16, i16x16, u16x16, m16x16, i32x16, u32x16, f32x16, m32x16); - -impl_from_cast!( - i16x8[test_v128]: i8x8, - u8x8, - m8x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast!( - u16x8[test_v128]: i8x8, - u8x8, - m8x8, - i16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast_mask!( - m16x8[test_v128]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); - -impl_from_cast!( - i32x4[test_v128]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast!( - u32x4[test_v128]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast!( - f32x4[test_v128]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast_mask!( - m32x4[test_v128]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); - -impl_from_cast!( - i64x2[test_v128]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast!( - u64x2[test_v128]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast!( - f64x2[test_v128]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast_mask!( - m64x2[test_v128]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); - -impl_from_cast!( - isizex2[test_v128]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - usizex2, - msizex2 -); -impl_from_cast!( - usizex2[test_v128]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - msizex2 -); -impl_from_cast_mask!( - msizex2[test_v128]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2 -); - -// FIXME[test_v128]: 64-bit single element vectors into_cast impls -impl_from_cast!(i128x1[test_v128]: u128x1, m128x1); -impl_from_cast!(u128x1[test_v128]: i128x1, m128x1); -impl_from_cast!(m128x1[test_v128]: i128x1, u128x1); diff --git a/third_party/rust/packed_simd/src/api/cast/v16.rs b/third_party/rust/packed_simd/src/api/cast/v16.rs deleted file mode 100644 index 896febacbb..0000000000 --- a/third_party/rust/packed_simd/src/api/cast/v16.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! `FromCast` and `IntoCast` implementations for portable 16-bit wide vectors -#[rustfmt::skip] - -use crate::*; - -impl_from_cast!( - i8x2[test_v16]: u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast!( - u8x2[test_v16]: i8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast_mask!( - m8x2[test_v16]: i8x2, - u8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); diff --git a/third_party/rust/packed_simd/src/api/cast/v256.rs b/third_party/rust/packed_simd/src/api/cast/v256.rs deleted file mode 100644 index fe0c835e3c..0000000000 --- a/third_party/rust/packed_simd/src/api/cast/v256.rs +++ /dev/null @@ -1,298 +0,0 @@ -//! `FromCast` and `IntoCast` implementations for portable 256-bit wide vectors -#[rustfmt::skip] - -use crate::*; - -impl_from_cast!(i8x32[test_v256]: u8x32, m8x32, i16x32, u16x32, m16x32); -impl_from_cast!(u8x32[test_v256]: i8x32, m8x32, i16x32, u16x32, m16x32); -impl_from_cast_mask!(m8x32[test_v256]: i8x32, u8x32, i16x32, u16x32, m16x32); - -impl_from_cast!(i16x16[test_v256]: i8x16, u8x16, m8x16, u16x16, m16x16, i32x16, u32x16, f32x16, m32x16); -impl_from_cast!(u16x16[test_v256]: i8x16, u8x16, m8x16, i16x16, m16x16, i32x16, u32x16, f32x16, m32x16); -impl_from_cast_mask!(m16x16[test_v256]: i8x16, u8x16, m8x16, i16x16, u16x16, i32x16, u32x16, f32x16, m32x16); - -impl_from_cast!( - i32x8[test_v256]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast!( - u32x8[test_v256]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast!( - f32x8[test_v256]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast_mask!( - m32x8[test_v256]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); - -impl_from_cast!( - i64x4[test_v256]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast!( - u64x4[test_v256]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast!( - f64x4[test_v256]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast_mask!( - m64x4[test_v256]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); - -impl_from_cast!( - i128x2[test_v256]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast!( - u128x2[test_v256]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast_mask!( - m128x2[test_v256]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - m64x2, - f64x2, - i128x2, - u128x2, - isizex2, - usizex2, - msizex2 -); - -impl_from_cast!( - isizex4[test_v256]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - usizex4, - msizex4 -); -impl_from_cast!( - usizex4[test_v256]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - msizex4 -); -impl_from_cast_mask!( - msizex4[test_v256]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4 -); diff --git a/third_party/rust/packed_simd/src/api/cast/v32.rs b/third_party/rust/packed_simd/src/api/cast/v32.rs deleted file mode 100644 index 4ad1cbf74d..0000000000 --- a/third_party/rust/packed_simd/src/api/cast/v32.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! `FromCast` and `IntoCast` implementations for portable 32-bit wide vectors -#[rustfmt::skip] - -use crate::*; - -impl_from_cast!( - i8x4[test_v32]: u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast!( - u8x4[test_v32]: i8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast_mask!( - m8x4[test_v32]: i8x4, - u8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); - -impl_from_cast!( - i16x2[test_v32]: i8x2, - u8x2, - m8x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast!( - u16x2[test_v32]: i8x2, - u8x2, - m8x2, - i16x2, - m16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast_mask!( - m16x2[test_v32]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - i32x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); diff --git a/third_party/rust/packed_simd/src/api/cast/v512.rs b/third_party/rust/packed_simd/src/api/cast/v512.rs deleted file mode 100644 index b64605045e..0000000000 --- a/third_party/rust/packed_simd/src/api/cast/v512.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! `FromCast` and `IntoCast` implementations for portable 512-bit wide vectors -#[rustfmt::skip] - -use crate::*; - -impl_from_cast!(i8x64[test_v512]: u8x64, m8x64); -impl_from_cast!(u8x64[test_v512]: i8x64, m8x64); -impl_from_cast_mask!(m8x64[test_v512]: i8x64, u8x64); - -impl_from_cast!(i16x32[test_v512]: i8x32, u8x32, m8x32, u16x32, m16x32); -impl_from_cast!(u16x32[test_v512]: i8x32, u8x32, m8x32, i16x32, m16x32); -impl_from_cast_mask!(m16x32[test_v512]: i8x32, u8x32, m8x32, i16x32, u16x32); - -impl_from_cast!(i32x16[test_v512]: i8x16, u8x16, m8x16, i16x16, u16x16, m16x16, u32x16, f32x16, m32x16); -impl_from_cast!(u32x16[test_v512]: i8x16, u8x16, m8x16, i16x16, u16x16, m16x16, i32x16, f32x16, m32x16); -impl_from_cast!(f32x16[test_v512]: i8x16, u8x16, m8x16, i16x16, u16x16, m16x16, i32x16, u32x16, m32x16); -impl_from_cast_mask!(m32x16[test_v512]: i8x16, u8x16, m8x16, i16x16, u16x16, m16x16, i32x16, u32x16, f32x16); - -impl_from_cast!( - i64x8[test_v512]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast!( - u64x8[test_v512]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast!( - f64x8[test_v512]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast_mask!( - m64x8[test_v512]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - isizex8, - usizex8, - msizex8 -); - -impl_from_cast!( - i128x4[test_v512]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast!( - u128x4[test_v512]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast_mask!( - m128x4[test_v512]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - m64x4, - f64x4, - i128x4, - u128x4, - isizex4, - usizex4, - msizex4 -); - -impl_from_cast!( - isizex8[test_v512]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - usizex8, - msizex8 -); -impl_from_cast!( - usizex8[test_v512]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - msizex8 -); -impl_from_cast_mask!( - msizex8[test_v512]: i8x8, - u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8 -); diff --git a/third_party/rust/packed_simd/src/api/cast/v64.rs b/third_party/rust/packed_simd/src/api/cast/v64.rs deleted file mode 100644 index b23d1a4917..0000000000 --- a/third_party/rust/packed_simd/src/api/cast/v64.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! `FromCast` and `IntoCast` implementations for portable 64-bit wide vectors -#[rustfmt::skip] - -use crate::*; - -impl_from_cast!( - i8x8[test_v64]: u8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast!( - u8x8[test_v64]: i8x8, - m8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); -impl_from_cast_mask!( - m8x8[test_v64]: i8x8, - u8x8, - i16x8, - u16x8, - m16x8, - i32x8, - u32x8, - f32x8, - m32x8, - i64x8, - u64x8, - f64x8, - m64x8, - isizex8, - usizex8, - msizex8 -); - -impl_from_cast!( - i16x4[test_v64]: i8x4, - u8x4, - m8x4, - u16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast!( - u16x4[test_v64]: i8x4, - u8x4, - m8x4, - i16x4, - m16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); -impl_from_cast_mask!( - m16x4[test_v64]: i8x4, - u8x4, - m8x4, - i16x4, - u16x4, - i32x4, - u32x4, - f32x4, - m32x4, - i64x4, - u64x4, - f64x4, - m64x4, - i128x4, - u128x4, - m128x4, - isizex4, - usizex4, - msizex4 -); - -impl_from_cast!( - i32x2[test_v64]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - u32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast!( - u32x2[test_v64]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - f32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast!( - f32x2[test_v64]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - m32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); -impl_from_cast_mask!( - m32x2[test_v64]: i8x2, - u8x2, - m8x2, - i16x2, - u16x2, - m16x2, - i32x2, - u32x2, - f32x2, - i64x2, - u64x2, - f64x2, - m64x2, - i128x2, - u128x2, - m128x2, - isizex2, - usizex2, - msizex2 -); diff --git a/third_party/rust/packed_simd/src/api/cmp.rs b/third_party/rust/packed_simd/src/api/cmp.rs deleted file mode 100644 index 6d5301dddd..0000000000 --- a/third_party/rust/packed_simd/src/api/cmp.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Implement cmp traits for vector types - -#[macro_use] -mod partial_eq; - -#[macro_use] -mod eq; - -#[macro_use] -mod partial_ord; - -#[macro_use] -mod ord; - -#[macro_use] -mod vertical; diff --git a/third_party/rust/packed_simd/src/api/cmp/eq.rs b/third_party/rust/packed_simd/src/api/cmp/eq.rs deleted file mode 100644 index 3c55d0dce5..0000000000 --- a/third_party/rust/packed_simd/src/api/cmp/eq.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Implements `Eq` for vector types. - -macro_rules! impl_cmp_eq { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $test_tt:tt | - ($true:expr, $false:expr) - ) => { - impl crate::cmp::Eq for $id {} - impl crate::cmp::Eq for LexicographicallyOrdered<$id> {} - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_eq>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn eq() { - fn foo(_: E) {} - let a = $id::splat($false); - foo(a); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/cmp/ord.rs b/third_party/rust/packed_simd/src/api/cmp/ord.rs deleted file mode 100644 index e54ba3bfde..0000000000 --- a/third_party/rust/packed_simd/src/api/cmp/ord.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Implements `Ord` for vector types. - -macro_rules! impl_cmp_ord { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $test_tt:tt | - ($true:expr, $false:expr) - ) => { - impl $id { - /// Returns a wrapper that implements `Ord`. - #[inline] - pub fn lex_ord(&self) -> LexicographicallyOrdered<$id> { - LexicographicallyOrdered(*self) - } - } - - impl crate::cmp::Ord for LexicographicallyOrdered<$id> { - #[inline] - fn cmp(&self, other: &Self) -> crate::cmp::Ordering { - match self.partial_cmp(other) { - Some(x) => x, - None => unsafe { crate::hint::unreachable_unchecked() }, - } - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_ord>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn eq() { - fn foo(_: E) {} - let a = $id::splat($false); - foo(a.partial_lex_ord()); - foo(a.lex_ord()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/cmp/partial_eq.rs b/third_party/rust/packed_simd/src/api/cmp/partial_eq.rs deleted file mode 100644 index d69dd47425..0000000000 --- a/third_party/rust/packed_simd/src/api/cmp/partial_eq.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Implements `PartialEq` for vector types. - -macro_rules! impl_cmp_partial_eq { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $test_tt:tt | - ($true:expr, $false:expr) - ) => { - // FIXME: https://github.com/rust-lang-nursery/rust-clippy/issues/2892 - #[allow(clippy::partialeq_ne_impl)] - impl crate::cmp::PartialEq<$id> for $id { - #[inline] - fn eq(&self, other: &Self) -> bool { - $id::eq(*self, *other).all() - } - #[inline] - fn ne(&self, other: &Self) -> bool { - $id::ne(*self, *other).any() - } - } - - // FIXME: https://github.com/rust-lang-nursery/rust-clippy/issues/2892 - #[allow(clippy::partialeq_ne_impl)] - impl crate::cmp::PartialEq> for LexicographicallyOrdered<$id> { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - #[inline] - fn ne(&self, other: &Self) -> bool { - self.0 != other.0 - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _cmp_PartialEq>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn partial_eq() { - let a = $id::splat($false); - let b = $id::splat($true); - - assert!(a != b); - assert!(!(a == b)); - assert!(a == a); - assert!(!(a != a)); - - if $id::lanes() > 1 { - let a = $id::splat($false).replace(0, $true); - let b = $id::splat($true); - - assert!(a != b); - assert!(!(a == b)); - assert!(a == a); - assert!(!(a != a)); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/cmp/partial_ord.rs b/third_party/rust/packed_simd/src/api/cmp/partial_ord.rs deleted file mode 100644 index 76ed9ebe4e..0000000000 --- a/third_party/rust/packed_simd/src/api/cmp/partial_ord.rs +++ /dev/null @@ -1,230 +0,0 @@ -//! Implements `PartialOrd` for vector types. -//! -//! This implements a lexicographical order. - -macro_rules! impl_cmp_partial_ord { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Returns a wrapper that implements `PartialOrd`. - #[inline] - pub fn partial_lex_ord(&self) -> LexicographicallyOrdered<$id> { - LexicographicallyOrdered(*self) - } - } - - impl crate::cmp::PartialOrd> for LexicographicallyOrdered<$id> { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - if PartialEq::eq(self, other) { - Some(crate::cmp::Ordering::Equal) - } else if PartialOrd::lt(self, other) { - Some(crate::cmp::Ordering::Less) - } else if PartialOrd::gt(self, other) { - Some(crate::cmp::Ordering::Greater) - } else { - None - } - } - #[inline] - fn lt(&self, other: &Self) -> bool { - let m_lt = self.0.lt(other.0); - let m_eq = self.0.eq(other.0); - for i in 0..$id::lanes() { - if m_eq.extract(i) { - continue; - } - return m_lt.extract(i); - } - false - } - #[inline] - fn le(&self, other: &Self) -> bool { - self.lt(other) | PartialEq::eq(self, other) - } - #[inline] - fn ge(&self, other: &Self) -> bool { - self.gt(other) | PartialEq::eq(self, other) - } - #[inline] - fn gt(&self, other: &Self) -> bool { - let m_gt = self.0.gt(other.0); - let m_eq = self.0.eq(other.0); - for i in 0..$id::lanes() { - if m_eq.extract(i) { - continue; - } - return m_gt.extract(i); - } - false - } - } - }; -} - -macro_rules! test_cmp_partial_ord_int { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_PartialOrd>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn partial_lex_ord() { - use crate::testing::utils::{test_cmp}; - // constant values - let a = $id::splat(0); - let b = $id::splat(1); - - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - - // variable values: a = [0, 1, 2, 3]; b = [3, 2, 1, 0] - let mut a = $id::splat(0); - let mut b = $id::splat(0); - for i in 0..$id::lanes() { - a = a.replace(i, i as $elem_ty); - b = b.replace(i, ($id::lanes() - i) as $elem_ty); - } - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - - // variable values: a = [0, 1, 2, 3]; b = [0, 1, 2, 4] - let mut b = a; - b = b.replace( - $id::lanes() - 1, - a.extract($id::lanes() - 1) + 1 as $elem_ty - ); - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - - if $id::lanes() > 2 { - // variable values a = [0, 1, 0, 0]; b = [0, 1, 2, 3] - let b = a; - let mut a = $id::splat(0); - a = a.replace(1, 1 as $elem_ty); - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - - // variable values: a = [0, 1, 2, 3]; b = [0, 1, 3, 2] - let mut b = a; - b = b.replace( - 2, a.extract($id::lanes() - 1) + 1 as $elem_ty - ); - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(crate::cmp::Ordering::Equal)); - } - } - } - } - } - }; -} - -macro_rules! test_cmp_partial_ord_mask { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_PartialOrd>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn partial_lex_ord() { - use crate::testing::utils::{test_cmp}; - use crate::cmp::Ordering; - - // constant values - let a = $id::splat(false); - let b = $id::splat(true); - - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Equal)); - - // variable values: - // a = [false, false, false, false]; - // b = [false, false, false, true] - let a = $id::splat(false); - let mut b = $id::splat(false); - b = b.replace($id::lanes() - 1, true); - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Equal)); - - // variable values: - // a = [true, true, true, false]; - // b = [true, true, true, true] - let mut a = $id::splat(true); - let b = $id::splat(true); - a = a.replace($id::lanes() - 1, false); - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Equal)); - - if $id::lanes() > 2 { - // variable values - // a = [false, true, false, false]; - // b = [false, true, true, true] - let mut a = $id::splat(false); - let mut b = $id::splat(true); - a = a.replace(1, true); - b = b.replace(0, false); - test_cmp(a.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Less)); - test_cmp(b.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Greater)); - test_cmp(a.partial_lex_ord(), a.partial_lex_ord(), - Some(Ordering::Equal)); - test_cmp(b.partial_lex_ord(), b.partial_lex_ord(), - Some(Ordering::Equal)); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/cmp/vertical.rs b/third_party/rust/packed_simd/src/api/cmp/vertical.rs deleted file mode 100644 index ea4a0d1a34..0000000000 --- a/third_party/rust/packed_simd/src/api/cmp/vertical.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! Vertical (lane-wise) vector comparisons returning vector masks. - -macro_rules! impl_cmp_vertical { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident, - $mask_ty:ident, - $is_mask:expr,($true:expr, $false:expr) | $test_tt:tt - ) => { - impl $id { - /// Lane-wise equality comparison. - #[inline] - pub fn eq(self, other: Self) -> $mask_ty { - use crate::llvm::simd_eq; - Simd(unsafe { simd_eq(self.0, other.0) }) - } - - /// Lane-wise inequality comparison. - #[inline] - pub fn ne(self, other: Self) -> $mask_ty { - use crate::llvm::simd_ne; - Simd(unsafe { simd_ne(self.0, other.0) }) - } - - /// Lane-wise less-than comparison. - #[inline] - pub fn lt(self, other: Self) -> $mask_ty { - use crate::llvm::{simd_gt, simd_lt}; - if $is_mask { - Simd(unsafe { simd_gt(self.0, other.0) }) - } else { - Simd(unsafe { simd_lt(self.0, other.0) }) - } - } - - /// Lane-wise less-than-or-equals comparison. - #[inline] - pub fn le(self, other: Self) -> $mask_ty { - use crate::llvm::{simd_ge, simd_le}; - if $is_mask { - Simd(unsafe { simd_ge(self.0, other.0) }) - } else { - Simd(unsafe { simd_le(self.0, other.0) }) - } - } - - /// Lane-wise greater-than comparison. - #[inline] - pub fn gt(self, other: Self) -> $mask_ty { - use crate::llvm::{simd_gt, simd_lt}; - if $is_mask { - Simd(unsafe { simd_lt(self.0, other.0) }) - } else { - Simd(unsafe { simd_gt(self.0, other.0) }) - } - } - - /// Lane-wise greater-than-or-equals comparison. - #[inline] - pub fn ge(self, other: Self) -> $mask_ty { - use crate::llvm::{simd_ge, simd_le}; - if $is_mask { - Simd(unsafe { simd_le(self.0, other.0) }) - } else { - Simd(unsafe { simd_ge(self.0, other.0) }) - } - } - } - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_vertical>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn cmp() { - let a = $id::splat($false); - let b = $id::splat($true); - - let r = a.lt(b); - let e = $mask_ty::splat(true); - assert!(r == e); - let r = a.le(b); - assert!(r == e); - - let e = $mask_ty::splat(false); - let r = a.gt(b); - assert!(r == e); - let r = a.ge(b); - assert!(r == e); - let r = a.eq(b); - assert!(r == e); - - let mut a = a; - let mut b = b; - let mut e = e; - for i in 0..$id::lanes() { - if i % 2 == 0 { - a = a.replace(i, $false); - b = b.replace(i, $true); - e = e.replace(i, true); - } else { - a = a.replace(i, $true); - b = b.replace(i, $false); - e = e.replace(i, false); - } - } - let r = a.lt(b); - assert!(r == e); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/default.rs b/third_party/rust/packed_simd/src/api/default.rs deleted file mode 100644 index 7af55ea77a..0000000000 --- a/third_party/rust/packed_simd/src/api/default.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Implements `Default` for vector types. - -macro_rules! impl_default { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl Default for $id { - #[inline] - fn default() -> Self { - Self::splat($elem_ty::default()) - } - } - - test_if!{ - $test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - pub mod [<$id _default>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn default() { - let a = $id::default(); - for i in 0..$id::lanes() { - assert_eq!(a.extract(i), $elem_ty::default()); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/fmt.rs b/third_party/rust/packed_simd/src/api/fmt.rs deleted file mode 100644 index f3f55c4015..0000000000 --- a/third_party/rust/packed_simd/src/api/fmt.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! Implements formatting APIs - -#[macro_use] -mod debug; -#[macro_use] -mod lower_hex; -#[macro_use] -mod upper_hex; -#[macro_use] -mod octal; -#[macro_use] -mod binary; diff --git a/third_party/rust/packed_simd/src/api/fmt/binary.rs b/third_party/rust/packed_simd/src/api/fmt/binary.rs deleted file mode 100644 index 91c0825559..0000000000 --- a/third_party/rust/packed_simd/src/api/fmt/binary.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Implement Octal formatting - -macro_rules! impl_fmt_binary { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::fmt::Binary for $id { - #[allow(clippy::missing_inline_in_public_items)] - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - write!(f, "{}(", stringify!($id))?; - for i in 0..$elem_count { - if i > 0 { - write!(f, ", ")?; - } - self.extract(i).fmt(f)?; - } - write!(f, ")") - } - } - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _fmt_binary>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn binary() { - use arrayvec::{ArrayString,ArrayVec}; - type TinyString = ArrayString<[u8; 512]>; - - use crate::fmt::Write; - let v = $id::splat($elem_ty::default()); - let mut s = TinyString::new(); - write!(&mut s, "{:#b}", v).unwrap(); - - let mut beg = TinyString::new(); - write!(&mut beg, "{}(", stringify!($id)).unwrap(); - assert!(s.starts_with(beg.as_str())); - assert!(s.ends_with(")")); - let s: ArrayVec<[TinyString; 64]> - = s.replace(beg.as_str(), "") - .replace(")", "").split(",") - .map(|v| TinyString::from(v.trim()).unwrap()) - .collect(); - assert_eq!(s.len(), $id::lanes()); - for (index, ss) in s.into_iter().enumerate() { - let mut e = TinyString::new(); - write!(&mut e, "{:#b}", v.extract(index)).unwrap(); - assert_eq!(ss, e); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/fmt/debug.rs b/third_party/rust/packed_simd/src/api/fmt/debug.rs deleted file mode 100644 index 1e209b3bff..0000000000 --- a/third_party/rust/packed_simd/src/api/fmt/debug.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Implement debug formatting - -macro_rules! impl_fmt_debug_tests { - ([$elem_ty:ty; $elem_count:expr]: $id:ident | $test_tt:tt) => { - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _fmt_debug>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn debug() { - use arrayvec::{ArrayString,ArrayVec}; - type TinyString = ArrayString<[u8; 512]>; - - use crate::fmt::Write; - let v = $id::default(); - let mut s = TinyString::new(); - write!(&mut s, "{:?}", v).unwrap(); - - let mut beg = TinyString::new(); - write!(&mut beg, "{}(", stringify!($id)).unwrap(); - assert!(s.starts_with(beg.as_str())); - assert!(s.ends_with(")")); - let s: ArrayVec<[TinyString; 64]> - = s.replace(beg.as_str(), "") - .replace(")", "").split(",") - .map(|v| TinyString::from(v.trim()).unwrap()) - .collect(); - assert_eq!(s.len(), $id::lanes()); - for (index, ss) in s.into_iter().enumerate() { - let mut e = TinyString::new(); - write!(&mut e, "{:?}", v.extract(index)).unwrap(); - assert_eq!(ss, e); - } - } - } - } - } - }; -} - -macro_rules! impl_fmt_debug { - ([$elem_ty:ty; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::fmt::Debug for $id { - #[allow(clippy::missing_inline_in_public_items)] - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - write!(f, "{}(", stringify!($id))?; - for i in 0..$elem_count { - if i > 0 { - write!(f, ", ")?; - } - self.extract(i).fmt(f)?; - } - write!(f, ")") - } - } - impl_fmt_debug_tests!([$elem_ty; $elem_count]: $id | $test_tt); - }; -} diff --git a/third_party/rust/packed_simd/src/api/fmt/lower_hex.rs b/third_party/rust/packed_simd/src/api/fmt/lower_hex.rs deleted file mode 100644 index 8f11d3119b..0000000000 --- a/third_party/rust/packed_simd/src/api/fmt/lower_hex.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Implement `LowerHex` formatting - -macro_rules! impl_fmt_lower_hex { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::fmt::LowerHex for $id { - #[allow(clippy::missing_inline_in_public_items)] - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - write!(f, "{}(", stringify!($id))?; - for i in 0..$elem_count { - if i > 0 { - write!(f, ", ")?; - } - self.extract(i).fmt(f)?; - } - write!(f, ")") - } - } - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _fmt_lower_hex>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn lower_hex() { - use arrayvec::{ArrayString,ArrayVec}; - type TinyString = ArrayString<[u8; 512]>; - - use crate::fmt::Write; - let v = $id::splat($elem_ty::default()); - let mut s = TinyString::new(); - write!(&mut s, "{:#x}", v).unwrap(); - - let mut beg = TinyString::new(); - write!(&mut beg, "{}(", stringify!($id)).unwrap(); - assert!(s.starts_with(beg.as_str())); - assert!(s.ends_with(")")); - let s: ArrayVec<[TinyString; 64]> - = s.replace(beg.as_str(), "").replace(")", "") - .split(",") - .map(|v| TinyString::from(v.trim()).unwrap()) - .collect(); - assert_eq!(s.len(), $id::lanes()); - for (index, ss) in s.into_iter().enumerate() { - let mut e = TinyString::new(); - write!(&mut e, "{:#x}", v.extract(index)).unwrap(); - assert_eq!(ss, e); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/fmt/octal.rs b/third_party/rust/packed_simd/src/api/fmt/octal.rs deleted file mode 100644 index e708e094ce..0000000000 --- a/third_party/rust/packed_simd/src/api/fmt/octal.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Implement Octal formatting - -macro_rules! impl_fmt_octal { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::fmt::Octal for $id { - #[allow(clippy::missing_inline_in_public_items)] - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - write!(f, "{}(", stringify!($id))?; - for i in 0..$elem_count { - if i > 0 { - write!(f, ", ")?; - } - self.extract(i).fmt(f)?; - } - write!(f, ")") - } - } - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _fmt_octal>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn octal_hex() { - use arrayvec::{ArrayString,ArrayVec}; - type TinyString = ArrayString<[u8; 512]>; - - use crate::fmt::Write; - let v = $id::splat($elem_ty::default()); - let mut s = TinyString::new(); - write!(&mut s, "{:#o}", v).unwrap(); - - let mut beg = TinyString::new(); - write!(&mut beg, "{}(", stringify!($id)).unwrap(); - assert!(s.starts_with(beg.as_str())); - assert!(s.ends_with(")")); - let s: ArrayVec<[TinyString; 64]> - = s.replace(beg.as_str(), "").replace(")", "") - .split(",") - .map(|v| TinyString::from(v.trim()).unwrap()) - .collect(); - assert_eq!(s.len(), $id::lanes()); - for (index, ss) in s.into_iter().enumerate() { - let mut e = TinyString::new(); - write!(&mut e, "{:#o}", v.extract(index)).unwrap(); - assert_eq!(ss, e); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/fmt/upper_hex.rs b/third_party/rust/packed_simd/src/api/fmt/upper_hex.rs deleted file mode 100644 index 5ad455706b..0000000000 --- a/third_party/rust/packed_simd/src/api/fmt/upper_hex.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Implement `UpperHex` formatting - -macro_rules! impl_fmt_upper_hex { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::fmt::UpperHex for $id { - #[allow(clippy::missing_inline_in_public_items)] - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - write!(f, "{}(", stringify!($id))?; - for i in 0..$elem_count { - if i > 0 { - write!(f, ", ")?; - } - self.extract(i).fmt(f)?; - } - write!(f, ")") - } - } - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _fmt_upper_hex>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn upper_hex() { - use arrayvec::{ArrayString,ArrayVec}; - type TinyString = ArrayString<[u8; 512]>; - - use crate::fmt::Write; - let v = $id::splat($elem_ty::default()); - let mut s = TinyString::new(); - write!(&mut s, "{:#X}", v).unwrap(); - - let mut beg = TinyString::new(); - write!(&mut beg, "{}(", stringify!($id)).unwrap(); - assert!(s.starts_with(beg.as_str())); - assert!(s.ends_with(")")); - let s: ArrayVec<[TinyString; 64]> - = s.replace(beg.as_str(), "").replace(")", "") - .split(",") - .map(|v| TinyString::from(v.trim()).unwrap()) - .collect(); - assert_eq!(s.len(), $id::lanes()); - for (index, ss) in s.into_iter().enumerate() { - let mut e = TinyString::new(); - write!(&mut e, "{:#X}", v.extract(index)).unwrap(); - assert_eq!(ss, e); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/from.rs b/third_party/rust/packed_simd/src/api/from.rs deleted file mode 100644 index c30c4d6e21..0000000000 --- a/third_party/rust/packed_simd/src/api/from.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Implementations of the `From` and `Into` traits - -#[macro_use] -mod from_array; - -#[macro_use] -mod from_vector; diff --git a/third_party/rust/packed_simd/src/api/from/from_array.rs b/third_party/rust/packed_simd/src/api/from/from_array.rs deleted file mode 100644 index 5c7801ddaf..0000000000 --- a/third_party/rust/packed_simd/src/api/from/from_array.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Implements `From<[T; N]>` and `Into<[T; N]>` for vector types. - -macro_rules! impl_from_array { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt - | ($non_default_array:expr, $non_default_vec:expr)) => { - impl From<[$elem_ty; $elem_count]> for $id { - #[inline] - fn from(array: [$elem_ty; $elem_count]) -> Self { - union U { - array: [$elem_ty; $elem_count], - vec: $id, - } - unsafe { U { array }.vec } - } - } - - impl From<$id> for [$elem_ty; $elem_count] { - #[inline] - fn from(vec: $id) -> Self { - union U { - array: [$elem_ty; $elem_count], - vec: $id, - } - unsafe { U { vec }.array } - } - } - - // FIXME: `Into::into` is not inline, but due to - // the blanket impl in `std`, which is not - // marked `default`, we cannot override it here with - // specialization. - /* - impl Into<[$elem_ty; $elem_count]> for $id { - #[inline] - fn into(self) -> [$elem_ty; $elem_count] { - union U { - array: [$elem_ty; $elem_count], - vec: $id, - } - unsafe { U { vec: self }.array } - } - } - - impl Into<$id> for [$elem_ty; $elem_count] { - #[inline] - fn into(self) -> $id { - union U { - array: [$elem_ty; $elem_count], - vec: $id, - } - unsafe { U { array: self }.vec } - } - } - */ - - test_if! { - $test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - mod [<$id _from>] { - use super::*; - #[test] - #[cfg_attr(miri, ignore)] - fn array() { - let vec: $id = Default::default(); - - // FIXME: Workaround for arrays with more than 32 - // elements. - // - // Safe because we never take a reference to any - // uninitialized element. - union W { - array: [$elem_ty; $elem_count], - other: () - } - let mut array = W { other: () }; - for i in 0..$elem_count { - let default: $elem_ty = Default::default(); - // note: array.other is the active member and - // initialized so we can take a reference to it: - let p = unsafe { - &mut array.other as *mut () as *mut $elem_ty - }; - // note: default is a valid bit-pattern for - // $elem_ty: - unsafe { - crate::ptr::write(p.wrapping_add(i), default) - }; - } - // note: the array variant of the union is properly - // initialized: - let mut array = unsafe { - array.array - }; - - array[0] = $non_default_array; - let vec = vec.replace(0, $non_default_vec); - - let vec_from_array = $id::from(array); - assert_eq!(vec_from_array, vec); - let array_from_vec - = <[$elem_ty; $elem_count]>::from(vec); - // FIXME: Workaround for arrays with more than 32 - // elements. - for i in 0..$elem_count { - assert_eq!(array_from_vec[i], array[i]); - } - - let vec_from_into_array: $id = array.into(); - assert_eq!(vec_from_into_array, vec); - let array_from_into_vec: [$elem_ty; $elem_count] - = vec.into(); - // FIXME: Workaround for arrays with more than 32 - // elements. - for i in 0..$elem_count { - assert_eq!(array_from_into_vec[i], array[i]); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/from/from_vector.rs b/third_party/rust/packed_simd/src/api/from/from_vector.rs deleted file mode 100644 index 55f70016d5..0000000000 --- a/third_party/rust/packed_simd/src/api/from/from_vector.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Implements `From` and `Into` for vector types. - -macro_rules! impl_from_vector { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt - | $source:ident) => { - impl From<$source> for $id { - #[inline] - fn from(source: $source) -> Self { - fn static_assert_same_number_of_lanes() - where - T: crate::sealed::Simd, - U: crate::sealed::Simd, - { - } - use crate::llvm::simd_cast; - static_assert_same_number_of_lanes::<$id, $source>(); - Simd(unsafe { simd_cast(source.0) }) - } - } - - // FIXME: `Into::into` is not inline, but due to the blanket impl in - // `std`, which is not marked `default`, we cannot override it here - // with specialization. - - /* - impl Into<$id> for $source { - #[inline] - fn into(self) -> $id { - unsafe { simd_cast(self) } - } - } - */ - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _from_ $source>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn from() { - assert_eq!($id::lanes(), $source::lanes()); - let source: $source = Default::default(); - let vec: $id = Default::default(); - - let e = $id::from(source); - assert_eq!(e, vec); - - let e: $id = source.into(); - assert_eq!(e, vec); - } - } - } - } - }; -} - -macro_rules! impl_from_vectors { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt - | $($source:ident),*) => { - $( - impl_from_vector!( - [$elem_ty; $elem_count]: $id | $test_tt | $source - ); - )* - } -} diff --git a/third_party/rust/packed_simd/src/api/hash.rs b/third_party/rust/packed_simd/src/api/hash.rs deleted file mode 100644 index ee80eff939..0000000000 --- a/third_party/rust/packed_simd/src/api/hash.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! Implements `Hash` for vector types. - -macro_rules! impl_hash { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::hash::Hash for $id { - #[inline] - fn hash(&self, state: &mut H) { - unsafe { - union A { - data: [$elem_ty; $id::lanes()], - vec: $id, - } - A { vec: *self }.data.hash(state) - } - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _hash>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn hash() { - use crate::hash::{Hash, Hasher}; - #[allow(deprecated)] - use crate::hash::{SipHasher13}; - type A = [$elem_ty; $id::lanes()]; - let a: A = [42 as $elem_ty; $id::lanes()]; - assert_eq!( - crate::mem::size_of::(), - crate::mem::size_of::<$id>() - ); - #[allow(deprecated)] - let mut a_hash = SipHasher13::new(); - let mut v_hash = a_hash.clone(); - a.hash(&mut a_hash); - - // Integer within mantissa^1 range. - #[allow(clippy::float_cmp)] - let v = $id::splat(42 as $elem_ty); - v.hash(&mut v_hash); - assert_eq!(a_hash.finish(), v_hash.finish()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/into_bits.rs b/third_party/rust/packed_simd/src/api/into_bits.rs deleted file mode 100644 index 03fbe4bff7..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Implementation of `FromBits` and `IntoBits`. - -/// Safe lossless bitwise conversion from `T` to `Self`. -#[cfg_attr(doc_cfg, doc(cfg(feature = "into_bits")))] -pub trait FromBits: crate::marker::Sized { - /// Safe lossless bitwise transmute from `T` to `Self`. - fn from_bits(t: T) -> Self; -} - -/// Safe lossless bitwise conversion from `Self` to `T`. -#[cfg_attr(doc_cfg, doc(cfg(feature = "into_bits")))] -pub trait IntoBits: crate::marker::Sized { - /// Safe lossless bitwise transmute from `self` to `T`. - fn into_bits(self) -> T; -} - -/// `FromBits` implies `IntoBits`. -impl IntoBits for T -where - U: FromBits, -{ - #[inline] - fn into_bits(self) -> U { - debug_assert!(crate::mem::size_of::() == crate::mem::size_of::()); - U::from_bits(self) - } -} - -/// `FromBits` and `IntoBits` are reflexive -impl FromBits for T { - #[inline] - fn from_bits(t: Self) -> Self { - t - } -} - -#[macro_use] -mod macros; - -mod v16; -pub use self::v16::*; - -mod v32; -pub use self::v32::*; - -mod v64; -pub use self::v64::*; - -mod v128; -pub use self::v128::*; - -mod v256; -pub use self::v256::*; - -mod v512; -pub use self::v512::*; - -mod arch_specific; -pub use self::arch_specific::*; diff --git a/third_party/rust/packed_simd/src/api/into_bits/arch_specific.rs b/third_party/rust/packed_simd/src/api/into_bits/arch_specific.rs deleted file mode 100644 index bfac915576..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/arch_specific.rs +++ /dev/null @@ -1,345 +0,0 @@ -//! `FromBits` and `IntoBits` between portable vector types and the -//! architecture-specific vector types. -#[rustfmt::skip] - -// FIXME: MIPS FromBits/IntoBits - -#[allow(unused)] -use crate::*; - -/// This macro implements FromBits for the portable and the architecture -/// specific vector types. -/// -/// The "leaf" case is at the bottom, and the most generic case is at the top. -/// The generic case is split into smaller cases recursively. -macro_rules! impl_arch { - ([$arch_head_i:ident[$arch_head_tt:tt]: $($arch_head_ty:ident),*], - $([$arch_tail_i:ident[$arch_tail_tt:tt]: $($arch_tail_ty:ident),*]),* | - from: $($from_ty:ident),* | into: $($into_ty:ident),* | - test: $test_tt:tt) => { - impl_arch!( - [$arch_head_i[$arch_head_tt]: $($arch_head_ty),*] | - from: $($from_ty),* | - into: $($into_ty),* | - test: $test_tt - ); - impl_arch!( - $([$arch_tail_i[$arch_tail_tt]: $($arch_tail_ty),*]),* | - from: $($from_ty),* | - into: $($into_ty),* | - test: $test_tt - ); - }; - ([$arch:ident[$arch_tt:tt]: $($arch_ty:ident),*] | - from: $($from_ty:ident),* | into: $($into_ty:ident),* | - test: $test_tt:tt) => { - // note: if target is "arm", "+v7,+neon" must be enabled - // and the std library must be recompiled with them - #[cfg(any( - not(target_arch = "arm"), - all(target_feature = "v7", target_feature = "neon", - any(feature = "core_arch", libcore_neon))) - )] - // note: if target is "powerpc", "altivec" must be enabled - // and the std library must be recompiled with it - #[cfg(any( - not(target_arch = "powerpc"), - all(target_feature = "altivec", feature = "core_arch"), - ))] - #[cfg(target_arch = $arch_tt)] - use crate::arch::$arch::{ - $($arch_ty),* - }; - - #[cfg(any( - not(target_arch = "arm"), - all(target_feature = "v7", target_feature = "neon", - any(feature = "core_arch", libcore_neon))) - )] - #[cfg(any( - not(target_arch = "powerpc"), - all(target_feature = "altivec", feature = "core_arch"), - ))] - #[cfg(target_arch = $arch_tt)] - impl_arch!($($arch_ty),* | $($from_ty),* | $($into_ty),* | - test: $test_tt); - }; - ($arch_head:ident, $($arch_tail:ident),* | $($from_ty:ident),* - | $($into_ty:ident),* | test: $test_tt:tt) => { - impl_arch!($arch_head | $($from_ty),* | $($into_ty),* | - test: $test_tt); - impl_arch!($($arch_tail),* | $($from_ty),* | $($into_ty),* | - test: $test_tt); - }; - ($arch_head:ident | $($from_ty:ident),* | $($into_ty:ident),* | - test: $test_tt:tt) => { - impl_from_bits!($arch_head[$test_tt]: $($from_ty),*); - impl_into_bits!($arch_head[$test_tt]: $($into_ty),*); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// Implementations for the 64-bit wide vector types: - -// FIXME: 64-bit single element types -// FIXME: arm/aarch float16x4_t missing -impl_arch!( - [ - arm["arm"]: int8x8_t, - uint8x8_t, - poly8x8_t, - int16x4_t, - uint16x4_t, - poly16x4_t, - int32x2_t, - uint32x2_t, - float32x2_t, - int64x1_t, - uint64x1_t - ], - [ - aarch64["aarch64"]: int8x8_t, - uint8x8_t, - poly8x8_t, - int16x4_t, - uint16x4_t, - poly16x4_t, - int32x2_t, - uint32x2_t, - float32x2_t, - int64x1_t, - uint64x1_t, - float64x1_t - ] | from: i8x8, - u8x8, - m8x8, - i16x4, - u16x4, - m16x4, - i32x2, - u32x2, - f32x2, - m32x2 | into: i8x8, - u8x8, - i16x4, - u16x4, - i32x2, - u32x2, - f32x2 | test: test_v64 -); - -//////////////////////////////////////////////////////////////////////////////// -// Implementations for the 128-bit wide vector types: - -// FIXME: arm/aarch float16x8_t missing -// FIXME: ppc vector_pixel missing -// FIXME: ppc64 vector_Float16 missing -// FIXME: ppc64 vector_signed_long_long missing -// FIXME: ppc64 vector_unsigned_long_long missing -// FIXME: ppc64 vector_bool_long_long missing -// FIXME: ppc64 vector_signed___int128 missing -// FIXME: ppc64 vector_unsigned___int128 missing -impl_arch!( - [x86["x86"]: __m128, __m128i, __m128d], - [x86_64["x86_64"]: __m128, __m128i, __m128d], - [ - arm["arm"]: int8x16_t, - uint8x16_t, - poly8x16_t, - int16x8_t, - uint16x8_t, - poly16x8_t, - int32x4_t, - uint32x4_t, - float32x4_t, - int64x2_t, - uint64x2_t - ], - [ - aarch64["aarch64"]: int8x16_t, - uint8x16_t, - poly8x16_t, - int16x8_t, - uint16x8_t, - poly16x8_t, - int32x4_t, - uint32x4_t, - float32x4_t, - int64x2_t, - uint64x2_t, - float64x2_t - ], - [ - powerpc["powerpc"]: vector_signed_char, - vector_unsigned_char, - vector_signed_short, - vector_unsigned_short, - vector_signed_int, - vector_unsigned_int, - vector_float - ], - [ - powerpc64["powerpc64"]: vector_signed_char, - vector_unsigned_char, - vector_signed_short, - vector_unsigned_short, - vector_signed_int, - vector_unsigned_int, - vector_float, - vector_signed_long, - vector_unsigned_long, - vector_double - ] | from: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 | into: i8x16, - u8x16, - i16x8, - u16x8, - i32x4, - u32x4, - f32x4, - i64x2, - u64x2, - f64x2, - i128x1, - u128x1 | test: test_v128 -); - -impl_arch!( - [powerpc["powerpc"]: vector_bool_char], - [powerpc64["powerpc64"]: vector_bool_char] | from: m8x16, - m16x8, - m32x4, - m64x2, - m128x1 | into: i8x16, - u8x16, - i16x8, - u16x8, - i32x4, - u32x4, - f32x4, - i64x2, - u64x2, - f64x2, - i128x1, - u128x1, - // Masks: - m8x16 | test: test_v128 -); - -impl_arch!( - [powerpc["powerpc"]: vector_bool_short], - [powerpc64["powerpc64"]: vector_bool_short] | from: m16x8, - m32x4, - m64x2, - m128x1 | into: i8x16, - u8x16, - i16x8, - u16x8, - i32x4, - u32x4, - f32x4, - i64x2, - u64x2, - f64x2, - i128x1, - u128x1, - // Masks: - m8x16, - m16x8 | test: test_v128 -); - -impl_arch!( - [powerpc["powerpc"]: vector_bool_int], - [powerpc64["powerpc64"]: vector_bool_int] | from: m32x4, - m64x2, - m128x1 | into: i8x16, - u8x16, - i16x8, - u16x8, - i32x4, - u32x4, - f32x4, - i64x2, - u64x2, - f64x2, - i128x1, - u128x1, - // Masks: - m8x16, - m16x8, - m32x4 | test: test_v128 -); - -impl_arch!( - [powerpc64["powerpc64"]: vector_bool_long] | from: m64x2, - m128x1 | into: i8x16, - u8x16, - i16x8, - u16x8, - i32x4, - u32x4, - f32x4, - i64x2, - u64x2, - f64x2, - i128x1, - u128x1, - // Masks: - m8x16, - m16x8, - m32x4, - m64x2 | test: test_v128 -); - -//////////////////////////////////////////////////////////////////////////////// -// Implementations for the 256-bit wide vector types - -impl_arch!( - [x86["x86"]: __m256, __m256i, __m256d], - [x86_64["x86_64"]: __m256, __m256i, __m256d] | from: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 | into: i8x32, - u8x32, - i16x16, - u16x16, - i32x8, - u32x8, - f32x8, - i64x4, - u64x4, - f64x4, - i128x2, - u128x2 | test: test_v256 -); - -//////////////////////////////////////////////////////////////////////////////// -// FIXME: Implementations for the 512-bit wide vector types diff --git a/third_party/rust/packed_simd/src/api/into_bits/macros.rs b/third_party/rust/packed_simd/src/api/into_bits/macros.rs deleted file mode 100644 index 265ab34ae0..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/macros.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Macros implementing `FromBits` - -macro_rules! impl_from_bits_ { - ($id:ident[$test_tt:tt]: $from_ty:ident) => { - impl crate::api::into_bits::FromBits<$from_ty> for $id { - #[inline] - fn from_bits(x: $from_ty) -> Self { - unsafe { crate::mem::transmute(x) } - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _from_bits_ $from_ty>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test() { - use crate::{ - ptr::{read_unaligned}, - mem::{size_of, zeroed} - }; - use crate::IntoBits; - assert_eq!(size_of::<$id>(), - size_of::<$from_ty>()); - // This is safe because we never create a reference to - // uninitialized memory: - let a: $from_ty = unsafe { zeroed() }; - - let b_0: $id = crate::FromBits::from_bits(a); - let b_1: $id = a.into_bits(); - - // Check that these are byte-wise equal, that is, - // that the bit patterns are identical: - for i in 0..size_of::<$id>() { - // This is safe because we only read initialized - // memory in bounds. Also, taking a reference to - // `b_i` is ok because the fields are initialized. - unsafe { - let b_0_v: u8 = read_unaligned( - (&b_0 as *const $id as *const u8) - .wrapping_add(i) - ); - let b_1_v: u8 = read_unaligned( - (&b_1 as *const $id as *const u8) - .wrapping_add(i) - ); - assert_eq!(b_0_v, b_1_v); - } - } - } - } - } - } - }; -} - -macro_rules! impl_from_bits { - ($id:ident[$test_tt:tt]: $($from_ty:ident),*) => { - $( - impl_from_bits_!($id[$test_tt]: $from_ty); - )* - } -} - -#[allow(unused)] -macro_rules! impl_into_bits { - ($id:ident[$test_tt:tt]: $($from_ty:ident),*) => { - $( - impl_from_bits_!($from_ty[$test_tt]: $id); - )* - } -} diff --git a/third_party/rust/packed_simd/src/api/into_bits/v128.rs b/third_party/rust/packed_simd/src/api/into_bits/v128.rs deleted file mode 100644 index 639c09c2c4..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/v128.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! `FromBits` and `IntoBits` implementations for portable 128-bit wide vectors -#[rustfmt::skip] - -#[allow(unused)] // wasm_bindgen_test -use crate::*; - -impl_from_bits!( - i8x16[test_v128]: u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!( - u8x16[test_v128]: i8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!(m8x16[test_v128]: m16x8, m32x4, m64x2, m128x1); - -impl_from_bits!( - i16x8[test_v128]: i8x16, - u8x16, - m8x16, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!( - u16x8[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!(m16x8[test_v128]: m32x4, m64x2, m128x1); - -impl_from_bits!( - i32x4[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!( - u32x4[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!( - f32x4[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!(m32x4[test_v128]: m64x2, m128x1); - -impl_from_bits!( - i64x2[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - u64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!( - u64x2[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - f64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!( - f64x2[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - m64x2, - i128x1, - u128x1, - m128x1 -); -impl_from_bits!(m64x2[test_v128]: m128x1); - -impl_from_bits!( - i128x1[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - u128x1, - m128x1 -); -impl_from_bits!( - u128x1[test_v128]: i8x16, - u8x16, - m8x16, - i16x8, - u16x8, - m16x8, - i32x4, - u32x4, - f32x4, - m32x4, - i64x2, - u64x2, - f64x2, - m64x2, - i128x1, - m128x1 -); -// note: m128x1 cannot be constructed from all the other masks bit patterns in -// here diff --git a/third_party/rust/packed_simd/src/api/into_bits/v16.rs b/third_party/rust/packed_simd/src/api/into_bits/v16.rs deleted file mode 100644 index e44d0e7f9a..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/v16.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! `FromBits` and `IntoBits` implementations for portable 16-bit wide vectors -#[rustfmt::skip] - -#[allow(unused)] // wasm_bindgen_test -use crate::*; - -impl_from_bits!(i8x2[test_v16]: u8x2, m8x2); -impl_from_bits!(u8x2[test_v16]: i8x2, m8x2); -// note: m8x2 cannot be constructed from all i8x2 or u8x2 bit patterns diff --git a/third_party/rust/packed_simd/src/api/into_bits/v256.rs b/third_party/rust/packed_simd/src/api/into_bits/v256.rs deleted file mode 100644 index e432bbbc9f..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/v256.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! `FromBits` and `IntoBits` implementations for portable 256-bit wide vectors -#[rustfmt::skip] - -#[allow(unused)] // wasm_bindgen_test -use crate::*; - -impl_from_bits!( - i8x32[test_v256]: u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!( - u8x32[test_v256]: i8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!(m8x32[test_v256]: m16x16, m32x8, m64x4, m128x2); - -impl_from_bits!( - i16x16[test_v256]: i8x32, - u8x32, - m8x32, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!( - u16x16[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!(m16x16[test_v256]: m32x8, m64x4, m128x2); - -impl_from_bits!( - i32x8[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!( - u32x8[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!( - f32x8[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!(m32x8[test_v256]: m64x4, m128x2); - -impl_from_bits!( - i64x4[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - u64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!( - u64x4[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - f64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!( - f64x4[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - m64x4, - i128x2, - u128x2, - m128x2 -); -impl_from_bits!(m64x4[test_v256]: m128x2); - -impl_from_bits!( - i128x2[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - u128x2, - m128x2 -); -impl_from_bits!( - u128x2[test_v256]: i8x32, - u8x32, - m8x32, - i16x16, - u16x16, - m16x16, - i32x8, - u32x8, - f32x8, - m32x8, - i64x4, - u64x4, - f64x4, - m64x4, - i128x2, - m128x2 -); -// note: m128x2 cannot be constructed from all the other masks bit patterns in -// here diff --git a/third_party/rust/packed_simd/src/api/into_bits/v32.rs b/third_party/rust/packed_simd/src/api/into_bits/v32.rs deleted file mode 100644 index 5dba38a179..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/v32.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! `FromBits` and `IntoBits` implementations for portable 32-bit wide vectors -#[rustfmt::skip] - -#[allow(unused)] // wasm_bindgen_test -use crate::*; - -impl_from_bits!(i8x4[test_v32]: u8x4, m8x4, i16x2, u16x2, m16x2); -impl_from_bits!(u8x4[test_v32]: i8x4, m8x4, i16x2, u16x2, m16x2); -impl_from_bits!(m8x4[test_v32]: m16x2); - -impl_from_bits!(i16x2[test_v32]: i8x4, u8x4, m8x4, u16x2, m16x2); -impl_from_bits!(u16x2[test_v32]: i8x4, u8x4, m8x4, i16x2, m16x2); -// note: m16x2 cannot be constructed from all m8x4 bit patterns diff --git a/third_party/rust/packed_simd/src/api/into_bits/v512.rs b/third_party/rust/packed_simd/src/api/into_bits/v512.rs deleted file mode 100644 index f6e9bb8bf7..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/v512.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! `FromBits` and `IntoBits` implementations for portable 512-bit wide vectors -#[rustfmt::skip] - -#[allow(unused)] // wasm_bindgen_test -use crate::*; - -impl_from_bits!( - i8x64[test_v512]: u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!( - u8x64[test_v512]: i8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!(m8x64[test_v512]: m16x32, m32x16, m64x8, m128x4); - -impl_from_bits!( - i16x32[test_v512]: i8x64, - u8x64, - m8x64, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!( - u16x32[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!(m16x32[test_v512]: m32x16, m64x8, m128x4); - -impl_from_bits!( - i32x16[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!( - u32x16[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!( - f32x16[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!(m32x16[test_v512]: m64x8, m128x4); - -impl_from_bits!( - i64x8[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - u64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!( - u64x8[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - f64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!( - f64x8[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - m64x8, - i128x4, - u128x4, - m128x4 -); -impl_from_bits!(m64x8[test_v512]: m128x4); - -impl_from_bits!( - i128x4[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - u128x4, - m128x4 -); -impl_from_bits!( - u128x4[test_v512]: i8x64, - u8x64, - m8x64, - i16x32, - u16x32, - m16x32, - i32x16, - u32x16, - f32x16, - m32x16, - i64x8, - u64x8, - f64x8, - m64x8, - i128x4, - m128x4 -); -// note: m128x4 cannot be constructed from all the other masks bit patterns in -// here diff --git a/third_party/rust/packed_simd/src/api/into_bits/v64.rs b/third_party/rust/packed_simd/src/api/into_bits/v64.rs deleted file mode 100644 index 5b065f1bd5..0000000000 --- a/third_party/rust/packed_simd/src/api/into_bits/v64.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! `FromBits` and `IntoBits` implementations for portable 64-bit wide vectors -#[rustfmt::skip] - -#[allow(unused)] // wasm_bindgen_test -use crate::*; - -impl_from_bits!(i8x8[test_v64]: u8x8, m8x8, i16x4, u16x4, m16x4, i32x2, u32x2, f32x2, m32x2); -impl_from_bits!(u8x8[test_v64]: i8x8, m8x8, i16x4, u16x4, m16x4, i32x2, u32x2, f32x2, m32x2); -impl_from_bits!(m8x8[test_v64]: m16x4, m32x2); - -impl_from_bits!(i16x4[test_v64]: i8x8, u8x8, m8x8, u16x4, m16x4, i32x2, u32x2, f32x2, m32x2); -impl_from_bits!(u16x4[test_v64]: i8x8, u8x8, m8x8, i16x4, m16x4, i32x2, u32x2, f32x2, m32x2); -impl_from_bits!(m16x4[test_v64]: m32x2); - -impl_from_bits!(i32x2[test_v64]: i8x8, u8x8, m8x8, i16x4, u16x4, m16x4, u32x2, f32x2, m32x2); -impl_from_bits!(u32x2[test_v64]: i8x8, u8x8, m8x8, i16x4, u16x4, m16x4, i32x2, f32x2, m32x2); -impl_from_bits!(f32x2[test_v64]: i8x8, u8x8, m8x8, i16x4, u16x4, m16x4, i32x2, u32x2, m32x2); -// note: m32x2 cannot be constructed from all m16x4 or m8x8 bit patterns diff --git a/third_party/rust/packed_simd/src/api/math.rs b/third_party/rust/packed_simd/src/api/math.rs deleted file mode 100644 index e7a8d256ba..0000000000 --- a/third_party/rust/packed_simd/src/api/math.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Implements vertical math operations - -#[macro_use] -mod float; diff --git a/third_party/rust/packed_simd/src/api/math/float.rs b/third_party/rust/packed_simd/src/api/math/float.rs deleted file mode 100644 index d5d2bee2eb..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Implements vertical floating-point math operations. - -#[macro_use] -mod abs; - -#[macro_use] -mod consts; - -#[macro_use] -mod cos; - -#[macro_use] -mod exp; - -#[macro_use] -mod powf; - -#[macro_use] -mod ln; - -#[macro_use] -mod mul_add; - -#[macro_use] -mod mul_adde; - -#[macro_use] -mod recpre; - -#[macro_use] -mod rsqrte; - -#[macro_use] -mod sin; - -#[macro_use] -mod sqrt; - -#[macro_use] -mod sqrte; - -#[macro_use] -mod tanh; - -macro_rules! impl_float_category { - ([$elem_ty:ident; $elem_count:expr]: $id:ident, $mask_ty:ident) => { - impl $id { - #[inline] - pub fn is_nan(self) -> $mask_ty { - self.ne(self) - } - - #[inline] - pub fn is_infinite(self) -> $mask_ty { - self.eq(Self::INFINITY) | self.eq(Self::NEG_INFINITY) - } - - #[inline] - pub fn is_finite(self) -> $mask_ty { - !(self.is_nan() | self.is_infinite()) - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/abs.rs b/third_party/rust/packed_simd/src/api/math/float/abs.rs deleted file mode 100644 index 1865bdb68e..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/abs.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `abs`. - -macro_rules! impl_math_float_abs { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Absolute value. - #[inline] - pub fn abs(self) -> Self { - use crate::codegen::math::float::abs::Abs; - Abs::abs(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_abs>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn abs() { - let o = $id::splat(1 as $elem_ty); - assert_eq!(o, o.abs()); - - let mo = $id::splat(-1 as $elem_ty); - assert_eq!(o, mo.abs()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/consts.rs b/third_party/rust/packed_simd/src/api/math/float/consts.rs deleted file mode 100644 index 7f41acbf1b..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/consts.rs +++ /dev/null @@ -1,74 +0,0 @@ -macro_rules! impl_float_consts { - ([$elem_ty:ident; $elem_count:expr]: $id:ident) => { - impl $id { - /// Machine epsilon value. - pub const EPSILON: $id = $id::splat(core::$elem_ty::EPSILON); - - /// Smallest finite value. - pub const MIN: $id = $id::splat(core::$elem_ty::MIN); - - /// Smallest positive normal value. - pub const MIN_POSITIVE: $id = $id::splat(core::$elem_ty::MIN_POSITIVE); - - /// Largest finite value. - pub const MAX: $id = $id::splat(core::$elem_ty::MAX); - - /// Not a Number (NaN). - pub const NAN: $id = $id::splat(core::$elem_ty::NAN); - - /// Infinity (∞). - pub const INFINITY: $id = $id::splat(core::$elem_ty::INFINITY); - - /// Negative infinity (-∞). - pub const NEG_INFINITY: $id = $id::splat(core::$elem_ty::NEG_INFINITY); - - /// Archimedes' constant (π) - pub const PI: $id = $id::splat(core::$elem_ty::consts::PI); - - /// π/2 - pub const FRAC_PI_2: $id = $id::splat(core::$elem_ty::consts::FRAC_PI_2); - - /// π/3 - pub const FRAC_PI_3: $id = $id::splat(core::$elem_ty::consts::FRAC_PI_3); - - /// π/4 - pub const FRAC_PI_4: $id = $id::splat(core::$elem_ty::consts::FRAC_PI_4); - - /// π/6 - pub const FRAC_PI_6: $id = $id::splat(core::$elem_ty::consts::FRAC_PI_6); - - /// π/8 - pub const FRAC_PI_8: $id = $id::splat(core::$elem_ty::consts::FRAC_PI_8); - - /// 1/π - pub const FRAC_1_PI: $id = $id::splat(core::$elem_ty::consts::FRAC_1_PI); - - /// 2/π - pub const FRAC_2_PI: $id = $id::splat(core::$elem_ty::consts::FRAC_2_PI); - - /// 2/sqrt(π) - pub const FRAC_2_SQRT_PI: $id = $id::splat(core::$elem_ty::consts::FRAC_2_SQRT_PI); - - /// sqrt(2) - pub const SQRT_2: $id = $id::splat(core::$elem_ty::consts::SQRT_2); - - /// 1/sqrt(2) - pub const FRAC_1_SQRT_2: $id = $id::splat(core::$elem_ty::consts::FRAC_1_SQRT_2); - - /// Euler's number (e) - pub const E: $id = $id::splat(core::$elem_ty::consts::E); - - /// log2(e) - pub const LOG2_E: $id = $id::splat(core::$elem_ty::consts::LOG2_E); - - /// log10(e) - pub const LOG10_E: $id = $id::splat(core::$elem_ty::consts::LOG10_E); - - /// ln(2) - pub const LN_2: $id = $id::splat(core::$elem_ty::consts::LN_2); - - /// ln(10) - pub const LN_10: $id = $id::splat(core::$elem_ty::consts::LN_10); - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/cos.rs b/third_party/rust/packed_simd/src/api/math/float/cos.rs deleted file mode 100644 index e5b8f46036..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/cos.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `cos`. - -macro_rules! impl_math_float_cos { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Cosine. - #[inline] - pub fn cos(self) -> Self { - use crate::codegen::math::float::cos::Cos; - Cos::cos(self) - } - - /// Cosine of `self * PI`. - #[inline] - pub fn cos_pi(self) -> Self { - use crate::codegen::math::float::cos_pi::CosPi; - CosPi::cos_pi(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_cos>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn cos() { - use crate::$elem_ty::consts::PI; - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let p = $id::splat(PI as $elem_ty); - let ph = $id::splat(PI as $elem_ty / 2.); - let z_r = $id::splat((PI as $elem_ty / 2.).cos()); - let o_r = $id::splat((PI as $elem_ty).cos()); - - assert_eq!(o, z.cos()); - assert_eq!(z_r, ph.cos()); - assert_eq!(o_r, p.cos()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/exp.rs b/third_party/rust/packed_simd/src/api/math/float/exp.rs deleted file mode 100644 index e3356d853a..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/exp.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `exp`. - -macro_rules! impl_math_float_exp { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Returns the exponential function of `self`: `e^(self)`. - #[inline] - pub fn exp(self) -> Self { - use crate::codegen::math::float::exp::Exp; - Exp::exp(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_exp>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn exp() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - assert_eq!(o, z.exp()); - - let e = $id::splat(crate::f64::consts::E as $elem_ty); - let tol = $id::splat(2.4e-4 as $elem_ty); - assert!((e - o.exp()).abs().le(tol).all()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/ln.rs b/third_party/rust/packed_simd/src/api/math/float/ln.rs deleted file mode 100644 index 5ceb9173ae..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/ln.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `ln`. - -macro_rules! impl_math_float_ln { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Returns the natural logarithm of `self`. - #[inline] - pub fn ln(self) -> Self { - use crate::codegen::math::float::ln::Ln; - Ln::ln(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_ln>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn ln() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - assert_eq!(z, o.ln()); - - let e = $id::splat(crate::f64::consts::E as $elem_ty); - let tol = $id::splat(2.4e-4 as $elem_ty); - assert!((o - e.ln()).abs().le(tol).all()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/mul_add.rs b/third_party/rust/packed_simd/src/api/math/float/mul_add.rs deleted file mode 100644 index 4b170ee2b7..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/mul_add.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `mul_add`. - -macro_rules! impl_math_float_mul_add { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Fused multiply add: `self * y + z` - #[inline] - pub fn mul_add(self, y: Self, z: Self) -> Self { - use crate::codegen::math::float::mul_add::MulAdd; - MulAdd::mul_add(self, y, z) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_mul_add>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn mul_add() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let t3 = $id::splat(3 as $elem_ty); - let f = $id::splat(4 as $elem_ty); - - assert_eq!(z, z.mul_add(z, z)); - assert_eq!(o, o.mul_add(o, z)); - assert_eq!(o, o.mul_add(z, o)); - assert_eq!(o, z.mul_add(o, o)); - - assert_eq!(t, o.mul_add(o, o)); - assert_eq!(t, o.mul_add(t, z)); - assert_eq!(t, t.mul_add(o, z)); - - assert_eq!(f, t.mul_add(t, z)); - assert_eq!(f, t.mul_add(o, t)); - assert_eq!(t3, t.mul_add(o, o)); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/mul_adde.rs b/third_party/rust/packed_simd/src/api/math/float/mul_adde.rs deleted file mode 100644 index c5b27110f2..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/mul_adde.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `mul_adde`. - -macro_rules! impl_math_float_mul_adde { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Fused multiply add estimate: ~= `self * y + z` - /// - /// While fused multiply-add (`fma`) has infinite precision, - /// `mul_adde` has _at worst_ the same precision of a multiply followed by an add. - /// This might be more efficient on architectures that do not have an `fma` instruction. - #[inline] - pub fn mul_adde(self, y: Self, z: Self) -> Self { - use crate::codegen::math::float::mul_adde::MulAddE; - MulAddE::mul_adde(self, y, z) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_mul_adde>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn mul_adde() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let t3 = $id::splat(3 as $elem_ty); - let f = $id::splat(4 as $elem_ty); - - assert_eq!(z, z.mul_adde(z, z)); - assert_eq!(o, o.mul_adde(o, z)); - assert_eq!(o, o.mul_adde(z, o)); - assert_eq!(o, z.mul_adde(o, o)); - - assert_eq!(t, o.mul_adde(o, o)); - assert_eq!(t, o.mul_adde(t, z)); - assert_eq!(t, t.mul_adde(o, z)); - - assert_eq!(f, t.mul_adde(t, z)); - assert_eq!(f, t.mul_adde(o, t)); - assert_eq!(t3, t.mul_adde(o, o)); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/powf.rs b/third_party/rust/packed_simd/src/api/math/float/powf.rs deleted file mode 100644 index 83dc9ff9c0..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/powf.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `powf`. - -macro_rules! impl_math_float_powf { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Raises `self` number to the floating point power of `x`. - #[inline] - pub fn powf(self, x: Self) -> Self { - use crate::codegen::math::float::powf::Powf; - Powf::powf(self, x) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_powf>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn powf() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - assert_eq!(o, o.powf(z)); - assert_eq!(o, t.powf(z)); - assert_eq!(o, o.powf(o)); - assert_eq!(t, t.powf(o)); - - let f = $id::splat(4 as $elem_ty); - assert_eq!(f, t.powf(t)); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/recpre.rs b/third_party/rust/packed_simd/src/api/math/float/recpre.rs deleted file mode 100644 index 127f0b2ff6..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/recpre.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `recpre`. - -macro_rules! impl_math_float_recpre { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Reciprocal estimate: `~= 1. / self`. - /// - /// FIXME: The precision of the estimate is currently unspecified. - #[inline] - pub fn recpre(self) -> Self { - $id::splat(1.) / self - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_recpre>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn recpre() { - let tol = $id::splat(2.4e-4 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let error = (o - o.recpre()).abs(); - assert!(error.le(tol).all()); - - let t = $id::splat(2 as $elem_ty); - let e = 0.5; - let error = (e - t.recpre()).abs(); - assert!(error.le(tol).all()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/rsqrte.rs b/third_party/rust/packed_simd/src/api/math/float/rsqrte.rs deleted file mode 100644 index c77977f7b1..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/rsqrte.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `rsqrte`. - -macro_rules! impl_math_float_rsqrte { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Reciprocal square-root estimate: `~= 1. / self.sqrt()`. - /// - /// FIXME: The precision of the estimate is currently unspecified. - #[inline] - pub fn rsqrte(self) -> Self { - unsafe { - use crate::llvm::simd_fsqrt; - $id::splat(1.) / Simd(simd_fsqrt(self.0)) - } - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_rsqrte>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn rsqrte() { - use crate::$elem_ty::consts::SQRT_2; - let tol = $id::splat(2.4e-4 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let error = (o - o.rsqrte()).abs(); - assert!(error.le(tol).all()); - - let t = $id::splat(2 as $elem_ty); - let e = 1. / SQRT_2; - let error = (e - t.rsqrte()).abs(); - assert!(error.le(tol).all()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/sin.rs b/third_party/rust/packed_simd/src/api/math/float/sin.rs deleted file mode 100644 index 49908319b1..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/sin.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `sin`. - -macro_rules! impl_math_float_sin { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Sine. - #[inline] - pub fn sin(self) -> Self { - use crate::codegen::math::float::sin::Sin; - Sin::sin(self) - } - - /// Sine of `self * PI`. - #[inline] - pub fn sin_pi(self) -> Self { - use crate::codegen::math::float::sin_pi::SinPi; - SinPi::sin_pi(self) - } - - /// Sine and cosine of `self * PI`. - #[inline] - pub fn sin_cos_pi(self) -> (Self, Self) { - use crate::codegen::math::float::sin_cos_pi::SinCosPi; - SinCosPi::sin_cos_pi(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_sin>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn sin() { - use crate::$elem_ty::consts::PI; - let z = $id::splat(0 as $elem_ty); - let p = $id::splat(PI as $elem_ty); - let ph = $id::splat(PI as $elem_ty / 2.); - let o_r = $id::splat((PI as $elem_ty / 2.).sin()); - let z_r = $id::splat((PI as $elem_ty).sin()); - - assert_eq!(z, z.sin()); - assert_eq!(o_r, ph.sin()); - assert_eq!(z_r, p.sin()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/sqrt.rs b/third_party/rust/packed_simd/src/api/math/float/sqrt.rs deleted file mode 100644 index ae624122d0..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/sqrt.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `sqrt`. - -macro_rules! impl_math_float_sqrt { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - #[inline] - pub fn sqrt(self) -> Self { - use crate::codegen::math::float::sqrt::Sqrt; - Sqrt::sqrt(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_sqrt>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn sqrt() { - use crate::$elem_ty::consts::SQRT_2; - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - assert_eq!(z, z.sqrt()); - assert_eq!(o, o.sqrt()); - - let t = $id::splat(2 as $elem_ty); - let e = $id::splat(SQRT_2); - assert_eq!(e, t.sqrt()); - - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/sqrte.rs b/third_party/rust/packed_simd/src/api/math/float/sqrte.rs deleted file mode 100644 index f7ffad748d..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/sqrte.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `sqrte`. - -macro_rules! impl_math_float_sqrte { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Square-root estimate. - /// - /// FIXME: The precision of the estimate is currently unspecified. - #[inline] - pub fn sqrte(self) -> Self { - use crate::codegen::math::float::sqrte::Sqrte; - Sqrte::sqrte(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_sqrte>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn sqrte() { - use crate::$elem_ty::consts::SQRT_2; - let tol = $id::splat(2.4e-4 as $elem_ty); - - let z = $id::splat(0 as $elem_ty); - let error = (z - z.sqrte()).abs(); - assert!(error.le(tol).all()); - - let o = $id::splat(1 as $elem_ty); - let error = (o - o.sqrte()).abs(); - assert!(error.le(tol).all()); - - let t = $id::splat(2 as $elem_ty); - let e = $id::splat(SQRT_2 as $elem_ty); - let error = (e - t.sqrte()).abs(); - - assert!(error.le(tol).all()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/math/float/tanh.rs b/third_party/rust/packed_simd/src/api/math/float/tanh.rs deleted file mode 100644 index acfd93caaa..0000000000 --- a/third_party/rust/packed_simd/src/api/math/float/tanh.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Implements vertical (lane-wise) floating-point `tanh`. - -macro_rules! impl_math_float_tanh { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Tanh. - #[inline] - pub fn tanh(self) -> Self { - use crate::codegen::math::float::tanh::Tanh; - Tanh::tanh(self) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _math_tanh>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn tanh() { - let z = $id::splat(0 as $elem_ty); - - assert_eq!(z, z.tanh()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/minimal.rs b/third_party/rust/packed_simd/src/api/minimal.rs deleted file mode 100644 index 840d9e3258..0000000000 --- a/third_party/rust/packed_simd/src/api/minimal.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[macro_use] -mod iuf; -#[macro_use] -mod mask; -#[macro_use] -mod ptr; diff --git a/third_party/rust/packed_simd/src/api/minimal/iuf.rs b/third_party/rust/packed_simd/src/api/minimal/iuf.rs deleted file mode 100644 index a155ac178a..0000000000 --- a/third_party/rust/packed_simd/src/api/minimal/iuf.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! Minimal API of signed integer, unsigned integer, and floating-point -//! vectors. - -macro_rules! impl_minimal_iuf { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $ielem_ty:ident | - $test_tt:tt | $($elem_name:ident),+ | $(#[$doc:meta])*) => { - - $(#[$doc])* - pub type $id = Simd<[$elem_ty; $elem_count]>; - - impl sealed::Simd for $id { - type Element = $elem_ty; - const LANES: usize = $elem_count; - type LanesType = [u32; $elem_count]; - } - - impl $id { - /// Creates a new instance with each vector elements initialized - /// with the provided values. - #[inline] - #[allow(clippy::too_many_arguments)] - pub const fn new($($elem_name: $elem_ty),*) -> Self { - Simd(codegen::$id($($elem_name as $ielem_ty),*)) - } - - /// Returns the number of vector lanes. - #[inline] - pub const fn lanes() -> usize { - $elem_count - } - - /// Constructs a new instance with each element initialized to - /// `value`. - #[inline] - pub const fn splat(value: $elem_ty) -> Self { - Simd(codegen::$id($({ - #[allow(non_camel_case_types, dead_code)] - struct $elem_name; - value as $ielem_ty - }),*)) - } - - /// Extracts the value at `index`. - /// - /// # Panics - /// - /// If `index >= Self::lanes()`. - #[inline] - pub fn extract(self, index: usize) -> $elem_ty { - assert!(index < $elem_count); - unsafe { self.extract_unchecked(index) } - } - - /// Extracts the value at `index`. - /// - /// # Safety - /// - /// If `index >= Self::lanes()` the behavior is undefined. - #[inline] - pub unsafe fn extract_unchecked(self, index: usize) -> $elem_ty { - use crate::llvm::simd_extract; - let e: $ielem_ty = simd_extract(self.0, index as u32); - e as $elem_ty - } - - /// Returns a new vector where the value at `index` is replaced by `new_value`. - /// - /// # Panics - /// - /// If `index >= Self::lanes()`. - #[inline] - #[must_use = "replace does not modify the original value - \ - it returns a new vector with the value at `index` \ - replaced by `new_value`d" - ] - pub fn replace(self, index: usize, new_value: $elem_ty) -> Self { - assert!(index < $elem_count); - unsafe { self.replace_unchecked(index, new_value) } - } - - /// Returns a new vector where the value at `index` is replaced by `new_value`. - /// - /// # Safety - /// - /// If `index >= Self::lanes()` the behavior is undefined. - #[inline] - #[must_use = "replace_unchecked does not modify the original value - \ - it returns a new vector with the value at `index` \ - replaced by `new_value`d" - ] - pub unsafe fn replace_unchecked( - self, - index: usize, - new_value: $elem_ty, - ) -> Self { - use crate::llvm::simd_insert; - Simd(simd_insert(self.0, index as u32, new_value as $ielem_ty)) - } - } - - test_if!{ - $test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - pub mod [<$id _minimal>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn minimal() { - // lanes: - assert_eq!($elem_count, $id::lanes()); - - // splat and extract / extract_unchecked: - const VAL: $elem_ty = 7 as $elem_ty; - const VEC: $id = $id::splat(VAL); - for i in 0..$id::lanes() { - assert_eq!(VAL, VEC.extract(i)); - assert_eq!( - VAL, unsafe { VEC.extract_unchecked(i) } - ); - } - - // replace / replace_unchecked - let new_vec = VEC.replace(0, 42 as $elem_ty); - for i in 0..$id::lanes() { - if i == 0 { - assert_eq!(42 as $elem_ty, new_vec.extract(i)); - } else { - assert_eq!(VAL, new_vec.extract(i)); - } - } - let new_vec = unsafe { - VEC.replace_unchecked(0, 42 as $elem_ty) - }; - for i in 0..$id::lanes() { - if i == 0 { - assert_eq!(42 as $elem_ty, new_vec.extract(i)); - } else { - assert_eq!(VAL, new_vec.extract(i)); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn extract_panic_oob() { - const VAL: $elem_ty = 7 as $elem_ty; - const VEC: $id = $id::splat(VAL); - let _ = VEC.extract($id::lanes()); - } - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn replace_panic_oob() { - const VAL: $elem_ty = 7 as $elem_ty; - const VEC: $id = $id::splat(VAL); - let _ = VEC.replace($id::lanes(), 42 as $elem_ty); - } - } - } - } - } -} diff --git a/third_party/rust/packed_simd/src/api/minimal/mask.rs b/third_party/rust/packed_simd/src/api/minimal/mask.rs deleted file mode 100644 index a420060b42..0000000000 --- a/third_party/rust/packed_simd/src/api/minimal/mask.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! Minimal API of mask vectors. - -macro_rules! impl_minimal_mask { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $ielem_ty:ident - | $test_tt:tt | $($elem_name:ident),+ | $(#[$doc:meta])*) => { - $(#[$doc])* - pub type $id = Simd<[$elem_ty; $elem_count]>; - - impl sealed::Simd for $id { - type Element = $elem_ty; - const LANES: usize = $elem_count; - type LanesType = [u32; $elem_count]; - } - - impl $id { - /// Creates a new instance with each vector elements initialized - /// with the provided values. - #[inline] - #[allow(clippy::too_many_arguments)] - pub const fn new($($elem_name: bool),*) -> Self { - Simd(codegen::$id($(Self::bool_to_internal($elem_name)),*)) - } - - /// Converts a boolean type into the type of the vector lanes. - #[inline] - #[allow(clippy::indexing_slicing)] - const fn bool_to_internal(x: bool) -> $ielem_ty { - [0 as $ielem_ty, !(0 as $ielem_ty)][x as usize] - } - - /// Returns the number of vector lanes. - #[inline] - pub const fn lanes() -> usize { - $elem_count - } - - /// Constructs a new instance with each element initialized to - /// `value`. - #[inline] - pub const fn splat(value: bool) -> Self { - Simd(codegen::$id($({ - #[allow(non_camel_case_types, dead_code)] - struct $elem_name; - Self::bool_to_internal(value) - }),*)) - } - - /// Extracts the value at `index`. - /// - /// # Panics - /// - /// If `index >= Self::lanes()`. - #[inline] - pub fn extract(self, index: usize) -> bool { - assert!(index < $elem_count); - unsafe { self.extract_unchecked(index) } - } - - /// Extracts the value at `index`. - /// - /// # Safety - /// - /// If `index >= Self::lanes()` the behavior is undefined. - #[inline] - pub unsafe fn extract_unchecked(self, index: usize) -> bool { - use crate::llvm::simd_extract; - let x: $ielem_ty = simd_extract(self.0, index as u32); - x != 0 - } - - /// Returns a new vector where the value at `index` is replaced by - /// `new_value`. - /// - /// # Panics - /// - /// If `index >= Self::lanes()`. - #[inline] - #[must_use = "replace does not modify the original value - \ - it returns a new vector with the value at `index` \ - replaced by `new_value`d" - ] - pub fn replace(self, index: usize, new_value: bool) -> Self { - assert!(index < $elem_count); - unsafe { self.replace_unchecked(index, new_value) } - } - - /// Returns a new vector where the value at `index` is replaced by - /// `new_value`. - /// - /// # Safety - /// - /// If `index >= Self::lanes()` the behavior is undefined. - #[inline] - #[must_use = "replace_unchecked does not modify the original value - \ - it returns a new vector with the value at `index` \ - replaced by `new_value`d" - ] - pub unsafe fn replace_unchecked( - self, - index: usize, - new_value: bool, - ) -> Self { - use crate::llvm::simd_insert; - Simd(simd_insert(self.0, index as u32, - Self::bool_to_internal(new_value))) - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _minimal>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn minimal() { - // TODO: test new - - // lanes: - assert_eq!($elem_count, $id::lanes()); - - // splat and extract / extract_unchecked: - let vec = $id::splat(true); - for i in 0..$id::lanes() { - assert_eq!(true, vec.extract(i)); - assert_eq!(true, - unsafe { vec.extract_unchecked(i) } - ); - } - - // replace / replace_unchecked - let new_vec = vec.replace(0, false); - for i in 0..$id::lanes() { - if i == 0 { - assert_eq!(false, new_vec.extract(i)); - } else { - assert_eq!(true, new_vec.extract(i)); - } - } - let new_vec = unsafe { - vec.replace_unchecked(0, false) - }; - for i in 0..$id::lanes() { - if i == 0 { - assert_eq!(false, new_vec.extract(i)); - } else { - assert_eq!(true, new_vec.extract(i)); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn extract_panic_oob() { - let vec = $id::splat(false); - let _ = vec.extract($id::lanes()); - } - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn replace_panic_oob() { - let vec = $id::splat(false); - let _ = vec.replace($id::lanes(), true); - } - } - } - } - } -} diff --git a/third_party/rust/packed_simd/src/api/minimal/ptr.rs b/third_party/rust/packed_simd/src/api/minimal/ptr.rs deleted file mode 100644 index d9e47c9ccb..0000000000 --- a/third_party/rust/packed_simd/src/api/minimal/ptr.rs +++ /dev/null @@ -1,1373 +0,0 @@ -//! Minimal API of pointer vectors. - -macro_rules! impl_minimal_p { - ([$elem_ty:ty; $elem_count:expr]: $id:ident, $mask_ty:ident, - $usize_ty:ident, $isize_ty:ident | $ref:ident | $test_tt:tt - | $($elem_name:ident),+ | ($true:expr, $false:expr) | - $(#[$doc:meta])*) => { - - $(#[$doc])* - pub type $id = Simd<[$elem_ty; $elem_count]>; - - impl sealed::Simd for $id { - type Element = $elem_ty; - const LANES: usize = $elem_count; - type LanesType = [u32; $elem_count]; - } - - impl $id { - /// Creates a new instance with each vector elements initialized - /// with the provided values. - #[inline] - #[allow(clippy::too_many_arguments)] - pub const fn new($($elem_name: $elem_ty),*) -> Self { - Simd(codegen::$id($($elem_name),*)) - } - - /// Returns the number of vector lanes. - #[inline] - pub const fn lanes() -> usize { - $elem_count - } - - /// Constructs a new instance with each element initialized to - /// `value`. - #[inline] - pub const fn splat(value: $elem_ty) -> Self { - Simd(codegen::$id($({ - #[allow(non_camel_case_types, dead_code)] - struct $elem_name; - value - }),*)) - } - - /// Constructs a new instance with each element initialized to - /// `null`. - #[inline] - pub const fn null() -> Self { - Self::splat(crate::ptr::null_mut() as $elem_ty) - } - - /// Returns a mask that selects those lanes that contain `null` - /// pointers. - #[inline] - pub fn is_null(self) -> $mask_ty { - self.eq(Self::null()) - } - - /// Extracts the value at `index`. - /// - /// # Panics - /// - /// If `index >= Self::lanes()`. - #[inline] - pub fn extract(self, index: usize) -> $elem_ty { - assert!(index < $elem_count); - unsafe { self.extract_unchecked(index) } - } - - /// Extracts the value at `index`. - /// - /// # Safety - /// - /// If `index >= Self::lanes()` the behavior is undefined. - #[inline] - pub unsafe fn extract_unchecked(self, index: usize) -> $elem_ty { - use crate::llvm::simd_extract; - simd_extract(self.0, index as u32) - } - - /// Returns a new vector where the value at `index` is replaced by - /// `new_value`. - /// - /// # Panics - /// - /// If `index >= Self::lanes()`. - #[inline] - #[must_use = "replace does not modify the original value - \ - it returns a new vector with the value at `index` \ - replaced by `new_value`d" - ] - #[allow(clippy::not_unsafe_ptr_arg_deref)] - pub fn replace(self, index: usize, new_value: $elem_ty) -> Self { - assert!(index < $elem_count); - unsafe { self.replace_unchecked(index, new_value) } - } - - /// Returns a new vector where the value at `index` is replaced by `new_value`. - /// - /// # Safety - /// - /// If `index >= Self::lanes()` the behavior is undefined. - #[inline] - #[must_use = "replace_unchecked does not modify the original value - \ - it returns a new vector with the value at `index` \ - replaced by `new_value`d" - ] - pub unsafe fn replace_unchecked( - self, - index: usize, - new_value: $elem_ty, - ) -> Self { - use crate::llvm::simd_insert; - Simd(simd_insert(self.0, index as u32, new_value)) - } - } - - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _minimal>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn minimal() { - // lanes: - assert_eq!($elem_count, $id::::lanes()); - - // splat and extract / extract_unchecked: - let VAL7: <$id as sealed::Simd>::Element - = $ref!(7); - let VAL42: <$id as sealed::Simd>::Element - = $ref!(42); - let VEC: $id = $id::splat(VAL7); - for i in 0..$id::::lanes() { - assert_eq!(VAL7, VEC.extract(i)); - assert_eq!( - VAL7, unsafe { VEC.extract_unchecked(i) } - ); - } - - // replace / replace_unchecked - let new_vec = VEC.replace(0, VAL42); - for i in 0..$id::::lanes() { - if i == 0 { - assert_eq!(VAL42, new_vec.extract(i)); - } else { - assert_eq!(VAL7, new_vec.extract(i)); - } - } - let new_vec = unsafe { - VEC.replace_unchecked(0, VAL42) - }; - for i in 0..$id::::lanes() { - if i == 0 { - assert_eq!(VAL42, new_vec.extract(i)); - } else { - assert_eq!(VAL7, new_vec.extract(i)); - } - } - - let mut n = $id::::null(); - assert_eq!( - n, - $id::::splat(unsafe { crate::mem::zeroed() }) - ); - assert!(n.is_null().all()); - n = n.replace( - 0, unsafe { crate::mem::transmute(1_isize) } - ); - assert!(!n.is_null().all()); - if $id::::lanes() > 1 { - assert!(n.is_null().any()); - } else { - assert!(!n.is_null().any()); - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn extract_panic_oob() { - let VAL: <$id as sealed::Simd>::Element - = $ref!(7); - let VEC: $id = $id::splat(VAL); - let _ = VEC.extract($id::::lanes()); - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn replace_panic_oob() { - let VAL: <$id as sealed::Simd>::Element - = $ref!(7); - let VAL42: <$id as sealed::Simd>::Element - = $ref!(42); - let VEC: $id = $id::splat(VAL); - let _ = VEC.replace($id::::lanes(), VAL42); - } - } - } - } - - impl crate::fmt::Debug for $id { - #[allow(clippy::missing_inline_in_public_items)] - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) - -> crate::fmt::Result { - write!( - f, - "{}<{}>(", - stringify!($id), - crate::intrinsics::type_name::() - )?; - for i in 0..$elem_count { - if i > 0 { - write!(f, ", ")?; - } - self.extract(i).fmt(f)?; - } - write!(f, ")") - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _fmt_debug>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn debug() { - use arrayvec::{ArrayString,ArrayVec}; - type TinyString = ArrayString<[u8; 512]>; - - use crate::fmt::Write; - let v = $id::::default(); - let mut s = TinyString::new(); - write!(&mut s, "{:?}", v).unwrap(); - - let mut beg = TinyString::new(); - write!(&mut beg, "{}(", stringify!($id)).unwrap(); - assert!( - s.starts_with(beg.as_str()), - "s = {} (should start with = {})", s, beg - ); - assert!(s.ends_with(")")); - let s: ArrayVec<[TinyString; 64]> - = s.replace(beg.as_str(), "") - .replace(")", "").split(",") - .map(|v| TinyString::from(v.trim()).unwrap()) - .collect(); - assert_eq!(s.len(), $id::::lanes()); - for (index, ss) in s.into_iter().enumerate() { - let mut e = TinyString::new(); - write!(&mut e, "{:?}", v.extract(index)).unwrap(); - assert_eq!(ss, e); - } - } - } - } - } - - impl Default for $id { - #[inline] - fn default() -> Self { - // FIXME: ptrs do not implement default - Self::null() - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _default>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn default() { - let a = $id::::default(); - for i in 0..$id::::lanes() { - assert_eq!( - a.extract(i), unsafe { crate::mem::zeroed() } - ); - } - } - } - } - } - - impl $id { - /// Lane-wise equality comparison. - #[inline] - pub fn eq(self, other: Self) -> $mask_ty { - unsafe { - use crate::llvm::simd_eq; - let a: $usize_ty = crate::mem::transmute(self); - let b: $usize_ty = crate::mem::transmute(other); - Simd(simd_eq(a.0, b.0)) - } - } - - /// Lane-wise inequality comparison. - #[inline] - pub fn ne(self, other: Self) -> $mask_ty { - unsafe { - use crate::llvm::simd_ne; - let a: $usize_ty = crate::mem::transmute(self); - let b: $usize_ty = crate::mem::transmute(other); - Simd(simd_ne(a.0, b.0)) - } - } - - /// Lane-wise less-than comparison. - #[inline] - pub fn lt(self, other: Self) -> $mask_ty { - unsafe { - use crate::llvm::simd_lt; - let a: $usize_ty = crate::mem::transmute(self); - let b: $usize_ty = crate::mem::transmute(other); - Simd(simd_lt(a.0, b.0)) - } - } - - /// Lane-wise less-than-or-equals comparison. - #[inline] - pub fn le(self, other: Self) -> $mask_ty { - unsafe { - use crate::llvm::simd_le; - let a: $usize_ty = crate::mem::transmute(self); - let b: $usize_ty = crate::mem::transmute(other); - Simd(simd_le(a.0, b.0)) - } - } - - /// Lane-wise greater-than comparison. - #[inline] - pub fn gt(self, other: Self) -> $mask_ty { - unsafe { - use crate::llvm::simd_gt; - let a: $usize_ty = crate::mem::transmute(self); - let b: $usize_ty = crate::mem::transmute(other); - Simd(simd_gt(a.0, b.0)) - } - } - - /// Lane-wise greater-than-or-equals comparison. - #[inline] - pub fn ge(self, other: Self) -> $mask_ty { - unsafe { - use crate::llvm::simd_ge; - let a: $usize_ty = crate::mem::transmute(self); - let b: $usize_ty = crate::mem::transmute(other); - Simd(simd_ge(a.0, b.0)) - } - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_vertical>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn cmp() { - let a = $id::::null(); - let b = $id::::splat(unsafe { - crate::mem::transmute(1_isize) - }); - - let r = a.lt(b); - let e = $mask_ty::splat(true); - assert!(r == e); - let r = a.le(b); - assert!(r == e); - - let e = $mask_ty::splat(false); - let r = a.gt(b); - assert!(r == e); - let r = a.ge(b); - assert!(r == e); - let r = a.eq(b); - assert!(r == e); - - let mut a = a; - let mut b = b; - let mut e = e; - for i in 0..$id::::lanes() { - if i % 2 == 0 { - a = a.replace( - i, - unsafe { crate::mem::transmute(0_isize) } - ); - b = b.replace( - i, - unsafe { crate::mem::transmute(1_isize) } - ); - e = e.replace(i, true); - } else { - a = a.replace( - i, - unsafe { crate::mem::transmute(1_isize) } - ); - b = b.replace( - i, - unsafe { crate::mem::transmute(0_isize) } - ); - e = e.replace(i, false); - } - } - let r = a.lt(b); - assert!(r == e); - } - } - } - } - - #[allow(clippy::partialeq_ne_impl)] - impl crate::cmp::PartialEq<$id> for $id { - #[inline] - fn eq(&self, other: &Self) -> bool { - $id::::eq(*self, *other).all() - } - #[inline] - fn ne(&self, other: &Self) -> bool { - $id::::ne(*self, *other).any() - } - } - - // FIXME: https://github.com/rust-lang-nursery/rust-clippy/issues/2892 - #[allow(clippy::partialeq_ne_impl)] - impl crate::cmp::PartialEq>> - for LexicographicallyOrdered<$id> - { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - #[inline] - fn ne(&self, other: &Self) -> bool { - self.0 != other.0 - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_PartialEq>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn partial_eq() { - let a = $id::::null(); - let b = $id::::splat(unsafe { - crate::mem::transmute(1_isize) - }); - - assert!(a != b); - assert!(!(a == b)); - assert!(a == a); - assert!(!(a != a)); - - if $id::::lanes() > 1 { - let a = $id::::null().replace(0, unsafe { - crate::mem::transmute(1_isize) - }); - let b = $id::::splat(unsafe { - crate::mem::transmute(1_isize) - }); - - assert!(a != b); - assert!(!(a == b)); - assert!(a == a); - assert!(!(a != a)); - } - } - } - } - } - - impl crate::cmp::Eq for $id {} - impl crate::cmp::Eq for LexicographicallyOrdered<$id> {} - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _cmp_eq>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn eq() { - fn foo(_: E) {} - let a = $id::::null(); - foo(a); - } - } - } - } - - impl From<[$elem_ty; $elem_count]> for $id { - #[inline] - fn from(array: [$elem_ty; $elem_count]) -> Self { - unsafe { - // FIXME: unnecessary zeroing; better than UB. - let mut u: Self = crate::mem::zeroed(); - crate::ptr::copy_nonoverlapping( - &array as *const [$elem_ty; $elem_count] as *const u8, - &mut u as *mut Self as *mut u8, - crate::mem::size_of::() - ); - u - } - } - } - impl Into<[$elem_ty; $elem_count]> for $id { - #[inline] - fn into(self) -> [$elem_ty; $elem_count] { - unsafe { - // FIXME: unnecessary zeroing; better than UB. - let mut u: [$elem_ty; $elem_count] = crate::mem::zeroed(); - crate::ptr::copy_nonoverlapping( - &self as *const $id as *const u8, - &mut u as *mut [$elem_ty; $elem_count] as *mut u8, - crate::mem::size_of::() - ); - u - } - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _from>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn array() { - let values = [1_i32; $elem_count]; - - let mut vec: $id = Default::default(); - let mut array = [ - $id::::null().extract(0); $elem_count - ]; - - for i in 0..$elem_count { - let ptr = &values[i] as *const i32 as *mut i32; - vec = vec.replace(i, ptr); - array[i] = ptr; - } - - // FIXME: there is no impl of From<$id> for [$elem_ty; N] - // let a0 = From::from(vec); - // assert_eq!(a0, array); - #[allow(unused_assignments)] - let mut a1 = array; - a1 = vec.into(); - assert_eq!(a1, array); - - let v0: $id = From::from(array); - assert_eq!(v0, vec); - let v1: $id = array.into(); - assert_eq!(v1, vec); - } - } - } - } - - impl $id { - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not aligned - /// to an `align_of::()` boundary. - #[inline] - pub fn from_slice_aligned(slice: &[$elem_ty]) -> Self { - unsafe { - assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_ptr(); - assert!( - target_ptr.align_offset(crate::mem::align_of::()) - == 0 - ); - Self::from_slice_aligned_unchecked(slice) - } - } - - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()`. - #[inline] - pub fn from_slice_unaligned(slice: &[$elem_ty]) -> Self { - unsafe { - assert!(slice.len() >= $elem_count); - Self::from_slice_unaligned_unchecked(slice) - } - } - - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not aligned - /// to an `align_of::()` boundary, the behavior is undefined. - #[inline] - pub unsafe fn from_slice_aligned_unchecked(slice: &[$elem_ty]) - -> Self { - #[allow(clippy::cast_ptr_alignment)] - *(slice.as_ptr().cast()) - } - - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` the behavior is undefined. - #[inline] - pub unsafe fn from_slice_unaligned_unchecked( - slice: &[$elem_ty], - ) -> Self { - use crate::mem::size_of; - let target_ptr = slice.as_ptr().cast(); - let mut x = Self::splat(crate::ptr::null_mut() as $elem_ty); - let self_ptr = &mut x as *mut Self as *mut u8; - crate::ptr::copy_nonoverlapping( - target_ptr, - self_ptr, - size_of::(), - ); - x - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _slice_from_slice>] { - use super::*; - use crate::iter::Iterator; - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn from_slice_unaligned() { - let (null, non_null) = ptr_vals!($id); - - let mut unaligned = [ - non_null; $id::::lanes() + 1 - ]; - unaligned[0] = null; - let vec = $id::::from_slice_unaligned( - &unaligned[1..] - ); - for (index, &b) in unaligned.iter().enumerate() { - if index == 0 { - assert_eq!(b, null); - } else { - assert_eq!(b, non_null); - assert_eq!(b, vec.extract(index - 1)); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn from_slice_unaligned_fail() { - let (_null, non_null) = ptr_vals!($id); - let unaligned = [non_null; $id::::lanes() + 1]; - // the slice is not large enough => panic - let _vec = $id::::from_slice_unaligned( - &unaligned[2..] - ); - } - - union A { - data: [<$id as sealed::Simd>::Element; - 2 * $id::::lanes()], - _vec: $id, - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn from_slice_aligned() { - let (null, non_null) = ptr_vals!($id); - let mut aligned = A { - data: [null; 2 * $id::::lanes()], - }; - for i in - $id::::lanes()..(2 * $id::::lanes()) { - unsafe { - aligned.data[i] = non_null; - } - } - - let vec = unsafe { - $id::::from_slice_aligned( - &aligned.data[$id::::lanes()..] - ) - }; - for (index, &b) in unsafe { - aligned.data.iter().enumerate() - } { - if index < $id::::lanes() { - assert_eq!(b, null); - } else { - assert_eq!(b, non_null); - assert_eq!( - b, vec.extract(index - $id::::lanes()) - ); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn from_slice_aligned_fail_lanes() { - let (_null, non_null) = ptr_vals!($id); - let aligned = A { - data: [non_null; 2 * $id::::lanes()], - }; - // the slice is not large enough => panic - let _vec = unsafe { - $id::::from_slice_aligned( - &aligned.data[2 * $id::::lanes()..] - ) - }; - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn from_slice_aligned_fail_align() { - unsafe { - let (null, _non_null) = ptr_vals!($id); - let aligned = A { - data: [null; 2 * $id::::lanes()], - }; - - // get a pointer to the front of data - let ptr = aligned.data.as_ptr(); - // offset pointer by one element - let ptr = ptr.wrapping_add(1); - - if ptr.align_offset( - crate::mem::align_of::<$id>() - ) == 0 { - // the pointer is properly aligned, so - // from_slice_aligned won't fail here (e.g. this - // can happen for i128x1). So we panic to make - // the "should_fail" test pass: - panic!("ok"); - } - - // create a slice - this is safe, because the - // elements of the slice exist, are properly - // initialized, and properly aligned: - let s = slice::from_raw_parts( - ptr, $id::::lanes() - ); - // this should always panic because the slice - // alignment does not match the alignment - // requirements for the vector type: - let _vec = $id::::from_slice_aligned(s); - } - } - } - } - } - - impl $id { - /// Writes the values of the vector to the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not - /// aligned to an `align_of::()` boundary. - #[inline] - pub fn write_to_slice_aligned(self, slice: &mut [$elem_ty]) { - unsafe { - assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_mut_ptr(); - assert!( - target_ptr.align_offset(crate::mem::align_of::()) - == 0 - ); - self.write_to_slice_aligned_unchecked(slice); - } - } - - /// Writes the values of the vector to the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()`. - #[inline] - pub fn write_to_slice_unaligned(self, slice: &mut [$elem_ty]) { - unsafe { - assert!(slice.len() >= $elem_count); - self.write_to_slice_unaligned_unchecked(slice); - } - } - - /// Writes the values of the vector to the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not - /// aligned to an `align_of::()` boundary, the behavior is - /// undefined. - #[inline] - pub unsafe fn write_to_slice_aligned_unchecked( - self, slice: &mut [$elem_ty], - ) { - #[allow(clippy::cast_ptr_alignment)] - *(slice.as_mut_ptr().cast()) = self; - } - - /// Writes the values of the vector to the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` the behavior is undefined. - #[inline] - pub unsafe fn write_to_slice_unaligned_unchecked( - self, slice: &mut [$elem_ty], - ) { - let target_ptr = slice.as_mut_ptr().cast(); - let self_ptr = &self as *const Self as *const u8; - crate::ptr::copy_nonoverlapping( - self_ptr, - target_ptr, - crate::mem::size_of::(), - ); - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _slice_write_to_slice>] { - use super::*; - use crate::iter::Iterator; - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn write_to_slice_unaligned() { - let (null, non_null) = ptr_vals!($id); - let mut unaligned = [null; $id::::lanes() + 1]; - let vec = $id::::splat(non_null); - vec.write_to_slice_unaligned(&mut unaligned[1..]); - for (index, &b) in unaligned.iter().enumerate() { - if index == 0 { - assert_eq!(b, null); - } else { - assert_eq!(b, non_null); - assert_eq!(b, vec.extract(index - 1)); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn write_to_slice_unaligned_fail() { - let (null, non_null) = ptr_vals!($id); - let mut unaligned = [null; $id::::lanes() + 1]; - let vec = $id::::splat(non_null); - // the slice is not large enough => panic - vec.write_to_slice_unaligned(&mut unaligned[2..]); - } - - union A { - data: [<$id as sealed::Simd>::Element; - 2 * $id::::lanes()], - _vec: $id, - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn write_to_slice_aligned() { - let (null, non_null) = ptr_vals!($id); - let mut aligned = A { - data: [null; 2 * $id::::lanes()], - }; - let vec = $id::::splat(non_null); - unsafe { - vec.write_to_slice_aligned( - &mut aligned.data[$id::::lanes()..] - ) - }; - for (index, &b) in - unsafe { aligned.data.iter().enumerate() } { - if index < $id::::lanes() { - assert_eq!(b, null); - } else { - assert_eq!(b, non_null); - assert_eq!( - b, vec.extract(index - $id::::lanes()) - ); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn write_to_slice_aligned_fail_lanes() { - let (null, non_null) = ptr_vals!($id); - let mut aligned = A { - data: [null; 2 * $id::::lanes()], - }; - let vec = $id::::splat(non_null); - // the slice is not large enough => panic - unsafe { - vec.write_to_slice_aligned( - &mut aligned.data[2 * $id::::lanes()..] - ) - }; - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn write_to_slice_aligned_fail_align() { - let (null, non_null) = ptr_vals!($id); - unsafe { - let mut aligned = A { - data: [null; 2 * $id::::lanes()], - }; - - // get a pointer to the front of data - let ptr = aligned.data.as_mut_ptr(); - // offset pointer by one element - let ptr = ptr.wrapping_add(1); - - if ptr.align_offset( - crate::mem::align_of::<$id>() - ) == 0 { - // the pointer is properly aligned, so - // write_to_slice_aligned won't fail here (e.g. - // this can happen for i128x1). So we panic to - // make the "should_fail" test pass: - panic!("ok"); - } - - // create a slice - this is safe, because the - // elements of the slice exist, are properly - // initialized, and properly aligned: - let s = slice::from_raw_parts_mut( - ptr, $id::::lanes() - ); - // this should always panic because the slice - // alignment does not match the alignment - // requirements for the vector type: - let vec = $id::::splat(non_null); - vec.write_to_slice_aligned(s); - } - } - } - } - } - - impl crate::hash::Hash for $id { - #[inline] - fn hash(&self, state: &mut H) { - let s: $usize_ty = unsafe { crate::mem::transmute(*self) }; - s.hash(state) - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _hash>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn hash() { - use crate::hash::{Hash, Hasher}; - #[allow(deprecated)] - use crate::hash::{SipHasher13}; - - let values = [1_i32; $elem_count]; - - let mut vec: $id = Default::default(); - let mut array = [ - $id::::null().extract(0); - $elem_count - ]; - - for i in 0..$elem_count { - let ptr = &values[i] as *const i32 as *mut i32; - vec = vec.replace(i, ptr); - array[i] = ptr; - } - - #[allow(deprecated)] - let mut a_hash = SipHasher13::new(); - let mut v_hash = a_hash.clone(); - array.hash(&mut a_hash); - vec.hash(&mut v_hash); - assert_eq!(a_hash.finish(), v_hash.finish()); - } - } - } - } - - impl $id { - /// Calculates the offset from a pointer. - /// - /// `count` is in units of `T`; e.g. a count of `3` represents a - /// pointer offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is - /// Undefined Behavior: - /// - /// * Both the starting and resulting pointer must be either in - /// bounds or one byte past the end of an allocated object. - /// - /// * The computed offset, in bytes, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" - /// the address space. That is, the infinite-precision sum, in bytes - /// must fit in a `usize`. - /// - /// The compiler and standard library generally tries to ensure - /// allocations never reach a size where an offset is a concern. For - /// instance, `Vec` and `Box` ensure they never allocate more than - /// `isize::MAX` bytes, so `vec.as_ptr().offset(vec.len() as isize)` - /// is always safe. - /// - /// Most platforms fundamentally can't even construct such an - /// allocation. For instance, no known 64-bit platform can ever - /// serve a request for 263 bytes due to page-table limitations or - /// splitting the address space. However, some 32-bit and 16-bit - /// platforms may successfully serve a request for more than - /// `isize::MAX` bytes with things like Physical Address Extension. - /// As such, memory acquired directly from allocators or memory - /// mapped files may be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints - /// are difficult to satisfy. The only advantage of this method is - /// that it enables more aggressive compiler optimizations. - #[inline] - pub unsafe fn offset(self, count: $isize_ty) -> Self { - // FIXME: should use LLVM's `add nsw nuw` - self.wrapping_offset(count) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// - /// `count` is in units of `T`; e.g. a count of `3` represents a - /// pointer offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires unsafe). - /// - /// Always use `.offset(count)` instead when possible, because - /// offset allows the compiler to optimize better. - #[inline] - pub fn wrapping_offset(self, count: $isize_ty) -> Self { - unsafe { - let x: $isize_ty = crate::mem::transmute(self); - // note: {+,*} currently performs a `wrapping_{add, mul}` - crate::mem::transmute( - x + (count * crate::mem::size_of::() as isize) - ) - } - } - - /// Calculates the distance between two pointers. - /// - /// The returned value is in units of `T`: the distance in bytes is - /// divided by `mem::size_of::()`. - /// - /// This function is the inverse of offset. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is - /// Undefined Behavior: - /// - /// * Both the starting and other pointer must be either in bounds - /// or one byte past the end of the same allocated object. - /// - /// * The distance between the pointers, in bytes, cannot overflow - /// an `isize`. - /// - /// * The distance between the pointers, in bytes, must be an exact - /// multiple of the size of `T`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" - /// the address space. - /// - /// The compiler and standard library generally try to ensure - /// allocations never reach a size where an offset is a concern. For - /// instance, `Vec` and `Box` ensure they never allocate more than - /// `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` - /// is always safe. - /// - /// Most platforms fundamentally can't even construct such an - /// allocation. For instance, no known 64-bit platform can ever - /// serve a request for 263 bytes due to page-table limitations or - /// splitting the address space. However, some 32-bit and 16-bit - /// platforms may successfully serve a request for more than - /// `isize::MAX` bytes with things like Physical Address Extension. - /// As such, memory acquired directly from allocators or memory - /// mapped files may be too large to handle with this function. - /// - /// Consider using `wrapping_offset_from` instead if these constraints - /// are difficult to satisfy. The only advantage of this method is - /// that it enables more aggressive compiler optimizations. - #[inline] - pub unsafe fn offset_from(self, origin: Self) -> $isize_ty { - // FIXME: should use LLVM's `sub nsw nuw`. - self.wrapping_offset_from(origin) - } - - /// Calculates the distance between two pointers. - /// - /// The returned value is in units of `T`: the distance in bytes is - /// divided by `mem::size_of::()`. - /// - /// If the address different between the two pointers is not a - /// multiple of `mem::size_of::()` then the result of the - /// division is rounded towards zero. - /// - /// Though this method is safe for any two pointers, note that its - /// result will be mostly useless if the two pointers aren't into - /// the same allocated object, for example if they point to two - /// different local variables. - #[inline] - pub fn wrapping_offset_from(self, origin: Self) -> $isize_ty { - let x: $isize_ty = unsafe { crate::mem::transmute(self) }; - let y: $isize_ty = unsafe { crate::mem::transmute(origin) }; - // note: {-,/} currently perform wrapping_{sub, div} - (y - x) / (crate::mem::size_of::() as isize) - } - - /// Calculates the offset from a pointer (convenience for - /// `.offset(count as isize)`). - /// - /// `count` is in units of `T`; e.g. a count of 3 represents a - /// pointer offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is - /// Undefined Behavior: - /// - /// * Both the starting and resulting pointer must be either in - /// bounds or one byte past the end of an allocated object. - /// - /// * The computed offset, in bytes, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" - /// the address space. That is, the infinite-precision sum must fit - /// in a `usize`. - /// - /// The compiler and standard library generally tries to ensure - /// allocations never reach a size where an offset is a concern. For - /// instance, `Vec` and `Box` ensure they never allocate more than - /// `isize::MAX` bytes, so `vec.as_ptr().add(vec.len())` is always - /// safe. - /// - /// Most platforms fundamentally can't even construct such an - /// allocation. For instance, no known 64-bit platform can ever - /// serve a request for 263 bytes due to page-table limitations or - /// splitting the address space. However, some 32-bit and 16-bit - /// platforms may successfully serve a request for more than - /// `isize::MAX` bytes with things like Physical Address Extension. - /// As such, memory acquired directly from allocators or memory - /// mapped files may be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints - /// are difficult to satisfy. The only advantage of this method is - /// that it enables more aggressive compiler optimizations. - #[inline] - #[allow(clippy::should_implement_trait)] - pub unsafe fn add(self, count: $usize_ty) -> Self { - self.offset(count.cast()) - } - - /// Calculates the offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). - /// - /// `count` is in units of T; e.g. a `count` of 3 represents a - /// pointer offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is - /// Undefined Behavior: - /// - /// * Both the starting and resulting pointer must be either in - /// bounds or one byte past the end of an allocated object. - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. - /// - /// * The offset being in bounds cannot rely on "wrapping around" - /// the address space. That is, the infinite-precision sum must fit - /// in a usize. - /// - /// The compiler and standard library generally tries to ensure - /// allocations never reach a size where an offset is a concern. For - /// instance, `Vec` and `Box` ensure they never allocate more than - /// `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an - /// allocation. For instance, no known 64-bit platform can ever - /// serve a request for 263 bytes due to page-table - /// limitations or splitting the address space. However, some 32-bit - /// and 16-bit platforms may successfully serve a request for more - /// than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or - /// memory mapped files *may* be too large to handle with this - /// function. - /// - /// Consider using `wrapping_offset` instead if these constraints - /// are difficult to satisfy. The only advantage of this method is - /// that it enables more aggressive compiler optimizations. - #[inline] - #[allow(clippy::should_implement_trait)] - pub unsafe fn sub(self, count: $usize_ty) -> Self { - let x: $isize_ty = count.cast(); - // note: - is currently wrapping_neg - self.offset(-x) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) - /// - /// `count` is in units of T; e.g. a `count` of 3 represents a - /// pointer offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// Always use `.add(count)` instead when possible, because `add` - /// allows the compiler to optimize better. - #[inline] - pub fn wrapping_add(self, count: $usize_ty) -> Self { - self.wrapping_offset(count.cast()) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as - /// isize).wrapping_sub())`) - /// - /// `count` is in units of T; e.g. a `count` of 3 represents a - /// pointer offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// Always use `.sub(count)` instead when possible, because `sub` - /// allows the compiler to optimize better. - #[inline] - pub fn wrapping_sub(self, count: $usize_ty) -> Self { - let x: $isize_ty = count.cast(); - self.wrapping_offset(-1 * x) - } - } - - impl $id { - /// Shuffle vector elements according to `indices`. - #[inline] - pub fn shuffle1_dyn(self, indices: I) -> Self - where - Self: codegen::shuffle1_dyn::Shuffle1Dyn, - { - codegen::shuffle1_dyn::Shuffle1Dyn::shuffle1_dyn(self, indices) - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _shuffle1_dyn>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn shuffle1_dyn() { - let (null, non_null) = ptr_vals!($id); - - // alternating = [non_null, null, non_null, null, ...] - let mut alternating = $id::::splat(null); - for i in 0..$id::::lanes() { - if i % 2 == 0 { - alternating = alternating.replace(i, non_null); - } - } - - type Indices = <$id - as codegen::shuffle1_dyn::Shuffle1Dyn>::Indices; - // even = [0, 0, 2, 2, 4, 4, ..] - let even = { - let mut v = Indices::splat(0); - for i in 0..$id::::lanes() { - if i % 2 == 0 { - v = v.replace(i, (i as u8).into()); - } else { - v = v.replace(i, (i as u8 - 1).into()); - } - } - v - }; - // odd = [1, 1, 3, 3, 5, 5, ...] - let odd = { - let mut v = Indices::splat(0); - for i in 0..$id::::lanes() { - if i % 2 != 0 { - v = v.replace(i, (i as u8).into()); - } else { - v = v.replace(i, (i as u8 + 1).into()); - } - } - v - }; - - assert_eq!( - alternating.shuffle1_dyn(even), - $id::::splat(non_null) - ); - if $id::::lanes() > 1 { - assert_eq!( - alternating.shuffle1_dyn(odd), - $id::::splat(null) - ); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops.rs b/third_party/rust/packed_simd/src/api/ops.rs deleted file mode 100644 index f71c98795d..0000000000 --- a/third_party/rust/packed_simd/src/api/ops.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Implementation of the `ops` traits -#[macro_use] -mod vector_mask_bitwise; -#[macro_use] -mod scalar_mask_bitwise; - -#[macro_use] -mod vector_arithmetic; -#[macro_use] -mod scalar_arithmetic; - -#[macro_use] -mod vector_bitwise; -#[macro_use] -mod scalar_bitwise; - -#[macro_use] -mod vector_shifts; -#[macro_use] -mod scalar_shifts; - -#[macro_use] -mod vector_rotates; - -#[macro_use] -mod vector_neg; - -#[macro_use] -mod vector_int_min_max; - -#[macro_use] -mod vector_float_min_max; diff --git a/third_party/rust/packed_simd/src/api/ops/scalar_arithmetic.rs b/third_party/rust/packed_simd/src/api/ops/scalar_arithmetic.rs deleted file mode 100644 index da1a2037ea..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/scalar_arithmetic.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! Vertical (lane-wise) vector-scalar / scalar-vector arithmetic operations. - -macro_rules! impl_ops_scalar_arithmetic { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::ops::Add<$elem_ty> for $id { - type Output = Self; - #[inline] - fn add(self, other: $elem_ty) -> Self { - self + $id::splat(other) - } - } - impl crate::ops::Add<$id> for $elem_ty { - type Output = $id; - #[inline] - fn add(self, other: $id) -> $id { - $id::splat(self) + other - } - } - - impl crate::ops::Sub<$elem_ty> for $id { - type Output = Self; - #[inline] - fn sub(self, other: $elem_ty) -> Self { - self - $id::splat(other) - } - } - impl crate::ops::Sub<$id> for $elem_ty { - type Output = $id; - #[inline] - fn sub(self, other: $id) -> $id { - $id::splat(self) - other - } - } - - impl crate::ops::Mul<$elem_ty> for $id { - type Output = Self; - #[inline] - fn mul(self, other: $elem_ty) -> Self { - self * $id::splat(other) - } - } - impl crate::ops::Mul<$id> for $elem_ty { - type Output = $id; - #[inline] - fn mul(self, other: $id) -> $id { - $id::splat(self) * other - } - } - - impl crate::ops::Div<$elem_ty> for $id { - type Output = Self; - #[inline] - fn div(self, other: $elem_ty) -> Self { - self / $id::splat(other) - } - } - impl crate::ops::Div<$id> for $elem_ty { - type Output = $id; - #[inline] - fn div(self, other: $id) -> $id { - $id::splat(self) / other - } - } - - impl crate::ops::Rem<$elem_ty> for $id { - type Output = Self; - #[inline] - fn rem(self, other: $elem_ty) -> Self { - self % $id::splat(other) - } - } - impl crate::ops::Rem<$id> for $elem_ty { - type Output = $id; - #[inline] - fn rem(self, other: $id) -> $id { - $id::splat(self) % other - } - } - - impl crate::ops::AddAssign<$elem_ty> for $id { - #[inline] - fn add_assign(&mut self, other: $elem_ty) { - *self = *self + other; - } - } - - impl crate::ops::SubAssign<$elem_ty> for $id { - #[inline] - fn sub_assign(&mut self, other: $elem_ty) { - *self = *self - other; - } - } - - impl crate::ops::MulAssign<$elem_ty> for $id { - #[inline] - fn mul_assign(&mut self, other: $elem_ty) { - *self = *self * other; - } - } - - impl crate::ops::DivAssign<$elem_ty> for $id { - #[inline] - fn div_assign(&mut self, other: $elem_ty) { - *self = *self / other; - } - } - - impl crate::ops::RemAssign<$elem_ty> for $id { - #[inline] - fn rem_assign(&mut self, other: $elem_ty) { - *self = *self % other; - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_scalar_arith>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn ops_scalar_arithmetic() { - let zi = 0 as $elem_ty; - let oi = 1 as $elem_ty; - let ti = 2 as $elem_ty; - let fi = 4 as $elem_ty; - let z = $id::splat(zi); - let o = $id::splat(oi); - let t = $id::splat(ti); - let f = $id::splat(fi); - - // add - assert_eq!(zi + z, z); - assert_eq!(z + zi, z); - assert_eq!(oi + z, o); - assert_eq!(o + zi, o); - assert_eq!(ti + z, t); - assert_eq!(t + zi, t); - assert_eq!(ti + t, f); - assert_eq!(t + ti, f); - // sub - assert_eq!(zi - z, z); - assert_eq!(z - zi, z); - assert_eq!(oi - z, o); - assert_eq!(o - zi, o); - assert_eq!(ti - z, t); - assert_eq!(t - zi, t); - assert_eq!(fi - t, t); - assert_eq!(f - ti, t); - assert_eq!(f - o - o, t); - assert_eq!(f - oi - oi, t); - // mul - assert_eq!(zi * z, z); - assert_eq!(z * zi, z); - assert_eq!(zi * o, z); - assert_eq!(z * oi, z); - assert_eq!(zi * t, z); - assert_eq!(z * ti, z); - assert_eq!(oi * t, t); - assert_eq!(o * ti, t); - assert_eq!(ti * t, f); - assert_eq!(t * ti, f); - // div - assert_eq!(zi / o, z); - assert_eq!(z / oi, z); - assert_eq!(ti / o, t); - assert_eq!(t / oi, t); - assert_eq!(fi / o, f); - assert_eq!(f / oi, f); - assert_eq!(ti / t, o); - assert_eq!(t / ti, o); - assert_eq!(fi / t, t); - assert_eq!(f / ti, t); - // rem - assert_eq!(oi % o, z); - assert_eq!(o % oi, z); - assert_eq!(fi % t, z); - assert_eq!(f % ti, z); - - { - let mut v = z; - assert_eq!(v, z); - v += oi; // add_assign - assert_eq!(v, o); - v -= oi; // sub_assign - assert_eq!(v, z); - v = t; - v *= oi; // mul_assign - assert_eq!(v, t); - v *= ti; - assert_eq!(v, f); - v /= oi; // div_assign - assert_eq!(v, f); - v /= ti; - assert_eq!(v, t); - v %= ti; // rem_assign - assert_eq!(v, z); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/scalar_bitwise.rs b/third_party/rust/packed_simd/src/api/ops/scalar_bitwise.rs deleted file mode 100644 index 88216769ae..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/scalar_bitwise.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! Vertical (lane-wise) vector-scalar / scalar-vector bitwise operations. - -macro_rules! impl_ops_scalar_bitwise { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $test_tt:tt | - ($true:expr, $false:expr) - ) => { - impl crate::ops::BitXor<$elem_ty> for $id { - type Output = Self; - #[inline] - fn bitxor(self, other: $elem_ty) -> Self { - self ^ $id::splat(other) - } - } - impl crate::ops::BitXor<$id> for $elem_ty { - type Output = $id; - #[inline] - fn bitxor(self, other: $id) -> $id { - $id::splat(self) ^ other - } - } - - impl crate::ops::BitAnd<$elem_ty> for $id { - type Output = Self; - #[inline] - fn bitand(self, other: $elem_ty) -> Self { - self & $id::splat(other) - } - } - impl crate::ops::BitAnd<$id> for $elem_ty { - type Output = $id; - #[inline] - fn bitand(self, other: $id) -> $id { - $id::splat(self) & other - } - } - - impl crate::ops::BitOr<$elem_ty> for $id { - type Output = Self; - #[inline] - fn bitor(self, other: $elem_ty) -> Self { - self | $id::splat(other) - } - } - impl crate::ops::BitOr<$id> for $elem_ty { - type Output = $id; - #[inline] - fn bitor(self, other: $id) -> $id { - $id::splat(self) | other - } - } - - impl crate::ops::BitAndAssign<$elem_ty> for $id { - #[inline] - fn bitand_assign(&mut self, other: $elem_ty) { - *self = *self & other; - } - } - impl crate::ops::BitOrAssign<$elem_ty> for $id { - #[inline] - fn bitor_assign(&mut self, other: $elem_ty) { - *self = *self | other; - } - } - impl crate::ops::BitXorAssign<$elem_ty> for $id { - #[inline] - fn bitxor_assign(&mut self, other: $elem_ty) { - *self = *self ^ other; - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_scalar_bitwise>] { - use super::*; - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn ops_scalar_bitwise() { - let zi = 0 as $elem_ty; - let oi = 1 as $elem_ty; - let ti = 2 as $elem_ty; - let z = $id::splat(zi); - let o = $id::splat(oi); - let t = $id::splat(ti); - - // BitAnd: - assert_eq!(oi & o, o); - assert_eq!(o & oi, o); - assert_eq!(oi & z, z); - assert_eq!(o & zi, z); - assert_eq!(zi & o, z); - assert_eq!(z & oi, z); - assert_eq!(zi & z, z); - assert_eq!(z & zi, z); - - assert_eq!(ti & t, t); - assert_eq!(t & ti, t); - assert_eq!(ti & o, z); - assert_eq!(t & oi, z); - assert_eq!(oi & t, z); - assert_eq!(o & ti, z); - - // BitOr: - assert_eq!(oi | o, o); - assert_eq!(o | oi, o); - assert_eq!(oi | z, o); - assert_eq!(o | zi, o); - assert_eq!(zi | o, o); - assert_eq!(z | oi, o); - assert_eq!(zi | z, z); - assert_eq!(z | zi, z); - - assert_eq!(ti | t, t); - assert_eq!(t | ti, t); - assert_eq!(zi | t, t); - assert_eq!(z | ti, t); - assert_eq!(ti | z, t); - assert_eq!(t | zi, t); - - // BitXOR: - assert_eq!(oi ^ o, z); - assert_eq!(o ^ oi, z); - assert_eq!(zi ^ z, z); - assert_eq!(z ^ zi, z); - assert_eq!(zi ^ o, o); - assert_eq!(z ^ oi, o); - assert_eq!(oi ^ z, o); - assert_eq!(o ^ zi, o); - - assert_eq!(ti ^ t, z); - assert_eq!(t ^ ti, z); - assert_eq!(ti ^ z, t); - assert_eq!(t ^ zi, t); - assert_eq!(zi ^ t, t); - assert_eq!(z ^ ti, t); - - { - // AndAssign: - let mut v = o; - v &= ti; - assert_eq!(v, z); - } - { - // OrAssign: - let mut v = z; - v |= oi; - assert_eq!(v, o); - } - { - // XORAssign: - let mut v = z; - v ^= oi; - assert_eq!(v, o); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/scalar_mask_bitwise.rs b/third_party/rust/packed_simd/src/api/ops/scalar_mask_bitwise.rs deleted file mode 100644 index 523a85207b..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/scalar_mask_bitwise.rs +++ /dev/null @@ -1,140 +0,0 @@ -//! Vertical (lane-wise) vector-vector bitwise operations. - -macro_rules! impl_ops_scalar_mask_bitwise { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $test_tt:tt | - ($true:expr, $false:expr) - ) => { - impl crate::ops::BitXor for $id { - type Output = Self; - #[inline] - fn bitxor(self, other: bool) -> Self { - self ^ $id::splat(other) - } - } - impl crate::ops::BitXor<$id> for bool { - type Output = $id; - #[inline] - fn bitxor(self, other: $id) -> $id { - $id::splat(self) ^ other - } - } - - impl crate::ops::BitAnd for $id { - type Output = Self; - #[inline] - fn bitand(self, other: bool) -> Self { - self & $id::splat(other) - } - } - impl crate::ops::BitAnd<$id> for bool { - type Output = $id; - #[inline] - fn bitand(self, other: $id) -> $id { - $id::splat(self) & other - } - } - - impl crate::ops::BitOr for $id { - type Output = Self; - #[inline] - fn bitor(self, other: bool) -> Self { - self | $id::splat(other) - } - } - impl crate::ops::BitOr<$id> for bool { - type Output = $id; - #[inline] - fn bitor(self, other: $id) -> $id { - $id::splat(self) | other - } - } - - impl crate::ops::BitAndAssign for $id { - #[inline] - fn bitand_assign(&mut self, other: bool) { - *self = *self & other; - } - } - impl crate::ops::BitOrAssign for $id { - #[inline] - fn bitor_assign(&mut self, other: bool) { - *self = *self | other; - } - } - impl crate::ops::BitXorAssign for $id { - #[inline] - fn bitxor_assign(&mut self, other: bool) { - *self = *self ^ other; - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_scalar_mask_bitwise>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn ops_scalar_mask_bitwise() { - let ti = true; - let fi = false; - let t = $id::splat(ti); - let f = $id::splat(fi); - assert!(t != f); - assert!(!(t == f)); - - // BitAnd: - assert_eq!(ti & f, f); - assert_eq!(t & fi, f); - assert_eq!(fi & t, f); - assert_eq!(f & ti, f); - assert_eq!(ti & t, t); - assert_eq!(t & ti, t); - assert_eq!(fi & f, f); - assert_eq!(f & fi, f); - - // BitOr: - assert_eq!(ti | f, t); - assert_eq!(t | fi, t); - assert_eq!(fi | t, t); - assert_eq!(f | ti, t); - assert_eq!(ti | t, t); - assert_eq!(t | ti, t); - assert_eq!(fi | f, f); - assert_eq!(f | fi, f); - - // BitXOR: - assert_eq!(ti ^ f, t); - assert_eq!(t ^ fi, t); - assert_eq!(fi ^ t, t); - assert_eq!(f ^ ti, t); - assert_eq!(ti ^ t, f); - assert_eq!(t ^ ti, f); - assert_eq!(fi ^ f, f); - assert_eq!(f ^ fi, f); - - { - // AndAssign: - let mut v = f; - v &= ti; - assert_eq!(v, f); - } - { - // OrAssign: - let mut v = f; - v |= ti; - assert_eq!(v, t); - } - { - // XORAssign: - let mut v = f; - v ^= ti; - assert_eq!(v, t); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/scalar_shifts.rs b/third_party/rust/packed_simd/src/api/ops/scalar_shifts.rs deleted file mode 100644 index 4a7a096263..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/scalar_shifts.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! Vertical (lane-wise) vector-scalar shifts operations. - -macro_rules! impl_ops_scalar_shifts { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::ops::Shl for $id { - type Output = Self; - #[inline] - fn shl(self, other: u32) -> Self { - self << $id::splat(other as $elem_ty) - } - } - impl crate::ops::Shr for $id { - type Output = Self; - #[inline] - fn shr(self, other: u32) -> Self { - self >> $id::splat(other as $elem_ty) - } - } - - impl crate::ops::ShlAssign for $id { - #[inline] - fn shl_assign(&mut self, other: u32) { - *self = *self << other; - } - } - impl crate::ops::ShrAssign for $id { - #[inline] - fn shr_assign(&mut self, other: u32) { - *self = *self >> other; - } - } - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_scalar_shifts>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg_attr(any(target_arch = "s390x", target_arch = "sparc64"), - allow(unreachable_code, unused_variables) - )] - #[cfg(not(target_arch = "aarch64"))] - //~^ FIXME: https://github.com/rust-lang/packed_simd/issues/317 - fn ops_scalar_shifts() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let f = $id::splat(4 as $elem_ty); - - { - let zi = 0 as u32; - let oi = 1 as u32; - let ti = 2 as u32; - let maxi - = (mem::size_of::<$elem_ty>() * 8 - 1) as u32; - - // shr - assert_eq!(z >> zi, z); - assert_eq!(z >> oi, z); - assert_eq!(z >> ti, z); - assert_eq!(z >> ti, z); - - #[cfg(any(target_arch = "s390x", target_arch = "sparc64"))] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/13 - return; - } - - assert_eq!(o >> zi, o); - assert_eq!(t >> zi, t); - assert_eq!(f >> zi, f); - assert_eq!(f >> maxi, z); - - assert_eq!(o >> oi, z); - assert_eq!(t >> oi, o); - assert_eq!(t >> ti, z); - assert_eq!(f >> oi, t); - assert_eq!(f >> ti, o); - assert_eq!(f >> maxi, z); - - // shl - assert_eq!(z << zi, z); - assert_eq!(o << zi, o); - assert_eq!(t << zi, t); - assert_eq!(f << zi, f); - assert_eq!(f << maxi, z); - - assert_eq!(o << oi, t); - assert_eq!(o << ti, f); - assert_eq!(t << oi, f); - - { // shr_assign - let mut v = o; - v >>= oi; - assert_eq!(v, z); - } - { // shl_assign - let mut v = o; - v <<= oi; - assert_eq!(v, t); - } - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_arithmetic.rs b/third_party/rust/packed_simd/src/api/ops/vector_arithmetic.rs deleted file mode 100644 index 7057f52d03..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_arithmetic.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! Vertical (lane-wise) vector-vector arithmetic operations. - -macro_rules! impl_ops_vector_arithmetic { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::ops::Add for $id { - type Output = Self; - #[inline] - fn add(self, other: Self) -> Self { - use crate::llvm::simd_add; - unsafe { Simd(simd_add(self.0, other.0)) } - } - } - - impl crate::ops::Sub for $id { - type Output = Self; - #[inline] - fn sub(self, other: Self) -> Self { - use crate::llvm::simd_sub; - unsafe { Simd(simd_sub(self.0, other.0)) } - } - } - - impl crate::ops::Mul for $id { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self { - use crate::llvm::simd_mul; - unsafe { Simd(simd_mul(self.0, other.0)) } - } - } - - impl crate::ops::Div for $id { - type Output = Self; - #[inline] - fn div(self, other: Self) -> Self { - use crate::llvm::simd_div; - unsafe { Simd(simd_div(self.0, other.0)) } - } - } - - impl crate::ops::Rem for $id { - type Output = Self; - #[inline] - fn rem(self, other: Self) -> Self { - use crate::llvm::simd_rem; - unsafe { Simd(simd_rem(self.0, other.0)) } - } - } - - impl crate::ops::AddAssign for $id { - #[inline] - fn add_assign(&mut self, other: Self) { - *self = *self + other; - } - } - - impl crate::ops::SubAssign for $id { - #[inline] - fn sub_assign(&mut self, other: Self) { - *self = *self - other; - } - } - - impl crate::ops::MulAssign for $id { - #[inline] - fn mul_assign(&mut self, other: Self) { - *self = *self * other; - } - } - - impl crate::ops::DivAssign for $id { - #[inline] - fn div_assign(&mut self, other: Self) { - *self = *self / other; - } - } - - impl crate::ops::RemAssign for $id { - #[inline] - fn rem_assign(&mut self, other: Self) { - *self = *self % other; - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_vector_arith>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn ops_vector_arithmetic() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let f = $id::splat(4 as $elem_ty); - - // add - assert_eq!(z + z, z); - assert_eq!(o + z, o); - assert_eq!(t + z, t); - assert_eq!(t + t, f); - // sub - assert_eq!(z - z, z); - assert_eq!(o - z, o); - assert_eq!(t - z, t); - assert_eq!(f - t, t); - assert_eq!(f - o - o, t); - // mul - assert_eq!(z * z, z); - assert_eq!(z * o, z); - assert_eq!(z * t, z); - assert_eq!(o * t, t); - assert_eq!(t * t, f); - // div - assert_eq!(z / o, z); - assert_eq!(t / o, t); - assert_eq!(f / o, f); - assert_eq!(t / t, o); - assert_eq!(f / t, t); - // rem - assert_eq!(o % o, z); - assert_eq!(f % t, z); - - { - let mut v = z; - assert_eq!(v, z); - v += o; // add_assign - assert_eq!(v, o); - v -= o; // sub_assign - assert_eq!(v, z); - v = t; - v *= o; // mul_assign - assert_eq!(v, t); - v *= t; - assert_eq!(v, f); - v /= o; // div_assign - assert_eq!(v, f); - v /= t; - assert_eq!(v, t); - v %= t; // rem_assign - assert_eq!(v, z); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_bitwise.rs b/third_party/rust/packed_simd/src/api/ops/vector_bitwise.rs deleted file mode 100644 index 7be9603fa2..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_bitwise.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Vertical (lane-wise) vector-vector bitwise operations. - -macro_rules! impl_ops_vector_bitwise { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $test_tt:tt | - ($true:expr, $false:expr) - ) => { - impl crate::ops::Not for $id { - type Output = Self; - #[inline] - fn not(self) -> Self { - Self::splat($true) ^ self - } - } - impl crate::ops::BitXor for $id { - type Output = Self; - #[inline] - fn bitxor(self, other: Self) -> Self { - use crate::llvm::simd_xor; - unsafe { Simd(simd_xor(self.0, other.0)) } - } - } - impl crate::ops::BitAnd for $id { - type Output = Self; - #[inline] - fn bitand(self, other: Self) -> Self { - use crate::llvm::simd_and; - unsafe { Simd(simd_and(self.0, other.0)) } - } - } - impl crate::ops::BitOr for $id { - type Output = Self; - #[inline] - fn bitor(self, other: Self) -> Self { - use crate::llvm::simd_or; - unsafe { Simd(simd_or(self.0, other.0)) } - } - } - impl crate::ops::BitAndAssign for $id { - #[inline] - fn bitand_assign(&mut self, other: Self) { - *self = *self & other; - } - } - impl crate::ops::BitOrAssign for $id { - #[inline] - fn bitor_assign(&mut self, other: Self) { - *self = *self | other; - } - } - impl crate::ops::BitXorAssign for $id { - #[inline] - fn bitxor_assign(&mut self, other: Self) { - *self = *self ^ other; - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_vector_bitwise>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn ops_vector_bitwise() { - - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let m = $id::splat(!z.extract(0)); - - // Not: - assert_eq!(!z, m); - assert_eq!(!m, z); - - // BitAnd: - assert_eq!(o & o, o); - assert_eq!(o & z, z); - assert_eq!(z & o, z); - assert_eq!(z & z, z); - - assert_eq!(t & t, t); - assert_eq!(t & o, z); - assert_eq!(o & t, z); - - // BitOr: - assert_eq!(o | o, o); - assert_eq!(o | z, o); - assert_eq!(z | o, o); - assert_eq!(z | z, z); - - assert_eq!(t | t, t); - assert_eq!(z | t, t); - assert_eq!(t | z, t); - - // BitXOR: - assert_eq!(o ^ o, z); - assert_eq!(z ^ z, z); - assert_eq!(z ^ o, o); - assert_eq!(o ^ z, o); - - assert_eq!(t ^ t, z); - assert_eq!(t ^ z, t); - assert_eq!(z ^ t, t); - - { - // AndAssign: - let mut v = o; - v &= t; - assert_eq!(v, z); - } - { - // OrAssign: - let mut v = z; - v |= o; - assert_eq!(v, o); - } - { - // XORAssign: - let mut v = z; - v ^= o; - assert_eq!(v, o); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_float_min_max.rs b/third_party/rust/packed_simd/src/api/ops/vector_float_min_max.rs deleted file mode 100644 index 8310667b7a..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_float_min_max.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Vertical (lane-wise) vector `min` and `max` for floating-point vectors. - -macro_rules! impl_ops_vector_float_min_max { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Minimum of two vectors. - /// - /// Returns a new vector containing the minimum value of each of - /// the input vector lanes. - #[inline] - pub fn min(self, x: Self) -> Self { - use crate::llvm::simd_fmin; - unsafe { Simd(simd_fmin(self.0, x.0)) } - } - - /// Maximum of two vectors. - /// - /// Returns a new vector containing the maximum value of each of - /// the input vector lanes. - #[inline] - pub fn max(self, x: Self) -> Self { - use crate::llvm::simd_fmax; - unsafe { Simd(simd_fmax(self.0, x.0)) } - } - } - test_if!{ - $test_tt: - paste::item! { - #[cfg(not(any( - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/223 - all(target_arch = "mips", target_endian = "big"), - target_arch = "mips64", - )))] - pub mod [<$id _ops_vector_min_max>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn min_max() { - let n = crate::$elem_ty::NAN; - let o = $id::splat(1. as $elem_ty); - let t = $id::splat(2. as $elem_ty); - - let mut m = o; // [1., 2., 1., 2., ...] - let mut on = o; - for i in 0..$id::lanes() { - if i % 2 == 0 { - m = m.replace(i, 2. as $elem_ty); - on = on.replace(i, n); - } - } - - assert_eq!(o.min(t), o); - assert_eq!(t.min(o), o); - assert_eq!(m.min(o), o); - assert_eq!(o.min(m), o); - assert_eq!(m.min(t), m); - assert_eq!(t.min(m), m); - - assert_eq!(o.max(t), t); - assert_eq!(t.max(o), t); - assert_eq!(m.max(o), m); - assert_eq!(o.max(m), m); - assert_eq!(m.max(t), t); - assert_eq!(t.max(m), t); - - assert_eq!(on.min(o), o); - assert_eq!(o.min(on), o); - assert_eq!(on.max(o), o); - assert_eq!(o.max(on), o); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_int_min_max.rs b/third_party/rust/packed_simd/src/api/ops/vector_int_min_max.rs deleted file mode 100644 index 36ea98e6bf..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_int_min_max.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Vertical (lane-wise) vector `min` and `max` for integer vectors. - -macro_rules! impl_ops_vector_int_min_max { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Minimum of two vectors. - /// - /// Returns a new vector containing the minimum value of each of - /// the input vector lanes. - #[inline] - pub fn min(self, x: Self) -> Self { - self.lt(x).select(self, x) - } - - /// Maximum of two vectors. - /// - /// Returns a new vector containing the maximum value of each of - /// the input vector lanes. - #[inline] - pub fn max(self, x: Self) -> Self { - self.gt(x).select(self, x) - } - } - test_if!{$test_tt: - paste::item! { - pub mod [<$id _ops_vector_min_max>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn min_max() { - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - - let mut m = o; - for i in 0..$id::lanes() { - if i % 2 == 0 { - m = m.replace(i, 2 as $elem_ty); - } - } - assert_eq!(o.min(t), o); - assert_eq!(t.min(o), o); - assert_eq!(m.min(o), o); - assert_eq!(o.min(m), o); - assert_eq!(m.min(t), m); - assert_eq!(t.min(m), m); - - assert_eq!(o.max(t), t); - assert_eq!(t.max(o), t); - assert_eq!(m.max(o), m); - assert_eq!(o.max(m), m); - assert_eq!(m.max(t), t); - assert_eq!(t.max(m), t); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_mask_bitwise.rs b/third_party/rust/packed_simd/src/api/ops/vector_mask_bitwise.rs deleted file mode 100644 index 295fc1ca81..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_mask_bitwise.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Vertical (lane-wise) vector-vector bitwise operations. - -macro_rules! impl_ops_vector_mask_bitwise { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $test_tt:tt | - ($true:expr, $false:expr) - ) => { - impl crate::ops::Not for $id { - type Output = Self; - #[inline] - fn not(self) -> Self { - Self::splat($true) ^ self - } - } - impl crate::ops::BitXor for $id { - type Output = Self; - #[inline] - fn bitxor(self, other: Self) -> Self { - use crate::llvm::simd_xor; - unsafe { Simd(simd_xor(self.0, other.0)) } - } - } - impl crate::ops::BitAnd for $id { - type Output = Self; - #[inline] - fn bitand(self, other: Self) -> Self { - use crate::llvm::simd_and; - unsafe { Simd(simd_and(self.0, other.0)) } - } - } - impl crate::ops::BitOr for $id { - type Output = Self; - #[inline] - fn bitor(self, other: Self) -> Self { - use crate::llvm::simd_or; - unsafe { Simd(simd_or(self.0, other.0)) } - } - } - impl crate::ops::BitAndAssign for $id { - #[inline] - fn bitand_assign(&mut self, other: Self) { - *self = *self & other; - } - } - impl crate::ops::BitOrAssign for $id { - #[inline] - fn bitor_assign(&mut self, other: Self) { - *self = *self | other; - } - } - impl crate::ops::BitXorAssign for $id { - #[inline] - fn bitxor_assign(&mut self, other: Self) { - *self = *self ^ other; - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_vector_mask_bitwise>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn ops_vector_mask_bitwise() { - let t = $id::splat(true); - let f = $id::splat(false); - assert!(t != f); - assert!(!(t == f)); - - // Not: - assert_eq!(!t, f); - assert_eq!(t, !f); - - // BitAnd: - assert_eq!(t & f, f); - assert_eq!(f & t, f); - assert_eq!(t & t, t); - assert_eq!(f & f, f); - - // BitOr: - assert_eq!(t | f, t); - assert_eq!(f | t, t); - assert_eq!(t | t, t); - assert_eq!(f | f, f); - - // BitXOR: - assert_eq!(t ^ f, t); - assert_eq!(f ^ t, t); - assert_eq!(t ^ t, f); - assert_eq!(f ^ f, f); - - { - // AndAssign: - let mut v = f; - v &= t; - assert_eq!(v, f); - } - { - // OrAssign: - let mut v = f; - v |= t; - assert_eq!(v, t); - } - { - // XORAssign: - let mut v = f; - v ^= t; - assert_eq!(v, t); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_neg.rs b/third_party/rust/packed_simd/src/api/ops/vector_neg.rs deleted file mode 100644 index e2d91fd2fe..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_neg.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Vertical (lane-wise) vector `Neg`. - -macro_rules! impl_ops_vector_neg { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::ops::Neg for $id { - type Output = Self; - #[inline] - fn neg(self) -> Self { - Self::splat(-1 as $elem_ty) * self - } - } - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_vector_neg>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn neg() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let f = $id::splat(4 as $elem_ty); - - let nz = $id::splat(-(0 as $elem_ty)); - let no = $id::splat(-(1 as $elem_ty)); - let nt = $id::splat(-(2 as $elem_ty)); - let nf = $id::splat(-(4 as $elem_ty)); - - assert_eq!(-z, nz); - assert_eq!(-o, no); - assert_eq!(-t, nt); - assert_eq!(-f, nf); - - assert_eq!(z, -nz); - assert_eq!(o, -no); - assert_eq!(t, -nt); - assert_eq!(f, -nf); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_rotates.rs b/third_party/rust/packed_simd/src/api/ops/vector_rotates.rs deleted file mode 100644 index 6c4bed72a2..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_rotates.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Vertical (lane-wise) vector rotates operations. -#![allow(unused)] - -macro_rules! impl_ops_vector_rotates { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Shifts the bits of each lane to the left by the specified - /// amount in the corresponding lane of `n`, wrapping the - /// truncated bits to the end of the resulting integer. - /// - /// Note: this is neither the same operation as `<<` nor equivalent - /// to `slice::rotate_left`. - #[inline] - pub fn rotate_left(self, n: $id) -> $id { - const LANE_WIDTH: $elem_ty = - crate::mem::size_of::<$elem_ty>() as $elem_ty * 8; - // Protect against undefined behavior for over-long bit shifts - let n = n % LANE_WIDTH; - (self << n) | (self >> ((LANE_WIDTH - n) % LANE_WIDTH)) - } - - /// Shifts the bits of each lane to the right by the specified - /// amount in the corresponding lane of `n`, wrapping the - /// truncated bits to the beginning of the resulting integer. - /// - /// Note: this is neither the same operation as `>>` nor equivalent - /// to `slice::rotate_right`. - #[inline] - pub fn rotate_right(self, n: $id) -> $id { - const LANE_WIDTH: $elem_ty = - crate::mem::size_of::<$elem_ty>() as $elem_ty * 8; - // Protect against undefined behavior for over-long bit shifts - let n = n % LANE_WIDTH; - (self >> n) | (self << ((LANE_WIDTH - n) % LANE_WIDTH)) - } - } - - test_if!{ - $test_tt: - paste::item! { - // FIXME: - // https://github.com/rust-lang-nursery/packed_simd/issues/75 - #[cfg(not(any( - target_arch = "s390x", - target_arch = "sparc64", - )))] - pub mod [<$id _ops_vector_rotate>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "aarch64"))] - //~^ FIXME: https://github.com/rust-lang/packed_simd/issues/317 - fn rotate_ops() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let f = $id::splat(4 as $elem_ty); - - let max = $id::splat( - (mem::size_of::<$elem_ty>() * 8 - 1) as $elem_ty); - - // rotate_right - assert_eq!(z.rotate_right(z), z); - assert_eq!(z.rotate_right(o), z); - assert_eq!(z.rotate_right(t), z); - - assert_eq!(o.rotate_right(z), o); - assert_eq!(t.rotate_right(z), t); - assert_eq!(f.rotate_right(z), f); - assert_eq!(f.rotate_right(max), f << 1); - - assert_eq!(o.rotate_right(o), o << max); - assert_eq!(t.rotate_right(o), o); - assert_eq!(t.rotate_right(t), o << max); - assert_eq!(f.rotate_right(o), t); - assert_eq!(f.rotate_right(t), o); - - // rotate_left - assert_eq!(z.rotate_left(z), z); - assert_eq!(o.rotate_left(z), o); - assert_eq!(t.rotate_left(z), t); - assert_eq!(f.rotate_left(z), f); - assert_eq!(f.rotate_left(max), t); - - assert_eq!(o.rotate_left(o), t); - assert_eq!(o.rotate_left(t), f); - assert_eq!(t.rotate_left(o), f); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ops/vector_shifts.rs b/third_party/rust/packed_simd/src/api/ops/vector_shifts.rs deleted file mode 100644 index 8bb5ac2fc0..0000000000 --- a/third_party/rust/packed_simd/src/api/ops/vector_shifts.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! Vertical (lane-wise) vector-vector shifts operations. - -macro_rules! impl_ops_vector_shifts { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl crate::ops::Shl<$id> for $id { - type Output = Self; - #[inline] - fn shl(self, other: Self) -> Self { - use crate::llvm::simd_shl; - unsafe { Simd(simd_shl(self.0, other.0)) } - } - } - impl crate::ops::Shr<$id> for $id { - type Output = Self; - #[inline] - fn shr(self, other: Self) -> Self { - use crate::llvm::simd_shr; - unsafe { Simd(simd_shr(self.0, other.0)) } - } - } - impl crate::ops::ShlAssign<$id> for $id { - #[inline] - fn shl_assign(&mut self, other: Self) { - *self = *self << other; - } - } - impl crate::ops::ShrAssign<$id> for $id { - #[inline] - fn shr_assign(&mut self, other: Self) { - *self = *self >> other; - } - } - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _ops_vector_shifts>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg_attr(any(target_arch = "s390x", target_arch = "sparc64"), - allow(unreachable_code, unused_variables) - )] - #[cfg(not(target_arch = "aarch64"))] - //~^ FIXME: https://github.com/rust-lang/packed_simd/issues/317 - fn ops_vector_shifts() { - let z = $id::splat(0 as $elem_ty); - let o = $id::splat(1 as $elem_ty); - let t = $id::splat(2 as $elem_ty); - let f = $id::splat(4 as $elem_ty); - - let max =$id::splat( - (mem::size_of::<$elem_ty>() * 8 - 1) as $elem_ty - ); - - // shr - assert_eq!(z >> z, z); - assert_eq!(z >> o, z); - assert_eq!(z >> t, z); - assert_eq!(z >> t, z); - - #[cfg(any(target_arch = "s390x", target_arch = "sparc64"))] { - // FIXME: rust produces bad codegen for shifts: - // https://github.com/rust-lang-nursery/packed_simd/issues/13 - return; - } - - assert_eq!(o >> z, o); - assert_eq!(t >> z, t); - assert_eq!(f >> z, f); - assert_eq!(f >> max, z); - - assert_eq!(o >> o, z); - assert_eq!(t >> o, o); - assert_eq!(t >> t, z); - assert_eq!(f >> o, t); - assert_eq!(f >> t, o); - assert_eq!(f >> max, z); - - // shl - assert_eq!(z << z, z); - assert_eq!(o << z, o); - assert_eq!(t << z, t); - assert_eq!(f << z, f); - assert_eq!(f << max, z); - - assert_eq!(o << o, t); - assert_eq!(o << t, f); - assert_eq!(t << o, f); - - { - // shr_assign - let mut v = o; - v >>= o; - assert_eq!(v, z); - } - { - // shl_assign - let mut v = o; - v <<= o; - assert_eq!(v, t); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/ptr.rs b/third_party/rust/packed_simd/src/api/ptr.rs deleted file mode 100644 index d2e523a49f..0000000000 --- a/third_party/rust/packed_simd/src/api/ptr.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Vector of pointers - -#[macro_use] -mod gather_scatter; diff --git a/third_party/rust/packed_simd/src/api/ptr/gather_scatter.rs b/third_party/rust/packed_simd/src/api/ptr/gather_scatter.rs deleted file mode 100644 index 374482ac31..0000000000 --- a/third_party/rust/packed_simd/src/api/ptr/gather_scatter.rs +++ /dev/null @@ -1,216 +0,0 @@ -//! Implements masked gather and scatters for vectors of pointers - -macro_rules! impl_ptr_read { - ([$elem_ty:ty; $elem_count:expr]: $id:ident, $mask_ty:ident - | $test_tt:tt) => { - impl $id - where - [T; $elem_count]: sealed::SimdArray, - { - /// Reads selected vector elements from memory. - /// - /// Instantiates a new vector by reading the values from `self` for - /// those lanes whose `mask` is `true`, and using the elements of - /// `value` otherwise. - /// - /// No memory is accessed for those lanes of `self` whose `mask` is - /// `false`. - /// - /// # Safety - /// - /// This method is unsafe because it dereferences raw pointers. The - /// pointers must be aligned to `mem::align_of::()`. - #[inline] - pub unsafe fn read( - self, - mask: Simd<[M; $elem_count]>, - value: Simd<[T; $elem_count]>, - ) -> Simd<[T; $elem_count]> - where - M: sealed::Mask, - [M; $elem_count]: sealed::SimdArray, - { - use crate::llvm::simd_gather; - Simd(simd_gather(value.0, self.0, mask.0)) - } - } - - test_if! { - $test_tt: - paste::item! { - mod [<$id _read>] { - use super::*; - #[test] - fn read() { - let mut v = [0_i32; $elem_count]; - for i in 0..$elem_count { - v[i] = i as i32; - } - - let mut ptr = $id::::null(); - - for i in 0..$elem_count { - ptr = ptr.replace(i, - &v[i] as *const i32 as *mut i32 - ); - } - - // all mask elements are true: - let mask = $mask_ty::splat(true); - let def = Simd::<[i32; $elem_count]>::splat(42_i32); - let r: Simd<[i32; $elem_count]> = unsafe { - ptr.read(mask, def) - }; - assert_eq!( - r, - Simd::<[i32; $elem_count]>::from_slice_unaligned( - &v - ) - ); - - let mut mask = mask; - for i in 0..$elem_count { - if i % 2 != 0 { - mask = mask.replace(i, false); - } - } - - // even mask elements are true, odd ones are false: - let r: Simd<[i32; $elem_count]> = unsafe { - ptr.read(mask, def) - }; - let mut e = v; - for i in 0..$elem_count { - if i % 2 != 0 { - e[i] = 42; - } - } - assert_eq!( - r, - Simd::<[i32; $elem_count]>::from_slice_unaligned( - &e - ) - ); - - // all mask elements are false: - let mask = $mask_ty::splat(false); - let def = Simd::<[i32; $elem_count]>::splat(42_i32); - let r: Simd<[i32; $elem_count]> = unsafe { - ptr.read(mask, def) } - ; - assert_eq!(r, def); - } - } - } - } - }; -} - -macro_rules! impl_ptr_write { - ([$elem_ty:ty; $elem_count:expr]: $id:ident, $mask_ty:ident - | $test_tt:tt) => { - impl $id - where - [T; $elem_count]: sealed::SimdArray, - { - /// Writes selected vector elements to memory. - /// - /// Writes the lanes of `values` for which the mask is `true` to - /// their corresponding memory addresses in `self`. - /// - /// No memory is accessed for those lanes of `self` whose `mask` is - /// `false`. - /// - /// Overlapping memory addresses of `self` are written to in order - /// from the lest-significant to the most-significant element. - /// - /// # Safety - /// - /// This method is unsafe because it dereferences raw pointers. The - /// pointers must be aligned to `mem::align_of::()`. - #[inline] - pub unsafe fn write(self, mask: Simd<[M; $elem_count]>, value: Simd<[T; $elem_count]>) - where - M: sealed::Mask, - [M; $elem_count]: sealed::SimdArray, - { - use crate::llvm::simd_scatter; - simd_scatter(value.0, self.0, mask.0) - } - } - - test_if! { - $test_tt: - paste::item! { - mod [<$id _write>] { - use super::*; - #[test] - fn write() { - // forty_two = [42, 42, 42, ...] - let forty_two - = Simd::<[i32; $elem_count]>::splat(42_i32); - - // This test will write to this array - let mut arr = [0_i32; $elem_count]; - for i in 0..$elem_count { - arr[i] = i as i32; - } - // arr = [0, 1, 2, ...] - - let mut ptr = $id::::null(); - for i in 0..$elem_count { - ptr = ptr.replace(i, unsafe { - arr.as_ptr().add(i) as *mut i32 - }); - } - // ptr = [&arr[0], &arr[1], ...] - - // write `forty_two` to all elements of `v` - { - let backup = arr; - unsafe { - ptr.write($mask_ty::splat(true), forty_two) - }; - assert_eq!(arr, [42_i32; $elem_count]); - arr = backup; // arr = [0, 1, 2, ...] - } - - // write 42 to even elements of arr: - { - // set odd elements of the mask to false - let mut mask = $mask_ty::splat(true); - for i in 0..$elem_count { - if i % 2 != 0 { - mask = mask.replace(i, false); - } - } - // mask = [true, false, true, false, ...] - - // expected result r = [42, 1, 42, 3, 42, 5, ...] - let mut r = arr; - for i in 0..$elem_count { - if i % 2 == 0 { - r[i] = 42; - } - } - - let backup = arr; - unsafe { ptr.write(mask, forty_two) }; - assert_eq!(arr, r); - arr = backup; // arr = [0, 1, 2, 3, ...] - } - - // write 42 to no elements of arr - { - let backup = arr; - unsafe { - ptr.write($mask_ty::splat(false), forty_two) - }; - assert_eq!(arr, backup); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/reductions.rs b/third_party/rust/packed_simd/src/api/reductions.rs deleted file mode 100644 index 54d2f0cc7f..0000000000 --- a/third_party/rust/packed_simd/src/api/reductions.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! Reductions - -#[macro_use] -mod float_arithmetic; -#[macro_use] -mod integer_arithmetic; -#[macro_use] -mod bitwise; -#[macro_use] -mod mask; -#[macro_use] -mod min_max; diff --git a/third_party/rust/packed_simd/src/api/reductions/bitwise.rs b/third_party/rust/packed_simd/src/api/reductions/bitwise.rs deleted file mode 100644 index 5bad4f474b..0000000000 --- a/third_party/rust/packed_simd/src/api/reductions/bitwise.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Implements portable horizontal bitwise vector reductions. -#![allow(unused)] - -macro_rules! impl_reduction_bitwise { - ( - [$elem_ty:ident; $elem_count:expr]: - $id:ident | $ielem_ty:ident | $test_tt:tt | - ($convert:expr) | - ($true:expr, $false:expr) - ) => { - impl $id { - /// Lane-wise bitwise `and` of the vector elements. - /// - /// Note: if the vector has one lane, the first element of the - /// vector is returned. - #[inline] - pub fn and(self) -> $elem_ty { - #[cfg(not(target_arch = "aarch64"))] - { - use crate::llvm::simd_reduce_and; - let r: $ielem_ty = unsafe { simd_reduce_and(self.0) }; - $convert(r) - } - #[cfg(target_arch = "aarch64")] - { - // FIXME: broken on aarch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - let mut x = self.extract(0) as $elem_ty; - for i in 1..$id::lanes() { - x &= self.extract(i) as $elem_ty; - } - x - } - } - - /// Lane-wise bitwise `or` of the vector elements. - /// - /// Note: if the vector has one lane, the first element of the - /// vector is returned. - #[inline] - pub fn or(self) -> $elem_ty { - #[cfg(not(target_arch = "aarch64"))] - { - use crate::llvm::simd_reduce_or; - let r: $ielem_ty = unsafe { simd_reduce_or(self.0) }; - $convert(r) - } - #[cfg(target_arch = "aarch64")] - { - // FIXME: broken on aarch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - let mut x = self.extract(0) as $elem_ty; - for i in 1..$id::lanes() { - x |= self.extract(i) as $elem_ty; - } - x - } - } - - /// Lane-wise bitwise `xor` of the vector elements. - /// - /// Note: if the vector has one lane, the first element of the - /// vector is returned. - #[inline] - pub fn xor(self) -> $elem_ty { - #[cfg(not(target_arch = "aarch64"))] - { - use crate::llvm::simd_reduce_xor; - let r: $ielem_ty = unsafe { simd_reduce_xor(self.0) }; - $convert(r) - } - #[cfg(target_arch = "aarch64")] - { - // FIXME: broken on aarch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - let mut x = self.extract(0) as $elem_ty; - for i in 1..$id::lanes() { - x ^= self.extract(i) as $elem_ty; - } - x - } - } - } - - test_if!{ - $test_tt: - paste::item! { - pub mod [<$id _reduction_bitwise>] { - use super::*; - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn and() { - let v = $id::splat($false); - assert_eq!(v.and(), $false); - let v = $id::splat($true); - assert_eq!(v.and(), $true); - let v = $id::splat($false); - let v = v.replace(0, $true); - if $id::lanes() > 1 { - assert_eq!(v.and(), $false); - } else { - assert_eq!(v.and(), $true); - } - let v = $id::splat($true); - let v = v.replace(0, $false); - assert_eq!(v.and(), $false); - - } - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn or() { - let v = $id::splat($false); - assert_eq!(v.or(), $false); - let v = $id::splat($true); - assert_eq!(v.or(), $true); - let v = $id::splat($false); - let v = v.replace(0, $true); - assert_eq!(v.or(), $true); - let v = $id::splat($true); - let v = v.replace(0, $false); - if $id::lanes() > 1 { - assert_eq!(v.or(), $true); - } else { - assert_eq!(v.or(), $false); - } - } - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn xor() { - let v = $id::splat($false); - assert_eq!(v.xor(), $false); - let v = $id::splat($true); - if $id::lanes() > 1 { - assert_eq!(v.xor(), $false); - } else { - assert_eq!(v.xor(), $true); - } - let v = $id::splat($false); - let v = v.replace(0, $true); - assert_eq!(v.xor(), $true); - let v = $id::splat($true); - let v = v.replace(0, $false); - if $id::lanes() > 1 { - assert_eq!(v.xor(), $true); - } else { - assert_eq!(v.xor(), $false); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/reductions/float_arithmetic.rs b/third_party/rust/packed_simd/src/api/reductions/float_arithmetic.rs deleted file mode 100644 index 9dc8783dbb..0000000000 --- a/third_party/rust/packed_simd/src/api/reductions/float_arithmetic.rs +++ /dev/null @@ -1,313 +0,0 @@ -//! Implements portable horizontal float vector arithmetic reductions. - -macro_rules! impl_reduction_float_arithmetic { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Horizontal sum of the vector elements. - /// - /// The intrinsic performs a tree-reduction of the vector elements. - /// That is, for an 8 element vector: - /// - /// > ((x0 + x1) + (x2 + x3)) + ((x4 + x5) + (x6 + x7)) - /// - /// If one of the vector element is `NaN` the reduction returns - /// `NaN`. The resulting `NaN` is not required to be equal to any - /// of the `NaN`s in the vector. - #[inline] - pub fn sum(self) -> $elem_ty { - #[cfg(not(target_arch = "aarch64"))] - { - use crate::llvm::simd_reduce_add_ordered; - unsafe { simd_reduce_add_ordered(self.0, 0 as $elem_ty) } - } - #[cfg(target_arch = "aarch64")] - { - // FIXME: broken on AArch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - let mut x = self.extract(0) as $elem_ty; - for i in 1..$id::lanes() { - x += self.extract(i) as $elem_ty; - } - x - } - } - - /// Horizontal product of the vector elements. - /// - /// The intrinsic performs a tree-reduction of the vector elements. - /// That is, for an 8 element vector: - /// - /// > ((x0 * x1) * (x2 * x3)) * ((x4 * x5) * (x6 * x7)) - /// - /// If one of the vector element is `NaN` the reduction returns - /// `NaN`. The resulting `NaN` is not required to be equal to any - /// of the `NaN`s in the vector. - #[inline] - pub fn product(self) -> $elem_ty { - #[cfg(not(target_arch = "aarch64"))] - { - use crate::llvm::simd_reduce_mul_ordered; - unsafe { simd_reduce_mul_ordered(self.0, 1 as $elem_ty) } - } - #[cfg(target_arch = "aarch64")] - { - // FIXME: broken on AArch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - let mut x = self.extract(0) as $elem_ty; - for i in 1..$id::lanes() { - x *= self.extract(i) as $elem_ty; - } - x - } - } - } - - impl crate::iter::Sum for $id { - #[inline] - fn sum>(iter: I) -> $id { - iter.fold($id::splat(0.), crate::ops::Add::add) - } - } - - impl crate::iter::Product for $id { - #[inline] - fn product>(iter: I) -> $id { - iter.fold($id::splat(1.), crate::ops::Mul::mul) - } - } - - impl<'a> crate::iter::Sum<&'a $id> for $id { - #[inline] - fn sum>(iter: I) -> $id { - iter.fold($id::splat(0.), |a, b| crate::ops::Add::add(a, *b)) - } - } - - impl<'a> crate::iter::Product<&'a $id> for $id { - #[inline] - fn product>(iter: I) -> $id { - iter.fold($id::splat(1.), |a, b| crate::ops::Mul::mul(a, *b)) - } - } - - test_if! { - $test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - pub mod [<$id _reduction_float_arith>] { - use super::*; - fn alternating(x: usize) -> $id { - let mut v = $id::splat(1 as $elem_ty); - for i in 0..$id::lanes() { - if i % x == 0 { - v = v.replace(i, 2 as $elem_ty); - } - } - v - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn sum() { - let v = $id::splat(0 as $elem_ty); - assert_eq!(v.sum(), 0 as $elem_ty); - let v = $id::splat(1 as $elem_ty); - assert_eq!(v.sum(), $id::lanes() as $elem_ty); - let v = alternating(2); - assert_eq!( - v.sum(), - ($id::lanes() / 2 + $id::lanes()) as $elem_ty - ); - } - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn product() { - let v = $id::splat(0 as $elem_ty); - assert_eq!(v.product(), 0 as $elem_ty); - let v = $id::splat(1 as $elem_ty); - assert_eq!(v.product(), 1 as $elem_ty); - let f = match $id::lanes() { - 64 => 16, - 32 => 8, - 16 => 4, - _ => 2, - }; - let v = alternating(f); - assert_eq!( - v.product(), - (2_usize.pow(($id::lanes() / f) as u32) - as $elem_ty) - ); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[allow(unreachable_code)] - fn sum_nan() { - // FIXME: https://bugs.llvm.org/show_bug.cgi?id=36732 - // https://github.com/rust-lang-nursery/packed_simd/issues/6 - return; - - let n0 = crate::$elem_ty::NAN; - let v0 = $id::splat(-3.0); - for i in 0..$id::lanes() { - let mut v = v0.replace(i, n0); - // If the vector contains a NaN the result is NaN: - assert!( - v.sum().is_nan(), - "nan at {} => {} | {:?}", - i, - v.sum(), - v - ); - for j in 0..i { - v = v.replace(j, n0); - assert!(v.sum().is_nan()); - } - } - let v = $id::splat(n0); - assert!(v.sum().is_nan(), "all nans | {:?}", v); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[allow(unreachable_code)] - fn product_nan() { - // FIXME: https://bugs.llvm.org/show_bug.cgi?id=36732 - // https://github.com/rust-lang-nursery/packed_simd/issues/6 - return; - - let n0 = crate::$elem_ty::NAN; - let v0 = $id::splat(-3.0); - for i in 0..$id::lanes() { - let mut v = v0.replace(i, n0); - // If the vector contains a NaN the result is NaN: - assert!( - v.product().is_nan(), - "nan at {} => {} | {:?}", - i, - v.product(), - v - ); - for j in 0..i { - v = v.replace(j, n0); - assert!(v.product().is_nan()); - } - } - let v = $id::splat(n0); - assert!(v.product().is_nan(), "all nans | {:?}", v); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[allow(unused, dead_code)] - fn sum_roundoff() { - // Performs a tree-reduction - fn tree_reduce_sum(a: &[$elem_ty]) -> $elem_ty { - assert!(!a.is_empty()); - if a.len() == 1 { - a[0] - } else if a.len() == 2 { - a[0] + a[1] - } else { - let mid = a.len() / 2; - let (left, right) = a.split_at(mid); - tree_reduce_sum(left) + tree_reduce_sum(right) - } - } - - let mut start = crate::$elem_ty::EPSILON; - let mut scalar_reduction = 0. as $elem_ty; - - let mut v = $id::splat(0. as $elem_ty); - for i in 0..$id::lanes() { - let c = if i % 2 == 0 { 1e3 } else { -1. }; - start *= ::core::$elem_ty::consts::PI * c; - scalar_reduction += start; - v = v.replace(i, start); - } - let simd_reduction = v.sum(); - - let mut a = [0. as $elem_ty; $id::lanes()]; - v.write_to_slice_unaligned(&mut a); - let tree_reduction = tree_reduce_sum(&a); - - // tolerate 1 ULP difference: - let red_bits = simd_reduction.to_bits(); - let tree_bits = tree_reduction.to_bits(); - assert!( - if red_bits > tree_bits { - red_bits - tree_bits - } else { - tree_bits - red_bits - } < 2, - "vector: {:?} | simd_reduction: {:?} | \ -tree_reduction: {} | scalar_reduction: {}", - v, - simd_reduction, - tree_reduction, - scalar_reduction - ); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[allow(unused, dead_code)] - fn product_roundoff() { - use ::core::convert::TryInto; - // Performs a tree-reduction - fn tree_reduce_product(a: &[$elem_ty]) -> $elem_ty { - assert!(!a.is_empty()); - if a.len() == 1 { - a[0] - } else if a.len() == 2 { - a[0] * a[1] - } else { - let mid = a.len() / 2; - let (left, right) = a.split_at(mid); - tree_reduce_product(left) - * tree_reduce_product(right) - } - } - - let mut start = crate::$elem_ty::EPSILON; - let mut scalar_reduction = 1. as $elem_ty; - - let mut v = $id::splat(0. as $elem_ty); - for i in 0..$id::lanes() { - let c = if i % 2 == 0 { 1e3 } else { -1. }; - start *= ::core::$elem_ty::consts::PI * c; - scalar_reduction *= start; - v = v.replace(i, start); - } - let simd_reduction = v.product(); - - let mut a = [0. as $elem_ty; $id::lanes()]; - v.write_to_slice_unaligned(&mut a); - let tree_reduction = tree_reduce_product(&a); - - // FIXME: Too imprecise, even only for product(f32x8). - // Figure out how to narrow this down. - let ulp_limit = $id::lanes() / 2; - let red_bits = simd_reduction.to_bits(); - let tree_bits = tree_reduction.to_bits(); - assert!( - if red_bits > tree_bits { - red_bits - tree_bits - } else { - tree_bits - red_bits - } < ulp_limit.try_into().unwrap(), - "vector: {:?} | simd_reduction: {:?} | \ -tree_reduction: {} | scalar_reduction: {}", - v, - simd_reduction, - tree_reduction, - scalar_reduction - ); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/reductions/integer_arithmetic.rs b/third_party/rust/packed_simd/src/api/reductions/integer_arithmetic.rs deleted file mode 100644 index e99e6cb5d7..0000000000 --- a/third_party/rust/packed_simd/src/api/reductions/integer_arithmetic.rs +++ /dev/null @@ -1,193 +0,0 @@ -//! Implements portable horizontal integer vector arithmetic reductions. - -macro_rules! impl_reduction_integer_arithmetic { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $ielem_ty:ident - | $test_tt:tt) => { - impl $id { - /// Horizontal wrapping sum of the vector elements. - /// - /// The intrinsic performs a tree-reduction of the vector elements. - /// That is, for an 8 element vector: - /// - /// > ((x0 + x1) + (x2 + x3)) + ((x4 + x5) + (x6 + x7)) - /// - /// If an operation overflows it returns the mathematical result - /// modulo `2^n` where `n` is the number of times it overflows. - #[inline] - pub fn wrapping_sum(self) -> $elem_ty { - #[cfg(not(target_arch = "aarch64"))] - { - use crate::llvm::simd_reduce_add_ordered; - let v: $ielem_ty = unsafe { simd_reduce_add_ordered(self.0, 0 as $ielem_ty) }; - v as $elem_ty - } - #[cfg(target_arch = "aarch64")] - { - // FIXME: broken on AArch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - let mut x = self.extract(0) as $elem_ty; - for i in 1..$id::lanes() { - x = x.wrapping_add(self.extract(i) as $elem_ty); - } - x - } - } - - /// Horizontal wrapping product of the vector elements. - /// - /// The intrinsic performs a tree-reduction of the vector elements. - /// That is, for an 8 element vector: - /// - /// > ((x0 * x1) * (x2 * x3)) * ((x4 * x5) * (x6 * x7)) - /// - /// If an operation overflows it returns the mathematical result - /// modulo `2^n` where `n` is the number of times it overflows. - #[inline] - pub fn wrapping_product(self) -> $elem_ty { - #[cfg(not(target_arch = "aarch64"))] - { - use crate::llvm::simd_reduce_mul_ordered; - let v: $ielem_ty = unsafe { simd_reduce_mul_ordered(self.0, 1 as $ielem_ty) }; - v as $elem_ty - } - #[cfg(target_arch = "aarch64")] - { - // FIXME: broken on AArch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - let mut x = self.extract(0) as $elem_ty; - for i in 1..$id::lanes() { - x = x.wrapping_mul(self.extract(i) as $elem_ty); - } - x - } - } - } - - impl crate::iter::Sum for $id { - #[inline] - fn sum>(iter: I) -> $id { - iter.fold($id::splat(0), crate::ops::Add::add) - } - } - - impl crate::iter::Product for $id { - #[inline] - fn product>(iter: I) -> $id { - iter.fold($id::splat(1), crate::ops::Mul::mul) - } - } - - impl<'a> crate::iter::Sum<&'a $id> for $id { - #[inline] - fn sum>(iter: I) -> $id { - iter.fold($id::splat(0), |a, b| crate::ops::Add::add(a, *b)) - } - } - - impl<'a> crate::iter::Product<&'a $id> for $id { - #[inline] - fn product>(iter: I) -> $id { - iter.fold($id::splat(1), |a, b| crate::ops::Mul::mul(a, *b)) - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _reduction_int_arith>] { - use super::*; - - fn alternating(x: usize) -> $id { - let mut v = $id::splat(1 as $elem_ty); - for i in 0..$id::lanes() { - if i % x == 0 { - v = v.replace(i, 2 as $elem_ty); - } - } - v - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn wrapping_sum() { - let v = $id::splat(0 as $elem_ty); - assert_eq!(v.wrapping_sum(), 0 as $elem_ty); - let v = $id::splat(1 as $elem_ty); - assert_eq!(v.wrapping_sum(), $id::lanes() as $elem_ty); - let v = alternating(2); - if $id::lanes() > 1 { - assert_eq!( - v.wrapping_sum(), - ($id::lanes() / 2 + $id::lanes()) as $elem_ty - ); - } else { - assert_eq!( - v.wrapping_sum(), - 2 as $elem_ty - ); - } - } - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn wrapping_sum_overflow() { - let start = $elem_ty::max_value() - - ($id::lanes() as $elem_ty / 2); - - let v = $id::splat(start as $elem_ty); - let vwrapping_sum = v.wrapping_sum(); - - let mut wrapping_sum = start; - for _ in 1..$id::lanes() { - wrapping_sum = wrapping_sum.wrapping_add(start); - } - assert_eq!(wrapping_sum, vwrapping_sum, "v = {:?}", v); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn wrapping_product() { - let v = $id::splat(0 as $elem_ty); - assert_eq!(v.wrapping_product(), 0 as $elem_ty); - let v = $id::splat(1 as $elem_ty); - assert_eq!(v.wrapping_product(), 1 as $elem_ty); - let f = match $id::lanes() { - 64 => 16, - 32 => 8, - 16 => 4, - _ => 2, - }; - let v = alternating(f); - if $id::lanes() > 1 { - assert_eq!( - v.wrapping_product(), - (2_usize.pow(($id::lanes() / f) as u32) - as $elem_ty) - ); - } else { - assert_eq!( - v.wrapping_product(), - 2 as $elem_ty - ); - } - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn wrapping_product_overflow() { - let start = $elem_ty::max_value() - - ($id::lanes() as $elem_ty / 2); - - let v = $id::splat(start as $elem_ty); - let vmul = v.wrapping_product(); - - let mut mul = start; - for _ in 1..$id::lanes() { - mul = mul.wrapping_mul(start); - } - assert_eq!(mul, vmul, "v = {:?}", v); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/reductions/mask.rs b/third_party/rust/packed_simd/src/api/reductions/mask.rs deleted file mode 100644 index 0dd6a84e7e..0000000000 --- a/third_party/rust/packed_simd/src/api/reductions/mask.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Implements portable horizontal mask reductions. - -macro_rules! impl_reduction_mask { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Are `all` vector lanes `true`? - #[inline] - pub fn all(self) -> bool { - unsafe { crate::codegen::reductions::mask::All::all(self) } - } - /// Is `any` vector lane `true`? - #[inline] - pub fn any(self) -> bool { - unsafe { crate::codegen::reductions::mask::Any::any(self) } - } - /// Are `all` vector lanes `false`? - #[inline] - pub fn none(self) -> bool { - !self.any() - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _reduction>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn all() { - let a = $id::splat(true); - assert!(a.all()); - let a = $id::splat(false); - assert!(!a.all()); - - if $id::lanes() > 1 { - for i in 0..$id::lanes() { - let mut a = $id::splat(true); - a = a.replace(i, false); - assert!(!a.all()); - let mut a = $id::splat(false); - a = a.replace(i, true); - assert!(!a.all()); - } - } - } - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn any() { - let a = $id::splat(true); - assert!(a.any()); - let a = $id::splat(false); - assert!(!a.any()); - - if $id::lanes() > 1 { - for i in 0..$id::lanes() { - let mut a = $id::splat(true); - a = a.replace(i, false); - assert!(a.any()); - let mut a = $id::splat(false); - a = a.replace(i, true); - assert!(a.any()); - } - } - } - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn none() { - let a = $id::splat(true); - assert!(!a.none()); - let a = $id::splat(false); - assert!(a.none()); - - if $id::lanes() > 1 { - for i in 0..$id::lanes() { - let mut a = $id::splat(true); - a = a.replace(i, false); - assert!(!a.none()); - let mut a = $id::splat(false); - a = a.replace(i, true); - assert!(!a.none()); - } - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/reductions/min_max.rs b/third_party/rust/packed_simd/src/api/reductions/min_max.rs deleted file mode 100644 index a3ce13a451..0000000000 --- a/third_party/rust/packed_simd/src/api/reductions/min_max.rs +++ /dev/null @@ -1,360 +0,0 @@ -//! Implements portable horizontal vector min/max reductions. - -macro_rules! impl_reduction_min_max { - ([$elem_ty:ident; $elem_count:expr]: $id:ident - | $ielem_ty:ident | $test_tt:tt) => { - impl $id { - /// Largest vector element value. - #[inline] - pub fn max_element(self) -> $elem_ty { - #[cfg(not(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "wasm32", - )))] - { - use crate::llvm::simd_reduce_max; - let v: $ielem_ty = unsafe { simd_reduce_max(self.0) }; - v as $elem_ty - } - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "wasm32", - ))] - { - // FIXME: broken on AArch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - // FIXME: broken on WASM32 - // https://github.com/rust-lang-nursery/packed_simd/issues/91 - let mut x = self.extract(0); - for i in 1..$id::lanes() { - x = x.max(self.extract(i)); - } - x - } - } - - /// Smallest vector element value. - #[inline] - pub fn min_element(self) -> $elem_ty { - #[cfg(not(any( - target_arch = "aarch64", - target_arch = "arm", - all(target_arch = "x86", not(target_feature = "sse2")), - target_arch = "powerpc64", - target_arch = "wasm32", - ),))] - { - use crate::llvm::simd_reduce_min; - let v: $ielem_ty = unsafe { simd_reduce_min(self.0) }; - v as $elem_ty - } - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - all(target_arch = "x86", not(target_feature = "sse2")), - target_arch = "powerpc64", - target_arch = "wasm32", - ))] - { - // FIXME: broken on AArch64 - // https://github.com/rust-lang-nursery/packed_simd/issues/15 - // FIXME: broken on i586-unknown-linux-gnu - // https://github.com/rust-lang-nursery/packed_simd/issues/22 - // FIXME: broken on WASM32 - // https://github.com/rust-lang-nursery/packed_simd/issues/91 - let mut x = self.extract(0); - for i in 1..$id::lanes() { - x = x.min(self.extract(i)); - } - x - } - } - } - test_if! {$test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - pub mod [<$id _reduction_min_max>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - pub fn max_element() { - let v = $id::splat(0 as $elem_ty); - assert_eq!(v.max_element(), 0 as $elem_ty); - if $id::lanes() > 1 { - let v = v.replace(1, 1 as $elem_ty); - assert_eq!(v.max_element(), 1 as $elem_ty); - } - let v = v.replace(0, 2 as $elem_ty); - assert_eq!(v.max_element(), 2 as $elem_ty); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - pub fn min_element() { - let v = $id::splat(0 as $elem_ty); - assert_eq!(v.min_element(), 0 as $elem_ty); - if $id::lanes() > 1 { - let v = v.replace(1, 1 as $elem_ty); - assert_eq!(v.min_element(), 0 as $elem_ty); - } - let v = $id::splat(1 as $elem_ty); - let v = v.replace(0, 2 as $elem_ty); - if $id::lanes() > 1 { - assert_eq!(v.min_element(), 1 as $elem_ty); - } else { - assert_eq!(v.min_element(), 2 as $elem_ty); - } - if $id::lanes() > 1 { - let v = $id::splat(2 as $elem_ty); - let v = v.replace(1, 1 as $elem_ty); - assert_eq!(v.min_element(), 1 as $elem_ty); - } - } - } - } - } - }; -} - -macro_rules! test_reduction_float_min_max { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - test_if! { - $test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - pub mod [<$id _reduction_min_max_nan>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn min_element_test() { - let n = crate::$elem_ty::NAN; - - assert_eq!(n.min(-3.), -3.); - assert_eq!((-3. as $elem_ty).min(n), -3.); - - let v0 = $id::splat(-3.); - - let target_with_broken_last_lane_nan = !cfg!(any( - target_arch = "arm", target_arch = "aarch64", - all(target_arch = "x86", - not(target_feature = "sse2") - ), - target_arch = "powerpc64", - target_arch = "wasm32", - )); - - // The vector is initialized to `-3.`s: [-3, -3, -3, -3] - for i in 0..$id::lanes() { - // We replace the i-th element of the vector with - // `NaN`: [-3, -3, -3, NaN] - let mut v = v0.replace(i, n); - - // If the NaN is in the last place, the LLVM - // implementation of these methods is broken on some - // targets: - if i == $id::lanes() - 1 && - target_with_broken_last_lane_nan { - assert_eq!(v.min_element(), -3., - "[A]: nan at {} => {} | {:?}", - i, v.min_element(), v); - - // If we replace all the elements in the vector - // up-to the `i-th` lane with `NaN`s, the result - // is still always `-3.` unless all elements of - // the vector are `NaN`s: - for j in 0..i { - v = v.replace(j, n); - if j == i-1 { - assert!(v.min_element().is_nan(), - "[B]: nan at {} => {} | {:?}", - i, v.min_element(), v); - } else { - assert_eq!(v.min_element(), -3., - "[B]: nan at {} => {} | {:?}", - i, v.min_element(), v); - } - } - - // We are done here, since we were in the last - // lane which is the last iteration of the loop. - break - } - - // We are not in the last lane, and there is only - // one `NaN` in the vector. - - // If the vector has one lane, the result is `NaN`: - if $id::lanes() == 1 { - assert!(v.min_element().is_nan(), - "[C]: all nans | v={:?} | min={} | \ -is_nan: {}", - v, v.min_element(), - v.min_element().is_nan() - ); - - // And we are done, since the vector only has - // one lane anyways. - break; - } - - // The vector has more than one lane, since there is - // only one `NaN` in the vector, the result is - // always `-3`. - assert_eq!(v.min_element(), -3., - "[D]: nan at {} => {} | {:?}", - i, v.min_element(), v); - - // If we replace all the elements in the vector - // up-to the `i-th` lane with `NaN`s, the result is - // still always `-3.` unless all elements of the - // vector are `NaN`s: - for j in 0..i { - v = v.replace(j, n); - - if i == $id::lanes() - 1 && j == i - 1 { - // All elements of the vector are `NaN`s, - // therefore the result is NaN as well. - // - // Note: the #lanes of the vector is > 1, so - // "i - 1" does not overflow. - assert!(v.min_element().is_nan(), - "[E]: all nans | v={:?} | min={} | \ -is_nan: {}", - v, v.min_element(), - v.min_element().is_nan()); - } else { - // There are non-`NaN` elements in the - // vector, therefore the result is `-3.`: - assert_eq!(v.min_element(), -3., - "[F]: nan at {} => {} | {:?}", - i, v.min_element(), v); - } - } - } - - // If the vector contains all NaNs the result is NaN: - assert!($id::splat(n).min_element().is_nan(), - "all nans | v={:?} | min={} | is_nan: {}", - $id::splat(n), $id::splat(n).min_element(), - $id::splat(n).min_element().is_nan()); - } - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn max_element_test() { - let n = crate::$elem_ty::NAN; - - assert_eq!(n.max(-3.), -3.); - assert_eq!((-3. as $elem_ty).max(n), -3.); - - let v0 = $id::splat(-3.); - - let target_with_broken_last_lane_nan = !cfg!(any( - target_arch = "arm", target_arch = "aarch64", - target_arch = "powerpc64", target_arch = "wasm32", - )); - - // The vector is initialized to `-3.`s: [-3, -3, -3, -3] - for i in 0..$id::lanes() { - // We replace the i-th element of the vector with - // `NaN`: [-3, -3, -3, NaN] - let mut v = v0.replace(i, n); - - // If the NaN is in the last place, the LLVM - // implementation of these methods is broken on some - // targets: - if i == $id::lanes() - 1 && - target_with_broken_last_lane_nan { - assert_eq!(v.max_element(), -3., - "[A]: nan at {} => {} | {:?}", - i, v.max_element(), v); - - // If we replace all the elements in the vector - // up-to the `i-th` lane with `NaN`s, the result - // is still always `-3.` unless all elements of - // the vector are `NaN`s: - for j in 0..i { - v = v.replace(j, n); - if j == i-1 { - assert!(v.min_element().is_nan(), - "[B]: nan at {} => {} | {:?}", - i, v.min_element(), v); - } else { - assert_eq!(v.max_element(), -3., - "[B]: nan at {} => {} | {:?}", - i, v.max_element(), v); - } - } - - // We are done here, since we were in the last - // lane which is the last iteration of the loop. - break - } - - // We are not in the last lane, and there is only - // one `NaN` in the vector. - - // If the vector has one lane, the result is `NaN`: - if $id::lanes() == 1 { - assert!(v.max_element().is_nan(), - "[C]: all nans | v={:?} | min={} | \ -is_nan: {}", - v, v.max_element(), - v.max_element().is_nan()); - - // And we are done, since the vector only has - // one lane anyways. - break; - } - - // The vector has more than one lane, since there is - // only one `NaN` in the vector, the result is - // always `-3`. - assert_eq!(v.max_element(), -3., - "[D]: nan at {} => {} | {:?}", - i, v.max_element(), v); - - // If we replace all the elements in the vector - // up-to the `i-th` lane with `NaN`s, the result is - // still always `-3.` unless all elements of the - // vector are `NaN`s: - for j in 0..i { - v = v.replace(j, n); - - if i == $id::lanes() - 1 && j == i - 1 { - // All elements of the vector are `NaN`s, - // therefore the result is NaN as well. - // - // Note: the #lanes of the vector is > 1, so - // "i - 1" does not overflow. - assert!(v.max_element().is_nan(), - "[E]: all nans | v={:?} | max={} | \ -is_nan: {}", - v, v.max_element(), - v.max_element().is_nan()); - } else { - // There are non-`NaN` elements in the - // vector, therefore the result is `-3.`: - assert_eq!(v.max_element(), -3., - "[F]: nan at {} => {} | {:?}", - i, v.max_element(), v); - } - } - } - - // If the vector contains all NaNs the result is NaN: - assert!($id::splat(n).max_element().is_nan(), - "all nans | v={:?} | max={} | is_nan: {}", - $id::splat(n), $id::splat(n).max_element(), - $id::splat(n).max_element().is_nan()); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/select.rs b/third_party/rust/packed_simd/src/api/select.rs deleted file mode 100644 index daf6294721..0000000000 --- a/third_party/rust/packed_simd/src/api/select.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Implements mask's `select`. - -/// Implements mask select method -macro_rules! impl_select { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Selects elements of `a` and `b` using mask. - /// - /// The lanes of the result for which the mask is `true` contain - /// the values of `a`. The remaining lanes contain the values of - /// `b`. - #[inline] - pub fn select(self, a: Simd, b: Simd) -> Simd - where - T: sealed::SimdArray::NT>, - { - use crate::llvm::simd_select; - Simd(unsafe { simd_select(self.0, a.0, b.0) }) - } - } - - test_select!(bool, $id, $id, (false, true) | $test_tt); - }; -} - -macro_rules! test_select { - ( - $elem_ty:ident, - $mask_ty:ident, - $vec_ty:ident,($small:expr, $large:expr) | - $test_tt:tt - ) => { - test_if! { - $test_tt: - paste::item! { - pub mod [<$vec_ty _select>] { - use super::*; - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn select() { - let o = $small as $elem_ty; - let t = $large as $elem_ty; - - let a = $vec_ty::splat(o); - let b = $vec_ty::splat(t); - let m = a.lt(b); - assert_eq!(m.select(a, b), a); - - let m = b.lt(a); - assert_eq!(m.select(b, a), a); - - let mut c = a; - let mut d = b; - let mut m_e = $mask_ty::splat(false); - for i in 0..$vec_ty::lanes() { - if i % 2 == 0 { - let c_tmp = c.extract(i); - c = c.replace(i, d.extract(i)); - d = d.replace(i, c_tmp); - } else { - m_e = m_e.replace(i, true); - } - } - - let m = c.lt(d); - assert_eq!(m_e, m); - assert_eq!(m.select(c, d), a); - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/shuffle.rs b/third_party/rust/packed_simd/src/api/shuffle.rs deleted file mode 100644 index 1c17bd766e..0000000000 --- a/third_party/rust/packed_simd/src/api/shuffle.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Implements portable vector shuffles with immediate indices. - -// FIXME: comprehensive tests -// https://github.com/rust-lang-nursery/packed_simd/issues/20 - -/// Shuffles vector elements. -/// -/// This macro returns a new vector that contains a shuffle of the elements in -/// one (`shuffle!(vec, [indices...])`) or two (`shuffle!(vec0, vec1, -/// [indices...])`) input vectors. -/// -/// The type of `vec0` and `vec1` must be equal, and the element type of the -/// resulting vector is the element type of the input vector. -/// -/// The number of `indices` must be a power-of-two in range `[0, 64)`, since -/// currently, the largest vector supported by the library has 64 lanes. The -/// length of the resulting vector equals the number of indices provided. -/// -/// The indices must be in range `[0, M * N)` where `M` is the number of input -/// vectors (`1` or `2`) and `N` is the number of lanes of the input vectors. -/// The indices `i` in range `[0, N)` refer to the `i`-th element of `vec0`, -/// while the indices in range `[N, 2*N)` refer to the `i - N`-th element of -/// `vec1`. -/// -/// # Examples -/// -/// Shuffling elements of two vectors: -/// -/// ``` -/// # use packed_simd::*; -/// # fn main() { -/// // Shuffle allows reordering the elements: -/// let x = i32x4::new(1, 2, 3, 4); -/// let y = i32x4::new(5, 6, 7, 8); -/// let r = shuffle!(x, y, [4, 0, 5, 1]); -/// assert_eq!(r, i32x4::new(5, 1, 6, 2)); -/// -/// // The resulting vector can als be smaller than the input: -/// let r = shuffle!(x, y, [1, 6]); -/// assert_eq!(r, i32x2::new(2, 7)); -/// -/// // Or larger: -/// let r = shuffle!(x, y, [1, 3, 4, 2, 1, 7, 2, 2]); -/// assert_eq!(r, i32x8::new(2, 4, 5, 3, 2, 8, 3, 3)); -/// // At most 2 * the number of lanes in the input vector. -/// # } -/// ``` -/// -/// Shuffling elements of one vector: -/// -/// ``` -/// # use packed_simd::*; -/// # fn main() { -/// // Shuffle allows reordering the elements of a vector: -/// let x = i32x4::new(1, 2, 3, 4); -/// let r = shuffle!(x, [2, 1, 3, 0]); -/// assert_eq!(r, i32x4::new(3, 2, 4, 1)); -/// -/// // The resulting vector can be smaller than the input: -/// let r = shuffle!(x, [1, 3]); -/// assert_eq!(r, i32x2::new(2, 4)); -/// -/// // Equal: -/// let r = shuffle!(x, [1, 3, 2, 0]); -/// assert_eq!(r, i32x4::new(2, 4, 3, 1)); -/// -/// // Or larger: -/// let r = shuffle!(x, [1, 3, 2, 2, 1, 3, 2, 2]); -/// assert_eq!(r, i32x8::new(2, 4, 3, 3, 2, 4, 3, 3)); -/// // At most 2 * the number of lanes in the input vector. -/// # } -/// ``` -#[macro_export] -macro_rules! shuffle { - ($vec0:expr, $vec1:expr, [$l0:expr, $l1:expr]) => {{ - #[allow(unused_unsafe)] - unsafe { - $crate::Simd($crate::__shuffle_vector2::<{[$l0, $l1]}, _, _>( - $vec0.0, - $vec1.0, - )) - } - }}; - ($vec0:expr, $vec1:expr, [$l0:expr, $l1:expr, $l2:expr, $l3:expr]) => {{ - #[allow(unused_unsafe)] - unsafe { - $crate::Simd($crate::__shuffle_vector4::<{[$l0, $l1, $l2, $l3]}, _, _>( - $vec0.0, - $vec1.0, - )) - } - }}; - ($vec0:expr, $vec1:expr, - [$l0:expr, $l1:expr, $l2:expr, $l3:expr, - $l4:expr, $l5:expr, $l6:expr, $l7:expr]) => {{ - #[allow(unused_unsafe)] - unsafe { - $crate::Simd($crate::__shuffle_vector8::<{[$l0, $l1, $l2, $l3, $l4, $l5, $l6, $l7]}, _, _>( - $vec0.0, - $vec1.0, - )) - } - }}; - ($vec0:expr, $vec1:expr, - [$l0:expr, $l1:expr, $l2:expr, $l3:expr, - $l4:expr, $l5:expr, $l6:expr, $l7:expr, - $l8:expr, $l9:expr, $l10:expr, $l11:expr, - $l12:expr, $l13:expr, $l14:expr, $l15:expr]) => {{ - #[allow(unused_unsafe)] - unsafe { - $crate::Simd($crate::__shuffle_vector16::<{ - [ - $l0, $l1, $l2, $l3, $l4, $l5, $l6, $l7, $l8, $l9, $l10, - $l11, $l12, $l13, $l14, $l15, - ] - }, _, _>( - $vec0.0, - $vec1.0, - )) - } - }}; - ($vec0:expr, $vec1:expr, - [$l0:expr, $l1:expr, $l2:expr, $l3:expr, - $l4:expr, $l5:expr, $l6:expr, $l7:expr, - $l8:expr, $l9:expr, $l10:expr, $l11:expr, - $l12:expr, $l13:expr, $l14:expr, $l15:expr, - $l16:expr, $l17:expr, $l18:expr, $l19:expr, - $l20:expr, $l21:expr, $l22:expr, $l23:expr, - $l24:expr, $l25:expr, $l26:expr, $l27:expr, - $l28:expr, $l29:expr, $l30:expr, $l31:expr]) => {{ - #[allow(unused_unsafe)] - unsafe { - $crate::Simd($crate::__shuffle_vector32::<{ - [ - $l0, $l1, $l2, $l3, $l4, $l5, $l6, $l7, $l8, $l9, $l10, - $l11, $l12, $l13, $l14, $l15, $l16, $l17, $l18, $l19, - $l20, $l21, $l22, $l23, $l24, $l25, $l26, $l27, $l28, - $l29, $l30, $l31, - ] - }, _, _>( - $vec0.0, - $vec1.0, - )) - } - }}; - ($vec0:expr, $vec1:expr, - [$l0:expr, $l1:expr, $l2:expr, $l3:expr, - $l4:expr, $l5:expr, $l6:expr, $l7:expr, - $l8:expr, $l9:expr, $l10:expr, $l11:expr, - $l12:expr, $l13:expr, $l14:expr, $l15:expr, - $l16:expr, $l17:expr, $l18:expr, $l19:expr, - $l20:expr, $l21:expr, $l22:expr, $l23:expr, - $l24:expr, $l25:expr, $l26:expr, $l27:expr, - $l28:expr, $l29:expr, $l30:expr, $l31:expr, - $l32:expr, $l33:expr, $l34:expr, $l35:expr, - $l36:expr, $l37:expr, $l38:expr, $l39:expr, - $l40:expr, $l41:expr, $l42:expr, $l43:expr, - $l44:expr, $l45:expr, $l46:expr, $l47:expr, - $l48:expr, $l49:expr, $l50:expr, $l51:expr, - $l52:expr, $l53:expr, $l54:expr, $l55:expr, - $l56:expr, $l57:expr, $l58:expr, $l59:expr, - $l60:expr, $l61:expr, $l62:expr, $l63:expr]) => {{ - #[allow(unused_unsafe)] - unsafe { - $crate::Simd($crate::__shuffle_vector64::<{[ - $l0, $l1, $l2, $l3, $l4, $l5, $l6, $l7, $l8, $l9, $l10, - $l11, $l12, $l13, $l14, $l15, $l16, $l17, $l18, $l19, - $l20, $l21, $l22, $l23, $l24, $l25, $l26, $l27, $l28, - $l29, $l30, $l31, $l32, $l33, $l34, $l35, $l36, $l37, - $l38, $l39, $l40, $l41, $l42, $l43, $l44, $l45, $l46, - $l47, $l48, $l49, $l50, $l51, $l52, $l53, $l54, $l55, - $l56, $l57, $l58, $l59, $l60, $l61, $l62, $l63, - ]}, _, _>( - $vec0.0, - $vec1.0, - )) - } - }}; - ($vec:expr, [$($l:expr),*]) => { - match $vec { - v => shuffle!(v, v, [$($l),*]) - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/shuffle1_dyn.rs b/third_party/rust/packed_simd/src/api/shuffle1_dyn.rs deleted file mode 100644 index 64536be6cb..0000000000 --- a/third_party/rust/packed_simd/src/api/shuffle1_dyn.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! Shuffle vector elements according to a dynamic vector of indices. - -macro_rules! impl_shuffle1_dyn { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Shuffle vector elements according to `indices`. - #[inline] - pub fn shuffle1_dyn(self, indices: I) -> Self - where - Self: codegen::shuffle1_dyn::Shuffle1Dyn, - { - codegen::shuffle1_dyn::Shuffle1Dyn::shuffle1_dyn(self, indices) - } - } - }; -} - -macro_rules! test_shuffle1_dyn { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _shuffle1_dyn>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn shuffle1_dyn() { - let increasing = { - let mut v = $id::splat(0 as $elem_ty); - for i in 0..$id::lanes() { - v = v.replace(i, i as $elem_ty); - } - v - }; - let decreasing = { - let mut v = $id::splat(0 as $elem_ty); - for i in 0..$id::lanes() { - v = v.replace( - i, - ($id::lanes() - 1 - i) as $elem_ty - ); - } - v - }; - - type Indices = < - $id as codegen::shuffle1_dyn::Shuffle1Dyn - >::Indices; - let increasing_ids: Indices = increasing.cast(); - let decreasing_ids: Indices = decreasing.cast(); - - assert_eq!( - increasing.shuffle1_dyn(increasing_ids), - increasing, - "(i,i)=>i" - ); - assert_eq!( - decreasing.shuffle1_dyn(increasing_ids), - decreasing, - "(d,i)=>d" - ); - assert_eq!( - increasing.shuffle1_dyn(decreasing_ids), - decreasing, - "(i,d)=>d" - ); - assert_eq!( - decreasing.shuffle1_dyn(decreasing_ids), - increasing, - "(d,d)=>i" - ); - - for i in 0..$id::lanes() { - let v_ids: Indices - = $id::splat(i as $elem_ty).cast(); - assert_eq!(increasing.shuffle1_dyn(v_ids), - $id::splat(increasing.extract(i)) - ); - assert_eq!(decreasing.shuffle1_dyn(v_ids), - $id::splat(decreasing.extract(i)) - ); - assert_eq!( - $id::splat(i as $elem_ty) - .shuffle1_dyn(increasing_ids), - $id::splat(i as $elem_ty) - ); - assert_eq!( - $id::splat(i as $elem_ty) - .shuffle1_dyn(decreasing_ids), - $id::splat(i as $elem_ty) - ); - } - } - } - } - } - }; -} - -macro_rules! test_shuffle1_dyn_mask { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _shuffle1_dyn>] { - use super::*; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn shuffle1_dyn() { - // alternating = [true, false, true, false, ...] - let mut alternating = $id::splat(false); - for i in 0..$id::lanes() { - if i % 2 == 0 { - alternating = alternating.replace(i, true); - } - } - - type Indices = < - $id as codegen::shuffle1_dyn::Shuffle1Dyn - >::Indices; - // even = [0, 0, 2, 2, 4, 4, ..] - let even = { - let mut v = Indices::splat(0); - for i in 0..$id::lanes() { - if i % 2 == 0 { - v = v.replace(i, (i as u8).into()); - } else { - v = v.replace(i, (i as u8 - 1).into()); - } - } - v - }; - // odd = [1, 1, 3, 3, 5, 5, ...] - let odd = { - let mut v = Indices::splat(0); - for i in 0..$id::lanes() { - if i % 2 != 0 { - v = v.replace(i, (i as u8).into()); - } else { - v = v.replace(i, (i as u8 + 1).into()); - } - } - v - }; - - assert_eq!( - alternating.shuffle1_dyn(even), - $id::splat(true) - ); - if $id::lanes() > 1 { - assert_eq!( - alternating.shuffle1_dyn(odd), - $id::splat(false) - ); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/slice.rs b/third_party/rust/packed_simd/src/api/slice.rs deleted file mode 100644 index 526b848b5c..0000000000 --- a/third_party/rust/packed_simd/src/api/slice.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Slice from/to methods - -#[macro_use] -mod from_slice; - -#[macro_use] -mod write_to_slice; diff --git a/third_party/rust/packed_simd/src/api/slice/from_slice.rs b/third_party/rust/packed_simd/src/api/slice/from_slice.rs deleted file mode 100644 index cafd6f8213..0000000000 --- a/third_party/rust/packed_simd/src/api/slice/from_slice.rs +++ /dev/null @@ -1,202 +0,0 @@ -//! Implements methods to read a vector type from a slice. - -macro_rules! impl_slice_from_slice { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not aligned - /// to an `align_of::()` boundary. - #[inline] - pub fn from_slice_aligned(slice: &[$elem_ty]) -> Self { - unsafe { - assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_ptr(); - assert_eq!(target_ptr.align_offset(crate::mem::align_of::()), 0); - Self::from_slice_aligned_unchecked(slice) - } - } - - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()`. - #[inline] - pub fn from_slice_unaligned(slice: &[$elem_ty]) -> Self { - unsafe { - assert!(slice.len() >= $elem_count); - Self::from_slice_unaligned_unchecked(slice) - } - } - - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not aligned - /// to an `align_of::()` boundary, the behavior is undefined. - #[inline] - pub unsafe fn from_slice_aligned_unchecked(slice: &[$elem_ty]) -> Self { - debug_assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_ptr(); - debug_assert_eq!(target_ptr.align_offset(crate::mem::align_of::()), 0); - - #[allow(clippy::cast_ptr_alignment)] - *(target_ptr as *const Self) - } - - /// Instantiates a new vector with the values of the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` the behavior is undefined. - #[inline] - pub unsafe fn from_slice_unaligned_unchecked(slice: &[$elem_ty]) -> Self { - use crate::mem::size_of; - debug_assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_ptr().cast(); - let mut x = Self::splat(0 as $elem_ty); - let self_ptr = &mut x as *mut Self as *mut u8; - crate::ptr::copy_nonoverlapping(target_ptr, self_ptr, size_of::()); - x - } - } - - test_if! { - $test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - pub mod [<$id _slice_from_slice>] { - use super::*; - use crate::iter::Iterator; - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn from_slice_unaligned() { - let mut unaligned = [42 as $elem_ty; $id::lanes() + 1]; - unaligned[0] = 0 as $elem_ty; - let vec = $id::from_slice_unaligned(&unaligned[1..]); - for (index, &b) in unaligned.iter().enumerate() { - if index == 0 { - assert_eq!(b, 0 as $elem_ty); - } else { - assert_eq!(b, 42 as $elem_ty); - assert_eq!(b, vec.extract(index - 1)); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn from_slice_unaligned_fail() { - let mut unaligned = [42 as $elem_ty; $id::lanes() + 1]; - unaligned[0] = 0 as $elem_ty; - // the slice is not large enough => panic - let _vec = $id::from_slice_unaligned(&unaligned[2..]); - } - - union A { - data: [$elem_ty; 2 * $id::lanes()], - _vec: $id, - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn from_slice_aligned() { - let mut aligned = A { - data: [0 as $elem_ty; 2 * $id::lanes()], - }; - for i in $id::lanes()..(2 * $id::lanes()) { - unsafe { - aligned.data[i] = 42 as $elem_ty; - } - } - - let vec = unsafe { - $id::from_slice_aligned( - &aligned.data[$id::lanes()..] - ) - }; - for (index, &b) in - unsafe { aligned.data.iter().enumerate() } { - if index < $id::lanes() { - assert_eq!(b, 0 as $elem_ty); - } else { - assert_eq!(b, 42 as $elem_ty); - assert_eq!( - b, vec.extract(index - $id::lanes()) - ); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn from_slice_aligned_fail_lanes() { - let aligned = A { - data: [0 as $elem_ty; 2 * $id::lanes()], - }; - let _vec = unsafe { - $id::from_slice_aligned( - &aligned.data[2 * $id::lanes()..] - ) - }; - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn from_slice_aligned_fail_align() { - unsafe { - let aligned = A { - data: [0 as $elem_ty; 2 * $id::lanes()], - }; - - // get a pointer to the front of data - let ptr: *const $elem_ty = aligned.data.as_ptr() - as *const $elem_ty; - // offset pointer by one element - let ptr = ptr.wrapping_add(1); - - if ptr.align_offset( - crate::mem::align_of::<$id>() - ) == 0 { - // the pointer is properly aligned, so - // from_slice_aligned won't fail here (e.g. this - // can happen for i128x1). So we panic to make - // the "should_fail" test pass: - panic!("ok"); - } - - // create a slice - this is safe, because the - // elements of the slice exist, are properly - // initialized, and properly aligned: - let s: &[$elem_ty] = slice::from_raw_parts( - ptr, $id::lanes() - ); - // this should always panic because the slice - // alignment does not match the alignment - // requirements for the vector type: - let _vec = $id::from_slice_aligned(s); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/slice/write_to_slice.rs b/third_party/rust/packed_simd/src/api/slice/write_to_slice.rs deleted file mode 100644 index 5abd4916e0..0000000000 --- a/third_party/rust/packed_simd/src/api/slice/write_to_slice.rs +++ /dev/null @@ -1,196 +0,0 @@ -//! Implements methods to write a vector type to a slice. - -macro_rules! impl_slice_write_to_slice { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Writes the values of the vector to the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not - /// aligned to an `align_of::()` boundary. - #[inline] - pub fn write_to_slice_aligned(self, slice: &mut [$elem_ty]) { - unsafe { - assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_mut_ptr(); - assert_eq!(target_ptr.align_offset(crate::mem::align_of::()), 0); - self.write_to_slice_aligned_unchecked(slice); - } - } - - /// Writes the values of the vector to the `slice`. - /// - /// # Panics - /// - /// If `slice.len() < Self::lanes()`. - #[inline] - pub fn write_to_slice_unaligned(self, slice: &mut [$elem_ty]) { - unsafe { - assert!(slice.len() >= $elem_count); - self.write_to_slice_unaligned_unchecked(slice); - } - } - - /// Writes the values of the vector to the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` or `&slice[0]` is not - /// aligned to an `align_of::()` boundary, the behavior is - /// undefined. - #[inline] - pub unsafe fn write_to_slice_aligned_unchecked(self, slice: &mut [$elem_ty]) { - debug_assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_mut_ptr(); - debug_assert_eq!(target_ptr.align_offset(crate::mem::align_of::()), 0); - - #[allow(clippy::cast_ptr_alignment)] - #[allow(clippy::cast_ptr_alignment)] - #[allow(clippy::cast_ptr_alignment)] - #[allow(clippy::cast_ptr_alignment)] - *(target_ptr as *mut Self) = self; - } - - /// Writes the values of the vector to the `slice`. - /// - /// # Safety - /// - /// If `slice.len() < Self::lanes()` the behavior is undefined. - #[inline] - pub unsafe fn write_to_slice_unaligned_unchecked(self, slice: &mut [$elem_ty]) { - debug_assert!(slice.len() >= $elem_count); - let target_ptr = slice.as_mut_ptr().cast(); - let self_ptr = &self as *const Self as *const u8; - crate::ptr::copy_nonoverlapping(self_ptr, target_ptr, crate::mem::size_of::()); - } - } - - test_if! { - $test_tt: - paste::item! { - // Comparisons use integer casts within mantissa^1 range. - #[allow(clippy::float_cmp)] - pub mod [<$id _slice_write_to_slice>] { - use super::*; - use crate::iter::Iterator; - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn write_to_slice_unaligned() { - let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; - let vec = $id::splat(42 as $elem_ty); - vec.write_to_slice_unaligned(&mut unaligned[1..]); - for (index, &b) in unaligned.iter().enumerate() { - if index == 0 { - assert_eq!(b, 0 as $elem_ty); - } else { - assert_eq!(b, 42 as $elem_ty); - assert_eq!(b, vec.extract(index - 1)); - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn write_to_slice_unaligned_fail() { - let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; - let vec = $id::splat(42 as $elem_ty); - vec.write_to_slice_unaligned(&mut unaligned[2..]); - } - - union A { - data: [$elem_ty; 2 * $id::lanes()], - _vec: $id, - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn write_to_slice_aligned() { - let mut aligned = A { - data: [0 as $elem_ty; 2 * $id::lanes()], - }; - let vec = $id::splat(42 as $elem_ty); - unsafe { - vec.write_to_slice_aligned( - &mut aligned.data[$id::lanes()..] - ); - for (idx, &b) in aligned.data.iter().enumerate() { - if idx < $id::lanes() { - assert_eq!(b, 0 as $elem_ty); - } else { - assert_eq!(b, 42 as $elem_ty); - assert_eq!( - b, vec.extract(idx - $id::lanes()) - ); - } - } - } - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn write_to_slice_aligned_fail_lanes() { - let mut aligned = A { - data: [0 as $elem_ty; 2 * $id::lanes()], - }; - let vec = $id::splat(42 as $elem_ty); - unsafe { - vec.write_to_slice_aligned( - &mut aligned.data[2 * $id::lanes()..] - ) - }; - } - - // FIXME: wasm-bindgen-test does not support #[should_panic] - // #[cfg_attr(not(target_arch = "wasm32"), test)] - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg(not(target_arch = "wasm32"))] - #[test] - #[should_panic] - fn write_to_slice_aligned_fail_align() { - unsafe { - let mut aligned = A { - data: [0 as $elem_ty; 2 * $id::lanes()], - }; - - // get a pointer to the front of data - let ptr: *mut $elem_ty - = aligned.data.as_mut_ptr() as *mut $elem_ty; - // offset pointer by one element - let ptr = ptr.wrapping_add(1); - - if ptr.align_offset(crate::mem::align_of::<$id>()) - == 0 { - // the pointer is properly aligned, so - // write_to_slice_aligned won't fail here (e.g. - // this can happen for i128x1). So we panic to - // make the "should_fail" test pass: - panic!("ok"); - } - - // create a slice - this is safe, because the - // elements of the slice exist, are properly - // initialized, and properly aligned: - let s: &mut [$elem_ty] - = slice::from_raw_parts_mut(ptr, $id::lanes()); - // this should always panic because the slice - // alignment does not match the alignment - // requirements for the vector type: - let vec = $id::splat(42 as $elem_ty); - vec.write_to_slice_aligned(s); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/api/swap_bytes.rs b/third_party/rust/packed_simd/src/api/swap_bytes.rs deleted file mode 100644 index 4649ed679b..0000000000 --- a/third_party/rust/packed_simd/src/api/swap_bytes.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! Horizontal swap bytes - -macro_rules! impl_swap_bytes { - ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { - impl $id { - /// Reverses the byte order of the vector. - #[inline] - pub fn swap_bytes(self) -> Self { - super::codegen::swap_bytes::SwapBytes::swap_bytes(self) - } - - /// Converts self to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - #[inline] - pub fn to_le(self) -> Self { - #[cfg(target_endian = "little")] - { - self - } - #[cfg(not(target_endian = "little"))] - { - self.swap_bytes() - } - } - - /// Converts self to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - #[inline] - pub fn to_be(self) -> Self { - #[cfg(target_endian = "big")] - { - self - } - #[cfg(not(target_endian = "big"))] - { - self.swap_bytes() - } - } - - /// Converts a vector from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - #[inline] - pub fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - { - x - } - #[cfg(not(target_endian = "little"))] - { - x.swap_bytes() - } - } - - /// Converts a vector from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - #[inline] - pub fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - { - x - } - #[cfg(not(target_endian = "big"))] - { - x.swap_bytes() - } - } - } - - test_if! { - $test_tt: - paste::item! { - pub mod [<$id _swap_bytes>] { - use super::*; - - const BYTES: [u8; 64] = [ - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - ]; - - macro_rules! swap { - ($func: ident) => {{ - // catch possible future >512 vectors - assert!(mem::size_of::<$id>() <= 64); - - let mut actual = BYTES; - let elems: &mut [$elem_ty] = unsafe { - slice::from_raw_parts_mut( - actual.as_mut_ptr() as *mut $elem_ty, - $id::lanes(), - ) - }; - - let vec = $id::from_slice_unaligned(elems); - $id::$func(vec).write_to_slice_unaligned(elems); - - actual - }}; - } - - macro_rules! test_swap { - ($func: ident) => {{ - let actual = swap!($func); - let expected = - BYTES.iter().rev() - .skip(64 - crate::mem::size_of::<$id>()); - assert!(actual.iter().zip(expected) - .all(|(x, y)| x == y)); - }}; - } - - macro_rules! test_no_swap { - ($func: ident) => {{ - let actual = swap!($func); - let expected = BYTES.iter() - .take(mem::size_of::<$id>()); - - assert!(actual.iter().zip(expected) - .all(|(x, y)| x == y)); - }}; - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn swap_bytes() { - test_swap!(swap_bytes); - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn to_le() { - #[cfg(target_endian = "little")] - { - test_no_swap!(to_le); - } - #[cfg(not(target_endian = "little"))] - { - test_swap!(to_le); - } - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn to_be() { - #[cfg(target_endian = "big")] - { - test_no_swap!(to_be); - } - #[cfg(not(target_endian = "big"))] - { - test_swap!(to_be); - } - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn from_le() { - #[cfg(target_endian = "little")] - { - test_no_swap!(from_le); - } - #[cfg(not(target_endian = "little"))] - { - test_swap!(from_le); - } - } - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn from_be() { - #[cfg(target_endian = "big")] - { - test_no_swap!(from_be); - } - #[cfg(not(target_endian = "big"))] - { - test_swap!(from_be); - } - } - } - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/codegen.rs b/third_party/rust/packed_simd/src/codegen.rs deleted file mode 100644 index 8a9e971486..0000000000 --- a/third_party/rust/packed_simd/src/codegen.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Code-generation utilities - -pub(crate) mod bit_manip; -pub(crate) mod llvm; -pub(crate) mod math; -pub(crate) mod reductions; -pub(crate) mod shuffle; -pub(crate) mod shuffle1_dyn; -pub(crate) mod swap_bytes; - -macro_rules! impl_simd_array { - ([$elem_ty:ident; $elem_count:expr]: - $tuple_id:ident | $($elem_tys:ident),*) => { - #[derive(Copy, Clone)] - #[repr(simd)] - pub struct $tuple_id($(pub(crate) $elem_tys),*); - //^^^^^^^ leaked through SimdArray - - impl crate::sealed::Seal for [$elem_ty; $elem_count] {} - - impl crate::sealed::SimdArray for [$elem_ty; $elem_count] { - type Tuple = $tuple_id; - type T = $elem_ty; - const N: usize = $elem_count; - type NT = [u32; $elem_count]; - } - - impl crate::sealed::Seal for $tuple_id {} - impl crate::sealed::Simd for $tuple_id { - type Element = $elem_ty; - const LANES: usize = $elem_count; - type LanesType = [u32; $elem_count]; - } - - } -} - -pub(crate) mod pointer_sized_int; - -pub(crate) mod v16; -pub(crate) use self::v16::*; - -pub(crate) mod v32; -pub(crate) use self::v32::*; - -pub(crate) mod v64; -pub(crate) use self::v64::*; - -pub(crate) mod v128; -pub(crate) use self::v128::*; - -pub(crate) mod v256; -pub(crate) use self::v256::*; - -pub(crate) mod v512; -pub(crate) use self::v512::*; - -pub(crate) mod vSize; -pub(crate) use self::vSize::*; - -pub(crate) mod vPtr; -pub(crate) use self::vPtr::*; diff --git a/third_party/rust/packed_simd/src/codegen/bit_manip.rs b/third_party/rust/packed_simd/src/codegen/bit_manip.rs deleted file mode 100644 index 32d8d717a0..0000000000 --- a/third_party/rust/packed_simd/src/codegen/bit_manip.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! LLVM bit manipulation intrinsics. -#[rustfmt::skip] - -pub(crate) use crate::*; - -#[allow(improper_ctypes, dead_code)] -extern "C" { - #[link_name = "llvm.ctlz.v2i8"] - fn ctlz_u8x2(x: u8x2, is_zero_undef: bool) -> u8x2; - #[link_name = "llvm.ctlz.v4i8"] - fn ctlz_u8x4(x: u8x4, is_zero_undef: bool) -> u8x4; - #[link_name = "llvm.ctlz.v8i8"] - fn ctlz_u8x8(x: u8x8, is_zero_undef: bool) -> u8x8; - #[link_name = "llvm.ctlz.v16i8"] - fn ctlz_u8x16(x: u8x16, is_zero_undef: bool) -> u8x16; - #[link_name = "llvm.ctlz.v32i8"] - fn ctlz_u8x32(x: u8x32, is_zero_undef: bool) -> u8x32; - #[link_name = "llvm.ctlz.v64i8"] - fn ctlz_u8x64(x: u8x64, is_zero_undef: bool) -> u8x64; - - #[link_name = "llvm.ctlz.v2i16"] - fn ctlz_u16x2(x: u16x2, is_zero_undef: bool) -> u16x2; - #[link_name = "llvm.ctlz.v4i16"] - fn ctlz_u16x4(x: u16x4, is_zero_undef: bool) -> u16x4; - #[link_name = "llvm.ctlz.v8i16"] - fn ctlz_u16x8(x: u16x8, is_zero_undef: bool) -> u16x8; - #[link_name = "llvm.ctlz.v16i16"] - fn ctlz_u16x16(x: u16x16, is_zero_undef: bool) -> u16x16; - #[link_name = "llvm.ctlz.v32i16"] - fn ctlz_u16x32(x: u16x32, is_zero_undef: bool) -> u16x32; - - #[link_name = "llvm.ctlz.v2i32"] - fn ctlz_u32x2(x: u32x2, is_zero_undef: bool) -> u32x2; - #[link_name = "llvm.ctlz.v4i32"] - fn ctlz_u32x4(x: u32x4, is_zero_undef: bool) -> u32x4; - #[link_name = "llvm.ctlz.v8i32"] - fn ctlz_u32x8(x: u32x8, is_zero_undef: bool) -> u32x8; - #[link_name = "llvm.ctlz.v16i32"] - fn ctlz_u32x16(x: u32x16, is_zero_undef: bool) -> u32x16; - - #[link_name = "llvm.ctlz.v2i64"] - fn ctlz_u64x2(x: u64x2, is_zero_undef: bool) -> u64x2; - #[link_name = "llvm.ctlz.v4i64"] - fn ctlz_u64x4(x: u64x4, is_zero_undef: bool) -> u64x4; - #[link_name = "llvm.ctlz.v8i64"] - fn ctlz_u64x8(x: u64x8, is_zero_undef: bool) -> u64x8; - - #[link_name = "llvm.ctlz.v1i128"] - fn ctlz_u128x1(x: u128x1, is_zero_undef: bool) -> u128x1; - #[link_name = "llvm.ctlz.v2i128"] - fn ctlz_u128x2(x: u128x2, is_zero_undef: bool) -> u128x2; - #[link_name = "llvm.ctlz.v4i128"] - fn ctlz_u128x4(x: u128x4, is_zero_undef: bool) -> u128x4; - - #[link_name = "llvm.cttz.v2i8"] - fn cttz_u8x2(x: u8x2, is_zero_undef: bool) -> u8x2; - #[link_name = "llvm.cttz.v4i8"] - fn cttz_u8x4(x: u8x4, is_zero_undef: bool) -> u8x4; - #[link_name = "llvm.cttz.v8i8"] - fn cttz_u8x8(x: u8x8, is_zero_undef: bool) -> u8x8; - #[link_name = "llvm.cttz.v16i8"] - fn cttz_u8x16(x: u8x16, is_zero_undef: bool) -> u8x16; - #[link_name = "llvm.cttz.v32i8"] - fn cttz_u8x32(x: u8x32, is_zero_undef: bool) -> u8x32; - #[link_name = "llvm.cttz.v64i8"] - fn cttz_u8x64(x: u8x64, is_zero_undef: bool) -> u8x64; - - #[link_name = "llvm.cttz.v2i16"] - fn cttz_u16x2(x: u16x2, is_zero_undef: bool) -> u16x2; - #[link_name = "llvm.cttz.v4i16"] - fn cttz_u16x4(x: u16x4, is_zero_undef: bool) -> u16x4; - #[link_name = "llvm.cttz.v8i16"] - fn cttz_u16x8(x: u16x8, is_zero_undef: bool) -> u16x8; - #[link_name = "llvm.cttz.v16i16"] - fn cttz_u16x16(x: u16x16, is_zero_undef: bool) -> u16x16; - #[link_name = "llvm.cttz.v32i16"] - fn cttz_u16x32(x: u16x32, is_zero_undef: bool) -> u16x32; - - #[link_name = "llvm.cttz.v2i32"] - fn cttz_u32x2(x: u32x2, is_zero_undef: bool) -> u32x2; - #[link_name = "llvm.cttz.v4i32"] - fn cttz_u32x4(x: u32x4, is_zero_undef: bool) -> u32x4; - #[link_name = "llvm.cttz.v8i32"] - fn cttz_u32x8(x: u32x8, is_zero_undef: bool) -> u32x8; - #[link_name = "llvm.cttz.v16i32"] - fn cttz_u32x16(x: u32x16, is_zero_undef: bool) -> u32x16; - - #[link_name = "llvm.cttz.v2i64"] - fn cttz_u64x2(x: u64x2, is_zero_undef: bool) -> u64x2; - #[link_name = "llvm.cttz.v4i64"] - fn cttz_u64x4(x: u64x4, is_zero_undef: bool) -> u64x4; - #[link_name = "llvm.cttz.v8i64"] - fn cttz_u64x8(x: u64x8, is_zero_undef: bool) -> u64x8; - - #[link_name = "llvm.cttz.v1i128"] - fn cttz_u128x1(x: u128x1, is_zero_undef: bool) -> u128x1; - #[link_name = "llvm.cttz.v2i128"] - fn cttz_u128x2(x: u128x2, is_zero_undef: bool) -> u128x2; - #[link_name = "llvm.cttz.v4i128"] - fn cttz_u128x4(x: u128x4, is_zero_undef: bool) -> u128x4; - - #[link_name = "llvm.ctpop.v2i8"] - fn ctpop_u8x2(x: u8x2) -> u8x2; - #[link_name = "llvm.ctpop.v4i8"] - fn ctpop_u8x4(x: u8x4) -> u8x4; - #[link_name = "llvm.ctpop.v8i8"] - fn ctpop_u8x8(x: u8x8) -> u8x8; - #[link_name = "llvm.ctpop.v16i8"] - fn ctpop_u8x16(x: u8x16) -> u8x16; - #[link_name = "llvm.ctpop.v32i8"] - fn ctpop_u8x32(x: u8x32) -> u8x32; - #[link_name = "llvm.ctpop.v64i8"] - fn ctpop_u8x64(x: u8x64) -> u8x64; - - #[link_name = "llvm.ctpop.v2i16"] - fn ctpop_u16x2(x: u16x2) -> u16x2; - #[link_name = "llvm.ctpop.v4i16"] - fn ctpop_u16x4(x: u16x4) -> u16x4; - #[link_name = "llvm.ctpop.v8i16"] - fn ctpop_u16x8(x: u16x8) -> u16x8; - #[link_name = "llvm.ctpop.v16i16"] - fn ctpop_u16x16(x: u16x16) -> u16x16; - #[link_name = "llvm.ctpop.v32i16"] - fn ctpop_u16x32(x: u16x32) -> u16x32; - - #[link_name = "llvm.ctpop.v2i32"] - fn ctpop_u32x2(x: u32x2) -> u32x2; - #[link_name = "llvm.ctpop.v4i32"] - fn ctpop_u32x4(x: u32x4) -> u32x4; - #[link_name = "llvm.ctpop.v8i32"] - fn ctpop_u32x8(x: u32x8) -> u32x8; - #[link_name = "llvm.ctpop.v16i32"] - fn ctpop_u32x16(x: u32x16) -> u32x16; - - #[link_name = "llvm.ctpop.v2i64"] - fn ctpop_u64x2(x: u64x2) -> u64x2; - #[link_name = "llvm.ctpop.v4i64"] - fn ctpop_u64x4(x: u64x4) -> u64x4; - #[link_name = "llvm.ctpop.v8i64"] - fn ctpop_u64x8(x: u64x8) -> u64x8; - - #[link_name = "llvm.ctpop.v1i128"] - fn ctpop_u128x1(x: u128x1) -> u128x1; - #[link_name = "llvm.ctpop.v2i128"] - fn ctpop_u128x2(x: u128x2) -> u128x2; - #[link_name = "llvm.ctpop.v4i128"] - fn ctpop_u128x4(x: u128x4) -> u128x4; -} - -pub(crate) trait BitManip { - fn ctpop(self) -> Self; - fn ctlz(self) -> Self; - fn cttz(self) -> Self; -} - -macro_rules! impl_bit_manip { - (inner: $ty:ident, $scalar:ty, $uty:ident, - $ctpop:ident, $ctlz:ident, $cttz:ident) => { - // FIXME: several LLVM intrinsics break on s390x https://github.com/rust-lang-nursery/packed_simd/issues/192 - #[cfg(target_arch = "s390x")] - impl_bit_manip! { scalar: $ty, $scalar } - #[cfg(not(target_arch = "s390x"))] - impl BitManip for $ty { - #[inline] - fn ctpop(self) -> Self { - let y: $uty = self.cast(); - unsafe { $ctpop(y).cast() } - } - - #[inline] - fn ctlz(self) -> Self { - let y: $uty = self.cast(); - // the ctxx intrinsics need compile-time constant - // `is_zero_undef` - unsafe { $ctlz(y, false).cast() } - } - - #[inline] - fn cttz(self) -> Self { - let y: $uty = self.cast(); - unsafe { $cttz(y, false).cast() } - } - } - }; - (sized_inner: $ty:ident, $scalar:ty, $uty:ident) => { - #[cfg(target_arch = "s390x")] - impl_bit_manip! { scalar: $ty, $scalar } - #[cfg(not(target_arch = "s390x"))] - impl BitManip for $ty { - #[inline] - fn ctpop(self) -> Self { - let y: $uty = self.cast(); - $uty::ctpop(y).cast() - } - - #[inline] - fn ctlz(self) -> Self { - let y: $uty = self.cast(); - $uty::ctlz(y).cast() - } - - #[inline] - fn cttz(self) -> Self { - let y: $uty = self.cast(); - $uty::cttz(y).cast() - } - } - }; - (scalar: $ty:ident, $scalar:ty) => { - impl BitManip for $ty { - #[inline] - fn ctpop(self) -> Self { - let mut ones = self; - for i in 0..Self::lanes() { - ones = ones.replace(i, self.extract(i).count_ones() as $scalar); - } - ones - } - - #[inline] - fn ctlz(self) -> Self { - let mut lz = self; - for i in 0..Self::lanes() { - lz = lz.replace(i, self.extract(i).leading_zeros() as $scalar); - } - lz - } - - #[inline] - fn cttz(self) -> Self { - let mut tz = self; - for i in 0..Self::lanes() { - tz = tz.replace(i, self.extract(i).trailing_zeros() as $scalar); - } - tz - } - } - }; - ($uty:ident, $uscalar:ty, $ity:ident, $iscalar:ty, - $ctpop:ident, $ctlz:ident, $cttz:ident) => { - impl_bit_manip! { inner: $uty, $uscalar, $uty, $ctpop, $ctlz, $cttz } - impl_bit_manip! { inner: $ity, $iscalar, $uty, $ctpop, $ctlz, $cttz } - }; - (sized: $usize:ident, $uscalar:ty, $isize:ident, - $iscalar:ty, $ty:ident) => { - impl_bit_manip! { sized_inner: $usize, $uscalar, $ty } - impl_bit_manip! { sized_inner: $isize, $iscalar, $ty } - }; -} - -impl_bit_manip! { u8x2 , u8, i8x2, i8, ctpop_u8x2, ctlz_u8x2, cttz_u8x2 } -impl_bit_manip! { u8x4 , u8, i8x4, i8, ctpop_u8x4, ctlz_u8x4, cttz_u8x4 } -#[cfg(not(target_arch = "aarch64"))] // see below -impl_bit_manip! { u8x8 , u8, i8x8, i8, ctpop_u8x8, ctlz_u8x8, cttz_u8x8 } -impl_bit_manip! { u8x16 , u8, i8x16, i8, ctpop_u8x16, ctlz_u8x16, cttz_u8x16 } -impl_bit_manip! { u8x32 , u8, i8x32, i8, ctpop_u8x32, ctlz_u8x32, cttz_u8x32 } -impl_bit_manip! { u8x64 , u8, i8x64, i8, ctpop_u8x64, ctlz_u8x64, cttz_u8x64 } -impl_bit_manip! { u16x2 , u16, i16x2, i16, ctpop_u16x2, ctlz_u16x2, cttz_u16x2 } -impl_bit_manip! { u16x4 , u16, i16x4, i16, ctpop_u16x4, ctlz_u16x4, cttz_u16x4 } -impl_bit_manip! { u16x8 , u16, i16x8, i16, ctpop_u16x8, ctlz_u16x8, cttz_u16x8 } -impl_bit_manip! { u16x16 , u16, i16x16, i16, ctpop_u16x16, ctlz_u16x16, cttz_u16x16 } -impl_bit_manip! { u16x32 , u16, i16x32, i16, ctpop_u16x32, ctlz_u16x32, cttz_u16x32 } -impl_bit_manip! { u32x2 , u32, i32x2, i32, ctpop_u32x2, ctlz_u32x2, cttz_u32x2 } -impl_bit_manip! { u32x4 , u32, i32x4, i32, ctpop_u32x4, ctlz_u32x4, cttz_u32x4 } -impl_bit_manip! { u32x8 , u32, i32x8, i32, ctpop_u32x8, ctlz_u32x8, cttz_u32x8 } -impl_bit_manip! { u32x16 , u32, i32x16, i32, ctpop_u32x16, ctlz_u32x16, cttz_u32x16 } -impl_bit_manip! { u64x2 , u64, i64x2, i64, ctpop_u64x2, ctlz_u64x2, cttz_u64x2 } -impl_bit_manip! { u64x4 , u64, i64x4, i64, ctpop_u64x4, ctlz_u64x4, cttz_u64x4 } -impl_bit_manip! { u64x8 , u64, i64x8, i64, ctpop_u64x8, ctlz_u64x8, cttz_u64x8 } -impl_bit_manip! { u128x1 , u128, i128x1, i128, ctpop_u128x1, ctlz_u128x1, cttz_u128x1 } -impl_bit_manip! { u128x2 , u128, i128x2, i128, ctpop_u128x2, ctlz_u128x2, cttz_u128x2 } -impl_bit_manip! { u128x4 , u128, i128x4, i128, ctpop_u128x4, ctlz_u128x4, cttz_u128x4 } - -#[cfg(target_arch = "aarch64")] -impl BitManip for u8x8 { - #[inline] - fn ctpop(self) -> Self { - let y: u8x8 = self.cast(); - unsafe { ctpop_u8x8(y).cast() } - } - - #[inline] - fn ctlz(self) -> Self { - let y: u8x8 = self.cast(); - unsafe { ctlz_u8x8(y, false).cast() } - } - - #[inline] - fn cttz(self) -> Self { - // FIXME: LLVM cttz.v8i8 broken on aarch64 https://github.com/rust-lang-nursery/packed_simd/issues/191 - // OPTIMIZE: adapt the algorithm used for v8i16/etc to Rust's aarch64 - // intrinsics - let mut tz = self; - for i in 0..Self::lanes() { - tz = tz.replace(i, self.extract(i).trailing_zeros() as u8); - } - tz - } -} -#[cfg(target_arch = "aarch64")] -impl BitManip for i8x8 { - #[inline] - fn ctpop(self) -> Self { - let y: u8x8 = self.cast(); - unsafe { ctpop_u8x8(y).cast() } - } - - #[inline] - fn ctlz(self) -> Self { - let y: u8x8 = self.cast(); - unsafe { ctlz_u8x8(y, false).cast() } - } - - #[inline] - fn cttz(self) -> Self { - // FIXME: LLVM cttz.v8i8 broken on aarch64 https://github.com/rust-lang-nursery/packed_simd/issues/191 - // OPTIMIZE: adapt the algorithm used for v8i16/etc to Rust's aarch64 - // intrinsics - let mut tz = self; - for i in 0..Self::lanes() { - tz = tz.replace(i, self.extract(i).trailing_zeros() as i8); - } - tz - } -} - -cfg_if! { - if #[cfg(target_pointer_width = "8")] { - impl_bit_manip! { sized: usizex2, usize, isizex2, isize, u8x2 } - impl_bit_manip! { sized: usizex4, usize, isizex4, isize, u8x4 } - impl_bit_manip! { sized: usizex8, usize, isizex8, isize, u8x8 } - } else if #[cfg(target_pointer_width = "16")] { - impl_bit_manip! { sized: usizex2, usize, isizex2, isize, u16x2 } - impl_bit_manip! { sized: usizex4, usize, isizex4, isize, u16x4 } - impl_bit_manip! { sized: usizex8, usize, isizex8, isize, u16x8 } - } else if #[cfg(target_pointer_width = "32")] { - impl_bit_manip! { sized: usizex2, usize, isizex2, isize, u32x2 } - impl_bit_manip! { sized: usizex4, usize, isizex4, isize, u32x4 } - impl_bit_manip! { sized: usizex8, usize, isizex8, isize, u32x8 } - } else if #[cfg(target_pointer_width = "64")] { - impl_bit_manip! { sized: usizex2, usize, isizex2, isize, u64x2 } - impl_bit_manip! { sized: usizex4, usize, isizex4, isize, u64x4 } - impl_bit_manip! { sized: usizex8, usize, isizex8, isize, u64x8 } - } else { - compile_error!("unsupported target_pointer_width"); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/llvm.rs b/third_party/rust/packed_simd/src/codegen/llvm.rs deleted file mode 100644 index bb482fac66..0000000000 --- a/third_party/rust/packed_simd/src/codegen/llvm.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! LLVM's platform intrinsics -#![allow(dead_code)] - -use crate::sealed::Shuffle; -#[allow(unused_imports)] // FIXME: spurious warning? -use crate::sealed::Simd; - -extern "platform-intrinsic" { - fn simd_shuffle(x: T, y: T, idx: I) -> U; -} - -#[allow(clippy::missing_safety_doc)] -#[inline] -pub unsafe fn __shuffle_vector2(x: T, y: T) -> U -where - T: Simd, - ::Element: Shuffle<[u32; 2], Output = U>, -{ - simd_shuffle(x, y, IDX) -} - -#[allow(clippy::missing_safety_doc)] -#[inline] -pub unsafe fn __shuffle_vector4(x: T, y: T) -> U -where - T: Simd, - ::Element: Shuffle<[u32; 4], Output = U>, -{ - simd_shuffle(x, y, IDX) -} - -#[allow(clippy::missing_safety_doc)] -#[inline] -pub unsafe fn __shuffle_vector8(x: T, y: T) -> U -where - T: Simd, - ::Element: Shuffle<[u32; 8], Output = U>, -{ - simd_shuffle(x, y, IDX) -} - -#[allow(clippy::missing_safety_doc)] -#[inline] -pub unsafe fn __shuffle_vector16(x: T, y: T) -> U -where - T: Simd, - ::Element: Shuffle<[u32; 16], Output = U>, -{ - simd_shuffle(x, y, IDX) -} - -#[allow(clippy::missing_safety_doc)] -#[inline] -pub unsafe fn __shuffle_vector32(x: T, y: T) -> U -where - T: Simd, - ::Element: Shuffle<[u32; 32], Output = U>, -{ - simd_shuffle(x, y, IDX) -} - -#[allow(clippy::missing_safety_doc)] -#[inline] -pub unsafe fn __shuffle_vector64(x: T, y: T) -> U -where - T: Simd, - ::Element: Shuffle<[u32; 64], Output = U>, -{ - simd_shuffle(x, y, IDX) -} - -extern "platform-intrinsic" { - pub(crate) fn simd_eq(x: T, y: T) -> U; - pub(crate) fn simd_ne(x: T, y: T) -> U; - pub(crate) fn simd_lt(x: T, y: T) -> U; - pub(crate) fn simd_le(x: T, y: T) -> U; - pub(crate) fn simd_gt(x: T, y: T) -> U; - pub(crate) fn simd_ge(x: T, y: T) -> U; - - pub(crate) fn simd_insert(x: T, idx: u32, val: U) -> T; - pub(crate) fn simd_extract(x: T, idx: u32) -> U; - - pub(crate) fn simd_cast(x: T) -> U; - - pub(crate) fn simd_add(x: T, y: T) -> T; - pub(crate) fn simd_sub(x: T, y: T) -> T; - pub(crate) fn simd_mul(x: T, y: T) -> T; - pub(crate) fn simd_div(x: T, y: T) -> T; - pub(crate) fn simd_rem(x: T, y: T) -> T; - pub(crate) fn simd_shl(x: T, y: T) -> T; - pub(crate) fn simd_shr(x: T, y: T) -> T; - pub(crate) fn simd_and(x: T, y: T) -> T; - pub(crate) fn simd_or(x: T, y: T) -> T; - pub(crate) fn simd_xor(x: T, y: T) -> T; - - pub(crate) fn simd_reduce_add_unordered(x: T) -> U; - pub(crate) fn simd_reduce_mul_unordered(x: T) -> U; - pub(crate) fn simd_reduce_add_ordered(x: T, acc: U) -> U; - pub(crate) fn simd_reduce_mul_ordered(x: T, acc: U) -> U; - pub(crate) fn simd_reduce_min(x: T) -> U; - pub(crate) fn simd_reduce_max(x: T) -> U; - pub(crate) fn simd_reduce_min_nanless(x: T) -> U; - pub(crate) fn simd_reduce_max_nanless(x: T) -> U; - pub(crate) fn simd_reduce_and(x: T) -> U; - pub(crate) fn simd_reduce_or(x: T) -> U; - pub(crate) fn simd_reduce_xor(x: T) -> U; - pub(crate) fn simd_reduce_all(x: T) -> bool; - pub(crate) fn simd_reduce_any(x: T) -> bool; - - pub(crate) fn simd_select(m: M, a: T, b: T) -> T; - - pub(crate) fn simd_fmin(a: T, b: T) -> T; - pub(crate) fn simd_fmax(a: T, b: T) -> T; - - pub(crate) fn simd_fsqrt(a: T) -> T; - pub(crate) fn simd_fma(a: T, b: T, c: T) -> T; - - pub(crate) fn simd_gather(value: T, pointers: P, mask: M) -> T; - pub(crate) fn simd_scatter(value: T, pointers: P, mask: M); - - pub(crate) fn simd_bitmask(value: T) -> U; -} diff --git a/third_party/rust/packed_simd/src/codegen/math.rs b/third_party/rust/packed_simd/src/codegen/math.rs deleted file mode 100644 index 9a0ea7a4e2..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Vertical math operations - -pub(crate) mod float; diff --git a/third_party/rust/packed_simd/src/codegen/math/float.rs b/third_party/rust/packed_simd/src/codegen/math/float.rs deleted file mode 100644 index 10d21831f1..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Vertical floating-point math operations. -#![allow(clippy::useless_transmute)] - -#[macro_use] -pub(crate) mod macros; -pub(crate) mod abs; -pub(crate) mod cos; -pub(crate) mod cos_pi; -pub(crate) mod exp; -pub(crate) mod ln; -pub(crate) mod mul_add; -pub(crate) mod mul_adde; -pub(crate) mod powf; -pub(crate) mod sin; -pub(crate) mod sin_cos_pi; -pub(crate) mod sin_pi; -pub(crate) mod sqrt; -pub(crate) mod sqrte; -pub(crate) mod tanh; diff --git a/third_party/rust/packed_simd/src/codegen/math/float/abs.rs b/third_party/rust/packed_simd/src/codegen/math/float/abs.rs deleted file mode 100644 index 34aacc25be..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/abs.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Vertical floating-point `fabs` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors fabs - -use crate::*; - -pub(crate) trait Abs { - fn abs(self) -> Self; -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.fabs.v2f32"] - fn fabs_v2f32(x: f32x2) -> f32x2; - #[link_name = "llvm.fabs.v4f32"] - fn fabs_v4f32(x: f32x4) -> f32x4; - #[link_name = "llvm.fabs.v8f32"] - fn fabs_v8f32(x: f32x8) -> f32x8; - #[link_name = "llvm.fabs.v16f32"] - fn fabs_v16f32(x: f32x16) -> f32x16; - /* FIXME 64-bit fabsgle elem vectors - #[link_name = "llvm.fabs.v1f64"] - fn fabs_v1f64(x: f64x1) -> f64x1; - */ - #[link_name = "llvm.fabs.v2f64"] - fn fabs_v2f64(x: f64x2) -> f64x2; - #[link_name = "llvm.fabs.v4f64"] - fn fabs_v4f64(x: f64x4) -> f64x4; - #[link_name = "llvm.fabs.v8f64"] - fn fabs_v8f64(x: f64x8) -> f64x8; - - #[link_name = "llvm.fabs.f32"] - fn fabs_f32(x: f32) -> f32; - #[link_name = "llvm.fabs.f64"] - fn fabs_f64(x: f64) -> f64; -} - -gen_unary_impl_table!(Abs, abs); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_unary!(f32x2[f32; 2]: fabs_f32); - impl_unary!(f32x4[f32; 4]: fabs_f32); - impl_unary!(f32x8[f32; 8]: fabs_f32); - impl_unary!(f32x16[f32; 16]: fabs_f32); - - impl_unary!(f64x2[f64; 2]: fabs_f64); - impl_unary!(f64x4[f64; 4]: fabs_f64); - impl_unary!(f64x8[f64; 8]: fabs_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_fabsf4_avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_fabsf8_avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_fabsd4_avx2); - - impl_unary!(f32x4: Sleef_fabsf4_avx2128); - impl_unary!(f32x8: Sleef_fabsf8_avx2); - impl_unary!(f64x2: Sleef_fabsd2_avx2128); - impl_unary!(f64x4: Sleef_fabsd4_avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_fabsf4_sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_fabsf8_avx); - impl_unary!(f64x8[h => f64x4]: Sleef_fabsd4_avx); - - impl_unary!(f32x4: Sleef_fabsf4_sse4); - impl_unary!(f32x8: Sleef_fabsf8_avx); - impl_unary!(f64x2: Sleef_fabsd2_sse4); - impl_unary!(f64x4: Sleef_fabsd4_avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_fabsf4_sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_fabsf4_sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_fabsd2_sse4); - - impl_unary!(f32x4: Sleef_fabsf4_sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_fabsf4_sse4); - impl_unary!(f64x2: Sleef_fabsd2_sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_fabsd2_sse4); - } else { - impl_unary!(f32x2[f32; 2]: fabs_f32); - impl_unary!(f32x16: fabs_v16f32); - impl_unary!(f64x8: fabs_v8f64); - - impl_unary!(f32x4: fabs_v4f32); - impl_unary!(f32x8: fabs_v8f32); - impl_unary!(f64x2: fabs_v2f64); - impl_unary!(f64x4: fabs_v4f64); - } - } - } else { - impl_unary!(f32x2[f32; 2]: fabs_f32); - impl_unary!(f32x4: fabs_v4f32); - impl_unary!(f32x8: fabs_v8f32); - impl_unary!(f32x16: fabs_v16f32); - - impl_unary!(f64x2: fabs_v2f64); - impl_unary!(f64x4: fabs_v4f64); - impl_unary!(f64x8: fabs_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/cos.rs b/third_party/rust/packed_simd/src/codegen/math/float/cos.rs deleted file mode 100644 index dec390cb74..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/cos.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Vertical floating-point `cos` -#![allow(unused)] - -// FIXME 64-bit 1 elem vector cos - -use crate::*; - -pub(crate) trait Cos { - fn cos(self) -> Self; -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.cos.v2f32"] - fn cos_v2f32(x: f32x2) -> f32x2; - #[link_name = "llvm.cos.v4f32"] - fn cos_v4f32(x: f32x4) -> f32x4; - #[link_name = "llvm.cos.v8f32"] - fn cos_v8f32(x: f32x8) -> f32x8; - #[link_name = "llvm.cos.v16f32"] - fn cos_v16f32(x: f32x16) -> f32x16; - /* FIXME 64-bit cosgle elem vectors - #[link_name = "llvm.cos.v1f64"] - fn cos_v1f64(x: f64x1) -> f64x1; - */ - #[link_name = "llvm.cos.v2f64"] - fn cos_v2f64(x: f64x2) -> f64x2; - #[link_name = "llvm.cos.v4f64"] - fn cos_v4f64(x: f64x4) -> f64x4; - #[link_name = "llvm.cos.v8f64"] - fn cos_v8f64(x: f64x8) -> f64x8; - - #[link_name = "llvm.cos.f32"] - fn cos_f32(x: f32) -> f32; - #[link_name = "llvm.cos.f64"] - fn cos_f64(x: f64) -> f64; -} - -gen_unary_impl_table!(Cos, cos); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_unary!(f32x2[f32; 2]: cos_f32); - impl_unary!(f32x4[f32; 4]: cos_f32); - impl_unary!(f32x8[f32; 8]: cos_f32); - impl_unary!(f32x16[f32; 16]: cos_f32); - - impl_unary!(f64x2[f64; 2]: cos_f64); - impl_unary!(f64x4[f64; 4]: cos_f64); - impl_unary!(f64x8[f64; 8]: cos_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_cosf4_u10avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_cosf8_u10avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_cosd4_u10avx2); - - impl_unary!(f32x4: Sleef_cosf4_u10avx2128); - impl_unary!(f32x8: Sleef_cosf8_u10avx2); - impl_unary!(f64x2: Sleef_cosd2_u10avx2128); - impl_unary!(f64x4: Sleef_cosd4_u10avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_cosf4_u10sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_cosf8_u10avx); - impl_unary!(f64x8[h => f64x4]: Sleef_cosd4_u10avx); - - impl_unary!(f32x4: Sleef_cosf4_u10sse4); - impl_unary!(f32x8: Sleef_cosf8_u10avx); - impl_unary!(f64x2: Sleef_cosd2_u10sse4); - impl_unary!(f64x4: Sleef_cosd4_u10avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_cosf4_u10sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_cosf4_u10sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_cosd2_u10sse4); - - impl_unary!(f32x4: Sleef_cosf4_u10sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_cosf4_u10sse4); - impl_unary!(f64x2: Sleef_cosd2_u10sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_cosd2_u10sse4); - } else { - impl_unary!(f32x2[f32; 2]: cos_f32); - impl_unary!(f32x16: cos_v16f32); - impl_unary!(f64x8: cos_v8f64); - - impl_unary!(f32x4: cos_v4f32); - impl_unary!(f32x8: cos_v8f32); - impl_unary!(f64x2: cos_v2f64); - impl_unary!(f64x4: cos_v4f64); - } - } - } else { - impl_unary!(f32x2[f32; 2]: cos_f32); - impl_unary!(f32x4: cos_v4f32); - impl_unary!(f32x8: cos_v8f32); - impl_unary!(f32x16: cos_v16f32); - - impl_unary!(f64x2: cos_v2f64); - impl_unary!(f64x4: cos_v4f64); - impl_unary!(f64x8: cos_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/cos_pi.rs b/third_party/rust/packed_simd/src/codegen/math/float/cos_pi.rs deleted file mode 100644 index e283280ee4..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/cos_pi.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Vertical floating-point `cos` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors cos_pi - -use crate::*; - -pub(crate) trait CosPi { - fn cos_pi(self) -> Self; -} - -gen_unary_impl_table!(CosPi, cos_pi); - -macro_rules! impl_def { - ($vid:ident, $PI:path) => { - impl CosPi for $vid { - #[inline] - fn cos_pi(self) -> Self { - (self * Self::splat($PI)).cos() - } - } - }; -} -macro_rules! impl_def32 { - ($vid:ident) => { - impl_def!($vid, crate::f32::consts::PI); - }; -} -macro_rules! impl_def64 { - ($vid:ident) => { - impl_def!($vid, crate::f64::consts::PI); - }; -} - -cfg_if! { - if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_cospif4_u05avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_cospif8_u05avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_cospid4_u05avx2); - - impl_unary!(f32x4: Sleef_cospif4_u05avx2128); - impl_unary!(f32x8: Sleef_cospif8_u05avx2); - impl_unary!(f64x2: Sleef_cospid2_u05avx2128); - impl_unary!(f64x4: Sleef_cospid4_u05avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_cospif4_u05sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_cospif8_u05avx); - impl_unary!(f64x8[h => f64x4]: Sleef_cospid4_u05avx); - - impl_unary!(f32x4: Sleef_cospif4_u05sse4); - impl_unary!(f32x8: Sleef_cospif8_u05avx); - impl_unary!(f64x2: Sleef_cospid2_u05sse4); - impl_unary!(f64x4: Sleef_cospid4_u05avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_cospif4_u05sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_cospif4_u05sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_cospid2_u05sse4); - - impl_unary!(f32x4: Sleef_cospif4_u05sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_cospif4_u05sse4); - impl_unary!(f64x2: Sleef_cospid2_u05sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_cospid2_u05sse4); - } else { - impl_def32!(f32x2); - impl_def32!(f32x4); - impl_def32!(f32x8); - impl_def32!(f32x16); - - impl_def64!(f64x2); - impl_def64!(f64x4); - impl_def64!(f64x8); - } - } - } else { - impl_def32!(f32x2); - impl_def32!(f32x4); - impl_def32!(f32x8); - impl_def32!(f32x16); - - impl_def64!(f64x2); - impl_def64!(f64x4); - impl_def64!(f64x8); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/exp.rs b/third_party/rust/packed_simd/src/codegen/math/float/exp.rs deleted file mode 100644 index a7b20580e3..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/exp.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Vertical floating-point `exp` -#![allow(unused)] - -// FIXME 64-bit expgle elem vectors misexpg - -use crate::*; - -pub(crate) trait Exp { - fn exp(self) -> Self; -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.exp.v2f32"] - fn exp_v2f32(x: f32x2) -> f32x2; - #[link_name = "llvm.exp.v4f32"] - fn exp_v4f32(x: f32x4) -> f32x4; - #[link_name = "llvm.exp.v8f32"] - fn exp_v8f32(x: f32x8) -> f32x8; - #[link_name = "llvm.exp.v16f32"] - fn exp_v16f32(x: f32x16) -> f32x16; - /* FIXME 64-bit expgle elem vectors - #[link_name = "llvm.exp.v1f64"] - fn exp_v1f64(x: f64x1) -> f64x1; - */ - #[link_name = "llvm.exp.v2f64"] - fn exp_v2f64(x: f64x2) -> f64x2; - #[link_name = "llvm.exp.v4f64"] - fn exp_v4f64(x: f64x4) -> f64x4; - #[link_name = "llvm.exp.v8f64"] - fn exp_v8f64(x: f64x8) -> f64x8; - - #[link_name = "llvm.exp.f32"] - fn exp_f32(x: f32) -> f32; - #[link_name = "llvm.exp.f64"] - fn exp_f64(x: f64) -> f64; -} - -gen_unary_impl_table!(Exp, exp); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_unary!(f32x2[f32; 2]: exp_f32); - impl_unary!(f32x4[f32; 4]: exp_f32); - impl_unary!(f32x8[f32; 8]: exp_f32); - impl_unary!(f32x16[f32; 16]: exp_f32); - - impl_unary!(f64x2[f64; 2]: exp_f64); - impl_unary!(f64x4[f64; 4]: exp_f64); - impl_unary!(f64x8[f64; 8]: exp_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_expf4_u10avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_expf8_u10avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_expd4_u10avx2); - - impl_unary!(f32x4: Sleef_expf4_u10avx2128); - impl_unary!(f32x8: Sleef_expf8_u10avx2); - impl_unary!(f64x2: Sleef_expd2_u10avx2128); - impl_unary!(f64x4: Sleef_expd4_u10avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_expf4_u10sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_expf8_u10avx); - impl_unary!(f64x8[h => f64x4]: Sleef_expd4_u10avx); - - impl_unary!(f32x4: Sleef_expf4_u10sse4); - impl_unary!(f32x8: Sleef_expf8_u10avx); - impl_unary!(f64x2: Sleef_expd2_u10sse4); - impl_unary!(f64x4: Sleef_expd4_u10avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_expf4_u10sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_expf4_u10sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_expd2_u10sse4); - - impl_unary!(f32x4: Sleef_expf4_u10sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_expf4_u10sse4); - impl_unary!(f64x2: Sleef_expd2_u10sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_expd2_u10sse4); - } else if #[cfg(target_feature = "sse2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_expf4_u10sse2); - impl_unary!(f32x16[q => f32x4]: Sleef_expf4_u10sse2); - impl_unary!(f64x8[q => f64x2]: Sleef_expd2_u10sse2); - - impl_unary!(f32x4: Sleef_expf4_u10sse2); - impl_unary!(f32x8[h => f32x4]: Sleef_expf4_u10sse2); - impl_unary!(f64x2: Sleef_expd2_u10sse2); - impl_unary!(f64x4[h => f64x2]: Sleef_expd2_u10sse2); - } else { - impl_unary!(f32x2[f32; 2]: exp_f32); - impl_unary!(f32x16: exp_v16f32); - impl_unary!(f64x8: exp_v8f64); - - impl_unary!(f32x4: exp_v4f32); - impl_unary!(f32x8: exp_v8f32); - impl_unary!(f64x2: exp_v2f64); - impl_unary!(f64x4: exp_v4f64); - } - } - } else { - impl_unary!(f32x2[f32; 2]: exp_f32); - impl_unary!(f32x4: exp_v4f32); - impl_unary!(f32x8: exp_v8f32); - impl_unary!(f32x16: exp_v16f32); - - impl_unary!(f64x2: exp_v2f64); - impl_unary!(f64x4: exp_v4f64); - impl_unary!(f64x8: exp_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/ln.rs b/third_party/rust/packed_simd/src/codegen/math/float/ln.rs deleted file mode 100644 index a5e38cb40d..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/ln.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Vertical floating-point `ln` -#![allow(unused)] - -// FIXME 64-bit lngle elem vectors mislng - -use crate::*; - -pub(crate) trait Ln { - fn ln(self) -> Self; -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.log.v2f32"] - fn ln_v2f32(x: f32x2) -> f32x2; - #[link_name = "llvm.log.v4f32"] - fn ln_v4f32(x: f32x4) -> f32x4; - #[link_name = "llvm.log.v8f32"] - fn ln_v8f32(x: f32x8) -> f32x8; - #[link_name = "llvm.log.v16f32"] - fn ln_v16f32(x: f32x16) -> f32x16; - /* FIXME 64-bit lngle elem vectors - #[link_name = "llvm.log.v1f64"] - fn ln_v1f64(x: f64x1) -> f64x1; - */ - #[link_name = "llvm.log.v2f64"] - fn ln_v2f64(x: f64x2) -> f64x2; - #[link_name = "llvm.log.v4f64"] - fn ln_v4f64(x: f64x4) -> f64x4; - #[link_name = "llvm.log.v8f64"] - fn ln_v8f64(x: f64x8) -> f64x8; - - #[link_name = "llvm.log.f32"] - fn ln_f32(x: f32) -> f32; - #[link_name = "llvm.log.f64"] - fn ln_f64(x: f64) -> f64; -} - -gen_unary_impl_table!(Ln, ln); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_unary!(f32x2[f32; 2]: ln_f32); - impl_unary!(f32x4[f32; 4]: ln_f32); - impl_unary!(f32x8[f32; 8]: ln_f32); - impl_unary!(f32x16[f32; 16]: ln_f32); - - impl_unary!(f64x2[f64; 2]: ln_f64); - impl_unary!(f64x4[f64; 4]: ln_f64); - impl_unary!(f64x8[f64; 8]: ln_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_logf4_u10avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_logf8_u10avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_logd4_u10avx2); - - impl_unary!(f32x4: Sleef_logf4_u10avx2128); - impl_unary!(f32x8: Sleef_logf8_u10avx2); - impl_unary!(f64x2: Sleef_logd2_u10avx2128); - impl_unary!(f64x4: Sleef_logd4_u10avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_logf4_u10sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_logf8_u10avx); - impl_unary!(f64x8[h => f64x4]: Sleef_logd4_u10avx); - - impl_unary!(f32x4: Sleef_logf4_u10sse4); - impl_unary!(f32x8: Sleef_logf8_u10avx); - impl_unary!(f64x2: Sleef_logd2_u10sse4); - impl_unary!(f64x4: Sleef_logd4_u10avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_logf4_u10sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_logf4_u10sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_logd2_u10sse4); - - impl_unary!(f32x4: Sleef_logf4_u10sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_logf4_u10sse4); - impl_unary!(f64x2: Sleef_logd2_u10sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_logd2_u10sse4); - } else if #[cfg(target_feature = "sse2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_logf4_u10sse2); - impl_unary!(f32x16[q => f32x4]: Sleef_logf4_u10sse2); - impl_unary!(f64x8[q => f64x2]: Sleef_logd2_u10sse2); - - impl_unary!(f32x4: Sleef_logf4_u10sse2); - impl_unary!(f32x8[h => f32x4]: Sleef_logf4_u10sse2); - impl_unary!(f64x2: Sleef_logd2_u10sse2); - impl_unary!(f64x4[h => f64x2]: Sleef_logd2_u10sse2); - } else { - impl_unary!(f32x2[f32; 2]: ln_f32); - impl_unary!(f32x16: ln_v16f32); - impl_unary!(f64x8: ln_v8f64); - - impl_unary!(f32x4: ln_v4f32); - impl_unary!(f32x8: ln_v8f32); - impl_unary!(f64x2: ln_v2f64); - impl_unary!(f64x4: ln_v4f64); - } - } - } else { - impl_unary!(f32x2[f32; 2]: ln_f32); - impl_unary!(f32x4: ln_v4f32); - impl_unary!(f32x8: ln_v8f32); - impl_unary!(f32x16: ln_v16f32); - - impl_unary!(f64x2: ln_v2f64); - impl_unary!(f64x4: ln_v4f64); - impl_unary!(f64x8: ln_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/macros.rs b/third_party/rust/packed_simd/src/codegen/math/float/macros.rs deleted file mode 100644 index 8daee1afe2..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/macros.rs +++ /dev/null @@ -1,470 +0,0 @@ -//! Utility macros -#![allow(unused)] - -macro_rules! impl_unary_ { - // implementation mapping 1:1 - (vec | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self) -> Self { - unsafe { - use crate::mem::transmute; - transmute($fun(transmute(self))) - } - } - } - }; - // implementation mapping 1:1 for when `$fun` is a generic function - // like some of the fp math rustc intrinsics (e.g. `fn fun(x: T) -> T`). - (gen | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self) -> Self { - unsafe { - use crate::mem::transmute; - transmute($fun(self.0)) - } - } - } - }; - (scalar | $trait_id:ident, $trait_method:ident, - $vec_id:ident, [$sid:ident; $scount:expr], $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self) -> Self { - unsafe { - union U { - vec: $vec_id, - scalars: [$sid; $scount], - } - let mut scalars = U { vec: self }.scalars; - for i in &mut scalars { - *i = $fun(*i); - } - U { scalars }.vec - } - } - } - }; - // implementation calling fun twice on each of the vector halves: - (halves | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vech_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self) -> Self { - unsafe { - use crate::mem::transmute; - union U { - vec: $vec_id, - halves: [$vech_id; 2], - } - - let mut halves = U { vec: self }.halves; - - *halves.get_unchecked_mut(0) = transmute($fun(transmute(*halves.get_unchecked(0)))); - *halves.get_unchecked_mut(1) = transmute($fun(transmute(*halves.get_unchecked(1)))); - - U { halves }.vec - } - } - } - }; - // implementation calling fun four times on each of the vector quarters: - (quarter | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vecq_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self) -> Self { - unsafe { - use crate::mem::transmute; - union U { - vec: $vec_id, - quarters: [$vecq_id; 4], - } - - let mut quarters = U { vec: self }.quarters; - - *quarters.get_unchecked_mut(0) = transmute($fun(transmute(*quarters.get_unchecked(0)))); - *quarters.get_unchecked_mut(1) = transmute($fun(transmute(*quarters.get_unchecked(1)))); - *quarters.get_unchecked_mut(2) = transmute($fun(transmute(*quarters.get_unchecked(2)))); - *quarters.get_unchecked_mut(3) = transmute($fun(transmute(*quarters.get_unchecked(3)))); - - U { quarters }.vec - } - } - } - }; - // implementation calling fun once on a vector twice as large: - (twice | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vect_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self) -> Self { - unsafe { - use crate::mem::{transmute, uninitialized}; - - union U { - vec: [$vec_id; 2], - twice: $vect_id, - } - - let twice = U { vec: [self, uninitialized()] }.twice; - let twice = transmute($fun(transmute(twice))); - - *(U { twice }.vec.get_unchecked(0)) - } - } - } - }; -} - -macro_rules! gen_unary_impl_table { - ($trait_id:ident, $trait_method:ident) => { - macro_rules! impl_unary { - ($vid:ident: $fun:ident) => { - impl_unary_!(vec | $trait_id, $trait_method, $vid, $fun); - }; - ($vid:ident[g]: $fun:ident) => { - impl_unary_!(gen | $trait_id, $trait_method, $vid, $fun); - }; - ($vid:ident[$sid:ident; $sc:expr]: $fun:ident) => { - impl_unary_!(scalar | $trait_id, $trait_method, $vid, [$sid; $sc], $fun); - }; - ($vid:ident[s]: $fun:ident) => { - impl_unary_!(scalar | $trait_id, $trait_method, $vid, $fun); - }; - ($vid:ident[h => $vid_h:ident]: $fun:ident) => { - impl_unary_!(halves | $trait_id, $trait_method, $vid, $vid_h, $fun); - }; - ($vid:ident[q => $vid_q:ident]: $fun:ident) => { - impl_unary_!(quarter | $trait_id, $trait_method, $vid, $vid_q, $fun); - }; - ($vid:ident[t => $vid_t:ident]: $fun:ident) => { - impl_unary_!(twice | $trait_id, $trait_method, $vid, $vid_t, $fun); - }; - } - }; -} - -macro_rules! impl_tertiary_ { - // implementation mapping 1:1 - (vec | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self, z: Self) -> Self { - unsafe { - use crate::mem::transmute; - transmute($fun(transmute(self), transmute(y), transmute(z))) - } - } - } - }; - (scalar | $trait_id:ident, $trait_method:ident, - $vec_id:ident, [$sid:ident; $scount:expr], $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self, z: Self) -> Self { - unsafe { - union U { - vec: $vec_id, - scalars: [$sid; $scount], - } - let mut x = U { vec: self }.scalars; - let y = U { vec: y }.scalars; - let z = U { vec: z }.scalars; - for (x, (y, z)) in (&mut scalars).zip(&y).zip(&z) { - *i = $fun(*i, *y, *z); - } - U { vec: x }.vec - } - } - } - }; - // implementation calling fun twice on each of the vector halves: - (halves | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vech_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self, z: Self) -> Self { - unsafe { - use crate::mem::transmute; - union U { - vec: $vec_id, - halves: [$vech_id; 2], - } - - let mut x_halves = U { vec: self }.halves; - let y_halves = U { vec: y }.halves; - let z_halves = U { vec: z }.halves; - - *x_halves.get_unchecked_mut(0) = transmute($fun( - transmute(*x_halves.get_unchecked(0)), - transmute(*y_halves.get_unchecked(0)), - transmute(*z_halves.get_unchecked(0)), - )); - *x_halves.get_unchecked_mut(1) = transmute($fun( - transmute(*x_halves.get_unchecked(1)), - transmute(*y_halves.get_unchecked(1)), - transmute(*z_halves.get_unchecked(1)), - )); - - U { halves: x_halves }.vec - } - } - } - }; - // implementation calling fun four times on each of the vector quarters: - (quarter | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vecq_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self, z: Self) -> Self { - unsafe { - use crate::mem::transmute; - union U { - vec: $vec_id, - quarters: [$vecq_id; 4], - } - - let mut x_quarters = U { vec: self }.quarters; - let y_quarters = U { vec: y }.quarters; - let z_quarters = U { vec: z }.quarters; - - *x_quarters.get_unchecked_mut(0) = transmute($fun( - transmute(*x_quarters.get_unchecked(0)), - transmute(*y_quarters.get_unchecked(0)), - transmute(*z_quarters.get_unchecked(0)), - )); - - *x_quarters.get_unchecked_mut(1) = transmute($fun( - transmute(*x_quarters.get_unchecked(1)), - transmute(*y_quarters.get_unchecked(1)), - transmute(*z_quarters.get_unchecked(1)), - )); - - *x_quarters.get_unchecked_mut(2) = transmute($fun( - transmute(*x_quarters.get_unchecked(2)), - transmute(*y_quarters.get_unchecked(2)), - transmute(*z_quarters.get_unchecked(2)), - )); - - *x_quarters.get_unchecked_mut(3) = transmute($fun( - transmute(*x_quarters.get_unchecked(3)), - transmute(*y_quarters.get_unchecked(3)), - transmute(*z_quarters.get_unchecked(3)), - )); - - U { quarters: x_quarters }.vec - } - } - } - }; - // implementation calling fun once on a vector twice as large: - (twice | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vect_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self, z: Self) -> Self { - unsafe { - use crate::mem::{transmute, uninitialized}; - - union U { - vec: [$vec_id; 2], - twice: $vect_id, - } - - let x_twice = U { vec: [self, uninitialized()] }.twice; - let y_twice = U { vec: [y, uninitialized()] }.twice; - let z_twice = U { vec: [z, uninitialized()] }.twice; - let twice: $vect_id = - transmute($fun(transmute(x_twice), transmute(y_twice), transmute(z_twice))); - - *(U { twice }.vec.get_unchecked(0)) - } - } - } - }; -} - -macro_rules! gen_tertiary_impl_table { - ($trait_id:ident, $trait_method:ident) => { - macro_rules! impl_tertiary { - ($vid:ident: $fun:ident) => { - impl_tertiary_!(vec | $trait_id, $trait_method, $vid, $fun); - }; - ($vid:ident[$sid:ident; $sc:expr]: $fun:ident) => { - impl_tertiary_!(scalar | $trait_id, $trait_method, $vid, [$sid; $sc], $fun); - }; - ($vid:ident[s]: $fun:ident) => { - impl_tertiary_!(scalar | $trait_id, $trait_method, $vid, $fun); - }; - ($vid:ident[h => $vid_h:ident]: $fun:ident) => { - impl_tertiary_!(halves | $trait_id, $trait_method, $vid, $vid_h, $fun); - }; - ($vid:ident[q => $vid_q:ident]: $fun:ident) => { - impl_tertiary_!(quarter | $trait_id, $trait_method, $vid, $vid_q, $fun); - }; - ($vid:ident[t => $vid_t:ident]: $fun:ident) => { - impl_tertiary_!(twice | $trait_id, $trait_method, $vid, $vid_t, $fun); - }; - } - }; -} - -macro_rules! impl_binary_ { - // implementation mapping 1:1 - (vec | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self) -> Self { - unsafe { - use crate::mem::transmute; - transmute($fun(transmute(self), transmute(y))) - } - } - } - }; - (scalar | $trait_id:ident, $trait_method:ident, - $vec_id:ident, [$sid:ident; $scount:expr], $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self) -> Self { - unsafe { - union U { - vec: $vec_id, - scalars: [$sid; $scount], - } - let mut x = U { vec: self }.scalars; - let y = U { vec: y }.scalars; - for (x, y) in x.iter_mut().zip(&y) { - *x = $fun(*x, *y); - } - U { scalars: x }.vec - } - } - } - }; - // implementation calling fun twice on each of the vector halves: - (halves | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vech_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self) -> Self { - unsafe { - use crate::mem::transmute; - union U { - vec: $vec_id, - halves: [$vech_id; 2], - } - - let mut x_halves = U { vec: self }.halves; - let y_halves = U { vec: y }.halves; - - *x_halves.get_unchecked_mut(0) = transmute($fun( - transmute(*x_halves.get_unchecked(0)), - transmute(*y_halves.get_unchecked(0)), - )); - *x_halves.get_unchecked_mut(1) = transmute($fun( - transmute(*x_halves.get_unchecked(1)), - transmute(*y_halves.get_unchecked(1)), - )); - - U { halves: x_halves }.vec - } - } - } - }; - // implementation calling fun four times on each of the vector quarters: - (quarter | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vecq_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self) -> Self { - unsafe { - use crate::mem::transmute; - union U { - vec: $vec_id, - quarters: [$vecq_id; 4], - } - - let mut x_quarters = U { vec: self }.quarters; - let y_quarters = U { vec: y }.quarters; - - *x_quarters.get_unchecked_mut(0) = transmute($fun( - transmute(*x_quarters.get_unchecked(0)), - transmute(*y_quarters.get_unchecked(0)), - )); - - *x_quarters.get_unchecked_mut(1) = transmute($fun( - transmute(*x_quarters.get_unchecked(1)), - transmute(*y_quarters.get_unchecked(1)), - )); - - *x_quarters.get_unchecked_mut(2) = transmute($fun( - transmute(*x_quarters.get_unchecked(2)), - transmute(*y_quarters.get_unchecked(2)), - )); - - *x_quarters.get_unchecked_mut(3) = transmute($fun( - transmute(*x_quarters.get_unchecked(3)), - transmute(*y_quarters.get_unchecked(3)), - )); - - U { quarters: x_quarters }.vec - } - } - } - }; - // implementation calling fun once on a vector twice as large: - (twice | $trait_id:ident, $trait_method:ident, $vec_id:ident, - $vect_id:ident, $fun:ident) => { - impl $trait_id for $vec_id { - #[inline] - fn $trait_method(self, y: Self) -> Self { - unsafe { - use crate::mem::{transmute, uninitialized}; - - union U { - vec: [$vec_id; 2], - twice: $vect_id, - } - - let x_twice = U { vec: [self, uninitialized()] }.twice; - let y_twice = U { vec: [y, uninitialized()] }.twice; - let twice: $vect_id = transmute($fun(transmute(x_twice), transmute(y_twice))); - - *(U { twice }.vec.get_unchecked(0)) - } - } - } - }; -} - -macro_rules! gen_binary_impl_table { - ($trait_id:ident, $trait_method:ident) => { - macro_rules! impl_binary { - ($vid:ident: $fun:ident) => { - impl_binary_!(vec | $trait_id, $trait_method, $vid, $fun); - }; - ($vid:ident[$sid:ident; $sc:expr]: $fun:ident) => { - impl_binary_!(scalar | $trait_id, $trait_method, $vid, [$sid; $sc], $fun); - }; - ($vid:ident[s]: $fun:ident) => { - impl_binary_!(scalar | $trait_id, $trait_method, $vid, $fun); - }; - ($vid:ident[h => $vid_h:ident]: $fun:ident) => { - impl_binary_!(halves | $trait_id, $trait_method, $vid, $vid_h, $fun); - }; - ($vid:ident[q => $vid_q:ident]: $fun:ident) => { - impl_binary_!(quarter | $trait_id, $trait_method, $vid, $vid_q, $fun); - }; - ($vid:ident[t => $vid_t:ident]: $fun:ident) => { - impl_binary_!(twice | $trait_id, $trait_method, $vid, $vid_t, $fun); - }; - } - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/mul_add.rs b/third_party/rust/packed_simd/src/codegen/math/float/mul_add.rs deleted file mode 100644 index d37f30fa86..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/mul_add.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Vertical floating-point `mul_add` -#![allow(unused)] -use crate::*; - -// FIXME: 64-bit 1 element mul_add - -pub(crate) trait MulAdd { - fn mul_add(self, y: Self, z: Self) -> Self; -} - -#[cfg(not(target_arch = "s390x"))] -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.fma.v2f32"] - fn fma_v2f32(x: f32x2, y: f32x2, z: f32x2) -> f32x2; - #[link_name = "llvm.fma.v4f32"] - fn fma_v4f32(x: f32x4, y: f32x4, z: f32x4) -> f32x4; - #[link_name = "llvm.fma.v8f32"] - fn fma_v8f32(x: f32x8, y: f32x8, z: f32x8) -> f32x8; - #[link_name = "llvm.fma.v16f32"] - fn fma_v16f32(x: f32x16, y: f32x16, z: f32x16) -> f32x16; - /* FIXME 64-bit single elem vectors - #[link_name = "llvm.fma.v1f64"] - fn fma_v1f64(x: f64x1, y: f64x1, z: f64x1) -> f64x1; - */ - #[link_name = "llvm.fma.v2f64"] - fn fma_v2f64(x: f64x2, y: f64x2, z: f64x2) -> f64x2; - #[link_name = "llvm.fma.v4f64"] - fn fma_v4f64(x: f64x4, y: f64x4, z: f64x4) -> f64x4; - #[link_name = "llvm.fma.v8f64"] - fn fma_v8f64(x: f64x8, y: f64x8, z: f64x8) -> f64x8; -} - -gen_tertiary_impl_table!(MulAdd, mul_add); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - macro_rules! impl_broken { - ($id:ident) => { - impl MulAdd for $id { - #[inline] - fn mul_add(self, y: Self, z: Self) -> Self { - self * y + z - } - } - }; - } - - impl_broken!(f32x2); - impl_broken!(f32x4); - impl_broken!(f32x8); - impl_broken!(f32x16); - - impl_broken!(f64x2); - impl_broken!(f64x4); - impl_broken!(f64x8); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_tertiary!(f32x2[t => f32x4]: Sleef_fmaf4_avx2128); - impl_tertiary!(f32x16[h => f32x8]: Sleef_fmaf8_avx2); - impl_tertiary!(f64x8[h => f64x4]: Sleef_fmad4_avx2); - - impl_tertiary!(f32x4: Sleef_fmaf4_avx2128); - impl_tertiary!(f32x8: Sleef_fmaf8_avx2); - impl_tertiary!(f64x2: Sleef_fmad2_avx2128); - impl_tertiary!(f64x4: Sleef_fmad4_avx2); - } else if #[cfg(target_feature = "avx")] { - impl_tertiary!(f32x2[t => f32x4]: Sleef_fmaf4_sse4); - impl_tertiary!(f32x16[h => f32x8]: Sleef_fmaf8_avx); - impl_tertiary!(f64x8[h => f64x4]: Sleef_fmad4_avx); - - impl_tertiary!(f32x4: Sleef_fmaf4_sse4); - impl_tertiary!(f32x8: Sleef_fmaf8_avx); - impl_tertiary!(f64x2: Sleef_fmad2_sse4); - impl_tertiary!(f64x4: Sleef_fmad4_avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_tertiary!(f32x2[t => f32x4]: Sleef_fmaf4_sse4); - impl_tertiary!(f32x16[q => f32x4]: Sleef_fmaf4_sse4); - impl_tertiary!(f64x8[q => f64x2]: Sleef_fmad2_sse4); - - impl_tertiary!(f32x4: Sleef_fmaf4_sse4); - impl_tertiary!(f32x8[h => f32x4]: Sleef_fmaf4_sse4); - impl_tertiary!(f64x2: Sleef_fmad2_sse4); - impl_tertiary!(f64x4[h => f64x2]: Sleef_fmad2_sse4); - } else { - impl_tertiary!(f32x2: fma_v2f32); - impl_tertiary!(f32x16: fma_v16f32); - impl_tertiary!(f64x8: fma_v8f64); - - impl_tertiary!(f32x4: fma_v4f32); - impl_tertiary!(f32x8: fma_v8f32); - impl_tertiary!(f64x2: fma_v2f64); - impl_tertiary!(f64x4: fma_v4f64); - } - } - } else { - impl_tertiary!(f32x2: fma_v2f32); - impl_tertiary!(f32x4: fma_v4f32); - impl_tertiary!(f32x8: fma_v8f32); - impl_tertiary!(f32x16: fma_v16f32); - // impl_tertiary!(f64x1: fma_v1f64); // FIXME 64-bit fmagle elem vectors - impl_tertiary!(f64x2: fma_v2f64); - impl_tertiary!(f64x4: fma_v4f64); - impl_tertiary!(f64x8: fma_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/mul_adde.rs b/third_party/rust/packed_simd/src/codegen/math/float/mul_adde.rs deleted file mode 100644 index c0baeacec2..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/mul_adde.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Approximation for floating-point `mul_add` -use crate::*; - -// FIXME: 64-bit 1 element mul_adde - -pub(crate) trait MulAddE { - fn mul_adde(self, y: Self, z: Self) -> Self; -} - -#[cfg(not(target_arch = "s390x"))] -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.fmuladd.v2f32"] - fn fmuladd_v2f32(x: f32x2, y: f32x2, z: f32x2) -> f32x2; - #[link_name = "llvm.fmuladd.v4f32"] - fn fmuladd_v4f32(x: f32x4, y: f32x4, z: f32x4) -> f32x4; - #[link_name = "llvm.fmuladd.v8f32"] - fn fmuladd_v8f32(x: f32x8, y: f32x8, z: f32x8) -> f32x8; - #[link_name = "llvm.fmuladd.v16f32"] - fn fmuladd_v16f32(x: f32x16, y: f32x16, z: f32x16) -> f32x16; - /* FIXME 64-bit single elem vectors - #[link_name = "llvm.fmuladd.v1f64"] - fn fmuladd_v1f64(x: f64x1, y: f64x1, z: f64x1) -> f64x1; - */ - #[link_name = "llvm.fmuladd.v2f64"] - fn fmuladd_v2f64(x: f64x2, y: f64x2, z: f64x2) -> f64x2; - #[link_name = "llvm.fmuladd.v4f64"] - fn fmuladd_v4f64(x: f64x4, y: f64x4, z: f64x4) -> f64x4; - #[link_name = "llvm.fmuladd.v8f64"] - fn fmuladd_v8f64(x: f64x8, y: f64x8, z: f64x8) -> f64x8; -} - -macro_rules! impl_mul_adde { - ($id:ident : $fn:ident) => { - impl MulAddE for $id { - #[inline] - fn mul_adde(self, y: Self, z: Self) -> Self { - #[cfg(not(target_arch = "s390x"))] - { - use crate::mem::transmute; - unsafe { transmute($fn(transmute(self), transmute(y), transmute(z))) } - } - #[cfg(target_arch = "s390x")] - { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - self * y + z - } - } - } - }; -} - -impl_mul_adde!(f32x2: fmuladd_v2f32); -impl_mul_adde!(f32x4: fmuladd_v4f32); -impl_mul_adde!(f32x8: fmuladd_v8f32); -impl_mul_adde!(f32x16: fmuladd_v16f32); -// impl_mul_adde!(f64x1: fma_v1f64); // FIXME 64-bit fmagle elem vectors -impl_mul_adde!(f64x2: fmuladd_v2f64); -impl_mul_adde!(f64x4: fmuladd_v4f64); -impl_mul_adde!(f64x8: fmuladd_v8f64); diff --git a/third_party/rust/packed_simd/src/codegen/math/float/powf.rs b/third_party/rust/packed_simd/src/codegen/math/float/powf.rs deleted file mode 100644 index 89ca52e96d..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/powf.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Vertical floating-point `powf` -#![allow(unused)] - -// FIXME 64-bit powfgle elem vectors mispowfg - -use crate::*; - -pub(crate) trait Powf { - fn powf(self, x: Self) -> Self; -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.pow.v2f32"] - fn powf_v2f32(x: f32x2, y: f32x2) -> f32x2; - #[link_name = "llvm.pow.v4f32"] - fn powf_v4f32(x: f32x4, y: f32x4) -> f32x4; - #[link_name = "llvm.pow.v8f32"] - fn powf_v8f32(x: f32x8, y: f32x8) -> f32x8; - #[link_name = "llvm.pow.v16f32"] - fn powf_v16f32(x: f32x16, y: f32x16) -> f32x16; - /* FIXME 64-bit powfgle elem vectors - #[link_name = "llvm.pow.v1f64"] - fn powf_v1f64(x: f64x1, y: f64x1) -> f64x1; - */ - #[link_name = "llvm.pow.v2f64"] - fn powf_v2f64(x: f64x2, y: f64x2) -> f64x2; - #[link_name = "llvm.pow.v4f64"] - fn powf_v4f64(x: f64x4, y: f64x4) -> f64x4; - #[link_name = "llvm.pow.v8f64"] - fn powf_v8f64(x: f64x8, y: f64x8) -> f64x8; - - #[link_name = "llvm.pow.f32"] - fn powf_f32(x: f32, y: f32) -> f32; - #[link_name = "llvm.pow.f64"] - fn powf_f64(x: f64, y: f64) -> f64; -} - -gen_binary_impl_table!(Powf, powf); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_binary!(f32x2[f32; 2]: powf_f32); - impl_binary!(f32x4[f32; 4]: powf_f32); - impl_binary!(f32x8[f32; 8]: powf_f32); - impl_binary!(f32x16[f32; 16]: powf_f32); - - impl_binary!(f64x2[f64; 2]: powf_f64); - impl_binary!(f64x4[f64; 4]: powf_f64); - impl_binary!(f64x8[f64; 8]: powf_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_binary!(f32x2[t => f32x4]: Sleef_powf4_u10avx2128); - impl_binary!(f32x16[h => f32x8]: Sleef_powf8_u10avx2); - impl_binary!(f64x8[h => f64x4]: Sleef_powd4_u10avx2); - - impl_binary!(f32x4: Sleef_powf4_u10avx2128); - impl_binary!(f32x8: Sleef_powf8_u10avx2); - impl_binary!(f64x2: Sleef_powd2_u10avx2128); - impl_binary!(f64x4: Sleef_powd4_u10avx2); - } else if #[cfg(target_feature = "avx")] { - impl_binary!(f32x2[t => f32x4]: Sleef_powf4_u10sse4); - impl_binary!(f32x16[h => f32x8]: Sleef_powf8_u10avx); - impl_binary!(f64x8[h => f64x4]: Sleef_powd4_u10avx); - - impl_binary!(f32x4: Sleef_powf4_u10sse4); - impl_binary!(f32x8: Sleef_powf8_u10avx); - impl_binary!(f64x2: Sleef_powd2_u10sse4); - impl_binary!(f64x4: Sleef_powd4_u10avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_binary!(f32x2[t => f32x4]: Sleef_powf4_u10sse4); - impl_binary!(f32x16[q => f32x4]: Sleef_powf4_u10sse4); - impl_binary!(f64x8[q => f64x2]: Sleef_powd2_u10sse4); - - impl_binary!(f32x4: Sleef_powf4_u10sse4); - impl_binary!(f32x8[h => f32x4]: Sleef_powf4_u10sse4); - impl_binary!(f64x2: Sleef_powd2_u10sse4); - impl_binary!(f64x4[h => f64x2]: Sleef_powd2_u10sse4); - } else if #[cfg(target_feature = "sse2")] { - impl_binary!(f32x2[t => f32x4]: Sleef_powf4_u10sse2); - impl_binary!(f32x16[q => f32x4]: Sleef_powf4_u10sse2); - impl_binary!(f64x8[q => f64x2]: Sleef_powd2_u10sse2); - - impl_binary!(f32x4: Sleef_powf4_u10sse2); - impl_binary!(f32x8[h => f32x4]: Sleef_powf4_u10sse2); - impl_binary!(f64x2: Sleef_powd2_u10sse2); - impl_binary!(f64x4[h => f64x2]: Sleef_powd2_u10sse2); - } else { - impl_binary!(f32x2[f32; 2]: powf_f32); - impl_binary!(f32x4: powf_v4f32); - impl_binary!(f32x8: powf_v8f32); - impl_binary!(f32x16: powf_v16f32); - - impl_binary!(f64x2: powf_v2f64); - impl_binary!(f64x4: powf_v4f64); - impl_binary!(f64x8: powf_v8f64); - } - } - } else { - impl_binary!(f32x2[f32; 2]: powf_f32); - impl_binary!(f32x4: powf_v4f32); - impl_binary!(f32x8: powf_v8f32); - impl_binary!(f32x16: powf_v16f32); - - impl_binary!(f64x2: powf_v2f64); - impl_binary!(f64x4: powf_v4f64); - impl_binary!(f64x8: powf_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/sin.rs b/third_party/rust/packed_simd/src/codegen/math/float/sin.rs deleted file mode 100644 index d881415909..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/sin.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Vertical floating-point `sin` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors sin - -use crate::*; - -pub(crate) trait Sin { - fn sin(self) -> Self; -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.sin.v2f32"] - fn sin_v2f32(x: f32x2) -> f32x2; - #[link_name = "llvm.sin.v4f32"] - fn sin_v4f32(x: f32x4) -> f32x4; - #[link_name = "llvm.sin.v8f32"] - fn sin_v8f32(x: f32x8) -> f32x8; - #[link_name = "llvm.sin.v16f32"] - fn sin_v16f32(x: f32x16) -> f32x16; - /* FIXME 64-bit single elem vectors - #[link_name = "llvm.sin.v1f64"] - fn sin_v1f64(x: f64x1) -> f64x1; - */ - #[link_name = "llvm.sin.v2f64"] - fn sin_v2f64(x: f64x2) -> f64x2; - #[link_name = "llvm.sin.v4f64"] - fn sin_v4f64(x: f64x4) -> f64x4; - #[link_name = "llvm.sin.v8f64"] - fn sin_v8f64(x: f64x8) -> f64x8; - - #[link_name = "llvm.sin.f32"] - fn sin_f32(x: f32) -> f32; - #[link_name = "llvm.sin.f64"] - fn sin_f64(x: f64) -> f64; -} - -gen_unary_impl_table!(Sin, sin); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_unary!(f32x2[f32; 2]: sin_f32); - impl_unary!(f32x4[f32; 4]: sin_f32); - impl_unary!(f32x8[f32; 8]: sin_f32); - impl_unary!(f32x16[f32; 16]: sin_f32); - - impl_unary!(f64x2[f64; 2]: sin_f64); - impl_unary!(f64x4[f64; 4]: sin_f64); - impl_unary!(f64x8[f64; 8]: sin_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sinf4_u10avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_sinf8_u10avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_sind4_u10avx2); - - impl_unary!(f32x4: Sleef_sinf4_u10avx2128); - impl_unary!(f32x8: Sleef_sinf8_u10avx2); - impl_unary!(f64x2: Sleef_sind2_u10avx2128); - impl_unary!(f64x4: Sleef_sind4_u10avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sinf4_u10sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_sinf8_u10avx); - impl_unary!(f64x8[h => f64x4]: Sleef_sind4_u10avx); - - impl_unary!(f32x4: Sleef_sinf4_u10sse4); - impl_unary!(f32x8: Sleef_sinf8_u10avx); - impl_unary!(f64x2: Sleef_sind2_u10sse4); - impl_unary!(f64x4: Sleef_sind4_u10avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sinf4_u10sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_sinf4_u10sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_sind2_u10sse4); - - impl_unary!(f32x4: Sleef_sinf4_u10sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_sinf4_u10sse4); - impl_unary!(f64x2: Sleef_sind2_u10sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_sind2_u10sse4); - } else { - impl_unary!(f32x2[f32; 2]: sin_f32); - impl_unary!(f32x16: sin_v16f32); - impl_unary!(f64x8: sin_v8f64); - - impl_unary!(f32x4: sin_v4f32); - impl_unary!(f32x8: sin_v8f32); - impl_unary!(f64x2: sin_v2f64); - impl_unary!(f64x4: sin_v4f64); - } - } - } else { - impl_unary!(f32x2[f32; 2]: sin_f32); - impl_unary!(f32x4: sin_v4f32); - impl_unary!(f32x8: sin_v8f32); - impl_unary!(f32x16: sin_v16f32); - - impl_unary!(f64x2: sin_v2f64); - impl_unary!(f64x4: sin_v4f64); - impl_unary!(f64x8: sin_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/sin_cos_pi.rs b/third_party/rust/packed_simd/src/codegen/math/float/sin_cos_pi.rs deleted file mode 100644 index b283d11111..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/sin_cos_pi.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! Vertical floating-point `sin_cos` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors sin_cos - -use crate::*; - -pub(crate) trait SinCosPi: Sized { - type Output; - fn sin_cos_pi(self) -> Self::Output; -} - -macro_rules! impl_def { - ($vid:ident, $PI:path) => { - impl SinCosPi for $vid { - type Output = (Self, Self); - #[inline] - fn sin_cos_pi(self) -> Self::Output { - let v = self * Self::splat($PI); - (v.sin(), v.cos()) - } - } - }; -} - -macro_rules! impl_def32 { - ($vid:ident) => { - impl_def!($vid, crate::f32::consts::PI); - }; -} -macro_rules! impl_def64 { - ($vid:ident) => { - impl_def!($vid, crate::f64::consts::PI); - }; -} - -macro_rules! impl_unary_t { - ($vid:ident: $fun:ident) => { - impl SinCosPi for $vid { - type Output = (Self, Self); - fn sin_cos_pi(self) -> Self::Output { - unsafe { - use crate::mem::transmute; - transmute($fun(transmute(self))) - } - } - } - }; - ($vid:ident[t => $vid_t:ident]: $fun:ident) => { - impl SinCosPi for $vid { - type Output = (Self, Self); - fn sin_cos_pi(self) -> Self::Output { - unsafe { - use crate::mem::{transmute, uninitialized}; - - union U { - vec: [$vid; 2], - twice: $vid_t, - } - - let twice = U { vec: [self, uninitialized()] }.twice; - let twice = transmute($fun(transmute(twice))); - - union R { - twice: ($vid_t, $vid_t), - vecs: ([$vid; 2], [$vid; 2]), - } - let r = R { twice }.vecs; - (*r.0.get_unchecked(0), *r.0.get_unchecked(1)) - } - } - } - }; - ($vid:ident[h => $vid_h:ident]: $fun:ident) => { - impl SinCosPi for $vid { - type Output = (Self, Self); - fn sin_cos_pi(self) -> Self::Output { - unsafe { - use crate::mem::transmute; - - union U { - vec: $vid, - halves: [$vid_h; 2], - } - - let halves = U { vec: self }.halves; - - let res_0: ($vid_h, $vid_h) = transmute($fun(transmute(*halves.get_unchecked(0)))); - let res_1: ($vid_h, $vid_h) = transmute($fun(transmute(*halves.get_unchecked(1)))); - - union R { - result: ($vid, $vid), - halves: ([$vid_h; 2], [$vid_h; 2]), - } - R { halves: ([res_0.0, res_1.0], [res_0.1, res_1.1]) }.result - } - } - } - }; - ($vid:ident[q => $vid_q:ident]: $fun:ident) => { - impl SinCosPi for $vid { - type Output = (Self, Self); - fn sin_cos_pi(self) -> Self::Output { - unsafe { - use crate::mem::transmute; - - union U { - vec: $vid, - quarters: [$vid_q; 4], - } - - let quarters = U { vec: self }.quarters; - - let res_0: ($vid_q, $vid_q) = transmute($fun(transmute(*quarters.get_unchecked(0)))); - let res_1: ($vid_q, $vid_q) = transmute($fun(transmute(*quarters.get_unchecked(1)))); - let res_2: ($vid_q, $vid_q) = transmute($fun(transmute(*quarters.get_unchecked(2)))); - let res_3: ($vid_q, $vid_q) = transmute($fun(transmute(*quarters.get_unchecked(3)))); - - union R { - result: ($vid, $vid), - quarters: ([$vid_q; 4], [$vid_q; 4]), - } - R { - quarters: ( - [res_0.0, res_1.0, res_2.0, res_3.0], - [res_0.1, res_1.1, res_2.1, res_3.1], - ), - } - .result - } - } - } - }; -} - -cfg_if! { - if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary_t!(f32x2[t => f32x4]: Sleef_sincospif4_u05avx2128); - impl_unary_t!(f32x16[h => f32x8]: Sleef_sincospif8_u05avx2); - impl_unary_t!(f64x8[h => f64x4]: Sleef_sincospid4_u05avx2); - - impl_unary_t!(f32x4: Sleef_sincospif4_u05avx2128); - impl_unary_t!(f32x8: Sleef_sincospif8_u05avx2); - impl_unary_t!(f64x2: Sleef_sincospid2_u05avx2128); - impl_unary_t!(f64x4: Sleef_sincospid4_u05avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary_t!(f32x2[t => f32x4]: Sleef_sincospif4_u05sse4); - impl_unary_t!(f32x16[h => f32x8]: Sleef_sincospif8_u05avx); - impl_unary_t!(f64x8[h => f64x4]: Sleef_sincospid4_u05avx); - - impl_unary_t!(f32x4: Sleef_sincospif4_u05sse4); - impl_unary_t!(f32x8: Sleef_sincospif8_u05avx); - impl_unary_t!(f64x2: Sleef_sincospid2_u05sse4); - impl_unary_t!(f64x4: Sleef_sincospid4_u05avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary_t!(f32x2[t => f32x4]: Sleef_sincospif4_u05sse4); - impl_unary_t!(f32x16[q => f32x4]: Sleef_sincospif4_u05sse4); - impl_unary_t!(f64x8[q => f64x2]: Sleef_sincospid2_u05sse4); - - impl_unary_t!(f32x4: Sleef_sincospif4_u05sse4); - impl_unary_t!(f32x8[h => f32x4]: Sleef_sincospif4_u05sse4); - impl_unary_t!(f64x2: Sleef_sincospid2_u05sse4); - impl_unary_t!(f64x4[h => f64x2]: Sleef_sincospid2_u05sse4); - } else { - impl_def32!(f32x2); - impl_def32!(f32x4); - impl_def32!(f32x8); - impl_def32!(f32x16); - - impl_def64!(f64x2); - impl_def64!(f64x4); - impl_def64!(f64x8); - } - } - } else { - impl_def32!(f32x2); - impl_def32!(f32x4); - impl_def32!(f32x8); - impl_def32!(f32x16); - - impl_def64!(f64x2); - impl_def64!(f64x4); - impl_def64!(f64x8); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/sin_pi.rs b/third_party/rust/packed_simd/src/codegen/math/float/sin_pi.rs deleted file mode 100644 index 0c8f6bb120..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/sin_pi.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Vertical floating-point `sin_pi` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors sin_pi - -use crate::*; - -pub(crate) trait SinPi { - fn sin_pi(self) -> Self; -} - -gen_unary_impl_table!(SinPi, sin_pi); - -macro_rules! impl_def { - ($vid:ident, $PI:path) => { - impl SinPi for $vid { - #[inline] - fn sin_pi(self) -> Self { - (self * Self::splat($PI)).sin() - } - } - }; -} -macro_rules! impl_def32 { - ($vid:ident) => { - impl_def!($vid, crate::f32::consts::PI); - }; -} -macro_rules! impl_def64 { - ($vid:ident) => { - impl_def!($vid, crate::f64::consts::PI); - }; -} - -cfg_if! { - if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sinpif4_u05avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_sinpif8_u05avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_sinpid4_u05avx2); - - impl_unary!(f32x4: Sleef_sinpif4_u05avx2128); - impl_unary!(f32x8: Sleef_sinpif8_u05avx2); - impl_unary!(f64x2: Sleef_sinpid2_u05avx2128); - impl_unary!(f64x4: Sleef_sinpid4_u05avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sinpif4_u05sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_sinpif8_u05avx); - impl_unary!(f64x8[h => f64x4]: Sleef_sinpid4_u05avx); - - impl_unary!(f32x4: Sleef_sinpif4_u05sse4); - impl_unary!(f32x8: Sleef_sinpif8_u05avx); - impl_unary!(f64x2: Sleef_sinpid2_u05sse4); - impl_unary!(f64x4: Sleef_sinpid4_u05avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sinpif4_u05sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_sinpif4_u05sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_sinpid2_u05sse4); - - impl_unary!(f32x4: Sleef_sinpif4_u05sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_sinpif4_u05sse4); - impl_unary!(f64x2: Sleef_sinpid2_u05sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_sinpid2_u05sse4); - } else { - impl_def32!(f32x2); - impl_def32!(f32x4); - impl_def32!(f32x8); - impl_def32!(f32x16); - - impl_def64!(f64x2); - impl_def64!(f64x4); - impl_def64!(f64x8); - } - } - } else { - impl_def32!(f32x2); - impl_def32!(f32x4); - impl_def32!(f32x8); - impl_def32!(f32x16); - - impl_def64!(f64x2); - impl_def64!(f64x4); - impl_def64!(f64x8); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/sqrt.rs b/third_party/rust/packed_simd/src/codegen/math/float/sqrt.rs deleted file mode 100644 index 67bb0a2a9c..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/sqrt.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Vertical floating-point `sqrt` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors sqrt - -use crate::*; - -pub(crate) trait Sqrt { - fn sqrt(self) -> Self; -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.sqrt.v2f32"] - fn sqrt_v2f32(x: f32x2) -> f32x2; - #[link_name = "llvm.sqrt.v4f32"] - fn sqrt_v4f32(x: f32x4) -> f32x4; - #[link_name = "llvm.sqrt.v8f32"] - fn sqrt_v8f32(x: f32x8) -> f32x8; - #[link_name = "llvm.sqrt.v16f32"] - fn sqrt_v16f32(x: f32x16) -> f32x16; - /* FIXME 64-bit sqrtgle elem vectors - #[link_name = "llvm.sqrt.v1f64"] - fn sqrt_v1f64(x: f64x1) -> f64x1; - */ - #[link_name = "llvm.sqrt.v2f64"] - fn sqrt_v2f64(x: f64x2) -> f64x2; - #[link_name = "llvm.sqrt.v4f64"] - fn sqrt_v4f64(x: f64x4) -> f64x4; - #[link_name = "llvm.sqrt.v8f64"] - fn sqrt_v8f64(x: f64x8) -> f64x8; - - #[link_name = "llvm.sqrt.f32"] - fn sqrt_f32(x: f32) -> f32; - #[link_name = "llvm.sqrt.f64"] - fn sqrt_f64(x: f64) -> f64; -} - -gen_unary_impl_table!(Sqrt, sqrt); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_unary!(f32x2[f32; 2]: sqrt_f32); - impl_unary!(f32x4[f32; 4]: sqrt_f32); - impl_unary!(f32x8[f32; 8]: sqrt_f32); - impl_unary!(f32x16[f32; 16]: sqrt_f32); - - impl_unary!(f64x2[f64; 2]: sqrt_f64); - impl_unary!(f64x4[f64; 4]: sqrt_f64); - impl_unary!(f64x8[f64; 8]: sqrt_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sqrtf4_avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_sqrtf8_avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_sqrtd4_avx2); - - impl_unary!(f32x4: Sleef_sqrtf4_avx2128); - impl_unary!(f32x8: Sleef_sqrtf8_avx2); - impl_unary!(f64x2: Sleef_sqrtd2_avx2128); - impl_unary!(f64x4: Sleef_sqrtd4_avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sqrtf4_sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_sqrtf8_avx); - impl_unary!(f64x8[h => f64x4]: Sleef_sqrtd4_avx); - - impl_unary!(f32x4: Sleef_sqrtf4_sse4); - impl_unary!(f32x8: Sleef_sqrtf8_avx); - impl_unary!(f64x2: Sleef_sqrtd2_sse4); - impl_unary!(f64x4: Sleef_sqrtd4_avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sqrtf4_sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_sqrtf4_sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_sqrtd2_sse4); - - impl_unary!(f32x4: Sleef_sqrtf4_sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_sqrtf4_sse4); - impl_unary!(f64x2: Sleef_sqrtd2_sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_sqrtd2_sse4); - } else { - impl_unary!(f32x2[f32; 2]: sqrt_f32); - impl_unary!(f32x16: sqrt_v16f32); - impl_unary!(f64x8: sqrt_v8f64); - - impl_unary!(f32x4: sqrt_v4f32); - impl_unary!(f32x8: sqrt_v8f32); - impl_unary!(f64x2: sqrt_v2f64); - impl_unary!(f64x4: sqrt_v4f64); - } - } - } else { - impl_unary!(f32x2[f32; 2]: sqrt_f32); - impl_unary!(f32x4: sqrt_v4f32); - impl_unary!(f32x8: sqrt_v8f32); - impl_unary!(f32x16: sqrt_v16f32); - - impl_unary!(f64x2: sqrt_v2f64); - impl_unary!(f64x4: sqrt_v4f64); - impl_unary!(f64x8: sqrt_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/sqrte.rs b/third_party/rust/packed_simd/src/codegen/math/float/sqrte.rs deleted file mode 100644 index 58a1de1f40..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/sqrte.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Vertical floating-point `sqrt` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors sqrte - -use crate::llvm::simd_fsqrt; -use crate::*; - -pub(crate) trait Sqrte { - fn sqrte(self) -> Self; -} - -gen_unary_impl_table!(Sqrte, sqrte); - -cfg_if! { - if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sqrtf4_u35avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_sqrtf8_u35avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_sqrtd4_u35avx2); - - impl_unary!(f32x4: Sleef_sqrtf4_u35avx2128); - impl_unary!(f32x8: Sleef_sqrtf8_u35avx2); - impl_unary!(f64x2: Sleef_sqrtd2_u35avx2128); - impl_unary!(f64x4: Sleef_sqrtd4_u35avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sqrtf4_u35sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_sqrtf8_u35avx); - impl_unary!(f64x8[h => f64x4]: Sleef_sqrtd4_u35avx); - - impl_unary!(f32x4: Sleef_sqrtf4_u35sse4); - impl_unary!(f32x8: Sleef_sqrtf8_u35avx); - impl_unary!(f64x2: Sleef_sqrtd2_u35sse4); - impl_unary!(f64x4: Sleef_sqrtd4_u35avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_sqrtf4_u35sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_sqrtf4_u35sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_sqrtd2_u35sse4); - - impl_unary!(f32x4: Sleef_sqrtf4_u35sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_sqrtf4_u35sse4); - impl_unary!(f64x2: Sleef_sqrtd2_u35sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_sqrtd2_u35sse4); - } else { - impl_unary!(f32x2[g]: simd_fsqrt); - impl_unary!(f32x16[g]: simd_fsqrt); - impl_unary!(f64x8[g]: simd_fsqrt); - - impl_unary!(f32x4[g]: simd_fsqrt); - impl_unary!(f32x8[g]: simd_fsqrt); - impl_unary!(f64x2[g]: simd_fsqrt); - impl_unary!(f64x4[g]: simd_fsqrt); - } - } - } else { - impl_unary!(f32x2[g]: simd_fsqrt); - impl_unary!(f32x4[g]: simd_fsqrt); - impl_unary!(f32x8[g]: simd_fsqrt); - impl_unary!(f32x16[g]: simd_fsqrt); - - impl_unary!(f64x2[g]: simd_fsqrt); - impl_unary!(f64x4[g]: simd_fsqrt); - impl_unary!(f64x8[g]: simd_fsqrt); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/math/float/tanh.rs b/third_party/rust/packed_simd/src/codegen/math/float/tanh.rs deleted file mode 100644 index 4243b0d886..0000000000 --- a/third_party/rust/packed_simd/src/codegen/math/float/tanh.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! Vertical floating-point `tanh` -#![allow(unused)] - -// FIXME 64-bit 1 elem vectors tanh - -#[cfg(not(feature = "std"))] -use num_traits::Float; - -use crate::*; - -pub(crate) trait Tanh { - fn tanh(self) -> Self; -} - -macro_rules! define_tanh { - ($name:ident, $basetype:ty, $simdtype:ty, $lanes:expr, $trait:path) => { - fn $name(x: $simdtype) -> $simdtype { - use core::intrinsics::transmute; - let mut buf: [$basetype; $lanes] = unsafe { transmute(x) }; - for elem in &mut buf { - *elem = <$basetype as $trait>::tanh(*elem); - } - unsafe { transmute(buf) } - } - }; - - (f32 => $name:ident, $type:ty, $lanes:expr) => { - define_tanh!($name, f32, $type, $lanes, Float); - }; - - (f64 => $name:ident, $type:ty, $lanes:expr) => { - define_tanh!($name, f64, $type, $lanes, Float); - }; -} - -// llvm does not seem to expose the hyperbolic versions of trigonometric -// functions; we thus call the classical rust versions on all of them (which -// stem from cmath). -define_tanh!(f32 => tanh_v2f32, f32x2, 2); -define_tanh!(f32 => tanh_v4f32, f32x4, 4); -define_tanh!(f32 => tanh_v8f32, f32x8, 8); -define_tanh!(f32 => tanh_v16f32, f32x16, 16); - -define_tanh!(f64 => tanh_v2f64, f64x2, 2); -define_tanh!(f64 => tanh_v4f64, f64x4, 4); -define_tanh!(f64 => tanh_v8f64, f64x8, 8); - -fn tanh_f32(x: f32) -> f32 { - Float::tanh(x) -} - -fn tanh_f64(x: f64) -> f64 { - Float::tanh(x) -} - -gen_unary_impl_table!(Tanh, tanh); - -cfg_if! { - if #[cfg(target_arch = "s390x")] { - // FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/14 - impl_unary!(f32x2[f32; 2]: tanh_f32); - impl_unary!(f32x4[f32; 4]: tanh_f32); - impl_unary!(f32x8[f32; 8]: tanh_f32); - impl_unary!(f32x16[f32; 16]: tanh_f32); - - impl_unary!(f64x2[f64; 2]: tanh_f64); - impl_unary!(f64x4[f64; 4]: tanh_f64); - impl_unary!(f64x8[f64; 8]: tanh_f64); - } else if #[cfg(all(target_arch = "x86_64", feature = "sleef-sys"))] { - use sleef_sys::*; - cfg_if! { - if #[cfg(target_feature = "avx2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_tanhf4_u10avx2128); - impl_unary!(f32x16[h => f32x8]: Sleef_tanhf8_u10avx2); - impl_unary!(f64x8[h => f64x4]: Sleef_tanhd4_u10avx2); - - impl_unary!(f32x4: Sleef_tanhf4_u10avx2128); - impl_unary!(f32x8: Sleef_tanhf8_u10avx2); - impl_unary!(f64x2: Sleef_tanhd2_u10avx2128); - impl_unary!(f64x4: Sleef_tanhd4_u10avx2); - } else if #[cfg(target_feature = "avx")] { - impl_unary!(f32x2[t => f32x4]: Sleef_tanhf4_u10sse4); - impl_unary!(f32x16[h => f32x8]: Sleef_tanhf8_u10avx); - impl_unary!(f64x8[h => f64x4]: Sleef_tanhd4_u10avx); - - impl_unary!(f32x4: Sleef_tanhf4_u10sse4); - impl_unary!(f32x8: Sleef_tanhf8_u10avx); - impl_unary!(f64x2: Sleef_tanhd2_u10sse4); - impl_unary!(f64x4: Sleef_tanhd4_u10avx); - } else if #[cfg(target_feature = "sse4.2")] { - impl_unary!(f32x2[t => f32x4]: Sleef_tanhf4_u10sse4); - impl_unary!(f32x16[q => f32x4]: Sleef_tanhf4_u10sse4); - impl_unary!(f64x8[q => f64x2]: Sleef_tanhd2_u10sse4); - - impl_unary!(f32x4: Sleef_tanhf4_u10sse4); - impl_unary!(f32x8[h => f32x4]: Sleef_tanhf4_u10sse4); - impl_unary!(f64x2: Sleef_tanhd2_u10sse4); - impl_unary!(f64x4[h => f64x2]: Sleef_tanhd2_u10sse4); - } else { - impl_unary!(f32x2[f32; 2]: tanh_f32); - impl_unary!(f32x16: tanh_v16f32); - impl_unary!(f64x8: tanh_v8f64); - - impl_unary!(f32x4: tanh_v4f32); - impl_unary!(f32x8: tanh_v8f32); - impl_unary!(f64x2: tanh_v2f64); - impl_unary!(f64x4: tanh_v4f64); - } - } - } else { - impl_unary!(f32x2[f32; 2]: tanh_f32); - impl_unary!(f32x4: tanh_v4f32); - impl_unary!(f32x8: tanh_v8f32); - impl_unary!(f32x16: tanh_v16f32); - - impl_unary!(f64x2: tanh_v2f64); - impl_unary!(f64x4: tanh_v4f64); - impl_unary!(f64x8: tanh_v8f64); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/pointer_sized_int.rs b/third_party/rust/packed_simd/src/codegen/pointer_sized_int.rs deleted file mode 100644 index 55cbc297aa..0000000000 --- a/third_party/rust/packed_simd/src/codegen/pointer_sized_int.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Provides `isize` and `usize` - -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(target_pointer_width = "8")] { - pub(crate) type isize_ = i8; - pub(crate) type usize_ = u8; - } else if #[cfg(target_pointer_width = "16")] { - pub(crate) type isize_ = i16; - pub(crate) type usize_ = u16; - } else if #[cfg(target_pointer_width = "32")] { - pub(crate) type isize_ = i32; - pub(crate) type usize_ = u32; - - } else if #[cfg(target_pointer_width = "64")] { - pub(crate) type isize_ = i64; - pub(crate) type usize_ = u64; - } else if #[cfg(target_pointer_width = "64")] { - pub(crate) type isize_ = i64; - pub(crate) type usize_ = u64; - } else if #[cfg(target_pointer_width = "128")] { - pub(crate) type isize_ = i128; - pub(crate) type usize_ = u128; - } else { - compile_error!("unsupported target_pointer_width"); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions.rs b/third_party/rust/packed_simd/src/codegen/reductions.rs deleted file mode 100644 index 302ca6d88f..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod mask; diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask.rs deleted file mode 100644 index a78bcc5632..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Code generation workaround for `all()` mask horizontal reduction. -//! -//! Works around [LLVM bug 36702]. -//! -//! [LLVM bug 36702]: https://bugs.llvm.org/show_bug.cgi?id=36702 -#![allow(unused_macros)] - -use crate::*; - -pub(crate) trait All: crate::marker::Sized { - unsafe fn all(self) -> bool; -} - -pub(crate) trait Any: crate::marker::Sized { - unsafe fn any(self) -> bool; -} - -#[macro_use] -mod fallback_impl; - -cfg_if! { - if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - #[macro_use] - mod x86; - } else if #[cfg(all(target_arch = "arm", target_feature = "v7", - target_feature = "neon", - any(feature = "core_arch", libcore_neon)))] { - #[macro_use] - mod arm; - } else if #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] { - #[macro_use] - mod aarch64; - } else { - #[macro_use] - mod fallback; - } -} - -impl_mask_reductions!(m8x2); -impl_mask_reductions!(m8x4); -impl_mask_reductions!(m8x8); -impl_mask_reductions!(m8x16); -impl_mask_reductions!(m8x32); -impl_mask_reductions!(m8x64); - -impl_mask_reductions!(m16x2); -impl_mask_reductions!(m16x4); -impl_mask_reductions!(m16x8); -impl_mask_reductions!(m16x16); -impl_mask_reductions!(m16x32); - -impl_mask_reductions!(m32x2); -impl_mask_reductions!(m32x4); -impl_mask_reductions!(m32x8); -impl_mask_reductions!(m32x16); - -// FIXME: 64-bit single element vector -// impl_mask_reductions!(m64x1); -impl_mask_reductions!(m64x2); -impl_mask_reductions!(m64x4); -impl_mask_reductions!(m64x8); - -impl_mask_reductions!(m128x1); -impl_mask_reductions!(m128x2); -impl_mask_reductions!(m128x4); - -impl_mask_reductions!(msizex2); -impl_mask_reductions!(msizex4); -impl_mask_reductions!(msizex8); diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/aarch64.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/aarch64.rs deleted file mode 100644 index b2db52c891..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/aarch64.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Mask reductions implementation for `aarch64` targets - -/// 128-bit wide vectors -macro_rules! aarch64_128_neon_impl { - ($id:ident, $vmin:ident, $vmax:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "neon")] - unsafe fn all(self) -> bool { - use crate::arch::aarch64::$vmin; - $vmin(crate::mem::transmute(self)) != 0 - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "neon")] - unsafe fn any(self) -> bool { - use crate::arch::aarch64::$vmax; - $vmax(crate::mem::transmute(self)) != 0 - } - } - }; -} - -/// 64-bit wide vectors -macro_rules! aarch64_64_neon_impl { - ($id:ident, $vec128:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "neon")] - unsafe fn all(self) -> bool { - // Duplicates the 64-bit vector into a 128-bit one and - // calls all on that. - union U { - halves: ($id, $id), - vec: $vec128, - } - U { halves: (self, self) }.vec.all() - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "neon")] - unsafe fn any(self) -> bool { - union U { - halves: ($id, $id), - vec: $vec128, - } - U { halves: (self, self) }.vec.any() - } - } - }; -} - -/// Mask reduction implementation for `aarch64` targets -macro_rules! impl_mask_reductions { - // 64-bit wide masks - (m8x8) => { - aarch64_64_neon_impl!(m8x8, m8x16); - }; - (m16x4) => { - aarch64_64_neon_impl!(m16x4, m16x8); - }; - (m32x2) => { - aarch64_64_neon_impl!(m32x2, m32x4); - }; - // 128-bit wide masks - (m8x16) => { - aarch64_128_neon_impl!(m8x16, vminvq_u8, vmaxvq_u8); - }; - (m16x8) => { - aarch64_128_neon_impl!(m16x8, vminvq_u16, vmaxvq_u16); - }; - (m32x4) => { - aarch64_128_neon_impl!(m32x4, vminvq_u32, vmaxvq_u32); - }; - // Fallback to LLVM's default code-generation: - ($id:ident) => { - fallback_impl!($id); - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/arm.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/arm.rs deleted file mode 100644 index 41c3cbc58a..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/arm.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Mask reductions implementation for `arm` targets - -/// Implementation for ARM + v7 + NEON for 64-bit or 128-bit wide vectors with -/// more than two elements. -macro_rules! arm_128_v7_neon_impl { - ($id:ident, $half:ident, $vpmin:ident, $vpmax:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "v7,neon")] - unsafe fn all(self) -> bool { - use crate::arch::arm::$vpmin; - use crate::mem::transmute; - union U { - halves: ($half, $half), - vec: $id, - } - let halves = U { vec: self }.halves; - let h: $half = transmute($vpmin(transmute(halves.0), transmute(halves.1))); - h.all() - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "v7,neon")] - unsafe fn any(self) -> bool { - use crate::arch::arm::$vpmax; - use crate::mem::transmute; - union U { - halves: ($half, $half), - vec: $id, - } - let halves = U { vec: self }.halves; - let h: $half = transmute($vpmax(transmute(halves.0), transmute(halves.1))); - h.any() - } - } - }; -} - -/// Mask reduction implementation for `arm` targets -macro_rules! impl_mask_reductions { - // 128-bit wide masks - (m8x16) => { - arm_128_v7_neon_impl!(m8x16, m8x8, vpmin_u8, vpmax_u8); - }; - (m16x8) => { - arm_128_v7_neon_impl!(m16x8, m16x4, vpmin_u16, vpmax_u16); - }; - (m32x4) => { - arm_128_v7_neon_impl!(m32x4, m32x2, vpmin_u32, vpmax_u32); - }; - // Fallback to LLVM's default code-generation: - ($id:ident) => { - fallback_impl!($id); - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/fallback.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/fallback.rs deleted file mode 100644 index 4c377a6878..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/fallback.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Default mask reduction implementations. - -/// Default mask reduction implementation -macro_rules! impl_mask_reductions { - ($id:ident) => { - fallback_impl!($id); - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/fallback_impl.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/fallback_impl.rs deleted file mode 100644 index 0d246e2fda..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/fallback_impl.rs +++ /dev/null @@ -1,237 +0,0 @@ -//! Default implementation of a mask reduction for any target. - -macro_rules! fallback_to_other_impl { - ($id:ident, $other:ident) => { - impl All for $id { - #[inline] - unsafe fn all(self) -> bool { - let m: $other = crate::mem::transmute(self); - m.all() - } - } - impl Any for $id { - #[inline] - unsafe fn any(self) -> bool { - let m: $other = crate::mem::transmute(self); - m.any() - } - } - }; -} - -/// Fallback implementation. -macro_rules! fallback_impl { - // 16-bit wide masks: - (m8x2) => { - impl All for m8x2 { - #[inline] - unsafe fn all(self) -> bool { - let i: u16 = crate::mem::transmute(self); - i == u16::max_value() - } - } - impl Any for m8x2 { - #[inline] - unsafe fn any(self) -> bool { - let i: u16 = crate::mem::transmute(self); - i != 0 - } - } - }; - // 32-bit wide masks - (m8x4) => { - impl All for m8x4 { - #[inline] - unsafe fn all(self) -> bool { - let i: u32 = crate::mem::transmute(self); - i == u32::max_value() - } - } - impl Any for m8x4 { - #[inline] - unsafe fn any(self) -> bool { - let i: u32 = crate::mem::transmute(self); - i != 0 - } - } - }; - (m16x2) => { - fallback_to_other_impl!(m16x2, m8x4); - }; - // 64-bit wide masks: - (m8x8) => { - impl All for m8x8 { - #[inline] - unsafe fn all(self) -> bool { - let i: u64 = crate::mem::transmute(self); - i == u64::max_value() - } - } - impl Any for m8x8 { - #[inline] - unsafe fn any(self) -> bool { - let i: u64 = crate::mem::transmute(self); - i != 0 - } - } - }; - (m16x4) => { - fallback_to_other_impl!(m16x4, m8x8); - }; - (m32x2) => { - fallback_to_other_impl!(m32x2, m16x4); - }; - // FIXME: 64x1 maxk - // 128-bit wide masks: - (m8x16) => { - impl All for m8x16 { - #[inline] - unsafe fn all(self) -> bool { - let i: u128 = crate::mem::transmute(self); - i == u128::max_value() - } - } - impl Any for m8x16 { - #[inline] - unsafe fn any(self) -> bool { - let i: u128 = crate::mem::transmute(self); - i != 0 - } - } - }; - (m16x8) => { - fallback_to_other_impl!(m16x8, m8x16); - }; - (m32x4) => { - fallback_to_other_impl!(m32x4, m16x8); - }; - (m64x2) => { - fallback_to_other_impl!(m64x2, m32x4); - }; - (m128x1) => { - fallback_to_other_impl!(m128x1, m64x2); - }; - // 256-bit wide masks - (m8x32) => { - impl All for m8x32 { - #[inline] - unsafe fn all(self) -> bool { - let i: [u128; 2] = crate::mem::transmute(self); - let o: [u128; 2] = [u128::max_value(); 2]; - i == o - } - } - impl Any for m8x32 { - #[inline] - unsafe fn any(self) -> bool { - let i: [u128; 2] = crate::mem::transmute(self); - let o: [u128; 2] = [0; 2]; - i != o - } - } - }; - (m16x16) => { - fallback_to_other_impl!(m16x16, m8x32); - }; - (m32x8) => { - fallback_to_other_impl!(m32x8, m16x16); - }; - (m64x4) => { - fallback_to_other_impl!(m64x4, m32x8); - }; - (m128x2) => { - fallback_to_other_impl!(m128x2, m64x4); - }; - // 512-bit wide masks - (m8x64) => { - impl All for m8x64 { - #[inline] - unsafe fn all(self) -> bool { - let i: [u128; 4] = crate::mem::transmute(self); - let o: [u128; 4] = [u128::max_value(); 4]; - i == o - } - } - impl Any for m8x64 { - #[inline] - unsafe fn any(self) -> bool { - let i: [u128; 4] = crate::mem::transmute(self); - let o: [u128; 4] = [0; 4]; - i != o - } - } - }; - (m16x32) => { - fallback_to_other_impl!(m16x32, m8x64); - }; - (m32x16) => { - fallback_to_other_impl!(m32x16, m16x32); - }; - (m64x8) => { - fallback_to_other_impl!(m64x8, m32x16); - }; - (m128x4) => { - fallback_to_other_impl!(m128x4, m64x8); - }; - // Masks with pointer-sized elements64 - (msizex2) => { - cfg_if! { - if #[cfg(target_pointer_width = "64")] { - fallback_to_other_impl!(msizex2, m64x2); - } else if #[cfg(target_pointer_width = "32")] { - fallback_to_other_impl!(msizex2, m32x2); - } else { - compile_error!("unsupported target_pointer_width"); - } - } - }; - (msizex4) => { - cfg_if! { - if #[cfg(target_pointer_width = "64")] { - fallback_to_other_impl!(msizex4, m64x4); - } else if #[cfg(target_pointer_width = "32")] { - fallback_to_other_impl!(msizex4, m32x4); - } else { - compile_error!("unsupported target_pointer_width"); - } - } - }; - (msizex8) => { - cfg_if! { - if #[cfg(target_pointer_width = "64")] { - fallback_to_other_impl!(msizex8, m64x8); - } else if #[cfg(target_pointer_width = "32")] { - fallback_to_other_impl!(msizex8, m32x8); - } else { - compile_error!("unsupported target_pointer_width"); - } - } - }; -} - -macro_rules! recurse_half { - ($vid:ident, $vid_h:ident) => { - impl All for $vid { - #[inline] - unsafe fn all(self) -> bool { - union U { - halves: ($vid_h, $vid_h), - vec: $vid, - } - let halves = U { vec: self }.halves; - halves.0.all() && halves.1.all() - } - } - impl Any for $vid { - #[inline] - unsafe fn any(self) -> bool { - union U { - halves: ($vid_h, $vid_h), - vec: $vid, - } - let halves = U { vec: self }.halves; - halves.0.any() || halves.1.any() - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/x86.rs deleted file mode 100644 index 4bf5098065..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86.rs +++ /dev/null @@ -1,216 +0,0 @@ -//! Mask reductions implementation for `x86` and `x86_64` targets - -#[cfg(target_feature = "sse")] -#[macro_use] -mod sse; - -#[cfg(target_feature = "sse2")] -#[macro_use] -mod sse2; - -#[cfg(target_feature = "avx")] -#[macro_use] -mod avx; - -#[cfg(target_feature = "avx2")] -#[macro_use] -mod avx2; - -/// x86 64-bit m8x8 implementation -macro_rules! x86_m8x8_impl { - ($id:ident) => { - fallback_impl!($id); - }; -} - -/// x86 128-bit m8x16 implementation -macro_rules! x86_m8x16_impl { - ($id:ident) => { - cfg_if! { - if #[cfg(target_feature = "sse2")] { - x86_m8x16_sse2_impl!($id); - } else { - fallback_impl!($id); - } - } - }; -} - -/// x86 128-bit m32x4 implementation -macro_rules! x86_m32x4_impl { - ($id:ident) => { - cfg_if! { - if #[cfg(target_feature = "sse")] { - x86_m32x4_sse_impl!($id); - } else { - fallback_impl!($id); - } - } - }; -} - -/// x86 128-bit m64x2 implementation -macro_rules! x86_m64x2_impl { - ($id:ident) => { - cfg_if! { - if #[cfg(target_feature = "sse2")] { - x86_m64x2_sse2_impl!($id); - } else if #[cfg(target_feature = "sse")] { - x86_m32x4_sse_impl!($id); - } else { - fallback_impl!($id); - } - } - }; -} - -/// x86 256-bit m8x32 implementation -macro_rules! x86_m8x32_impl { - ($id:ident, $half_id:ident) => { - cfg_if! { - if #[cfg(target_feature = "avx2")] { - x86_m8x32_avx2_impl!($id); - } else if #[cfg(target_feature = "avx")] { - x86_m8x32_avx_impl!($id); - } else if #[cfg(target_feature = "sse2")] { - recurse_half!($id, $half_id); - } else { - fallback_impl!($id); - } - } - }; -} - -/// x86 256-bit m32x8 implementation -macro_rules! x86_m32x8_impl { - ($id:ident, $half_id:ident) => { - cfg_if! { - if #[cfg(target_feature = "avx")] { - x86_m32x8_avx_impl!($id); - } else if #[cfg(target_feature = "sse")] { - recurse_half!($id, $half_id); - } else { - fallback_impl!($id); - } - } - }; -} - -/// x86 256-bit m64x4 implementation -macro_rules! x86_m64x4_impl { - ($id:ident, $half_id:ident) => { - cfg_if! { - if #[cfg(target_feature = "avx")] { - x86_m64x4_avx_impl!($id); - } else if #[cfg(target_feature = "sse")] { - recurse_half!($id, $half_id); - } else { - fallback_impl!($id); - } - } - }; -} - -/// Fallback implementation. -macro_rules! x86_intr_impl { - ($id:ident) => { - impl All for $id { - #[inline] - unsafe fn all(self) -> bool { - use crate::llvm::simd_reduce_all; - simd_reduce_all(self.0) - } - } - impl Any for $id { - #[inline] - unsafe fn any(self) -> bool { - use crate::llvm::simd_reduce_any; - simd_reduce_any(self.0) - } - } - }; -} - -/// Mask reduction implementation for `x86` and `x86_64` targets -macro_rules! impl_mask_reductions { - // 64-bit wide masks - (m8x8) => { - x86_m8x8_impl!(m8x8); - }; - (m16x4) => { - x86_m8x8_impl!(m16x4); - }; - (m32x2) => { - x86_m8x8_impl!(m32x2); - }; - // 128-bit wide masks - (m8x16) => { - x86_m8x16_impl!(m8x16); - }; - (m16x8) => { - x86_m8x16_impl!(m16x8); - }; - (m32x4) => { - x86_m32x4_impl!(m32x4); - }; - (m64x2) => { - x86_m64x2_impl!(m64x2); - }; - (m128x1) => { - x86_intr_impl!(m128x1); - }; - // 256-bit wide masks: - (m8x32) => { - x86_m8x32_impl!(m8x32, m8x16); - }; - (m16x16) => { - x86_m8x32_impl!(m16x16, m16x8); - }; - (m32x8) => { - x86_m32x8_impl!(m32x8, m32x4); - }; - (m64x4) => { - x86_m64x4_impl!(m64x4, m64x2); - }; - (m128x2) => { - x86_intr_impl!(m128x2); - }; - (msizex2) => { - cfg_if! { - if #[cfg(target_pointer_width = "64")] { - fallback_to_other_impl!(msizex2, m64x2); - } else if #[cfg(target_pointer_width = "32")] { - fallback_to_other_impl!(msizex2, m32x2); - } else { - compile_error!("unsupported target_pointer_width"); - } - } - }; - (msizex4) => { - cfg_if! { - if #[cfg(target_pointer_width = "64")] { - fallback_to_other_impl!(msizex4, m64x4); - } else if #[cfg(target_pointer_width = "32")] { - fallback_to_other_impl!(msizex4, m32x4); - } else { - compile_error!("unsupported target_pointer_width"); - } - } - }; - (msizex8) => { - cfg_if! { - if #[cfg(target_pointer_width = "64")] { - fallback_to_other_impl!(msizex8, m64x8); - } else if #[cfg(target_pointer_width = "32")] { - fallback_to_other_impl!(msizex8, m32x8); - } else { - compile_error!("unsupported target_pointer_width"); - } - } - }; - - // Fallback to LLVM's default code-generation: - ($id:ident) => { - fallback_impl!($id); - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx.rs deleted file mode 100644 index 61f352d228..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! Mask reductions implementation for `x86` and `x86_64` targets with `AVX` - -/// `x86`/`x86_64` 256-bit `AVX` implementation -/// FIXME: it might be faster here to do two `_mm_movmask_epi8` -#[cfg(target_feature = "avx")] -macro_rules! x86_m8x32_avx_impl { - ($id:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "avx")] - unsafe fn all(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_testc_si256; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_testc_si256; - _mm256_testc_si256(crate::mem::transmute(self), crate::mem::transmute($id::splat(true))) != 0 - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "avx")] - unsafe fn any(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_testz_si256; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_testz_si256; - _mm256_testz_si256(crate::mem::transmute(self), crate::mem::transmute(self)) == 0 - } - } - }; -} - -/// `x86`/`x86_64` 256-bit m32x8 `AVX` implementation -macro_rules! x86_m32x8_avx_impl { - ($id:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn all(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_movemask_ps; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_movemask_ps; - // _mm256_movemask_ps(a) creates a 8bit mask containing the - // most significant bit of each lane of `a`. If all bits are - // set, then all 8 lanes of the mask are true. - _mm256_movemask_ps(crate::mem::transmute(self)) == 0b_1111_1111_i32 - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn any(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_movemask_ps; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_movemask_ps; - - _mm256_movemask_ps(crate::mem::transmute(self)) != 0 - } - } - }; -} - -/// `x86`/`x86_64` 256-bit m64x4 `AVX` implementation -macro_rules! x86_m64x4_avx_impl { - ($id:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn all(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_movemask_pd; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_movemask_pd; - // _mm256_movemask_pd(a) creates a 4bit mask containing the - // most significant bit of each lane of `a`. If all bits are - // set, then all 4 lanes of the mask are true. - _mm256_movemask_pd(crate::mem::transmute(self)) == 0b_1111_i32 - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn any(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_movemask_pd; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_movemask_pd; - - _mm256_movemask_pd(crate::mem::transmute(self)) != 0 - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx2.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx2.rs deleted file mode 100644 index d37d023420..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/avx2.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Mask reductions implementation for `x86` and `x86_64` targets with `AVX2`. -#![allow(unused)] - -/// x86/x86_64 256-bit m8x32 AVX2 implementation -macro_rules! x86_m8x32_avx2_impl { - ($id:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "sse2")] - unsafe fn all(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_movemask_epi8; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_movemask_epi8; - // _mm256_movemask_epi8(a) creates a 32bit mask containing the - // most significant bit of each byte of `a`. If all - // bits are set, then all 32 lanes of the mask are - // true. - _mm256_movemask_epi8(crate::mem::transmute(self)) == -1_i32 - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "sse2")] - unsafe fn any(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm256_movemask_epi8; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm256_movemask_epi8; - - _mm256_movemask_epi8(crate::mem::transmute(self)) != 0 - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse.rs deleted file mode 100644 index e0c9aee92b..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Mask reductions implementation for `x86` and `x86_64` targets with `SSE`. -#![allow(unused)] - -/// `x86`/`x86_64` 128-bit `m32x4` `SSE` implementation -macro_rules! x86_m32x4_sse_impl { - ($id:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn all(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm_movemask_ps; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm_movemask_ps; - // _mm_movemask_ps(a) creates a 4bit mask containing the - // most significant bit of each lane of `a`. If all - // bits are set, then all 4 lanes of the mask are - // true. - _mm_movemask_ps(crate::mem::transmute(self)) == 0b_1111_i32 - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn any(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm_movemask_ps; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm_movemask_ps; - - _mm_movemask_ps(crate::mem::transmute(self)) != 0 - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse2.rs b/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse2.rs deleted file mode 100644 index bbb52fa47e..0000000000 --- a/third_party/rust/packed_simd/src/codegen/reductions/mask/x86/sse2.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Mask reductions implementation for `x86` and `x86_64` targets with `SSE2`. -#![allow(unused)] - -/// `x86`/`x86_64` 128-bit m64x2 `SSE2` implementation -macro_rules! x86_m64x2_sse2_impl { - ($id:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn all(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm_movemask_pd; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm_movemask_pd; - // _mm_movemask_pd(a) creates a 2bit mask containing the - // most significant bit of each lane of `a`. If all - // bits are set, then all 2 lanes of the mask are - // true. - _mm_movemask_pd(crate::mem::transmute(self)) == 0b_11_i32 - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "sse")] - unsafe fn any(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm_movemask_pd; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm_movemask_pd; - - _mm_movemask_pd(crate::mem::transmute(self)) != 0 - } - } - }; -} - -/// `x86`/`x86_64` 128-bit m8x16 `SSE2` implementation -macro_rules! x86_m8x16_sse2_impl { - ($id:ident) => { - impl All for $id { - #[inline] - #[target_feature(enable = "sse2")] - unsafe fn all(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm_movemask_epi8; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm_movemask_epi8; - // _mm_movemask_epi8(a) creates a 16bit mask containing the - // most significant bit of each byte of `a`. If all - // bits are set, then all 16 lanes of the mask are - // true. - _mm_movemask_epi8(crate::mem::transmute(self)) == i32::from(u16::max_value()) - } - } - impl Any for $id { - #[inline] - #[target_feature(enable = "sse2")] - unsafe fn any(self) -> bool { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm_movemask_epi8; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm_movemask_epi8; - - _mm_movemask_epi8(crate::mem::transmute(self)) != 0 - } - } - }; -} diff --git a/third_party/rust/packed_simd/src/codegen/shuffle.rs b/third_party/rust/packed_simd/src/codegen/shuffle.rs deleted file mode 100644 index d3acd48f5b..0000000000 --- a/third_party/rust/packed_simd/src/codegen/shuffle.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! Implementations of the `ShuffleResult` trait for the different numbers of -//! lanes and vector element types. - -use crate::masks::*; -use crate::sealed::{Seal, Shuffle}; - -macro_rules! impl_shuffle { - ($array:ty, $base:ty, $out:ty) => { - impl Seal<$array> for $base {} - impl Shuffle<$array> for $base { - type Output = $out; - } - }; -} - -impl_shuffle! { [u32; 2], i8, crate::codegen::i8x2 } -impl_shuffle! { [u32; 4], i8, crate::codegen::i8x4 } -impl_shuffle! { [u32; 8], i8, crate::codegen::i8x8 } -impl_shuffle! { [u32; 16], i8, crate::codegen::i8x16 } -impl_shuffle! { [u32; 32], i8, crate::codegen::i8x32 } -impl_shuffle! { [u32; 64], i8, crate::codegen::i8x64 } - -impl_shuffle! { [u32; 2], u8, crate::codegen::u8x2 } -impl_shuffle! { [u32; 4], u8, crate::codegen::u8x4 } -impl_shuffle! { [u32; 8], u8, crate::codegen::u8x8 } -impl_shuffle! { [u32; 16], u8, crate::codegen::u8x16 } -impl_shuffle! { [u32; 32], u8, crate::codegen::u8x32 } -impl_shuffle! { [u32; 64], u8, crate::codegen::u8x64 } - -impl_shuffle! { [u32; 2], m8, crate::codegen::m8x2 } -impl_shuffle! { [u32; 4], m8, crate::codegen::m8x4 } -impl_shuffle! { [u32; 8], m8, crate::codegen::m8x8 } -impl_shuffle! { [u32; 16], m8, crate::codegen::m8x16 } -impl_shuffle! { [u32; 32], m8, crate::codegen::m8x32 } -impl_shuffle! { [u32; 64], m8, crate::codegen::m8x64 } - -impl_shuffle! { [u32; 2], i16, crate::codegen::i16x2 } -impl_shuffle! { [u32; 4], i16, crate::codegen::i16x4 } -impl_shuffle! { [u32; 8], i16, crate::codegen::i16x8 } -impl_shuffle! { [u32; 16], i16, crate::codegen::i16x16 } -impl_shuffle! { [u32; 32], i16, crate::codegen::i16x32 } - -impl_shuffle! { [u32; 2], u16, crate::codegen::u16x2 } -impl_shuffle! { [u32; 4], u16, crate::codegen::u16x4 } -impl_shuffle! { [u32; 8], u16, crate::codegen::u16x8 } -impl_shuffle! { [u32; 16], u16, crate::codegen::u16x16 } -impl_shuffle! { [u32; 32], u16, crate::codegen::u16x32 } - -impl_shuffle! { [u32; 2], m16, crate::codegen::m16x2 } -impl_shuffle! { [u32; 4], m16, crate::codegen::m16x4 } -impl_shuffle! { [u32; 8], m16, crate::codegen::m16x8 } -impl_shuffle! { [u32; 16], m16, crate::codegen::m16x16 } - -impl_shuffle! { [u32; 2], i32, crate::codegen::i32x2 } -impl_shuffle! { [u32; 4], i32, crate::codegen::i32x4 } -impl_shuffle! { [u32; 8], i32, crate::codegen::i32x8 } -impl_shuffle! { [u32; 16], i32, crate::codegen::i32x16 } - -impl_shuffle! { [u32; 2], u32, crate::codegen::u32x2 } -impl_shuffle! { [u32; 4], u32, crate::codegen::u32x4 } -impl_shuffle! { [u32; 8], u32, crate::codegen::u32x8 } -impl_shuffle! { [u32; 16], u32, crate::codegen::u32x16 } - -impl_shuffle! { [u32; 2], f32, crate::codegen::f32x2 } -impl_shuffle! { [u32; 4], f32, crate::codegen::f32x4 } -impl_shuffle! { [u32; 8], f32, crate::codegen::f32x8 } -impl_shuffle! { [u32; 16], f32, crate::codegen::f32x16 } - -impl_shuffle! { [u32; 2], m32, crate::codegen::m32x2 } -impl_shuffle! { [u32; 4], m32, crate::codegen::m32x4 } -impl_shuffle! { [u32; 8], m32, crate::codegen::m32x8 } -impl_shuffle! { [u32; 16], m32, crate::codegen::m32x16 } - -/* FIXME: 64-bit single element vector -impl_shuffle! { [u32; 1], i64, crate::codegen::i64x1 } -*/ -impl_shuffle! { [u32; 2], i64, crate::codegen::i64x2 } -impl_shuffle! { [u32; 4], i64, crate::codegen::i64x4 } -impl_shuffle! { [u32; 8], i64, crate::codegen::i64x8 } - -/* FIXME: 64-bit single element vector -impl_shuffle! { [u32; 1], i64, crate::codegen::i64x1 } -*/ -impl_shuffle! { [u32; 2], u64, crate::codegen::u64x2 } -impl_shuffle! { [u32; 4], u64, crate::codegen::u64x4 } -impl_shuffle! { [u32; 8], u64, crate::codegen::u64x8 } - -/* FIXME: 64-bit single element vector -impl_shuffle! { [u32; 1], i64, crate::codegen::i64x1 } -*/ -impl_shuffle! { [u32; 2], f64, crate::codegen::f64x2 } -impl_shuffle! { [u32; 4], f64, crate::codegen::f64x4 } -impl_shuffle! { [u32; 8], f64, crate::codegen::f64x8 } - -/* FIXME: 64-bit single element vector -impl_shuffle! { [u32; 1], i64, crate::codegen::i64x1 } -*/ -impl_shuffle! { [u32; 2], m64, crate::codegen::m64x2 } -impl_shuffle! { [u32; 4], m64, crate::codegen::m64x4 } -impl_shuffle! { [u32; 8], m64, crate::codegen::m64x8 } - -impl_shuffle! { [u32; 2], isize, crate::codegen::isizex2 } -impl_shuffle! { [u32; 4], isize, crate::codegen::isizex4 } -impl_shuffle! { [u32; 8], isize, crate::codegen::isizex8 } - -impl_shuffle! { [u32; 2], usize, crate::codegen::usizex2 } -impl_shuffle! { [u32; 4], usize, crate::codegen::usizex4 } -impl_shuffle! { [u32; 8], usize, crate::codegen::usizex8 } - -impl_shuffle! { [u32; 2], msize, crate::codegen::msizex2 } -impl_shuffle! { [u32; 4], msize, crate::codegen::msizex4 } -impl_shuffle! { [u32; 8], msize, crate::codegen::msizex8 } - -impl Seal<[u32; 2]> for *const T {} -impl Shuffle<[u32; 2]> for *const T { - type Output = crate::codegen::cptrx2; -} -impl Seal<[u32; 4]> for *const T {} -impl Shuffle<[u32; 4]> for *const T { - type Output = crate::codegen::cptrx4; -} -impl Seal<[u32; 8]> for *const T {} -impl Shuffle<[u32; 8]> for *const T { - type Output = crate::codegen::cptrx8; -} - -impl Seal<[u32; 2]> for *mut T {} -impl Shuffle<[u32; 2]> for *mut T { - type Output = crate::codegen::mptrx2; -} -impl Seal<[u32; 4]> for *mut T {} -impl Shuffle<[u32; 4]> for *mut T { - type Output = crate::codegen::mptrx4; -} -impl Seal<[u32; 8]> for *mut T {} -impl Shuffle<[u32; 8]> for *mut T { - type Output = crate::codegen::mptrx8; -} - -impl_shuffle! { [u32; 1], i128, crate::codegen::i128x1 } -impl_shuffle! { [u32; 2], i128, crate::codegen::i128x2 } -impl_shuffle! { [u32; 4], i128, crate::codegen::i128x4 } - -impl_shuffle! { [u32; 1], u128, crate::codegen::u128x1 } -impl_shuffle! { [u32; 2], u128, crate::codegen::u128x2 } -impl_shuffle! { [u32; 4], u128, crate::codegen::u128x4 } - -impl_shuffle! { [u32; 1], m128, crate::codegen::m128x1 } -impl_shuffle! { [u32; 2], m128, crate::codegen::m128x2 } -impl_shuffle! { [u32; 4], m128, crate::codegen::m128x4 } diff --git a/third_party/rust/packed_simd/src/codegen/shuffle1_dyn.rs b/third_party/rust/packed_simd/src/codegen/shuffle1_dyn.rs deleted file mode 100644 index 19d457a45b..0000000000 --- a/third_party/rust/packed_simd/src/codegen/shuffle1_dyn.rs +++ /dev/null @@ -1,408 +0,0 @@ -//! Shuffle vector lanes with run-time indices. - -use crate::*; - -pub trait Shuffle1Dyn { - type Indices; - fn shuffle1_dyn(self, _: Self::Indices) -> Self; -} - -// Fallback implementation -macro_rules! impl_fallback { - ($id:ident) => { - impl Shuffle1Dyn for $id { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - let mut result = Self::splat(0); - for i in 0..$id::lanes() { - result = result.replace(i, self.extract(indices.extract(i) as usize)); - } - result - } - } - }; -} - -macro_rules! impl_shuffle1_dyn { - (u8x8) => { - cfg_if! { - if #[cfg(all( - any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "doesnotexist", target_feature = "v7", - target_feature = "neon") - ), - any(feature = "core_arch", libcore_neon) - ) - )] { - impl Shuffle1Dyn for u8x8 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - #[cfg(target_arch = "aarch64")] - use crate::arch::aarch64::vtbl1_u8; - #[cfg(target_arch = "doesnotexist")] - use crate::arch::arm::vtbl1_u8; - - // This is safe because the binary is compiled with - // neon enabled at compile-time and can therefore only - // run on CPUs that have it enabled. - unsafe { - Simd(mem::transmute( - vtbl1_u8(mem::transmute(self.0), - crate::mem::transmute(indices.0)) - )) - } - } - } - } else { - impl_fallback!(u8x8); - } - } - }; - (u8x16) => { - cfg_if! { - if #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), - target_feature = "ssse3"))] { - impl Shuffle1Dyn for u8x16 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - #[cfg(target_arch = "x86")] - use crate::arch::x86::_mm_shuffle_epi8; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::_mm_shuffle_epi8; - // This is safe because the binary is compiled with - // ssse3 enabled at compile-time and can therefore only - // run on CPUs that have it enabled. - unsafe { - Simd(mem::transmute( - _mm_shuffle_epi8(mem::transmute(self.0), - crate::mem::transmute(indices)) - )) - } - } - } - } else if #[cfg(all(target_arch = "aarch64", target_feature = "neon", - any(feature = "core_arch", libcore_neon)))] { - impl Shuffle1Dyn for u8x16 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - use crate::arch::aarch64::vqtbl1q_u8; - - // This is safe because the binary is compiled with - // neon enabled at compile-time and can therefore only - // run on CPUs that have it enabled. - unsafe { - Simd(mem::transmute( - vqtbl1q_u8(mem::transmute(self.0), - crate::mem::transmute(indices.0)) - )) - } - } - } - } else if #[cfg(all(target_arch = "doesnotexist", target_feature = "v7", - target_feature = "neon", - any(feature = "core_arch", libcore_neon)))] { - impl Shuffle1Dyn for u8x16 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - use crate::arch::arm::vtbl2_u8; - - // This is safe because the binary is compiled with - // neon enabled at compile-time and can therefore only - // run on CPUs that have it enabled. - unsafe { - union U { - j: u8x16, - s: (u8x8, u8x8), - } - - let (i0, i1) = U { j: y }.s; - - let r0 = vtbl2_u8( - mem::transmute(x), - crate::mem::transmute(i0) - ); - let r1 = vtbl2_u8( - mem::transmute(x), - crate::mem::transmute(i1) - ); - - let r = U { s: (r0, r1) }.j; - - Simd(mem::transmute(r)) - } - } - } - } else { - impl_fallback!(u8x16); - } - } - }; - (u16x8) => { - impl Shuffle1Dyn for u16x8 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - let indices: u8x8 = (indices * 2).cast(); - let indices: u8x16 = shuffle!(indices, [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7]); - let v = u8x16::new(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1); - let indices = indices + v; - unsafe { - let s: u8x16 = crate::mem::transmute(self); - crate::mem::transmute(s.shuffle1_dyn(indices)) - } - } - } - }; - (u32x4) => { - cfg_if! { - if #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), - target_feature = "avx"))] { - impl Shuffle1Dyn for u32x4 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - #[cfg(target_arch = "x86")] - use crate::arch::x86::{_mm_permutevar_ps}; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::{_mm_permutevar_ps}; - - unsafe { - crate::mem::transmute( - _mm_permutevar_ps( - crate::mem::transmute(self.0), - crate::mem::transmute(indices.0) - ) - ) - } - } - } - } else { - impl Shuffle1Dyn for u32x4 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - let indices: u8x4 = (indices * 4).cast(); - let indices: u8x16 = shuffle!( - indices, - [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3] - ); - let v = u8x16::new( - 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 - ); - let indices = indices + v; - unsafe { - let s: u8x16 =crate::mem::transmute(self); - crate::mem::transmute(s.shuffle1_dyn(indices)) - } - } - } - } - } - }; - (u64x2) => { - cfg_if! { - if #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), - target_feature = "avx"))] { - impl Shuffle1Dyn for u64x2 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - #[cfg(target_arch = "x86")] - use crate::arch::x86::{_mm_permutevar_pd}; - #[cfg(target_arch = "x86_64")] - use crate::arch::x86_64::{_mm_permutevar_pd}; - // _mm_permutevar_pd uses the _second_ bit of each - // element to perform the selection, that is: 0b00 => 0, - // 0b10 => 1: - let indices = indices << 1; - unsafe { - crate::mem::transmute( - _mm_permutevar_pd( - crate::mem::transmute(self), - crate::mem::transmute(indices) - ) - ) - } - } - } - } else { - impl Shuffle1Dyn for u64x2 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - let indices: u8x2 = (indices * 8).cast(); - let indices: u8x16 = shuffle!( - indices, - [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1] - ); - let v = u8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7 - ); - let indices = indices + v; - unsafe { - let s: u8x16 =crate::mem::transmute(self); - crate::mem::transmute(s.shuffle1_dyn(indices)) - } - } - } - } - } - }; - (u128x1) => { - impl Shuffle1Dyn for u128x1 { - type Indices = Self; - #[inline] - fn shuffle1_dyn(self, _indices: Self::Indices) -> Self { - self - } - } - }; - ($id:ident) => { - impl_fallback!($id); - }; -} - -impl_shuffle1_dyn!(u8x2); -impl_shuffle1_dyn!(u8x4); -impl_shuffle1_dyn!(u8x8); -impl_shuffle1_dyn!(u8x16); -impl_shuffle1_dyn!(u8x32); -impl_shuffle1_dyn!(u8x64); - -impl_shuffle1_dyn!(u16x2); -impl_shuffle1_dyn!(u16x4); -impl_shuffle1_dyn!(u16x8); -impl_shuffle1_dyn!(u16x16); -impl_shuffle1_dyn!(u16x32); - -impl_shuffle1_dyn!(u32x2); -impl_shuffle1_dyn!(u32x4); -impl_shuffle1_dyn!(u32x8); -impl_shuffle1_dyn!(u32x16); - -impl_shuffle1_dyn!(u64x2); -impl_shuffle1_dyn!(u64x4); -impl_shuffle1_dyn!(u64x8); - -impl_shuffle1_dyn!(usizex2); -impl_shuffle1_dyn!(usizex4); -impl_shuffle1_dyn!(usizex8); - -impl_shuffle1_dyn!(u128x1); -impl_shuffle1_dyn!(u128x2); -impl_shuffle1_dyn!(u128x4); - -// Implementation for non-unsigned vector types -macro_rules! impl_shuffle1_dyn_non_u { - ($id:ident, $uid:ident) => { - impl Shuffle1Dyn for $id { - type Indices = $uid; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - unsafe { - let u: $uid = crate::mem::transmute(self); - crate::mem::transmute(u.shuffle1_dyn(indices)) - } - } - } - }; -} - -impl_shuffle1_dyn_non_u!(i8x2, u8x2); -impl_shuffle1_dyn_non_u!(i8x4, u8x4); -impl_shuffle1_dyn_non_u!(i8x8, u8x8); -impl_shuffle1_dyn_non_u!(i8x16, u8x16); -impl_shuffle1_dyn_non_u!(i8x32, u8x32); -impl_shuffle1_dyn_non_u!(i8x64, u8x64); - -impl_shuffle1_dyn_non_u!(i16x2, u16x2); -impl_shuffle1_dyn_non_u!(i16x4, u16x4); -impl_shuffle1_dyn_non_u!(i16x8, u16x8); -impl_shuffle1_dyn_non_u!(i16x16, u16x16); -impl_shuffle1_dyn_non_u!(i16x32, u16x32); - -impl_shuffle1_dyn_non_u!(i32x2, u32x2); -impl_shuffle1_dyn_non_u!(i32x4, u32x4); -impl_shuffle1_dyn_non_u!(i32x8, u32x8); -impl_shuffle1_dyn_non_u!(i32x16, u32x16); - -impl_shuffle1_dyn_non_u!(i64x2, u64x2); -impl_shuffle1_dyn_non_u!(i64x4, u64x4); -impl_shuffle1_dyn_non_u!(i64x8, u64x8); - -impl_shuffle1_dyn_non_u!(isizex2, usizex2); -impl_shuffle1_dyn_non_u!(isizex4, usizex4); -impl_shuffle1_dyn_non_u!(isizex8, usizex8); - -impl_shuffle1_dyn_non_u!(i128x1, u128x1); -impl_shuffle1_dyn_non_u!(i128x2, u128x2); -impl_shuffle1_dyn_non_u!(i128x4, u128x4); - -impl_shuffle1_dyn_non_u!(m8x2, u8x2); -impl_shuffle1_dyn_non_u!(m8x4, u8x4); -impl_shuffle1_dyn_non_u!(m8x8, u8x8); -impl_shuffle1_dyn_non_u!(m8x16, u8x16); -impl_shuffle1_dyn_non_u!(m8x32, u8x32); -impl_shuffle1_dyn_non_u!(m8x64, u8x64); - -impl_shuffle1_dyn_non_u!(m16x2, u16x2); -impl_shuffle1_dyn_non_u!(m16x4, u16x4); -impl_shuffle1_dyn_non_u!(m16x8, u16x8); -impl_shuffle1_dyn_non_u!(m16x16, u16x16); -impl_shuffle1_dyn_non_u!(m16x32, u16x32); - -impl_shuffle1_dyn_non_u!(m32x2, u32x2); -impl_shuffle1_dyn_non_u!(m32x4, u32x4); -impl_shuffle1_dyn_non_u!(m32x8, u32x8); -impl_shuffle1_dyn_non_u!(m32x16, u32x16); - -impl_shuffle1_dyn_non_u!(m64x2, u64x2); -impl_shuffle1_dyn_non_u!(m64x4, u64x4); -impl_shuffle1_dyn_non_u!(m64x8, u64x8); - -impl_shuffle1_dyn_non_u!(msizex2, usizex2); -impl_shuffle1_dyn_non_u!(msizex4, usizex4); -impl_shuffle1_dyn_non_u!(msizex8, usizex8); - -impl_shuffle1_dyn_non_u!(m128x1, u128x1); -impl_shuffle1_dyn_non_u!(m128x2, u128x2); -impl_shuffle1_dyn_non_u!(m128x4, u128x4); - -impl_shuffle1_dyn_non_u!(f32x2, u32x2); -impl_shuffle1_dyn_non_u!(f32x4, u32x4); -impl_shuffle1_dyn_non_u!(f32x8, u32x8); -impl_shuffle1_dyn_non_u!(f32x16, u32x16); - -impl_shuffle1_dyn_non_u!(f64x2, u64x2); -impl_shuffle1_dyn_non_u!(f64x4, u64x4); -impl_shuffle1_dyn_non_u!(f64x8, u64x8); - -// Implementation for non-unsigned vector types -macro_rules! impl_shuffle1_dyn_ptr { - ($id:ident, $uid:ident) => { - impl Shuffle1Dyn for $id { - type Indices = $uid; - #[inline] - fn shuffle1_dyn(self, indices: Self::Indices) -> Self { - unsafe { - let u: $uid = crate::mem::transmute(self); - crate::mem::transmute(u.shuffle1_dyn(indices)) - } - } - } - }; -} - -impl_shuffle1_dyn_ptr!(cptrx2, usizex2); -impl_shuffle1_dyn_ptr!(cptrx4, usizex4); -impl_shuffle1_dyn_ptr!(cptrx8, usizex8); - -impl_shuffle1_dyn_ptr!(mptrx2, usizex2); -impl_shuffle1_dyn_ptr!(mptrx4, usizex4); -impl_shuffle1_dyn_ptr!(mptrx8, usizex8); diff --git a/third_party/rust/packed_simd/src/codegen/swap_bytes.rs b/third_party/rust/packed_simd/src/codegen/swap_bytes.rs deleted file mode 100644 index 9cf34a3e04..0000000000 --- a/third_party/rust/packed_simd/src/codegen/swap_bytes.rs +++ /dev/null @@ -1,149 +0,0 @@ -//! Horizontal swap bytes reductions. - -// FIXME: investigate using `llvm.bswap` -// https://github.com/rust-lang-nursery/packed_simd/issues/19 - -use crate::*; - -pub(crate) trait SwapBytes { - fn swap_bytes(self) -> Self; -} - -macro_rules! impl_swap_bytes { - (v16: $($id:ident,)+) => { - $( - impl SwapBytes for $id { - #[inline] - fn swap_bytes(self) -> Self { - shuffle!(self, [1, 0]) - } - } - )+ - }; - (v32: $($id:ident,)+) => { - $( - impl SwapBytes for $id { - #[inline] - #[allow(clippy::useless_transmute)] - fn swap_bytes(self) -> Self { - unsafe { - let bytes: u8x4 = crate::mem::transmute(self); - let result: u8x4 = shuffle!(bytes, [3, 2, 1, 0]); - crate::mem::transmute(result) - } - } - } - )+ - }; - (v64: $($id:ident,)+) => { - $( - impl SwapBytes for $id { - #[inline] - #[allow(clippy::useless_transmute)] - fn swap_bytes(self) -> Self { - unsafe { - let bytes: u8x8 = crate::mem::transmute(self); - let result: u8x8 = shuffle!( - bytes, [7, 6, 5, 4, 3, 2, 1, 0] - ); - crate::mem::transmute(result) - } - } - } - )+ - }; - (v128: $($id:ident,)+) => { - $( - impl SwapBytes for $id { - #[inline] - #[allow(clippy::useless_transmute)] - fn swap_bytes(self) -> Self { - unsafe { - let bytes: u8x16 = crate::mem::transmute(self); - let result: u8x16 = shuffle!(bytes, [ - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - ]); - crate::mem::transmute(result) - } - } - } - )+ - }; - (v256: $($id:ident,)+) => { - $( - impl SwapBytes for $id { - #[inline] - #[allow(clippy::useless_transmute)] - fn swap_bytes(self) -> Self { - unsafe { - let bytes: u8x32 = crate::mem::transmute(self); - let result: u8x32 = shuffle!(bytes, [ - 31, 30, 29, 28, 27, 26, 25, 24, - 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - ]); - crate::mem::transmute(result) - } - } - } - )+ - }; - (v512: $($id:ident,)+) => { - $( - impl SwapBytes for $id { - #[inline] - #[allow(clippy::useless_transmute)] - fn swap_bytes(self) -> Self { - unsafe { - let bytes: u8x64 = crate::mem::transmute(self); - let result: u8x64 = shuffle!(bytes, [ - 63, 62, 61, 60, 59, 58, 57, 56, - 55, 54, 53, 52, 51, 50, 49, 48, - 47, 46, 45, 44, 43, 42, 41, 40, - 39, 38, 37, 36, 35, 34, 33, 32, - 31, 30, 29, 28, 27, 26, 25, 24, - 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - ]); - crate::mem::transmute(result) - } - } - } - )+ - }; -} - -impl_swap_bytes!(v16: u8x2, i8x2,); -impl_swap_bytes!(v32: u8x4, i8x4, u16x2, i16x2,); -// FIXME: 64-bit single element vector -impl_swap_bytes!(v64: u8x8, i8x8, u16x4, i16x4, u32x2, i32x2 /* u64x1, i64x1, */,); - -impl_swap_bytes!(v128: u8x16, i8x16, u16x8, i16x8, u32x4, i32x4, u64x2, i64x2, u128x1, i128x1,); -impl_swap_bytes!(v256: u8x32, i8x32, u16x16, i16x16, u32x8, i32x8, u64x4, i64x4, u128x2, i128x2,); - -impl_swap_bytes!(v512: u8x64, i8x64, u16x32, i16x32, u32x16, i32x16, u64x8, i64x8, u128x4, i128x4,); - -cfg_if! { - if #[cfg(target_pointer_width = "8")] { - impl_swap_bytes!(v16: isizex2, usizex2,); - impl_swap_bytes!(v32: isizex4, usizex4,); - impl_swap_bytes!(v64: isizex8, usizex8,); - } else if #[cfg(target_pointer_width = "16")] { - impl_swap_bytes!(v32: isizex2, usizex2,); - impl_swap_bytes!(v64: isizex4, usizex4,); - impl_swap_bytes!(v128: isizex8, usizex8,); - } else if #[cfg(target_pointer_width = "32")] { - impl_swap_bytes!(v64: isizex2, usizex2,); - impl_swap_bytes!(v128: isizex4, usizex4,); - impl_swap_bytes!(v256: isizex8, usizex8,); - } else if #[cfg(target_pointer_width = "64")] { - impl_swap_bytes!(v128: isizex2, usizex2,); - impl_swap_bytes!(v256: isizex4, usizex4,); - impl_swap_bytes!(v512: isizex8, usizex8,); - } else { - compile_error!("unsupported target_pointer_width"); - } -} diff --git a/third_party/rust/packed_simd/src/codegen/v128.rs b/third_party/rust/packed_simd/src/codegen/v128.rs deleted file mode 100644 index 9506424fad..0000000000 --- a/third_party/rust/packed_simd/src/codegen/v128.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! Internal 128-bit wide vector types - -use crate::masks::*; - -#[rustfmt::skip] -impl_simd_array!( - [i8; 16]: i8x16 | - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8 -); -#[rustfmt::skip] -impl_simd_array!( - [u8; 16]: u8x16 | - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8 -); -#[rustfmt::skip] -impl_simd_array!( - [m8; 16]: m8x16 | - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8 -); - -impl_simd_array!([i16; 8]: i16x8 | i16, i16, i16, i16, i16, i16, i16, i16); -impl_simd_array!([u16; 8]: u16x8 | u16, u16, u16, u16, u16, u16, u16, u16); -impl_simd_array!([m16; 8]: m16x8 | i16, i16, i16, i16, i16, i16, i16, i16); - -impl_simd_array!([i32; 4]: i32x4 | i32, i32, i32, i32); -impl_simd_array!([u32; 4]: u32x4 | u32, u32, u32, u32); -impl_simd_array!([f32; 4]: f32x4 | f32, f32, f32, f32); -impl_simd_array!([m32; 4]: m32x4 | i32, i32, i32, i32); - -impl_simd_array!([i64; 2]: i64x2 | i64, i64); -impl_simd_array!([u64; 2]: u64x2 | u64, u64); -impl_simd_array!([f64; 2]: f64x2 | f64, f64); -impl_simd_array!([m64; 2]: m64x2 | i64, i64); - -impl_simd_array!([i128; 1]: i128x1 | i128); -impl_simd_array!([u128; 1]: u128x1 | u128); -impl_simd_array!([m128; 1]: m128x1 | i128); diff --git a/third_party/rust/packed_simd/src/codegen/v16.rs b/third_party/rust/packed_simd/src/codegen/v16.rs deleted file mode 100644 index 4d55a6d899..0000000000 --- a/third_party/rust/packed_simd/src/codegen/v16.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Internal 16-bit wide vector types - -use crate::masks::*; - -impl_simd_array!([i8; 2]: i8x2 | i8, i8); -impl_simd_array!([u8; 2]: u8x2 | u8, u8); -impl_simd_array!([m8; 2]: m8x2 | i8, i8); diff --git a/third_party/rust/packed_simd/src/codegen/v256.rs b/third_party/rust/packed_simd/src/codegen/v256.rs deleted file mode 100644 index 5ca4759f0c..0000000000 --- a/third_party/rust/packed_simd/src/codegen/v256.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Internal 256-bit wide vector types - -use crate::masks::*; - -#[rustfmt::skip] -impl_simd_array!( - [i8; 32]: i8x32 | - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8 -); -#[rustfmt::skip] -impl_simd_array!( - [u8; 32]: u8x32 | - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8 -); -#[rustfmt::skip] -impl_simd_array!( - [m8; 32]: m8x32 | - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8 -); -#[rustfmt::skip] -impl_simd_array!( - [i16; 16]: i16x16 | - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16 -); -#[rustfmt::skip] -impl_simd_array!( - [u16; 16]: u16x16 | - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16 -); -#[rustfmt::skip] -impl_simd_array!( - [m16; 16]: m16x16 | - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16 -); - -impl_simd_array!([i32; 8]: i32x8 | i32, i32, i32, i32, i32, i32, i32, i32); -impl_simd_array!([u32; 8]: u32x8 | u32, u32, u32, u32, u32, u32, u32, u32); -impl_simd_array!([f32; 8]: f32x8 | f32, f32, f32, f32, f32, f32, f32, f32); -impl_simd_array!([m32; 8]: m32x8 | i32, i32, i32, i32, i32, i32, i32, i32); - -impl_simd_array!([i64; 4]: i64x4 | i64, i64, i64, i64); -impl_simd_array!([u64; 4]: u64x4 | u64, u64, u64, u64); -impl_simd_array!([f64; 4]: f64x4 | f64, f64, f64, f64); -impl_simd_array!([m64; 4]: m64x4 | i64, i64, i64, i64); - -impl_simd_array!([i128; 2]: i128x2 | i128, i128); -impl_simd_array!([u128; 2]: u128x2 | u128, u128); -impl_simd_array!([m128; 2]: m128x2 | i128, i128); diff --git a/third_party/rust/packed_simd/src/codegen/v32.rs b/third_party/rust/packed_simd/src/codegen/v32.rs deleted file mode 100644 index ae1dabd00c..0000000000 --- a/third_party/rust/packed_simd/src/codegen/v32.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Internal 32-bit wide vector types - -use crate::masks::*; - -impl_simd_array!([i8; 4]: i8x4 | i8, i8, i8, i8); -impl_simd_array!([u8; 4]: u8x4 | u8, u8, u8, u8); -impl_simd_array!([m8; 4]: m8x4 | i8, i8, i8, i8); - -impl_simd_array!([i16; 2]: i16x2 | i16, i16); -impl_simd_array!([u16; 2]: u16x2 | u16, u16); -impl_simd_array!([m16; 2]: m16x2 | i16, i16); diff --git a/third_party/rust/packed_simd/src/codegen/v512.rs b/third_party/rust/packed_simd/src/codegen/v512.rs deleted file mode 100644 index bf95110340..0000000000 --- a/third_party/rust/packed_simd/src/codegen/v512.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! Internal 512-bit wide vector types - -use crate::masks::*; - -#[rustfmt::skip] -impl_simd_array!( - [i8; 64]: i8x64 | - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8 -); -#[rustfmt::skip] -impl_simd_array!( - [u8; 64]: u8x64 | - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8, - u8, u8, u8, u8 -); -#[rustfmt::skip] -impl_simd_array!( - [m8; 64]: m8x64 | - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8, - i8, i8, i8, i8 -); -#[rustfmt::skip] -impl_simd_array!( - [i16; 32]: i16x32 | - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16 -); -#[rustfmt::skip] -impl_simd_array!( - [u16; 32]: u16x32 | - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16, - u16, u16, u16, u16 -); -#[rustfmt::skip] -impl_simd_array!( - [m16; 32]: m16x32 | - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16, - i16, i16, i16, i16 -); - -#[rustfmt::skip] -impl_simd_array!( - [i32; 16]: i32x16 | - i32, i32, i32, i32, - i32, i32, i32, i32, - i32, i32, i32, i32, - i32, i32, i32, i32 -); -#[rustfmt::skip] -impl_simd_array!( - [u32; 16]: u32x16 | - u32, u32, u32, u32, - u32, u32, u32, u32, - u32, u32, u32, u32, - u32, u32, u32, u32 -); -#[rustfmt::skip] -impl_simd_array!( - [f32; 16]: f32x16 | - f32, f32, f32, f32, - f32, f32, f32, f32, - f32, f32, f32, f32, - f32, f32, f32, f32 -); -#[rustfmt::skip] -impl_simd_array!( - [m32; 16]: m32x16 | - i32, i32, i32, i32, - i32, i32, i32, i32, - i32, i32, i32, i32, - i32, i32, i32, i32 -); - -impl_simd_array!([i64; 8]: i64x8 | i64, i64, i64, i64, i64, i64, i64, i64); -impl_simd_array!([u64; 8]: u64x8 | u64, u64, u64, u64, u64, u64, u64, u64); -impl_simd_array!([f64; 8]: f64x8 | f64, f64, f64, f64, f64, f64, f64, f64); -impl_simd_array!([m64; 8]: m64x8 | i64, i64, i64, i64, i64, i64, i64, i64); - -impl_simd_array!([i128; 4]: i128x4 | i128, i128, i128, i128); -impl_simd_array!([u128; 4]: u128x4 | u128, u128, u128, u128); -impl_simd_array!([m128; 4]: m128x4 | i128, i128, i128, i128); diff --git a/third_party/rust/packed_simd/src/codegen/v64.rs b/third_party/rust/packed_simd/src/codegen/v64.rs deleted file mode 100644 index 3cfb67c1a0..0000000000 --- a/third_party/rust/packed_simd/src/codegen/v64.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Internal 64-bit wide vector types - -use crate::masks::*; - -impl_simd_array!([i8; 8]: i8x8 | i8, i8, i8, i8, i8, i8, i8, i8); -impl_simd_array!([u8; 8]: u8x8 | u8, u8, u8, u8, u8, u8, u8, u8); -impl_simd_array!([m8; 8]: m8x8 | i8, i8, i8, i8, i8, i8, i8, i8); - -impl_simd_array!([i16; 4]: i16x4 | i16, i16, i16, i16); -impl_simd_array!([u16; 4]: u16x4 | u16, u16, u16, u16); -impl_simd_array!([m16; 4]: m16x4 | i16, i16, i16, i16); - -impl_simd_array!([i32; 2]: i32x2 | i32, i32); -impl_simd_array!([u32; 2]: u32x2 | u32, u32); -impl_simd_array!([f32; 2]: f32x2 | f32, f32); -impl_simd_array!([m32; 2]: m32x2 | i32, i32); - -impl_simd_array!([i64; 1]: i64x1 | i64); -impl_simd_array!([u64; 1]: u64x1 | u64); -impl_simd_array!([f64; 1]: f64x1 | f64); -impl_simd_array!([m64; 1]: m64x1 | i64); diff --git a/third_party/rust/packed_simd/src/codegen/vPtr.rs b/third_party/rust/packed_simd/src/codegen/vPtr.rs deleted file mode 100644 index abd3aa8779..0000000000 --- a/third_party/rust/packed_simd/src/codegen/vPtr.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Pointer vector types - -macro_rules! impl_simd_ptr { - ([$ptr_ty:ty; $elem_count:expr]: $tuple_id:ident | $ty:ident - | $($tys:ty),*) => { - #[derive(Copy, Clone)] - #[repr(simd)] - pub struct $tuple_id<$ty>($(pub(crate) $tys),*); - //^^^^^^^ leaked through SimdArray - - impl<$ty> crate::sealed::Seal for [$ptr_ty; $elem_count] {} - impl<$ty> crate::sealed::SimdArray for [$ptr_ty; $elem_count] { - type Tuple = $tuple_id<$ptr_ty>; - type T = $ptr_ty; - const N: usize = $elem_count; - type NT = [u32; $elem_count]; - } - - impl<$ty> crate::sealed::Seal for $tuple_id<$ptr_ty> {} - impl<$ty> crate::sealed::Simd for $tuple_id<$ptr_ty> { - type Element = $ptr_ty; - const LANES: usize = $elem_count; - type LanesType = [u32; $elem_count]; - } - - } -} - -impl_simd_ptr!([*const T; 2]: cptrx2 | T | T, T); -impl_simd_ptr!([*const T; 4]: cptrx4 | T | T, T, T, T); -impl_simd_ptr!([*const T; 8]: cptrx8 | T | T, T, T, T, T, T, T, T); - -impl_simd_ptr!([*mut T; 2]: mptrx2 | T | T, T); -impl_simd_ptr!([*mut T; 4]: mptrx4 | T | T, T, T, T); -impl_simd_ptr!([*mut T; 8]: mptrx8 | T | T, T, T, T, T, T, T, T); diff --git a/third_party/rust/packed_simd/src/codegen/vSize.rs b/third_party/rust/packed_simd/src/codegen/vSize.rs deleted file mode 100644 index d5db03991d..0000000000 --- a/third_party/rust/packed_simd/src/codegen/vSize.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Vector types with pointer-sized elements - -use crate::codegen::pointer_sized_int::{isize_, usize_}; -use crate::masks::*; - -impl_simd_array!([isize; 2]: isizex2 | isize_, isize_); -impl_simd_array!([usize; 2]: usizex2 | usize_, usize_); -impl_simd_array!([msize; 2]: msizex2 | isize_, isize_); - -impl_simd_array!([isize; 4]: isizex4 | isize_, isize_, isize_, isize_); -impl_simd_array!([usize; 4]: usizex4 | usize_, usize_, usize_, usize_); -impl_simd_array!([msize; 4]: msizex4 | isize_, isize_, isize_, isize_); - -impl_simd_array!([isize; 8]: isizex8 | isize_, isize_, isize_, isize_, isize_, isize_, isize_, isize_); -impl_simd_array!([usize; 8]: usizex8 | usize_, usize_, usize_, usize_, usize_, usize_, usize_, usize_); -impl_simd_array!([msize; 8]: msizex8 | isize_, isize_, isize_, isize_, isize_, isize_, isize_, isize_); diff --git a/third_party/rust/packed_simd/src/lib.rs b/third_party/rust/packed_simd/src/lib.rs deleted file mode 100644 index 867cc10e9e..0000000000 --- a/third_party/rust/packed_simd/src/lib.rs +++ /dev/null @@ -1,348 +0,0 @@ -//! # Portable packed SIMD vectors -//! -//! This crate is proposed for stabilization as `std::packed_simd` in [RFC2366: -//! `std::simd`](https://github.com/rust-lang/rfcs/pull/2366) . -//! -//! The examples available in the -//! [`examples/`](https://github.com/rust-lang-nursery/packed_simd/tree/master/examples) -//! sub-directory of the crate showcase how to use the library in practice. -//! -//! ## Table of contents -//! -//! - [Introduction](#introduction) -//! - [Vector types](#vector-types) -//! - [Conditional operations](#conditional-operations) -//! - [Conversions](#conversions) -//! - [Hardware Features](#hardware-features) -//! - [Performance guide](https://rust-lang-nursery.github.io/packed_simd/perf-guide/) -//! -//! ## Introduction -//! -//! This crate exports [`Simd<[T; N]>`][`Simd`]: a packed vector of `N` -//! elements of type `T` as well as many type aliases for this type: for -//! example, [`f32x4`], which is just an alias for `Simd<[f32; 4]>`. -//! -//! The operations on packed vectors are, by default, "vertical", that is, they -//! are applied to each vector lane in isolation of the others: -//! -//! ``` -//! # use packed_simd::*; -//! let a = i32x4::new(1, 2, 3, 4); -//! let b = i32x4::new(5, 6, 7, 8); -//! assert_eq!(a + b, i32x4::new(6, 8, 10, 12)); -//! ``` -//! -//! Many "horizontal" operations are also provided: -//! -//! ``` -//! # use packed_simd::*; -//! # let a = i32x4::new(1, 2, 3, 4); -//! assert_eq!(a.wrapping_sum(), 10); -//! ``` -//! -//! In virtually all architectures vertical operations are fast, while -//! horizontal operations are, by comparison, much slower. That is, the -//! most portably-efficient way of performing a reduction over a slice -//! is to collect the results into a vector using vertical operations, -//! and performing a single horizontal operation at the end: -//! -//! ``` -//! # use packed_simd::*; -//! fn reduce(x: &[i32]) -> i32 { -//! assert_eq!(x.len() % 4, 0); -//! let mut sum = i32x4::splat(0); // [0, 0, 0, 0] -//! for i in (0..x.len()).step_by(4) { -//! sum += i32x4::from_slice_unaligned(&x[i..]); -//! } -//! sum.wrapping_sum() -//! } -//! -//! let x = [0, 1, 2, 3, 4, 5, 6, 7]; -//! assert_eq!(reduce(&x), 28); -//! ``` -//! -//! ## Vector types -//! -//! The vector type aliases are named according to the following scheme: -//! -//! > `{element_type}x{number_of_lanes} == Simd<[element_type; -//! number_of_lanes]>` -//! -//! where the following element types are supported: -//! -//! * `i{element_width}`: signed integer -//! * `u{element_width}`: unsigned integer -//! * `f{element_width}`: float -//! * `m{element_width}`: mask (see below) -//! * `*{const,mut} T`: `const` and `mut` pointers -//! -//! ## Basic operations -//! -//! ``` -//! # use packed_simd::*; -//! // Sets all elements to `0`: -//! let a = i32x4::splat(0); -//! -//! // Reads a vector from a slice: -//! let mut arr = [0, 0, 0, 1, 2, 3, 4, 5]; -//! let b = i32x4::from_slice_unaligned(&arr); -//! -//! // Reads the 4-th element of a vector: -//! assert_eq!(b.extract(3), 1); -//! -//! // Returns a new vector where the 4-th element is replaced with `1`: -//! let a = a.replace(3, 1); -//! assert_eq!(a, b); -//! -//! // Writes a vector to a slice: -//! let a = a.replace(2, 1); -//! a.write_to_slice_unaligned(&mut arr[4..]); -//! assert_eq!(arr, [0, 0, 0, 1, 0, 0, 1, 1]); -//! ``` -//! -//! ## Conditional operations -//! -//! One often needs to perform an operation on some lanes of the vector. Vector -//! masks, like `m32x4`, allow selecting on which vector lanes an operation is -//! to be performed: -//! -//! ``` -//! # use packed_simd::*; -//! let a = i32x4::new(1, 1, 2, 2); -//! -//! // Add `1` to the first two lanes of the vector. -//! let m = m16x4::new(true, true, false, false); -//! let a = m.select(a + 1, a); -//! assert_eq!(a, i32x4::splat(2)); -//! ``` -//! -//! The elements of a vector mask are either `true` or `false`. Here `true` -//! means that a lane is "selected", while `false` means that a lane is not -//! selected. -//! -//! All vector masks implement a `mask.select(a: T, b: T) -> T` method that -//! works on all vectors that have the same number of lanes as the mask. The -//! resulting vector contains the elements of `a` for those lanes for which the -//! mask is `true`, and the elements of `b` otherwise. -//! -//! The example constructs a mask with the first two lanes set to `true` and -//! the last two lanes set to `false`. This selects the first two lanes of `a + -//! 1` and the last two lanes of `a`, producing a vector where the first two -//! lanes have been incremented by `1`. -//! -//! > note: mask `select` can be used on vector types that have the same number -//! > of lanes as the mask. The example shows this by using [`m16x4`] instead -//! > of [`m32x4`]. It is _typically_ more performant to use a mask element -//! > width equal to the element width of the vectors being operated upon. -//! > This is, however, not true for 512-bit wide vectors when targeting -//! > AVX-512, where the most efficient masks use only 1-bit per element. -//! -//! All vertical comparison operations returns masks: -//! -//! ``` -//! # use packed_simd::*; -//! let a = i32x4::new(1, 1, 3, 3); -//! let b = i32x4::new(2, 2, 0, 0); -//! -//! // ge: >= (Greater Eequal; see also lt, le, gt, eq, ne). -//! let m = a.ge(i32x4::splat(2)); -//! -//! if m.any() { -//! // all / any / none allow coherent control flow -//! let d = m.select(a, b); -//! assert_eq!(d, i32x4::new(2, 2, 3, 3)); -//! } -//! ``` -//! -//! ## Conversions -//! -//! * **lossless widening conversions**: [`From`]/[`Into`] are implemented for -//! vectors with the same number of lanes when the conversion is value -//! preserving (same as in `std`). -//! -//! * **safe bitwise conversions**: The cargo feature `into_bits` provides the -//! `IntoBits/FromBits` traits (`x.into_bits()`). These perform safe bitwise -//! `transmute`s when all bit patterns of the source type are valid bit -//! patterns of the target type and are also implemented for the -//! architecture-specific vector types of `std::arch`. For example, `let x: -//! u8x8 = m8x8::splat(true).into_bits();` is provided because all `m8x8` bit -//! patterns are valid `u8x8` bit patterns. However, the opposite is not -//! true, not all `u8x8` bit patterns are valid `m8x8` bit-patterns, so this -//! operation cannot be performed safely using `x.into_bits()`; one needs to -//! use `unsafe { crate::mem::transmute(x) }` for that, making sure that the -//! value in the `u8x8` is a valid bit-pattern of `m8x8`. -//! -//! * **numeric casts** (`as`): are performed using [`FromCast`]/[`Cast`] -//! (`x.cast()`), just like `as`: -//! -//! * casting integer vectors whose lane types have the same size (e.g. -//! `i32xN` -> `u32xN`) is a **no-op**, -//! -//! * casting from a larger integer to a smaller integer (e.g. `u32xN` -> -//! `u8xN`) will **truncate**, -//! -//! * casting from a smaller integer to a larger integer (e.g. `u8xN` -> -//! `u32xN`) will: -//! * **zero-extend** if the source is unsigned, or -//! * **sign-extend** if the source is signed, -//! -//! * casting from a float to an integer will **round the float towards -//! zero**, -//! -//! * casting from an integer to float will produce the floating point -//! representation of the integer, **rounding to nearest, ties to even**, -//! -//! * casting from an `f32` to an `f64` is perfect and lossless, -//! -//! * casting from an `f64` to an `f32` **rounds to nearest, ties to even**. -//! -//! Numeric casts are not very "precise": sometimes lossy, sometimes value -//! preserving, etc. -//! -//! ## Hardware Features -//! -//! This crate can use different hardware features based on your configured -//! `RUSTFLAGS`. For example, with no configured `RUSTFLAGS`, `u64x8` on -//! x86_64 will use SSE2 operations like `PCMPEQD`. If you configure -//! `RUSTFLAGS='-C target-feature=+avx2,+avx'` on supported x86_64 hardware -//! the same `u64x8` may use wider AVX2 operations like `VPCMPEQQ`. It is -//! important for performance and for hardware support requirements that -//! you choose an appropriate set of `target-feature` and `target-cpu` -//! options during builds. For more information, see the [Performance -//! guide](https://rust-lang-nursery.github.io/packed_simd/perf-guide/) - -#![feature( - adt_const_params, - repr_simd, - rustc_attrs, - platform_intrinsics, - stdsimd, - arm_target_feature, - link_llvm_intrinsics, - core_intrinsics, - stmt_expr_attributes, - custom_inner_attributes, -)] -#![allow(non_camel_case_types, non_snake_case, - // FIXME: these types are unsound in C FFI already - // See https://github.com/rust-lang/rust/issues/53346 - improper_ctypes_definitions, - incomplete_features, - clippy::cast_possible_truncation, - clippy::cast_lossless, - clippy::cast_possible_wrap, - clippy::cast_precision_loss, - // TODO: manually add the `#[must_use]` attribute where appropriate - clippy::must_use_candidate, - // This lint is currently broken for generic code - // See https://github.com/rust-lang/rust-clippy/issues/3410 - clippy::use_self, - clippy::wrong_self_convention, - clippy::from_over_into, -)] -#![cfg_attr(test, feature(hashmap_internals))] -#![cfg_attr(doc_cfg, feature(doc_cfg))] -#![deny(rust_2018_idioms, clippy::missing_inline_in_public_items)] -#![no_std] - -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(feature = "core_arch")] { - #[allow(unused_imports)] - use core_arch as arch; - } else { - #[allow(unused_imports)] - use core::arch; - } -} - -#[cfg(all(target_arch = "wasm32", test))] -use wasm_bindgen_test::*; - -#[allow(unused_imports)] -use core::{ - /* arch (handled above), */ cmp, f32, f64, fmt, hash, hint, i128, i16, i32, i64, i8, intrinsics, - isize, iter, marker, mem, ops, ptr, slice, u128, u16, u32, u64, u8, usize, -}; - -#[macro_use] -mod testing; -#[macro_use] -mod api; -mod codegen; -mod sealed; - -pub use crate::sealed::{Mask, Shuffle, Simd as SimdVector, SimdArray}; - -/// Packed SIMD vector type. -/// -/// # Examples -/// -/// ``` -/// # use packed_simd::Simd; -/// let v = Simd::<[i32; 4]>::new(0, 1, 2, 3); -/// assert_eq!(v.extract(2), 2); -/// ``` -#[repr(transparent)] -#[derive(Copy, Clone)] -pub struct Simd( - // FIXME: this type should be private, - // but it currently must be public for the - // `shuffle!` macro to work: it needs to - // access the internal `repr(simd)` type - // to call the shuffle intrinsics. - #[doc(hidden)] pub ::Tuple, -); - -impl sealed::Seal for Simd {} - -/// Wrapper over `T` implementing a lexicoraphical order via the `PartialOrd` -/// and/or `Ord` traits. -#[repr(transparent)] -#[derive(Copy, Clone, Debug)] -#[allow(clippy::missing_inline_in_public_items)] -pub struct LexicographicallyOrdered(T); - -mod masks; -pub use self::masks::*; - -mod v16; -pub use self::v16::*; - -mod v32; -pub use self::v32::*; - -mod v64; -pub use self::v64::*; - -mod v128; -pub use self::v128::*; - -mod v256; -pub use self::v256::*; - -mod v512; -pub use self::v512::*; - -mod vSize; -pub use self::vSize::*; - -mod vPtr; -pub use self::vPtr::*; - -pub use self::api::cast::*; - -#[cfg(feature = "into_bits")] -pub use self::api::into_bits::*; - -// Re-export the shuffle intrinsics required by the `shuffle!` macro. -#[doc(hidden)] -pub use self::codegen::llvm::{ - __shuffle_vector16, __shuffle_vector2, __shuffle_vector32, __shuffle_vector4, __shuffle_vector64, - __shuffle_vector8, -}; - -pub(crate) mod llvm { - pub(crate) use crate::codegen::llvm::*; -} diff --git a/third_party/rust/packed_simd/src/masks.rs b/third_party/rust/packed_simd/src/masks.rs deleted file mode 100644 index 04534eab2b..0000000000 --- a/third_party/rust/packed_simd/src/masks.rs +++ /dev/null @@ -1,126 +0,0 @@ -//! Mask types - -macro_rules! impl_mask_ty { - ($id:ident : $elem_ty:ident | #[$doc:meta]) => { - #[$doc] - #[derive(Copy, Clone)] - pub struct $id($elem_ty); - - impl crate::sealed::Seal for $id {} - impl crate::sealed::Mask for $id { - #[inline] - fn test(&self) -> bool { - $id::test(self) - } - } - - impl $id { - /// Instantiate a mask with `value` - #[inline] - pub fn new(x: bool) -> Self { - if x { - $id(!0) - } else { - $id(0) - } - } - /// Test if the mask is set - #[inline] - pub fn test(&self) -> bool { - self.0 != 0 - } - } - - impl Default for $id { - #[inline] - fn default() -> Self { - $id(0) - } - } - - #[allow(clippy::partialeq_ne_impl)] - impl PartialEq<$id> for $id { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - #[inline] - fn ne(&self, other: &Self) -> bool { - self.0 != other.0 - } - } - - impl Eq for $id {} - - impl PartialOrd<$id> for $id { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - use crate::cmp::Ordering; - if self == other { - Some(Ordering::Equal) - } else if self.0 > other.0 { - // Note: - // * false = 0_i - // * true == !0_i == -1_i - Some(Ordering::Less) - } else { - Some(Ordering::Greater) - } - } - - #[inline] - fn lt(&self, other: &Self) -> bool { - self.0 > other.0 - } - #[inline] - fn gt(&self, other: &Self) -> bool { - self.0 < other.0 - } - #[inline] - fn le(&self, other: &Self) -> bool { - self.0 >= other.0 - } - #[inline] - fn ge(&self, other: &Self) -> bool { - self.0 <= other.0 - } - } - - impl Ord for $id { - #[inline] - fn cmp(&self, other: &Self) -> crate::cmp::Ordering { - match self.partial_cmp(other) { - Some(x) => x, - None => unsafe { crate::hint::unreachable_unchecked() }, - } - } - } - - impl crate::hash::Hash for $id { - #[inline] - fn hash(&self, state: &mut H) { - (self.0 != 0).hash(state); - } - } - - impl crate::fmt::Debug for $id { - #[inline] - fn fmt(&self, fmtter: &mut crate::fmt::Formatter<'_>) -> Result<(), crate::fmt::Error> { - write!(fmtter, "{}({})", stringify!($id), self.0 != 0) - } - } - }; -} - -impl_mask_ty!(m8: i8 | /// 8-bit wide mask. -); -impl_mask_ty!(m16: i16 | /// 16-bit wide mask. -); -impl_mask_ty!(m32: i32 | /// 32-bit wide mask. -); -impl_mask_ty!(m64: i64 | /// 64-bit wide mask. -); -impl_mask_ty!(m128: i128 | /// 128-bit wide mask. -); -impl_mask_ty!(msize: isize | /// isize-wide mask. -); diff --git a/third_party/rust/packed_simd/src/sealed.rs b/third_party/rust/packed_simd/src/sealed.rs deleted file mode 100644 index 0ec20300fd..0000000000 --- a/third_party/rust/packed_simd/src/sealed.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Sealed traits - -/// A sealed trait, this is logically private to the crate -/// and will prevent implementations from outside the crate -pub trait Seal {} - -/// Trait implemented by arrays that can be SIMD types. -pub trait SimdArray: Seal { - /// The type of the #[repr(simd)] type. - type Tuple: Copy + Clone; - /// The element type of the vector. - type T; - /// The number of elements in the array. - const N: usize; - /// The type: `[u32; Self::N]`. - type NT; -} - -/// This traits is used to constraint the arguments -/// and result type of the portable shuffles. -#[doc(hidden)] -pub trait Shuffle: Seal { - // Lanes is a `[u32; N]` where `N` is the number of vector lanes - - /// The result type of the shuffle. - type Output; -} - -/// This trait is implemented by all SIMD vector types. -pub trait Simd: Seal { - /// Element type of the SIMD vector - type Element; - /// The number of elements in the SIMD vector. - const LANES: usize; - /// The type: `[u32; Self::N]`. - type LanesType; -} - -/// This trait is implemented by all mask types -pub trait Mask: Seal { - fn test(&self) -> bool; -} diff --git a/third_party/rust/packed_simd/src/testing.rs b/third_party/rust/packed_simd/src/testing.rs deleted file mode 100644 index 6320b28055..0000000000 --- a/third_party/rust/packed_simd/src/testing.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Testing macros and other utilities. - -#[macro_use] -mod macros; - -#[cfg(test)] -#[macro_use] -pub(crate) mod utils; diff --git a/third_party/rust/packed_simd/src/testing/macros.rs b/third_party/rust/packed_simd/src/testing/macros.rs deleted file mode 100644 index 7bc4268b90..0000000000 --- a/third_party/rust/packed_simd/src/testing/macros.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Testing macros - -macro_rules! test_if { - ($cfg_tt:tt: $it:item) => { - #[cfg(any( - // Test everything if: - // - // * tests are enabled, - // * no features about exclusively testing - // specific vector classes are enabled - all(test, not(any( - test_v16, - test_v32, - test_v64, - test_v128, - test_v256, - test_v512, - test_none, // disables all tests - ))), - // Test if: - // - // * tests are enabled - // * a particular cfg token tree returns true - all(test, $cfg_tt), - ))] - $it - }; -} - -#[cfg(test)] -#[allow(unused)] -macro_rules! ref_ { - ($anything:tt) => { - &$anything - }; -} - -#[cfg(test)] -#[allow(unused)] -macro_rules! ref_mut_ { - ($anything:tt) => { - &mut $anything - }; -} diff --git a/third_party/rust/packed_simd/src/testing/utils.rs b/third_party/rust/packed_simd/src/testing/utils.rs deleted file mode 100644 index 7d8f395739..0000000000 --- a/third_party/rust/packed_simd/src/testing/utils.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Testing utilities - -#![allow(dead_code)] -// FIXME: Or don't. But it's true this is a problematic comparison. -#![allow(clippy::neg_cmp_op_on_partial_ord)] - -use crate::{cmp::PartialOrd, fmt::Debug, LexicographicallyOrdered}; - -/// Tests PartialOrd for `a` and `b` where `a < b` is true. -pub fn test_lt(a: LexicographicallyOrdered, b: LexicographicallyOrdered) -where - LexicographicallyOrdered: Debug + PartialOrd, -{ - assert!(a < b, "{:?}, {:?}", a, b); - assert!(b > a, "{:?}, {:?}", a, b); - - assert!(!(a == b), "{:?}, {:?}", a, b); - assert_ne!(a, b, "{:?}, {:?}", a, b); - - assert!(a <= b, "{:?}, {:?}", a, b); - assert!(b >= a, "{:?}, {:?}", a, b); - - // The elegance of the mathematical expression of irreflexivity is more - // than clippy can handle. - #[allow(clippy::eq_op)] - { - // Irreflexivity - assert!(!(a < a), "{:?}, {:?}", a, b); - assert!(!(b < b), "{:?}, {:?}", a, b); - assert!(!(a > a), "{:?}, {:?}", a, b); - assert!(!(b > b), "{:?}, {:?}", a, b); - - assert!(a <= a, "{:?}, {:?}", a, b); - assert!(b <= b, "{:?}, {:?}", a, b); - } -} - -/// Tests PartialOrd for `a` and `b` where `a <= b` is true. -pub fn test_le(a: LexicographicallyOrdered, b: LexicographicallyOrdered) -where - LexicographicallyOrdered: Debug + PartialOrd, -{ - assert!(a <= b, "{:?}, {:?}", a, b); - assert!(b >= a, "{:?}, {:?}", a, b); - - assert!(a <= b, "{:?}, {:?}", a, b); - assert!(b >= a, "{:?}, {:?}", a, b); - - if a == b { - assert!(!(a < b), "{:?}, {:?}", a, b); - assert!(!(b > a), "{:?}, {:?}", a, b); - - assert!(!(a != b), "{:?}, {:?}", a, b); - } else { - assert_ne!(a, b, "{:?}, {:?}", a, b); - test_lt(a, b); - } -} - -/// Test PartialOrd::partial_cmp for `a` and `b` returning `Ordering` -pub fn test_cmp( - a: LexicographicallyOrdered, - b: LexicographicallyOrdered, - o: Option, -) where - LexicographicallyOrdered: PartialOrd + Debug, - T: Debug + crate::sealed::Simd + Copy + Clone, - ::Element: Default + Copy + Clone + PartialOrd, -{ - assert!(T::LANES <= 64, "array length in these two arrays needs updating"); - let mut arr_a: [T::Element; 64] = [Default::default(); 64]; - let mut arr_b: [T::Element; 64] = [Default::default(); 64]; - - unsafe { crate::ptr::write_unaligned(arr_a.as_mut_ptr() as *mut LexicographicallyOrdered, a) } - unsafe { crate::ptr::write_unaligned(arr_b.as_mut_ptr() as *mut LexicographicallyOrdered, b) } - let expected = arr_a[0..T::LANES].partial_cmp(&arr_b[0..T::LANES]); - let result = a.partial_cmp(&b); - assert_eq!(expected, result, "{:?}, {:?}", a, b); - assert_eq!(o, result, "{:?}, {:?}", a, b); - match o { - Some(crate::cmp::Ordering::Less) => { - test_lt(a, b); - test_le(a, b); - } - Some(crate::cmp::Ordering::Greater) => { - test_lt(b, a); - test_le(b, a); - } - Some(crate::cmp::Ordering::Equal) => { - assert!(a == b, "{:?}, {:?}", a, b); - assert!(!(a != b), "{:?}, {:?}", a, b); - assert!(!(a < b), "{:?}, {:?}", a, b); - assert!(!(b < a), "{:?}, {:?}", a, b); - assert!(!(a > b), "{:?}, {:?}", a, b); - assert!(!(b > a), "{:?}, {:?}", a, b); - - test_le(a, b); - test_le(b, a); - } - None => { - assert!(!(a == b), "{:?}, {:?}", a, b); - assert!(!(a != b), "{:?}, {:?}", a, b); - assert!(!(a < b), "{:?}, {:?}", a, b); - assert!(!(a > b), "{:?}, {:?}", a, b); - assert!(!(b < a), "{:?}, {:?}", a, b); - assert!(!(b > a), "{:?}, {:?}", a, b); - assert!(!(a <= b), "{:?}, {:?}", a, b); - assert!(!(b <= a), "{:?}, {:?}", a, b); - assert!(!(a >= b), "{:?}, {:?}", a, b); - assert!(!(b >= a), "{:?}, {:?}", a, b); - } - } -} - -// Returns a tuple containing two distinct pointer values of the same type as -// the element type of the Simd vector `$id`. -#[allow(unused)] -macro_rules! ptr_vals { - ($id:ty) => { - // expands to an expression - #[allow(unused_unsafe)] - unsafe { - // all bits cleared - let clear: <$id as sealed::Simd>::Element = crate::mem::zeroed(); - // all bits set - let set: <$id as sealed::Simd>::Element = crate::mem::transmute(-1_isize); - (clear, set) - } - }; -} diff --git a/third_party/rust/packed_simd/src/v128.rs b/third_party/rust/packed_simd/src/v128.rs deleted file mode 100644 index 7949f6619a..0000000000 --- a/third_party/rust/packed_simd/src/v128.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! 128-bit wide vector types -#[rustfmt::skip] - -use crate::*; - -impl_i!([i8; 16]: i8x16, m8x16 | i8, u16 | test_v128 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: | - /// A 128-bit vector with 16 `i8` lanes. -); -impl_u!([u8; 16]: u8x16, m8x16 | u8, u16 | test_v128 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: | - /// A 128-bit vector with 16 `u8` lanes. -); -impl_m!([m8; 16]: m8x16 | i8, u16 | test_v128 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: m16x16 | - /// A 128-bit vector mask with 16 `m8` lanes. -); - -impl_i!([i16; 8]: i16x8, m16x8 | i16, u8 | test_v128 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: i8x8, u8x8 | - /// A 128-bit vector with 8 `i16` lanes. -); -impl_u!([u16; 8]: u16x8, m16x8 | u16, u8 | test_v128 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: u8x8 | - /// A 128-bit vector with 8 `u16` lanes. -); -impl_m!([m16; 8]: m16x8 | i16, u8 | test_v128 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: m8x8, m32x8 | - /// A 128-bit vector mask with 8 `m16` lanes. -); - -impl_i!([i32; 4]: i32x4, m32x4 | i32, u8 | test_v128 | x0, x1, x2, x3 | - From: i8x4, u8x4, i16x4, u16x4 | - /// A 128-bit vector with 4 `i32` lanes. -); -impl_u!([u32; 4]: u32x4, m32x4 | u32, u8 | test_v128 | x0, x1, x2, x3 | - From: u8x4, u16x4 | - /// A 128-bit vector with 4 `u32` lanes. -); -impl_f!([f32; 4]: f32x4, m32x4 | f32 | test_v128 | x0, x1, x2, x3 | - From: i8x4, u8x4, i16x4, u16x4 | - /// A 128-bit vector with 4 `f32` lanes. -); -impl_m!([m32; 4]: m32x4 | i32, u8 | test_v128 | x0, x1, x2, x3 | - From: m8x4, m16x4, m64x4 | - /// A 128-bit vector mask with 4 `m32` lanes. -); - -impl_i!([i64; 2]: i64x2, m64x2 | i64, u8 | test_v128 | x0, x1 | - From: i8x2, u8x2, i16x2, u16x2, i32x2, u32x2 | - /// A 128-bit vector with 2 `i64` lanes. -); -impl_u!([u64; 2]: u64x2, m64x2 | u64, u8 | test_v128 | x0, x1 | - From: u8x2, u16x2, u32x2 | - /// A 128-bit vector with 2 `u64` lanes. -); -impl_f!([f64; 2]: f64x2, m64x2 | f64 | test_v128 | x0, x1 | - From: i8x2, u8x2, i16x2, u16x2, i32x2, u32x2, f32x2 | - /// A 128-bit vector with 2 `f64` lanes. -); -impl_m!([m64; 2]: m64x2 | i64, u8 | test_v128 | x0, x1 | - From: m8x2, m16x2, m32x2, m128x2 | - /// A 128-bit vector mask with 2 `m64` lanes. -); - -impl_i!([i128; 1]: i128x1, m128x1 | i128, u8 | test_v128 | x0 | - From: /*i8x1, u8x1, i16x1, u16x1, i32x1, u32x1, i64x1, u64x1 */ | // FIXME: unary small vector types - /// A 128-bit vector with 1 `i128` lane. -); -impl_u!([u128; 1]: u128x1, m128x1 | u128, u8 | test_v128 | x0 | - From: /*u8x1, u16x1, u32x1, u64x1 */ | // FIXME: unary small vector types - /// A 128-bit vector with 1 `u128` lane. -); -impl_m!([m128; 1]: m128x1 | i128, u8 | test_v128 | x0 | - From: /*m8x1, m16x1, m32x1, m64x1 */ | // FIXME: unary small vector types - /// A 128-bit vector mask with 1 `m128` lane. -); diff --git a/third_party/rust/packed_simd/src/v16.rs b/third_party/rust/packed_simd/src/v16.rs deleted file mode 100644 index 4ca5afb2a7..0000000000 --- a/third_party/rust/packed_simd/src/v16.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! 16-bit wide vector types - -use crate::*; - -impl_i!([i8; 2]: i8x2, m8x2 | i8, u8 | test_v16 | x0, x1 | - From: | - /// A 16-bit vector with 2 `i8` lanes. -); -impl_u!([u8; 2]: u8x2, m8x2 | u8, u8 | test_v16 | x0, x1 | - From: | - /// A 16-bit vector with 2 `u8` lanes. -); -impl_m!([m8; 2]: m8x2 | i8, u8 | test_v16 | x0, x1 | - From: m16x2, m32x2, m64x2, m128x2 | - /// A 16-bit vector mask with 2 `m8` lanes. -); diff --git a/third_party/rust/packed_simd/src/v256.rs b/third_party/rust/packed_simd/src/v256.rs deleted file mode 100644 index f0c3bc2813..0000000000 --- a/third_party/rust/packed_simd/src/v256.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! 256-bit wide vector types -#[rustfmt::skip] - -use crate::*; - -impl_i!([i8; 32]: i8x32, m8x32 | i8, u32 | test_v256 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31 | - From: | - /// A 256-bit vector with 32 `i8` lanes. -); -impl_u!([u8; 32]: u8x32, m8x32 | u8, u32 | test_v256 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31 | - From: | - /// A 256-bit vector with 32 `u8` lanes. -); -impl_m!([m8; 32]: m8x32 | i8, u32 | test_v256 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31 | - From: | - /// A 256-bit vector mask with 32 `m8` lanes. -); - -impl_i!([i16; 16]: i16x16, m16x16 | i16, u16 | test_v256 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: i8x16, u8x16 | - /// A 256-bit vector with 16 `i16` lanes. -); -impl_u!([u16; 16]: u16x16, m16x16 | u16, u16 | test_v256 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: u8x16 | - /// A 256-bit vector with 16 `u16` lanes. -); -impl_m!([m16; 16]: m16x16 | i16, u16 | test_v256 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: m8x16 | - /// A 256-bit vector mask with 16 `m16` lanes. -); - -impl_i!([i32; 8]: i32x8, m32x8 | i32, u8 | test_v256 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: i8x8, u8x8, i16x8, u16x8 | - /// A 256-bit vector with 8 `i32` lanes. -); -impl_u!([u32; 8]: u32x8, m32x8 | u32, u8 | test_v256 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: u8x8, u16x8 | - /// A 256-bit vector with 8 `u32` lanes. -); -impl_f!([f32; 8]: f32x8, m32x8 | f32 | test_v256 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: i8x8, u8x8, i16x8, u16x8 | - /// A 256-bit vector with 8 `f32` lanes. -); -impl_m!([m32; 8]: m32x8 | i32, u8 | test_v256 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: m8x8, m16x8 | - /// A 256-bit vector mask with 8 `m32` lanes. -); - -impl_i!([i64; 4]: i64x4, m64x4 | i64, u8 | test_v256 | x0, x1, x2, x3 | - From: i8x4, u8x4, i16x4, u16x4, i32x4, u32x4 | - /// A 256-bit vector with 4 `i64` lanes. -); -impl_u!([u64; 4]: u64x4, m64x4 | u64, u8 | test_v256 | x0, x1, x2, x3 | - From: u8x4, u16x4, u32x4 | - /// A 256-bit vector with 4 `u64` lanes. -); -impl_f!([f64; 4]: f64x4, m64x4 | f64 | test_v256 | x0, x1, x2, x3 | - From: i8x4, u8x4, i16x4, u16x4, i32x4, u32x4, f32x4 | - /// A 256-bit vector with 4 `f64` lanes. -); -impl_m!([m64; 4]: m64x4 | i64, u8 | test_v256 | x0, x1, x2, x3 | - From: m8x4, m16x4, m32x4 | - /// A 256-bit vector mask with 4 `m64` lanes. -); - -impl_i!([i128; 2]: i128x2, m128x2 | i128, u8 | test_v256 | x0, x1 | - From: i8x2, u8x2, i16x2, u16x2, i32x2, u32x2, i64x2, u64x2 | - /// A 256-bit vector with 2 `i128` lanes. -); -impl_u!([u128; 2]: u128x2, m128x2 | u128, u8 | test_v256 | x0, x1 | - From: u8x2, u16x2, u32x2, u64x2 | - /// A 256-bit vector with 2 `u128` lanes. -); -impl_m!([m128; 2]: m128x2 | i128, u8 | test_v256 | x0, x1 | - From: m8x2, m16x2, m32x2, m64x2 | - /// A 256-bit vector mask with 2 `m128` lanes. -); diff --git a/third_party/rust/packed_simd/src/v32.rs b/third_party/rust/packed_simd/src/v32.rs deleted file mode 100644 index 75a1838e5e..0000000000 --- a/third_party/rust/packed_simd/src/v32.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! 32-bit wide vector types - -use crate::*; - -impl_i!([i8; 4]: i8x4, m8x4 | i8, u8 | test_v32 | x0, x1, x2, x3 | - From: | - /// A 32-bit vector with 4 `i8` lanes. -); -impl_u!([u8; 4]: u8x4, m8x4 | u8, u8 | test_v32 | x0, x1, x2, x3 | - From: | - /// A 32-bit vector with 4 `u8` lanes. -); -impl_m!([m8; 4]: m8x4 | i8, u8 | test_v32 | x0, x1, x2, x3 | - From: m16x4, m32x4, m64x4 | - /// A 32-bit vector mask with 4 `m8` lanes. -); - -impl_i!([i16; 2]: i16x2, m16x2 | i16, u8 | test_v32 | x0, x1 | - From: i8x2, u8x2 | - /// A 32-bit vector with 2 `i16` lanes. -); -impl_u!([u16; 2]: u16x2, m16x2 | u16, u8 | test_v32 | x0, x1 | - From: u8x2 | - /// A 32-bit vector with 2 `u16` lanes. -); -impl_m!([m16; 2]: m16x2 | i16, u8 | test_v32 | x0, x1 | - From: m8x2, m32x2, m64x2, m128x2 | - /// A 32-bit vector mask with 2 `m16` lanes. -); diff --git a/third_party/rust/packed_simd/src/v512.rs b/third_party/rust/packed_simd/src/v512.rs deleted file mode 100644 index 4c8c71338a..0000000000 --- a/third_party/rust/packed_simd/src/v512.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! 512-bit wide vector types -#[rustfmt::skip] - -use crate::*; - -impl_i!([i8; 64]: i8x64, m8x64 | i8, u64 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, - x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, - x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63 | - From: | - /// A 512-bit vector with 64 `i8` lanes. -); -impl_u!([u8; 64]: u8x64, m8x64 | u8, u64 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, - x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, - x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63 | - From: | - /// A 512-bit vector with 64 `u8` lanes. -); -impl_m!([m8; 64]: m8x64 | i8, u64 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, - x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, - x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63 | - From: | - /// A 512-bit vector mask with 64 `m8` lanes. -); - -impl_i!([i16; 32]: i16x32, m16x32 | i16, u32 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31 | - From: i8x32, u8x32 | - /// A 512-bit vector with 32 `i16` lanes. -); -impl_u!([u16; 32]: u16x32, m16x32 | u16, u32 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31 | - From: u8x32 | - /// A 512-bit vector with 32 `u16` lanes. -); -impl_m!([m16; 32]: m16x32 | i16, u32 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31 | - From: m8x32 | - /// A 512-bit vector mask with 32 `m16` lanes. -); - -impl_i!([i32; 16]: i32x16, m32x16 | i32, u16 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: i8x16, u8x16, i16x16, u16x16 | - /// A 512-bit vector with 16 `i32` lanes. -); -impl_u!([u32; 16]: u32x16, m32x16 | u32, u16 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: u8x16, u16x16 | - /// A 512-bit vector with 16 `u32` lanes. -); -impl_f!([f32; 16]: f32x16, m32x16 | f32 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: i8x16, u8x16, i16x16, u16x16 | - /// A 512-bit vector with 16 `f32` lanes. -); -impl_m!([m32; 16]: m32x16 | i32, u16 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 | - From: m8x16, m16x16 | - /// A 512-bit vector mask with 16 `m32` lanes. -); - -impl_i!([i64; 8]: i64x8, m64x8 | i64, u8 | test_v512 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: i8x8, u8x8, i16x8, u16x8, i32x8, u32x8 | - /// A 512-bit vector with 8 `i64` lanes. -); -impl_u!([u64; 8]: u64x8, m64x8 | u64, u8 | test_v512 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: u8x8, u16x8, u32x8 | - /// A 512-bit vector with 8 `u64` lanes. -); -impl_f!([f64; 8]: f64x8, m64x8 | f64 | test_v512 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: i8x8, u8x8, i16x8, u16x8, i32x8, u32x8, f32x8 | - /// A 512-bit vector with 8 `f64` lanes. -); -impl_m!([m64; 8]: m64x8 | i64, u8 | test_v512 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: m8x8, m16x8, m32x8 | - /// A 512-bit vector mask with 8 `m64` lanes. -); - -impl_i!([i128; 4]: i128x4, m128x4 | i128, u8 | test_v512 | x0, x1, x2, x3 | - From: i8x4, u8x4, i16x4, u16x4, i32x4, u32x4, i64x4, u64x4 | - /// A 512-bit vector with 4 `i128` lanes. -); -impl_u!([u128; 4]: u128x4, m128x4 | u128, u8 | test_v512 | x0, x1, x2, x3 | - From: u8x4, u16x4, u32x4, u64x4 | - /// A 512-bit vector with 4 `u128` lanes. -); -impl_m!([m128; 4]: m128x4 | i128, u8 | test_v512 | x0, x1, x2, x3 | - From: m8x4, m16x4, m32x4, m64x4 | - /// A 512-bit vector mask with 4 `m128` lanes. -); diff --git a/third_party/rust/packed_simd/src/v64.rs b/third_party/rust/packed_simd/src/v64.rs deleted file mode 100644 index bf6b9de610..0000000000 --- a/third_party/rust/packed_simd/src/v64.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! 64-bit wide vector types -#[rustfmt::skip] - -use super::*; - -impl_i!([i8; 8]: i8x8, m8x8 | i8, u8 | test_v64 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: | - /// A 64-bit vector with 8 `i8` lanes. -); -impl_u!([u8; 8]: u8x8, m8x8 | u8, u8 | test_v64 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: | - /// A 64-bit vector with 8 `u8` lanes. -); -impl_m!([m8; 8]: m8x8 | i8, u8 | test_v64 | x0, x1, x2, x3, x4, x5, x6, x7 | - From: m16x8, m32x8 | - /// A 64-bit vector mask with 8 `m8` lanes. -); - -impl_i!([i16; 4]: i16x4, m16x4 | i16, u8 | test_v64 | x0, x1, x2, x3 | - From: i8x4, u8x4 | - /// A 64-bit vector with 4 `i16` lanes. -); -impl_u!([u16; 4]: u16x4, m16x4 | u16, u8 | test_v64 | x0, x1, x2, x3 | - From: u8x4 | - /// A 64-bit vector with 4 `u16` lanes. -); -impl_m!([m16; 4]: m16x4 | i16, u8 | test_v64 | x0, x1, x2, x3 | - From: m8x4, m32x4, m64x4 | - /// A 64-bit vector mask with 4 `m16` lanes. -); - -impl_i!([i32; 2]: i32x2, m32x2 | i32, u8 | test_v64 | x0, x1 | - From: i8x2, u8x2, i16x2, u16x2 | - /// A 64-bit vector with 2 `i32` lanes. -); -impl_u!([u32; 2]: u32x2, m32x2 | u32, u8 | test_v64 | x0, x1 | - From: u8x2, u16x2 | - /// A 64-bit vector with 2 `u32` lanes. -); -impl_m!([m32; 2]: m32x2 | i32, u8 | test_v64 | x0, x1 | - From: m8x2, m16x2, m64x2, m128x2 | - /// A 64-bit vector mask with 2 `m32` lanes. -); -impl_f!([f32; 2]: f32x2, m32x2 | f32 | test_v64 | x0, x1 | - From: i8x2, u8x2, i16x2, u16x2 | - /// A 64-bit vector with 2 `f32` lanes. -); - -/* -impl_i!([i64; 1]: i64x1, m64x1 | i64, u8 | test_v64 | x0 | - From: /*i8x1, u8x1, i16x1, u16x1, i32x1, u32x1*/ | // FIXME: primitive to vector conversion - /// A 64-bit vector with 1 `i64` lanes. -); -impl_u!([u64; 1]: u64x1, m64x1 | u64, u8 | test_v64 | x0 | - From: /*u8x1, u16x1, u32x1*/ | // FIXME: primitive to vector conversion - /// A 64-bit vector with 1 `u64` lanes. -); -impl_m!([m64; 1]: m64x1 | i64, u8 | test_v64 | x0 | - From: /*m8x1, m16x1, m32x1, */ m128x1 | // FIXME: unary small vector types - /// A 64-bit vector mask with 1 `m64` lanes. -); -impl_f!([f64; 1]: f64x1, m64x1 | f64 | test_v64 | x0 | - From: /*i8x1, u8x1, i16x1, u16x1, i32x1, u32x1, f32x1*/ | // FIXME: unary small vector types - /// A 64-bit vector with 1 `f64` lanes. -); -*/ diff --git a/third_party/rust/packed_simd/src/vPtr.rs b/third_party/rust/packed_simd/src/vPtr.rs deleted file mode 100644 index e34cb170eb..0000000000 --- a/third_party/rust/packed_simd/src/vPtr.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Vectors of pointers -#[rustfmt::skip] - -use crate::*; - -impl_const_p!( - [*const T; 2]: cptrx2, msizex2, usizex2, isizex2 | test_v128 | x0, x1 | From: | - /// A vector with 2 `*const T` lanes -); - -impl_mut_p!( - [*mut T; 2]: mptrx2, msizex2, usizex2, isizex2 | test_v128 | x0, x1 | From: | - /// A vector with 2 `*mut T` lanes -); - -impl_const_p!( - [*const T; 4]: cptrx4, msizex4, usizex4, isizex4 | test_v256 | x0, x1, x2, x3 | From: | - /// A vector with 4 `*const T` lanes -); - -impl_mut_p!( - [*mut T; 4]: mptrx4, msizex4, usizex4, isizex4 | test_v256 | x0, x1, x2, x3 | From: | - /// A vector with 4 `*mut T` lanes -); - -impl_const_p!( - [*const T; 8]: cptrx8, msizex8, usizex8, isizex8 | test_v512 | x0, x1, x2, x3, x4, x5, x6, x7 | From: | - /// A vector with 8 `*const T` lanes -); - -impl_mut_p!( - [*mut T; 8]: mptrx8, msizex8, usizex8, isizex8 | test_v512 | x0, x1, x2, x3, x4, x5, x6, x7 | From: | - /// A vector with 8 `*mut T` lanes -); diff --git a/third_party/rust/packed_simd/src/vSize.rs b/third_party/rust/packed_simd/src/vSize.rs deleted file mode 100644 index b5d8910061..0000000000 --- a/third_party/rust/packed_simd/src/vSize.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Vectors with pointer-sized elements - -use crate::codegen::pointer_sized_int::{isize_, usize_}; -use crate::*; - -impl_i!([isize; 2]: isizex2, msizex2 | isize_, u8 | test_v128 | - x0, x1| - From: | - /// A vector with 2 `isize` lanes. -); - -impl_u!([usize; 2]: usizex2, msizex2 | usize_, u8 | test_v128 | - x0, x1| - From: | - /// A vector with 2 `usize` lanes. -); -impl_m!([msize; 2]: msizex2 | isize_, u8 | test_v128 | - x0, x1 | - From: | - /// A vector mask with 2 `msize` lanes. -); - -impl_i!([isize; 4]: isizex4, msizex4 | isize_, u8 | test_v256 | - x0, x1, x2, x3 | - From: | - /// A vector with 4 `isize` lanes. -); -impl_u!([usize; 4]: usizex4, msizex4 | usize_, u8 | test_v256 | - x0, x1, x2, x3| - From: | - /// A vector with 4 `usize` lanes. -); -impl_m!([msize; 4]: msizex4 | isize_, u8 | test_v256 | - x0, x1, x2, x3 | - From: | - /// A vector mask with 4 `msize` lanes. -); - -impl_i!([isize; 8]: isizex8, msizex8 | isize_, u8 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7 | - From: | - /// A vector with 8 `isize` lanes. -); -impl_u!([usize; 8]: usizex8, msizex8 | usize_, u8 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7 | - From: | - /// A vector with 8 `usize` lanes. -); -impl_m!([msize; 8]: msizex8 | isize_, u8 | test_v512 | - x0, x1, x2, x3, x4, x5, x6, x7 | - From: | - /// A vector mask with 8 `msize` lanes. -); diff --git a/third_party/rust/packed_simd/tests/endianness.rs b/third_party/rust/packed_simd/tests/endianness.rs deleted file mode 100644 index 17a7796b1b..0000000000 --- a/third_party/rust/packed_simd/tests/endianness.rs +++ /dev/null @@ -1,268 +0,0 @@ -#[cfg(target_arch = "wasm32")] -use wasm_bindgen_test::*; - -use packed_simd::*; -use std::{mem, slice}; - -#[cfg_attr(not(target_arch = "wasm32"), test)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn endian_indexing() { - let v = i32x4::new(0, 1, 2, 3); - assert_eq!(v.extract(0), 0); - assert_eq!(v.extract(1), 1); - assert_eq!(v.extract(2), 2); - assert_eq!(v.extract(3), 3); -} - -#[cfg_attr(not(target_arch = "wasm32"), test)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn endian_bitcasts() { - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let t: i16x8 = unsafe { mem::transmute(x) }; - let e: i16x8 = if cfg!(target_endian = "little") { - i16x8::new(256, 770, 1284, 1798, 2312, 2826, 3340, 3854) - } else { - i16x8::new(1, 515, 1029, 1543, 2057, 2571, 3085, 3599) - }; - assert_eq!(t, e); -} - -#[cfg_attr(not(target_arch = "wasm32"), test)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn endian_casts() { - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let t: i16x16 = x.into(); // simd_cast - #[rustfmt::skip] - let e = i16x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - assert_eq!(t, e); -} - -#[cfg_attr(not(target_arch = "wasm32"), test)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn endian_load_and_stores() { - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let mut y: [i16; 8] = [0; 8]; - x.write_to_slice_unaligned(unsafe { slice::from_raw_parts_mut(&mut y as *mut _ as *mut i8, 16) }); - - let e: [i16; 8] = if cfg!(target_endian = "little") { - [256, 770, 1284, 1798, 2312, 2826, 3340, 3854] - } else { - [1, 515, 1029, 1543, 2057, 2571, 3085, 3599] - }; - assert_eq!(y, e); - - let z = i8x16::from_slice_unaligned(unsafe { slice::from_raw_parts(&y as *const _ as *const i8, 16) }); - assert_eq!(z, x); -} - -#[cfg_attr(not(target_arch = "wasm32"), test)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn endian_array_union() { - union A { - data: [f32; 4], - vec: f32x4, - } - let x: [f32; 4] = unsafe { A { vec: f32x4::new(0., 1., 2., 3.) }.data }; - // As all of these are integer values within the mantissa^1 range, it - // would be very unusual for them to actually fail to compare. - #[allow(clippy::float_cmp)] - { - assert_eq!(x[0], 0_f32); - assert_eq!(x[1], 1_f32); - assert_eq!(x[2], 2_f32); - assert_eq!(x[3], 3_f32); - } - let y: f32x4 = unsafe { A { data: [3., 2., 1., 0.] }.vec }; - assert_eq!(y, f32x4::new(3., 2., 1., 0.)); - - union B { - data: [i8; 16], - vec: i8x16, - } - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let x: [i8; 16] = unsafe { B { vec: x }.data }; - - for (i, v) in x.iter().enumerate() { - assert_eq!(i as i8, *v); - } - - #[rustfmt::skip] - let y = [ - 15, 14, 13, 12, 11, 19, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - ]; - #[rustfmt::skip] - let e = i8x16::new( - 15, 14, 13, 12, 11, 19, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - ); - let z = unsafe { B { data: y }.vec }; - assert_eq!(z, e); - - union C { - data: [i16; 8], - vec: i8x16, - } - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let x: [i16; 8] = unsafe { C { vec: x }.data }; - - let e: [i16; 8] = if cfg!(target_endian = "little") { - [256, 770, 1284, 1798, 2312, 2826, 3340, 3854] - } else { - [1, 515, 1029, 1543, 2057, 2571, 3085, 3599] - }; - assert_eq!(x, e); -} - -#[cfg_attr(not(target_arch = "wasm32"), test)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn endian_tuple_access() { - type F32x4T = (f32, f32, f32, f32); - union A { - data: F32x4T, - vec: f32x4, - } - let x: F32x4T = unsafe { A { vec: f32x4::new(0., 1., 2., 3.) }.data }; - // As all of these are integer values within the mantissa^1 range, it - // would be very unusual for them to actually fail to compare. - #[allow(clippy::float_cmp)] - { - assert_eq!(x.0, 0_f32); - assert_eq!(x.1, 1_f32); - assert_eq!(x.2, 2_f32); - assert_eq!(x.3, 3_f32); - } - let y: f32x4 = unsafe { A { data: (3., 2., 1., 0.) }.vec }; - assert_eq!(y, f32x4::new(3., 2., 1., 0.)); - - #[rustfmt::skip] - type I8x16T = (i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8); - union B { - data: I8x16T, - vec: i8x16, - } - - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let x: I8x16T = unsafe { B { vec: x }.data }; - - assert_eq!(x.0, 0); - assert_eq!(x.1, 1); - assert_eq!(x.2, 2); - assert_eq!(x.3, 3); - assert_eq!(x.4, 4); - assert_eq!(x.5, 5); - assert_eq!(x.6, 6); - assert_eq!(x.7, 7); - assert_eq!(x.8, 8); - assert_eq!(x.9, 9); - assert_eq!(x.10, 10); - assert_eq!(x.11, 11); - assert_eq!(x.12, 12); - assert_eq!(x.13, 13); - assert_eq!(x.14, 14); - assert_eq!(x.15, 15); - - #[rustfmt::skip] - let y = ( - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - ); - let z: i8x16 = unsafe { B { data: y }.vec }; - #[rustfmt::skip] - let e = i8x16::new( - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - ); - assert_eq!(e, z); - - #[rustfmt::skip] - type I16x8T = (i16, i16, i16, i16, i16, i16, i16, i16); - union C { - data: I16x8T, - vec: i8x16, - } - - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let x: I16x8T = unsafe { C { vec: x }.data }; - - let e: [i16; 8] = if cfg!(target_endian = "little") { - [256, 770, 1284, 1798, 2312, 2826, 3340, 3854] - } else { - [1, 515, 1029, 1543, 2057, 2571, 3085, 3599] - }; - assert_eq!(x.0, e[0]); - assert_eq!(x.1, e[1]); - assert_eq!(x.2, e[2]); - assert_eq!(x.3, e[3]); - assert_eq!(x.4, e[4]); - assert_eq!(x.5, e[5]); - assert_eq!(x.6, e[6]); - assert_eq!(x.7, e[7]); - - #[rustfmt::skip] - #[repr(C)] - #[derive(Copy ,Clone)] - pub struct Tup(pub i8, pub i8, pub i16, pub i8, pub i8, pub i16, - pub i8, pub i8, pub i16, pub i8, pub i8, pub i16); - - union D { - data: Tup, - vec: i8x16, - } - - #[rustfmt::skip] - let x = i8x16::new( - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - ); - let x: Tup = unsafe { D { vec: x }.data }; - - let e: [i16; 12] = if cfg!(target_endian = "little") { - [0, 1, 770, 4, 5, 1798, 8, 9, 2826, 12, 13, 3854] - } else { - [0, 1, 515, 4, 5, 1543, 8, 9, 2571, 12, 13, 3599] - }; - assert_eq!(x.0 as i16, e[0]); - assert_eq!(x.1 as i16, e[1]); - assert_eq!(x.2 as i16, e[2]); - assert_eq!(x.3 as i16, e[3]); - assert_eq!(x.4 as i16, e[4]); - assert_eq!(x.5 as i16, e[5]); - assert_eq!(x.6 as i16, e[6]); - assert_eq!(x.7 as i16, e[7]); - assert_eq!(x.8 as i16, e[8]); - assert_eq!(x.9 as i16, e[9]); - assert_eq!(x.10 as i16, e[10]); - assert_eq!(x.11 as i16, e[11]); -} diff --git a/third_party/rust/plist/Cargo.toml b/third_party/rust/plist/Cargo.toml index 4829298f4f..f064e35f27 100644 --- a/third_party/rust/plist/Cargo.toml +++ b/third_party/rust/plist/Cargo.toml @@ -24,7 +24,7 @@ repository = "https://github.com/ebarnard/rust-plist/" version = "0.13.0" [dependencies.indexmap] -version = "1.0.2" +version = "2.1.0" [dependencies.line-wrap] version = "0.1.1" diff --git a/third_party/rust/plist/src/lib.rs b/third_party/rust/plist/src/lib.rs index 0ac048e30d..018bbe7d94 100644 --- a/third_party/rust/plist/src/lib.rs +++ b/third_party/rust/plist/src/lib.rs @@ -72,6 +72,8 @@ //! specify a tilde requirement e.g. `plist = "~1.0.3"` in you `Cargo.toml` so that the plist crate //! is not automatically updated to version 1.1. +#![allow(warnings)] // Third-party + pub mod dictionary; #[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")] diff --git a/third_party/rust/plist/src/stream/binary_writer.rs b/third_party/rust/plist/src/stream/binary_writer.rs index 0e04dbe865..690e2092a2 100644 --- a/third_party/rust/plist/src/stream/binary_writer.rs +++ b/third_party/rust/plist/src/stream/binary_writer.rs @@ -577,7 +577,7 @@ fn is_even(value: usize) -> bool { fn value_mut<'a>( values: &'a mut IndexMap, ValueState>, value_index: usize, -) -> (&'a mut Value<'static>, &'a mut ValueState) { +) -> (&'a Value<'static>, &'a mut ValueState) { values .get_index_mut(value_index) .expect("internal consistency error") diff --git a/third_party/rust/prio/.cargo-checksum.json b/third_party/rust/prio/.cargo-checksum.json index 2d8ae36c4a..858b46fcbc 100644 --- a/third_party/rust/prio/.cargo-checksum.json +++ b/third_party/rust/prio/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"9ae63800fb2fb7ad25b5206e1c6aedba07ebeadce625fa3d3c214391c754c434","LICENSE":"5f5a5db8d4baa0eea0ff2d32a5a86c7a899a3343f1496f4477f42e2d651cc6dc","README.md":"8b36e999c5b65c83fcc77d85e78e690438c08afbb8292640cfc7dbc5164dcfcd","benches/cycle_counts.rs":"40d2ce27e6df99b9d7f4913b39d29a7e60c8efa3718218d125f2691b559b0b77","benches/speed_tests.rs":"2ef52920b677cb0292adf3d5f6bf06f57e678b510550acc99e51b33e8a1bdb44","documentation/releases.md":"14cfe917c88b69d557badc683b887c734254810402c7e19c9a45d815637480a9","src/benchmarked.rs":"a1ca26229967c55ba0d000ed5a594ba42ba2a27af0b1f5e37168f00cb62ad562","src/codec.rs":"2f5763612d19659c7f3f806b94795276c032da7a8e0b41687b355e32b99929da","src/dp.rs":"683de654a0a4bfd51741fdb03f17a3e2a15d11633857623dae3a5df199cfccb6","src/dp/distributions.rs":"8cedb5d44aa8bed9635d8791ec0f05a42fabff95f63d59f50bf9c7764d0c68bd","src/fft.rs":"5900d31263cf16eec9d462eb75458c2582d4c502312d478f87652317ec9f1e9f","src/field.rs":"6e29dcad7ce386e6a0f549214a6a14335118e177e8a2a9d6b1eafbf1fb865ac1","src/field/field255.rs":"6472c11354a1a75d733436607739e69051d5ee15a3f2477bee22d3dd8c80b686","src/flp.rs":"e961b9000e1d332a98975bfbfead93f26af56333338f6102ae09c0a5cdb87987","src/flp/gadgets.rs":"ddf641b0c06348b2a74bd579f994ce8f3ba387f4fa5ec3ca5e3a1260237a1615","src/flp/types.rs":"cb57d1f71b73d19893bfc5e86077b8bdaf66f1cc62b6a49d78ac15737580f45d","src/flp/types/fixedpoint_l2.rs":"22c96b2d0f3bf57155a6acddeee9b6164c3521e99cd12f6b2dd5c206543765d6","src/flp/types/fixedpoint_l2/compatible_float.rs":"8bcfc8ccb1e3ef32fdabbbac40dd7ffb9af10ab9ed10d9cd8c02cd55faa8814f","src/fp.rs":"a70f2961bd9df6a6b9ad683924ed27e4d44fc67408681d7b68fba2c4594edba4","src/idpf.rs":"6a81395351d8beca8f38774f883af23e161067f32ea9f9c177a135b00b139b3c","src/lib.rs":"bb5a25d5d1b2b0f916acd66e27bbcd16022965110f46292edf512973191a9497","src/polynomial.rs":"8e91a56de1a9eaf7eb1f01857e1e1834f768525cadc3bbe02f4f4ff44deeaef8","src/prng.rs":"bcf0125f0fe82c17fca417f068d49c5e08e0e7159a2d5e8a156bb52702d070cc","src/topology/mod.rs":"09a6d07c598d7bb52164bb5f82ab5ceddba5a192454828a789516d621e85c557","src/topology/ping_pong.rs":"89b4b4968d2c3b322ba8ca72101bb026426f5c4f10efb4a7895cb0c4a1488d03","src/vdaf.rs":"fe507b7644288e4912ac3c561a77c390cb85005b889fdcb471392a5886683607","src/vdaf/dummy.rs":"386e7e163625a1c53a1a95dd47c14324c206872080dbe76e90ec5d93f90d39ae","src/vdaf/poplar1.rs":"78af3fe04ef038ec263073522b1c93e0e14a1ab08d6ef1136dd4aa46cb19f667","src/vdaf/prio2.rs":"97d425fcb0a8a15f600ee202e4da7be68ee04e329e8e9f4d50cecd7557213662","src/vdaf/prio2/client.rs":"90c529400c3be77461b02d5cd78c52e98626e83e149b677da711097c9b17e806","src/vdaf/prio2/server.rs":"a5ebc32d92849d2a565888e18c63eac36d2e854f2e51c98ebc04983837465235","src/vdaf/prio2/test_vector.rs":"507cb6d05e40270786eb2c123866a18f7ee586e7c022161bf8fd47cb472507a9","src/vdaf/prio3.rs":"0c60f16188604013bd894e9dddfc8263f65d9b882f7e6831d43c14e05b389af9","src/vdaf/prio3_test.rs":"e2c7e1fd6f20ea3c886a2bfb5a63262f41c9a419e0e419d0b808f585b55b730e","src/vdaf/test_vec/07/IdpfPoplar_0.json":"f4f23df90774d7ac74c0bd984e25db7c1a2c53705adf30a693f388922f2c5d38","src/vdaf/test_vec/07/Poplar1_0.json":"8a5a44e85c5c08bf54a656a8692cad962d08bf9ef49e69f04ca4646de3cc1a40","src/vdaf/test_vec/07/Poplar1_1.json":"1caff76c31ce637baca4adc62f63b4d0d887a860bba8f59ffdef5409f5a0988e","src/vdaf/test_vec/07/Poplar1_2.json":"439eb1ea543929b127c6f77b1109f2455f649a9a84b0335d3dd5177e75fe521f","src/vdaf/test_vec/07/Poplar1_3.json":"2864fe4000934fa4035dcb5914da804ddbd3e7e125c459efc5f400b41b5b6b55","src/vdaf/test_vec/07/Prio3Count_0.json":"33e41769b1e11376276dbfcc6670100673ea3ed887baaaf5c37c6f389167c26c","src/vdaf/test_vec/07/Prio3Count_1.json":"483f53318116847bd43d4b6040ef2f00436f643c05eae153144285e8a032990c","src/vdaf/test_vec/07/Prio3Histogram_0.json":"f71a736c57eb0811b34e2806dc7c6005b67fc62fffb0779a263f1030a09ec747","src/vdaf/test_vec/07/Prio3Histogram_1.json":"3d67c8547fe69baa6ba8d90c3fd307003f9ebe04984c39343dcd8e794a6bf5d8","src/vdaf/test_vec/07/Prio3SumVec_0.json":"9d0ff391d954073ccbb798d382ba8701131687410e6d754c3bce36e9c8f650df","src/vdaf/test_vec/07/Prio3SumVec_1.json":"83f1abe06fc76a9f628be112efc8168243ce4713b878fe7d6ffe2b5b17a87382","src/vdaf/test_vec/07/Prio3Sum_0.json":"732093776a144bf9a8e71ae3179ae0fd74e5db3787b31603dceeb6e557d9d814","src/vdaf/test_vec/07/Prio3Sum_1.json":"a4250943b8a33d4d19652bd8a7312059ea92e3f8b1d541439b64bff996bc1bf4","src/vdaf/test_vec/07/XofFixedKeyAes128.json":"ff40fc42eec15a483bd02e798ddab6c38d81a335f1fe5703290ced88d7ceae26","src/vdaf/test_vec/07/XofShake128.json":"e68b4769f4fb9be9a8d9d5bf823636ed97c6e1f68bcd794c7576ba8b42eeba9a","src/vdaf/test_vec/prio2/fieldpriov2.json":"7ba82fcf068dfd5b04fc7fd01ebe5626ea9740be9cd6aa631525f23b80bcd027","src/vdaf/xof.rs":"175a4b0077bf295aeee4f42c70b55684079f4ef8c1b580b90ac0af8914f05fc9","tests/discrete_gauss.rs":"ddae145ac52ff8cd2b2134266733fee6fd9378bfb68c943a28e5a0a314a1ceb7","tests/test_vectors/discrete_gauss_100.json":"0f056accac870bf79539c82492f7b1f30d69835fe780bb83e0a15b0f0b318bc3","tests/test_vectors/discrete_gauss_2.342.json":"2ce62090c800c786b02ad409c4de18a94858105cd4859d7f595fbdf7ab79e8e1","tests/test_vectors/discrete_gauss_3.json":"b088841eef4cba2b287f04d3707a7efd33c11a2d40a71c8d953e8231150dbe6e","tests/test_vectors/discrete_gauss_41293847.json":"5896a922e313ce15d1353f0bdbf1f55413cc6a8116531cfc1fd9f3f7000e9002","tests/test_vectors/discrete_gauss_9.json":"4ae1c1195d752b6db5b3be47e7e662c2070aac1146e5b9ce9398c0c93cec21d2","tests/test_vectors/discrete_gauss_9999999999999999999999.json":"d65ec163c7bcbd8091c748e659eba460a9c56b37bc7612fd4a96394e58480b23"},"package":"b3163d19b7d8bc08c7ab6b74510f5e048c0937509d14c28b8919d2baf8cb9387"} \ No newline at end of file +{"files":{"Cargo.toml":"305efd4975370d0fa7b94ad850c0228d1db1d7baf271b15061ac7f2036e99381","LICENSE":"5f5a5db8d4baa0eea0ff2d32a5a86c7a899a3343f1496f4477f42e2d651cc6dc","README.md":"9a2b0c376b6f421300552b1ad52f87b346b4ab2b59b2c21fcd3ee4cf10445c3c","benches/cycle_counts.rs":"d3e9d26f6a43e73df488ae0ef3aec4b3088343bfae7603d68561a01418bf8fbf","benches/speed_tests.rs":"2080c3c5d80ffa1100dbd8981c48574cc5ecb9c4b959a2c1bd4a759314307c3e","documentation/field_parameters.sage":"8b0ec3dafebb8f6eeac606bef40dcaf3e521e8988944ade06ce89cbde780f101","documentation/releases.md":"14cfe917c88b69d557badc683b887c734254810402c7e19c9a45d815637480a9","src/benchmarked.rs":"a1ca26229967c55ba0d000ed5a594ba42ba2a27af0b1f5e37168f00cb62ad562","src/codec.rs":"0706823b71da46a6ba4f359f1253a283a5a5a126ebb0087e73ae42ee4c746f12","src/dp.rs":"5480fc055c60082898e3eee84ac0fa3737f2c4588dd07eed0c787b170a5acdea","src/dp/distributions.rs":"f1cf6694f78874cd5c2561a69c7cd40f85302007b095e56ed29a348a8b13840d","src/fft.rs":"36d8c7fe23c3f32bc555b00bd8bc9b48f4a081b9a93cb1c8908277981acbc067","src/field.rs":"3cd2aeaf81a9a9522bfcab0393aef81df72ed15af7562549dfd288c1eeb50584","src/field/field255.rs":"16e706e175322a1e1c5bfe2152afb03080e04963cd925eafbe72e4fb272734df","src/flp.rs":"129040b44306098298943fc44c6eaf19833b7bcd9dadeecce8787fcbb297b8f5","src/flp/gadgets.rs":"ddf641b0c06348b2a74bd579f994ce8f3ba387f4fa5ec3ca5e3a1260237a1615","src/flp/types.rs":"eb6ff64af7c58a71912909e9a783690d595bfaab39d50c4805afd2caf892efad","src/flp/types/fixedpoint_l2.rs":"5a42a04fdad9309816064b60d7a92aeb548f38c45dafa23ff83755cc5d73f55d","src/flp/types/fixedpoint_l2/compatible_float.rs":"8bcfc8ccb1e3ef32fdabbbac40dd7ffb9af10ab9ed10d9cd8c02cd55faa8814f","src/fp.rs":"a70f2961bd9df6a6b9ad683924ed27e4d44fc67408681d7b68fba2c4594edba4","src/idpf.rs":"ffb41ad4d56f817f5dc44379ef760f23c22883da518ff31fd6e4f411c898193b","src/lib.rs":"58101cbe431eb5160f7edce480515076749e101fd1231c82c7842e408807ce37","src/polynomial.rs":"de703703484219103dd617339a4b3130d74da5d2072b74ebbcbd7889cb82cd8f","src/prng.rs":"28d44b6588a0fb12c5b0b8021ca6d48385db8c7b525606412ec6e2e1e748e9c4","src/topology/mod.rs":"09a6d07c598d7bb52164bb5f82ab5ceddba5a192454828a789516d621e85c557","src/topology/ping_pong.rs":"c0d15d6af01e1e4e5639719ea668a0f25f9787cc2e35d8c59f6a19ef27780e5a","src/vdaf.rs":"b2ec4b02f89208714383722bad46e1a982843623a30f7b17905d57d7875bafb1","src/vdaf/dummy.rs":"143cb9b91db66397c8d577e61d1ac53b964c01c900f2e94573a680c1feb895f3","src/vdaf/poplar1.rs":"60f13b1b4b59ea16387675d274b43e9e39d712943642711a904f76f6be315087","src/vdaf/prio2.rs":"ad620cc08d4ff5eeb0e4ecdada80c2ec8929ffbb5d011dae64d21433da0a305b","src/vdaf/prio2/client.rs":"21b9a4acaccc0bddeba78d49c0f296f46a247bd3973873492418470bdb891e5f","src/vdaf/prio2/server.rs":"74771170162c7dae631042bdaf85f9b0371fa83fae2b0984ef8dea9cec49f499","src/vdaf/prio2/test_vector.rs":"9f56d12b79d7d3c0326329364787ee11d15d1a04f6c2e3bf0c25e35180b69411","src/vdaf/prio3.rs":"2970516f222eb911a8411ad7ffabe3dc6d9912d66f10f4999efab64fe842ab38","src/vdaf/prio3_test.rs":"83ad6f43e8d4da1995272a13848dd51f12a82b4b03821ff13d34b8e3d7535e98","src/vdaf/test_vec/08/IdpfPoplar_0.json":"f7cb4d44ac48c4062e4d62d5db9da7d456cc614a91400e90a4ba9796e2bc5db5","src/vdaf/test_vec/08/Poplar1_0.json":"510c406c7709e27a358680a7b42e0ed0950ac32a52d11ca34facc31e2d7026ad","src/vdaf/test_vec/08/Poplar1_1.json":"ff8172582d174befed35bb75d13ebec4b13f5c39eda8ffc771c43497a487809a","src/vdaf/test_vec/08/Poplar1_2.json":"24548c5a29219418f43e6d3cfd11980945a540e0b7a017f152b6d934c1132c78","src/vdaf/test_vec/08/Poplar1_3.json":"dec75bb53311d27428dd96382e1fe2ac66030ee124802f706035fadedd61b0c1","src/vdaf/test_vec/08/Prio3Count_0.json":"58c3aaedecb52147850804cb6033fb5e9636a386f4e1757891d65f4f1efee345","src/vdaf/test_vec/08/Prio3Count_1.json":"2f0f2688925d6789290a3ed9f46fa0815024f4be5ba3bbc46c1e73fb3b824f41","src/vdaf/test_vec/08/Prio3Histogram_0.json":"a14fd6dd9a9e7bfccda2066414db9e89d3fdc9a0531e28e674f70d7786369a7d","src/vdaf/test_vec/08/Prio3Histogram_1.json":"bef205f52aae80a5fef98a8e19b97bb43541c5140ed1dc1509a8a7c7f2cacfe5","src/vdaf/test_vec/08/Prio3SumVec_0.json":"ba07aa0d0435e9c1b4f4bd27ae2eb20d20e2f3c9c35bdeb3b7d0b91d1cdb7245","src/vdaf/test_vec/08/Prio3SumVec_1.json":"32864dc26cb90551bae952c51c65afc52ba9679a1d77c6f0a2b42d46cda7ae50","src/vdaf/test_vec/08/Prio3Sum_0.json":"2710a9e07af08bbc073f70afd18f9ca176f7a0b161dc4902b1db877431b89eb0","src/vdaf/test_vec/08/Prio3Sum_1.json":"1487295734b0381ddee13a8dc98b0b66d04ed0e96b496de7181614c06bdfc369","src/vdaf/test_vec/08/XofFixedKeyAes128.json":"a96370275c08778d7b95b2b3af2156a180a1319b4ff13aa62340fcc39609cd83","src/vdaf/test_vec/08/XofTurboShake128.json":"3444a04c7f0c6f8656847b7580be11dfeffb3f5ed650dc18581a683b662a7695","src/vdaf/test_vec/XofHmacSha256Aes128.json":"58816eaf9b9ec0a87a00f04c8998c40d6e3e5f2a3a678360da42e1b9819ee545","src/vdaf/test_vec/prio2/fieldpriov2.json":"7ba82fcf068dfd5b04fc7fd01ebe5626ea9740be9cd6aa631525f23b80bcd027","src/vdaf/xof.rs":"3ffec960474f73f4ce313dab4bde49d36d4b819e2410935b2d83ca9d8f2f0bd7","src/vidpf.rs":"58f013388a547d9c894be174f85fb9b964bbc866c1ee3206bbdeba960f601b74","tests/discrete_gauss.rs":"abada12c4b5d1f6c9380a6f07312d24eab5d4d189dae20b89d800a85618bd2bd","tests/test_vectors/discrete_gauss_100.json":"f0b33dda1cb19b44be90224af937be9a1af779bd730ae70db59967c843895010","tests/test_vectors/discrete_gauss_2.342.json":"3c3d9a1c69ed235d93b7a483d1386c54381deacb005103b5df3efaa00d583665","tests/test_vectors/discrete_gauss_3.json":"ee3d2208ae3af0a78b9366e72e7d747e36b357ac1ae60394d37defffd483c318","tests/test_vectors/discrete_gauss_41293847.json":"ba752876c5f685bef8c78a2ab9ba4e592e20e4053da856c0329f5283a14ef01d","tests/test_vectors/discrete_gauss_9.json":"2bd50a5ebb17e572bdf7072c352a23b64436d108f2570d95ae0373717c833279","tests/test_vectors/discrete_gauss_9999999999999999999999.json":"1c951ed0590e0beee87e8a007a4b91ec7045b2fa19b35d42b35dce4e7dd80995"},"package":"5cec5eb0d28eee4ea74be34b28ed4c625e88c54ff83c21b412a5ea7cc48624ae"} \ No newline at end of file diff --git a/third_party/rust/prio/Cargo.toml b/third_party/rust/prio/Cargo.toml index 6e7bcd7e6e..283a4555d1 100644 --- a/third_party/rust/prio/Cargo.toml +++ b/third_party/rust/prio/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.64" +rust-version = "1.71" name = "prio" -version = "0.15.3" +version = "0.16.2" authors = [ "Josh Aas ", "Tim Geoghegan ", @@ -54,7 +54,7 @@ name = "cycle_counts" harness = false [dependencies.aes] -version = "0.8.3" +version = "0.8.4" optional = true [dependencies.bitvec] @@ -62,24 +62,29 @@ version = "1.0.1" optional = true [dependencies.byteorder] -version = "1.4.3" +version = "1.5.0" [dependencies.ctr] version = "0.9.2" optional = true [dependencies.fiat-crypto] -version = "0.2.1" +version = "0.2.6" optional = true [dependencies.fixed] -version = "1.23" +version = "1.26" optional = true [dependencies.getrandom] -version = "0.2.10" +version = "0.2.12" features = ["std"] +[dependencies.hex] +version = "0.4.3" +features = ["serde"] +optional = true + [dependencies.hmac] version = "0.12.1" optional = true @@ -93,11 +98,11 @@ features = [ optional = true [dependencies.num-integer] -version = "0.1.45" +version = "0.1.46" optional = true [dependencies.num-iter] -version = "0.1.43" +version = "0.1.44" optional = true [dependencies.num-rational] @@ -106,7 +111,7 @@ features = ["serde"] optional = true [dependencies.num-traits] -version = "0.2.16" +version = "0.2.18" optional = true [dependencies.rand] @@ -117,15 +122,19 @@ optional = true version = "0.6.4" [dependencies.rayon] -version = "1.8.0" +version = "1.9.0" optional = true [dependencies.serde] version = "1.0" features = ["derive"] +[dependencies.serde_json] +version = "1.0" +optional = true + [dependencies.sha2] -version = "0.10.7" +version = "0.10.8" optional = true [dependencies.sha3] @@ -137,11 +146,15 @@ version = "2.5.0" [dependencies.thiserror] version = "1.0" +[dependencies.zipf] +version = "7.0.1" +optional = true + [dev-dependencies.assert_matches] version = "1.5.0" [dev-dependencies.base64] -version = "0.21.4" +version = "0.22.0" [dev-dependencies.cfg-if] version = "1.0.0" @@ -152,19 +165,12 @@ version = "0.5" [dev-dependencies.fixed-macro] version = "1.2.0" -[dev-dependencies.hex] -version = "0.4.3" -features = ["serde"] - [dev-dependencies.hex-literal] version = "0.4.1" [dev-dependencies.iai] version = "0.1" -[dev-dependencies.itertools] -version = "0.11.0" - [dev-dependencies.modinverse] version = "0.1.0" @@ -172,24 +178,20 @@ version = "0.1.0" version = "0.4.4" [dev-dependencies.once_cell] -version = "1.18.0" +version = "1.19.0" [dev-dependencies.rand] version = "0.8" -[dev-dependencies.serde_json] -version = "1.0" - [dev-dependencies.statrs] version = "0.16.0" -[dev-dependencies.zipf] -version = "7.0.1" - [features] crypto-dependencies = [ "aes", "ctr", + "hmac", + "sha2", ] default = ["crypto-dependencies"] experimental = [ @@ -204,9 +206,9 @@ experimental = [ "rand", ] multithreaded = ["rayon"] -prio2 = [ - "crypto-dependencies", - "hmac", - "sha2", +test-util = [ + "hex", + "rand", + "serde_json", + "zipf", ] -test-util = ["rand"] diff --git a/third_party/rust/prio/README.md b/third_party/rust/prio/README.md index b81a0150c2..b724eebfb1 100644 --- a/third_party/rust/prio/README.md +++ b/third_party/rust/prio/README.md @@ -1,8 +1,6 @@ # libprio-rs -[![Build Status]][actions] [![Latest Version]][crates.io] [![Docs badge]][docs.rs] +[![Latest Version]][crates.io] [![Docs badge]][docs.rs] -[Build Status]: https://github.com/divviup/libprio-rs/workflows/ci-build/badge.svg -[actions]: https://github.com/divviup/libprio-rs/actions?query=branch%3Amain [Latest Version]: https://img.shields.io/crates/v/prio.svg [crates.io]: https://crates.io/crates/prio [Docs badge]: https://img.shields.io/badge/docs.rs-rustdoc-green @@ -38,12 +36,13 @@ increases (e.g., 0.10 to 0.11). | ----- | ---------- | ------------- | ------------- | --------------------- | ------ | | 0.8 | `release/0.8` | [`draft-irtf-cfrg-vdaf-01`][vdaf-01] | [`draft-ietf-ppm-dap-01`][dap-01] | Yes | Unmaintained as of March 28, 2023 | | 0.9 | `release/0.9` | [`draft-irtf-cfrg-vdaf-03`][vdaf-03] | [`draft-ietf-ppm-dap-02`][dap-02] and [`draft-ietf-ppm-dap-03`][dap-03] | Yes | Unmaintained as of September 22, 2022 | -| 0.10 | `release/0.10` | [`draft-irtf-cfrg-vdaf-03`][vdaf-03] | [`draft-ietf-ppm-dap-02`][dap-02] and [`draft-ietf-ppm-dap-03`][dap-03] | Yes | Supported | +| 0.10 | `release/0.10` | [`draft-irtf-cfrg-vdaf-03`][vdaf-03] | [`draft-ietf-ppm-dap-02`][dap-02] and [`draft-ietf-ppm-dap-03`][dap-03] | Yes | Unmaintained as of November 14, 2023 | | 0.11 | `release/0.11` | [`draft-irtf-cfrg-vdaf-04`][vdaf-04] | N/A | Yes | Unmaintained | | 0.12 | `release/0.12` | [`draft-irtf-cfrg-vdaf-05`][vdaf-05] | [`draft-ietf-ppm-dap-04`][dap-04] | Yes | Supported | | 0.13 | `release/0.13` | [`draft-irtf-cfrg-vdaf-06`][vdaf-06] | [`draft-ietf-ppm-dap-05`][dap-05] | Yes | Unmaintained | | 0.14 | `release/0.14` | [`draft-irtf-cfrg-vdaf-06`][vdaf-06] | [`draft-ietf-ppm-dap-05`][dap-05] | Yes | Unmaintained | -| 0.15 | `main` | [`draft-irtf-cfrg-vdaf-07`][vdaf-07] | [`draft-ietf-ppm-dap-06`][dap-06] | Yes | Supported | +| 0.15 | `release/0.15` | [`draft-irtf-cfrg-vdaf-07`][vdaf-07] | [`draft-ietf-ppm-dap-07`][dap-07] | Yes | Supported | +| 0.16 | `main` | [`draft-irtf-cfrg-vdaf-08`][vdaf-08] | [`draft-ietf-ppm-dap-09`][dap-09] | Yes | Supported | [vdaf-01]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/01/ [vdaf-03]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/03/ @@ -51,12 +50,14 @@ increases (e.g., 0.10 to 0.11). [vdaf-05]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/05/ [vdaf-06]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/06/ [vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +[vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ [dap-01]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/01/ [dap-02]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/02/ [dap-03]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/03/ [dap-04]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/04/ [dap-05]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/05/ -[dap-06]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/06/ +[dap-07]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/07/ +[dap-09]: https://datatracker.ietf.org/doc/draft-ietf-ppm-dap/09/ [enpa]: https://www.abetterinternet.org/post/prio-services-for-covid-en/ [enpa-whitepaper]: https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ENPA_White_Paper.pdf [prio-server]: https://github.com/divviup/prio-server @@ -68,9 +69,11 @@ increases (e.g., 0.10 to 0.11). This crate defines the following feature flags: -|Name|Default feature?|Description| -|---|---|---| -|`crypto-dependencies`|Yes|Enables dependencies on various RustCrypto crates, and uses them to implement `XofShake128` to support VDAFs.| -|`experimental`|No|Certain experimental APIs are guarded by this feature. They may undergo breaking changes in future patch releases, as an exception to semantic versioning.| -|`multithreaded`|No|Enables certain Prio3 VDAF implementations that use `rayon` for parallelization of gadget evaluations.| -|`prio2`|No|Enables the Prio v2 API, and a VDAF based on the Prio2 system.| +|Name|Default feature?|Description|Semver stable?| +|---|---|---|---| +|`crypto-dependencies`|Yes|Enables dependencies on various RustCrypto crates, and uses them to implement `XofTurboShake128` to support VDAFs.|✅| +|`experimental`|No|Certain experimental APIs are guarded by this feature.|❌| +|`multithreaded`|No|Enables certain Prio3 VDAF implementations that use `rayon` for parallelization of gadget evaluations.|✅| +|`test-util`|No|Enables test utilities for VDAF users and VDAF implementers.|❌| + +Features that are not marked as "Semver stable" may undergo breaking changes in future patch releases, as an exception to semantic versioning. diff --git a/third_party/rust/prio/benches/cycle_counts.rs b/third_party/rust/prio/benches/cycle_counts.rs index 43a4ccdad0..5ab704cd44 100644 --- a/third_party/rust/prio/benches/cycle_counts.rs +++ b/third_party/rust/prio/benches/cycle_counts.rs @@ -5,15 +5,12 @@ use iai::black_box; #[cfg(feature = "experimental")] use prio::{ codec::{Decode, Encode, ParameterizedDecode}, - field::{Field255, FieldElement}, + field::{Field255, FieldElement, FieldPrio2}, idpf::{Idpf, IdpfInput, IdpfPublicShare, RingBufferCache}, - vdaf::{poplar1::Poplar1IdpfValue, xof::Seed}, -}; -#[cfg(feature = "prio2")] -use prio::{ - field::FieldPrio2, vdaf::{ + poplar1::Poplar1IdpfValue, prio2::{Prio2, Prio2PrepareShare}, + xof::Seed, Aggregator, Share, }, }; @@ -45,7 +42,7 @@ fn prng_4096() -> Vec { prng(4096) } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_client(size: usize) -> Vec> { let prio2 = Prio2::new(size).unwrap(); let input = vec![0u32; size]; @@ -53,22 +50,22 @@ fn prio2_client(size: usize) -> Vec> { prio2.shard(&black_box(input), &black_box(nonce)).unwrap().1 } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_client_10() -> Vec> { prio2_client(10) } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_client_100() -> Vec> { prio2_client(100) } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_client_1000() -> Vec> { prio2_client(1000) } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_shard_and_prepare(size: usize) -> Prio2PrepareShare { let prio2 = Prio2::new(size).unwrap(); let input = vec![0u32; size]; @@ -80,24 +77,24 @@ fn prio2_shard_and_prepare(size: usize) -> Prio2PrepareShare { .1 } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_shard_and_prepare_10() -> Prio2PrepareShare { prio2_shard_and_prepare(10) } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_shard_and_prepare_100() -> Prio2PrepareShare { prio2_shard_and_prepare(100) } -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2_shard_and_prepare_1000() -> Prio2PrepareShare { prio2_shard_and_prepare(1000) } fn prio3_client_count() -> Vec> { let prio3 = Prio3::new_count(2).unwrap(); - let measurement = 1; + let measurement = true; let nonce = [0; 16]; prio3 .shard(&black_box(measurement), &black_box(nonce)) @@ -241,7 +238,7 @@ fn idpf_codec() { .unwrap(); let bits = 4; let public_share = IdpfPublicShare::, Poplar1IdpfValue>::get_decoded_with_param(&bits, &data).unwrap(); - let encoded = public_share.get_encoded(); + let encoded = public_share.get_encoded().unwrap(); let _ = black_box(encoded.len()); } @@ -261,34 +258,10 @@ macro_rules! main_base { }; } -#[cfg(feature = "prio2")] -macro_rules! main_add_prio2 { - ( $( $func_name:ident ),* $(,)* ) => { - main_base!( - prio2_client_10, - prio2_client_100, - prio2_client_1000, - prio2_shard_and_prepare_10, - prio2_shard_and_prepare_100, - prio2_shard_and_prepare_1000, - $( $func_name, )* - ); - }; -} - -#[cfg(not(feature = "prio2"))] -macro_rules! main_add_prio2 { - ( $( $func_name:ident ),* $(,)* ) => { - main_base!( - $( $func_name, )* - ); - }; -} - #[cfg(feature = "multithreaded")] macro_rules! main_add_multithreaded { ( $( $func_name:ident ),* $(,)* ) => { - main_add_prio2!( + main_base!( prio3_client_count_vec_multithreaded_1000, $( $func_name, )* ); @@ -298,7 +271,7 @@ macro_rules! main_add_multithreaded { #[cfg(not(feature = "multithreaded"))] macro_rules! main_add_multithreaded { ( $( $func_name:ident ),* $(,)* ) => { - main_add_prio2!( + main_base!( $( $func_name, )* ); }; @@ -308,6 +281,12 @@ macro_rules! main_add_multithreaded { macro_rules! main_add_experimental { ( $( $func_name:ident ),* $(,)* ) => { main_add_multithreaded!( + prio2_client_10, + prio2_client_100, + prio2_client_1000, + prio2_shard_and_prepare_10, + prio2_shard_and_prepare_100, + prio2_shard_and_prepare_1000, idpf_codec, idpf_poplar_gen_8, idpf_poplar_gen_128, diff --git a/third_party/rust/prio/benches/speed_tests.rs b/third_party/rust/prio/benches/speed_tests.rs index 66458b1ada..d90085a74d 100644 --- a/third_party/rust/prio/benches/speed_tests.rs +++ b/third_party/rust/prio/benches/speed_tests.rs @@ -15,7 +15,9 @@ use num_rational::Ratio; use num_traits::ToPrimitive; #[cfg(feature = "experimental")] use prio::dp::distributions::DiscreteGaussian; -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] +use prio::idpf::test_utils::generate_zipf_distributed_batch; +#[cfg(feature = "experimental")] use prio::vdaf::prio2::Prio2; use prio::{ benchmarked::*, @@ -35,8 +37,6 @@ use rand::prelude::*; #[cfg(feature = "experimental")] use std::iter; use std::time::Duration; -#[cfg(feature = "experimental")] -use zipf::ZipfDistribution; /// Seed for generation of random benchmark inputs. /// @@ -116,7 +116,7 @@ fn poly_mul(c: &mut Criterion) { } /// Benchmark prio2. -#[cfg(feature = "prio2")] +#[cfg(feature = "experimental")] fn prio2(c: &mut Criterion) { let mut group = c.benchmark_group("prio2_shard"); for input_length in [10, 100, 1_000] { @@ -164,14 +164,14 @@ fn prio3(c: &mut Criterion) { c.bench_function("prio3count_shard", |b| { let vdaf = Prio3::new_count(num_shares).unwrap(); - let measurement = black_box(1); + let measurement = black_box(true); let nonce = black_box([0u8; 16]); b.iter(|| vdaf.shard(&measurement, &nonce).unwrap()); }); c.bench_function("prio3count_prepare_init", |b| { let vdaf = Prio3::new_count(num_shares).unwrap(); - let measurement = black_box(1); + let measurement = black_box(true); let nonce = black_box([0u8; 16]); let verify_key = black_box([0u8; 16]); let (public_share, input_shares) = vdaf.shard(&measurement, &nonce).unwrap(); @@ -712,7 +712,7 @@ fn poplar1(c: &mut Criterion) { for size in test_sizes.iter() { group.throughput(Throughput::Bytes(*size as u64 / 8)); group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| { - let vdaf = Poplar1::new_shake128(size); + let vdaf = Poplar1::new_turboshake128(size); let mut rng = StdRng::seed_from_u64(RNG_SEED); let nonce = rng.gen::<[u8; 16]>(); @@ -736,7 +736,7 @@ fn poplar1(c: &mut Criterion) { for size in test_sizes.iter() { group.measurement_time(Duration::from_secs(30)); // slower benchmark group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| { - let vdaf = Poplar1::new_shake128(size); + let vdaf = Poplar1::new_turboshake128(size); let mut rng = StdRng::seed_from_u64(RNG_SEED); b.iter_batched( @@ -746,7 +746,7 @@ fn poplar1(c: &mut Criterion) { // Parameters are chosen to match Chris Wood's experimental setup: // https://github.com/chris-wood/heavy-hitter-comparison - let (measurements, prefix_tree) = poplar1_generate_zipf_distributed_batch( + let (measurements, prefix_tree) = generate_zipf_distributed_batch( &mut rng, // rng size, // bits 10, // threshold @@ -794,83 +794,54 @@ fn poplar1(c: &mut Criterion) { group.finish(); } -/// Generate a set of Poplar1 measurements with the given bit length `bits`. They are sampled -/// according to the Zipf distribution with parameters `zipf_support` and `zipf_exponent`. Return -/// the measurements, along with the prefix tree for the desired threshold. -/// -/// The prefix tree consists of a sequence of candidate prefixes for each level. For a given level, -/// the candidate prefixes are computed from the hit counts of the prefixes at the previous level: -/// For any prefix `p` whose hit count is at least the desired threshold, add `p || 0` and `p || 1` -/// to the list. +/// Benchmark VIDPF performance. #[cfg(feature = "experimental")] -fn poplar1_generate_zipf_distributed_batch( - rng: &mut impl Rng, - bits: usize, - threshold: usize, - measurement_count: usize, - zipf_support: usize, - zipf_exponent: f64, -) -> (Vec, Vec>) { - // Generate random inputs. - let mut inputs = Vec::with_capacity(zipf_support); - for _ in 0..zipf_support { - let bools: Vec = (0..bits).map(|_| rng.gen()).collect(); - inputs.push(IdpfInput::from_bools(&bools)); - } +fn vidpf(c: &mut Criterion) { + use prio::vidpf::{Vidpf, VidpfInput, VidpfWeight}; - // Sample a number of inputs according to the Zipf distribution. - let mut samples = Vec::with_capacity(measurement_count); - let zipf = ZipfDistribution::new(zipf_support, zipf_exponent).unwrap(); - for _ in 0..measurement_count { - samples.push(inputs[zipf.sample(rng) - 1].clone()); - } + let test_sizes = [8usize, 8 * 16, 8 * 256]; + const NONCE_SIZE: usize = 16; + const NONCE: &[u8; NONCE_SIZE] = b"Test Nonce VIDPF"; - // Compute the prefix tree for the desired threshold. - let mut prefix_tree = Vec::with_capacity(bits); - prefix_tree.push(vec![ - IdpfInput::from_bools(&[false]), - IdpfInput::from_bools(&[true]), - ]); - - for level in 0..bits - 1 { - // Compute the hit count of each prefix from the previous level. - let mut hit_counts = vec![0; prefix_tree[level].len()]; - for (hit_count, prefix) in hit_counts.iter_mut().zip(prefix_tree[level].iter()) { - for sample in samples.iter() { - let mut is_prefix = true; - for j in 0..prefix.len() { - if prefix[j] != sample[j] { - is_prefix = false; - break; - } - } - if is_prefix { - *hit_count += 1; - } - } - } + let mut group = c.benchmark_group("vidpf_gen"); + for size in test_sizes.iter() { + group.throughput(Throughput::Bytes(*size as u64 / 8)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| { + let bits = iter::repeat_with(random).take(size).collect::>(); + let input = VidpfInput::from_bools(&bits); + let weight = VidpfWeight::from(vec![Field255::one(), Field255::one()]); - // Compute the next set of candidate prefixes. - let mut next_prefixes = Vec::new(); - for (hit_count, prefix) in hit_counts.iter().zip(prefix_tree[level].iter()) { - if *hit_count >= threshold { - next_prefixes.push(prefix.clone_with_suffix(&[false])); - next_prefixes.push(prefix.clone_with_suffix(&[true])); - } - } - prefix_tree.push(next_prefixes); + let vidpf = Vidpf::, NONCE_SIZE>::new(2); + + b.iter(|| { + let _ = vidpf.gen(&input, &weight, NONCE).unwrap(); + }); + }); } + group.finish(); - (samples, prefix_tree) + let mut group = c.benchmark_group("vidpf_eval"); + for size in test_sizes.iter() { + group.throughput(Throughput::Bytes(*size as u64 / 8)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| { + let bits = iter::repeat_with(random).take(size).collect::>(); + let input = VidpfInput::from_bools(&bits); + let weight = VidpfWeight::from(vec![Field255::one(), Field255::one()]); + let vidpf = Vidpf::, NONCE_SIZE>::new(2); + + let (public, keys) = vidpf.gen(&input, &weight, NONCE).unwrap(); + + b.iter(|| { + let _ = vidpf.eval(&keys[0], &public, &input, NONCE).unwrap(); + }); + }); + } + group.finish(); } -#[cfg(all(feature = "prio2", feature = "experimental"))] -criterion_group!(benches, poplar1, prio3, prio2, poly_mul, prng, idpf, dp_noise); -#[cfg(all(not(feature = "prio2"), feature = "experimental"))] -criterion_group!(benches, poplar1, prio3, poly_mul, prng, idpf, dp_noise); -#[cfg(all(feature = "prio2", not(feature = "experimental")))] -criterion_group!(benches, prio3, prio2, prng, poly_mul); -#[cfg(all(not(feature = "prio2"), not(feature = "experimental")))] +#[cfg(feature = "experimental")] +criterion_group!(benches, poplar1, prio3, prio2, poly_mul, prng, idpf, dp_noise, vidpf); +#[cfg(not(feature = "experimental"))] criterion_group!(benches, prio3, prng, poly_mul); criterion_main!(benches); diff --git a/third_party/rust/prio/documentation/field_parameters.sage b/third_party/rust/prio/documentation/field_parameters.sage new file mode 100755 index 0000000000..b83505baac --- /dev/null +++ b/third_party/rust/prio/documentation/field_parameters.sage @@ -0,0 +1,117 @@ +#!/usr/bin/env sage + +# This file recomputes the values in src/fp.rs for each FFT-friendly finite +# field. + +import pprint + + +class Field: + # The name of the field. + name: str + + # The prime modulus that defines the field. + modulus: Integer + + # A generator element that generates a large subgroup with an order that's + # a power of two. This is _not_ in Montgomery representation. + generator_element: Integer + + # The base 2 logarithm of the order of the FFT-friendly multiplicative + # subgroup. The generator element will be a 2^num_roots-th root of unity. + num_roots: Integer + + def __init__(self, name, modulus, generator_element): + assert is_prime(modulus) + self.name = name + self.modulus = modulus + self.generator_element = generator_element + + self.num_roots = None + for (prime, power) in factor(modulus - 1): + if prime == 2: + self.num_roots = power + break + else: + raise Exception( + "Multiplicative subgroup order is not a multiple of two" + ) + + def mu(self): + """ + Computes mu, a constant used during multiplication. It is defined by + mu = (-p)^-1 mod r, where r is the modulus implicitly used in wrapping + machine word operations. + """ + r = 2 ^ 64 + return (-self.modulus).inverse_mod(r) + + def r2(self): + """ + Computes R^2 mod p. This constant is used when converting into + Montgomery representation. R is the machine word-friendly modulus + used in the Montgomery representation. + """ + R = 2 ^ 128 + return R ^ 2 % self.modulus + + def to_montgomery(self, element): + """ + Transforms an element into its Montgomery representation. + """ + R = 2 ^ 128 + return element * R % self.modulus + + def bit_mask(self): + """ + An integer with the same bit length as the prime modulus, but with all + bits set. + """ + return 2 ^ (self.modulus.nbits()) - 1 + + def roots(self): + """ + Returns a list of roots of unity, in Montgomery representation. The + value at index i is a 2^i-th root of unity. Note that the first array + element will thus be the Montgomery representation of one. + """ + return [ + self.to_montgomery( + pow( + self.generator_element, + 2 ^ (self.num_roots - i), + self.modulus, + ) + ) + for i in range(min(self.num_roots, 20) + 1) + ] + + +FIELDS = [ + Field( + "FieldPrio2", + 2 ^ 20 * 4095 + 1, + 3925978153, + ), + Field( + "Field64", + 2 ^ 32 * 4294967295 + 1, + pow(7, 4294967295, 2 ^ 32 * 4294967295 + 1), + ), + Field( + "Field128", + 2 ^ 66 * 4611686018427387897 + 1, + pow(7, 4611686018427387897, 2 ^ 66 * 4611686018427387897 + 1), + ), +] +for field in FIELDS: + print(field.name) + print(f"p: {field.modulus}") + print(f"mu: {field.mu()}") + print(f"r2: {field.r2()}") + print(f"g: {field.to_montgomery(field.generator_element)}") + print(f"num_roots: {field.num_roots}") + print(f"bit_mask: {field.bit_mask()}") + print("roots:") + pprint.pprint(field.roots()) + print() diff --git a/third_party/rust/prio/src/codec.rs b/third_party/rust/prio/src/codec.rs index 71f4f8ce5f..98e6299abd 100644 --- a/third_party/rust/prio/src/codec.rs +++ b/third_party/rust/prio/src/codec.rs @@ -20,6 +20,7 @@ use std::{ /// An error that occurred during decoding. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum CodecError { /// An I/O error. #[error("I/O error")] @@ -33,6 +34,10 @@ pub enum CodecError { #[error("length prefix of encoded vector overflows buffer: {0}")] LengthPrefixTooBig(usize), + /// The byte length of a vector exceeded the range of its length prefix. + #[error("vector length exceeded range of length prefix")] + LengthPrefixOverflow, + /// Custom errors from [`Decode`] implementations. #[error("other error: {0}")] Other(#[source] Box), @@ -97,10 +102,10 @@ impl ParameterizedDecode for D { /// Describes how to encode objects into a byte sequence. pub trait Encode { /// Append the encoded form of this object to the end of `bytes`, growing the vector as needed. - fn encode(&self, bytes: &mut Vec); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError>; /// Convenience method to encode a value into a new `Vec`. - fn get_encoded(&self) -> Vec { + fn get_encoded(&self) -> Result, CodecError> { self.get_encoded_with_param(&()) } @@ -116,17 +121,21 @@ pub trait ParameterizedEncode

    { /// Append the encoded form of this object to the end of `bytes`, growing the vector as needed. /// `encoding_parameter` provides details of the wire encoding, used to control how the value /// is encoded. - fn encode_with_param(&self, encoding_parameter: &P, bytes: &mut Vec); + fn encode_with_param( + &self, + encoding_parameter: &P, + bytes: &mut Vec, + ) -> Result<(), CodecError>; /// Convenience method to encode a value into a new `Vec`. - fn get_encoded_with_param(&self, encoding_parameter: &P) -> Vec { + fn get_encoded_with_param(&self, encoding_parameter: &P) -> Result, CodecError> { let mut ret = if let Some(length) = self.encoded_len_with_param(encoding_parameter) { Vec::with_capacity(length) } else { Vec::new() }; - self.encode_with_param(encoding_parameter, &mut ret); - ret + self.encode_with_param(encoding_parameter, &mut ret)?; + Ok(ret) } /// Returns an optional hint indicating how many bytes will be required to encode this value, or @@ -139,7 +148,11 @@ pub trait ParameterizedEncode

    { /// Provide a blanket implementation so that any [`Encode`] can be used as a /// `ParameterizedEncode` for any `T`. impl ParameterizedEncode for E { - fn encode_with_param(&self, _encoding_parameter: &T, bytes: &mut Vec) { + fn encode_with_param( + &self, + _encoding_parameter: &T, + bytes: &mut Vec, + ) -> Result<(), CodecError> { self.encode(bytes) } @@ -155,7 +168,9 @@ impl Decode for () { } impl Encode for () { - fn encode(&self, _bytes: &mut Vec) {} + fn encode(&self, _bytes: &mut Vec) -> Result<(), CodecError> { + Ok(()) + } fn encoded_len(&self) -> Option { Some(0) @@ -171,8 +186,9 @@ impl Decode for u8 { } impl Encode for u8 { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { bytes.push(*self); + Ok(()) } fn encoded_len(&self) -> Option { @@ -187,8 +203,9 @@ impl Decode for u16 { } impl Encode for u16 { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { bytes.extend_from_slice(&u16::to_be_bytes(*self)); + Ok(()) } fn encoded_len(&self) -> Option { @@ -208,9 +225,10 @@ impl Decode for U24 { } impl Encode for U24 { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { // Encode lower three bytes of the u32 as u24 bytes.extend_from_slice(&u32::to_be_bytes(self.0)[1..]); + Ok(()) } fn encoded_len(&self) -> Option { @@ -225,8 +243,9 @@ impl Decode for u32 { } impl Encode for u32 { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { bytes.extend_from_slice(&u32::to_be_bytes(*self)); + Ok(()) } fn encoded_len(&self) -> Option { @@ -241,8 +260,9 @@ impl Decode for u64 { } impl Encode for u64 { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { bytes.extend_from_slice(&u64::to_be_bytes(*self)); + Ok(()) } fn encoded_len(&self) -> Option { @@ -257,18 +277,19 @@ pub fn encode_u8_items>( bytes: &mut Vec, encoding_parameter: &P, items: &[E], -) { +) -> Result<(), CodecError> { // Reserve space to later write length let len_offset = bytes.len(); bytes.push(0); for item in items { - item.encode_with_param(encoding_parameter, bytes); + item.encode_with_param(encoding_parameter, bytes)?; } - let len = bytes.len() - len_offset - 1; - assert!(len <= usize::from(u8::MAX)); - bytes[len_offset] = len as u8; + let len = + u8::try_from(bytes.len() - len_offset - 1).map_err(|_| CodecError::LengthPrefixOverflow)?; + bytes[len_offset] = len; + Ok(()) } /// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of @@ -292,20 +313,19 @@ pub fn encode_u16_items>( bytes: &mut Vec, encoding_parameter: &P, items: &[E], -) { +) -> Result<(), CodecError> { // Reserve space to later write length let len_offset = bytes.len(); - 0u16.encode(bytes); + 0u16.encode(bytes)?; for item in items { - item.encode_with_param(encoding_parameter, bytes); + item.encode_with_param(encoding_parameter, bytes)?; } - let len = bytes.len() - len_offset - 2; - assert!(len <= usize::from(u16::MAX)); - for (offset, byte) in u16::to_be_bytes(len as u16).iter().enumerate() { - bytes[len_offset + offset] = *byte; - } + let len = u16::try_from(bytes.len() - len_offset - 2) + .map_err(|_| CodecError::LengthPrefixOverflow)?; + bytes[len_offset..len_offset + 2].copy_from_slice(&len.to_be_bytes()); + Ok(()) } /// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of @@ -330,20 +350,22 @@ pub fn encode_u24_items>( bytes: &mut Vec, encoding_parameter: &P, items: &[E], -) { +) -> Result<(), CodecError> { // Reserve space to later write length let len_offset = bytes.len(); - U24(0).encode(bytes); + U24(0).encode(bytes)?; for item in items { - item.encode_with_param(encoding_parameter, bytes); + item.encode_with_param(encoding_parameter, bytes)?; } - let len = bytes.len() - len_offset - 3; - assert!(len <= 0xffffff); - for (offset, byte) in u32::to_be_bytes(len as u32)[1..].iter().enumerate() { - bytes[len_offset + offset] = *byte; + let len = u32::try_from(bytes.len() - len_offset - 3) + .map_err(|_| CodecError::LengthPrefixOverflow)?; + if len > 0xffffff { + return Err(CodecError::LengthPrefixOverflow); } + bytes[len_offset..len_offset + 3].copy_from_slice(&len.to_be_bytes()[1..]); + Ok(()) } /// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of @@ -368,20 +390,19 @@ pub fn encode_u32_items>( bytes: &mut Vec, encoding_parameter: &P, items: &[E], -) { +) -> Result<(), CodecError> { // Reserve space to later write length let len_offset = bytes.len(); - 0u32.encode(bytes); + 0u32.encode(bytes)?; for item in items { - item.encode_with_param(encoding_parameter, bytes); + item.encode_with_param(encoding_parameter, bytes)?; } - let len = bytes.len() - len_offset - 4; - let len: u32 = len.try_into().expect("Length too large"); - for (offset, byte) in len.to_be_bytes().iter().enumerate() { - bytes[len_offset + offset] = *byte; - } + let len = u32::try_from(bytes.len() - len_offset - 4) + .map_err(|_| CodecError::LengthPrefixOverflow)?; + bytes[len_offset..len_offset + 4].copy_from_slice(&len.to_be_bytes()); + Ok(()) } /// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of @@ -432,6 +453,7 @@ fn decode_items>( #[cfg(test)] mod tests { + use std::io::ErrorKind; use super::*; use assert_matches::assert_matches; @@ -439,7 +461,7 @@ mod tests { #[test] fn encode_nothing() { let mut bytes = vec![]; - ().encode(&mut bytes); + ().encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), 0); } @@ -448,7 +470,7 @@ mod tests { let value = 100u8; let mut bytes = vec![]; - value.encode(&mut bytes); + value.encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), 1); let decoded = u8::decode(&mut Cursor::new(&bytes)).unwrap(); @@ -460,7 +482,7 @@ mod tests { let value = 1000u16; let mut bytes = vec![]; - value.encode(&mut bytes); + value.encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), 2); // Check endianness of encoding assert_eq!(bytes, vec![3, 232]); @@ -474,7 +496,7 @@ mod tests { let value = U24(1_000_000u32); let mut bytes = vec![]; - value.encode(&mut bytes); + value.encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), 3); // Check endianness of encoding assert_eq!(bytes, vec![15, 66, 64]); @@ -488,7 +510,7 @@ mod tests { let value = 134_217_728u32; let mut bytes = vec![]; - value.encode(&mut bytes); + value.encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), 4); // Check endianness of encoding assert_eq!(bytes, vec![8, 0, 0, 0]); @@ -502,7 +524,7 @@ mod tests { let value = 137_438_953_472u64; let mut bytes = vec![]; - value.encode(&mut bytes); + value.encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), 8); // Check endianness of encoding assert_eq!(bytes, vec![0, 0, 0, 32, 0, 0, 0, 0]); @@ -521,12 +543,12 @@ mod tests { } impl Encode for TestMessage { - fn encode(&self, bytes: &mut Vec) { - self.field_u8.encode(bytes); - self.field_u16.encode(bytes); - self.field_u24.encode(bytes); - self.field_u32.encode(bytes); - self.field_u64.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.field_u8.encode(bytes)?; + self.field_u16.encode(bytes)?; + self.field_u24.encode(bytes)?; + self.field_u32.encode(bytes)?; + self.field_u64.encode(bytes) } fn encoded_len(&self) -> Option { @@ -584,7 +606,7 @@ mod tests { }; let mut bytes = vec![]; - value.encode(&mut bytes); + value.encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), TestMessage::encoded_length()); assert_eq!(value.encoded_len().unwrap(), TestMessage::encoded_length()); @@ -622,7 +644,7 @@ mod tests { fn roundtrip_variable_length_u8() { let values = messages_vec(); let mut bytes = vec![]; - encode_u8_items(&mut bytes, &(), &values); + encode_u8_items(&mut bytes, &(), &values).unwrap(); assert_eq!( bytes.len(), @@ -640,7 +662,7 @@ mod tests { fn roundtrip_variable_length_u16() { let values = messages_vec(); let mut bytes = vec![]; - encode_u16_items(&mut bytes, &(), &values); + encode_u16_items(&mut bytes, &(), &values).unwrap(); assert_eq!( bytes.len(), @@ -661,7 +683,7 @@ mod tests { fn roundtrip_variable_length_u24() { let values = messages_vec(); let mut bytes = vec![]; - encode_u24_items(&mut bytes, &(), &values); + encode_u24_items(&mut bytes, &(), &values).unwrap(); assert_eq!( bytes.len(), @@ -682,7 +704,7 @@ mod tests { fn roundtrip_variable_length_u32() { let values = messages_vec(); let mut bytes = Vec::new(); - encode_u32_items(&mut bytes, &(), &values); + encode_u32_items(&mut bytes, &(), &values).unwrap(); assert_eq!(bytes.len(), 4 + 3 * TestMessage::encoded_length()); @@ -696,6 +718,21 @@ mod tests { assert_eq!(values, decoded); } + #[test] + fn decode_too_short() { + let values = messages_vec(); + let mut bytes = Vec::new(); + encode_u32_items(&mut bytes, &(), &values).unwrap(); + + let error = + decode_u32_items::<_, TestMessage>(&(), &mut Cursor::new(&bytes[..3])).unwrap_err(); + assert_matches!(error, CodecError::Io(e) => assert_eq!(e.kind(), ErrorKind::UnexpectedEof)); + + let error = + decode_u32_items::<_, TestMessage>(&(), &mut Cursor::new(&bytes[..4])).unwrap_err(); + assert_matches!(error, CodecError::LengthPrefixTooBig(_)); + } + #[test] fn decode_items_overflow() { let encoded = vec![1u8]; @@ -724,11 +761,56 @@ mod tests { #[test] fn length_hint_correctness() { - assert_eq!(().encoded_len().unwrap(), ().get_encoded().len()); - assert_eq!(0u8.encoded_len().unwrap(), 0u8.get_encoded().len()); - assert_eq!(0u16.encoded_len().unwrap(), 0u16.get_encoded().len()); - assert_eq!(U24(0).encoded_len().unwrap(), U24(0).get_encoded().len()); - assert_eq!(0u32.encoded_len().unwrap(), 0u32.get_encoded().len()); - assert_eq!(0u64.encoded_len().unwrap(), 0u64.get_encoded().len()); + assert_eq!(().encoded_len().unwrap(), ().get_encoded().unwrap().len()); + assert_eq!(0u8.encoded_len().unwrap(), 0u8.get_encoded().unwrap().len()); + assert_eq!( + 0u16.encoded_len().unwrap(), + 0u16.get_encoded().unwrap().len() + ); + assert_eq!( + U24(0).encoded_len().unwrap(), + U24(0).get_encoded().unwrap().len() + ); + assert_eq!( + 0u32.encoded_len().unwrap(), + 0u32.get_encoded().unwrap().len() + ); + assert_eq!( + 0u64.encoded_len().unwrap(), + 0u64.get_encoded().unwrap().len() + ); + } + + #[test] + fn get_decoded_leftover() { + let encoded_good = [1, 2, 3, 4]; + assert_matches!(u32::get_decoded(&encoded_good).unwrap(), 0x01020304u32); + + let encoded_bad = [1, 2, 3, 4, 5]; + let error = u32::get_decoded(&encoded_bad).unwrap_err(); + assert_matches!(error, CodecError::BytesLeftOver(1)); + } + + #[test] + fn encoded_len_backwards_compatibility() { + struct MyMessage; + + impl Encode for MyMessage { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + bytes.extend_from_slice(b"Hello, world"); + Ok(()) + } + } + + assert_eq!(MyMessage.encoded_len(), None); + + assert_eq!(MyMessage.get_encoded().unwrap(), b"Hello, world"); + } + + #[test] + fn encode_length_prefix_overflow() { + let mut bytes = Vec::new(); + let error = encode_u8_items(&mut bytes, &(), &[1u8; u8::MAX as usize + 1]).unwrap_err(); + assert_matches!(error, CodecError::LengthPrefixOverflow); } } diff --git a/third_party/rust/prio/src/dp.rs b/third_party/rust/prio/src/dp.rs index 506676dbb9..6ed4f2afdf 100644 --- a/third_party/rust/prio/src/dp.rs +++ b/third_party/rust/prio/src/dp.rs @@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize}; /// Errors propagated by methods in this module. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum DpError { /// Tried to use an invalid float as privacy parameter. #[error( diff --git a/third_party/rust/prio/src/dp/distributions.rs b/third_party/rust/prio/src/dp/distributions.rs index ba0270df9c..5fc42f96ec 100644 --- a/third_party/rust/prio/src/dp/distributions.rs +++ b/third_party/rust/prio/src/dp/distributions.rs @@ -292,7 +292,7 @@ mod tests { use super::*; use crate::dp::Rational; - use crate::vdaf::xof::SeedStreamSha3; + use crate::vdaf::xof::SeedStreamTurboShake128; use num_bigint::{BigUint, Sign, ToBigInt, ToBigUint}; use num_traits::{One, Signed, ToPrimitive}; @@ -306,15 +306,15 @@ mod tests { DiscreteGaussian::new(Ratio::::from_integer(BigUint::from(5u8))).unwrap(); // check samples are consistent - let mut rng = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]); let samples: Vec = (0..10) .map(|_| i8::try_from(sampler.sample(&mut rng)).unwrap()) .collect(); let samples1: Vec = (0..10) .map(|_| i8::try_from(sampler.sample(&mut rng)).unwrap()) .collect(); - assert_eq!(samples, vec![-3, -11, -3, 5, 1, 5, 2, 2, 1, 18]); - assert_eq!(samples1, vec![4, -4, -5, -2, 0, -5, -3, 1, 1, -2]); + assert_eq!(samples, vec![0, -3, -2, 3, 2, -1, -5, 4, -7, -5]); + assert_eq!(samples1, vec![2, 7, -8, -3, 1, -3, -3, 6, -3, -1]); } #[test] @@ -325,7 +325,7 @@ mod tests { // sample from a manually created distribution let sampler1 = DiscreteGaussian::new(Ratio::::from_integer(BigUint::from(4u8))).unwrap(); - let mut rng = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]); let samples1: Vec = (0..10) .map(|_| i8::try_from(sampler1.sample(&mut rng)).unwrap()) .collect(); @@ -337,7 +337,7 @@ mod tests { let sampler2 = zcdp .create_distribution(Ratio::::from_integer(1u8.into())) .unwrap(); - let mut rng2 = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng2 = SeedStreamTurboShake128::from_seed([0u8; 16]); let samples2: Vec = (0..10) .map(|_| i8::try_from(sampler2.sample(&mut rng2)).unwrap()) .collect(); @@ -485,7 +485,7 @@ mod tests { .unwrap(); // collect that number of samples - let mut rng = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]); let samples: Vec = (1..n_samples) .map(|_| { sample_discrete_gaussian(&Ratio::::from_integer(sigma.clone()), &mut rng) @@ -519,7 +519,7 @@ mod tests { #[test] fn empirical_test_gauss() { [100, 2000, 20000].iter().for_each(|p| { - let mut rng = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]); let sampler = || { sample_discrete_gaussian( &Ratio::::from_integer((*p).to_biguint().unwrap()), @@ -541,7 +541,7 @@ mod tests { #[test] fn empirical_test_bernoulli_mean() { [2u8, 5u8, 7u8, 9u8].iter().for_each(|p| { - let mut rng = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]); let sampler = || { if sample_bernoulli( &Ratio::::new(BigUint::one(), (*p).into()), @@ -565,7 +565,7 @@ mod tests { #[test] fn empirical_test_geometric_mean() { [2u8, 5u8, 7u8, 9u8].iter().for_each(|p| { - let mut rng = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]); let sampler = || { sample_geometric_exp( &Ratio::::new(BigUint::one(), (*p).into()), @@ -588,7 +588,7 @@ mod tests { #[test] fn empirical_test_laplace_mean() { [2u8, 5u8, 7u8, 9u8].iter().for_each(|p| { - let mut rng = SeedStreamSha3::from_seed([0u8; 16]); + let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]); let sampler = || { sample_discrete_laplace( &Ratio::::new(BigUint::one(), (*p).into()), diff --git a/third_party/rust/prio/src/fft.rs b/third_party/rust/prio/src/fft.rs index cac59a89ea..612013eb45 100644 --- a/third_party/rust/prio/src/fft.rs +++ b/third_party/rust/prio/src/fft.rs @@ -10,6 +10,7 @@ use std::convert::TryFrom; /// An error returned by an FFT operation. #[derive(Debug, PartialEq, Eq, thiserror::Error)] +#[non_exhaustive] pub enum FftError { /// The output is too small. #[error("output slice is smaller than specified size")] diff --git a/third_party/rust/prio/src/field.rs b/third_party/rust/prio/src/field.rs index fb931de2d3..e6cd5c105d 100644 --- a/third_party/rust/prio/src/field.rs +++ b/third_party/rust/prio/src/field.rs @@ -7,7 +7,6 @@ //! [`FftFriendlyFieldElement`], and have an associated element called the "generator" that //! generates a multiplicative subgroup of order `2^n` for some `n`. -#[cfg(feature = "crypto-dependencies")] use crate::prng::{Prng, PrngError}; use crate::{ codec::{CodecError, Decode, Encode}, @@ -25,8 +24,8 @@ use std::{ io::{Cursor, Read}, marker::PhantomData, ops::{ - Add, AddAssign, BitAnd, ControlFlow, Div, DivAssign, Mul, MulAssign, Neg, Shl, Shr, Sub, - SubAssign, + Add, AddAssign, BitAnd, ControlFlow, Div, DivAssign, Mul, MulAssign, Neg, Range, Shl, Shr, + Sub, SubAssign, }, }; use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq}; @@ -39,6 +38,7 @@ pub use field255::Field255; /// Possible errors from finite field operations. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum FieldError { /// Input sizes do not match. #[error("input sizes do not match")] @@ -46,19 +46,24 @@ pub enum FieldError { /// Returned when decoding a [`FieldElement`] from a too-short byte string. #[error("short read from bytes")] ShortRead, - /// Returned when decoding a [`FieldElement`] from a byte string that encodes an integer greater - /// than or equal to the field modulus. - #[error("read from byte slice exceeds modulus")] + /// Returned when converting an integer to a [`FieldElement`] if the integer is greater than or + /// equal to the field modulus. + #[error("input value exceeds modulus")] ModulusOverflow, /// Error while performing I/O. #[error("I/O error")] Io(#[from] std::io::Error), /// Error encoding or decoding a field. #[error("Codec error")] - Codec(#[from] CodecError), + #[deprecated] + Codec(CodecError), /// Error converting to [`FieldElementWithInteger::Integer`]. #[error("Integer TryFrom error")] IntegerTryFrom, + /// Returned when encoding an integer to "bitvector representation", or decoding from the same, + /// if the number of bits is larger than the bit length of the field's modulus. + #[error("bit vector length exceeds modulus bit length")] + BitVectorTooLong, } /// Objects with this trait represent an element of `GF(p)` for some prime `p`. @@ -100,8 +105,8 @@ pub trait FieldElement: fn inv(&self) -> Self; /// Interprets the next [`Self::ENCODED_SIZE`] bytes from the input slice as an element of the - /// field. The `m` most significant bits are cleared, where `m` is equal to the length of - /// [`Self::Integer`] in bits minus the length of the modulus in bits. + /// field. Any of the most significant bits beyond the bit length of the modulus will be + /// cleared, in order to minimize the amount of rejection sampling needed. /// /// # Errors /// @@ -110,9 +115,9 @@ pub trait FieldElement: /// /// # Warnings /// - /// This function should only be used within [`prng::Prng`] to convert a random byte string into - /// a field element. Use [`Self::decode`] to deserialize field elements. Use - /// [`field::rand`] or [`prng::Prng`] to randomly generate field elements. + /// This function should only be used internally to convert a random byte string into + /// a field element. Use [`Decode::decode`] to deserialize field elements. Use + /// [`random_vector`] to randomly generate field elements. #[doc(hidden)] fn try_from_random(bytes: &[u8]) -> Result; @@ -129,9 +134,10 @@ pub trait FieldElement: /// Ideally we would implement `From<&[F: FieldElement]> for Vec` or the corresponding /// `Into`, but the orphan rule and the stdlib's blanket implementations of `Into` make this /// impossible. + #[deprecated] fn slice_into_byte_vec(values: &[Self]) -> Vec { let mut vec = Vec::with_capacity(values.len() * Self::ENCODED_SIZE); - encode_fieldvec(values, &mut vec); + encode_fieldvec(values, &mut vec).unwrap(); vec } @@ -149,18 +155,49 @@ pub trait FieldElement: /// Ideally we would implement `From<&[u8]> for Vec` or the corresponding /// `Into`, but the orphan rule and the stdlib's blanket implementations of `Into` make this /// impossible. + #[deprecated] fn byte_slice_into_vec(bytes: &[u8]) -> Result, FieldError> { if bytes.len() % Self::ENCODED_SIZE != 0 { return Err(FieldError::ShortRead); } let mut vec = Vec::with_capacity(bytes.len() / Self::ENCODED_SIZE); for chunk in bytes.chunks_exact(Self::ENCODED_SIZE) { - vec.push(Self::get_decoded(chunk)?); + #[allow(deprecated)] + vec.push(Self::get_decoded(chunk).map_err(FieldError::Codec)?); } Ok(vec) } } +/// An integer type that accompanies a finite field. Integers and field elements may be converted +/// back and forth via the natural map between residue classes modulo 'p' and integers between 0 +/// and p - 1. +pub trait Integer: + Debug + + Eq + + Ord + + BitAnd + + Div + + Shl + + Shr + + Add + + Sub + + TryFrom + + TryInto +{ + /// The error returned if converting `usize` to this integer type fails. + type TryFromUsizeError: std::error::Error; + + /// The error returned if converting this integer type to a `u64` fails. + type TryIntoU64Error: std::error::Error; + + /// Returns zero. + fn zero() -> Self; + + /// Returns one. + fn one() -> Self; +} + /// Extension trait for field elements that can be converted back and forth to an integer type. /// /// The `Integer` associated type is an integer (primitive or otherwise) that supports various @@ -168,104 +205,95 @@ pub trait FieldElement: /// integer type. This trait also defines methods on field elements, `pow` and `modulus`, that make /// use of the associated integer type. pub trait FieldElementWithInteger: FieldElement + From { - /// The error returned if converting `usize` to an `Integer` fails. - type IntegerTryFromError: std::error::Error; - - /// The error returned if converting an `Integer` to a `u64` fails. - type TryIntoU64Error: std::error::Error; - /// The integer representation of a field element. - type Integer: Copy - + Debug - + Eq - + Ord - + BitAnd - + Div - + Shl - + Shr - + Add - + Sub - + From - + TryFrom - + TryInto; + type Integer: Integer + From + Copy; /// Modular exponentation, i.e., `self^exp (mod p)`. fn pow(&self, exp: Self::Integer) -> Self; /// Returns the prime modulus `p`. fn modulus() -> Self::Integer; -} - -/// Methods common to all `FieldElementWithInteger` implementations that are private to the crate. -pub(crate) trait FieldElementWithIntegerExt: FieldElementWithInteger { - /// Encode `input` as bitvector of elements of `Self`. Output is written into the `output` slice. - /// If `output.len()` is smaller than the number of bits required to respresent `input`, - /// an error is returned. - /// - /// # Arguments + /// Encode the integer `input` as a sequence of bits in two's complement representation, least + /// significant bit first, and then map each bit to a field element. /// - /// * `input` - The field element to encode - /// * `output` - The slice to write the encoded bits into. Least signicant bit comes first - fn fill_with_bitvector_representation( - input: &Self::Integer, - output: &mut [Self], - ) -> Result<(), FieldError> { - // Create a mutable copy of `input`. In each iteration of the following loop we take the - // least significant bit, and shift input to the right by one bit. - let mut i = *input; - - let one = Self::Integer::from(Self::one()); - for bit in output.iter_mut() { - let w = Self::from(i & one); - *bit = w; - i = i >> 1; + /// Returns an error if `input` cannot be represented with `bits` many bits, or if `bits` + /// is larger than the bit width of the field's modulus. + fn encode_as_bitvector( + input: Self::Integer, + bits: usize, + ) -> Result, FieldError> { + // Check if `bits` is too large for this field. + if !Self::valid_integer_bitlength(bits) { + return Err(FieldError::BitVectorTooLong); } - // If `i` is still not zero, this means that it cannot be encoded by `bits` bits. - if i != Self::Integer::from(Self::zero()) { + // Check if the input value can be represented in the requested number of bits by shifting + // it. The above check on `bits` ensures this shift won't panic due to the shift width + // being too large. + if input >> bits != Self::Integer::zero() { return Err(FieldError::InputSizeMismatch); } - Ok(()) + Ok(BitvectorRepresentationIter { + inner: 0..bits, + input, + }) } - /// Encode `input` as `bits`-bit vector of elements of `Self` if it's small enough - /// to be represented with that many bits. - /// - /// # Arguments + /// Inverts the encoding done by [`Self::encode_as_bitvector`], and returns a single field + /// element. /// - /// * `input` - The field element to encode - /// * `bits` - The number of bits to use for the encoding - fn encode_into_bitvector_representation( - input: &Self::Integer, - bits: usize, - ) -> Result, FieldError> { - let mut result = vec![Self::zero(); bits]; - Self::fill_with_bitvector_representation(input, &mut result)?; - Ok(result) - } - - /// Decode the bitvector-represented value `input` into a simple representation as a single - /// field element. + /// This performs an inner product between the input vector of field elements and successive + /// powers of two (starting with 2^0 = 1). If the input came from [`Self::encode_as_bitvector`], + /// then the result will be equal to the originally encoded integer, projected into the field. /// - /// # Errors + /// Note that this decoding operation is linear, so it can be applied to secret shares of an + /// encoded integer, and if the results are summed up, it will be equal to the encoded integer. /// - /// This function errors if `2^input.len() - 1` does not fit into the field `Self`. - fn decode_from_bitvector_representation(input: &[Self]) -> Result { - let fi_one = Self::Integer::from(Self::one()); - + /// Returns an error if the length of the input is larger than the bit width of the field's + /// modulus. + fn decode_bitvector(input: &[Self]) -> Result { if !Self::valid_integer_bitlength(input.len()) { - return Err(FieldError::ModulusOverflow); + return Err(FieldError::BitVectorTooLong); } let mut decoded = Self::zero(); - for (l, bit) in input.iter().enumerate() { - let w = fi_one << l; - decoded += Self::from(w) * *bit; + let one = Self::one(); + let two = one + one; + let mut power_of_two = one; + for value in input.iter() { + decoded += *value * power_of_two; + power_of_two *= two; } Ok(decoded) } +} + +/// This iterator returns a sequence of field elements that are equal to zero or one, representing +/// some integer in two's complement form. See [`FieldElementWithInteger::encode_as_bitvector`]. +// Note that this is implemented with a separate struct, instead of using the map combinator, +// because return_position_impl_trait_in_trait is not yet stable. +#[derive(Debug, Clone)] +pub struct BitvectorRepresentationIter { + inner: Range, + input: F::Integer, +} + +impl Iterator for BitvectorRepresentationIter +where + F: FieldElementWithInteger, +{ + type Item = F; + + #[inline] + fn next(&mut self) -> Option { + let bit_offset = self.inner.next()?; + Some(F::from((self.input >> bit_offset) & F::Integer::one())) + } +} +/// Methods common to all `FieldElementWithInteger` implementations that are private to the crate. +pub(crate) trait FieldElementWithIntegerExt: FieldElementWithInteger { /// Interpret `i` as [`Self::Integer`] if it's representable in that type and smaller than the /// field modulus. fn valid_integer_try_from(i: N) -> Result @@ -285,7 +313,7 @@ pub(crate) trait FieldElementWithIntegerExt: FieldElementWithInteger { if bits >= 8 * Self::ENCODED_SIZE { return false; } - if Self::modulus() >> bits != Self::Integer::from(Self::zero()) { + if Self::modulus() >> bits != Self::Integer::zero() { return true; } false @@ -382,7 +410,7 @@ macro_rules! make_field { /// /// As an invariant, this integer representing the field element in the Montgomery domain /// must be less than the field modulus, `p`. - #[derive(Clone, Copy, PartialOrd, Ord, Default)] + #[derive(Clone, Copy, Default)] pub struct $elem(u128); impl $elem { @@ -640,9 +668,10 @@ macro_rules! make_field { } impl Encode for $elem { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { let slice = <[u8; $elem::ENCODED_SIZE]>::from(*self); bytes.extend_from_slice(&slice); + Ok(()) } fn encoded_len(&self) -> Option { @@ -683,8 +712,6 @@ macro_rules! make_field { impl FieldElementWithInteger for $elem { type Integer = $int; - type IntegerTryFromError = >::Error; - type TryIntoU64Error = >::Error; fn pow(&self, exp: Self::Integer) -> Self { // FieldParameters::pow() relies on mul(), and will always return a value less @@ -717,6 +744,45 @@ macro_rules! make_field { }; } +impl Integer for u32 { + type TryFromUsizeError = >::Error; + type TryIntoU64Error = >::Error; + + fn zero() -> Self { + 0 + } + + fn one() -> Self { + 1 + } +} + +impl Integer for u64 { + type TryFromUsizeError = >::Error; + type TryIntoU64Error = >::Error; + + fn zero() -> Self { + 0 + } + + fn one() -> Self { + 1 + } +} + +impl Integer for u128 { + type TryFromUsizeError = >::Error; + type TryIntoU64Error = >::Error; + + fn zero() -> Self { + 0 + } + + fn one() -> Self { + 1 + } +} + make_field!( /// Same as Field32, but encoded in little endian for compatibility with Prio v2. FieldPrio2, @@ -761,7 +827,7 @@ pub(crate) fn merge_vector( } /// Outputs an additive secret sharing of the input. -#[cfg(all(feature = "crypto-dependencies", test))] +#[cfg(test)] pub(crate) fn split_vector( inp: &[F], num_shares: usize, @@ -785,18 +851,20 @@ pub(crate) fn split_vector( } /// Generate a vector of uniformly distributed random field elements. -#[cfg(feature = "crypto-dependencies")] -#[cfg_attr(docsrs, doc(cfg(feature = "crypto-dependencies")))] pub fn random_vector(len: usize) -> Result, PrngError> { Ok(Prng::new()?.take(len).collect()) } /// `encode_fieldvec` serializes a type that is equivalent to a vector of field elements. #[inline(always)] -pub(crate) fn encode_fieldvec>(val: T, bytes: &mut Vec) { +pub(crate) fn encode_fieldvec>( + val: T, + bytes: &mut Vec, +) -> Result<(), CodecError> { for elem in val.as_ref() { - elem.encode(bytes); + elem.encode(bytes)?; } + Ok(()) } /// `decode_fieldvec` deserializes some number of field elements from a cursor, and advances the @@ -822,16 +890,14 @@ pub(crate) fn decode_fieldvec( #[cfg(test)] pub(crate) mod test_utils { - use super::{FieldElement, FieldElementWithInteger}; + use super::{FieldElement, FieldElementWithInteger, Integer}; use crate::{codec::CodecError, field::FieldError, prng::Prng}; use assert_matches::assert_matches; use std::{ collections::hash_map::DefaultHasher, - convert::{TryFrom, TryInto}, - fmt::Debug, + convert::TryFrom, hash::{Hash, Hasher}, io::Cursor, - ops::{Add, BitAnd, Div, Shl, Shr, Sub}, }; /// A test-only copy of `FieldElementWithInteger`. @@ -842,42 +908,30 @@ pub(crate) mod test_utils { /// requires the `Integer` associated type satisfy `Clone`, not `Copy`, so that it may be used /// with arbitrary precision integer implementations. pub(crate) trait TestFieldElementWithInteger: - FieldElement + From + FieldElement + From { type IntegerTryFromError: std::error::Error; type TryIntoU64Error: std::error::Error; - type Integer: Clone - + Debug - + Eq - + Ord - + BitAnd - + Div - + Shl - + Shr - + Add - + Sub - + From - + TryFrom - + TryInto; - - fn pow(&self, exp: Self::Integer) -> Self; - - fn modulus() -> Self::Integer; + type TestInteger: Integer + From + Clone; + + fn pow(&self, exp: Self::TestInteger) -> Self; + + fn modulus() -> Self::TestInteger; } impl TestFieldElementWithInteger for F where F: FieldElementWithInteger, { - type IntegerTryFromError = ::IntegerTryFromError; - type TryIntoU64Error = ::TryIntoU64Error; - type Integer = ::Integer; + type IntegerTryFromError = ::TryFromUsizeError; + type TryIntoU64Error = ::TryIntoU64Error; + type TestInteger = F::Integer; - fn pow(&self, exp: Self::Integer) -> Self { + fn pow(&self, exp: Self::TestInteger) -> Self { ::pow(self, exp) } - fn modulus() -> Self::Integer { + fn modulus() -> Self::TestInteger { ::modulus() } } @@ -885,11 +939,11 @@ pub(crate) mod test_utils { pub(crate) fn field_element_test_common() { let mut prng: Prng = Prng::new().unwrap(); let int_modulus = F::modulus(); - let int_one = F::Integer::try_from(1).unwrap(); + let int_one = F::TestInteger::try_from(1).unwrap(); let zero = F::zero(); let one = F::one(); - let two = F::from(F::Integer::try_from(2).unwrap()); - let four = F::from(F::Integer::try_from(4).unwrap()); + let two = F::from(F::TestInteger::try_from(2).unwrap()); + let four = F::from(F::TestInteger::try_from(4).unwrap()); // add assert_eq!(F::from(int_modulus.clone() - int_one.clone()) + one, zero); @@ -943,10 +997,22 @@ pub(crate) mod test_utils { assert_eq!(a, c); // integer conversion - assert_eq!(F::Integer::from(zero), F::Integer::try_from(0).unwrap()); - assert_eq!(F::Integer::from(one), F::Integer::try_from(1).unwrap()); - assert_eq!(F::Integer::from(two), F::Integer::try_from(2).unwrap()); - assert_eq!(F::Integer::from(four), F::Integer::try_from(4).unwrap()); + assert_eq!( + F::TestInteger::from(zero), + F::TestInteger::try_from(0).unwrap() + ); + assert_eq!( + F::TestInteger::from(one), + F::TestInteger::try_from(1).unwrap() + ); + assert_eq!( + F::TestInteger::from(two), + F::TestInteger::try_from(2).unwrap() + ); + assert_eq!( + F::TestInteger::from(four), + F::TestInteger::try_from(4).unwrap() + ); // serialization let test_inputs = vec![ @@ -957,7 +1023,7 @@ pub(crate) mod test_utils { ]; for want in test_inputs.iter() { let mut bytes = vec![]; - want.encode(&mut bytes); + want.encode(&mut bytes).unwrap(); assert_eq!(bytes.len(), F::ENCODED_SIZE); assert_eq!(want.encoded_len().unwrap(), F::ENCODED_SIZE); @@ -966,9 +1032,12 @@ pub(crate) mod test_utils { assert_eq!(got, *want); } - let serialized_vec = F::slice_into_byte_vec(&test_inputs); - let deserialized = F::byte_slice_into_vec(&serialized_vec).unwrap(); - assert_eq!(deserialized, test_inputs); + #[allow(deprecated)] + { + let serialized_vec = F::slice_into_byte_vec(&test_inputs); + let deserialized = F::byte_slice_into_vec(&serialized_vec).unwrap(); + assert_eq!(deserialized, test_inputs); + } let test_input = prng.get(); let json = serde_json::to_string(&test_input).unwrap(); @@ -981,13 +1050,16 @@ pub(crate) mod test_utils { element.as_u64().unwrap(); } - let err = F::byte_slice_into_vec(&[0]).unwrap_err(); - assert_matches!(err, FieldError::ShortRead); + #[allow(deprecated)] + { + let err = F::byte_slice_into_vec(&[0]).unwrap_err(); + assert_matches!(err, FieldError::ShortRead); - let err = F::byte_slice_into_vec(&vec![0xffu8; F::ENCODED_SIZE]).unwrap_err(); - assert_matches!(err, FieldError::Codec(CodecError::Other(err)) => { - assert_matches!(err.downcast_ref::(), Some(FieldError::ModulusOverflow)); - }); + let err = F::byte_slice_into_vec(&vec![0xffu8; F::ENCODED_SIZE]).unwrap_err(); + assert_matches!(err, FieldError::Codec(CodecError::Other(err)) => { + assert_matches!(err.downcast_ref::(), Some(FieldError::ModulusOverflow)); + }); + } let insufficient = vec![0u8; F::ENCODED_SIZE - 1]; let err = F::try_from(insufficient.as_ref()).unwrap_err(); @@ -1004,7 +1076,7 @@ pub(crate) mod test_utils { // various products that should be equal have the same hash. Three is chosen as a generator // here because it happens to generate fairly large subgroups of (Z/pZ)* for all four // primes. - let three = F::from(F::Integer::try_from(3).unwrap()); + let three = F::from(F::TestInteger::try_from(3).unwrap()); let mut powers_of_three = Vec::with_capacity(500); let mut power = one; for _ in 0..500 { @@ -1169,22 +1241,19 @@ mod tests { fn test_encode_into_bitvector() { let zero = Field128::zero(); let one = Field128::one(); - let zero_enc = Field128::encode_into_bitvector_representation(&0, 4).unwrap(); - let one_enc = Field128::encode_into_bitvector_representation(&1, 4).unwrap(); - let fifteen_enc = Field128::encode_into_bitvector_representation(&15, 4).unwrap(); + let zero_enc = Field128::encode_as_bitvector(0, 4) + .unwrap() + .collect::>(); + let one_enc = Field128::encode_as_bitvector(1, 4) + .unwrap() + .collect::>(); + let fifteen_enc = Field128::encode_as_bitvector(15, 4) + .unwrap() + .collect::>(); assert_eq!(zero_enc, [zero; 4]); assert_eq!(one_enc, [one, zero, zero, zero]); assert_eq!(fifteen_enc, [one; 4]); - Field128::encode_into_bitvector_representation(&16, 4).unwrap_err(); - } - - #[test] - fn test_fill_bitvector() { - let zero = Field128::zero(); - let one = Field128::one(); - let mut output: Vec = vec![zero; 6]; - Field128::fill_with_bitvector_representation(&9, &mut output[1..5]).unwrap(); - assert_eq!(output, [zero, one, zero, zero, one, zero]); - Field128::fill_with_bitvector_representation(&16, &mut output[1..5]).unwrap_err(); + Field128::encode_as_bitvector(16, 4).unwrap_err(); + Field128::encode_as_bitvector(0, 129).unwrap_err(); } } diff --git a/third_party/rust/prio/src/field/field255.rs b/third_party/rust/prio/src/field/field255.rs index fd06a6334a..15a53f8b09 100644 --- a/third_party/rust/prio/src/field/field255.rs +++ b/third_party/rust/prio/src/field/field255.rs @@ -271,8 +271,9 @@ impl<'de> Deserialize<'de> for Field255 { } impl Encode for Field255 { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { bytes.extend_from_slice(&<[u8; Self::ENCODED_SIZE]>::from(*self)); + Ok(()) } fn encoded_len(&self) -> Option { @@ -341,7 +342,7 @@ mod tests { codec::Encode, field::{ test_utils::{field_element_test_common, TestFieldElementWithInteger}, - FieldElement, FieldError, + FieldElement, FieldError, Integer, }, }; use assert_matches::assert_matches; @@ -375,16 +376,30 @@ mod tests { } } + impl Integer for BigUint { + type TryFromUsizeError = >::Error; + + type TryIntoU64Error = >::Error; + + fn zero() -> Self { + Self::new(Vec::new()) + } + + fn one() -> Self { + Self::new(Vec::from([1])) + } + } + impl TestFieldElementWithInteger for Field255 { - type Integer = BigUint; - type IntegerTryFromError = >::Error; - type TryIntoU64Error = >::Error; + type TestInteger = BigUint; + type IntegerTryFromError = >::Error; + type TryIntoU64Error = >::Error; - fn pow(&self, _exp: Self::Integer) -> Self { + fn pow(&self, _exp: Self::TestInteger) -> Self { unimplemented!("Field255::pow() is not implemented because it's not needed yet") } - fn modulus() -> Self::Integer { + fn modulus() -> Self::TestInteger { MODULUS.clone() } } @@ -415,7 +430,7 @@ mod tests { #[test] fn encode_endianness() { let mut one_encoded = Vec::new(); - Field255::one().encode(&mut one_encoded); + Field255::one().encode(&mut one_encoded).unwrap(); assert_eq!( one_encoded, [ diff --git a/third_party/rust/prio/src/flp.rs b/third_party/rust/prio/src/flp.rs index 1912ebab14..5fd956155a 100644 --- a/third_party/rust/prio/src/flp.rs +++ b/third_party/rust/prio/src/flp.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 //! Implementation of the generic Fully Linear Proof (FLP) system specified in -//! [[draft-irtf-cfrg-vdaf-07]]. This is the main building block of [`Prio3`](crate::vdaf::prio3). +//! [[draft-irtf-cfrg-vdaf-08]]. This is the main building block of [`Prio3`](crate::vdaf::prio3). //! //! The FLP is derived for any implementation of the [`Type`] trait. Such an implementation //! specifies a validity circuit that defines the set of valid measurements, as well as the finite @@ -24,7 +24,7 @@ //! //! // The prover chooses a measurement. //! let count = Count::new(); -//! let input: Vec = count.encode_measurement(&0).unwrap(); +//! let input: Vec = count.encode_measurement(&false).unwrap(); //! //! // The prover and verifier agree on "joint randomness" used to generate and //! // check the proof. The application needs to ensure that the prover @@ -44,7 +44,7 @@ //! assert!(count.decide(&verifier).unwrap()); //! ``` //! -//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ #[cfg(feature = "experimental")] use crate::dp::DifferentialPrivacyStrategy; @@ -61,6 +61,7 @@ pub mod types; /// Errors propagated by methods in this module. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum FlpError { /// Calling [`Type::prove`] returned an error. #[error("prove error: {0}")] @@ -110,20 +111,12 @@ pub enum FlpError { /// An error happened during noising. #[error("differential privacy error: {0}")] DifferentialPrivacy(#[from] crate::dp::DpError), - - /// Unit test error. - #[cfg(test)] - #[error("test failed: {0}")] - Test(String), } /// A type. Implementations of this trait specify how a particular kind of measurement is encoded /// as a vector of field elements and how validity of the encoded measurement is determined. /// Validity is determined via an arithmetic circuit evaluated over the encoded measurement. pub trait Type: Sized + Eq + Clone + Debug { - /// The Prio3 VDAF identifier corresponding to this type. - const ID: u32; - /// The type of raw measurement to be encoded. type Measurement: Clone + Debug; @@ -178,7 +171,7 @@ pub trait Type: Sized + Eq + Clone + Debug { /// use prio::field::{random_vector, FieldElement, Field64}; /// /// let count = Count::new(); - /// let input: Vec = count.encode_measurement(&1).unwrap(); + /// let input: Vec = count.encode_measurement(&true).unwrap(); /// let joint_rand = random_vector(count.joint_rand_len()).unwrap(); /// let v = count.valid(&mut count.gadget(), &input, &joint_rand, 1).unwrap(); /// assert_eq!(v, Field64::zero()); @@ -552,6 +545,7 @@ pub trait Type: Sized + Eq + Clone + Debug { /// A type which supports adding noise to aggregate shares for Server Differential Privacy. #[cfg(feature = "experimental")] +#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))] pub trait TypeWithNoise: Type where S: DifferentialPrivacyStrategy, @@ -754,6 +748,227 @@ pub(crate) fn gadget_poly_len(gadget_degree: usize, wire_poly_len: usize) -> usi gadget_degree * (wire_poly_len - 1) + 1 } +/// Utilities for testing FLPs. +#[cfg(feature = "test-util")] +#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] +pub mod test_utils { + use super::*; + use crate::field::{random_vector, FieldElement, FieldElementWithInteger}; + + /// Various tests for an FLP. + #[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] + pub struct FlpTest<'a, T: Type> { + /// The FLP. + pub flp: &'a T, + + /// Optional test name. + pub name: Option<&'a str>, + + /// The input to use for the tests. + pub input: &'a [T::Field], + + /// If set, the expected result of truncating the input. + pub expected_output: Option<&'a [T::Field]>, + + /// Whether the input is expected to be valid. + pub expect_valid: bool, + } + + impl FlpTest<'_, T> { + /// Construct a test and run it. Expect the input to be valid and compare the truncated + /// output to the provided value. + pub fn expect_valid( + flp: &T, + input: &[T::Field], + expected_output: &[T::Field], + ) { + FlpTest { + flp, + name: None, + input, + expected_output: Some(expected_output), + expect_valid: true, + } + .run::() + } + + /// Construct a test and run it. Expect the input to be invalid. + pub fn expect_invalid(flp: &T, input: &[T::Field]) { + FlpTest { + flp, + name: None, + input, + expect_valid: false, + expected_output: None, + } + .run::() + } + + /// Construct a test and run it. Expect the input to be valid. + pub fn expect_valid_no_output(flp: &T, input: &[T::Field]) { + FlpTest { + flp, + name: None, + input, + expect_valid: true, + expected_output: None, + } + .run::() + } + + /// Run the tests. + pub fn run(&self) { + let name = self.name.unwrap_or("unnamed test"); + + assert_eq!( + self.input.len(), + self.flp.input_len(), + "{name}: unexpected input length" + ); + + let mut gadgets = self.flp.gadget(); + let joint_rand = random_vector(self.flp.joint_rand_len()).unwrap(); + let prove_rand = random_vector(self.flp.prove_rand_len()).unwrap(); + let query_rand = random_vector(self.flp.query_rand_len()).unwrap(); + assert_eq!( + self.flp.query_rand_len(), + gadgets.len(), + "{name}: unexpected number of gadgets" + ); + assert_eq!( + self.flp.joint_rand_len(), + joint_rand.len(), + "{name}: unexpected joint rand length" + ); + assert_eq!( + self.flp.prove_rand_len(), + prove_rand.len(), + "{name}: unexpected prove rand length", + ); + assert_eq!( + self.flp.query_rand_len(), + query_rand.len(), + "{name}: unexpected query rand length", + ); + + // Run the validity circuit. + let v = self + .flp + .valid(&mut gadgets, self.input, &joint_rand, 1) + .unwrap(); + assert_eq!( + v == T::Field::zero(), + self.expect_valid, + "{name}: unexpected output of valid() returned {v}", + ); + + // Generate the proof. + let proof = self + .flp + .prove(self.input, &prove_rand, &joint_rand) + .unwrap(); + assert_eq!( + proof.len(), + self.flp.proof_len(), + "{name}: unexpected proof length" + ); + + // Query the proof. + let verifier = self + .flp + .query(self.input, &proof, &query_rand, &joint_rand, 1) + .unwrap(); + assert_eq!( + verifier.len(), + self.flp.verifier_len(), + "{name}: unexpected verifier length" + ); + + // Decide if the input is valid. + let res = self.flp.decide(&verifier).unwrap(); + assert_eq!(res, self.expect_valid, "{name}: unexpected decision"); + + // Run distributed FLP. + let input_shares = split_vector::<_, SHARES>(self.input); + let proof_shares = split_vector::<_, SHARES>(&proof); + let verifier: Vec = (0..SHARES) + .map(|i| { + self.flp + .query( + &input_shares[i], + &proof_shares[i], + &query_rand, + &joint_rand, + SHARES, + ) + .unwrap() + }) + .reduce(|mut left, right| { + for (x, y) in left.iter_mut().zip(right.iter()) { + *x += *y; + } + left + }) + .unwrap(); + + let res = self.flp.decide(&verifier).unwrap(); + assert_eq!( + res, self.expect_valid, + "{name}: unexpected distributed decision" + ); + + // Try verifying various proof mutants. + for i in 0..std::cmp::min(proof.len(), 10) { + let mut mutated_proof = proof.clone(); + mutated_proof[i] *= T::Field::from( + ::Integer::try_from(23).unwrap(), + ); + let verifier = self + .flp + .query(self.input, &mutated_proof, &query_rand, &joint_rand, 1) + .unwrap(); + assert!( + !self.flp.decide(&verifier).unwrap(), + "{name}: proof mutant {} deemed valid", + i + ); + } + + // Try truncating the input. + if let Some(ref expected_output) = self.expected_output { + let output = self.flp.truncate(self.input.to_vec()).unwrap(); + + assert_eq!( + output.len(), + self.flp.output_len(), + "{name}: unexpected output length of truncate()" + ); + + assert_eq!( + &output, expected_output, + "{name}: unexpected output of truncate()" + ); + } + } + } + + fn split_vector(inp: &[F]) -> [Vec; SHARES] { + let mut outp = Vec::with_capacity(SHARES); + outp.push(inp.to_vec()); + + for _ in 1..SHARES { + let share: Vec = + random_vector(inp.len()).expect("failed to generate a random vector"); + for (x, y) in outp[0].iter_mut().zip(&share) { + *x -= *y; + } + outp.push(share); + } + + outp.try_into().unwrap() + } +} + #[cfg(test)] mod tests { use super::*; @@ -825,7 +1040,6 @@ mod tests { } impl Type for TestType { - const ID: u32 = 0xFFFF0000; type Measurement = F::Integer; type AggregateResult = F::Integer; type Field = F; @@ -960,7 +1174,6 @@ mod tests { } impl Type for Issue254Type { - const ID: u32 = 0xFFFF0000; type Measurement = F::Integer; type AggregateResult = F::Integer; type Field = F; diff --git a/third_party/rust/prio/src/flp/types.rs b/third_party/rust/prio/src/flp/types.rs index 18c290355c..bca88a36cd 100644 --- a/third_party/rust/prio/src/flp/types.rs +++ b/third_party/rust/prio/src/flp/types.rs @@ -9,6 +9,7 @@ use crate::polynomial::poly_range_check; use std::convert::TryInto; use std::fmt::{self, Debug}; use std::marker::PhantomData; +use subtle::Choice; /// The counter data type. Each measurement is `0` or `1` and the aggregate result is the sum of the measurements (i.e., the total number of `1s`). #[derive(Clone, PartialEq, Eq)] pub struct Count { @@ -37,18 +38,16 @@ impl Default for Count { } impl Type for Count { - const ID: u32 = 0x00000000; - type Measurement = F::Integer; + type Measurement = bool; type AggregateResult = F::Integer; type Field = F; - fn encode_measurement(&self, value: &F::Integer) -> Result, FlpError> { - let max = F::valid_integer_try_from(1)?; - if *value > max { - return Err(FlpError::Encode("Count value must be 0 or 1".to_string())); - } - - Ok(vec![F::from(*value)]) + fn encode_measurement(&self, value: &bool) -> Result, FlpError> { + Ok(vec![F::conditional_select( + &F::zero(), + &F::one(), + Choice::from(u8::from(*value)), + )]) } fn decode_result(&self, data: &[F], _num_measurements: usize) -> Result { @@ -140,13 +139,12 @@ impl Sum { } impl Type for Sum { - const ID: u32 = 0x00000001; type Measurement = F::Integer; type AggregateResult = F::Integer; type Field = F; fn encode_measurement(&self, summand: &F::Integer) -> Result, FlpError> { - let v = F::encode_into_bitvector_representation(summand, self.bits)?; + let v = F::encode_as_bitvector(*summand, self.bits)?.collect(); Ok(v) } @@ -174,7 +172,7 @@ impl Type for Sum { fn truncate(&self, input: Vec) -> Result, FlpError> { self.truncate_call_check(&input)?; - let res = F::decode_from_bitvector_representation(&input)?; + let res = F::decode_bitvector(&input)?; Ok(vec![res]) } @@ -239,13 +237,12 @@ impl Average { } impl Type for Average { - const ID: u32 = 0xFFFF0000; type Measurement = F::Integer; type AggregateResult = f64; type Field = F; fn encode_measurement(&self, summand: &F::Integer) -> Result, FlpError> { - let v = F::encode_into_bitvector_representation(summand, self.bits)?; + let v = F::encode_as_bitvector(*summand, self.bits)?.collect(); Ok(v) } @@ -279,7 +276,7 @@ impl Type for Average { fn truncate(&self, input: Vec) -> Result, FlpError> { self.truncate_call_check(&input)?; - let res = F::decode_from_bitvector_representation(&input)?; + let res = F::decode_bitvector(&input)?; Ok(vec![res]) } @@ -380,7 +377,6 @@ where F: FftFriendlyFieldElement, S: ParallelSumGadget> + Eq + 'static, { - const ID: u32 = 0x00000003; type Measurement = usize; type AggregateResult = Vec; type Field = F; @@ -574,7 +570,6 @@ where F: FftFriendlyFieldElement, S: ParallelSumGadget> + Eq + 'static, { - const ID: u32 = 0x00000002; type Measurement = Vec; type AggregateResult = Vec; type Field = F; @@ -588,18 +583,15 @@ where ))); } - let mut flattened = vec![F::zero(); self.flattened_len]; - for (summand, chunk) in measurement - .iter() - .zip(flattened.chunks_exact_mut(self.bits)) - { + let mut flattened = Vec::with_capacity(self.flattened_len); + for summand in measurement.iter() { if summand > &self.max { return Err(FlpError::Encode(format!( "summand exceeds maximum of 2^{}-1", self.bits ))); } - F::fill_with_bitvector_representation(summand, chunk)?; + flattened.extend(F::encode_as_bitvector(*summand, self.bits)?); } Ok(flattened) @@ -642,7 +634,7 @@ where self.truncate_call_check(&input)?; let mut unflattened = Vec::with_capacity(self.len); for chunk in input.chunks(self.bits) { - unflattened.push(F::decode_from_bitvector_representation(chunk)?); + unflattened.push(F::decode_bitvector(chunk)?); } Ok(unflattened) } @@ -783,7 +775,7 @@ mod tests { use crate::flp::gadgets::ParallelSum; #[cfg(feature = "multithreaded")] use crate::flp::gadgets::ParallelSumMultithreaded; - use crate::flp::types::test_utils::{flp_validity_test, ValidityTestCase}; + use crate::flp::test_utils::FlpTest; use std::cmp; #[test] @@ -797,7 +789,7 @@ mod tests { count .decode_result( &count - .truncate(count.encode_measurement(&1).unwrap()) + .truncate(count.encode_measurement(&true).unwrap()) .unwrap(), 1 ) @@ -806,39 +798,11 @@ mod tests { ); // Test FLP on valid input. - flp_validity_test( - &count, - &count.encode_measurement(&1).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![one]), - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( - &count, - &count.encode_measurement(&0).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![zero]), - num_shares: 3, - }, - ) - .unwrap(); + FlpTest::expect_valid::<3>(&count, &count.encode_measurement(&true).unwrap(), &[one]); + FlpTest::expect_valid::<3>(&count, &count.encode_measurement(&false).unwrap(), &[zero]); // Test FLP on invalid input. - flp_validity_test( - &count, - &[TestField::from(1337)], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); + FlpTest::expect_invalid::<3>(&count, &[TestField::from(1337)]); // Try running the validity circuit on an input that's too short. count.valid(&mut count.gadget(), &[], &[], 1).unwrap_err(); @@ -865,72 +829,22 @@ mod tests { ); // Test FLP on valid input. - flp_validity_test( + FlpTest::expect_valid::<3>( &sum, &sum.encode_measurement(&1337).unwrap(), - &ValidityTestCase { - expect_valid: true, - expected_output: Some(vec![TestField::from(1337)]), - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( - &Sum::new(0).unwrap(), - &[], - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![zero]), - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( - &Sum::new(2).unwrap(), - &[one, zero], - &ValidityTestCase { - expect_valid: true, - expected_output: Some(vec![one]), - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( + &[TestField::from(1337)], + ); + FlpTest::expect_valid::<3>(&Sum::new(0).unwrap(), &[], &[zero]); + FlpTest::expect_valid::<3>(&Sum::new(2).unwrap(), &[one, zero], &[one]); + FlpTest::expect_valid::<3>( &Sum::new(9).unwrap(), &[one, zero, one, one, zero, one, one, one, zero], - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![TestField::from(237)]), - num_shares: 3, - }, - ) - .unwrap(); + &[TestField::from(237)], + ); // Test FLP on invalid input. - flp_validity_test( - &Sum::new(3).unwrap(), - &[one, nine, zero], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( - &Sum::new(5).unwrap(), - &[zero, zero, zero, zero, nine], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); + FlpTest::expect_invalid::<3>(&Sum::new(3).unwrap(), &[one, nine, zero]); + FlpTest::expect_invalid::<3>(&Sum::new(5).unwrap(), &[zero, zero, zero, zero, nine]); } #[test] @@ -1000,83 +914,29 @@ mod tests { ); // Test valid inputs. - flp_validity_test( + FlpTest::expect_valid::<3>( &hist, &hist.encode_measurement(&0).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![one, zero, zero]), - num_shares: 3, - }, - ) - .unwrap(); + &[one, zero, zero], + ); - flp_validity_test( + FlpTest::expect_valid::<3>( &hist, &hist.encode_measurement(&1).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![zero, one, zero]), - num_shares: 3, - }, - ) - .unwrap(); + &[zero, one, zero], + ); - flp_validity_test( + FlpTest::expect_valid::<3>( &hist, &hist.encode_measurement(&2).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![zero, zero, one]), - num_shares: 3, - }, - ) - .unwrap(); + &[zero, zero, one], + ); // Test invalid inputs. - flp_validity_test( - &hist, - &[zero, zero, nine], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( - &hist, - &[zero, one, one], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( - &hist, - &[one, one, one], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); - - flp_validity_test( - &hist, - &[zero, zero, zero], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); + FlpTest::expect_invalid::<3>(&hist, &[zero, zero, nine]); + FlpTest::expect_invalid::<3>(&hist, &[zero, one, one]); + FlpTest::expect_invalid::<3>(&hist, &[one, one, one]); + FlpTest::expect_invalid::<3>(&hist, &[zero, zero, zero]); } #[test] @@ -1104,72 +964,38 @@ mod tests { for len in 1..10 { let chunk_length = cmp::max((len as f64).sqrt() as usize, 1); let sum_vec = f(1, len, chunk_length).unwrap(); - flp_validity_test( + FlpTest::expect_valid_no_output::<3>( &sum_vec, &sum_vec.encode_measurement(&vec![1; len]).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![one; len]), - num_shares: 3, - }, - ) - .unwrap(); + ); } let len = 100; let sum_vec = f(1, len, 10).unwrap(); - flp_validity_test( + FlpTest::expect_valid::<3>( &sum_vec, &sum_vec.encode_measurement(&vec![1; len]).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![one; len]), - num_shares: 3, - }, - ) - .unwrap(); + &vec![one; len], + ); let len = 23; let sum_vec = f(4, len, 4).unwrap(); - flp_validity_test( + FlpTest::expect_valid::<3>( &sum_vec, &sum_vec.encode_measurement(&vec![9; len]).unwrap(), - &ValidityTestCase:: { - expect_valid: true, - expected_output: Some(vec![nine; len]), - num_shares: 3, - }, - ) - .unwrap(); + &vec![nine; len], + ); // Test on invalid inputs. for len in 1..10 { let chunk_length = cmp::max((len as f64).sqrt() as usize, 1); let sum_vec = f(1, len, chunk_length).unwrap(); - flp_validity_test( - &sum_vec, - &vec![nine; len], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); + FlpTest::expect_invalid::<3>(&sum_vec, &vec![nine; len]); } let len = 23; let sum_vec = f(2, len, 4).unwrap(); - flp_validity_test( - &sum_vec, - &vec![nine; 2 * len], - &ValidityTestCase:: { - expect_valid: false, - expected_output: None, - num_shares: 3, - }, - ) - .unwrap(); + FlpTest::expect_invalid::<3>(&sum_vec, &vec![nine; 2 * len]); // Round trip let want = vec![1; len]; @@ -1232,184 +1058,6 @@ mod tests { } } -#[cfg(test)] -mod test_utils { - use super::*; - use crate::field::{random_vector, split_vector, FieldElement}; - - pub(crate) struct ValidityTestCase { - pub(crate) expect_valid: bool, - pub(crate) expected_output: Option>, - // Number of shares to split input and proofs into in `flp_test`. - pub(crate) num_shares: usize, - } - - pub(crate) fn flp_validity_test( - typ: &T, - input: &[T::Field], - t: &ValidityTestCase, - ) -> Result<(), FlpError> { - let mut gadgets = typ.gadget(); - - if input.len() != typ.input_len() { - return Err(FlpError::Test(format!( - "unexpected input length: got {}; want {}", - input.len(), - typ.input_len() - ))); - } - - if typ.query_rand_len() != gadgets.len() { - return Err(FlpError::Test(format!( - "query rand length: got {}; want {}", - typ.query_rand_len(), - gadgets.len() - ))); - } - - let joint_rand = random_vector(typ.joint_rand_len()).unwrap(); - let prove_rand = random_vector(typ.prove_rand_len()).unwrap(); - let query_rand = random_vector(typ.query_rand_len()).unwrap(); - - // Run the validity circuit. - let v = typ.valid(&mut gadgets, input, &joint_rand, 1)?; - if v != T::Field::zero() && t.expect_valid { - return Err(FlpError::Test(format!( - "expected valid input: valid() returned {v}" - ))); - } - if v == T::Field::zero() && !t.expect_valid { - return Err(FlpError::Test(format!( - "expected invalid input: valid() returned {v}" - ))); - } - - // Generate the proof. - let proof = typ.prove(input, &prove_rand, &joint_rand)?; - if proof.len() != typ.proof_len() { - return Err(FlpError::Test(format!( - "unexpected proof length: got {}; want {}", - proof.len(), - typ.proof_len() - ))); - } - - // Query the proof. - let verifier = typ.query(input, &proof, &query_rand, &joint_rand, 1)?; - if verifier.len() != typ.verifier_len() { - return Err(FlpError::Test(format!( - "unexpected verifier length: got {}; want {}", - verifier.len(), - typ.verifier_len() - ))); - } - - // Decide if the input is valid. - let res = typ.decide(&verifier)?; - if res != t.expect_valid { - return Err(FlpError::Test(format!( - "decision is {}; want {}", - res, t.expect_valid, - ))); - } - - // Run distributed FLP. - let input_shares: Vec> = split_vector(input, t.num_shares) - .unwrap() - .into_iter() - .collect(); - - let proof_shares: Vec> = split_vector(&proof, t.num_shares) - .unwrap() - .into_iter() - .collect(); - - let verifier: Vec = (0..t.num_shares) - .map(|i| { - typ.query( - &input_shares[i], - &proof_shares[i], - &query_rand, - &joint_rand, - t.num_shares, - ) - .unwrap() - }) - .reduce(|mut left, right| { - for (x, y) in left.iter_mut().zip(right.iter()) { - *x += *y; - } - left - }) - .unwrap(); - - let res = typ.decide(&verifier)?; - if res != t.expect_valid { - return Err(FlpError::Test(format!( - "distributed decision is {}; want {}", - res, t.expect_valid, - ))); - } - - // Try verifying various proof mutants. - for i in 0..proof.len() { - let mut mutated_proof = proof.clone(); - mutated_proof[i] += T::Field::one(); - let verifier = typ.query(input, &mutated_proof, &query_rand, &joint_rand, 1)?; - if typ.decide(&verifier)? { - return Err(FlpError::Test(format!( - "decision for proof mutant {} is {}; want {}", - i, true, false, - ))); - } - } - - // Try verifying a proof that is too short. - let mut mutated_proof = proof.clone(); - mutated_proof.truncate(gadgets[0].arity() - 1); - if typ - .query(input, &mutated_proof, &query_rand, &joint_rand, 1) - .is_ok() - { - return Err(FlpError::Test( - "query on short proof succeeded; want failure".to_string(), - )); - } - - // Try verifying a proof that is too long. - let mut mutated_proof = proof; - mutated_proof.extend_from_slice(&[T::Field::one(); 17]); - if typ - .query(input, &mutated_proof, &query_rand, &joint_rand, 1) - .is_ok() - { - return Err(FlpError::Test( - "query on long proof succeeded; want failure".to_string(), - )); - } - - if let Some(ref want) = t.expected_output { - let got = typ.truncate(input.to_vec())?; - - if got.len() != typ.output_len() { - return Err(FlpError::Test(format!( - "unexpected output length: got {}; want {}", - got.len(), - typ.output_len() - ))); - } - - if &got != want { - return Err(FlpError::Test(format!( - "unexpected output: got {got:?}; want {want:?}" - ))); - } - } - - Ok(()) - } -} - #[cfg(feature = "experimental")] #[cfg_attr(docsrs, doc(cfg(feature = "experimental")))] pub mod fixedpoint_l2; diff --git a/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs b/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs index b5aa2fd116..8766c035b8 100644 --- a/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs +++ b/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs @@ -172,15 +172,17 @@ pub mod compatible_float; use crate::dp::{distributions::ZCdpDiscreteGaussian, DifferentialPrivacyStrategy, DpError}; -use crate::field::{Field128, FieldElement, FieldElementWithInteger, FieldElementWithIntegerExt}; +use crate::field::{ + Field128, FieldElement, FieldElementWithInteger, FieldElementWithIntegerExt, Integer, +}; use crate::flp::gadgets::{Mul, ParallelSumGadget, PolyEval}; use crate::flp::types::fixedpoint_l2::compatible_float::CompatibleFloat; use crate::flp::types::parallel_sum_range_checks; use crate::flp::{FlpError, Gadget, Type, TypeWithNoise}; -use crate::vdaf::xof::SeedStreamSha3; +use crate::vdaf::xof::SeedStreamTurboShake128; use fixed::traits::Fixed; use num_bigint::{BigInt, BigUint, TryFromBigIntError}; -use num_integer::Integer; +use num_integer::Integer as _; use num_rational::Ratio; use rand::{distributions::Distribution, Rng}; use rand_core::SeedableRng; @@ -250,7 +252,7 @@ where /// fixed point vector with `entries` entries. pub fn new(entries: usize) -> Result { // (0) initialize constants - let fi_one = u128::from(Field128::one()); + let fi_one = ::Integer::one(); // (I) Check that the fixed type is compatible. // @@ -400,7 +402,6 @@ where SPoly: ParallelSumGadget> + Eq + Clone + 'static, SMul: ParallelSumGadget> + Eq + Clone + 'static, { - const ID: u32 = 0xFFFF0000; type Measurement = Vec; type AggregateResult = Vec; type Field = Field128; @@ -419,12 +420,9 @@ where // Encode the integer entries bitwise, and write them into the `encoded` // vector. let mut encoded: Vec = - vec![Field128::zero(); self.bits_per_entry * self.entries + self.bits_for_norm]; - for (l, entry) in integer_entries.clone().enumerate() { - Field128::fill_with_bitvector_representation( - &entry, - &mut encoded[l * self.bits_per_entry..(l + 1) * self.bits_per_entry], - )?; + Vec::with_capacity(self.bits_per_entry * self.entries + self.bits_for_norm); + for entry in integer_entries.clone() { + encoded.extend(Field128::encode_as_bitvector(entry, self.bits_per_entry)?); } // (II) Vector norm. @@ -434,10 +432,7 @@ where let norm_int = u128::from(norm); // Write the norm into the `entries` vector. - Field128::fill_with_bitvector_representation( - &norm_int, - &mut encoded[self.range_norm_begin..self.range_norm_end], - )?; + encoded.extend(Field128::encode_as_bitvector(norm_int, self.bits_for_norm)?); Ok(encoded) } @@ -535,7 +530,7 @@ where // decode the bit-encoded entries into elements in the range [0,2^n): let decoded_entries: Result, _> = input[0..self.entries * self.bits_per_entry] .chunks(self.bits_per_entry) - .map(Field128::decode_from_bitvector_representation) + .map(Field128::decode_bitvector) .collect(); // run parallel sum gadget on the decoded entries @@ -544,7 +539,7 @@ where // Chunks which are too short need to be extended with a share of the // encoded zero value, that is: 1/num_shares * (2^(n-1)) - let fi_one = u128::from(Field128::one()); + let fi_one = ::Integer::one(); let zero_enc = Field128::from(fi_one << (self.bits_per_entry - 1)); let zero_enc_share = zero_enc * num_shares_inverse; @@ -567,7 +562,7 @@ where // The submitted norm is also decoded from its bit-encoding, and // compared with the computed norm. let submitted_norm_enc = &input[self.range_norm_begin..self.range_norm_end]; - let submitted_norm = Field128::decode_from_bitvector_representation(submitted_norm_enc)?; + let submitted_norm = Field128::decode_bitvector(submitted_norm_enc)?; let norm_check = computed_norm - submitted_norm; @@ -586,7 +581,7 @@ where let start = i_entry * self.bits_per_entry; let end = (i_entry + 1) * self.bits_per_entry; - let decoded = Field128::decode_from_bitvector_representation(&input[start..end])?; + let decoded = Field128::decode_bitvector(&input[start..end])?; decoded_vector.push(decoded); } Ok(decoded_vector) @@ -644,7 +639,11 @@ where agg_result: &mut [Self::Field], _num_measurements: usize, ) -> Result<(), FlpError> { - self.add_noise(dp_strategy, agg_result, &mut SeedStreamSha3::from_entropy()) + self.add_noise( + dp_strategy, + agg_result, + &mut SeedStreamTurboShake128::from_entropy(), + ) } } @@ -686,8 +685,8 @@ mod tests { use crate::dp::{Rational, ZCdpBudget}; use crate::field::{random_vector, Field128, FieldElement}; use crate::flp::gadgets::ParallelSum; - use crate::flp::types::test_utils::{flp_validity_test, ValidityTestCase}; - use crate::vdaf::xof::SeedStreamSha3; + use crate::flp::test_utils::FlpTest; + use crate::vdaf::xof::SeedStreamTurboShake128; use fixed::types::extra::{U127, U14, U63}; use fixed::{FixedI128, FixedI16, FixedI64}; use fixed_macro::fixed; @@ -768,15 +767,23 @@ mod tests { let strategy = ZCdpDiscreteGaussian::from_budget(ZCdpBudget::new( Rational::from_unsigned(100u8, 3u8).unwrap(), )); - vsum.add_noise(&strategy, &mut v, &mut SeedStreamSha3::from_seed([0u8; 16])) - .unwrap(); + vsum.add_noise( + &strategy, + &mut v, + &mut SeedStreamTurboShake128::from_seed([0u8; 16]), + ) + .unwrap(); assert_eq!( vsum.decode_result(&v, 1).unwrap(), match n { // sensitivity depends on encoding so the noise differs - 16 => vec![0.150604248046875, 0.139373779296875, -0.03759765625], - 32 => vec![0.3051439793780446, 0.1226568529382348, 0.08595499861985445], - 64 => vec![0.2896077990915178, 0.16115188007715098, 0.0788390114728425], + 16 => vec![0.288970947265625, 0.168853759765625, 0.085662841796875], + 32 => vec![0.257810294162482, 0.10634658299386501, 0.10149003705009818], + 64 => vec![ + 0.37697368351762867, + -0.02388947667663828, + 0.19813152630930916 + ], _ => panic!("unsupported bitsize"), } ); @@ -785,52 +792,46 @@ mod tests { let mut input: Vec = vsum.encode_measurement(&fp_vec).unwrap(); assert_eq!(input[0], Field128::zero()); input[0] = one; // it was zero - flp_validity_test( - &vsum, - &input, - &ValidityTestCase:: { - expect_valid: false, - expected_output: Some(vec![ - Field128::from(enc_vec[0] + 1), // = enc(0.25) + 2^0 - Field128::from(enc_vec[1]), - Field128::from(enc_vec[2]), - ]), - num_shares: 3, - }, - ) - .unwrap(); + FlpTest { + name: None, + flp: &vsum, + input: &input, + expected_output: Some(&[ + Field128::from(enc_vec[0] + 1), // = enc(0.25) + 2^0 + Field128::from(enc_vec[1]), + Field128::from(enc_vec[2]), + ]), + expect_valid: false, + } + .run::<3>(); // encoding contains entries that are not zero or one let mut input2: Vec = vsum.encode_measurement(&fp_vec).unwrap(); input2[0] = one + one; - flp_validity_test( - &vsum, - &input2, - &ValidityTestCase:: { - expect_valid: false, - expected_output: Some(vec![ - Field128::from(enc_vec[0] + 2), // = enc(0.25) + 2*2^0 - Field128::from(enc_vec[1]), - Field128::from(enc_vec[2]), - ]), - num_shares: 3, - }, - ) - .unwrap(); + FlpTest { + name: None, + flp: &vsum, + input: &input2, + expected_output: Some(&[ + Field128::from(enc_vec[0] + 2), // = enc(0.25) + 2*2^0 + Field128::from(enc_vec[1]), + Field128::from(enc_vec[2]), + ]), + expect_valid: false, + } + .run::<3>(); // norm is too big // 2^n - 1, the field element encoded by the all-1 vector let one_enc = Field128::from(((2_u128) << (n - 1)) - 1); - flp_validity_test( - &vsum, - &vec![one; 3 * n + 2 * n - 2], // all vector entries and the norm are all-1-vectors - &ValidityTestCase:: { - expect_valid: false, - expected_output: Some(vec![one_enc; 3]), - num_shares: 3, - }, - ) - .unwrap(); + FlpTest { + name: None, + flp: &vsum, + input: &vec![one; 3 * n + 2 * n - 2], // all vector entries and the norm are all-1-vectors + expected_output: Some(&[one_enc; 3]), + expect_valid: false, + } + .run::<3>(); // invalid submission length, should be 3n + (2*n - 2) for a // 3-element n-bit vector. 3*n bits for 3 entries, (2*n-2) for norm. diff --git a/third_party/rust/prio/src/idpf.rs b/third_party/rust/prio/src/idpf.rs index 2bb73f2159..b3da128fa0 100644 --- a/third_party/rust/prio/src/idpf.rs +++ b/third_party/rust/prio/src/idpf.rs @@ -1,7 +1,7 @@ //! This module implements the incremental distributed point function (IDPF) described in -//! [[draft-irtf-cfrg-vdaf-07]]. +//! [[draft-irtf-cfrg-vdaf-08]]. //! -//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ use crate::{ codec::{CodecError, Decode, Encode, ParameterizedDecode}, @@ -24,12 +24,14 @@ use std::{ collections::{HashMap, VecDeque}, fmt::Debug, io::{Cursor, Read}, + iter::zip, ops::{Add, AddAssign, ControlFlow, Index, Sub}, }; use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq}; /// IDPF-related errors. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum IdpfError { /// Error from incompatible shares at different levels. #[error("tried to merge shares from incompatible levels")] @@ -107,6 +109,11 @@ impl IdpfInput { index: self.index[..=level].to_owned().into(), } } + + /// Return the bit at the specified level if the level is in bounds. + pub fn get(&self, level: usize) -> Option { + self.index.get(level).as_deref().copied() + } } impl From> for IdpfInput { @@ -146,7 +153,7 @@ pub trait IdpfValue: + Sub + ConditionallyNegatable + Encode - + Decode + + ParameterizedDecode + Sized { /// Any run-time parameters needed to produce a value. @@ -239,11 +246,13 @@ fn extend(seed: &[u8; 16], xof_fixed_key: &XofFixedKeyAes128Key) -> ([[u8; 16]; seed_stream.fill_bytes(&mut seeds[0]); seed_stream.fill_bytes(&mut seeds[1]); - let mut byte = [0u8]; - seed_stream.fill_bytes(&mut byte); - let control_bits = [(byte[0] & 1).into(), ((byte[0] >> 1) & 1).into()]; + // "Steal" the control bits from the seeds. + let control_bits_0 = seeds[0].as_ref()[0] & 1; + let control_bits_1 = seeds[1].as_ref()[0] & 1; + seeds[0].as_mut()[0] &= 0xfe; + seeds[1].as_mut()[0] &= 0xfe; - (seeds, control_bits) + (seeds, [control_bits_0.into(), control_bits_1.into()]) } fn convert( @@ -670,7 +679,7 @@ where VI: Encode, VL: Encode, { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { // Control bits need to be written within each byte in LSB-to-MSB order, and assigned into // bytes in big-endian order. Thus, the first four levels will have their control bits // encoded in the last byte, and the last levels will have their control bits encoded in the @@ -691,11 +700,11 @@ where bytes.append(&mut packed_control); for correction_words in self.inner_correction_words.iter() { - Seed(correction_words.seed).encode(bytes); - correction_words.value.encode(bytes); + Seed(correction_words.seed).encode(bytes)?; + correction_words.value.encode(bytes)?; } - Seed(self.leaf_correction_word.seed).encode(bytes); - self.leaf_correction_word.value.encode(bytes); + Seed(self.leaf_correction_word.seed).encode(bytes)?; + self.leaf_correction_word.value.encode(bytes) } fn encoded_len(&self) -> Option { @@ -785,7 +794,7 @@ where impl Eq for IdpfCorrectionWord where V: ConstantTimeEq {} -fn xor_seeds(left: &[u8; 16], right: &[u8; 16]) -> [u8; 16] { +pub(crate) fn xor_seeds(left: &[u8; 16], right: &[u8; 16]) -> [u8; 16] { let mut seed = [0u8; 16]; for (a, (b, c)) in left.iter().zip(right.iter().zip(seed.iter_mut())) { *c = a ^ b; @@ -819,7 +828,7 @@ fn control_bit_to_seed_mask(control: Choice) -> [u8; 16] { /// Take two seeds and a control bit, and return the first seed if the control bit is zero, or the /// XOR of the two seeds if the control bit is one. This does not branch on the control bit. -fn conditional_xor_seeds( +pub(crate) fn conditional_xor_seeds( normal_input: &[u8; 16], switched_input: &[u8; 16], control: Choice, @@ -832,13 +841,18 @@ fn conditional_xor_seeds( /// Returns one of two seeds, depending on the value of a selector bit. Does not branch on the /// selector input or make selector-dependent memory accesses. -fn conditional_select_seed(select: Choice, seeds: &[[u8; 16]; 2]) -> [u8; 16] { +pub(crate) fn conditional_select_seed(select: Choice, seeds: &[[u8; 16]; 2]) -> [u8; 16] { or_seeds( &and_seeds(&control_bit_to_seed_mask(!select), &seeds[0]), &and_seeds(&control_bit_to_seed_mask(select), &seeds[1]), ) } +/// Interchange the contents of seeds if the choice is 1, otherwise seeds remain unchanged. +pub(crate) fn conditional_swap_seed(lhs: &mut [u8; 16], rhs: &mut [u8; 16], choice: Choice) { + zip(lhs, rhs).for_each(|(a, b)| u8::conditional_swap(a, b, choice)); +} + /// An interface that provides memoization of IDPF computations. /// /// Each instance of a type implementing `IdpfCache` should only be used with one IDPF key and @@ -947,11 +961,91 @@ impl IdpfCache for RingBufferCache { } } +/// Utilities for testing IDPFs. +#[cfg(feature = "test-util")] +#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] +pub mod test_utils { + use super::*; + + use rand::prelude::*; + use zipf::ZipfDistribution; + + /// Generate a set of IDPF inputs with the given bit length `bits`. They are sampled according + /// to the Zipf distribution with parameters `zipf_support` and `zipf_exponent`. Return the + /// measurements, along with the prefixes traversed during the heavy hitters computation for + /// the given threshold. + /// + /// The prefix tree consists of a sequence of candidate prefixes for each level. For a given level, + /// the candidate prefixes are computed from the hit counts of the prefixes at the previous level: + /// For any prefix `p` whose hit count is at least the desired threshold, add `p || 0` and `p || 1` + /// to the list. + pub fn generate_zipf_distributed_batch( + rng: &mut impl Rng, + bits: usize, + threshold: usize, + measurement_count: usize, + zipf_support: usize, + zipf_exponent: f64, + ) -> (Vec, Vec>) { + // Generate random inputs. + let mut inputs = Vec::with_capacity(zipf_support); + for _ in 0..zipf_support { + let bools: Vec = (0..bits).map(|_| rng.gen()).collect(); + inputs.push(IdpfInput::from_bools(&bools)); + } + + // Sample a number of inputs according to the Zipf distribution. + let mut samples = Vec::with_capacity(measurement_count); + let zipf = ZipfDistribution::new(zipf_support, zipf_exponent).unwrap(); + for _ in 0..measurement_count { + samples.push(inputs[zipf.sample(rng) - 1].clone()); + } + + // Compute the prefix tree for the desired threshold. + let mut prefix_tree = Vec::with_capacity(bits); + prefix_tree.push(vec![ + IdpfInput::from_bools(&[false]), + IdpfInput::from_bools(&[true]), + ]); + + for level in 0..bits - 1 { + // Compute the hit count of each prefix from the previous level. + let mut hit_counts = vec![0; prefix_tree[level].len()]; + for (hit_count, prefix) in hit_counts.iter_mut().zip(prefix_tree[level].iter()) { + for sample in samples.iter() { + let mut is_prefix = true; + for j in 0..prefix.len() { + if prefix[j] != sample[j] { + is_prefix = false; + break; + } + } + if is_prefix { + *hit_count += 1; + } + } + } + + // Compute the next set of candidate prefixes. + let mut next_prefixes = Vec::with_capacity(prefix_tree.last().unwrap().len()); + for (hit_count, prefix) in hit_counts.iter().zip(prefix_tree[level].iter()) { + if *hit_count >= threshold { + next_prefixes.push(prefix.clone_with_suffix(&[false])); + next_prefixes.push(prefix.clone_with_suffix(&[true])); + } + } + prefix_tree.push(next_prefixes); + } + + (samples, prefix_tree) + } +} + #[cfg(test)] mod tests { use std::{ collections::HashMap, - convert::{TryFrom, TryInto}, + convert::TryInto, io::Cursor, ops::{Add, AddAssign, Sub}, str::FromStr, @@ -1568,16 +1662,16 @@ mod tests { seed: [0xab; 16], control_bits: [Choice::from(1), Choice::from(0)], value: Poplar1IdpfValue::new([ - Field64::try_from(83261u64).unwrap(), - Field64::try_from(125159u64).unwrap(), + Field64::from(83261u64), + Field64::from(125159u64), ]), }, IdpfCorrectionWord{ seed: [0xcd;16], control_bits: [Choice::from(0), Choice::from(1)], value: Poplar1IdpfValue::new([ - Field64::try_from(17614120u64).unwrap(), - Field64::try_from(20674u64).unwrap(), + Field64::from(17614120u64), + Field64::from(20674u64), ]), }, ]), @@ -1605,7 +1699,7 @@ mod tests { "f0debc9a78563412f0debc9a78563412f0debc9a78563412f0debc9a78563412", // field element correction word, continued )) .unwrap(); - let encoded = public_share.get_encoded(); + let encoded = public_share.get_encoded().unwrap(); let decoded = IdpfPublicShare::get_decoded_with_param(&3, &message).unwrap(); assert_eq!(public_share, decoded); assert_eq!(message, encoded); @@ -1692,7 +1786,7 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", )) .unwrap(); - let encoded = public_share.get_encoded(); + let encoded = public_share.get_encoded().unwrap(); let decoded = IdpfPublicShare::get_decoded_with_param(&9, &message).unwrap(); assert_eq!(public_share, decoded); assert_eq!(message, encoded); @@ -1761,7 +1855,7 @@ mod tests { 0, ); - assert_eq!(public_share.get_encoded(), serialized_public_share); + assert_eq!(public_share.get_encoded().unwrap(), serialized_public_share); assert_eq!( IdpfPublicShare::get_decoded_with_param(&idpf_bits, &serialized_public_share) .unwrap(), @@ -1821,7 +1915,7 @@ mod tests { /// Load a test vector for Idpf key generation. fn load_idpfpoplar_test_vector() -> IdpfTestVector { let test_vec: serde_json::Value = - serde_json::from_str(include_str!("vdaf/test_vec/07/IdpfPoplar_0.json")).unwrap(); + serde_json::from_str(include_str!("vdaf/test_vec/08/IdpfPoplar_0.json")).unwrap(); let test_vec_obj = test_vec.as_object().unwrap(); let bits = test_vec_obj @@ -1939,7 +2033,7 @@ mod tests { public_share, expected_public_share, "public share did not match\n{public_share:#x?}\n{expected_public_share:#x?}" ); - let encoded_public_share = public_share.get_encoded(); + let encoded_public_share = public_share.get_encoded().unwrap(); assert_eq!(encoded_public_share, test_vector.public_share); } @@ -1988,7 +2082,9 @@ mod tests { } impl Encode for MyUnit { - fn encode(&self, _: &mut Vec) {} + fn encode(&self, _: &mut Vec) -> Result<(), CodecError> { + Ok(()) + } } impl Decode for MyUnit { @@ -2066,8 +2162,8 @@ mod tests { } impl Encode for MyVector { - fn encode(&self, bytes: &mut Vec) { - encode_u32_items(bytes, &(), &self.0); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + encode_u32_items(bytes, &(), &self.0) } } diff --git a/third_party/rust/prio/src/lib.rs b/third_party/rust/prio/src/lib.rs index c9d4e22c49..630e118646 100644 --- a/third_party/rust/prio/src/lib.rs +++ b/third_party/rust/prio/src/lib.rs @@ -17,6 +17,7 @@ pub mod benchmarked; pub mod codec; #[cfg(feature = "experimental")] +#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))] pub mod dp; mod fft; pub mod field; @@ -32,3 +33,9 @@ mod polynomial; mod prng; pub mod topology; pub mod vdaf; +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] +#[cfg_attr( + docsrs, + doc(cfg(all(feature = "crypto-dependencies", feature = "experimental"))) +)] +pub mod vidpf; diff --git a/third_party/rust/prio/src/polynomial.rs b/third_party/rust/prio/src/polynomial.rs index 89d8a91404..272266f538 100644 --- a/third_party/rust/prio/src/polynomial.rs +++ b/third_party/rust/prio/src/polynomial.rs @@ -3,7 +3,7 @@ //! Functions for polynomial interpolation and evaluation -#[cfg(feature = "prio2")] +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] use crate::fft::{discrete_fourier_transform, discrete_fourier_transform_inv_finish}; use crate::field::FftFriendlyFieldElement; @@ -204,7 +204,7 @@ pub fn poly_mul(p: &[F], q: &[F]) -> Vec { out } -#[cfg(feature = "prio2")] +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] #[inline] pub fn poly_interpret_eval( points: &[F], diff --git a/third_party/rust/prio/src/prng.rs b/third_party/rust/prio/src/prng.rs index cb7d3a54c8..2c3f5b6640 100644 --- a/third_party/rust/prio/src/prng.rs +++ b/third_party/rust/prio/src/prng.rs @@ -6,10 +6,9 @@ //! NOTE: The public API for this module is a work in progress. use crate::field::{FieldElement, FieldElementExt}; -#[cfg(feature = "crypto-dependencies")] +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] use crate::vdaf::xof::SeedStreamAes128; -#[cfg(feature = "crypto-dependencies")] -use getrandom::getrandom; +use crate::vdaf::xof::{Seed, SeedStreamTurboShake128, Xof, XofTurboShake128}; use rand_core::RngCore; use std::marker::PhantomData; @@ -19,6 +18,7 @@ const BUFFER_SIZE_IN_ELEMENTS: usize = 32; /// Errors propagated by methods in this module. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum PrngError { /// Failure when calling getrandom(). #[error("getrandom: {0}")] @@ -35,7 +35,7 @@ pub(crate) struct Prng { buffer_index: usize, } -#[cfg(feature = "crypto-dependencies")] +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] impl Prng { /// Create a [`Prng`] from a seed for Prio 2. The first 16 bytes of the seed and the last 16 /// bytes of the seed are used, respectively, for the key and initialization vector for AES128 @@ -44,12 +44,17 @@ impl Prng { let seed_stream = SeedStreamAes128::new(&seed[..16], &seed[16..]); Self::from_seed_stream(seed_stream) } +} +impl Prng { /// Create a [`Prng`] from a randomly generated seed. pub(crate) fn new() -> Result { - let mut seed = [0; 32]; - getrandom(&mut seed)?; - Ok(Self::from_prio2_seed(&seed)) + let seed = Seed::generate()?; + Ok(Prng::from_seed_stream(XofTurboShake128::seed_stream( + &seed, + &[], + &[], + ))) } } @@ -125,18 +130,20 @@ where #[cfg(test)] mod tests { use super::*; + #[cfg(feature = "experimental")] + use crate::field::{encode_fieldvec, Field128, FieldPrio2}; use crate::{ codec::Decode, - field::{Field64, FieldPrio2}, - vdaf::xof::{Seed, SeedStreamSha3, Xof, XofShake128}, + field::Field64, + vdaf::xof::{Seed, SeedStreamTurboShake128, Xof, XofTurboShake128}, }; - #[cfg(feature = "prio2")] + #[cfg(feature = "experimental")] use base64::{engine::Engine, prelude::BASE64_STANDARD}; - #[cfg(feature = "prio2")] + #[cfg(feature = "experimental")] use sha2::{Digest, Sha256}; - use std::convert::TryInto; #[test] + #[cfg(feature = "experimental")] fn secret_sharing_interop() { let seed = [ 0xcd, 0x85, 0x5b, 0xd4, 0x86, 0x48, 0xa4, 0xce, 0x52, 0x5c, 0x36, 0xee, 0x5a, 0x71, @@ -158,21 +165,22 @@ mod tests { } /// takes a seed and hash as base64 encoded strings - #[cfg(feature = "prio2")] + #[cfg(feature = "experimental")] fn random_data_interop(seed_base64: &str, hash_base64: &str, len: usize) { let seed = BASE64_STANDARD.decode(seed_base64).unwrap(); let random_data = extract_share_from_seed::(len, &seed); - let random_bytes = FieldPrio2::slice_into_byte_vec(&random_data); + let mut random_bytes = Vec::new(); + encode_fieldvec(&random_data, &mut random_bytes).unwrap(); - let mut hasher = Sha256::new(); + let mut hasher = ::new(); hasher.update(&random_bytes); let digest = hasher.finalize(); assert_eq!(BASE64_STANDARD.encode(digest), hash_base64); } #[test] - #[cfg(feature = "prio2")] + #[cfg(feature = "experimental")] fn test_hash_interop() { random_data_interop( "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=", @@ -206,6 +214,7 @@ mod tests { ); } + #[cfg(feature = "experimental")] fn extract_share_from_seed(length: usize, seed: &[u8]) -> Vec { assert_eq!(seed.len(), 32); Prng::from_prio2_seed(seed.try_into().unwrap()) @@ -218,22 +227,22 @@ mod tests { // These constants were found in a brute-force search, and they test that the XOF performs // rejection sampling correctly when the raw output exceeds the prime modulus. let seed = Seed::get_decoded(&[ - 0x29, 0xb2, 0x98, 0x64, 0xb4, 0xaa, 0x4e, 0x07, 0x2a, 0x44, 0x49, 0x24, 0xf6, 0x74, - 0x0a, 0x3d, + 0xd5, 0x3f, 0xff, 0x5d, 0x88, 0x8c, 0x60, 0x4e, 0x9f, 0x24, 0x16, 0xe1, 0xa2, 0x0a, + 0x62, 0x34, ]) .unwrap(); - let expected = Field64::from(2035552711764301796); + let expected = Field64::from(3401316594827516850); - let seed_stream = XofShake128::seed_stream(&seed, b"", b""); + let seed_stream = XofTurboShake128::seed_stream(&seed, b"", b""); let mut prng = Prng::::from_seed_stream(seed_stream); - let actual = prng.nth(33236).unwrap(); + let actual = prng.nth(662).unwrap(); assert_eq!(actual, expected); #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] { - let mut seed_stream = XofShake128::seed_stream(&seed, b"", b""); + let mut seed_stream = XofTurboShake128::seed_stream(&seed, b"", b""); let mut actual = ::zero(); - for _ in 0..=33236 { + for _ in 0..=662 { actual = ::generate(&mut seed_stream, &()); } assert_eq!(actual, expected); @@ -246,12 +255,12 @@ mod tests { fn left_over_buffer_back_fill() { let seed = Seed::generate().unwrap(); - let mut prng: Prng = - Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b"")); + let mut prng: Prng = + Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b"")); // Construct a `Prng` with a longer-than-usual buffer. - let mut prng_weird_buffer_size: Prng = - Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b"")); + let mut prng_weird_buffer_size: Prng = + Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b"")); let mut extra = [0; 7]; prng_weird_buffer_size.seed_stream.fill_bytes(&mut extra); prng_weird_buffer_size.buffer.extend_from_slice(&extra); @@ -265,13 +274,13 @@ mod tests { #[cfg(feature = "experimental")] #[test] - fn into_new_field() { + fn into_different_field() { let seed = Seed::generate().unwrap(); - let want: Prng = - Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b"")); + let want: Prng = + Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b"")); let want_buffer = want.buffer.clone(); - let got: Prng = want.into_new_field(); + let got: Prng = want.into_new_field(); assert_eq!(got.buffer_index, 0); assert_eq!(got.buffer, want_buffer); } diff --git a/third_party/rust/prio/src/topology/ping_pong.rs b/third_party/rust/prio/src/topology/ping_pong.rs index c55d4f638d..646f181865 100644 --- a/third_party/rust/prio/src/topology/ping_pong.rs +++ b/third_party/rust/prio/src/topology/ping_pong.rs @@ -4,7 +4,7 @@ //! two aggregators, designated "Leader" and "Helper". This topology is required for implementing //! the [Distributed Aggregation Protocol][DAP]. //! -//! [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8 +//! [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8 //! [DAP]: https://datatracker.ietf.org/doc/html/draft-ietf-ppm-dap use crate::{ @@ -15,6 +15,7 @@ use std::fmt::Debug; /// Errors emitted by this module. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum PingPongError { /// Error running prepare_init #[error("vdaf.prepare_init: {0}")] @@ -28,12 +29,12 @@ pub enum PingPongError { #[error("vdaf.prepare_next {0}")] VdafPrepareNext(VdafError), - /// Error decoding a prepare share - #[error("decode prep share {0}")] + /// Error encoding or decoding a prepare share + #[error("encode/decode prep share {0}")] CodecPrepShare(CodecError), - /// Error decoding a prepare message - #[error("decode prep message {0}")] + /// Error encoding or decoding a prepare message + #[error("encode/decode prep message {0}")] CodecPrepMessage(CodecError), /// Host is in an unexpected state @@ -63,7 +64,7 @@ pub enum PingPongError { /// variants are opaque byte buffers. This is because the ping-pong routines take responsibility for /// decoding preparation shares and messages, which usually requires having the preparation state. /// -/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8 +/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8 #[derive(Clone, PartialEq, Eq)] pub enum PingPongMessage { /// Corresponds to MessageType.initialize. @@ -108,27 +109,28 @@ impl Debug for PingPongMessage { } impl Encode for PingPongMessage { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { // The encoding includes an implicit discriminator byte, called MessageType in the VDAF // spec. match self { Self::Initialize { prep_share } => { - 0u8.encode(bytes); - encode_u32_items(bytes, &(), prep_share); + 0u8.encode(bytes)?; + encode_u32_items(bytes, &(), prep_share)?; } Self::Continue { prep_msg, prep_share, } => { - 1u8.encode(bytes); - encode_u32_items(bytes, &(), prep_msg); - encode_u32_items(bytes, &(), prep_share); + 1u8.encode(bytes)?; + encode_u32_items(bytes, &(), prep_msg)?; + encode_u32_items(bytes, &(), prep_share)?; } Self::Finish { prep_msg } => { - 2u8.encode(bytes); - encode_u32_items(bytes, &(), prep_msg); + 2u8.encode(bytes)?; + encode_u32_items(bytes, &(), prep_msg)?; } } + Ok(()) } fn encoded_len(&self) -> Option { @@ -182,7 +184,7 @@ impl Decode for PingPongMessage { /// preprocessed prepare message. Their encoding is much smaller than the `(State, Message)` tuple, /// which can always be recomputed with [`Self::evaluate`]. /// -/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8 +/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8 #[derive(Clone, Debug, Eq)] pub struct PingPongTransition< const VERIFY_KEY_SIZE: usize, @@ -212,26 +214,31 @@ impl< ), PingPongError, > { - let prep_msg = self.current_prepare_message.get_encoded(); + let prep_msg = self + .current_prepare_message + .get_encoded() + .map_err(PingPongError::CodecPrepMessage)?; vdaf.prepare_next( self.previous_prepare_state.clone(), self.current_prepare_message.clone(), ) - .map(|transition| match transition { - PrepareTransition::Continue(prep_state, prep_share) => ( + .map_err(PingPongError::VdafPrepareNext) + .and_then(|transition| match transition { + PrepareTransition::Continue(prep_state, prep_share) => Ok(( PingPongState::Continued(prep_state), PingPongMessage::Continue { prep_msg, - prep_share: prep_share.get_encoded(), + prep_share: prep_share + .get_encoded() + .map_err(PingPongError::CodecPrepShare)?, }, - ), - PrepareTransition::Finish(output_share) => ( + )), + PrepareTransition::Finish(output_share) => Ok(( PingPongState::Finished(output_share), PingPongMessage::Finish { prep_msg }, - ), + )), }) - .map_err(PingPongError::VdafPrepareNext) } } @@ -253,9 +260,9 @@ where A: Aggregator, A::PrepareState: Encode, { - fn encode(&self, bytes: &mut Vec) { - self.previous_prepare_state.encode(bytes); - self.current_prepare_message.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.previous_prepare_state.encode(bytes)?; + self.current_prepare_message.encode(bytes) } fn encoded_len(&self) -> Option { @@ -293,7 +300,7 @@ where /// code, and the `Rejected` state is represented as `std::result::Result::Err`, so this enum does /// not include those variants. /// -/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8 +/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8 #[derive(Clone, Debug, PartialEq, Eq)] pub enum PingPongState< const VERIFY_KEY_SIZE: usize, @@ -331,7 +338,7 @@ pub enum PingPongContinuedValue< /// Extension trait on [`crate::vdaf::Aggregator`] which adds the [VDAF Ping-Pong Topology][VDAF]. /// -/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8 +/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8 pub trait PingPongTopology: Aggregator { @@ -351,7 +358,7 @@ pub trait PingPongTopology Result<(Self::State, PingPongMessage), PingPongError>; /// Initialize helper state using the helper's input share and the leader's first prepare share. - /// Corresponds to `ping_pong_helper_init` in the forthcoming `draft-irtf-cfrg-vdaf-07`. + /// Corresponds to `ping_pong_helper_init` in [VDAF]. /// /// If successful, the returned [`PingPongTransition`] should be evaluated, yielding a /// [`PingPongMessage`], which should be transmitted to the leader, and a [`PingPongState`]. @@ -378,6 +385,8 @@ pub trait PingPongTopology { Ok(PingPongContinuedValue::FinishedNoMessage { output_share }) } - (PrepareTransition::Continue(_, _), None) => { - return Err(PingPongError::PeerMessageMismatch { - found: inbound.variant(), - expected: "continue", - }) - } - (PrepareTransition::Finish(_), Some(_)) => { - return Err(PingPongError::PeerMessageMismatch { - found: inbound.variant(), - expected: "finish", - }) - } + (PrepareTransition::Continue(_, _), None) => Err(PingPongError::PeerMessageMismatch { + found: inbound.variant(), + expected: "continue", + }), + (PrepareTransition::Finish(_), Some(_)) => Err(PingPongError::PeerMessageMismatch { + found: inbound.variant(), + expected: "finish", + }), } } } @@ -914,7 +905,7 @@ mod tests { for (message, expected_hex) in messages { let mut encoded_val = Vec::new(); - message.encode(&mut encoded_val); + message.encode(&mut encoded_val).unwrap(); let got_hex = hex::encode(&encoded_val); assert_eq!( &got_hex, expected_hex, @@ -942,7 +933,7 @@ mod tests { current_prepare_message: (), }; - let encoded = transition.get_encoded(); + let encoded = transition.get_encoded().unwrap(); let hex_encoded = hex::encode(&encoded); assert_eq!( diff --git a/third_party/rust/prio/src/vdaf.rs b/third_party/rust/prio/src/vdaf.rs index 1a6c5f0315..e5f4e14c5a 100644 --- a/third_party/rust/prio/src/vdaf.rs +++ b/third_party/rust/prio/src/vdaf.rs @@ -1,14 +1,16 @@ // SPDX-License-Identifier: MPL-2.0 //! Verifiable Distributed Aggregation Functions (VDAFs) as described in -//! [[draft-irtf-cfrg-vdaf-07]]. +//! [[draft-irtf-cfrg-vdaf-08]]. //! -//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ #[cfg(feature = "experimental")] use crate::dp::DifferentialPrivacyStrategy; #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] use crate::idpf::IdpfError; +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] +use crate::vidpf::VidpfError; use crate::{ codec::{CodecError, Decode, Encode, ParameterizedDecode}, field::{encode_fieldvec, merge_vector, FieldElement, FieldError}, @@ -17,15 +19,16 @@ use crate::{ vdaf::xof::Seed, }; use serde::{Deserialize, Serialize}; -use std::{fmt::Debug, io::Cursor}; +use std::{error::Error, fmt::Debug, io::Cursor}; use subtle::{Choice, ConstantTimeEq}; /// A component of the domain-separation tag, used to bind the VDAF operations to the document /// version. This will be revised with each draft with breaking changes. -pub(crate) const VERSION: u8 = 7; +pub(crate) const VERSION: u8 = 8; /// Errors emitted by this module. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum VdafError { /// An error occurred. #[error("vdaf error: {0}")] @@ -55,6 +58,15 @@ pub enum VdafError { #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] #[error("idpf error: {0}")] Idpf(#[from] IdpfError), + + /// VIDPF error. + #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] + #[error("vidpf error: {0}")] + Vidpf(#[from] VidpfError), + + /// Errors from other VDAFs. + #[error(transparent)] + Other(Box), } /// An additive share of a vector of field elements. @@ -67,18 +79,6 @@ pub enum Share { Helper(Seed), } -impl Share { - /// Truncate the Leader's share to the given length. If this is the Helper's share, then this - /// method clones the input without modifying it. - #[cfg(feature = "prio2")] - pub(crate) fn truncated(&self, len: usize) -> Self { - match self { - Self::Leader(ref data) => Self::Leader(data[..len].to_vec()), - Self::Helper(ref seed) => Self::Helper(seed.clone()), - } - } -} - impl PartialEq for Share { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() @@ -130,16 +130,15 @@ impl ParameterizedDecode Encode for Share { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { match self { Share::Leader(share_data) => { for x in share_data { - x.encode(bytes); + x.encode(bytes)?; } + Ok(()) } - Share::Helper(share_seed) => { - share_seed.encode(bytes); - } + Share::Helper(share_seed) => share_seed.encode(bytes), } } @@ -158,9 +157,6 @@ impl Encode for Share { /// and [`Collector`], which define the roles of the various parties involved in the execution of /// the VDAF. pub trait Vdaf: Clone + Debug { - /// Algorithm identifier for this VDAF. - const ID: u32; - /// The type of Client measurement to be aggregated. type Measurement: Clone + Debug; @@ -188,17 +184,20 @@ pub trait Vdaf: Clone + Debug { + for<'a> ParameterizedDecode<(&'a Self, &'a Self::AggregationParam)> + Encode; + /// Return the VDAF's algorithm ID. + fn algorithm_id(&self) -> u32; + /// The number of Aggregators. The Client generates as many input shares as there are /// Aggregators. fn num_aggregators(&self) -> usize; /// Generate the domain separation tag for this VDAF. The output is used for domain separation /// by the XOF. - fn domain_separation_tag(usage: u16) -> [u8; 8] { + fn domain_separation_tag(&self, usage: u16) -> [u8; 8] { let mut dst = [0_u8; 8]; dst[0] = VERSION; dst[1] = 0; // algorithm class - dst[2..6].copy_from_slice(&(Self::ID).to_be_bytes()); + dst[2..6].copy_from_slice(&(self.algorithm_id()).to_be_bytes()); dst[6..8].copy_from_slice(&usage.to_be_bytes()); dst } @@ -211,7 +210,7 @@ pub trait Client: Vdaf { /// /// Implements `Vdaf::shard` from [VDAF]. /// - /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.1 + /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.1 fn shard( &self, measurement: &Self::Measurement, @@ -247,7 +246,7 @@ pub trait Aggregator: Vda /// /// Implements `Vdaf.prep_init` from [VDAF]. /// - /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2 + /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.2 fn prepare_init( &self, verify_key: &[u8; VERIFY_KEY_SIZE], @@ -262,29 +261,7 @@ pub trait Aggregator: Vda /// /// Implements `Vdaf.prep_shares_to_prep` from [VDAF]. /// - /// # Notes - /// - /// [`Self::prepare_shares_to_prepare_message`] is preferable since its name better matches the - /// specification. - /// - /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2 - #[deprecated( - since = "0.15.0", - note = "Use Vdaf::prepare_shares_to_prepare_message instead" - )] - fn prepare_preprocess>( - &self, - agg_param: &Self::AggregationParam, - inputs: M, - ) -> Result { - self.prepare_shares_to_prepare_message(agg_param, inputs) - } - - /// Preprocess a round of preparation shares into a single input to [`Self::prepare_next`]. - /// - /// Implements `Vdaf.prep_shares_to_prep` from [VDAF]. - /// - /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2 + /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.2 fn prepare_shares_to_prepare_message>( &self, agg_param: &Self::AggregationParam, @@ -301,31 +278,7 @@ pub trait Aggregator: Vda /// /// Implements `Vdaf.prep_next` from [VDAF]. /// - /// # Notes - /// - /// [`Self::prepare_next`] is preferable since its name better matches the specification. - /// - /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2 - #[deprecated(since = "0.15.0", note = "Use Vdaf::prepare_next")] - fn prepare_step( - &self, - state: Self::PrepareState, - input: Self::PrepareMessage, - ) -> Result, VdafError> { - self.prepare_next(state, input) - } - - /// Compute the next state transition from the current state and the previous round of input - /// messages. If this returns [`PrepareTransition::Continue`], then the returned - /// [`Self::PrepareShare`] should be combined with the other Aggregators' `PrepareShare`s from - /// this round and passed into another call to this method. This continues until this method - /// returns [`PrepareTransition::Finish`], at which point the returned output share may be - /// aggregated. If the method returns an error, the aggregator should consider its input share - /// invalid and not attempt to process it any further. - /// - /// Implements `Vdaf.prep_next` from [VDAF]. - /// - /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2 + /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.2 fn prepare_next( &self, state: Self::PrepareState, @@ -342,6 +295,7 @@ pub trait Aggregator: Vda /// Aggregator that implements differential privacy with Aggregator-side noise addition. #[cfg(feature = "experimental")] +#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))] pub trait AggregatorWithNoise< const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize, @@ -428,7 +382,7 @@ impl From> for OutputShare { } impl Encode for OutputShare { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { encode_fieldvec(&self.0, bytes) } @@ -451,6 +405,12 @@ impl Debug for OutputShare { pub struct AggregateShare(Vec); +impl From> for AggregateShare { + fn from(other: Vec) -> Self { + Self(other) + } +} + impl PartialEq for AggregateShare { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() @@ -498,7 +458,7 @@ impl AggregateShare { } impl Encode for AggregateShare { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { encode_fieldvec(&self.0, bytes) } @@ -507,151 +467,190 @@ impl Encode for AggregateShare { } } -#[cfg(test)] -pub(crate) fn run_vdaf( - vdaf: &V, - agg_param: &V::AggregationParam, - measurements: M, -) -> Result -where - V: Client<16> + Aggregator + Collector, - M: IntoIterator, -{ +/// Utilities for testing VDAFs. +#[cfg(feature = "test-util")] +#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] +pub mod test_utils { + use super::{Aggregatable, Aggregator, Client, Collector, PrepareTransition, VdafError}; + use crate::codec::{Encode, ParameterizedDecode}; use rand::prelude::*; - let mut rng = thread_rng(); - let mut verify_key = [0; SEED_SIZE]; - rng.fill(&mut verify_key[..]); - - let mut agg_shares: Vec> = vec![None; vdaf.num_aggregators()]; - let mut num_measurements: usize = 0; - for measurement in measurements.into_iter() { - num_measurements += 1; - let nonce = rng.gen(); - let (public_share, input_shares) = vdaf.shard(&measurement, &nonce)?; - let out_shares = run_vdaf_prepare( - vdaf, - &verify_key, - agg_param, - &nonce, - public_share, - input_shares, - )?; - for (out_share, agg_share) in out_shares.into_iter().zip(agg_shares.iter_mut()) { - // Check serialization of output shares - let encoded_out_share = out_share.get_encoded(); - let round_trip_out_share = - V::OutputShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_out_share) - .unwrap(); - assert_eq!(round_trip_out_share.get_encoded(), encoded_out_share); - let this_agg_share = V::AggregateShare::from(out_share); - if let Some(ref mut inner) = agg_share { - inner.merge(&this_agg_share)?; - } else { - *agg_share = Some(this_agg_share); - } + /// Execute the VDAF end-to-end and return the aggregate result. + pub fn run_vdaf( + vdaf: &V, + agg_param: &V::AggregationParam, + measurements: M, + ) -> Result + where + V: Client<16> + Aggregator + Collector, + M: IntoIterator, + { + let mut sharded_measurements = Vec::new(); + for measurement in measurements.into_iter() { + let nonce = random(); + let (public_share, input_shares) = vdaf.shard(&measurement, &nonce)?; + + sharded_measurements.push((public_share, nonce, input_shares)); } - } - for agg_share in agg_shares.iter() { - // Check serialization of aggregate shares - let encoded_agg_share = agg_share.as_ref().unwrap().get_encoded(); - let round_trip_agg_share = - V::AggregateShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_agg_share) - .unwrap(); - assert_eq!(round_trip_agg_share.get_encoded(), encoded_agg_share); - } + run_vdaf_sharded(vdaf, agg_param, sharded_measurements) + } + + /// Execute the VDAF on sharded measurements and return the aggregate result. + pub fn run_vdaf_sharded( + vdaf: &V, + agg_param: &V::AggregationParam, + sharded_measurements: M, + ) -> Result + where + V: Client<16> + Aggregator + Collector, + M: IntoIterator, + I: IntoIterator, + { + let mut rng = thread_rng(); + let mut verify_key = [0; SEED_SIZE]; + rng.fill(&mut verify_key[..]); + + let mut agg_shares: Vec> = vec![None; vdaf.num_aggregators()]; + let mut num_measurements: usize = 0; + for (public_share, nonce, input_shares) in sharded_measurements.into_iter() { + num_measurements += 1; + let out_shares = run_vdaf_prepare( + vdaf, + &verify_key, + agg_param, + &nonce, + public_share, + input_shares, + )?; + for (out_share, agg_share) in out_shares.into_iter().zip(agg_shares.iter_mut()) { + // Check serialization of output shares + let encoded_out_share = out_share.get_encoded().unwrap(); + let round_trip_out_share = + V::OutputShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_out_share) + .unwrap(); + assert_eq!( + round_trip_out_share.get_encoded().unwrap(), + encoded_out_share + ); - let res = vdaf.unshard( - agg_param, - agg_shares.into_iter().map(|option| option.unwrap()), - num_measurements, - )?; - Ok(res) -} + let this_agg_share = V::AggregateShare::from(out_share); + if let Some(ref mut inner) = agg_share { + inner.merge(&this_agg_share)?; + } else { + *agg_share = Some(this_agg_share); + } + } + } -#[cfg(test)] -pub(crate) fn run_vdaf_prepare( - vdaf: &V, - verify_key: &[u8; SEED_SIZE], - agg_param: &V::AggregationParam, - nonce: &[u8; 16], - public_share: V::PublicShare, - input_shares: M, -) -> Result, VdafError> -where - V: Client<16> + Aggregator + Collector, - M: IntoIterator, -{ - let input_shares = input_shares - .into_iter() - .map(|input_share| input_share.get_encoded()); - - let mut states = Vec::new(); - let mut outbound = Vec::new(); - for (agg_id, input_share) in input_shares.enumerate() { - let (state, msg) = vdaf.prepare_init( - verify_key, - agg_id, + for agg_share in agg_shares.iter() { + // Check serialization of aggregate shares + let encoded_agg_share = agg_share.as_ref().unwrap().get_encoded().unwrap(); + let round_trip_agg_share = + V::AggregateShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_agg_share) + .unwrap(); + assert_eq!( + round_trip_agg_share.get_encoded().unwrap(), + encoded_agg_share + ); + } + + let res = vdaf.unshard( agg_param, - nonce, - &public_share, - &V::InputShare::get_decoded_with_param(&(vdaf, agg_id), &input_share) - .expect("failed to decode input share"), + agg_shares.into_iter().map(|option| option.unwrap()), + num_measurements, )?; - states.push(state); - outbound.push(msg.get_encoded()); - } + Ok(res) + } + + /// Execute VDAF preparation for a single report and return the recovered output shares. + pub fn run_vdaf_prepare( + vdaf: &V, + verify_key: &[u8; SEED_SIZE], + agg_param: &V::AggregationParam, + nonce: &[u8; 16], + public_share: V::PublicShare, + input_shares: M, + ) -> Result, VdafError> + where + V: Client<16> + Aggregator + Collector, + M: IntoIterator, + { + let public_share = + V::PublicShare::get_decoded_with_param(vdaf, &public_share.get_encoded().unwrap()) + .unwrap(); + let input_shares = input_shares + .into_iter() + .map(|input_share| input_share.get_encoded().unwrap()); - let mut inbound = vdaf - .prepare_shares_to_prepare_message( - agg_param, - outbound.iter().map(|encoded| { - V::PrepareShare::get_decoded_with_param(&states[0], encoded) - .expect("failed to decode prep share") - }), - )? - .get_encoded(); - - let mut out_shares = Vec::new(); - loop { + let mut states = Vec::new(); let mut outbound = Vec::new(); - for state in states.iter_mut() { - match vdaf.prepare_next( - state.clone(), - V::PrepareMessage::get_decoded_with_param(state, &inbound) - .expect("failed to decode prep message"), - )? { - PrepareTransition::Continue(new_state, msg) => { - outbound.push(msg.get_encoded()); - *state = new_state - } - PrepareTransition::Finish(out_share) => { - out_shares.push(out_share); + for (agg_id, input_share) in input_shares.enumerate() { + let (state, msg) = vdaf.prepare_init( + verify_key, + agg_id, + agg_param, + nonce, + &public_share, + &V::InputShare::get_decoded_with_param(&(vdaf, agg_id), &input_share) + .expect("failed to decode input share"), + )?; + states.push(state); + outbound.push(msg.get_encoded().unwrap()); + } + + let mut inbound = vdaf + .prepare_shares_to_prepare_message( + agg_param, + outbound.iter().map(|encoded| { + V::PrepareShare::get_decoded_with_param(&states[0], encoded) + .expect("failed to decode prep share") + }), + )? + .get_encoded() + .unwrap(); + + let mut out_shares = Vec::new(); + loop { + let mut outbound = Vec::new(); + for state in states.iter_mut() { + match vdaf.prepare_next( + state.clone(), + V::PrepareMessage::get_decoded_with_param(state, &inbound) + .expect("failed to decode prep message"), + )? { + PrepareTransition::Continue(new_state, msg) => { + outbound.push(msg.get_encoded().unwrap()); + *state = new_state + } + PrepareTransition::Finish(out_share) => { + out_shares.push(out_share); + } } } - } - if outbound.len() == vdaf.num_aggregators() { - // Another round is required before output shares are computed. - inbound = vdaf - .prepare_shares_to_prepare_message( - agg_param, - outbound.iter().map(|encoded| { - V::PrepareShare::get_decoded_with_param(&states[0], encoded) - .expect("failed to decode prep share") - }), - )? - .get_encoded(); - } else if outbound.is_empty() { - // Each Aggregator recovered an output share. - break; - } else { - panic!("Aggregators did not finish the prepare phase at the same time"); + if outbound.len() == vdaf.num_aggregators() { + // Another round is required before output shares are computed. + inbound = vdaf + .prepare_shares_to_prepare_message( + agg_param, + outbound.iter().map(|encoded| { + V::PrepareShare::get_decoded_with_param(&states[0], encoded) + .expect("failed to decode prep share") + }), + )? + .get_encoded() + .unwrap(); + } else if outbound.is_empty() { + // Each Aggregator recovered an output share. + break; + } else { + panic!("Aggregators did not finish the prepare phase at the same time"); + } } - } - Ok(out_shares) + Ok(out_shares) + } } #[cfg(test)] @@ -663,20 +662,17 @@ where for<'a> T: ParameterizedDecode<(&'a V, &'a V::AggregationParam)>, { // Generate an arbitrary vector of field elements. - let g = F::one() + F::one(); - let vec: Vec = itertools::iterate(F::one(), |&v| g * v) - .take(length) - .collect(); + let vec: Vec = crate::field::random_vector(length).unwrap(); // Serialize the field element vector into a vector of bytes. let mut bytes = Vec::with_capacity(vec.len() * F::ENCODED_SIZE); - encode_fieldvec(&vec, &mut bytes); + encode_fieldvec(&vec, &mut bytes).unwrap(); // Deserialize the type of interest from those bytes. let value = T::get_decoded_with_param(&(vdaf, agg_param), &bytes).unwrap(); // Round-trip the value back to a vector of bytes. - let encoded = value.get_encoded(); + let encoded = value.get_encoded().unwrap(); assert_eq!(encoded, bytes); } @@ -741,6 +737,7 @@ mod tests { } #[cfg(feature = "test-util")] +#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] pub mod dummy; #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] #[cfg_attr( @@ -748,10 +745,14 @@ pub mod dummy; doc(cfg(all(feature = "crypto-dependencies", feature = "experimental"))) )] pub mod poplar1; -#[cfg(feature = "prio2")] -#[cfg_attr(docsrs, doc(cfg(feature = "prio2")))] +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] +#[cfg_attr( + docsrs, + doc(cfg(all(feature = "crypto-dependencies", feature = "experimental"))) +)] pub mod prio2; pub mod prio3; -#[cfg(test)] -mod prio3_test; +#[cfg(any(test, feature = "test-util"))] +#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] +pub mod prio3_test; pub mod xof; diff --git a/third_party/rust/prio/src/vdaf/dummy.rs b/third_party/rust/prio/src/vdaf/dummy.rs index 507e7916bb..2bb0f96b8a 100644 --- a/third_party/rust/prio/src/vdaf/dummy.rs +++ b/third_party/rust/prio/src/vdaf/dummy.rs @@ -12,6 +12,9 @@ use crate::{ use rand::random; use std::{fmt::Debug, io::Cursor, sync::Arc}; +/// The Dummy VDAF does summation modulus 256 so we can predict aggregation results. +const MODULUS: u64 = u8::MAX as u64 + 1; + type ArcPrepInitFn = Arc Result<(), VdafError> + 'static + Send + Sync>; type ArcPrepStepFn = Arc< @@ -49,7 +52,9 @@ impl Vdaf { move |state| -> Result, VdafError> { let new_round = state.current_round + 1; if new_round == rounds { - Ok(PrepareTransition::Finish(OutputShare(state.input_share))) + Ok(PrepareTransition::Finish(OutputShare(u64::from( + state.input_share, + )))) } else { Ok(PrepareTransition::Continue( PrepareState { @@ -76,7 +81,7 @@ impl Vdaf { self } - /// Provide an alternate implementation of [`vdaf::Aggregator::prepare_step`]. + /// Provide an alternate implementation of [`vdaf::Aggregator::prepare_next`]. pub fn with_prep_step_fn< F: Fn(&PrepareState) -> Result, VdafError>, >( @@ -98,16 +103,18 @@ impl Default for Vdaf { } impl vdaf::Vdaf for Vdaf { - const ID: u32 = 0xFFFF0000; - type Measurement = u8; - type AggregateResult = u8; + type AggregateResult = u64; type AggregationParam = AggregationParam; type PublicShare = (); type InputShare = InputShare; type OutputShare = OutputShare; type AggregateShare = AggregateShare; + fn algorithm_id(&self) -> u32 { + 0xFFFF0000 + } + fn num_aggregators(&self) -> usize { 2 } @@ -155,7 +162,7 @@ impl vdaf::Aggregator<0, 16> for Vdaf { fn aggregate>( &self, - _: &Self::AggregationParam, + _aggregation_param: &Self::AggregationParam, output_shares: M, ) -> Result { let mut aggregate_share = AggregateShare(0); @@ -184,12 +191,28 @@ impl vdaf::Client<16> for Vdaf { } } +impl vdaf::Collector for Vdaf { + fn unshard>( + &self, + aggregation_param: &Self::AggregationParam, + agg_shares: M, + _num_measurements: usize, + ) -> Result { + Ok(agg_shares + .into_iter() + .fold(0, |acc, share| (acc + share.0) % MODULUS) + // Sum in the aggregation parameter so that collections over the same measurements with + // varying parameters will yield predictable but distinct results. + + u64::from(aggregation_param.0)) + } +} + /// A dummy input share. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] pub struct InputShare(pub u8); impl Encode for InputShare { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { self.0.encode(bytes) } @@ -209,7 +232,7 @@ impl Decode for InputShare { pub struct AggregationParam(pub u8); impl Encode for AggregationParam { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { self.0.encode(bytes) } @@ -226,17 +249,17 @@ impl Decode for AggregationParam { /// Dummy output share. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct OutputShare(pub u8); +pub struct OutputShare(pub u64); impl Decode for OutputShare { fn decode(bytes: &mut Cursor<&[u8]>) -> Result { - Ok(Self(u8::decode(bytes)?)) + Ok(Self(u64::decode(bytes)?)) } } impl Encode for OutputShare { - fn encode(&self, bytes: &mut Vec) { - self.0.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.0.encode(bytes) } fn encoded_len(&self) -> Option { @@ -252,9 +275,9 @@ pub struct PrepareState { } impl Encode for PrepareState { - fn encode(&self, bytes: &mut Vec) { - self.input_share.encode(bytes); - self.current_round.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.input_share.encode(bytes)?; + self.current_round.encode(bytes) } fn encoded_len(&self) -> Option { @@ -282,31 +305,30 @@ impl Aggregatable for AggregateShare { type OutputShare = OutputShare; fn merge(&mut self, other: &Self) -> Result<(), VdafError> { - self.0 += other.0; + self.0 = (self.0 + other.0) % MODULUS; Ok(()) } fn accumulate(&mut self, out_share: &Self::OutputShare) -> Result<(), VdafError> { - self.0 += u64::from(out_share.0); + self.0 = (self.0 + out_share.0) % MODULUS; Ok(()) } } impl From for AggregateShare { fn from(out_share: OutputShare) -> Self { - Self(u64::from(out_share.0)) + Self(out_share.0) } } impl Decode for AggregateShare { fn decode(bytes: &mut Cursor<&[u8]>) -> Result { - let val = u64::decode(bytes)?; - Ok(Self(val)) + Ok(Self(u64::decode(bytes)?)) } } impl Encode for AggregateShare { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { self.0.encode(bytes) } @@ -314,3 +336,86 @@ impl Encode for AggregateShare { self.0.encoded_len() } } + +/// Returns the aggregate result that the dummy VDAF would compute over the provided measurements, +/// for the provided aggregation parameter. +pub fn expected_aggregate_result(aggregation_parameter: u8, measurements: M) -> u64 +where + M: IntoIterator, +{ + (measurements.into_iter().map(u64::from).sum::()) % MODULUS + + u64::from(aggregation_parameter) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::vdaf::{test_utils::run_vdaf_sharded, Client}; + use rand::prelude::*; + + fn run_test(rounds: u32, aggregation_parameter: u8) { + let vdaf = Vdaf::new(rounds); + let mut verify_key = [0; 0]; + thread_rng().fill(&mut verify_key[..]); + let measurements = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]; + + let mut sharded_measurements = Vec::new(); + for measurement in measurements { + let nonce = thread_rng().gen(); + let (public_share, input_shares) = vdaf.shard(&measurement, &nonce).unwrap(); + + sharded_measurements.push((public_share, nonce, input_shares)); + } + + let result = run_vdaf_sharded( + &vdaf, + &AggregationParam(aggregation_parameter), + sharded_measurements.clone(), + ) + .unwrap(); + assert_eq!( + result, + expected_aggregate_result(aggregation_parameter, measurements) + ); + } + + #[test] + fn single_round_agg_param_10() { + run_test(1, 10) + } + + #[test] + fn single_round_agg_param_20() { + run_test(1, 20) + } + + #[test] + fn single_round_agg_param_32() { + run_test(1, 32) + } + + #[test] + fn single_round_agg_param_u8_max() { + run_test(1, u8::MAX) + } + + #[test] + fn two_round_agg_param_10() { + run_test(2, 10) + } + + #[test] + fn two_round_agg_param_20() { + run_test(2, 20) + } + + #[test] + fn two_round_agg_param_32() { + run_test(2, 32) + } + + #[test] + fn two_round_agg_param_u8_max() { + run_test(2, u8::MAX) + } +} diff --git a/third_party/rust/prio/src/vdaf/poplar1.rs b/third_party/rust/prio/src/vdaf/poplar1.rs index e8591f2049..514ed39069 100644 --- a/third_party/rust/prio/src/vdaf/poplar1.rs +++ b/third_party/rust/prio/src/vdaf/poplar1.rs @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -//! Implementation of Poplar1 as specified in [[draft-irtf-cfrg-vdaf-07]]. +//! Implementation of Poplar1 as specified in [[draft-irtf-cfrg-vdaf-08]]. //! -//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ use crate::{ codec::{CodecError, Decode, Encode, ParameterizedDecode}, @@ -10,7 +10,7 @@ use crate::{ idpf::{Idpf, IdpfInput, IdpfOutputShare, IdpfPublicShare, IdpfValue, RingBufferCache}, prng::Prng, vdaf::{ - xof::{Seed, Xof, XofShake128}, + xof::{Seed, Xof, XofTurboShake128}, Aggregatable, Aggregator, Client, Collector, PrepareTransition, Vdaf, VdafError, }, }; @@ -34,9 +34,9 @@ const DST_VERIFY_RANDOMNESS: u16 = 4; impl Poplar1 { /// Create an instance of [`Poplar1`]. The caller provides the bit length of each - /// measurement (`BITS` as defined in the [[draft-irtf-cfrg-vdaf-07]]). + /// measurement (`BITS` as defined in [[draft-irtf-cfrg-vdaf-08]]). /// - /// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ + /// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ pub fn new(bits: usize) -> Self { Self { bits, @@ -45,12 +45,12 @@ impl Poplar1 { } } -impl Poplar1 { - /// Create an instance of [`Poplar1`] using [`XofShake128`]. The caller provides the bit length of - /// each measurement (`BITS` as defined in the [[draft-irtf-cfrg-vdaf-07]]). +impl Poplar1 { + /// Create an instance of [`Poplar1`] using [`XofTurboShake128`]. The caller provides the bit length of + /// each measurement (`BITS` as defined in [[draft-irtf-cfrg-vdaf-08]]). /// - /// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ - pub fn new_shake128(bits: usize) -> Self { + /// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ + pub fn new_turboshake128(bits: usize) -> Self { Poplar1::new(bits) } } @@ -65,6 +65,7 @@ pub struct Poplar1 { impl, const SEED_SIZE: usize> Poplar1 { /// Construct a `Prng` with the given seed and info-string suffix. fn init_prng( + &self, seed: &[u8; SEED_SIZE], usage: u16, binder_chunks: I, @@ -75,7 +76,7 @@ impl, const SEED_SIZE: usize> Poplar1 { P: Xof, F: FieldElement, { - let mut xof = P::init(seed, &Self::domain_separation_tag(usage)); + let mut xof = P::init(seed, &self.domain_separation_tag(usage)); for binder_chunk in binder_chunks.into_iter() { xof.update(binder_chunk.as_ref()); } @@ -156,15 +157,15 @@ impl ConstantTimeEq for Poplar1InputShare { } impl Encode for Poplar1InputShare { - fn encode(&self, bytes: &mut Vec) { - self.idpf_key.encode(bytes); - self.corr_seed.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.idpf_key.encode(bytes)?; + self.corr_seed.encode(bytes)?; for corr in self.corr_inner.iter() { - corr[0].encode(bytes); - corr[1].encode(bytes); + corr[0].encode(bytes)?; + corr[1].encode(bytes)?; } - self.corr_leaf[0].encode(bytes); - self.corr_leaf[1].encode(bytes); + self.corr_leaf[0].encode(bytes)?; + self.corr_leaf[1].encode(bytes) } fn encoded_len(&self) -> Option { @@ -219,7 +220,7 @@ impl ConstantTimeEq for Poplar1PrepareState { } impl Encode for Poplar1PrepareState { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { self.0.encode(bytes) } @@ -268,15 +269,15 @@ impl ConstantTimeEq for PrepareStateVariant { } impl Encode for PrepareStateVariant { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { match self { PrepareStateVariant::Inner(prep_state) => { - 0u8.encode(bytes); - prep_state.encode(bytes); + 0u8.encode(bytes)?; + prep_state.encode(bytes) } PrepareStateVariant::Leaf(prep_state) => { - 1u8.encode(bytes); - prep_state.encode(bytes); + 1u8.encode(bytes)?; + prep_state.encode(bytes) } } } @@ -342,16 +343,17 @@ impl Debug for PrepareState { } impl Encode for PrepareState { - fn encode(&self, bytes: &mut Vec) { - self.sketch.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.sketch.encode(bytes)?; // `expect` safety: output_share's length is the same as the number of prefixes; the number // of prefixes is capped at 2^32-1. u32::try_from(self.output_share.len()) .expect("Couldn't convert output_share length to u32") - .encode(bytes); + .encode(bytes)?; for elem in &self.output_share { - elem.encode(bytes); + elem.encode(bytes)?; } + Ok(()) } fn encoded_len(&self) -> Option { @@ -430,14 +432,14 @@ impl ConstantTimeEq for SketchState { } impl Encode for SketchState { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { match self { SketchState::RoundOne { A_share, B_share, .. } => { - 0u8.encode(bytes); - A_share.encode(bytes); - B_share.encode(bytes); + 0u8.encode(bytes)?; + A_share.encode(bytes)?; + B_share.encode(bytes) } SketchState::RoundTwo => 1u8.encode(bytes), } @@ -519,19 +521,19 @@ enum PrepareMessageVariant { } impl Encode for Poplar1PrepareMessage { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { match self.0 { PrepareMessageVariant::SketchInner(vec) => { - vec[0].encode(bytes); - vec[1].encode(bytes); - vec[2].encode(bytes); + vec[0].encode(bytes)?; + vec[1].encode(bytes)?; + vec[2].encode(bytes) } PrepareMessageVariant::SketchLeaf(vec) => { - vec[0].encode(bytes); - vec[1].encode(bytes); - vec[2].encode(bytes); + vec[0].encode(bytes)?; + vec[1].encode(bytes)?; + vec[2].encode(bytes) } - PrepareMessageVariant::Done => (), + PrepareMessageVariant::Done => Ok(()), } } @@ -614,17 +616,19 @@ impl ConstantTimeEq for Poplar1FieldVec { } impl Encode for Poplar1FieldVec { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { match self { Self::Inner(ref data) => { for elem in data { - elem.encode(bytes); + elem.encode(bytes)?; } + Ok(()) } Self::Leaf(ref data) => { for elem in data { - elem.encode(bytes); + elem.encode(bytes)?; } + Ok(()) } } } @@ -769,11 +773,11 @@ impl Poplar1AggregationParam { } impl Encode for Poplar1AggregationParam { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { // Okay to unwrap because `try_from_prefixes()` checks this conversion succeeds. let prefix_count = u32::try_from(self.prefixes.len()).unwrap(); - self.level.encode(bytes); - prefix_count.encode(bytes); + self.level.encode(bytes)?; + prefix_count.encode(bytes)?; // The encoding of the prefixes is defined by treating the IDPF indices as integers, // shifting and ORing them together, and encoding the resulting arbitrary precision integer @@ -799,6 +803,7 @@ impl Encode for Poplar1AggregationParam { let mut packed = packed.into_vec(); packed.reverse(); bytes.append(&mut packed); + Ok(()) } fn encoded_len(&self) -> Option { @@ -839,7 +844,6 @@ impl Decode for Poplar1AggregationParam { } impl, const SEED_SIZE: usize> Vdaf for Poplar1 { - const ID: u32 = 0x00001000; type Measurement = IdpfInput; type AggregateResult = Vec; type AggregationParam = Poplar1AggregationParam; @@ -848,6 +852,10 @@ impl, const SEED_SIZE: usize> Vdaf for Poplar1 { type OutputShare = Poplar1FieldVec; type AggregateShare = Poplar1FieldVec; + fn algorithm_id(&self) -> u32 { + 0x00001000 + } + fn num_aggregators(&self) -> usize { 2 } @@ -870,7 +878,7 @@ impl, const SEED_SIZE: usize> Poplar1 { // Generate the authenticator for each inner level of the IDPF tree. let mut prng = - Self::init_prng::<_, _, Field64>(&poplar_random[2], DST_SHARD_RANDOMNESS, [&[]]); + self.init_prng::<_, _, Field64>(&poplar_random[2], DST_SHARD_RANDOMNESS, [nonce]); let auth_inner: Vec = (0..self.bits - 1).map(|_| prng.get()).collect(); // Generate the authenticator for the last level of the IDPF tree (i.e., the leaves). @@ -900,12 +908,12 @@ impl, const SEED_SIZE: usize> Poplar1 { let corr_seed_0 = &poplar_random[0]; let corr_seed_1 = &poplar_random[1]; let mut prng = prng.into_new_field::(); - let mut corr_prng_0 = Self::init_prng::<_, _, Field64>( + let mut corr_prng_0 = self.init_prng::<_, _, Field64>( corr_seed_0, DST_CORR_INNER, [[0].as_slice(), nonce.as_slice()], ); - let mut corr_prng_1 = Self::init_prng::<_, _, Field64>( + let mut corr_prng_1 = self.init_prng::<_, _, Field64>( corr_seed_1, DST_CORR_INNER, [[1].as_slice(), nonce.as_slice()], @@ -921,12 +929,12 @@ impl, const SEED_SIZE: usize> Poplar1 { // Generate the correlated randomness for the leaf nodes. let mut prng = prng.into_new_field::(); - let mut corr_prng_0 = Self::init_prng::<_, _, Field255>( + let mut corr_prng_0 = self.init_prng::<_, _, Field255>( corr_seed_0, DST_CORR_LEAF, [[0].as_slice(), nonce.as_slice()], ); - let mut corr_prng_1 = Self::init_prng::<_, _, Field255>( + let mut corr_prng_1 = self.init_prng::<_, _, Field255>( corr_seed_1, DST_CORR_LEAF, [[1].as_slice(), nonce.as_slice()], @@ -952,6 +960,60 @@ impl, const SEED_SIZE: usize> Poplar1 { ], )) } + + /// Evaluate the IDPF at the given prefixes and compute the Aggregator's share of the sketch. + #[allow(clippy::too_many_arguments)] + fn eval_and_sketch( + &self, + verify_key: &[u8; SEED_SIZE], + agg_id: usize, + nonce: &[u8; 16], + agg_param: &Poplar1AggregationParam, + public_share: &Poplar1PublicShare, + idpf_key: &Seed<16>, + corr_prng: &mut Prng, + ) -> Result<(Vec, Vec), VdafError> + where + P: Xof, + F: FieldElement, + Poplar1IdpfValue: + From, Poplar1IdpfValue>>, + { + let mut verify_prng = self.init_prng( + verify_key, + DST_VERIFY_RANDOMNESS, + [nonce.as_slice(), agg_param.level.to_be_bytes().as_slice()], + ); + + let mut out_share = Vec::with_capacity(agg_param.prefixes.len()); + let mut sketch_share = vec![ + corr_prng.get(), // a_share + corr_prng.get(), // b_share + corr_prng.get(), // c_share + ]; + + let mut idpf_eval_cache = RingBufferCache::new(agg_param.prefixes.len()); + let idpf = Idpf::, Poplar1IdpfValue>::new((), ()); + for prefix in agg_param.prefixes.iter() { + let share = Poplar1IdpfValue::::from(idpf.eval( + agg_id, + public_share, + idpf_key, + prefix, + nonce, + &mut idpf_eval_cache, + )?); + + let r = verify_prng.get(); + let checked_data_share = share.0[0] * r; + sketch_share[0] += checked_data_share; + sketch_share[1] += checked_data_share * r; + sketch_share[2] += share.0[1] * r; + out_share.push(share.0[0]); + } + + Ok((out_share, sketch_share)) + } } impl, const SEED_SIZE: usize> Client<16> for Poplar1 { @@ -1000,7 +1062,7 @@ impl, const SEED_SIZE: usize> Aggregator }; if usize::from(agg_param.level) < self.bits - 1 { - let mut corr_prng = Self::init_prng::<_, _, Field64>( + let mut corr_prng = self.init_prng::<_, _, Field64>( input_share.corr_seed.as_ref(), DST_CORR_INNER, [[agg_id as u8].as_slice(), nonce.as_slice()], @@ -1011,7 +1073,7 @@ impl, const SEED_SIZE: usize> Aggregator corr_prng.get(); } - let (output_share, sketch_share) = eval_and_sketch::( + let (output_share, sketch_share) = self.eval_and_sketch::( verify_key, agg_id, nonce, @@ -1033,13 +1095,13 @@ impl, const SEED_SIZE: usize> Aggregator Poplar1FieldVec::Inner(sketch_share), )) } else { - let corr_prng = Self::init_prng::<_, _, Field255>( + let corr_prng = self.init_prng::<_, _, Field255>( input_share.corr_seed.as_ref(), DST_CORR_LEAF, [[agg_id as u8].as_slice(), nonce.as_slice()], ); - let (output_share, sketch_share) = eval_and_sketch::( + let (output_share, sketch_share) = self.eval_and_sketch::( verify_key, agg_id, nonce, @@ -1257,59 +1319,6 @@ fn compute_next_corr_shares, S: RngCore>( (corr_0, corr_1) } -/// Evaluate the IDPF at the given prefixes and compute the Aggregator's share of the sketch. -fn eval_and_sketch( - verify_key: &[u8; SEED_SIZE], - agg_id: usize, - nonce: &[u8; 16], - agg_param: &Poplar1AggregationParam, - public_share: &Poplar1PublicShare, - idpf_key: &Seed<16>, - corr_prng: &mut Prng, -) -> Result<(Vec, Vec), VdafError> -where - P: Xof, - F: FieldElement, - Poplar1IdpfValue: - From, Poplar1IdpfValue>>, -{ - // TODO(cjpatton) spec: Consider not encoding the prefixes here. - let mut verify_prng = Poplar1::::init_prng( - verify_key, - DST_VERIFY_RANDOMNESS, - [nonce.as_slice(), agg_param.level.to_be_bytes().as_slice()], - ); - - let mut out_share = Vec::with_capacity(agg_param.prefixes.len()); - let mut sketch_share = vec![ - corr_prng.get(), // a_share - corr_prng.get(), // b_share - corr_prng.get(), // c_share - ]; - - let mut idpf_eval_cache = RingBufferCache::new(agg_param.prefixes.len()); - let idpf = Idpf::, Poplar1IdpfValue>::new((), ()); - for prefix in agg_param.prefixes.iter() { - let share = Poplar1IdpfValue::::from(idpf.eval( - agg_id, - public_share, - idpf_key, - prefix, - nonce, - &mut idpf_eval_cache, - )?); - - let r = verify_prng.get(); - let checked_data_share = share.0[0] * r; - sketch_share[0] += checked_data_share; - sketch_share[1] += checked_data_share * r; - sketch_share[2] += share.0[1] * r; - out_share.push(share.0[0]); - } - - Ok((out_share, sketch_share)) -} - /// Compute the Aggregator's share of the sketch verifier. The shares should sum to zero. #[allow(non_snake_case)] fn finish_sketch( @@ -1447,9 +1456,9 @@ impl Encode for Poplar1IdpfValue where F: FieldElement, { - fn encode(&self, bytes: &mut Vec) { - self.0[0].encode(bytes); - self.0[1].encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.0[0].encode(bytes)?; + self.0[1].encode(bytes) } fn encoded_len(&self) -> Option { @@ -1491,7 +1500,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::vdaf::{equality_comparison_test, run_vdaf_prepare}; + use crate::vdaf::{equality_comparison_test, test_utils::run_vdaf_prepare}; use assert_matches::assert_matches; use rand::prelude::*; use serde::Deserialize; @@ -1628,7 +1637,7 @@ mod tests { #[test] fn shard_prepare() { let mut rng = thread_rng(); - let vdaf = Poplar1::new_shake128(64); + let vdaf = Poplar1::new_turboshake128(64); let verify_key = rng.gen(); let input = IdpfInput::from_bytes(b"12341324"); let nonce = rng.gen(); @@ -1672,7 +1681,7 @@ mod tests { fn heavy_hitters() { let mut rng = thread_rng(); let verify_key = rng.gen(); - let vdaf = Poplar1::new_shake128(8); + let vdaf = Poplar1::new_turboshake128(8); run_heavy_hitters( &vdaf, @@ -1699,7 +1708,7 @@ mod tests { corr_leaf: [Field255::one(), ::zero()], }; assert_eq!( - input_share.get_encoded().len(), + input_share.get_encoded().unwrap().len(), input_share.encoded_len().unwrap() ); @@ -1710,7 +1719,7 @@ mod tests { Field64::one(), ])); assert_eq!( - prep_msg.get_encoded().len(), + prep_msg.get_encoded().unwrap().len(), prep_msg.encoded_len().unwrap() ); let prep_msg = Poplar1PrepareMessage(PrepareMessageVariant::SketchLeaf([ @@ -1719,24 +1728,24 @@ mod tests { Field255::one(), ])); assert_eq!( - prep_msg.get_encoded().len(), + prep_msg.get_encoded().unwrap().len(), prep_msg.encoded_len().unwrap() ); let prep_msg = Poplar1PrepareMessage(PrepareMessageVariant::Done); assert_eq!( - prep_msg.get_encoded().len(), + prep_msg.get_encoded().unwrap().len(), prep_msg.encoded_len().unwrap() ); // Field vector variants. let field_vec = Poplar1FieldVec::Inner(vec![Field64::one(); 23]); assert_eq!( - field_vec.get_encoded().len(), + field_vec.get_encoded().unwrap().len(), field_vec.encoded_len().unwrap() ); let field_vec = Poplar1FieldVec::Leaf(vec![Field255::one(); 23]); assert_eq!( - field_vec.get_encoded().len(), + field_vec.get_encoded().unwrap().len(), field_vec.encoded_len().unwrap() ); @@ -1747,7 +1756,7 @@ mod tests { ])) .unwrap(); assert_eq!( - agg_param.get_encoded().len(), + agg_param.get_encoded().unwrap().len(), agg_param.encoded_len().unwrap() ); let agg_param = Poplar1AggregationParam::try_from_prefixes(Vec::from([ @@ -1756,14 +1765,14 @@ mod tests { ])) .unwrap(); assert_eq!( - agg_param.get_encoded().len(), + agg_param.get_encoded().unwrap().len(), agg_param.encoded_len().unwrap() ); } #[test] fn round_trip_prepare_state() { - let vdaf = Poplar1::new_shake128(1); + let vdaf = Poplar1::new_turboshake128(1); for (agg_id, prep_state) in [ ( 0, @@ -1862,7 +1871,7 @@ mod tests { })), ), ] { - let encoded_prep_state = prep_state.get_encoded(); + let encoded_prep_state = prep_state.get_encoded().unwrap(); assert_eq!(prep_state.encoded_len(), Some(encoded_prep_state.len())); let decoded_prep_state = Poplar1PrepareState::get_decoded_with_param(&(&vdaf, agg_id), &encoded_prep_state) @@ -1947,7 +1956,7 @@ mod tests { ), ] { let agg_param = Poplar1AggregationParam::try_from_prefixes(prefixes).unwrap(); - let encoded = agg_param.get_encoded(); + let encoded = agg_param.get_encoded().unwrap(); assert_eq!(encoded, reference_encoding); let decoded = Poplar1AggregationParam::get_decoded(reference_encoding).unwrap(); assert_eq!(decoded, agg_param); @@ -2037,7 +2046,7 @@ mod tests { } // Shard measurement. - let poplar = Poplar1::new_shake128(test_vector.bits); + let poplar = Poplar1::new_turboshake128(test_vector.bits); let (public_share, input_shares) = poplar .shard_with_random(&measurement, &nonce, &idpf_random, &poplar_random) .unwrap(); @@ -2118,14 +2127,17 @@ mod tests { Poplar1PublicShare::get_decoded_with_param(&poplar, prep.public_share.as_ref()) .unwrap() ); - assert_eq!(&public_share.get_encoded(), prep.public_share.as_ref()); + assert_eq!( + &public_share.get_encoded().unwrap(), + prep.public_share.as_ref() + ); assert_eq!( input_shares[0], Poplar1InputShare::get_decoded_with_param(&(&poplar, 0), prep.input_shares[0].as_ref()) .unwrap() ); assert_eq!( - &input_shares[0].get_encoded(), + &input_shares[0].get_encoded().unwrap(), prep.input_shares[0].as_ref() ); assert_eq!( @@ -2134,7 +2146,7 @@ mod tests { .unwrap() ); assert_eq!( - &input_shares[1].get_encoded(), + &input_shares[1].get_encoded().unwrap(), prep.input_shares[1].as_ref() ); assert_eq!( @@ -2146,7 +2158,7 @@ mod tests { .unwrap() ); assert_eq!( - &init_prep_share_0.get_encoded(), + &init_prep_share_0.get_encoded().unwrap(), prep.prep_shares[0][0].as_ref() ); assert_eq!( @@ -2158,7 +2170,7 @@ mod tests { .unwrap() ); assert_eq!( - &init_prep_share_1.get_encoded(), + &init_prep_share_1.get_encoded().unwrap(), prep.prep_shares[0][1].as_ref() ); assert_eq!( @@ -2169,7 +2181,10 @@ mod tests { ) .unwrap() ); - assert_eq!(&r1_prep_msg.get_encoded(), prep.prep_messages[0].as_ref()); + assert_eq!( + &r1_prep_msg.get_encoded().unwrap(), + prep.prep_messages[0].as_ref() + ); assert_eq!( r1_prep_share_0, @@ -2180,7 +2195,7 @@ mod tests { .unwrap() ); assert_eq!( - &r1_prep_share_0.get_encoded(), + &r1_prep_share_0.get_encoded().unwrap(), prep.prep_shares[1][0].as_ref() ); assert_eq!( @@ -2192,7 +2207,7 @@ mod tests { .unwrap() ); assert_eq!( - &r1_prep_share_1.get_encoded(), + &r1_prep_share_1.get_encoded().unwrap(), prep.prep_shares[1][1].as_ref() ); assert_eq!( @@ -2203,7 +2218,10 @@ mod tests { ) .unwrap() ); - assert_eq!(&r2_prep_msg.get_encoded(), prep.prep_messages[1].as_ref()); + assert_eq!( + &r2_prep_msg.get_encoded().unwrap(), + prep.prep_messages[1].as_ref() + ); for (out_share, expected_out_share) in [ (out_share_0, &prep.out_shares[0]), (out_share_1, &prep.out_shares[1]), @@ -2212,13 +2230,13 @@ mod tests { Poplar1FieldVec::Inner(vec) => { assert_eq!(vec.len(), expected_out_share.len()); for (element, expected) in vec.iter().zip(expected_out_share.iter()) { - assert_eq!(&element.get_encoded(), expected.as_ref()); + assert_eq!(&element.get_encoded().unwrap(), expected.as_ref()); } } Poplar1FieldVec::Leaf(vec) => { assert_eq!(vec.len(), expected_out_share.len()); for (element, expected) in vec.iter().zip(expected_out_share.iter()) { - assert_eq!(&element.get_encoded(), expected.as_ref()); + assert_eq!(&element.get_encoded().unwrap(), expected.as_ref()); } } }; @@ -2233,7 +2251,7 @@ mod tests { ); assert_eq!( - &agg_share_0.get_encoded(), + &agg_share_0.get_encoded().unwrap(), test_vector.agg_shares[0].as_ref() ); assert_eq!( @@ -2245,7 +2263,7 @@ mod tests { .unwrap() ); assert_eq!( - &agg_share_1.get_encoded(), + &agg_share_1.get_encoded().unwrap(), test_vector.agg_shares[1].as_ref() ); assert_eq!(agg_result, test_vector.agg_result); @@ -2253,22 +2271,22 @@ mod tests { #[test] fn test_vec_poplar1_0() { - check_test_vec(include_str!("test_vec/07/Poplar1_0.json")); + check_test_vec(include_str!("test_vec/08/Poplar1_0.json")); } #[test] fn test_vec_poplar1_1() { - check_test_vec(include_str!("test_vec/07/Poplar1_1.json")); + check_test_vec(include_str!("test_vec/08/Poplar1_1.json")); } #[test] fn test_vec_poplar1_2() { - check_test_vec(include_str!("test_vec/07/Poplar1_2.json")); + check_test_vec(include_str!("test_vec/08/Poplar1_2.json")); } #[test] fn test_vec_poplar1_3() { - check_test_vec(include_str!("test_vec/07/Poplar1_3.json")); + check_test_vec(include_str!("test_vec/08/Poplar1_3.json")); } #[test] diff --git a/third_party/rust/prio/src/vdaf/prio2.rs b/third_party/rust/prio/src/vdaf/prio2.rs index 4669c47d00..ba725d90d7 100644 --- a/third_party/rust/prio/src/vdaf/prio2.rs +++ b/third_party/rust/prio/src/vdaf/prio2.rs @@ -88,8 +88,13 @@ impl Prio2 { ) .map_err(|e| VdafError::Uncategorized(e.to_string()))?; + let truncated_share = match input_share { + Share::Leader(data) => Share::Leader(data[..self.input_len].to_vec()), + Share::Helper(seed) => Share::Helper(seed.clone()), + }; + Ok(( - Prio2PrepareState(input_share.truncated(self.input_len)), + Prio2PrepareState(truncated_share), Prio2PrepareShare(verifier_share), )) } @@ -117,7 +122,6 @@ impl Prio2 { } impl Vdaf for Prio2 { - const ID: u32 = 0xFFFF0000; type Measurement = Vec; type AggregateResult = Vec; type AggregationParam = (); @@ -126,6 +130,10 @@ impl Vdaf for Prio2 { type OutputShare = OutputShare; type AggregateShare = AggregateShare; + fn algorithm_id(&self) -> u32 { + 0xFFFF0000 + } + fn num_aggregators(&self) -> usize { // Prio2 can easily be extended to support more than two Aggregators. 2 @@ -184,8 +192,8 @@ impl ConstantTimeEq for Prio2PrepareState { } impl Encode for Prio2PrepareState { - fn encode(&self, bytes: &mut Vec) { - self.0.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.0.encode(bytes) } fn encoded_len(&self) -> Option { @@ -213,10 +221,10 @@ impl<'a> ParameterizedDecode<(&'a Prio2, usize)> for Prio2PrepareState { pub struct Prio2PrepareShare(v2_server::VerificationMessage); impl Encode for Prio2PrepareShare { - fn encode(&self, bytes: &mut Vec) { - self.0.f_r.encode(bytes); - self.0.g_r.encode(bytes); - self.0.h_r.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.0.f_r.encode(bytes)?; + self.0.g_r.encode(bytes)?; + self.0.h_r.encode(bytes) } fn encoded_len(&self) -> Option { @@ -388,7 +396,7 @@ mod tests { use super::*; use crate::vdaf::{ equality_comparison_test, fieldvec_roundtrip_test, prio2::test_vector::Priov2TestVector, - run_vdaf, + test_utils::run_vdaf, }; use assert_matches::assert_matches; use rand::prelude::*; @@ -434,7 +442,7 @@ mod tests { ) .unwrap(); - let encoded_prepare_state = prepare_state.get_encoded(); + let encoded_prepare_state = prepare_state.get_encoded().unwrap(); let decoded_prepare_state = Prio2PrepareState::get_decoded_with_param( &(&prio2, agg_id), &encoded_prepare_state, @@ -446,7 +454,7 @@ mod tests { encoded_prepare_state.len() ); - let encoded_prepare_share = prepare_share.get_encoded(); + let encoded_prepare_share = prepare_share.get_encoded().unwrap(); let decoded_prepare_share = Prio2PrepareShare::get_decoded_with_param(&prepare_state, &encoded_prepare_share) .expect("failed to decode prepare share"); diff --git a/third_party/rust/prio/src/vdaf/prio2/client.rs b/third_party/rust/prio/src/vdaf/prio2/client.rs index dbce39ee3f..9515601d8a 100644 --- a/third_party/rust/prio/src/vdaf/prio2/client.rs +++ b/third_party/rust/prio/src/vdaf/prio2/client.rs @@ -4,10 +4,14 @@ //! Primitives for the Prio2 client. use crate::{ - field::{FftFriendlyFieldElement, FieldError}, + codec::CodecError, + field::FftFriendlyFieldElement, polynomial::{poly_fft, PolyAuxMemory}, prng::{Prng, PrngError}, - vdaf::{xof::SeedStreamAes128, VdafError}, + vdaf::{ + xof::{Seed, SeedStreamAes128}, + VdafError, + }, }; use std::convert::TryFrom; @@ -32,9 +36,9 @@ pub enum SerializeError { /// Emitted by `unpack_proof[_mut]` if the serialized share+proof has the wrong length #[error("serialized input has wrong length")] UnpackInputSizeMismatch, - /// Finite field operation error. - #[error("finite field operation error")] - Field(#[from] FieldError), + /// Codec error. + #[error(transparent)] + Codec(#[from] CodecError), } #[derive(Debug)] @@ -63,7 +67,7 @@ impl ClientMemory { } Ok(Self { - prng: Prng::new()?, + prng: Prng::from_prio2_seed(Seed::<32>::generate()?.as_ref()), points_f: vec![F::zero(); n], points_g: vec![F::zero(); n], evals_f: vec![F::zero(); 2 * n], diff --git a/third_party/rust/prio/src/vdaf/prio2/server.rs b/third_party/rust/prio/src/vdaf/prio2/server.rs index 11c161babf..9d2871c867 100644 --- a/third_party/rust/prio/src/vdaf/prio2/server.rs +++ b/third_party/rust/prio/src/vdaf/prio2/server.rs @@ -101,9 +101,13 @@ pub(crate) fn is_valid_share( #[cfg(test)] mod test_util { use crate::{ + codec::ParameterizedDecode, field::{merge_vector, FftFriendlyFieldElement}, prng::Prng, - vdaf::prio2::client::proof_length, + vdaf::{ + prio2::client::{proof_length, SerializeError}, + Share, ShareDecodingParameter, + }, }; use super::{generate_verification_message, is_valid_share, ServerError, VerificationMessage}; @@ -133,17 +137,17 @@ mod test_util { /// Deserialize fn deserialize_share(&self, share: &[u8]) -> Result, ServerError> { let len = proof_length(self.dimension); - Ok(if self.is_first_server { - F::byte_slice_into_vec(share)? + let decoding_parameter = if self.is_first_server { + ShareDecodingParameter::Leader(len) } else { - if share.len() != 32 { - return Err(ServerError::ShareLength); - } - - Prng::from_prio2_seed(&share.try_into().unwrap()) - .take(len) - .collect() - }) + ShareDecodingParameter::Helper + }; + let decoded_share = Share::get_decoded_with_param(&decoding_parameter, share) + .map_err(SerializeError::from)?; + match decoded_share { + Share::Leader(vec) => Ok(vec), + Share::Helper(seed) => Ok(Prng::from_prio2_seed(&seed.0).take(len).collect()), + } } /// Generate verification message from an encrypted share @@ -194,14 +198,19 @@ mod test_util { mod tests { use super::*; use crate::{ - codec::Encode, + codec::{Encode, ParameterizedDecode}, field::{FieldElement, FieldPrio2}, prng::Prng, vdaf::{ - prio2::{client::unpack_proof_mut, server::test_util::Server, Prio2}, - Client, + prio2::{ + client::{proof_length, unpack_proof_mut}, + server::test_util::Server, + Prio2, + }, + Client, Share, ShareDecodingParameter, }, }; + use assert_matches::assert_matches; use rand::{random, Rng}; fn secret_share(share: &mut [FieldPrio2]) -> Vec { @@ -286,10 +295,13 @@ mod tests { let vdaf = Prio2::new(dim).unwrap(); let (_, shares) = vdaf.shard(&data, &[0; 16]).unwrap(); - let share1_original = shares[0].get_encoded(); - let share2 = shares[1].get_encoded(); + let share1_original = shares[0].get_encoded().unwrap(); + let share2 = shares[1].get_encoded().unwrap(); - let mut share1_field = FieldPrio2::byte_slice_into_vec(&share1_original).unwrap(); + let mut share1_field: Vec = assert_matches!( + Share::get_decoded_with_param(&ShareDecodingParameter::<32>::Leader(proof_length(dim)), &share1_original), + Ok(Share::Leader(vec)) => vec + ); let unpacked_share1 = unpack_proof_mut(&mut share1_field, dim).unwrap(); let one = FieldPrio2::from(1); @@ -304,7 +316,9 @@ mod tests { }; // reserialize altered share1 - let share1_modified = FieldPrio2::slice_into_byte_vec(&share1_field); + let share1_modified = Share::::Leader(share1_field) + .get_encoded() + .unwrap(); let mut prng = Prng::from_prio2_seed(&random()); let eval_at = vdaf.choose_eval_at(&mut prng); diff --git a/third_party/rust/prio/src/vdaf/prio2/test_vector.rs b/third_party/rust/prio/src/vdaf/prio2/test_vector.rs index ae2b8b0f9d..114b437b55 100644 --- a/third_party/rust/prio/src/vdaf/prio2/test_vector.rs +++ b/third_party/rust/prio/src/vdaf/prio2/test_vector.rs @@ -48,9 +48,16 @@ mod base64 { //! instead of an array of an array of integers when serializing to JSON. // // Thank you, Alice! https://users.rust-lang.org/t/serialize-a-vec-u8-to-json-as-base64/57781/2 - use crate::field::{FieldElement, FieldPrio2}; + use crate::{ + codec::ParameterizedDecode, + field::{encode_fieldvec, FieldElement, FieldPrio2}, + vdaf::{Share, ShareDecodingParameter}, + }; + use assert_matches::assert_matches; use base64::{engine::Engine, prelude::BASE64_STANDARD}; - use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; + use serde::{ + de::Error as _, ser::Error as _, Deserialize, Deserializer, Serialize, Serializer, + }; pub fn serialize_bytes(v: &[Vec], s: S) -> Result { let base64_vec = v @@ -63,21 +70,28 @@ mod base64 { pub fn deserialize_bytes<'de, D: Deserializer<'de>>(d: D) -> Result>, D::Error> { >::deserialize(d)? .iter() - .map(|s| BASE64_STANDARD.decode(s.as_bytes()).map_err(Error::custom)) + .map(|s| { + BASE64_STANDARD + .decode(s.as_bytes()) + .map_err(D::Error::custom) + }) .collect() } pub fn serialize_field(v: &[FieldPrio2], s: S) -> Result { - String::serialize( - &BASE64_STANDARD.encode(FieldPrio2::slice_into_byte_vec(v)), - s, - ) + let mut bytes = Vec::new(); + encode_fieldvec(v, &mut bytes).map_err(S::Error::custom)?; + String::serialize(&BASE64_STANDARD.encode(&bytes), s) } pub fn deserialize_field<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { let bytes = BASE64_STANDARD .decode(String::deserialize(d)?.as_bytes()) - .map_err(Error::custom)?; - FieldPrio2::byte_slice_into_vec(&bytes).map_err(Error::custom) + .map_err(D::Error::custom)?; + let decoding_parameter = + ShareDecodingParameter::<32>::Leader(bytes.len() / FieldPrio2::ENCODED_SIZE); + let share = Share::::get_decoded_with_param(&decoding_parameter, &bytes) + .map_err(D::Error::custom)?; + assert_matches!(share, Share::Leader(vec) => Ok(vec)) } } diff --git a/third_party/rust/prio/src/vdaf/prio3.rs b/third_party/rust/prio/src/vdaf/prio3.rs index 4a7cdefb84..084f87f411 100644 --- a/third_party/rust/prio/src/vdaf/prio3.rs +++ b/third_party/rust/prio/src/vdaf/prio3.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -//! Implementation of the Prio3 VDAF [[draft-irtf-cfrg-vdaf-07]]. +//! Implementation of the Prio3 VDAF [[draft-irtf-cfrg-vdaf-08]]. //! //! **WARNING:** This code has not undergone significant security analysis. Use at your own risk. //! @@ -9,7 +9,7 @@ //! 2019 [[BBCG+19]], that lead to substantial improvements in terms of run time and communication //! cost. The security of the construction was analyzed in [[DPRS23]]. //! -//! Prio3 is a transformation of a Fully Linear Proof (FLP) system [[draft-irtf-cfrg-vdaf-07]] into +//! Prio3 is a transformation of a Fully Linear Proof (FLP) system [[draft-irtf-cfrg-vdaf-08]] into //! a VDAF. The base type, [`Prio3`], supports a wide variety of aggregation functions, some of //! which are instantiated here: //! @@ -20,14 +20,14 @@ //! //! Additional types can be constructed from [`Prio3`] as needed. //! -//! (*) denotes that the type is specified in [[draft-irtf-cfrg-vdaf-07]]. +//! (*) denotes that the type is specified in [[draft-irtf-cfrg-vdaf-08]]. //! //! [BBCG+19]: https://ia.cr/2019/188 //! [CGB17]: https://crypto.stanford.edu/prio/ //! [DPRS23]: https://ia.cr/2023/130 -//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ -use super::xof::XofShake128; +use super::xof::XofTurboShake128; #[cfg(feature = "experimental")] use super::AggregatorWithNoise; use crate::codec::{CodecError, Decode, Encode, ParameterizedDecode}; @@ -72,19 +72,19 @@ const DST_JOINT_RAND_SEED: u16 = 6; const DST_JOINT_RAND_PART: u16 = 7; /// The count type. Each measurement is an integer in `[0,2)` and the aggregate result is the sum. -pub type Prio3Count = Prio3, XofShake128, 16>; +pub type Prio3Count = Prio3, XofTurboShake128, 16>; impl Prio3Count { /// Construct an instance of Prio3Count with the given number of aggregators. pub fn new_count(num_aggregators: u8) -> Result { - Prio3::new(num_aggregators, Count::new()) + Prio3::new(num_aggregators, 1, 0x00000000, Count::new()) } } /// The count-vector type. Each measurement is a vector of integers in `[0,2^bits)` and the /// aggregate is the element-wise sum. pub type Prio3SumVec = - Prio3>>, XofShake128, 16>; + Prio3>>, XofTurboShake128, 16>; impl Prio3SumVec { /// Construct an instance of Prio3SumVec with the given number of aggregators. `bits` defines @@ -96,7 +96,12 @@ impl Prio3SumVec { len: usize, chunk_length: usize, ) -> Result { - Prio3::new(num_aggregators, SumVec::new(bits, len, chunk_length)?) + Prio3::new( + num_aggregators, + 1, + 0x00000002, + SumVec::new(bits, len, chunk_length)?, + ) } } @@ -104,8 +109,11 @@ impl Prio3SumVec { /// time. Note that the improvement is only noticeable for very large input lengths. #[cfg(feature = "multithreaded")] #[cfg_attr(docsrs, doc(cfg(feature = "multithreaded")))] -pub type Prio3SumVecMultithreaded = - Prio3>>, XofShake128, 16>; +pub type Prio3SumVecMultithreaded = Prio3< + SumVec>>, + XofTurboShake128, + 16, +>; #[cfg(feature = "multithreaded")] impl Prio3SumVecMultithreaded { @@ -118,13 +126,18 @@ impl Prio3SumVecMultithreaded { len: usize, chunk_length: usize, ) -> Result { - Prio3::new(num_aggregators, SumVec::new(bits, len, chunk_length)?) + Prio3::new( + num_aggregators, + 1, + 0x00000002, + SumVec::new(bits, len, chunk_length)?, + ) } } /// The sum type. Each measurement is an integer in `[0,2^bits)` for some `0 < bits < 64` and the /// aggregate is the sum. -pub type Prio3Sum = Prio3, XofShake128, 16>; +pub type Prio3Sum = Prio3, XofTurboShake128, 16>; impl Prio3Sum { /// Construct an instance of Prio3Sum with the given number of aggregators and required bit @@ -136,7 +149,7 @@ impl Prio3Sum { ))); } - Prio3::new(num_aggregators, Sum::new(bits)?) + Prio3::new(num_aggregators, 1, 0x00000001, Sum::new(bits)?) } } @@ -160,7 +173,7 @@ pub type Prio3FixedPointBoundedL2VecSum = Prio3< ParallelSum>, ParallelSum>, >, - XofShake128, + XofTurboShake128, 16, >; @@ -173,7 +186,12 @@ impl Prio3FixedPointBoundedL2VecSum { entries: usize, ) -> Result { check_num_aggregators(num_aggregators)?; - Prio3::new(num_aggregators, FixedPointBoundedL2VecSum::new(entries)?) + Prio3::new( + num_aggregators, + 1, + 0xFFFF0000, + FixedPointBoundedL2VecSum::new(entries)?, + ) } } @@ -191,7 +209,7 @@ pub type Prio3FixedPointBoundedL2VecSumMultithreaded = Prio3< ParallelSumMultithreaded>, ParallelSumMultithreaded>, >, - XofShake128, + XofTurboShake128, 16, >; @@ -204,14 +222,19 @@ impl Prio3FixedPointBoundedL2VecSumMultithreaded Result { check_num_aggregators(num_aggregators)?; - Prio3::new(num_aggregators, FixedPointBoundedL2VecSum::new(entries)?) + Prio3::new( + num_aggregators, + 1, + 0xFFFF0000, + FixedPointBoundedL2VecSum::new(entries)?, + ) } } /// The histogram type. Each measurement is an integer in `[0, length)` and the result is a /// histogram counting the number of occurrences of each measurement. pub type Prio3Histogram = - Prio3>>, XofShake128, 16>; + Prio3>>, XofTurboShake128, 16>; impl Prio3Histogram { /// Constructs an instance of Prio3Histogram with the given number of aggregators, @@ -221,7 +244,12 @@ impl Prio3Histogram { length: usize, chunk_length: usize, ) -> Result { - Prio3::new(num_aggregators, Histogram::new(length, chunk_length)?) + Prio3::new( + num_aggregators, + 1, + 0x00000003, + Histogram::new(length, chunk_length)?, + ) } } @@ -229,8 +257,11 @@ impl Prio3Histogram { /// time. Note that this improvement is only noticeable for very large input lengths. #[cfg(feature = "multithreaded")] #[cfg_attr(docsrs, doc(cfg(feature = "multithreaded")))] -pub type Prio3HistogramMultithreaded = - Prio3>>, XofShake128, 16>; +pub type Prio3HistogramMultithreaded = Prio3< + Histogram>>, + XofTurboShake128, + 16, +>; #[cfg(feature = "multithreaded")] impl Prio3HistogramMultithreaded { @@ -241,13 +272,18 @@ impl Prio3HistogramMultithreaded { length: usize, chunk_length: usize, ) -> Result { - Prio3::new(num_aggregators, Histogram::new(length, chunk_length)?) + Prio3::new( + num_aggregators, + 1, + 0x00000003, + Histogram::new(length, chunk_length)?, + ) } } /// The average type. Each measurement is an integer in `[0,2^bits)` for some `0 < bits < 64` and /// the aggregate is the arithmetic average. -pub type Prio3Average = Prio3, XofShake128, 16>; +pub type Prio3Average = Prio3, XofTurboShake128, 16>; impl Prio3Average { /// Construct an instance of Prio3Average with the given number of aggregators and required bit @@ -263,6 +299,8 @@ impl Prio3Average { Ok(Prio3 { num_aggregators, + num_proofs: 1, + algorithm_id: 0xFFFF0000, typ: Average::new(bits)?, phantom: PhantomData, }) @@ -277,7 +315,7 @@ impl Prio3Average { /// - a [`Xof`] for deriving vectors of field elements from seeds. /// /// New instances can be defined by aliasing the base type. For example, [`Prio3Count`] is an alias -/// for `Prio3, XofShake128, 16>`. +/// for `Prio3, XofTurboShake128, 16>`. /// /// ``` /// use prio::vdaf::{ @@ -292,7 +330,7 @@ impl Prio3Average { /// let mut out_shares = vec![vec![]; num_shares.into()]; /// let mut rng = thread_rng(); /// let verify_key = rng.gen(); -/// let measurements = [0, 1, 1, 1, 0]; +/// let measurements = [false, true, true, true, false]; /// for measurement in measurements { /// // Shard /// let nonce = rng.gen::<[u8; 16]>(); @@ -316,7 +354,7 @@ impl Prio3Average { /// let prep_msg = vdaf.prepare_shares_to_prepare_message(&(), prep_shares).unwrap(); /// /// for (agg_id, state) in prep_states.into_iter().enumerate() { -/// let out_share = match vdaf.prepare_step(state, prep_msg.clone()).unwrap() { +/// let out_share = match vdaf.prepare_next(state, prep_msg.clone()).unwrap() { /// PrepareTransition::Finish(out_share) => out_share, /// _ => panic!("unexpected transition"), /// }; @@ -339,6 +377,8 @@ where P: Xof, { num_aggregators: u8, + num_proofs: u8, + algorithm_id: u32, typ: T, phantom: PhantomData

    , } @@ -348,12 +388,25 @@ where T: Type, P: Xof, { - /// Construct an instance of this Prio3 VDAF with the given number of aggregators and the - /// underlying type. - pub fn new(num_aggregators: u8, typ: T) -> Result { + /// Construct an instance of this Prio3 VDAF with the given number of aggregators, number of + /// proofs to generate and verify, the algorithm ID, and the underlying type. + pub fn new( + num_aggregators: u8, + num_proofs: u8, + algorithm_id: u32, + typ: T, + ) -> Result { check_num_aggregators(num_aggregators)?; + if num_proofs == 0 { + return Err(VdafError::Uncategorized( + "num_proofs must be at least 1".to_string(), + )); + } + Ok(Self { num_aggregators, + num_proofs, + algorithm_id, typ, phantom: PhantomData, }) @@ -369,19 +422,72 @@ where self.typ.verifier_len() } + #[inline] + fn num_proofs(&self) -> usize { + self.num_proofs.into() + } + + fn derive_prove_rands(&self, prove_rand_seed: &Seed) -> Vec { + P::seed_stream( + prove_rand_seed, + &self.domain_separation_tag(DST_PROVE_RANDOMNESS), + &[self.num_proofs], + ) + .into_field_vec(self.typ.prove_rand_len() * self.num_proofs()) + } + fn derive_joint_rand_seed<'a>( - parts: impl Iterator>, + &self, + joint_rand_parts: impl Iterator>, ) -> Seed { let mut xof = P::init( &[0; SEED_SIZE], - &Self::domain_separation_tag(DST_JOINT_RAND_SEED), + &self.domain_separation_tag(DST_JOINT_RAND_SEED), ); - for part in parts { + for part in joint_rand_parts { xof.update(part.as_ref()); } xof.into_seed() } + fn derive_joint_rands<'a>( + &self, + joint_rand_parts: impl Iterator>, + ) -> (Seed, Vec) { + let joint_rand_seed = self.derive_joint_rand_seed(joint_rand_parts); + let joint_rands = P::seed_stream( + &joint_rand_seed, + &self.domain_separation_tag(DST_JOINT_RANDOMNESS), + &[self.num_proofs], + ) + .into_field_vec(self.typ.joint_rand_len() * self.num_proofs()); + + (joint_rand_seed, joint_rands) + } + + fn derive_helper_proofs_share( + &self, + proofs_share_seed: &Seed, + agg_id: u8, + ) -> Prng { + Prng::from_seed_stream(P::seed_stream( + proofs_share_seed, + &self.domain_separation_tag(DST_PROOF_SHARE), + &[self.num_proofs, agg_id], + )) + } + + fn derive_query_rands(&self, verify_key: &[u8; SEED_SIZE], nonce: &[u8; 16]) -> Vec { + let mut xof = P::init( + verify_key, + &self.domain_separation_tag(DST_QUERY_RANDOMNESS), + ); + xof.update(&[self.num_proofs]); + xof.update(nonce); + xof.into_seed_stream() + .into_field_vec(self.typ.query_rand_len() * self.num_proofs()) + } + fn random_size(&self) -> usize { if self.typ.joint_rand_len() == 0 { // Two seeds per helper for measurement and proof shares, plus one seed for proving @@ -438,42 +544,45 @@ where let proof_share_seed = random_seeds.next().unwrap().try_into().unwrap(); let measurement_share_prng: Prng = Prng::from_seed_stream(P::seed_stream( &Seed(measurement_share_seed), - &Self::domain_separation_tag(DST_MEASUREMENT_SHARE), + &self.domain_separation_tag(DST_MEASUREMENT_SHARE), &[agg_id], )); - let joint_rand_blind = - if let Some(helper_joint_rand_parts) = helper_joint_rand_parts.as_mut() { - let joint_rand_blind = random_seeds.next().unwrap().try_into().unwrap(); - let mut joint_rand_part_xof = P::init( - &joint_rand_blind, - &Self::domain_separation_tag(DST_JOINT_RAND_PART), - ); - joint_rand_part_xof.update(&[agg_id]); // Aggregator ID - joint_rand_part_xof.update(nonce); - - let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE); - for (x, y) in leader_measurement_share - .iter_mut() - .zip(measurement_share_prng) - { - *x -= y; - y.encode(&mut encoding_buffer); - joint_rand_part_xof.update(&encoding_buffer); - encoding_buffer.clear(); - } + let joint_rand_blind = if let Some(helper_joint_rand_parts) = + helper_joint_rand_parts.as_mut() + { + let joint_rand_blind = random_seeds.next().unwrap().try_into().unwrap(); + let mut joint_rand_part_xof = P::init( + &joint_rand_blind, + &self.domain_separation_tag(DST_JOINT_RAND_PART), + ); + joint_rand_part_xof.update(&[agg_id]); // Aggregator ID + joint_rand_part_xof.update(nonce); + + let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE); + for (x, y) in leader_measurement_share + .iter_mut() + .zip(measurement_share_prng) + { + *x -= y; + y.encode(&mut encoding_buffer).map_err(|_| { + VdafError::Uncategorized("failed to encode measurement share".to_string()) + })?; + joint_rand_part_xof.update(&encoding_buffer); + encoding_buffer.clear(); + } - helper_joint_rand_parts.push(joint_rand_part_xof.into_seed()); + helper_joint_rand_parts.push(joint_rand_part_xof.into_seed()); - Some(joint_rand_blind) - } else { - for (x, y) in leader_measurement_share - .iter_mut() - .zip(measurement_share_prng) - { - *x -= y; - } - None - }; + Some(joint_rand_blind) + } else { + for (x, y) in leader_measurement_share + .iter_mut() + .zip(measurement_share_prng) + { + *x -= y; + } + None + }; let helper = HelperShare::from_seeds(measurement_share_seed, proof_share_seed, joint_rand_blind); helper_shares.push(helper); @@ -483,71 +592,75 @@ where let public_share = Prio3PublicShare { joint_rand_parts: helper_joint_rand_parts .as_ref() - .map(|helper_joint_rand_parts| { - let leader_blind_bytes = random_seeds.next().unwrap().try_into().unwrap(); - let leader_blind = Seed::from_bytes(leader_blind_bytes); - - let mut joint_rand_part_xof = P::init( - leader_blind.as_ref(), - &Self::domain_separation_tag(DST_JOINT_RAND_PART), - ); - joint_rand_part_xof.update(&[0]); // Aggregator ID - joint_rand_part_xof.update(nonce); - let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE); - for x in leader_measurement_share.iter() { - x.encode(&mut encoding_buffer); - joint_rand_part_xof.update(&encoding_buffer); - encoding_buffer.clear(); - } - leader_blind_opt = Some(leader_blind); - - let leader_joint_rand_seed_part = joint_rand_part_xof.into_seed(); - - let mut vec = Vec::with_capacity(self.num_aggregators()); - vec.push(leader_joint_rand_seed_part); - vec.extend(helper_joint_rand_parts.iter().cloned()); - vec - }), + .map( + |helper_joint_rand_parts| -> Result>, VdafError> { + let leader_blind_bytes = random_seeds.next().unwrap().try_into().unwrap(); + let leader_blind = Seed::from_bytes(leader_blind_bytes); + + let mut joint_rand_part_xof = P::init( + leader_blind.as_ref(), + &self.domain_separation_tag(DST_JOINT_RAND_PART), + ); + joint_rand_part_xof.update(&[0]); // Aggregator ID + joint_rand_part_xof.update(nonce); + let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE); + for x in leader_measurement_share.iter() { + x.encode(&mut encoding_buffer).map_err(|_| { + VdafError::Uncategorized( + "failed to encode measurement share".to_string(), + ) + })?; + joint_rand_part_xof.update(&encoding_buffer); + encoding_buffer.clear(); + } + leader_blind_opt = Some(leader_blind); + + let leader_joint_rand_seed_part = joint_rand_part_xof.into_seed(); + + let mut vec = Vec::with_capacity(self.num_aggregators()); + vec.push(leader_joint_rand_seed_part); + vec.extend(helper_joint_rand_parts.iter().cloned()); + Ok(vec) + }, + ) + .transpose()?, }; // Compute the joint randomness. - let joint_rand: Vec = public_share + let joint_rands = public_share .joint_rand_parts .as_ref() - .map(|joint_rand_parts| { - let joint_rand_seed = Self::derive_joint_rand_seed(joint_rand_parts.iter()); - P::seed_stream( - &joint_rand_seed, - &Self::domain_separation_tag(DST_JOINT_RANDOMNESS), - &[], - ) - .into_field_vec(self.typ.joint_rand_len()) - }) + .map(|joint_rand_parts| self.derive_joint_rands(joint_rand_parts.iter()).1) .unwrap_or_default(); - // Run the proof-generation algorithm. - let prove_rand_seed = random_seeds.next().unwrap().try_into().unwrap(); - let prove_rand = P::seed_stream( - &Seed::from_bytes(prove_rand_seed), - &Self::domain_separation_tag(DST_PROVE_RANDOMNESS), - &[], - ) - .into_field_vec(self.typ.prove_rand_len()); - let mut leader_proof_share = - self.typ - .prove(&encoded_measurement, &prove_rand, &joint_rand)?; + // Generate the proofs. + let prove_rands = self.derive_prove_rands(&Seed::from_bytes( + random_seeds.next().unwrap().try_into().unwrap(), + )); + let mut leader_proofs_share = Vec::with_capacity(self.typ.proof_len() * self.num_proofs()); + for p in 0..self.num_proofs() { + let prove_rand = + &prove_rands[p * self.typ.prove_rand_len()..(p + 1) * self.typ.prove_rand_len()]; + let joint_rand = + &joint_rands[p * self.typ.joint_rand_len()..(p + 1) * self.typ.joint_rand_len()]; + + leader_proofs_share.append(&mut self.typ.prove( + &encoded_measurement, + prove_rand, + joint_rand, + )?); + } // Generate the proof shares and distribute the joint randomness seed hints. for (j, helper) in helper_shares.iter_mut().enumerate() { - let proof_share_prng: Prng = Prng::from_seed_stream(P::seed_stream( - &helper.proof_share, - &Self::domain_separation_tag(DST_PROOF_SHARE), - &[j as u8 + 1], - )); - for (x, y) in leader_proof_share - .iter_mut() - .zip(proof_share_prng) - .take(self.typ.proof_len()) + for (x, y) in + leader_proofs_share + .iter_mut() + .zip(self.derive_helper_proofs_share( + &helper.proofs_share, + u8::try_from(j).unwrap() + 1, + )) + .take(self.typ.proof_len() * self.num_proofs()) { *x -= y; } @@ -557,14 +670,14 @@ where let mut out = Vec::with_capacity(num_aggregators as usize); out.push(Prio3InputShare { measurement_share: Share::Leader(leader_measurement_share), - proof_share: Share::Leader(leader_proof_share), + proofs_share: Share::Leader(leader_proofs_share), joint_rand_blind: leader_blind_opt, }); for helper in helper_shares.into_iter() { out.push(Prio3InputShare { measurement_share: Share::Helper(helper.measurement_share), - proof_share: Share::Helper(helper.proof_share), + proofs_share: Share::Helper(helper.proofs_share), joint_rand_blind: helper.joint_rand_blind, }); } @@ -585,7 +698,6 @@ where T: Type, P: Xof, { - const ID: u32 = T::ID; type Measurement = T::Measurement; type AggregateResult = T::AggregateResult; type AggregationParam = (); @@ -594,6 +706,10 @@ where type OutputShare = OutputShare; type AggregateShare = AggregateShare; + fn algorithm_id(&self) -> u32 { + self.algorithm_id + } + fn num_aggregators(&self) -> usize { self.num_aggregators as usize } @@ -607,12 +723,13 @@ pub struct Prio3PublicShare { } impl Encode for Prio3PublicShare { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { if let Some(joint_rand_parts) = self.joint_rand_parts.as_ref() { for part in joint_rand_parts.iter() { - part.encode(bytes); + part.encode(bytes)?; } } + Ok(()) } fn encoded_len(&self) -> Option { @@ -675,7 +792,7 @@ pub struct Prio3InputShare { measurement_share: Share, /// The proof share. - proof_share: Share, + proofs_share: Share, /// Blinding seed used by the Aggregator to compute the joint randomness. This field is optional /// because not every [`Type`] requires joint randomness. @@ -697,28 +814,29 @@ impl ConstantTimeEq for Prio3InputSha self.joint_rand_blind.as_ref(), other.joint_rand_blind.as_ref(), ) & self.measurement_share.ct_eq(&other.measurement_share) - & self.proof_share.ct_eq(&other.proof_share) + & self.proofs_share.ct_eq(&other.proofs_share) } } impl Encode for Prio3InputShare { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { if matches!( - (&self.measurement_share, &self.proof_share), + (&self.measurement_share, &self.proofs_share), (Share::Leader(_), Share::Helper(_)) | (Share::Helper(_), Share::Leader(_)) ) { panic!("tried to encode input share with ambiguous encoding") } - self.measurement_share.encode(bytes); - self.proof_share.encode(bytes); + self.measurement_share.encode(bytes)?; + self.proofs_share.encode(bytes)?; if let Some(ref blind) = self.joint_rand_blind { - blind.encode(bytes); + blind.encode(bytes)?; } + Ok(()) } fn encoded_len(&self) -> Option { - let mut len = self.measurement_share.encoded_len()? + self.proof_share.encoded_len()?; + let mut len = self.measurement_share.encoded_len()? + self.proofs_share.encoded_len()?; if let Some(ref blind) = self.joint_rand_blind { len += blind.encoded_len()?; } @@ -742,7 +860,7 @@ where let (input_decoder, proof_decoder) = if agg_id == 0 { ( ShareDecodingParameter::Leader(prio3.typ.input_len()), - ShareDecodingParameter::Leader(prio3.typ.proof_len()), + ShareDecodingParameter::Leader(prio3.typ.proof_len() * prio3.num_proofs()), ) } else { ( @@ -752,7 +870,7 @@ where }; let measurement_share = Share::decode_with_param(&input_decoder, bytes)?; - let proof_share = Share::decode_with_param(&proof_decoder, bytes)?; + let proofs_share = Share::decode_with_param(&proof_decoder, bytes)?; let joint_rand_blind = if prio3.typ.joint_rand_len() > 0 { let blind = Seed::decode(bytes)?; Some(blind) @@ -762,7 +880,7 @@ where Ok(Prio3InputShare { measurement_share, - proof_share, + proofs_share, joint_rand_blind, }) } @@ -772,7 +890,7 @@ where /// Message broadcast by each [`Aggregator`] in each round of the Preparation phase. pub struct Prio3PrepareShare { /// A share of the FLP verifier message. (See [`Type`].) - verifier: Vec, + verifiers: Vec, /// A part of the joint randomness seed. joint_rand_part: Option>, @@ -792,25 +910,26 @@ impl ConstantTimeEq for Prio3PrepareS option_ct_eq( self.joint_rand_part.as_ref(), other.joint_rand_part.as_ref(), - ) & self.verifier.ct_eq(&other.verifier) + ) & self.verifiers.ct_eq(&other.verifiers) } } impl Encode for Prio3PrepareShare { - fn encode(&self, bytes: &mut Vec) { - for x in &self.verifier { - x.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + for x in &self.verifiers { + x.encode(bytes)?; } if let Some(ref seed) = self.joint_rand_part { - seed.encode(bytes); + seed.encode(bytes)?; } + Ok(()) } fn encoded_len(&self) -> Option { // Each element of the verifier has the same size. - let mut len = F::ENCODED_SIZE * self.verifier.len(); + let mut len = F::ENCODED_SIZE * self.verifiers.len(); if let Some(ref seed) = self.joint_rand_part { len += seed.encoded_len()?; } @@ -825,9 +944,9 @@ impl decoding_parameter: &Prio3PrepareState, bytes: &mut Cursor<&[u8]>, ) -> Result { - let mut verifier = Vec::with_capacity(decoding_parameter.verifier_len); - for _ in 0..decoding_parameter.verifier_len { - verifier.push(F::decode(bytes)?); + let mut verifiers = Vec::with_capacity(decoding_parameter.verifiers_len); + for _ in 0..decoding_parameter.verifiers_len { + verifiers.push(F::decode(bytes)?); } let joint_rand_part = if decoding_parameter.joint_rand_seed.is_some() { @@ -837,7 +956,7 @@ impl }; Ok(Prio3PrepareShare { - verifier, + verifiers, joint_rand_part, }) } @@ -869,10 +988,11 @@ impl ConstantTimeEq for Prio3PrepareMessage { } impl Encode for Prio3PrepareMessage { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { if let Some(ref seed) = self.joint_rand_seed { - seed.encode(bytes); + seed.encode(bytes)?; } + Ok(()) } fn encoded_len(&self) -> Option { @@ -924,7 +1044,7 @@ pub struct Prio3PrepareState { measurement_share: Share, joint_rand_seed: Option>, agg_id: u8, - verifier_len: usize, + verifiers_len: usize, } impl PartialEq for Prio3PrepareState { @@ -939,7 +1059,7 @@ impl ConstantTimeEq for Prio3PrepareS fn ct_eq(&self, other: &Self) -> Choice { // We allow short-circuiting on the presence or absence of the joint_rand_seed, as well as // the aggregator ID & verifier length parameters. - if self.agg_id != other.agg_id || self.verifier_len != other.verifier_len { + if self.agg_id != other.agg_id || self.verifiers_len != other.verifiers_len { return Choice::from(0); } @@ -962,7 +1082,7 @@ impl Debug for Prio3PrepareState { }, ) .field("agg_id", &self.agg_id) - .field("verifier_len", &self.verifier_len) + .field("verifiers_len", &self.verifiers_len) .finish() } } @@ -971,11 +1091,12 @@ impl Encode for Prio3PrepareState { /// Append the encoded form of this object to the end of `bytes`, growing the vector as needed. - fn encode(&self, bytes: &mut Vec) { - self.measurement_share.encode(bytes); + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + self.measurement_share.encode(bytes)?; if let Some(ref seed) = self.joint_rand_seed { - seed.encode(bytes); + seed.encode(bytes)?; } + Ok(()) } fn encoded_len(&self) -> Option { @@ -1018,7 +1139,7 @@ where measurement_share, joint_rand_seed, agg_id, - verifier_len: prio3.typ.verifier_len(), + verifiers_len: prio3.typ.verifier_len() * prio3.num_proofs(), }) } } @@ -1051,14 +1172,6 @@ where VdafError, > { let agg_id = self.role_try_from(agg_id)?; - let mut query_rand_xof = P::init( - verify_key, - &Self::domain_separation_tag(DST_QUERY_RANDOMNESS), - ); - query_rand_xof.update(nonce); - let query_rand = query_rand_xof - .into_seed_stream() - .into_field_vec(self.typ.query_rand_len()); // Create a reference to the (expanded) measurement share. let expanded_measurement_share: Option> = match msg.measurement_share { @@ -1066,7 +1179,7 @@ where Share::Helper(ref seed) => Some( P::seed_stream( seed, - &Self::domain_separation_tag(DST_MEASUREMENT_SHARE), + &self.domain_separation_tag(DST_MEASUREMENT_SHARE), &[agg_id], ) .into_field_vec(self.typ.input_len()), @@ -1078,33 +1191,32 @@ where }; // Create a reference to the (expanded) proof share. - let expanded_proof_share: Option> = match msg.proof_share { + let expanded_proofs_share: Option> = match msg.proofs_share { Share::Leader(_) => None, - Share::Helper(ref seed) => Some( - P::seed_stream( - seed, - &Self::domain_separation_tag(DST_PROOF_SHARE), - &[agg_id], - ) - .into_field_vec(self.typ.proof_len()), + Share::Helper(ref proof_shares_seed) => Some( + self.derive_helper_proofs_share(proof_shares_seed, agg_id) + .take(self.typ.proof_len() * self.num_proofs()) + .collect(), ), }; - let proof_share = match msg.proof_share { + let proofs_share = match msg.proofs_share { Share::Leader(ref data) => data, - Share::Helper(_) => expanded_proof_share.as_ref().unwrap(), + Share::Helper(_) => expanded_proofs_share.as_ref().unwrap(), }; // Compute the joint randomness. - let (joint_rand_seed, joint_rand_part, joint_rand) = if self.typ.joint_rand_len() > 0 { + let (joint_rand_seed, joint_rand_part, joint_rands) = if self.typ.joint_rand_len() > 0 { let mut joint_rand_part_xof = P::init( msg.joint_rand_blind.as_ref().unwrap().as_ref(), - &Self::domain_separation_tag(DST_JOINT_RAND_PART), + &self.domain_separation_tag(DST_JOINT_RAND_PART), ); joint_rand_part_xof.update(&[agg_id]); joint_rand_part_xof.update(nonce); let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE); for x in measurement_share { - x.encode(&mut encoding_buffer); + x.encode(&mut encoding_buffer).map_err(|_| { + VdafError::Uncategorized("failed to encode measurement share".to_string()) + })?; joint_rand_part_xof.update(&encoding_buffer); encoding_buffer.clear(); } @@ -1131,37 +1243,47 @@ where .skip(agg_id as usize + 1), ); - let joint_rand_seed = Self::derive_joint_rand_seed(corrected_joint_rand_parts); + let (joint_rand_seed, joint_rands) = + self.derive_joint_rands(corrected_joint_rand_parts); - let joint_rand = P::seed_stream( - &joint_rand_seed, - &Self::domain_separation_tag(DST_JOINT_RANDOMNESS), - &[], + ( + Some(joint_rand_seed), + Some(own_joint_rand_part), + joint_rands, ) - .into_field_vec(self.typ.joint_rand_len()); - (Some(joint_rand_seed), Some(own_joint_rand_part), joint_rand) } else { (None, None, Vec::new()) }; // Run the query-generation algorithm. - let verifier_share = self.typ.query( - measurement_share, - proof_share, - &query_rand, - &joint_rand, - self.num_aggregators as usize, - )?; + let query_rands = self.derive_query_rands(verify_key, nonce); + let mut verifiers_share = Vec::with_capacity(self.typ.verifier_len() * self.num_proofs()); + for p in 0..self.num_proofs() { + let query_rand = + &query_rands[p * self.typ.query_rand_len()..(p + 1) * self.typ.query_rand_len()]; + let joint_rand = + &joint_rands[p * self.typ.joint_rand_len()..(p + 1) * self.typ.joint_rand_len()]; + let proof_share = + &proofs_share[p * self.typ.proof_len()..(p + 1) * self.typ.proof_len()]; + + verifiers_share.append(&mut self.typ.query( + measurement_share, + proof_share, + query_rand, + joint_rand, + self.num_aggregators as usize, + )?); + } Ok(( Prio3PrepareState { measurement_share: msg.measurement_share.clone(), joint_rand_seed, agg_id, - verifier_len: verifier_share.len(), + verifiers_len: verifiers_share.len(), }, Prio3PrepareShare { - verifier: verifier_share, + verifiers: verifiers_share, joint_rand_part, }, )) @@ -1174,17 +1296,17 @@ where _: &Self::AggregationParam, inputs: M, ) -> Result, VdafError> { - let mut verifier = vec![T::Field::zero(); self.typ.verifier_len()]; + let mut verifiers = vec![T::Field::zero(); self.typ.verifier_len() * self.num_proofs()]; let mut joint_rand_parts = Vec::with_capacity(self.num_aggregators()); let mut count = 0; for share in inputs.into_iter() { count += 1; - if share.verifier.len() != verifier.len() { + if share.verifiers.len() != verifiers.len() { return Err(VdafError::Uncategorized(format!( "unexpected verifier share length: got {}; want {}", - share.verifier.len(), - verifier.len(), + share.verifiers.len(), + verifiers.len(), ))); } @@ -1193,7 +1315,7 @@ where joint_rand_parts.push(joint_rand_seed_part); } - for (x, y) in verifier.iter_mut().zip(share.verifier) { + for (x, y) in verifiers.iter_mut().zip(share.verifiers) { *x += y; } } @@ -1205,19 +1327,17 @@ where ))); } - // Check the proof verifier. - match self.typ.decide(&verifier) { - Ok(true) => (), - Ok(false) => { + // Check the proof verifiers. + for verifier in verifiers.chunks(self.typ.verifier_len()) { + if !self.typ.decide(verifier)? { return Err(VdafError::Uncategorized( "proof verifier check failed".into(), - )) + )); } - Err(err) => return Err(VdafError::from(err)), - }; + } let joint_rand_seed = if self.typ.joint_rand_len() > 0 { - Some(Self::derive_joint_rand_seed(joint_rand_parts.iter())) + Some(self.derive_joint_rand_seed(joint_rand_parts.iter())) } else { None }; @@ -1249,7 +1369,7 @@ where let measurement_share = match step.measurement_share { Share::Leader(data) => data, Share::Helper(seed) => { - let dst = Self::domain_separation_tag(DST_MEASUREMENT_SHARE); + let dst = self.domain_separation_tag(DST_MEASUREMENT_SHARE); P::seed_stream(&seed, &dst, &[step.agg_id]).into_field_vec(self.typ.input_len()) } }; @@ -1324,7 +1444,7 @@ where #[derive(Clone)] struct HelperShare { measurement_share: Seed, - proof_share: Seed, + proofs_share: Seed, joint_rand_blind: Option>, } @@ -1336,7 +1456,7 @@ impl HelperShare { ) -> Self { HelperShare { measurement_share: Seed::from_bytes(measurement_share), - proof_share: Seed::from_bytes(proof_share), + proofs_share: Seed::from_bytes(proof_share), joint_rand_blind: joint_rand_blind.map(Seed::from_bytes), } } @@ -1458,7 +1578,8 @@ mod tests { #[cfg(feature = "experimental")] use crate::flp::gadgets::ParallelSumGadget; use crate::vdaf::{ - equality_comparison_test, fieldvec_roundtrip_test, run_vdaf, run_vdaf_prepare, + equality_comparison_test, fieldvec_roundtrip_test, + test_utils::{run_vdaf, run_vdaf_prepare}, }; use assert_matches::assert_matches; #[cfg(feature = "experimental")] @@ -1474,24 +1595,27 @@ mod tests { fn test_prio3_count() { let prio3 = Prio3::new_count(2).unwrap(); - assert_eq!(run_vdaf(&prio3, &(), [1, 0, 0, 1, 1]).unwrap(), 3); + assert_eq!( + run_vdaf(&prio3, &(), [true, false, false, true, true]).unwrap(), + 3 + ); let mut nonce = [0; 16]; let mut verify_key = [0; 16]; thread_rng().fill(&mut verify_key[..]); thread_rng().fill(&mut nonce[..]); - let (public_share, input_shares) = prio3.shard(&0, &nonce).unwrap(); + let (public_share, input_shares) = prio3.shard(&false, &nonce).unwrap(); run_vdaf_prepare(&prio3, &verify_key, &(), &nonce, public_share, input_shares).unwrap(); - let (public_share, input_shares) = prio3.shard(&1, &nonce).unwrap(); + let (public_share, input_shares) = prio3.shard(&true, &nonce).unwrap(); run_vdaf_prepare(&prio3, &verify_key, &(), &nonce, public_share, input_shares).unwrap(); - test_serialization(&prio3, &1, &nonce).unwrap(); + test_serialization(&prio3, &true, &nonce).unwrap(); let prio3_extra_helper = Prio3::new_count(3).unwrap(); assert_eq!( - run_vdaf(&prio3_extra_helper, &(), [1, 0, 0, 1, 1]).unwrap(), + run_vdaf(&prio3_extra_helper, &(), [true, false, false, true, true]).unwrap(), 3, ); } @@ -1522,7 +1646,7 @@ mod tests { assert_matches!(result, Err(VdafError::Uncategorized(_))); let (public_share, mut input_shares) = prio3.shard(&1, &nonce).unwrap(); - assert_matches!(input_shares[0].proof_share, Share::Leader(ref mut data) => { + assert_matches!(input_shares[0].proofs_share, Share::Leader(ref mut data) => { data[0] += Field128::one(); }); let result = run_vdaf_prepare(&prio3, &verify_key, &(), &nonce, public_share, input_shares); @@ -1549,6 +1673,30 @@ mod tests { ); } + #[test] + fn test_prio3_sum_vec_multiproof() { + let prio3 = Prio3::< + SumVec>>, + XofTurboShake128, + 16, + >::new(2, 2, 0xFFFF0000, SumVec::new(2, 20, 4).unwrap()) + .unwrap(); + + assert_eq!( + run_vdaf( + &prio3, + &(), + [ + vec![0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1], + vec![0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 1, 3, 0, 3, 0, 0, 0, 1, 0, 0], + vec![1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1], + ] + ) + .unwrap(), + vec![1, 3, 1, 0, 3, 1, 0, 1, 2, 2, 3, 3, 1, 5, 1, 2, 1, 3, 0, 2], + ); + } + #[test] #[cfg(feature = "multithreaded")] fn test_prio3_sum_vec_multithreaded() { @@ -1598,7 +1746,7 @@ mod tests { fn test_fixed_vec( fp_0: Fx, - prio3: Prio3, XofShake128, 16>, + prio3: Prio3, XofTurboShake128, 16>, ) where Fx: Fixed + CompatibleFloat + std::ops::Neg, PE: Eq + ParallelSumGadget> + Clone + 'static, @@ -1690,7 +1838,7 @@ mod tests { fp_4_inv: Fx, fp_8_inv: Fx, fp_16_inv: Fx, - prio3: Prio3, XofShake128, 16>, + prio3: Prio3, XofTurboShake128, 16>, ) where Fx: Fixed + CompatibleFloat + std::ops::Neg, PE: Eq + ParallelSumGadget> + Clone + 'static, @@ -1752,7 +1900,7 @@ mod tests { let (public_share, mut input_shares) = prio3 .shard(&vec![fp_4_inv, fp_8_inv, fp_16_inv], &nonce) .unwrap(); - assert_matches!(input_shares[0].proof_share, Share::Leader(ref mut data) => { + assert_matches!(input_shares[0].proofs_share, Share::Leader(ref mut data) => { data[0] += Field128::one(); }); let result = @@ -1823,7 +1971,7 @@ mod tests { } if let (Share::Helper(left), Share::Helper(right)) = - (&x.proof_share, &y.proof_share) + (&x.proofs_share, &y.proofs_share) { assert_ne!(left, right); } @@ -1847,7 +1995,7 @@ mod tests { thread_rng().fill(&mut verify_key[..]); let (public_share, input_shares) = prio3.shard(measurement, nonce)?; - let encoded_public_share = public_share.get_encoded(); + let encoded_public_share = public_share.get_encoded().unwrap(); let decoded_public_share = Prio3PublicShare::get_decoded_with_param(prio3, &encoded_public_share) .expect("failed to decode public share"); @@ -1858,7 +2006,7 @@ mod tests { ); for (agg_id, input_share) in input_shares.iter().enumerate() { - let encoded_input_share = input_share.get_encoded(); + let encoded_input_share = input_share.get_encoded().unwrap(); let decoded_input_share = Prio3InputShare::get_decoded_with_param(&(prio3, agg_id), &encoded_input_share) .expect("failed to decode input share"); @@ -1875,7 +2023,7 @@ mod tests { let (prepare_state, prepare_share) = prio3.prepare_init(&verify_key, agg_id, &(), nonce, &public_share, input_share)?; - let encoded_prepare_state = prepare_state.get_encoded(); + let encoded_prepare_state = prepare_state.get_encoded().unwrap(); let decoded_prepare_state = Prio3PrepareState::get_decoded_with_param(&(prio3, agg_id), &encoded_prepare_state) .expect("failed to decode prepare state"); @@ -1885,7 +2033,7 @@ mod tests { encoded_prepare_state.len() ); - let encoded_prepare_share = prepare_share.get_encoded(); + let encoded_prepare_share = prepare_share.get_encoded().unwrap(); let decoded_prepare_share = Prio3PrepareShare::get_decoded_with_param(&prepare_state, &encoded_prepare_share) .expect("failed to decode prepare share"); @@ -1903,7 +2051,7 @@ mod tests { .prepare_shares_to_prepare_message(&(), prepare_shares) .unwrap(); - let encoded_prepare_message = prepare_message.get_encoded(); + let encoded_prepare_message = prepare_message.get_encoded().unwrap(); let decoded_prepare_message = Prio3PrepareMessage::get_decoded_with_param( &last_prepare_state.unwrap(), &encoded_prepare_message, @@ -1967,31 +2115,31 @@ mod tests { // Default. Prio3InputShare { measurement_share: Share::Leader(Vec::from([0])), - proof_share: Share::Leader(Vec::from([1])), + proofs_share: Share::Leader(Vec::from([1])), joint_rand_blind: Some(Seed([2])), }, // Modified measurement share. Prio3InputShare { measurement_share: Share::Leader(Vec::from([100])), - proof_share: Share::Leader(Vec::from([1])), + proofs_share: Share::Leader(Vec::from([1])), joint_rand_blind: Some(Seed([2])), }, // Modified proof share. Prio3InputShare { measurement_share: Share::Leader(Vec::from([0])), - proof_share: Share::Leader(Vec::from([101])), + proofs_share: Share::Leader(Vec::from([101])), joint_rand_blind: Some(Seed([2])), }, // Modified joint_rand_blind. Prio3InputShare { measurement_share: Share::Leader(Vec::from([0])), - proof_share: Share::Leader(Vec::from([1])), + proofs_share: Share::Leader(Vec::from([1])), joint_rand_blind: Some(Seed([102])), }, // Missing joint_rand_blind. Prio3InputShare { measurement_share: Share::Leader(Vec::from([0])), - proof_share: Share::Leader(Vec::from([1])), + proofs_share: Share::Leader(Vec::from([1])), joint_rand_blind: None, }, ]) @@ -2002,22 +2150,22 @@ mod tests { equality_comparison_test(&[ // Default. Prio3PrepareShare { - verifier: Vec::from([0]), + verifiers: Vec::from([0]), joint_rand_part: Some(Seed([1])), }, // Modified verifier. Prio3PrepareShare { - verifier: Vec::from([100]), + verifiers: Vec::from([100]), joint_rand_part: Some(Seed([1])), }, // Modified joint_rand_part. Prio3PrepareShare { - verifier: Vec::from([0]), + verifiers: Vec::from([0]), joint_rand_part: Some(Seed([101])), }, // Missing joint_rand_part. Prio3PrepareShare { - verifier: Vec::from([0]), + verifiers: Vec::from([0]), joint_rand_part: None, }, ]) @@ -2049,42 +2197,42 @@ mod tests { measurement_share: Share::Leader(Vec::from([0])), joint_rand_seed: Some(Seed([1])), agg_id: 2, - verifier_len: 3, + verifiers_len: 3, }, // Modified measurement share. Prio3PrepareState { measurement_share: Share::Leader(Vec::from([100])), joint_rand_seed: Some(Seed([1])), agg_id: 2, - verifier_len: 3, + verifiers_len: 3, }, // Modified joint_rand_seed. Prio3PrepareState { measurement_share: Share::Leader(Vec::from([0])), joint_rand_seed: Some(Seed([101])), agg_id: 2, - verifier_len: 3, + verifiers_len: 3, }, // Missing joint_rand_seed. Prio3PrepareState { measurement_share: Share::Leader(Vec::from([0])), joint_rand_seed: None, agg_id: 2, - verifier_len: 3, + verifiers_len: 3, }, // Modified agg_id. Prio3PrepareState { measurement_share: Share::Leader(Vec::from([0])), joint_rand_seed: Some(Seed([1])), agg_id: 102, - verifier_len: 3, + verifiers_len: 3, }, // Modified verifier_len. Prio3PrepareState { measurement_share: Share::Leader(Vec::from([0])), joint_rand_seed: Some(Seed([1])), agg_id: 2, - verifier_len: 103, + verifiers_len: 103, }, ]) } diff --git a/third_party/rust/prio/src/vdaf/prio3_test.rs b/third_party/rust/prio/src/vdaf/prio3_test.rs index 372a2c8560..9a3dfd85f4 100644 --- a/third_party/rust/prio/src/vdaf/prio3_test.rs +++ b/third_party/rust/prio/src/vdaf/prio3_test.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 +//! Tools for evaluating Prio3 test vectors. + use crate::{ codec::{Encode, ParameterizedDecode}, flp::Type, @@ -58,19 +60,21 @@ macro_rules! err { // TODO Generalize this method to work with any VDAF. To do so we would need to add // `shard_with_random()` to traits. (There may be a less invasive alternative.) -fn check_prep_test_vec( +fn check_prep_test_vec( prio3: &Prio3, verify_key: &[u8; SEED_SIZE], test_num: usize, - t: &TPrio3Prep, + t: &TPrio3Prep, ) -> Vec> where - T: Type, + MS: Clone, + MP: From, + T: Type, P: Xof, { let nonce = <[u8; 16]>::try_from(t.nonce.clone()).unwrap(); let (public_share, input_shares) = prio3 - .shard_with_random(&t.measurement, &nonce, &t.rand) + .shard_with_random(&t.measurement.clone().into(), &nonce, &t.rand) .expect("failed to generate input shares"); assert_eq!( @@ -86,7 +90,7 @@ where "#{test_num}" ); assert_eq!( - input_shares[agg_id].get_encoded(), + input_shares[agg_id].get_encoded().unwrap(), want.as_ref(), "#{test_num}" ) @@ -110,14 +114,18 @@ where .unwrap_or_else(|e| err!(test_num, e, "decode test vector (prep share)")), "#{test_num}" ); - assert_eq!(prep_shares[i].get_encoded(), want.as_ref(), "#{test_num}"); + assert_eq!( + prep_shares[i].get_encoded().unwrap(), + want.as_ref(), + "#{test_num}" + ); } let inbound = prio3 .prepare_shares_to_prepare_message(&(), prep_shares) .unwrap_or_else(|e| err!(test_num, e, "prep preprocess")); assert_eq!(t.prep_messages.len(), 1); - assert_eq!(inbound.get_encoded(), t.prep_messages[0].as_ref()); + assert_eq!(inbound.get_encoded().unwrap(), t.prep_messages[0].as_ref()); let mut out_shares = Vec::new(); for state in states.iter_mut() { @@ -130,7 +138,11 @@ where } for (got, want) in out_shares.iter().zip(t.out_shares.iter()) { - let got: Vec> = got.as_ref().iter().map(|x| x.get_encoded()).collect(); + let got: Vec> = got + .as_ref() + .iter() + .map(|x| x.get_encoded().unwrap()) + .collect(); assert_eq!(got.len(), want.len()); for (got_elem, want_elem) in got.iter().zip(want.iter()) { assert_eq!(got_elem.as_slice(), want_elem.as_ref()); @@ -141,12 +153,14 @@ where } #[must_use] -fn check_aggregate_test_vec( +fn check_aggregate_test_vec( prio3: &Prio3, - t: &TPrio3, + t: &TPrio3, ) -> T::AggregateResult where - T: Type, + MS: Clone, + MP: From, + T: Type, P: Xof, { let verify_key = t.verify_key.as_ref().try_into().unwrap(); @@ -167,85 +181,113 @@ where .collect::>(); for (got, want) in aggregate_shares.iter().zip(t.agg_shares.iter()) { - let got = got.get_encoded(); + let got = got.get_encoded().unwrap(); assert_eq!(got.as_slice(), want.as_ref()); } prio3.unshard(&(), aggregate_shares, 1).unwrap() } +/// Evaluate a Prio3 test vector. The instance of Prio3 is constructed from the `new_vdaf` callback, +/// which takes in the VDAF parameters encoded by the test vectors and the number of shares. +/// +/// This version allows customizing the deserialization of measurements, via an additional type +/// parameter. +#[cfg(feature = "test-util")] +#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] +pub fn check_test_vec_custom_de( + test_vec_json_str: &str, + new_vdaf: impl Fn(&HashMap, u8) -> Prio3, +) where + MS: for<'de> Deserialize<'de> + Clone, + MP: From, + A: for<'de> Deserialize<'de> + Debug + Eq, + T: Type, + P: Xof, +{ + let t: TPrio3 = serde_json::from_str(test_vec_json_str).unwrap(); + let vdaf = new_vdaf(&t.other_params, t.shares); + let agg_result = check_aggregate_test_vec(&vdaf, &t); + assert_eq!(agg_result, serde_json::from_value(t.agg_result).unwrap()); +} + +/// Evaluate a Prio3 test vector. The instance of Prio3 is constructed from the `new_vdaf` callback, +/// which takes in the VDAF parameters encoded by the test vectors and the number of shares. +#[cfg(feature = "test-util")] +#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] +pub fn check_test_vec( + test_vec_json_str: &str, + new_vdaf: impl Fn(&HashMap, u8) -> Prio3, +) where + M: for<'de> Deserialize<'de> + Clone, + A: for<'de> Deserialize<'de> + Debug + Eq, + T: Type, + P: Xof, +{ + check_test_vec_custom_de::(test_vec_json_str, new_vdaf) +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(transparent)] +struct Prio3CountMeasurement(u8); + +impl From for bool { + fn from(value: Prio3CountMeasurement) -> Self { + value.0 != 0 + } +} + #[test] fn test_vec_prio3_count() { for test_vector_str in [ - include_str!("test_vec/07/Prio3Count_0.json"), - include_str!("test_vec/07/Prio3Count_1.json"), + include_str!("test_vec/08/Prio3Count_0.json"), + include_str!("test_vec/08/Prio3Count_1.json"), ] { - let t: TPrio3 = serde_json::from_str(test_vector_str).unwrap(); - let prio3 = Prio3::new_count(t.shares).unwrap(); - - let aggregate_result = check_aggregate_test_vec(&prio3, &t); - assert_eq!(aggregate_result, t.agg_result.as_u64().unwrap()); + check_test_vec_custom_de::( + test_vector_str, + |_json_params, num_shares| Prio3::new_count(num_shares).unwrap(), + ); } } #[test] fn test_vec_prio3_sum() { for test_vector_str in [ - include_str!("test_vec/07/Prio3Sum_0.json"), - include_str!("test_vec/07/Prio3Sum_1.json"), + include_str!("test_vec/08/Prio3Sum_0.json"), + include_str!("test_vec/08/Prio3Sum_1.json"), ] { - let t: TPrio3 = serde_json::from_str(test_vector_str).unwrap(); - let bits = t.other_params["bits"].as_u64().unwrap() as usize; - let prio3 = Prio3::new_sum(t.shares, bits).unwrap(); - - let aggregate_result = check_aggregate_test_vec(&prio3, &t); - assert_eq!(aggregate_result, t.agg_result.as_u64().unwrap() as u128); + check_test_vec(test_vector_str, |json_params, num_shares| { + let bits = json_params["bits"].as_u64().unwrap() as usize; + Prio3::new_sum(num_shares, bits).unwrap() + }); } } #[test] fn test_vec_prio3_sum_vec() { for test_vector_str in [ - include_str!("test_vec/07/Prio3SumVec_0.json"), - include_str!("test_vec/07/Prio3SumVec_1.json"), + include_str!("test_vec/08/Prio3SumVec_0.json"), + include_str!("test_vec/08/Prio3SumVec_1.json"), ] { - let t: TPrio3> = serde_json::from_str(test_vector_str).unwrap(); - let bits = t.other_params["bits"].as_u64().unwrap() as usize; - let length = t.other_params["length"].as_u64().unwrap() as usize; - let chunk_length = t.other_params["chunk_length"].as_u64().unwrap() as usize; - let prio3 = Prio3::new_sum_vec(t.shares, bits, length, chunk_length).unwrap(); - - let aggregate_result = check_aggregate_test_vec(&prio3, &t); - let expected_aggregate_result = t - .agg_result - .as_array() - .unwrap() - .iter() - .map(|val| val.as_u64().unwrap() as u128) - .collect::>(); - assert_eq!(aggregate_result, expected_aggregate_result); + check_test_vec(test_vector_str, |json_params, num_shares| { + let bits = json_params["bits"].as_u64().unwrap() as usize; + let length = json_params["length"].as_u64().unwrap() as usize; + let chunk_length = json_params["chunk_length"].as_u64().unwrap() as usize; + Prio3::new_sum_vec(num_shares, bits, length, chunk_length).unwrap() + }); } } #[test] fn test_vec_prio3_histogram() { for test_vector_str in [ - include_str!("test_vec/07/Prio3Histogram_0.json"), - include_str!("test_vec/07/Prio3Histogram_1.json"), + include_str!("test_vec/08/Prio3Histogram_0.json"), + include_str!("test_vec/08/Prio3Histogram_1.json"), ] { - let t: TPrio3 = serde_json::from_str(test_vector_str).unwrap(); - let length = t.other_params["length"].as_u64().unwrap() as usize; - let chunk_length = t.other_params["chunk_length"].as_u64().unwrap() as usize; - let prio3 = Prio3::new_histogram(t.shares, length, chunk_length).unwrap(); - - let aggregate_result = check_aggregate_test_vec(&prio3, &t); - let expected_aggregate_result = t - .agg_result - .as_array() - .unwrap() - .iter() - .map(|val| val.as_u64().unwrap() as u128) - .collect::>(); - assert_eq!(aggregate_result, expected_aggregate_result); + check_test_vec(test_vector_str, |json_params, num_shares| { + let length = json_params["length"].as_u64().unwrap() as usize; + let chunk_length = json_params["chunk_length"].as_u64().unwrap() as usize; + Prio3::new_histogram(num_shares, length, chunk_length).unwrap() + }); } } diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json deleted file mode 100644 index 2ff7aa7ffd..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "alpha": "0", - "beta_inner": [ - [ - "0", - "0" - ], - [ - "1", - "1" - ], - [ - "2", - "2" - ], - [ - "3", - "3" - ], - [ - "4", - "4" - ], - [ - "5", - "5" - ], - [ - "6", - "6" - ], - [ - "7", - "7" - ], - [ - "8", - "8" - ] - ], - "beta_leaf": [ - "9", - "9" - ], - "binder": "736f6d65206e6f6e6365", - "bits": 10, - "keys": [ - "000102030405060708090a0b0c0d0e0f", - "101112131415161718191a1b1c1d1e1f" - ], - "public_share": "921909356f44964d29c537aeeaeba92e573e4298c88dcc35bd3ae6acb4367236226b1af3151d5814f308f04e208fde2110c72523338563bc1c5fb47d22b5c34ae102e1e82fa250c7e23b95e985f91d7d91887fa7fb301ec20a06b1d4408d9a594754dcd86ec00c91f40f17c1ff52ed99fcd59965fe243a6cec7e672fefc5e3a29e653d5dcca8917e8af2c4f19d122c6dd30a3e2a80fb809383ced9d24fcd86516025174f5183fddfc6d74dde3b78834391c785defc8e4fbff92214df4c8322ee433a8eaeed7369419e0d6037a536e081df333aaab9e8e4d207d846961f015d96d57e3b59e24927773d6e0d66108955c1da134baab4eacd363c8e452b8c3845d5fb5c0ff6c27d7423a73d32742ccc3c750a17cd1f6026dd98a2cf6d2bff2dd339017b25af23d6db00ae8975e3f7e6aaef4af71f3e8cd14eb5c4373db9c3a76fc04659b761e650a97cb873df894064ecb2043a4317ef237ffe8f130eb5c2ca2a132c16f14943cd7e462568c8544b82e29329eb2a" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json deleted file mode 100644 index 79fadca3df..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "agg_param": [ - 0, - [ - 0, - 1 - ] - ], - "agg_result": [ - 0, - 1 - ], - "agg_shares": [ - "70f1cb8dc03c9eea88d270d6211a8667", - "910e34723ec361157a2d8f29dde57998" - ], - "bits": 4, - "prep": [ - { - "input_shares": [ - "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930", - "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c" - ], - "measurement": 13, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "70f1cb8dc03c9eea", - "88d270d6211a8667" - ], - [ - "910e34723ec36115", - "7a2d8f29dde57998" - ] - ], - "prep_messages": [ - "d4cd54eb29f676c2d10fab848e6e85ebd51804e3562cf23b", - "" - ], - "prep_shares": [ - [ - "bd68d28c9fff9a30f84122278759025501b83270bf27b41d", - "1765825e8af6db91d9cd885d07158396d460d17297043e1e" - ], - [ - "7c9659b7c681b4a4", - "8569a648387e4b5b" - ] - ], - "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json deleted file mode 100644 index a566fe8b4d..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "agg_param": [ - 1, - [ - 0, - 1, - 2, - 3 - ] - ], - "agg_result": [ - 0, - 0, - 0, - 1 - ], - "agg_shares": [ - "d83fbcbf13566502f5849058b8b089e568a4e8aab8565425f69a56f809fc4527", - "29c04340eba99afd0c7b6fa7464f761a995b175546a9abda0c65a907f503bad8" - ], - "bits": 4, - "prep": [ - { - "input_shares": [ - "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930", - "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c" - ], - "measurement": 13, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "d83fbcbf13566502", - "f5849058b8b089e5", - "68a4e8aab8565425", - "f69a56f809fc4527" - ], - [ - "29c04340eba99afd", - "0c7b6fa7464f761a", - "995b175546a9abda", - "0c65a907f503bad8" - ] - ], - "prep_messages": [ - "d45c0eabcc906acfb8239f3d0ef2b69a0f465979b04e355c", - "" - ], - "prep_shares": [ - [ - "5d1b91841835491251436306076eaaa674d4b95b84b2a084", - "77417d26b45b21bd68e03b3706840cf49c719f1d2b9c94d7" - ], - [ - "6e703a28b5960604", - "938fc5d74969f9fb" - ] - ], - "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json deleted file mode 100644 index 8141bc942e..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "agg_param": [ - 2, - [ - 0, - 2, - 4, - 6 - ] - ], - "agg_result": [ - 0, - 0, - 0, - 1 - ], - "agg_shares": [ - "7ea47022f22f6be9bce8e0ee2eb522bcbc2d246c17704beed7043426b646fe26", - "835b8fdd0cd0941645171f11d04add4345d2db93e78fb4112bfbcbd948b901d9" - ], - "bits": 4, - "prep": [ - { - "input_shares": [ - "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930", - "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c" - ], - "measurement": 13, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "7ea47022f22f6be9", - "bce8e0ee2eb522bc", - "bc2d246c17704bee", - "d7043426b646fe26" - ], - [ - "835b8fdd0cd09416", - "45171f11d04add43", - "45d2db93e78fb411", - "2bfbcbd948b901d9" - ] - ], - "prep_messages": [ - "6fb240ce8b8a2a8ce62112240f676105e0398515599f04b4", - "" - ], - "prep_shares": [ - [ - "ca0f02c7c61655263bf76d954b8abd16eb6e5ce2b26911b2", - "a5a23e07c573d565ac2aa48ec2dca3eef5ca2833a635f301" - ], - [ - "f5171a3cc9d49422", - "0ce8e5c3352b6bdd" - ] - ], - "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json deleted file mode 100644 index 1741ec0ebc..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "agg_param": [ - 3, - [ - 1, - 3, - 5, - 7, - 9, - 13, - 15 - ] - ], - "agg_result": [ - 0, - 0, - 0, - 0, - 0, - 1, - 0 - ], - "agg_shares": [ - "ec2be80f01fd1ded599b1a18d6ef112c400f421cca2c080d4ccc5cdd09562b3e556c1aaabe9dd47e8bc25979394c7bb5c61fd1db34b8dfdcc3eff4a5304fb7706b5462025bb400e644f2e0752f38098702491691494a2b498176ef41c4e6a962f716473c53087a3e80db0b9acb50cb15081b5ea4b50c48093f67a8c75875422dfd64ab2fa71fa3f3b55ec708ba4086672aff514d0cffe6f1c07f117c22af9b2c67b2a0c7ec1366ce474721174edb8b9eb33faef5f9c9d0c956e4407a86473120cfa46e8c634c1bc66c63a2009911f82c8426a45013e637aaba0e471b03f0a67a", - "01d417f0fe02e212a664e5e72910eed3bff0bde335d3f7f2b333a322f6a9d4419893e55541622b81743da686c6b3844a39e02e24cb4720233c100b5acfb0480f82ab9dfda44bff19bb0d1f8ad0c7f678fdb6e96eb6b5d4b67e8910be3b19561df6e8b8c3acf785c17f24f46534af34eaf7e4a15b4af3b7f6c0985738a78abd52f09a54d058e05c0c4aa138f745bf7998d500aeb2f300190e3f80ee83dd506453874d5f3813ec9931b8b8dee8b12474614cc0510a06362f36a91bbf8579b8ce5f1e5b91739cb3e439939c5dff66ee07d37bd95bafec19c85545f1b8e4fc0f5905" - ], - "bits": 4, - "prep": [ - { - "input_shares": [ - "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930", - "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c" - ], - "measurement": 13, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "ec2be80f01fd1ded599b1a18d6ef112c400f421cca2c080d4ccc5cdd09562b3e", - "556c1aaabe9dd47e8bc25979394c7bb5c61fd1db34b8dfdcc3eff4a5304fb770", - "6b5462025bb400e644f2e0752f38098702491691494a2b498176ef41c4e6a962", - "f716473c53087a3e80db0b9acb50cb15081b5ea4b50c48093f67a8c75875422d", - "fd64ab2fa71fa3f3b55ec708ba4086672aff514d0cffe6f1c07f117c22af9b2c", - "67b2a0c7ec1366ce474721174edb8b9eb33faef5f9c9d0c956e4407a86473120", - "cfa46e8c634c1bc66c63a2009911f82c8426a45013e637aaba0e471b03f0a67a" - ], - [ - "01d417f0fe02e212a664e5e72910eed3bff0bde335d3f7f2b333a322f6a9d441", - "9893e55541622b81743da686c6b3844a39e02e24cb4720233c100b5acfb0480f", - "82ab9dfda44bff19bb0d1f8ad0c7f678fdb6e96eb6b5d4b67e8910be3b19561d", - "f6e8b8c3acf785c17f24f46534af34eaf7e4a15b4af3b7f6c0985738a78abd52", - "f09a54d058e05c0c4aa138f745bf7998d500aeb2f300190e3f80ee83dd506453", - "874d5f3813ec9931b8b8dee8b12474614cc0510a06362f36a91bbf8579b8ce5f", - "1e5b91739cb3e439939c5dff66ee07d37bd95bafec19c85545f1b8e4fc0f5905" - ] - ], - "prep_messages": [ - "4a2b97cf17e54b126a86c6791c50d6507ee8b74b3d9903bcf3881121bc6e0975c4efb2d8b8a132b8a6caa4eb39ac2bbb5bdc351604fa9e78d1a6f5a5f615bb0c8819f485d8b24a4e48da47d3b7458a9cfde1e85c66453319a3f6d43dc40a0135", - "" - ], - "prep_shares": [ - [ - "4e64e5ed76c69ef68d3e144918a719986e40ab82f34bd30298b0085a3265d16988b8f646731ef47cb2fb1598e4cb817747623f1cc70ee7843ce1a9d6e3cf5c456801c9a3ae0c7c7663349a3daaf8fb51d165085c751e5bdd4e800df9e1e0193e", - "fcc6b1e1a01ead1bdc47b23004a9bcb80fa80cc9494d30b95bd808c78909380b2937bc9145833e3bf4ce8e5355e0a943147af6f93cebb7f394c54bcf12465e470d182be229a6ced7e4a5ad950d4d8e4a2c7ce000f126d83b5476c744e229e776" - ], - [ - "003c39f76240f6f9bcc6065a247b4432a651d5d72a35aff45928eec28c8a9d07", - "edc3c6089dbf09064339f9a5db84bbcd59ae2a28d5ca500ba6d7113d73756278" - ] - ], - "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json deleted file mode 100644 index c27ad93435..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "agg_param": null, - "agg_result": 1, - "agg_shares": [ - "afead111dacc0c7e", - "53152eee2433f381" - ], - "prep": [ - { - "input_shares": [ - "afead111dacc0c7ec08c411babd6e2404df512ddfa0a81736b7607f4ccb3f39e414fdb4bc89a63569702c92aed6a6a96", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" - ], - "measurement": 1, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "afead111dacc0c7e" - ], - [ - "53152eee2433f381" - ] - ], - "prep_messages": [ - "" - ], - "prep_shares": [ - [ - "123f23c117b7ed6099be9e6a31a42a9caa60882a3b4aa50303f8b588c9efe60b", - "efc0dc3ee748129f2da661f47a625a57d64a5b62ab38647c34bb161c7576d721" - ] - ], - "public_share": "", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json deleted file mode 100644 index 148fe6df58..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "agg_param": null, - "agg_result": 1, - "agg_shares": [ - "c5647e016eea69f6", - "53152eee2433f381", - "eb8553106be2a287" - ], - "prep": [ - { - "input_shares": [ - "c5647e016eea69f6d10e90d05e2ad8b402b8580f394a719b371ae8f1a364b280d08ca7177946a1a0b9643e2469b0a2e9", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", - "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" - ], - "measurement": 1, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "c5647e016eea69f6" - ], - [ - "53152eee2433f381" - ], - [ - "eb8553106be2a287" - ] - ], - "prep_messages": [ - "" - ], - "prep_shares": [ - [ - "5c8d00fd24e449d375581d6adbeaf9cf4bdface6d368fd7b1562e5bf47b9fa68", - "efc0dc3ee748129f2da661f47a625a57d64a5b62ab38647c34bb161c7576d721", - "b7b122c4f1d2a38df764c623c266f02f7b5178c3d64735ec06037585d643f528" - ] - ], - "public_share": "", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 3, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json deleted file mode 100644 index 099f786669..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "agg_param": null, - "agg_result": [ - 0, - 0, - 1, - 0 - ], - "agg_shares": [ - "14be9c4ef7a6e12e963fdeac21cebdd4d36e13f4bc25306322e56303c62c90afd73f6b4aa9fdf33cb0afb55426d645ff8cd7e78cebf9d4f1087f6d4a033c8eae", - "ed4163b108591ed14dc02153de31422b2e91ec0b43dacf9cc11a9cfc39d36f502bc094b556020cc333504aabd929ba007528187314062b0edb8092b5fcc37151" - ], - "chunk_length": 2, - "length": 4, - "prep": [ - { - "input_shares": [ - "14be9c4ef7a6e12e963fdeac21cebdd4d36e13f4bc25306322e56303c62c90afd73f6b4aa9fdf33cb0afb55426d645ff8cd7e78cebf9d4f1087f6d4a033c8eaeec786d3b212d968c939de66318dbacafe73c1f5aa3e9078ba2f63ec5179e6b4694612c36f5d4d539d46dab1ac20e43963978d9dd36f19f31c83e58c903c2cd94215c68b15f5d6071e9e19fa973829dc71b536351b0db1072e77b7570e3e06c65fac248d21dd970f29640050e901d06775f05a897850cab5707ac25543ed6ce7061b9cd70c783e0483727236d0cbb05dafefd78ec4e6419efe93d6f82cdadbfd4e860661238040229f60205bbba983790303132333435363738393a3b3c3d3e3f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" - ], - "measurement": 2, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "14be9c4ef7a6e12e963fdeac21cebdd4", - "d36e13f4bc25306322e56303c62c90af", - "d73f6b4aa9fdf33cb0afb55426d645ff", - "8cd7e78cebf9d4f1087f6d4a033c8eae" - ], - [ - "ed4163b108591ed14dc02153de31422b", - "2e91ec0b43dacf9cc11a9cfc39d36f50", - "2bc094b556020cc333504aabd929ba00", - "7528187314062b0edb8092b5fcc37151" - ] - ], - "prep_messages": [ - "7556ccbddbd14d509ee89124d31d1feb" - ], - "prep_shares": [ - [ - "806b1f8537500ce0b4b501b0ae5ed8f82679ba11ad995d6f605b000e32c41afb6d0070287fe7b99b8304d264cba1e3c6f4456e1c06f3b9d3d4947b2041c86b020d26c74d7663817e6a91960489806931b304fcd3755b43b96c806d2bbeb0166bbec7c61c35f886f3f539890522388f43", - "8194e07ac8aff31f2f4afe4f51a12707b692a56a1745315a1022b4eb257b2a8725c610416af7b0d1a296f409cdb3fbf4f4c0d488206d794254e4755fd124cdc9a67364ddc7865afe3554de5f52f1ac910f3f8e110cfbad4113861316dc73ec60de4f6c512adaa41de631eda8d6d8c189" - ] - ], - "public_share": "bec7c61c35f886f3f539890522388f43de4f6c512adaa41de631eda8d6d8c189", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json deleted file mode 100644 index 0b9a9b4d5d..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "agg_param": null, - "agg_result": [ - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "agg_shares": [ - "a6d2b4756e63a10bf5f650e258c73b0ccb20bace98e225dea29d625d527fdd4ded86beb9a0a0ac5c4216f5add7a297cece34b479a568a327f1e259839f813df97b34de254be5b9b9c8d9e56dbff50b7a6bf1e5967686755a1dc42e0ab170add8c88f8ca68f945e768a5007c775fd27cfecb4495e257a2f2f94ca48830aa16ec0decaeee645e295c5dc2ebe491aae1a7f17b2807fcb33ee08127db466067bf84ec613dac9c93adbe73dd262c1859b2865", - "ed4163b108591ed14dc02153de31422b2e91ec0b43dacf9cc11a9cfc39d36f502bc094b556020cc333504aabd929ba007528187314062b0edb8092b5fcc3715126e16ce274ad58caaa14d22608269a4c41a256d3c9e847c0a6ac1a4fbaf6309e9ccbe74a9442ca956d843d6bd5adf9797a84557597d9cc81ddfa281ae5048d686bdb289ec2f3c96cdfa79b6974e6d15aec047748636d4358226283e11a78e045f59db2dda566162a56c85936ac0f4696", - "6eebe7d888434023a1488dcac80682c8084e592524430a857f4701a673adb261eab8ac90085d47e06d99c0a64e33ae30bfa23313469131cafb9b13c763ba50b560eab4f73f6ded7b7011486b38e45939566cc395bf9042e5038fb6a6949821899ea48b0edc28d7f3cf2abbcdb454deb69cc6602c43ac034f563a8e62105a04d7b859e87af729a0cd2729a64c716b1326fe480838d15ece9eaf20c8b7de0c276b464e7358905e0eee4f654308ce549104" - ], - "chunk_length": 3, - "length": 11, - "prep": [ - { - "input_shares": [ - "a6d2b4756e63a10bf5f650e258c73b0ccb20bace98e225dea29d625d527fdd4ded86beb9a0a0ac5c4216f5add7a297cece34b479a568a327f1e259839f813df97b34de254be5b9b9c8d9e56dbff50b7a6bf1e5967686755a1dc42e0ab170add8c88f8ca68f945e768a5007c775fd27cfecb4495e257a2f2f94ca48830aa16ec0decaeee645e295c5dc2ebe491aae1a7f17b2807fcb33ee08127db466067bf84ec613dac9c93adbe73dd262c1859b2865508d344dda6c4339e650c401324c31481780ef7e7dcc07120ac004c05ab75ee5d22e2d0eb229dcdd3755fab49a1c2916e17c8ed2d975cfe76d576569bf05233c07f94417fccaf73d1cc33e17dae74650badffdd639a9b9f9e89de4b9fd13e258b90fbb2b3817b607dc14e6e5327746ca20d1f1918bce9714b135ffe01eb4e6aefab92b0462f7e676e26007e8c2e5a66e16f32f7c8457a6dfba39d9082f640006d560b4d64e86e2e2358c84e03b857c980f51b1a78b53f7cb44343ed184d8dc87ebf8698609eeefae5d8882224ebd28b9531015badea8ae9fe01c7495cafecdc4f13389ea4eb0bbce0a5ab85aa6fc06aabd96d28c84ecf039bfeb4c350049485f8a4c706a109164ff4c640edaedd0ad50820b1d1ed7ab08fc69c48b39aff1eebc02ef1ea40bd70784bfa50511c3dd64b107f4297842280c3cff8d94be202a0e2cb0090f3adb2189f445fcf291f452f162606162636465666768696a6b6c6d6e6f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", - "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" - ], - "measurement": 2, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "a6d2b4756e63a10bf5f650e258c73b0c", - "cb20bace98e225dea29d625d527fdd4d", - "ed86beb9a0a0ac5c4216f5add7a297ce", - "ce34b479a568a327f1e259839f813df9", - "7b34de254be5b9b9c8d9e56dbff50b7a", - "6bf1e5967686755a1dc42e0ab170add8", - "c88f8ca68f945e768a5007c775fd27cf", - "ecb4495e257a2f2f94ca48830aa16ec0", - "decaeee645e295c5dc2ebe491aae1a7f", - "17b2807fcb33ee08127db466067bf84e", - "c613dac9c93adbe73dd262c1859b2865" - ], - [ - "ed4163b108591ed14dc02153de31422b", - "2e91ec0b43dacf9cc11a9cfc39d36f50", - "2bc094b556020cc333504aabd929ba00", - "7528187314062b0edb8092b5fcc37151", - "26e16ce274ad58caaa14d22608269a4c", - "41a256d3c9e847c0a6ac1a4fbaf6309e", - "9ccbe74a9442ca956d843d6bd5adf979", - "7a84557597d9cc81ddfa281ae5048d68", - "6bdb289ec2f3c96cdfa79b6974e6d15a", - "ec047748636d4358226283e11a78e045", - "f59db2dda566162a56c85936ac0f4696" - ], - [ - "6eebe7d888434023a1488dcac80682c8", - "084e592524430a857f4701a673adb261", - "eab8ac90085d47e06d99c0a64e33ae30", - "bfa23313469131cafb9b13c763ba50b5", - "60eab4f73f6ded7b7011486b38e45939", - "566cc395bf9042e5038fb6a694982189", - "9ea48b0edc28d7f3cf2abbcdb454deb6", - "9cc6602c43ac034f563a8e62105a04d7", - "b859e87af729a0cd2729a64c716b1326", - "fe480838d15ece9eaf20c8b7de0c276b", - "464e7358905e0eee4f654308ce549104" - ] - ], - "prep_messages": [ - "4b7dc5c1b2a08aec5dcfc13de800559b" - ], - "prep_shares": [ - [ - "e80c098526d9321dd0801f97a648722016fa117f10cb2b062fc5fb1e55705894007f838333ef348c6306e141369bd88d123c66d2faeb132e330a73882c38765d425847bd86e5f784b3348ee4840c5df103b49f04c4dcca4667abb956187da58c91c946d9d5fdf496d95428f8a625dddfc8b7bb469397ebd4b177f902896febdaac39a8d9ec0aa1a24132036c2430929c", - "4f6d4137ddffd58b243b8f845a1684550b240ea3e91a68335f717b83056e9b45c5e62d7a24da54147fcb9260d023cb7f9c8d036f0100f5fea0ce22f49e3d7672bc83fd5c724f2684f3442e8c5291c41509151808d1da447cddc3fe11cf5cd8d7fe662cf035eff88b583f6b32499b332aa6dee37947ef482e15fcb3a7f04b20813162d162b9bf30eee4953b6fdabd10f1", - "ca85b543fc26f756ef4351e4fea0098a73787eeab8b613029af310882b7e87d28fc5502fd76bd704626d9f0f662e531feaf1fa912cc209de6541401d8508a4788d92e549f58241334cfa29abc1fb80a28ae61d7a4060d9582e3e20f182e4519ab1bb9547c545aafc21416e779856c80cf3690155119111aebf3800757989229e4966453f7aa269163b272848de80227f" - ] - ], - "public_share": "ac39a8d9ec0aa1a24132036c2430929c3162d162b9bf30eee4953b6fdabd10f14966453f7aa269163b272848de80227f", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" - } - ], - "shares": 3, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json deleted file mode 100644 index a7178fcfee..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "agg_param": null, - "agg_result": [ - 256, - 257, - 258, - 259, - 260, - 261, - 262, - 263, - 264, - 265 - ], - "agg_shares": [ - "cdeb52d4615d1c718ef21a6560939efcb5024c89ea9b0f0018302087c0e978b5b5c84c8c4f217b14584cc3939963f56a2718c17af81d1f85129347fc73b2548262e047a67c3e0583eeef7c4a98a5da4ccdb558491081a00a8de5a46b8c2f299bc69162a7411b3ecf2b47670db337083dc50b8fc6d5c5d21da52fc7f538166b0e4564edd8fbb75bc8c4fdd0c02be2b6d11bc4a159297b72e2c635a9250feb2445", - "3415ad2b9ea2e38e550de59a9f6c61034dfeb3761564f0ffcbcfdf783f16874a4e38b373b0de84eb8bb33c6c669c0a95dde83e8507e2e07ad16cb8038c4dab7da320b85983c1fa7cf50f83b5675a25b3394ba7b6ef7e5ff5561a5b9473d0d664416f9d58bee4c130b8b898f24cc8f7c243f570392a3a2de23ed0380ac7e994f1c49c12270448a4371f022f3fd41d492eef3c5ea6d6848d1d1dca56daf014dbba" - ], - "bits": 8, - "chunk_length": 9, - "length": 10, - "prep": [ - { - "input_shares": [ - "2451f59efba2edc493c9246ff1f0e0a7f8f6f22ee46e662c899e485d7ce288d6becdfee804a39618972fbaa595eeec25423e412cbe51d44a62747de627630302368ec3535a2545a2799e8a0b9a144c811158dda278865d834b34fbe77ad11dbb9fdcf0637c24e10d5ab36d03cdc5f6b95e400a0a81608d96c25733c376376de3927c3570e8ab671358a1686d0c44ac938368d5621cff66585454ef124daa5f18efd7e791a4bcb11caf74b378e2c4feff3e5bad16e7c3fab987eb4d4a0c675bb4f4e70e1373fb00a5dd30a1118355c20e2e4c3700be3d3c1cf25d3e4a729836ba564aa074f99be0d23d4cc0dc9f263c986988e0d16a3d28c262d34f220b1ed127cddea3e2a1bd075c653d4b6f1c3d35e25d2804e7960250dea42dc4a52c9545bedc182ee8391b4c6849366af8e15f30bd06872e5ed651ef7db0b0c442886de32eeeeacc5f2dfe87f9375b4774153fc9e442105b5f8e452e80874c84131400d4d588a1a5d94bac9e68dbf917ef6405b0bc13fa89daf46f84405aedb166ac93f6545256b1da6ac65e01d580bb26eef82c34b9d728fc0c96ff898ed46bd289abbec9917397552ebf6d1eb3f916f69ee9f80e9466512bff70af2d8f3a9ed599f24e33550a09304e1b4f51948e2d8cbf5a1bb14455b1786ae3af4670111bc3983293ad9ae029128efd86d0a05cb3f442b43f466cec5cc9c4989bf5a29eb5c2401bc8bba0d5b7487bc0bf010c968fe76e3a9924459dce6704528d56540081240ed0d2f301a8c9baca5c183b1b5c3a9c03dce5036926d06e1470c2e63d15fdc3a61056154fca9439c595098ff3794c7d7e62af5e3139b43e22a0f8864c254a069a083604762d77ea000177a7b908efe27f6e00db7ea25f573734af803044fb2dc333ed9ad589d7677e23614143fa6836d68ed311dcedf0ea031688b2cf8c5248f21be444f1c61b050a0ab7dca04992673afb737bd27526a72dda3b03dad4d3b0bb81f0887ee6f25ec4cf35d58ea5f085e97609cfb6a8e97d84fdf8755b8e81ff29614bf1b03bcd2b8d9ab06dc4d60785f83eb6ee4573859223214ecdad734d114e15e1971a8b82222910fd041a1123a4e792a9239f99252de3e3e8d5bb209e2c9bda506a79853c482546940364a8246392fb5e18e85847458445fe3a970b29db6d3d0e4a806cfec7c8538f24896d2d10669113f2b724161d2007ee75c0b651f4934046142b04b2015212997c609625bbeb81b9fa0249c167196557c08ae9ea2defcf7859eed4d35b2183c628cb82fe01255e558e7c8b13bded6ba43ed8b92f6ba7879b39932468260c5768ca0909aae899ad1252c5dbcd741d971f179bc36e88a0a10981f73202cb25db324da405fdd5ca5331431afe362c5f933b3c1216c3e19140cd27f7c2ef67898887856a46a518a3afec78ee0d9dce778289a38d2df906932c40019afadab12fe7d0695316e5a3c1e38aa630a44bc8cc01a5a8cae060b7de435e54963b9354182d64e340ec9dc3e37f8b2bbaaab23608b86827991df4367839f443c160c1eb77f41159f69592c3eb37c21a521afcd34036a13a145e9cb1039704b8e523359ea5c3a50f705118ea7d8b1063eb85bfcdc941e0235579e97856ee6f6bfe9c4d0d161b5662de26a2fbddc530ce918a98514903c63a3476d6ebe68e2503e6bf255691fbd8a006e9c77f5a4ad9e3e8d21a56bc4f7bc90d61ebb31eaa4dce48eb9a8069a584ae35266a4bc4af970860d2e9a0df7b87e8fc8b597e73a85d8eeb91def6057d7a77e8f859ee9ee07ef2fb2260660e59ee16458eafbd7bab979ed9bf72c1c27cadc9011f563aeed9a4b2f09ce5455857bcf3acbe0e1cf15537594469c777a885ad24ac5a8c894a8257c5212fb46184ad7f280bc25600129b25bf941460fcdd2e45a0216f1f2fec84d4792a15f877d15c649991ef998621a50a04251257ed6ccd803fdbc83ce4b5c4d7e8ee4487848768384e0b3970ec899dfb423560e755c4716deb3e188ca780cc7a97e8fb80076e9c44c6b7575725253ae4605844c3748bf90c14f17ee80a42fea450c05eb1f251eb09855f2ab368047d68cd7f4b8898d0113d52117375eed77707e7abff8554dc7da30cca674ac587198c0f165a47a5db79e9cc1c7bda9cdc36b94f14141a307850062f4d7208b8c612691699e3e3c16c3fc2dc6604e0fcb27acd6b5d326d2663a3f819589176c70423bc4d37d8c2a17e97468cf923a5388eb0d1de61358e9651a7e76b033d32d6c84e7ed5831a990b46e8228b6ef120643049645b82e100a7ed6ddd2ebfe2dcbd8b0e7ac1e5ee021d4279f164acc47875ade2c0acff5dbbf3a6eb0e8601632c926780be1660270420aa02c99fb39af1852b09904791e90cfa1f02aec0ab2de111524394819527819e52d495196ab3aff1e323dfec07af91e18b9a04e37552a23b13177bdcfc64ec7108e5e9b3679ccdf6b1e998e2bbcd5fbbbebf5ad8008e727cae6499cc06aa03809947e298683a4340f51d6eecad38d0a7a5437dd6e72bce6543b81fd3a438d71e232845cdb403f1011295f9aee5e33352b86e92343985884284c9646da13545f37b9d6da7d0cf902c19a5ca1f4f1818a2c2644807fcc54be35c29f96fb4fea5efdc88b270f1c5504bd8ba558834786020cc2f03ab5c56eaea38532b9faf6208f57d970b2e5ff92872713c9e0ad07b26e72dca6f9a9c02bad6c9db4d1d738f306292f14415d2856c2b073c5d8faf89e9713ceb375b6eefabc240bf6c6bf39cafb99993767dbaf5ee5f4b3f93e638e904fb55f443312c145b809fd203b5b3a16bd229b952e100bbfc0e49bbd05d54c3e5fa1a44fe55de16cfa52f3b169e0bfe95b1b8b6367f9309adfe3df079104fd720d46d772def3c0534d73615071fa22a79af875f796478d2f599dbb4c1ed303132333435363738393a3b3c3d3e3f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" - ], - "measurement": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9 - ], - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "9aa31b9c201fb42526a6b32120318aa9", - "e8551983a3deafaafe0f608295f8d291", - "3eed6ed96f607eb1be6e96868876fc78", - "65b295d3525f0ad74886c2fe7b3b1cd6", - "794a6d37d41457d6f04fd418888cf36e", - "483cc86d052be058d0a1e12384ba0d89", - "9c85cb376b5ebfeffb6c22af3bbd02bf", - "9c0385979cecf00983ba97fc12b2235a", - "c7cbf9f2533dc942eca94540b9a0e745", - "0f418bc80d2926f6ec11e3615a4e0c17" - ], - [ - "675ce463dfe04bdabd594cdedfce7556", - "1aaae67c5c215055e5ef9f7d6a072d6e", - "c5129126909f814e2591697977890387", - "9f4d6a2cada0f5289b793d0184c4e329", - "8cb592c82beba829f3af2be777730c91", - "bec33792fad41fa7135e1edc7b45f276", - "6b7a34c894a14010e892dd50c442fd40", - "6cfc7a6863130ff660456803ed4ddca5", - "4234060dacc236bdf755babf465f18ba", - "fbbe7437f2d6d909f7ed1c9ea5b1f3e8" - ] - ], - "prep_messages": [ - "db085315822777376b4d0f962d8f06d9" - ], - "prep_shares": [ - [ - "e6a4fe7264f95c384446bd51db14f78e7f4133afed0604aeb3b87125fc076c7447d795723adfe93d85f9fe2993c52420e45694fd2ec164a54a7267ee5efc8cb40b6659ac81f2e850786218bcec469ec4f7bb28e875d75ee98d54d566186c61c35448a50cb11e195d886622861a78bbb74325b7972e7b4c47f0e2e10a15d7a33c3daecb2dfc507b1b6676c1e9bfc52a4873f408a5788e7b77ce6943e67f3f457280544d93b81b08e427f699ba54adcbb0ffab83366d9b336846c0c989f0bc25bdd14683f1a85e844b9dbac26daae84cc8d57ef6b0c340798ac5ade63150e8d7a9673b64d798a97cf2715f399fd371e342c1ad50e28431f54180ef63ad7dd21f3e5d8d67159cacfd56f5d99c39d53047c8d7bf11ad83a2e3e569e1393b12d87d01701fa71b50b51e092ca6b797bb97890efb6327f1c4e488663dca5f00675c2af7368a9ab95b3c4e9e1a8dd5430d336833", - "1b5b018d9b06a3c79fb942ae24eb087131693625114418115cb3e54a45056eabd0f6e371501957e00796db78ea8f3388eb8345e938f5fbdd8b24c3a968276d7c457ff43ce93631942f823f5bb9c6d1335b8022e804072711cb8fa5fb3afb209e696c9cac47da44cdc3eb3874eb0d8c89692408b463df12bb2d6e8193d5829cce221e486a579b91cd10a0fb38fec7214a9008d574ba32615f6215aef827a2962a31df892814bd8b8f828d029f07f6acf490e7ecd3377f10b86ec2d5741ba37a3a9522b897e840e315a614a89d0bcf8296bdd45e330eaf3f34b3ce4e1dd41306eae92147fc6676eedff2cb239581f46750df341390e066dabb01ef6362694f923d5a65dbc5252a8da8702a979aca3e211af7124485c1c7dc68f6fb1bdfb9a4d0d993cece17c818d8fb1151f1ef1b32745f09c155f42259af588b424c1dafe8d0e90a3dfc6f55bb428773ce15071cb720fb" - ] - ], - "public_share": "368a9ab95b3c4e9e1a8dd5430d3368330a3dfc6f55bb428773ce15071cb720fb", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - }, - { - "input_shares": [ - "2551f59efba2edc493c9246ff1f0e0a7f8f6f22ee46e662c899e485d7ce288d6becdfee804a39618972fbaa595eeec25423e412cbe51d44a62747de627630302368ec3535a2545a2799e8a0b9a144c811158dda278865d834b34fbe77ad11dbb9fdcf0637c24e10d5ab36d03cdc5f6b95e400a0a81608d96c25733c376376de3927c3570e8ab671358a1686d0c44ac938368d5621cff66585454ef124daa5f18efd7e791a4bcb11caf74b378e2c4feff3e5bad16e7c3fab987eb4d4a0c675bb4f4e70e1373fb00a5dd30a1118355c20e2e4c3700be3d3c1cf25d3e4a729836ba564aa074f99be0d23d4cc0dc9f263c986988e0d16a3d28c262d34f220b1ed127cedea3e2a1bd075c653d4b6f1c3d35e25c2804e7960250dea42dc4a52c9545bedc182ee8391b4c6849366af8e15f30bd06872e5ed651ef7db0b0c442886de32eeeeacc5f2dfe87f9375b4774153fc9e442105b5f8e452e80874c84131400d4d588a1a5d94bac9e68dbf917ef6405b0bc13fa89daf46f84405aedb166ac93f6545256b1da6ac65e01d580bb26eef82c34b8d728fc0c96ff898ed46bd289abbec9917397552ebf6d1eb3f916f69ee9f80e9466512bff70af2d8f3a9ed599f24e33550a09304e1b4f51948e2d8cbf5a1bb14455b1786ae3af4670111bc3983293ad9ae029128efd86d0a05cb3f442b43f466cec5cc9c4989bf5a29eb5c2401bc8bba1d5b7487bc0bf010c968fe76e3a9924459dce6704528d56540081240ed0d2f300a8c9baca5c183b1b5c3a9c03dce5036926d06e1470c2e63d15fdc3a61056154fca9439c595098ff3794c7d7e62af5e3139b43e22a0f8864c254a069a083604762d77ea000177a7b908efe27f6e00db7ea25f573734af803044fb2dc333ed9ad589d7677e23614143fa6836d68ed311dcedf0ea031688b2cf8c5248f21be444f0c61b050a0ab7dca04992673afb737bd27526a72dda3b03dad4d3b0bb81f0887ee6f25ec4cf35d58ea5f085e97609cfb6a8e97d84fdf8755b8e81ff29614bf1b03bcd2b8d9ab06dc4d60785f83eb6ee4573859223214ecdad734d114e15e1971b8b82222910fd041a1123a4e792a9239e99252de3e3e8d5bb209e2c9bda506a78853c482546940364a8246392fb5e18e85847458445fe3a970b29db6d3d0e4a806cfec7c8538f24896d2d10669113f2b724161d2007ee75c0b651f4934046142b04b2015212997c609625bbeb81b9fa0249c167196557c08ae9ea2defcf7859eed4d35b2183c628cb82fe01255e558e7b8b13bded6ba43ed8b92f6ba7879b39922468260c5768ca0909aae899ad1252c5dbcd741d971f179bc36e88a0a10981f73202cb25db324da405fdd5ca5331431afe362c5f933b3c1216c3e19140cd27f7c2ef67898887856a46a518a3afec78ee0d9dce778289a38d2df906932c40019bfadab12fe7d0695316e5a3c1e38aa630a44bc8cc01a5a8cae060b7de435e54963b9354182d64e340ec9dc3e37f8b2bb9aab23608b86827991df4367839f443c160c1eb77f41159f69592c3eb37c21a521afcd34036a13a145e9cb1039704b8e523359ea5c3a50f705118ea7d8b1063eb85bfcdc941e0235579e97856ee6f6bfe9c4d0d161b5662de26a2fbddc530ce918a98514903c63a3476d6ebe68e2503e6bf255691fbd8a006e9c77f5a4ad9e3e7d21a56bc4f7bc90d61ebb31eaa4dce48eb9a8069a584ae35266a4bc4af970860d2e9a0df7b87e8fc8b597e73a85d8eeb91def6057d7a77e8f859ee9ee07ef2fb2260660e59ee16458eafbd7bab979ed9bf72c1c27cadc9011f563aeed9a4b2f09ce5455857bcf3acbe0e1cf15537594469c777a885ad24ac5a8c894a8257c5212fb46184ad7f280bc25600129b25bf941460fcdd2e45a0216f1f2fec84d4792a15f877d15c649991ef998621a50a04251257ed6ccd803fdbc83ce4b5c4d7e8ee4487848768384e0b3970ec899dfb423560e755c4716deb3e188ca780cc7a97e8fb80076e9c44c6b7575725253ae4605844c3748bf90c14f17ee80a42fea450c05eb1f251eb09855f2ab368047d68cd7f4b8898d0113d52117375eed77707e7abff8554dc7da30cca674ac587198c0f165a47a5db79e9cc1c7bda9cdc36b94f14141a307850062f4d7208b8c612691699e3e3c16c3fc2dc6604e0fcb27acd6b5d326d2663a3f819589176c70423bc4d42a21c0a30addfe4b4176740f9a418eca631cda9a8b94d20c7f9b834ed87751464dc5e5b446d920312003e4673b48c6c12b407af1ed90002507883f78d166f0b90bc14ed77d4aec6220cdd51948cdad29ab70513aadccd0e3c8c8108d3b0722602d9612aa6feb323a4ff3e8fe0e3d5701467491acdd3c71c34bc019047647779922216ccd61c47958461e3017adf446c4bd2ab7fbf70e41419679f6a9b3fa4c9aa5e9ef8469ace0d88bc35a3374f462573d2ba24b712359ef36e413006a9883bfa4fad43d89c7f1732725e3cad482d17a9499e1fb0f57d1ca93cafa7fd6d654a70cd7318bd7ace30e981217317105bcfe5e33352b86e92343985884284c9646d966beb8aca87d44e15dcce24aeb08312091cd98e6b52e2525409c58438f00131d33ce09fde0343f84db73369954f2d77a3a559189bc4dfd7e7c043b1364b36550595f624483c4eccccb1c4958a9284e43522dcc72ad9b01162d964605eab990dd1ddd25796f55991e1201f22526117662c0cad518f191effe5608b444b9e8973f5a11a8c154bc501bc47bb4fb5832d67f4c5ea5c221e64ff88ff5d5117aadac704a8b94beb036e87fc9a9462c355231b9bbe8a9122f12390073600f2d7f6262f1758eced79619900cad1910286c5bae553c6525c63c52ca97bf452957c5fc1a7d695dcb5ed0cf0004454c528d63960cd303132333435363738393a3b3c3d3e3f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" - ], - "measurement": [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 - ], - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "9ba31b9c201fb42526a6b32120318aa9", - "e8551983a3deafaafe0f608295f8d291", - "3ded6ed96f607eb1be6e96868876fc78", - "63b295d3525f0ad74886c2fe7b3b1cd6", - "764a6d37d41457d6f04fd418888cf36e", - "443cc86d052be058d0a1e12384ba0d89", - "9785cb376b5ebfeffb6c22af3bbd02bf", - "960385979cecf00983ba97fc12b2235a", - "c0cbf9f2533dc942eca94540b9a0e745", - "07418bc80d2926f6ec11e3615a4e0c17" - ], - [ - "675ce463dfe04bdabd594cdedfce7556", - "1aaae67c5c215055e5ef9f7d6a072d6e", - "c5129126909f814e2591697977890387", - "9f4d6a2cada0f5289b793d0184c4e329", - "8cb592c82beba829f3af2be777730c91", - "bec33792fad41fa7135e1edc7b45f276", - "6b7a34c894a14010e892dd50c442fd40", - "6cfc7a6863130ff660456803ed4ddca5", - "4234060dacc236bdf755babf465f18ba", - "fbbe7437f2d6d909f7ed1c9ea5b1f3e8" - ] - ], - "prep_messages": [ - "fdecd6d197e824492dd550fcdd0aa3c7" - ], - "prep_shares": [ - [ - "e6a4fe7264f95c384446bd51db14f78eec654b5beb7d60677c0b8385ca51a5bf896c79a069b04f339fdcb675885a26f533ec0d6e805beef6d7683a8ecdfa46cb87fdbc532efa5b1041347ed94f54fbca15041d013729d5eb78dcb1a1c293e0035448a50cb11e195d886622861a78bbb7bccc68d521fac002ece757cc5d82afb3b0f9f8766a1714047b50417a8e7f63eacf222c675bdf1d3e8362806ef5f9c16c446a1e5e06ce539aa300bc68c837c9207c5dbc7d85f896fb1be725e461ceacd303716a2cd8005e370a8ac1062d966b5c1499813d0dc63d697c4fd44dcfe81b3cfc37952de43649650c52ca9f2044fd3dfc42cd08bf0659e6a7facee2468ad1b07903a933ec3cbd06a5f81461e434449c32ef6678f3c8fd250c0b3318e80235144a96f07af2169dfddb503b38a2039f80f6bdfbbec6b3ad1025a43a90249221d20e627a73e2ed92bf1920574f42775675", - "1b5b018d9b06a3c79fb942ae24eb0871aba638b677efec2418d7921020c44ff8d0f6e371501957e00796db78ea8f338813d41fd058418e6056a93bb2785cec1d457ff43ce93631942f823f5bb9c6d133fbfbf9d10fa7922dccd1e570b0246775696c9cac47da44cdc3eb3874eb0d8c89fcdfd722a57116825749c8972129304c221e486a579b91cd10a0fb38fec7214af0fe63f4a24e9e189e180a8aaed3b22931df892814bd8b8f828d029f07f6acf402eb7c22aea07b55e871ebdf6475ae509522b897e840e315a614a89d0bcf8296c0b0d5b745f277689643e3da46c09a1ce92147fc6676eedff2cb239581f46750fa1947870c81f9d565f51ed7e09d86dc5a65dbc5252a8da8702a979aca3e211ae9def20e5f2fa85d16e3ccb0a917510793cece17c818d8fb1151f1ef1b32745f09c155f42259af588b424c1dafe8d0e90a3dfc6f55bb428773ce15071cb720fb" - ] - ], - "public_share": "0e627a73e2ed92bf1920574f427756750a3dfc6f55bb428773ce15071cb720fb", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - }, - { - "input_shares": [ - "2551f59efba2edc493c9246ff1f0e0a7f9f6f22ee46e662c899e485d7ce288d6bfcdfee804a39618972fbaa595eeec25433e412cbe51d44a62747de627630302378ec3535a2545a2799e8a0b9a144c811258dda278865d834b34fbe77ad11dbba0dcf0637c24e10d5ab36d03cdc5f6b95f400a0a81608d96c25733c376376de3927c3570e8ab671358a1686d0c44ac938468d5621cff66585454ef124daa5f18f0d7e791a4bcb11caf74b378e2c4feff3f5bad16e7c3fab987eb4d4a0c675bb4f5e70e1373fb00a5dd30a1118355c20e2f4c3700be3d3c1cf25d3e4a729836ba574aa074f99be0d23d4cc0dc9f263c986a88e0d16a3d28c262d34f220b1ed127cedea3e2a1bd075c653d4b6f1c3d35e25d2804e7960250dea42dc4a52c9545bedd182ee8391b4c6849366af8e15f30bd07872e5ed651ef7db0b0c442886de32eefeacc5f2dfe87f9375b4774153fc9e443105b5f8e452e80874c84131400d4d589a1a5d94bac9e68dbf917ef6405b0bc14fa89daf46f84405aedb166ac93f6545256b1da6ac65e01d580bb26eef82c34b9d728fc0c96ff898ed46bd289abbec9927397552ebf6d1eb3f916f69ee9f80e9566512bff70af2d8f3a9ed599f24e33560a09304e1b4f51948e2d8cbf5a1bb14555b1786ae3af4670111bc3983293ad9be029128efd86d0a05cb3f442b43f466dec5cc9c4989bf5a29eb5c2401bc8bba1d5b7487bc0bf010c968fe76e3a9924469dce6704528d56540081240ed0d2f301a8c9baca5c183b1b5c3a9c03dce5036a26d06e1470c2e63d15fdc3a610561550ca9439c595098ff3794c7d7e62af5e3239b43e22a0f8864c254a069a083604772d77ea000177a7b908efe27f6e00db7fa25f573734af803044fb2dc333ed9ad589d7677e23614143fa6836d68ed311ddedf0ea031688b2cf8c5248f21be444f1c61b050a0ab7dca04992673afb737bd37526a72dda3b03dad4d3b0bb81f0887fe6f25ec4cf35d58ea5f085e97609cfb7a8e97d84fdf8755b8e81ff29614bf1b13bcd2b8d9ab06dc4d60785f83eb6ee4673859223214ecdad734d114e15e1971b8b82222910fd041a1123a4e792a9239f99252de3e3e8d5bb209e2c9bda506a79853c482546940364a8246392fb5e18e95847458445fe3a970b29db6d3d0e4a816cfec7c8538f24896d2d10669113f2b824161d2007ee75c0b651f4934046142c04b2015212997c609625bbeb81b9fa0349c167196557c08ae9ea2defcf7859eed4d35b2183c628cb82fe01255e558e7c8b13bded6ba43ed8b92f6ba7879b39932468260c5768ca0909aae899ad1252c6dbcd741d971f179bc36e88a0a10981f83202cb25db324da405fdd5ca5331431bfe362c5f933b3c1216c3e19140cd27f8c2ef67898887856a46a518a3afec78ef0d9dce778289a38d2df906932c40019bfadab12fe7d0695316e5a3c1e38aa631a44bc8cc01a5a8cae060b7de435e54973b9354182d64e340ec9dc3e37f8b2bbaaab23608b86827991df4367839f443c260c1eb77f41159f69592c3eb37c21a531afcd34036a13a145e9cb1039704b8e623359ea5c3a50f705118ea7d8b1063ec85bfcdc941e0235579e97856ee6f6bfe9c4d0d161b5662de26a2fbddc530ce928a98514903c63a3476d6ebe68e2503e7bf255691fbd8a006e9c77f5a4ad9e3e8d21a56bc4f7bc90d61ebb31eaa4dce49eb9a8069a584ae35266a4bc4af970861d2e9a0df7b87e8fc8b597e73a85d8eec91def6057d7a77e8f859ee9ee07ef2fc2260660e59ee16458eafbd7bab979ed9bf72c1c27cadc9011f563aeed9a4b2f09ce5455857bcf3acbe0e1cf15537594469c777a885ad24ac5a8c894a8257c5212fb46184ad7f280bc25600129b25bf941460fcdd2e45a0216f1f2fec84d4792a15f877d15c649991ef998621a50a04251257ed6ccd803fdbc83ce4b5c4d7e8ee4487848768384e0b3970ec899dfb423560e755c4716deb3e188ca780cc7a97e8fb80076e9c44c6b7575725253ae4605844c3748bf90c14f17ee80a42fea450c05eb1f251eb09855f2ab368047d68cd7f4b8898d0113d52117375eed77707e7abff8554dc7da30cca674ac587198c0f165a47a5db79e9cc1c7bda9cdc36b94f14141a307850062f4d7208b8c612691699e3e3c16c3fc2dc6604e0fcb27acd6b5d326d2663a3f819589176c70423bc4dc97f402ea5053f2aa068d42c371d327339bd8637472eb9be88e409688a53bff392a8891c96c7804998d761fcf34dbf8da8cb17567f75ab4be29ecb6c33c85bf572b645bb7b226e4b99ccc0d959e6d809ec45b70cefe5ada611ea14962c9788d3e15100872669baf3c07a424cc205db97c0e2f72880a40a48d3820f89a16c7ee9dbc44bea18d787e0b730093a7b1fe4f9fd3e50128c61f6d4179fde88b02629629bf9f56f15abe3860ad2c99eaee9eba2310ca898fee5103f7bcb11ec9f4154007cf7d2b51a173331576526665d9f90879a2122b2bdef3a2cff68e57b146ae6d99a4e247d0daa693ef0a07aadc1a4b25ce5e33352b86e92343985884284c9646d0f8ec766552f75092a8b613870386a8b77901f01cddd76b4761e74519b24b851a570b5de8ca954b2c7df0fb314b6fa550e8e49713a28358e399afb3b9199496b229bc55644ee8e4772f1e00dc53886ade4932acee5cfd079707bd1d204c58360f26434fb158b53c1c4a51b65703f123f8090fe42dc48dbd3469a7d4bf1958203adffe46dd39084b66c789517b4438ed9415946ca552d523fa6c71e3302c3552f140d62d41cf3580e5e8500674cbb7d9ddd849d1ddb1d48ef7fd92f363e5e5b6a95b0c67b37e7e5e6a4dec9d8d56e577562eecec955cb6f9925c81cc165634018ab142c519ddd54f358356cee2ba50840303132333435363738393a3b3c3d3e3f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" - ], - "measurement": [ - 255, - 255, - 255, - 255, - 255, - 255, - 255, - 255, - 255, - 255 - ], - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "99a41b9c201fb42526a6b32120318aa9", - "e6561983a3deafaafe0f608295f8d291", - "3bee6ed96f607eb1be6e96868876fc78", - "61b395d3525f0ad74886c2fe7b3b1cd6", - "744b6d37d41457d6f04fd418888cf36e", - "423dc86d052be058d0a1e12384ba0d89", - "9586cb376b5ebfeffb6c22af3bbd02bf", - "940485979cecf00983ba97fc12b2235a", - "beccf9f2533dc942eca94540b9a0e745", - "05428bc80d2926f6ec11e3615a4e0c17" - ], - [ - "675ce463dfe04bdabd594cdedfce7556", - "1aaae67c5c215055e5ef9f7d6a072d6e", - "c5129126909f814e2591697977890387", - "9f4d6a2cada0f5289b793d0184c4e329", - "8cb592c82beba829f3af2be777730c91", - "bec33792fad41fa7135e1edc7b45f276", - "6b7a34c894a14010e892dd50c442fd40", - "6cfc7a6863130ff660456803ed4ddca5", - "4234060dacc236bdf755babf465f18ba", - "fbbe7437f2d6d909f7ed1c9ea5b1f3e8" - ] - ], - "prep_messages": [ - "190c0ef07d6f2cbd1bed12d71b5f118d" - ], - "prep_shares": [ - [ - "e6a4fe7264f95c384446bd51db14f78ef1ffdfc96013014baff7bd0684b8ff3360f6a2a23b1d7b71796b845eeb21e7d1682128dc8b87837803fec0e3bd6c548d5cc9c041a482cbfc38120743a2f1a0985053eaeccc339c56c2edf76451e22c9a1bca6ab2181850f44d904964d1f227a970e70b59328028ddafdb1649a8c4f1f7cbeb366e42f8603a7b627f7519f25617a33726ede06ab438714b4bd3cda025dc2bcab64974eb02b9e2a23bf0cab4e5ef1e87bb1a72767098c768a20e1090a712ed38c1e8803fd18181cc0069355b40f5f98ff3cbd2b31022df719d9c660e7d5bab239819730ad9165a38641379444093ba148996166ccf5e2826bddb7a7dc8eda4dd5928b12e1ea715538788804b5ce231dfc98ff45027ff8cb1f92007f2339621201a7dc483c83bb6df082105cb5f5d9eda1f847b3d43b4e16502062d5a4a158f651439d7666c683a6283d308c91b25", - "1b5b018d9b06a3c79fb942ae24eb08714d70b996c916bc83063fda0f9ec82780d0f6e371501957e00796db78ea8f338874640cdcd2ca1496ea55d62aa3709498457ff43ce93631942f823f5bb9c6d133b1f04db02cc745245af6a31e4dfe912a696c9cac47da44cdc3eb3874eb0d8c89cc603d2ceec1678996fe311424b56e65221e486a579b91cd10a0fb38fec7214a46c9ce7f890afed4efa31fb5ca8766ae31df892814bd8b8f828d029f07f6acf47620063e9fa98ab947b376e068b9be689522b897e840e315a614a89d0bcf8296332affc2e6b52204d1d7994260e415c6e92147fc6676eedff2cb239581f4675066213f3b302497abbf10c1729131a0125a65dbc5252a8da8702a979aca3e211afb99a0edb76c92f2bd5941c6071db19d93cece17c818d8fb1151f1ef1b32745f09c155f42259af588b424c1dafe8d0e90a3dfc6f55bb428773ce15071cb720fb" - ] - ], - "public_share": "8f651439d7666c683a6283d308c91b250a3dfc6f55bb428773ce15071cb720fb", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json deleted file mode 100644 index af95aac5a0..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json +++ /dev/null @@ -1,146 +0,0 @@ -{ - "agg_param": null, - "agg_result": [ - 45328, - 76286, - 26980 - ], - "agg_shares": [ - "598a4207618eab7bd108c110106e84cd9498b18b79cace4b383274cef0ab280eae74b07f9a7f087a89a4f51f3adb97ed", - "ea61abdf14b8477f6de1b47a18ac778ad0149cb235e666ccce92a9246a2858403e5903013ab179dcf6719d10fccdf589", - "cfc412198ab90c0589158a74d7e503a89b7cb3c1504fcae7dc3ae20ca52b7fb17a9b4c7f2bcf7da947e96ccfc9567288" - ], - "bits": 16, - "chunk_length": 7, - "length": 3, - "prep": [ - { - "input_shares": [ - "db3fe5357f56f6cfe9a0a34ed08e231765b423d5670741c151f7bc28cb15c4c8678df838b6ef52d74c5bb5e8c8c607b2674c024da705b558163e3127ae09f4a5c061dc6129d71755ec77b5d5a2fc088541fa612bf1273d94718e0d28b654ea9524148bf910a5c6d55b596e323d4f55ab62b0851e0985987ea39cf500bfd4d5faed37f519120b574aead76d706e149c54b6e790f7c35553f830f67553ff3f08db0f5d8a2e157f9c1ef6eedcb845a19fffd3f9c6e705b035c95f3ebe51219a91c6ffff33c52b8fd7e90417636bb443c98c3e6933b1599c09151095fff99d7af43d327fcf2afdc50144e5b8f5b1ff1f8cc8d442613dc76dd48100dd4637b38fc5fa239333c6d1e2bec2132a3e3cf5fd11f7e823fbf275071a71535740ac64de88b83ba002bd4490de5c7540e454331d46ebb825725b964ecfcc5c3bb076bf57fd819c0bd788b4495da456594503c8f5b618c4713e957a7589b151ead3a27ae80153b0fbc219f5524eec22dc91aa56ed87a71d2b6e6b857ee03a700fb5af5b23513fb73023c2764f74b40f00e44e2e7acd463e7f38c783a898015b51863659502645e7d7fdf14abf76c605d42e523a540f40e816db420d599cea502baa131d6b61b8aed86a09b9f7587e107c6fc9043d72644153b54234146535e9ec25223d293f4a2a4481b5649a7625116aef735ecbbdd9e99076985e1c424e91c29ae231c01f2b12007c81a9b3c72a84522014f4cdcb949bb9850b62b1c9c5d35f0fc3dbf4f637ae85d3082ffd15890041a455a5dd38efca02eb415afcd2c93a2b6ab46c88847f380affbc3a9af4745718044c9f23978026af66871e610e1beee21360fc5ae4f05dd32689328216db3c512fddacefb2713187f4f5069170db246ae0cb13b3b88f8c832d11ae6b26fe6f0f89b9a9056c28ac6160134ab1af4be606a2ca7d1256cfc223c823ae4921ba11aab9e4f8104885b2d17ac7826ad06b0fd0e54397e67179755b29c6d724f3e9d9a6934619ef0bfee72cdcf0031672bb6e55be53d3ef0fccf7beba7dea636eff7fdecee99f60a0bc5d5cb11e24683ca8085cf218a3607c3f5a051c33717f39834435c5c542f42bd9c9d9103173cb11436e2a626e228415924037ee4a4078f0d9a5bd0fef1dc9415740c4b32f51d199d912907a103c7e25928acadfb4dc1e8d32c34b4f0100bfe95feb850e0d7b359aae9a332913d1f8eca0d1cd93dee2f4b75076536037ca2b6bec5003ae89e03db9813d0dd2165bf50a836ca492f05750a3b5fff4d089fc54fdf225aa112d72ab021b0cef1b8d31c852133fae501406668db0cb4c3589934bde5ec218876b0dc4087b61d706234635d5d9065787a21ed895fb7c05902a554f879dae44d0905292815c5ae2338be1faa9249c7a0530623084f3a7c8bdddf0cf0123597127f9416dcad20f71bb98bf0078d9d20d4ae09c46fc1882cae650f48bebfcc443dfd7963c9944f0ce0a9bda91fe8b8f307fb3da48e573224324c35e867599262fa281ee6bc537928747dd4a1370440bda92e28eb5ba088481e476f19e2a03a7c7619eb79e2184afff7bb585319fa6a58dbfb8862f5d193ccfe0e4aeb58c1633d9e983861d4976615b11514160e5d77ed9a3e2179893c65d9de03813d27aec3485d96098764ee1e7779d47850e6b96ba064b4b913da8390416afb16719a38b725d5b27db351049bdb322cfc93a905a108d07e49764eb5f3f66fe8f3aec7580606162636465666768696a6b6c6d6e6f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", - "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" - ], - "measurement": [ - 10000, - 32000, - 9 - ], - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "7e6f6b02cb848e7e3c5840b05acfd699", - "dda1902ed398efc35ebb269aa58e0d5a", - "cd03902ade7fad281b8cfc5f1349ddf9" - ], - [ - "f9758e4a5c3d6d2a1b4b3c7e5d397d83", - "9bb1de90bc4c2244e630e3b6780dc86a", - "15735600bee57d499ed0890554ef5183" - ], - [ - "9b4106b3d83d0457705c83d147f7abe2", - "89299140701aeef79e13f6aee1632a3b", - "298919d5639ad48d0ea3799a98c7d082" - ] - ], - "prep_messages": [ - "429a80b8b2f73ce00d066d0c0e540cfb" - ], - "prep_shares": [ - [ - "574ce7d79da173f0652f7d1e699d5fe756c90210a093e0c893b2b7510374465c35014cdcef24d6044e63ece20db245a982c5a00f16227c6530ade1e5fd4e925f8505da8add8b97fa3216790b11b46ad76bec9b6b3f0c1e9b8284f81f0c83bb690033a6c4a8e962d34b51e27aeaa33a0d41e852a78af96c6dfba1d36364996df4eaaacc993e5633528fb0d106753112ecbfe7fec74ea75d2d1b16267ee1b3d6145e746f19d0840be93d38baa3a5c7d42c6a05311092b4fe05e38aa9e24fb9c99a5aa4bc485752d049703409ccb6656150eeb34048030f19b5353df1e23b376b1c4be2925034d8b7a847690ca7f0c4f338c30b461d9e8c1a1de094fea67efdc4d3da6e96a43cd51241f828f01028e5b0e9", - "21c1bcbdd38fa9e8d86272f8c66c2b16768d00a79945c6014bb55374174299e4e7967f80f8df630af6f5aac52647e36437d08d0aabfd406b0984557a1a69b28f3706033ed34cde0d6bfd39a81a0fca04117cd7ac37f06815b6dc1a356454d669b0e7871238066b280f7c09e0365214235dcd39dfdf6e46ad632d50101029ff490910f79b754d99088059cf1d5da8a791b1a51d8d96fe428bac8f547dc2e9632c4e00b3a6e95d36d03d83969de2989c120aa3c54040bc7f49f910df6c5e4003721a03a3f1d743c457d0cbadbc0bd25ca7f464f404a1f39f852872314ca44ea35a32c150fc25094cd2147739d1a1e03e8f6e636170867687f1c511dbb936fb521b6639ebc145f03b6d1751fcdf14c5108e", - "89f25b6a8ecee226a56d10e9cff57402c3198e7629d8c4152d9319172f0df07727e57ad2e170a0a32cf748f9dc0fe45597d26743a7254aebceb106f0f172a5f2aecf563787471334096bb202a07696b7e0cf22d7dda51e1cf0fcc3d0d5d0a9f4c7ea8999a3f4edb4bd7d3ecb26f2137fe9d443f34248265c25a12290866130c9ccd2dd263bce8b78c14ddbc0c94ed85da0c401ac614c789711c0e2db27ad6ef59aabfdbb6bf174fff2358c4a8d6b7e6cd2a0d41883f3563506755a920aaa7695cf35ffecb0b195d01d1d86ee1a015df5de2f145b61ef3bc5fff1634d911a69540c03444dcb256fa982b24cf064dd6e4dffe71f8d5648cf336acd9485f9d70e24f2ad6b4aa14511e7b660c0866f73672a" - ] - ], - "public_share": "da6e96a43cd51241f828f01028e5b0e96639ebc145f03b6d1751fcdf14c5108ef2ad6b4aa14511e7b660c0866f73672a", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" - }, - { - "input_shares": [ - "db3fe5357f56f6cfe9a0a34ed08e231766b423d5670741c151f7bc28cb15c4c8688df838b6ef52d74c5bb5e8c8c607b2684c024da705b558163e3127ae09f4a5bf61dc6129d71755ec77b5d5a2fc088541fa612bf1273d94718e0d28b654ea9524148bf910a5c6d55b596e323d4f55ab63b0851e0985987ea39cf500bfd4d5faed37f519120b574aead76d706e149c54b6e790f7c35553f830f67553ff3f08db0e5d8a2e157f9c1ef6eedcb845a19fffd4f9c6e705b035c95f3ebe51219a91c6ffff33c52b8fd7e90417636bb443c98c3d6933b1599c09151095fff99d7af43d337fcf2afdc50144e5b8f5b1ff1f8cc8d442613dc76dd48100dd4637b38fc5fa249333c6d1e2bec2132a3e3cf5fd11f7e923fbf275071a71535740ac64de88b83ca002bd4490de5c7540e454331d46ebb925725b964ecfcc5c3bb076bf57fd819d0bd788b4495da456594503c8f5b618c4713e957a7589b151ead3a27ae80153b0fbc219f5524eec22dc91aa56ed87a71e2b6e6b857ee03a700fb5af5b23513fb63023c2764f74b40f00e44e2e7acd463e7f38c783a898015b51863659502645e7d7fdf14abf76c605d42e523a540f40e816db420d599cea502baa131d6b61b8add86a09b9f7587e107c6fc9043d72644053b54234146535e9ec25223d293f4a2a4481b5649a7625116aef735ecbbdd9e99076985e1c424e91c29ae231c01f2b12007c81a9b3c72a84522014f4cdcb949bb9850b62b1c9c5d35f0fc3dbf4f637af85d3082ffd15890041a455a5dd38efc902eb415afcd2c93a2b6ab46c88847f390affbc3a9af4745718044c9f23978027af66871e610e1beee21360fc5ae4f05ed32689328216db3c512fddacefb2713287f4f5069170db246ae0cb13b3b88f8d832d11ae6b26fe6f0f89b9a9056c28ad6160134ab1af4be606a2ca7d1256cfc223c823ae4921ba11aab9e4f8104885b3d17ac7826ad06b0fd0e54397e67179755b29c6d724f3e9d9a6934619ef0bfee72cdcf0031672bb6e55be53d3ef0fccf7beba7dea636eff7fdecee99f60a0bc5d5cb11e24683ca8085cf218a3607c3f5a051c33717f39834435c5c542f42bd9c9d9103173cb11436e2a626e228415924037ee4a4078f0d9a5bd0fef1dc9415740c4b32f51d199d912907a103c7e25928acadfb4dc1e8d32c34b4f0100bfe95feb850e0d7b359aae9a332913d1f8eca0d1cd93dee2f4b75076536037ca2b6bec5003ae89e03db9813d0dd2165bf50a836ca492f05750a3b5fff4d089fc54fdf225aa112d72ab021b0cef1b8d31c852133fae501406668db0cb4c3589934bde5ec218876b0dc4087b61d706234635d5d9065787a21ed895fb7c05902a554f879dae44d0905292815c5ae2338be1faa924d95673e4d904cc4215bfda1c9c0ca55fa38af6b696ef4f1a452d6870c1d82fa311cee716b00a11313a0ba7c4038e5e195b5e1d3502a44d9a9ab1636394821eaf157e6c77316f6e26b98ca81220752396890cce205581aead60bfcc3916a6c2d6d360c7e845e70c8c68e4acb5eb2877a9a7c7619eb79e2184afff7bb585319fa669b151040f5b15cab2d8c3a50379e9d9e8bf1ac6319bc32e489f64793f882d0e3e1906ac04d47eaec15c20c503d007d09d6a9b032d0f9a8b3d95447fcb1d4b7334b95d873a171f876dcc2a62a62af58e10802f88742027d3d27b9d72fea73dc84906d3dde03299dc3e033651406229da606162636465666768696a6b6c6d6e6f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", - "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" - ], - "measurement": [ - 19342, - 19615, - 3061 - ], - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "fc936b02cb848e7e3c5840b05acfd699", - "7c71902ed398efc35ebb269aa58e0d5a", - "b90f902ade7fad281b8cfc5f1349ddf9" - ], - [ - "f9758e4a5c3d6d2a1b4b3c7e5d397d83", - "9bb1de90bc4c2244e630e3b6780dc86a", - "15735600bee57d499ed0890554ef5183" - ], - [ - "9b4106b3d83d0457705c83d147f7abe2", - "89299140701aeef79e13f6aee1632a3b", - "298919d5639ad48d0ea3799a98c7d082" - ] - ], - "prep_messages": [ - "e129a25d4bb45ae8f5ff9d97d72f6d86" - ], - "prep_shares": [ - [ - "574ce7d79da173f0652f7d1e699d5fe7865e23ddbe20c3646ca1d41f8d0d123a831f3b90d5b917779d25ca7aafd5c903b4b996399d29d3af9fcb1c6549c36a639e45759c53b3bf6a1014fbdf7ea4d5d3726af036968d80aed52a7e48dc0a06ee66a6e34bf38ce1083cb56057cfbe98ae9138b635f2b64b60daf151ce214d33b99062b201463033142fc734e4c163fd8a5d2ea4503567c0a9739027883ab0b37ece24259b5ddcc88b3e272bbad93857a52a48abf5eb9fb135ccaf27fc0379f49f203cc0f5a4f14183ef3b935076893f0bc56dcd9b0ffbf8f711039bfd3fe894c0c007d8702db35ded99e2605fa3d9d4b70f6dfcdea9883c839e2a91aa358a38359e2d3cb20272a3ecb52e1edc17a48940", - "21c1bcbdd38fa9e8d86272f8c66c2b167ab67945b007b46536ece1073c4ac681e7967f80f8df630af6f5aac52647e36454b87d9c2d6aa2d4c2186b47a6bef8153706033ed34cde0d6bfd39a81a0fca04618cc495486eccfbcba29099fb101871b0e7871238066b280f7c09e0365214230a741f21625c730fae5e37a7a3cbe0c00910f79b754d99088059cf1d5da8a7911221c38f8a6f79877dd34cb4fd2990744e00b3a6e95d36d03d83969de2989c12e44eb18d466e8954631aa1dbe84e78111a03a3f1d743c457d0cbadbc0bd25ca7de998de032e28d1a8ca88d584ad7a64032c150fc25094cd2147739d1a1e03e8f6e636170867687f1c511dbb936fb521b6639ebc145f03b6d1751fcdf14c5108e", - "89f25b6a8ecee226a56d10e9cff57402a204a4e83b6b78a5aa32317f68443eac27e57ad2e170a0a32cf748f9dc0fe45524ab48c23361b4b327d498fd702f23b6aecf563787471334096bb202a07696b7eb8d79193777673f93547e14b15adb2ac7ea8999a3f4edb4bd7d3ecb26f2137f5e2881b52fd4d3ec538b978ebba54312ccd2dd263bce8b78c14ddbc0c94ed85d38fdf5fb7ee2eeb21ef066fdde8a94f89aabfdbb6bf174fff2358c4a8d6b7e6cdb080672d15b2ae06d6ca64387b56c00cf35ffecb0b195d01d1d86ee1a015df53e771738ec1faca3fcdfe4f033977dd50c03444dcb256fa982b24cf064dd6e4dffe71f8d5648cf336acd9485f9d70e24f2ad6b4aa14511e7b660c0866f73672a" - ] - ], - "public_share": "9e2d3cb20272a3ecb52e1edc17a489406639ebc145f03b6d1751fcdf14c5108ef2ad6b4aa14511e7b660c0866f73672a", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" - }, - { - "input_shares": [ - "db3fe5357f56f6cfe9a0a34ed08e231766b423d5670741c151f7bc28cb15c4c8678df838b6ef52d74c5bb5e8c8c607b2674c024da705b558163e3127ae09f4a5c061dc6129d71755ec77b5d5a2fc088542fa612bf1273d94718e0d28b654ea9525148bf910a5c6d55b596e323d4f55ab62b0851e0985987ea39cf500bfd4d5faec37f519120b574aead76d706e149c54b6e790f7c35553f830f67553ff3f08db0f5d8a2e157f9c1ef6eedcb845a19fffd4f9c6e705b035c95f3ebe51219a91c6000034c52b8fd7e90417636bb443c98c3e6933b1599c09151095fff99d7af43d327fcf2afdc50144e5b8f5b1ff1f8cc8d442613dc76dd48100dd4637b38fc5fa249333c6d1e2bec2132a3e3cf5fd11f7e923fbf275071a71535740ac64de88b83ca002bd4490de5c7540e454331d46ebb925725b964ecfcc5c3bb076bf57fd819d0bd788b4495da456594503c8f5b618c4713e957a7589b151ead3a27ae80153b1fbc219f5524eec22dc91aa56ed87a71d2b6e6b857ee03a700fb5af5b23513fb63023c2764f74b40f00e44e2e7acd463e7f38c783a898015b51863659502645e6d7fdf14abf76c605d42e523a540f40e716db420d599cea502baa131d6b61b8add86a09b9f7587e107c6fc9043d72644153b54234146535e9ec25223d293f4a2a4481b5649a7625116aef735ecbbdd9e99076985e1c424e91c29ae231c01f2b11007c81a9b3c72a84522014f4cdcb949cb9850b62b1c9c5d35f0fc3dbf4f637af85d3082ffd15890041a455a5dd38efc902eb415afcd2c93a2b6ab46c88847f380affbc3a9af4745718044c9f23978027af66871e610e1beee21360fc5ae4f05ed32689328216db3c512fddacefb2713187f4f5069170db246ae0cb13b3b88f8d832d11ae6b26fe6f0f89b9a9056c28ac6160134ab1af4be606a2ca7d1256cfc323c823ae4921ba11aab9e4f8104885b3d17ac7826ad06b0fd0e54397e67179765b29c6d724f3e9d9a6934619ef0bfee72cdcf0031672bb6e55be53d3ef0fccf8beba7dea636eff7fdecee99f60a0bc5d5cb11e24683ca8085cf218a3607c3f5a051c33717f39834435c5c542f42bd9c9d9103173cb11436e2a626e228415924037ee4a4078f0d9a5bd0fef1dc9415740c4b32f51d199d912907a103c7e25928acadfb4dc1e8d32c34b4f0100bfe95feb850e0d7b359aae9a332913d1f8eca0d1cd93dee2f4b75076536037ca2b6bec5003ae89e03db9813d0dd2165bf50a836ca492f05750a3b5fff4d089fc54fdf225aa112d72ab021b0cef1b8d31c852133fae501406668db0cb4c3589934bde5ec218876b0dc4087b61d706234635d5d9065787a21ed895fb7c05902a554f879dae44d0905292815c5ae2338be1faa924c67468654e6880c69828616e9d011132b27aa457c6dcbd554ec4374ec882357626d6f323bfadc3b23ac6d390e40f8f2008e462458194a1f9d63e0b977f4be907f34aecb0a12ad13b95bfc858c412abab064106faf149e9b25cb557c12a54e6ae957097b8b11f174094d134cc213bf98da7c7619eb79e2184afff7bb585319fa67b935c839af760464b6f3d5402847d07d9cf6c2502ae55f33e08959b38de273b2911fa9ef530cc2cc1a1f3f8224ed7c8efe455f3ad1e462c1d089d4be054801a56ecdd4dca5bbc7191990a1c028d6d79934bf7aed757eccdd68512ebe9f919f087f6020e75fa8e281316ae3a0a50a7f5606162636465666768696a6b6c6d6e6f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", - "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" - ], - "measurement": [ - 15986, - 24671, - 23910 - ], - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "e0866b02cb848e7e3c5840b05acfd699", - "3c85902ed398efc35ebb269aa58e0d5a", - "2a61902ade7fad281b8cfc5f1349ddf9" - ], - [ - "f9758e4a5c3d6d2a1b4b3c7e5d397d83", - "9bb1de90bc4c2244e630e3b6780dc86a", - "15735600bee57d499ed0890554ef5183" - ], - [ - "9b4106b3d83d0457705c83d147f7abe2", - "89299140701aeef79e13f6aee1632a3b", - "298919d5639ad48d0ea3799a98c7d082" - ] - ], - "prep_messages": [ - "62b225fa36c2cbc5896a40b1360f0ce0" - ], - "prep_shares": [ - [ - "574ce7d79da173f0652f7d1e699d5fe74186663960507c6ac01fafa7046bc88a5c4146feb2861bcb9f3ad8bb294028812c631ce293cde53b6fc09c6bdbcb839ede24393da7141c26a1a594ccdab1fba7ed2b2e38faf952343a2871b854699ff9533b4f88f9bc7e935cc62e3dea6efff7e2d396d8276281db4e789dc30d3fe01c397b64d685e87e7dccae1b7636b1a1486293f29e5c3433ee211e1f66ec5a7a0f1d79ed261735f53fdb51cbd51c1a6b057bf2845e34bfa091f0f8fd7565242c8b247064dfac759c1c646d085bca6ad0845b9cc2093fd49d493ebf2d48a90b99815f0bd165f56453c6b27dff04d3a161d9fc0bc4177e423791d4064faccfbbd3218c6815a24e38fb752efc839e59043cbb", - "21c1bcbdd38fa9e8d86272f8c66c2b16ce028e4f460022aed5c3e47011081a9ce7967f80f8df630af6f5aac52647e36481e9f91e23071ea7d98af1e76a9dd5823706033ed34cde0d6bfd39a81a0fca048271f4696baf9fd2e8a37e7b5e1be75eb0e7871238066b280f7c09e036521423abafe75c716165e86a573bab2e46efda0910f79b754d99088059cf1d5da8a79146cedb83d4b00d96b9871a66d73147984e00b3a6e95d36d03d83969de2989c12e222e1015cad12a219308643f8e1c1511a03a3f1d743c457d0cbadbc0bd25ca7cb9908430d0604df4468ab54b36f81ef32c150fc25094cd2147739d1a1e03e8f6e636170867687f1c511dbb936fb521b6639ebc145f03b6d1751fcdf14c5108e", - "89f25b6a8ecee226a56d10e9cff5740294125c8939f32731654a11d38906f94a27e57ad2e170a0a32cf748f9dc0fe45503b71c971d945163a09158bc06295e77aecf563787471334096bb202a07696b7f7c98da9fca5e00ff5ce6eb4b9d52274c7ea8999a3f4edb4bd7d3ecb26f2137fbd6dc71ed450947219eef408d88af7dbccd2dd263bce8b78c14ddbc0c94ed85db3255ece317e82a0f3b4a873e9b72b949aabfdbb6bf174fff2358c4a8d6b7e6c545473085c7c9b5c2aa9d290b01670ffcf35ffecb0b195d01d1d86ee1a015df56465c0991dd00dfda6948958c3ff38510c03444dcb256fa982b24cf064dd6e4dffe71f8d5648cf336acd9485f9d70e24f2ad6b4aa14511e7b660c0866f73672a" - ] - ], - "public_share": "8c6815a24e38fb752efc839e59043cbb6639ebc145f03b6d1751fcdf14c5108ef2ad6b4aa14511e7b660c0866f73672a", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" - } - ], - "shares": 3, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json deleted file mode 100644 index 4dd3798668..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "agg_param": null, - "agg_result": 100, - "agg_shares": [ - "0467d4fd6a7ec85386c9f3ef0790dc10", - "61992b02958137ac5d360c10f86f23ef" - ], - "bits": 8, - "prep": [ - { - "input_shares": [ - "1ac8a54e6804d575f85957d45c728487722ad069fc1ed413da970ea56ae482d81057f898a367319a14f402d072c24bb71aa13cf4f9cdcd731e779aaa4a5d561ff40e41797cf2d43308849ff9080f846c2e78e2736a1d3cdaa68f3ec890d633cc13f5bf96466d3f02f93612bc827ff53357d52ae00dd234b9758f2cbb7aa9682d06041da1507aa12446de554a945924f445d3715279ef00f4c55ae987cec4bb9f1316efdc8737b7f924d046a6b8ef222b0dc1205ce9b464076fa80d2dfe37af4d836d597ade7d51e18e9c95d13158942d249efd0a1a226759e4bc1d46d3a41bdb227703fe0a7554cf4769935bc99cd1f35b274ecec240816af4915c7abe3e16b7be5ab5e105f9ae7b2e683191c9400cf99ab0c687e4929f87e6e64f712ca02f07a1b29fcebdbfde7655797f9c1b6b3114420d8a19736ae614116782278b7a71f9ef6928ad44ce588644886523d6fbe0b7bbb47248edbaa0b5ce33f74a07005e2a6842eb2c05778e170112f6e6a5f206d7830aa122e29069dcb4a4c064e63c29b3c6e2b22dfb5ab344ca0f1be8e8ce36d26435413de2dc4f53e158ebb8478b4a98de014a688db9470106fd7e73a65c2e656b5a627b5584ca0594ba10cc39c5612bcef576625c37c5249ad5c04e42c66d6a9653c4ec47e2bcd860870bef64f812974654f17f77c08eaa395803d33bdf31db17d76dbb9d2407d7c4f9efbce274542ff6aa0dcf188803eb586108317db430ad517ce7cb0f56d225c835161eb348949ebe253bedc338c6b939ce837561f01d7f0304963eab2a28b38c36bb169a4ee0637635818bd5e4798a8319152a2678b0aa7b837cb0f24df6148ae2c84b78db8892f4415f90f3804e7a29cdcd32a0a8625fd20aca47ee0ef12ebd6138b3534a1b42303132333435363738393a3b3c3d3e3f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" - ], - "measurement": 100, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "0467d4fd6a7ec85386c9f3ef0790dc10" - ], - [ - "61992b02958137ac5d360c10f86f23ef" - ] - ], - "prep_messages": [ - "0fd2bb14ac123437f6520fdc4a817934" - ], - "prep_shares": [ - [ - "61428b8d7e326827ac832bc4074ad61652efcfdb8d95b6f06b83dd9f5d55ce9f142d1a1fd437eb8c84581ad15dcd9a57417942e63a1a46e6b0ffc8b6d6300f7d", - "a0bd747281cd97d8377cd43bf8b529e9eb5e4b1153111bd6cd06aa3a5493a6da4470f696b9afff52ec10fc00040e4538470fdb8d3e05e188aba2b16e24c71b69" - ] - ], - "public_share": "417942e63a1a46e6b0ffc8b6d6300f7d470fdb8d3e05e188aba2b16e24c71b69", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" - } - ], - "shares": 2, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json deleted file mode 100644 index 8e7163ae2a..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "agg_param": null, - "agg_result": 100, - "agg_shares": [ - "b3916e4086c52aa0439356b05082885a", - "61992b02958137ac5d360c10f86f23ef", - "52d565bde4b89db326369d3fb70d54b6" - ], - "bits": 8, - "prep": [ - { - "input_shares": [ - "ec863a16981eee70b71dc7d396a85ba412dcb4e86769d6db0c60f668456f5d6fbb844d9503580fb7b662bbb2ed7d92002e6ab4a2d31a6f611cbb5c48ca6df69811d536f74a3ff61eb29bd9b9f1b64c35eddd5c4ac97376057883a317f2989b545a682775f948f28f80f366f36b4eb90f931bca79e229eae377102295d9c46da2e239f74f045084747039c0a955726b4258bc0d14da7474bea6cd136eb5e55e9531e6a68703003a64943a5650b16674c82d9c4b526a7ed3d69f8f13ae83609cf056f3fed8d6593fdad7b367d2d248413072651073ea91b8162d42af168698f0f0928c8238b2df218e26d004d2bdb5f9f20d0a43c0286d08cfc26971f282992f82ff14d51cee3e0f3fc7411869c2176cabc6b1a68e33ff5eb217490de9f0d85cb84e9115bb7e208a190d25bf9cc138485892802a50b790ba6f45804de487a3353e54b5471adb5ab612d9ee6416649e136456215503637e0daab367149bc5cdf02a2dabc2790f84cadec1510263fe6aa27df5df395b7a241777a8ed28da27276b48f599dd895a005746cfd1f3c874e6f52407f4c417934d7091685c0b38b1d76b398ad263ec73f4f811aed38febf67a19a001a2c7ab8071f986939713cccd146c7a049c5129783359fcf86410765028fbfbbe62c2474a6b75de0ba49c037e07946deae971207f4f74b8b1d6a7b225eb0b66ed1f3878bc14d9d7a38b2162247b7ed9ac3df6fd2a98a3e4bf2855c8fb13f39487481fe03f5b5cb5123d11aaef180ff8ae69709322459a01a72e9304295ae5721d6eac6dae140677d0dd60f192f0475bacfd131d4ff3393238caa00fe0847c3a43c97a31f84f58b3c7487c5c0a09e85b39ed4b69fcdfa071da15216fd5f1fad125328e40689acce1a6cb113c2a16f599606162636465666768696a6b6c6d6e6f", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", - "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" - ], - "measurement": 100, - "nonce": "000102030405060708090a0b0c0d0e0f", - "out_shares": [ - [ - "b3916e4086c52aa0439356b05082885a" - ], - [ - "61992b02958137ac5d360c10f86f23ef" - ], - [ - "52d565bde4b89db326369d3fb70d54b6" - ] - ], - "prep_messages": [ - "e385da3bc2246be76ff12a7093ecb45e" - ], - "prep_shares": [ - [ - "7b6a9ad01449ec86dc6736dced3ecd24b47ab2a3768908b10696d537f2b02c98cf3314686f94ac37c7d81b14fea51f784e037bbdd56b2ee8486757acad61db1e", - "40a478cd7376c1e9ea339ddcf96ab1a7eb5e4b1153111bd6cd06aa3a5493a6da4470f696b9afff52ec10fc00040e4538470fdb8d3e05e188aba2b16e24c71b69", - "46f1ec617740528f1c642c47185681331adc83aace0cc5ddd256cf295c93c64d207d424f5056a8d59748ba9e423c4cf5f560fb4c6505c9a773629e12f21ee230" - ] - ], - "public_share": "4e037bbdd56b2ee8486757acad61db1e470fdb8d3e05e188aba2b16e24c71b69f560fb4c6505c9a773629e12f21ee230", - "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" - } - ], - "shares": 3, - "verify_key": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json b/third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json deleted file mode 100644 index ea76c50ff8..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "binder": "62696e64657220737472696e67", - "derived_seed": "9cb53deb2feda2f9a7f34fde29a833f4", - "dst": "646f6d61696e2073657061726174696f6e20746167", - "expanded_vec_field128": "9cb53deb2feda2f9a7f34fde29a833f44ade288b2f55f2cd257e5f40595b5069543b40b740dfcf8ab5c863924f4510716b625f633a2f7e55a50b24a5fec9155dec199170f9ebe46768e9d120f7e8f62840441ef53dd5d2ba2d3fd39032e2da99498f4abf815b09c667cef08f0882fa945ba3335d2c7407de1b1650a5f4fe52884caf3ef1f5802eabb8f238c4d9d419bed904dcf79b22da49f68fb547c287a9cd4a38d58017eb2031a6bf1b4defb8905c3b777e9287f62a7fb0f97e4d8a26c4e5b909958bc73a6f7512b5b845488d98a7fcedf711ada6972f4c06818d3c3e7a070a88af60dc0323b59f304935fbbbd3792e590c9b6bce7459deba3599c7f30fe64a638219dde4bde4b1a51df8d85c2f36604c44f5f188148e3ba1dca3fd8073240ee577ef322df19a13d9ffa486a6833f4eb2838a58746707b8bf531cc86098f43809276b5f02914b26cb75938ca16eafa73397920a2f5e607af30e62ff60b83e15699d4d0265affe185b307ed330941a41b2b628e44d9a19412f7d9513cacd7b1fd740b7708e3bc764a0cf2146bca7c94d1901c43f509d7dcc9dfec54476789284e53f3760610a0ac5fce205e9b9aa0355c29702a5c9395bf1de8c974c800e1037a6bf5e0bd2af7d96b7f000ff6ab93299966b6832c493b600f2595a3db99353d2f8889019cd3ec5a73fa457f5442ed5edf349e78c9cf0cbf4f65aea03754c381c3efc206b7f17447cc51ac68eceacab9d92b13b0bc700c99a26ce2b6c3271f7639aa72dc27bbd54984907abb10ef1047ef352d378ddae48bf381804c89aa1847f5027537cf6af1b30aa44cead6495e98ca5b3205d39beb49d2db6752a4e57158e8c83464002b0b4a9838bc381c1dbdc3e9a584554fb76671a15f907c0b395a5", - "length": 40, - "seed": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json b/third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json deleted file mode 100644 index edafb1bd4d..0000000000 --- a/third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "binder": "62696e64657220737472696e67", - "derived_seed": "87c4d0dd654bf8eec8805c68b5eb0182", - "dst": "646f6d61696e2073657061726174696f6e20746167", - "expanded_vec_field128": "87c4d0dd654bf8eec8805c68b5eb0182b1b8ede598cfb8d8b234038fd0492eb14268bbb2ac15a55d463c8227c2d4fae8607631d13157c4935c5d2d56e4b1e2bdfe0f80b286d82e631704acee29ab6f7acaa316d3623cc3371297604caf57bc2eafe72056143971345901b9fb9f95b6a7384c6a88143124ff693ce9e453675f87a6b6338a1e1c9f72d19e32b51f60a1d7469de1fbe25407cc338d896b34c5fc437d2551297027eeefca9aaccdb78d655a6c220cbc2d76cc4a64b04806ae893c952996abb91f6ec32b6de27fe51be59514352d31af4967c0a85c5823ff73be7f15b9c0769321e4b69cb931a4e88f9da1fde1c5df9d84a7eadb41cf25681fc64a84a1c4accded794c1e6fec1fb26a286712425bfc29521273dcfc76cbab9b3c3c2b840ab6a4f9fd73ea434fc1c22a91943ed38fef0136f0f18f680c191978ab77c750d577c3526a327564da05cfc7bb9ef52c140d9e63b1f39761648772eaa61e2efb15890aed8340e6854b428f16dff5654c8a0852d46e817b49bbe91db3c46620adbd009a0d7d40843c1b6b7786833d3c1ae097b4fa35815dbcfca78e00a34f15936ed6d0f5bf50fc25adbecd3adfa55ba6bc7052f0662595cf7a933dfcc3d0ad5d825ec3bc191586a1c36a037d1c9e73c24777825d6afe59774abdb2918c2147a0436b17bafd967e07c46c3d6240c771f4fd4f9b3fff38b294508b8af5a1b71385f90f407620b7aa636fd2b55435b3688fc26ad3c23b2ad48158c4c475c07eb58569a8d1a906452b82d582397c4c69f5e79d3082d03b4dd85b5277a8b44c933d52d168caae8c602376f5487670a172d138364cb975c569c9c2d79506746090ea8102907c91b66764fd8740ca7bd3acb59173df29b5fa7542e51bce67b97c9ee2", - "length": 40, - "seed": "000102030405060708090a0b0c0d0e0f" -} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json new file mode 100644 index 0000000000..68f3159234 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json @@ -0,0 +1,52 @@ +{ + "alpha": "0", + "beta_inner": [ + [ + "0", + "0" + ], + [ + "1", + "1" + ], + [ + "2", + "2" + ], + [ + "3", + "3" + ], + [ + "4", + "4" + ], + [ + "5", + "5" + ], + [ + "6", + "6" + ], + [ + "7", + "7" + ], + [ + "8", + "8" + ] + ], + "beta_leaf": [ + "9", + "9" + ], + "binder": "736f6d65206e6f6e6365", + "bits": 10, + "keys": [ + "000102030405060708090a0b0c0d0e0f", + "101112131415161718191a1b1c1d1e1f" + ], + "public_share": "18850fb4933f36be2d456c4e2477baf2c9a4a7204fb09ae3e3ff925ecfe07a297b07b1980635d1e1f512afbd6388c98f5bf076cc5fe746282e59b81e51bffd6699fac7ec2dab3e9dd2c60d896beb64131d73b8abd7b2f0b327e5d91b42c677468048180e55bd80946611101ff01cb82022f7aecbe1db443499a311b7b9ee114acc16ae30d73d77ab2995eef0d536c26753647394f24d0c7b6db95b0eda08056b919e862c373e9c7a1e17590e5d5f250e56249ad28f9c13a8b57dfd7dcd05d78d49640d0aa35173cb4a659ada59f57d0c408edf52cb16d8bfb5c5d56d0c28a1aa7d96054c848cfeb0eeb6576b7c8c5328dfe502bc5eef4f1c6f58abe9ad37b448995e2b584cdb5f3a94f056ca7b868ad8f593f07c73f88596398fb4f13c5a7393b8fb0d2c76076132f54484f5f18209f42e4fe98ba2b9b1d1d19c139dc4520ada547ddbb70baecf1bba61a7b3cbb4648a7235142e201a173038dac559940a55d29a68cc87298d722b6644fa445460ddb9938c64" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json new file mode 100644 index 0000000000..c4056a156a --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json @@ -0,0 +1,56 @@ +{ + "agg_param": [ + 0, + [ + 0, + 1 + ] + ], + "agg_result": [ + 0, + 1 + ], + "agg_shares": [ + "42417a6b9fd228e050220f57293f7555", + "bfbe85945f2dd71fb2ddf0a8d5c08aaa" + ], + "bits": 4, + "prep": [ + { + "input_shares": [ + "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53", + "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721" + ], + "measurement": 13, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "42417a6b9fd228e0", + "50220f57293f7555" + ], + [ + "bfbe85945f2dd71f", + "b2ddf0a8d5c08aaa" + ] + ], + "prep_messages": [ + "f7c882b687b7bd461fb1f898356db5fa88833cdaa1e26a71", + "" + ], + "prep_shares": [ + [ + "029b574f4e07246cb5b90e90207a148abb7dfba2efb9a32a", + "f62d2b6738b099da6af7e90815f3a070cd054137b228c746" + ], + [ + "264531e72e56a380", + "dbbace18d0a95c7f" + ] + ], + "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json new file mode 100644 index 0000000000..ea8bbfea10 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json @@ -0,0 +1,64 @@ +{ + "agg_param": [ + 1, + [ + 0, + 1, + 2, + 3 + ] + ], + "agg_result": [ + 0, + 0, + 0, + 1 + ], + "agg_shares": [ + "f4265a0ff9c4f0d1f068b522d608c1a38cde98228531a78ccb74919ef72f5051", + "0dd9a5f0053b0f2e11974add28f73e5c752167dd79ce5873378b6e6107d0afae" + ], + "bits": 4, + "prep": [ + { + "input_shares": [ + "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53", + "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721" + ], + "measurement": 13, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "f4265a0ff9c4f0d1", + "f068b522d608c1a3", + "8cde98228531a78c", + "cb74919ef72f5051" + ], + [ + "0dd9a5f0053b0f2e", + "11974add28f73e5c", + "752167dd79ce5873", + "378b6e6107d0afae" + ] + ], + "prep_messages": [ + "d2ca8d38065df3047d92ebacf9c366b83ad81d98fb17356a", + "" + ], + "prep_shares": [ + [ + "4c00ed0607d7702352c8786bb90f360edd89e3c8507274b1", + "87caa031fe8582e12bca724140b430aa5e4e3acfa9a5c0b8" + ], + [ + "1ed0621986d79f57", + "e32f9de6782860a8" + ] + ], + "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json new file mode 100644 index 0000000000..9b4fd0bc70 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json @@ -0,0 +1,64 @@ +{ + "agg_param": [ + 2, + [ + 0, + 2, + 4, + 6 + ] + ], + "agg_result": [ + 0, + 0, + 0, + 1 + ], + "agg_shares": [ + "6bc200377c0ebf33de6ac488c1427b38bea3859050a09e19208319b3875c5099", + "963dffc882f140cc23953b773dbd84c7435c7a6fae5f61e6e27ce64c77a3af66" + ], + "bits": 4, + "prep": [ + { + "input_shares": [ + "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53", + "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721" + ], + "measurement": 13, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "6bc200377c0ebf33", + "de6ac488c1427b38", + "bea3859050a09e19", + "208319b3875c5099" + ], + [ + "963dffc882f140cc", + "23953b773dbd84c7", + "435c7a6fae5f61e6", + "e27ce64c77a3af66" + ] + ], + "prep_messages": [ + "453405bb632d670892ddc291c4d886ce098d206debd7e121", + "" + ], + "prep_shares": [ + [ + "bd7d6befff9982c88c631d4c593d754f4b817e23f0faf751", + "89b699cb6293e43f067aa5456b9b117fbf0ba249fadce9cf" + ], + [ + "c36085ecec965e1f", + "3e9f7a131269a1e0" + ] + ], + "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json new file mode 100644 index 0000000000..f280aedebc --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json @@ -0,0 +1,76 @@ +{ + "agg_param": [ + 3, + [ + 1, + 3, + 5, + 7, + 9, + 13, + 15 + ] + ], + "agg_result": [ + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ], + "agg_shares": [ + "7e787b132dfe4dfcf9f8cab505a6133d30b7fd75f52a422d05ce25abe1b9cc5d3c4dce1f874d3e6bc4e9d9162ce3ae1e01da0581055c3d83de238e22b71bed1e8a69ed19cf9ccc49f2bb00c049d3153af4087218b63d6ae26ad30ca130641f50cb85fedfecf35fed0451625ebf2dac37281549b3cd8798fdd12d3eca3a68a17ec2c6f6086fca7b6dd59cd532e1b72bc95bedbfb4ce1dcc7cc873d989601e8a16ca1724e563a6c114b58e3bf58a65c621b00ebd22074223ec8e863c418a8ec83e0701d49174dab847df196325664790b6aba39c2d8ab74275b80ecc5d85c43c61", + "6f8784ecd201b2030607354afa59ecc2cf48028a0ad5bdd2fa31da541e463322b1b231e078b2c1943b1626e9d31c51e1fe25fa7efaa3c27c21dc71dd48e41261639612e6306333b60d44ff3fb62ceac50bf78de749c2951d952cf35ecf9be02f227a0120130ca012fbae9da140d253c8d7eab64c327867022ed2c135c5975e012b3909f7903584922a632acd1e48d436a412404b31e23383378c26769fe1756924e8db1a9c593eeb4a71c40a759a39de4ff142ddf8bddc137179c3be75713741e6fe2b6e8b2547b820e69cda99b86f49545c63d27548bd8a47f133a27a3bc31e" + ], + "bits": 4, + "prep": [ + { + "input_shares": [ + "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53", + "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721" + ], + "measurement": 13, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "7e787b132dfe4dfcf9f8cab505a6133d30b7fd75f52a422d05ce25abe1b9cc5d", + "3c4dce1f874d3e6bc4e9d9162ce3ae1e01da0581055c3d83de238e22b71bed1e", + "8a69ed19cf9ccc49f2bb00c049d3153af4087218b63d6ae26ad30ca130641f50", + "cb85fedfecf35fed0451625ebf2dac37281549b3cd8798fdd12d3eca3a68a17e", + "c2c6f6086fca7b6dd59cd532e1b72bc95bedbfb4ce1dcc7cc873d989601e8a16", + "ca1724e563a6c114b58e3bf58a65c621b00ebd22074223ec8e863c418a8ec83e", + "0701d49174dab847df196325664790b6aba39c2d8ab74275b80ecc5d85c43c61" + ], + [ + "6f8784ecd201b2030607354afa59ecc2cf48028a0ad5bdd2fa31da541e463322", + "b1b231e078b2c1943b1626e9d31c51e1fe25fa7efaa3c27c21dc71dd48e41261", + "639612e6306333b60d44ff3fb62ceac50bf78de749c2951d952cf35ecf9be02f", + "227a0120130ca012fbae9da140d253c8d7eab64c327867022ed2c135c5975e01", + "2b3909f7903584922a632acd1e48d436a412404b31e23383378c26769fe17569", + "24e8db1a9c593eeb4a71c40a759a39de4ff142ddf8bddc137179c3be75713741", + "e6fe2b6e8b2547b820e69cda99b86f49545c63d27548bd8a47f133a27a3bc31e" + ] + ], + "prep_messages": [ + "d6ce08ae0327f913210f5e0701c594bf1baa15a33f6933f9b73787f73464db6a6a10f3c7e7e76a1844367d0091f16a7f090e7ed1fcc6f2a456e9e12daec41b18e08c45f8b9c5d20b02e8fecd25cb7fc05e98a6c79a1ee08da284161b3bd94d53", + "" + ], + "prep_shares": [ + [ + "b289bbdd941be53774dbb8177fd40ee4614c325d64ca211dee7268c34fd93c7855030fd22ac1db9e4760d9cd03a090b976b2b9a9bcef2e9f9affeb5cd6afe05423b5b3db766c04dc072864e1dd8b0d0fabf8b8add732c7eeff4ae5ba5fe0fc13", + "11454dd06e0b14dcac33a5ef81f085dbb95de345db9e11dcc9c41e34e58a9e72020de4f5bc268f79fcd5a3328d51dac5925bc42740d7c305bce9f5d0d7143b43bdd7911c4359ce2ffabf9aec473f72b1b39fed19c3eb189fa2393160dbf8503f" + ], + [ + "b4fe321bd55f5135b7ebfda820401ad7b7fba83b65e68b8ede4b0a566a9f5629", + "3901cde42aa0aeca48140257dfbfe528480457c49a19747121b4f5a99560a956" + ] + ], + "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json new file mode 100644 index 0000000000..c0336fa679 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json @@ -0,0 +1,39 @@ +{ + "agg_param": null, + "agg_result": 1, + "agg_shares": [ + "352c53cbc1f95eee", + "cdd3ac343d06a111" + ], + "prep": [ + { + "input_shares": [ + "352c53cbc1f95eee43253a8650e8ac18a5bd9c18b824886772947facdf1a413f1cf547cdb8c1ad4ed4c1294ccc856209", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + ], + "measurement": 1, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "352c53cbc1f95eee" + ], + [ + "cdd3ac343d06a111" + ] + ], + "prep_messages": [ + "" + ], + "prep_shares": [ + [ + "f6340e6030e5960b53ad59de202314363e6063ed75a89676e3b9635d397d650e", + "0bcbf19fce1a69f4b5de9ce10c9c671b9baa607f88bfa49de4367212193d9b3b" + ] + ], + "public_share": "", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json new file mode 100644 index 0000000000..6731f2a13b --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json @@ -0,0 +1,45 @@ +{ + "agg_param": null, + "agg_result": 1, + "agg_shares": [ + "4eeea47bcff955f0", + "cdd3ac343d06a111", + "e83dae4ff1ff08fe" + ], + "prep": [ + { + "input_shares": [ + "4eeea47bcff955f08194b8660a6bb007a346b42952b2298158c165d94c1c40979e10b54ae7092a5a14b325df003a6f9d", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" + ], + "measurement": 1, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "4eeea47bcff955f0" + ], + [ + "cdd3ac343d06a111" + ], + [ + "e83dae4ff1ff08fe" + ] + ], + "prep_messages": [ + "" + ], + "prep_shares": [ + [ + "817531f295522feac2551124114fdc827bfda7719fb1eb33b0b4e1c49761f62f", + "0bcbf19fce1a69f4b5de9ce10c9c671b9baa607f88bfa49de4367212193d9b3b", + "76bfdc6d999267219aa129cccf1e2459cf93ae20bf886d0d22fe0f5fcded28e6" + ] + ], + "public_share": "", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 3, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json new file mode 100644 index 0000000000..b39dc2838d --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json @@ -0,0 +1,52 @@ +{ + "agg_param": null, + "agg_result": [ + 0, + 0, + 1, + 0 + ], + "agg_shares": [ + "ac3ba28d7f5649e6b3932251da118acf6740508adaf7837c87cd0574c48a00ea2ba59154eff2921c69cdeb23276510d3758486d91898690c4ba0fd3e6e149956", + "55c45d7280a9b619306cddae25ee75309abfaf7525087c835c32fa8b3b75ff15d75a6eab100d6de37a3214dcd89aef2c8c7b7926e76796f3985f02c191eb66a9" + ], + "chunk_length": 2, + "length": 4, + "prep": [ + { + "input_shares": [ + "ac3ba28d7f5649e6b3932251da118acf6740508adaf7837c87cd0574c48a00ea2ba59154eff2921c69cdeb23276510d3758486d91898690c4ba0fd3e6e149956aaa0fbc70889fae40bf0b8873db6f2c2c26ef6772e0dd8d091e12a1dbe4388bbc88819a887c53a4afa8e3e35b0c00100af9000ad245790e71c322e5c252e25a25514ccc4ebeb9b9f47a98223b2d04d44f94a2cb4791ff9a056eca2a0c74ab11f08d41d917cdaa2858d372c08339c414559066eb7be61cf2b5bb36c7c598a97b19802fead02586c39b001c18b5ff36e66d9ab75d6e9c6c0c0eaae66b1014ba2645047801054acea9f87404cc2749584db303132333435363738393a3b3c3d3e3f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + ], + "measurement": 2, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "ac3ba28d7f5649e6b3932251da118acf", + "6740508adaf7837c87cd0574c48a00ea", + "2ba59154eff2921c69cdeb23276510d3", + "758486d91898690c4ba0fd3e6e149956" + ], + [ + "55c45d7280a9b619306cddae25ee7530", + "9abfaf7525087c835c32fa8b3b75ff15", + "d75a6eab100d6de37a3214dcd89aef2c", + "8c7b7926e76796f3985f02c191eb66a9" + ] + ], + "prep_messages": [ + "1acd91a20b79e95050d47db9bf4b1ed5" + ], + "prep_shares": [ + [ + "aaf0cada92114681d890231d05395ea51dcf30c4fa042de2f21b10d3126976a4565c5032534c5af98418b0bf0647dddada1e47da1c608f0d03070d5baf530d1e52b4ace95d26bdc41c0bf64068880a5bcbf5ab84954e1087ff8721b600477c48bc82ef4255afbf48216c910cd76ca594", + "570f35256deeb97e0b6fdce2fac6a15a8d4d3367a586ac831119c6edeefb5ab1d4a2ad70c499a97f61b3eb86717264b1a941e67b26a189ff84bc81c89edafd3187e190bacd40bfa5813ccbd77338c7eedb90e273a045b29382cdddc5571e35de1da4a26362199818038b8624ba1ea4a9" + ] + ], + "public_share": "bc82ef4255afbf48216c910cd76ca5941da4a26362199818038b8624ba1ea4a9", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json new file mode 100644 index 0000000000..512b2aca98 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json @@ -0,0 +1,89 @@ +{ + "agg_param": null, + "agg_result": [ + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "agg_shares": [ + "6ef23fd4b5f5502e5c215848c3703c1ac06dbc83cebd2ebb78b8549c64cf10b6a709f226d0e6aadbaac7c1512dce7f44e0715547855fae84e0a1f1fe7612423940c18ce556a3754c64b46de79038603b2ffae8c57346b7a9385f34f084d8f62d8e145aab9b0f1c038ed9f7b94d82a6cc7d32743c367987da80859005285a4b2f41e62177eead51b17bae964e100bd7408688c19870104fddb90ed31a0065a92f870079891c2ccc659a2a2cf3cb424cc3", + "55c45d7280a9b619306cddae25ee75309abfaf7525087c835c32fa8b3b75ff15d75a6eab100d6de37a3214dcd89aef2c8c7b7926e76796f3985f02c191eb66a970fd5de8e08724782338a0d5e77d181f61a976f8712fccdde127760cb8056d105e3d2f6c325607ab4a9a3ce791283b3af006fd1a4aa66fbfb30ade0e81c5d226e5c8ad6b7e4bdd02db51d98a13f5cf81d7797d2adb9c59afef3378108eec9ad02f4bddb5208b11cdd02e159b36eddd76", + "3e4962b9c960f8b75772ca0817a14db5a7d293060c3a55c10e15b1d75fbbef33849b9f2d1f0ce840be052ad2f996908e951231929338bb876afe0b40f701571d51411532c8d4653b5c13f242874987a5715ca0411a8a7c78c9785503c3219cc116ae76e8319adc51ef8bcb5e20551ef994c68ea87fe00866af6f91eb56e0e1a9db50301d9306d14b8dff8f26dcff583da5fdc03cb45257731ebdb4d471aebbff4cb4a9c0c24822cd5ca6be71fdcfd5c5" + ], + "chunk_length": 3, + "length": 11, + "prep": [ + { + "input_shares": [ + "6ef23fd4b5f5502e5c215848c3703c1ac06dbc83cebd2ebb78b8549c64cf10b6a709f226d0e6aadbaac7c1512dce7f44e0715547855fae84e0a1f1fe7612423940c18ce556a3754c64b46de79038603b2ffae8c57346b7a9385f34f084d8f62d8e145aab9b0f1c038ed9f7b94d82a6cc7d32743c367987da80859005285a4b2f41e62177eead51b17bae964e100bd7408688c19870104fddb90ed31a0065a92f870079891c2ccc659a2a2cf3cb424cc31d60b4e3908aa656e527d0a66eaeaaf493bde0a7a86be4ed3145a5596fab04256c95611675891b234a939c91215ec467aa9a516cd6a9a7b8d1a4ddb91e8dbfbcc8d9a45d8792f9d56a68061809b7ef4963736c20e3cb8ce6a95e1bd84c7ae51ccb14192b3101ac85a5a3a62415fb516df685b9313b53f39bc6a74062a55435f9c35f50ffd660a6d7e0e9365128bf6d87e52358afe563bc1bdce119291c611597889d36caf3247f61821eb596b089dddaf32359b12e74260a24d816335a2bf1aa93dbd84dd31773f2795ee931187525a570589f31e66a0e0d8a92370c3458fb00b2afb3e3d98f142cf9606d47d28a75caa8b4ee730e1ff3faf0aed3a154887dceaa6dfad49582d4a560b0d6599e0cbab2b36f20b8ca497f6540ca17f69595c695c2c6e0e00956acca22c71fab529936c47ad8de0e09f39d41a3b0469edcbfea242b20cd6a4748d4075ffb9a755b297902606162636465666768696a6b6c6d6e6f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + ], + "measurement": 2, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "6ef23fd4b5f5502e5c215848c3703c1a", + "c06dbc83cebd2ebb78b8549c64cf10b6", + "a709f226d0e6aadbaac7c1512dce7f44", + "e0715547855fae84e0a1f1fe76124239", + "40c18ce556a3754c64b46de79038603b", + "2ffae8c57346b7a9385f34f084d8f62d", + "8e145aab9b0f1c038ed9f7b94d82a6cc", + "7d32743c367987da80859005285a4b2f", + "41e62177eead51b17bae964e100bd740", + "8688c19870104fddb90ed31a0065a92f", + "870079891c2ccc659a2a2cf3cb424cc3" + ], + [ + "55c45d7280a9b619306cddae25ee7530", + "9abfaf7525087c835c32fa8b3b75ff15", + "d75a6eab100d6de37a3214dcd89aef2c", + "8c7b7926e76796f3985f02c191eb66a9", + "70fd5de8e08724782338a0d5e77d181f", + "61a976f8712fccdde127760cb8056d10", + "5e3d2f6c325607ab4a9a3ce791283b3a", + "f006fd1a4aa66fbfb30ade0e81c5d226", + "e5c8ad6b7e4bdd02db51d98a13f5cf81", + "d7797d2adb9c59afef3378108eec9ad0", + "2f4bddb5208b11cdd02e159b36eddd76" + ], + [ + "3e4962b9c960f8b75772ca0817a14db5", + "a7d293060c3a55c10e15b1d75fbbef33", + "849b9f2d1f0ce840be052ad2f996908e", + "951231929338bb876afe0b40f701571d", + "51411532c8d4653b5c13f242874987a5", + "715ca0411a8a7c78c9785503c3219cc1", + "16ae76e8319adc51ef8bcb5e20551ef9", + "94c68ea87fe00866af6f91eb56e0e1a9", + "db50301d9306d14b8dff8f26dcff583d", + "a5fdc03cb45257731ebdb4d471aebbff", + "4cb4a9c0c24822cd5ca6be71fdcfd5c5" + ] + ], + "prep_messages": [ + "1b2dc3cedc43f65731985f19081f490a" + ], + "prep_shares": [ + [ + "cd5978e237aafb0552d6f2614be379176c256bd1bb2d3fa71ec64fcf5e64b6baf5c530e6c828d5be1468539c16917e08f6cc5d754b81f6ea05ed0747377a2dbb5a731ed05a41704a11aea67a37c668810c7fbee6ef543f6a757ffa07f22a6fdc6c37173af38746dcd7ef1f2cb0f555d13b999f3ef6a282b6649c29878349c501711da5ad2a4ac3de6fccb15c803f918a", + "87cd13bcc0f7bb62542f40b8a480db80fca16e26264525b236a3664c792009277d9133d4ff0df494d18758677dbea683d9be082297301d1db87b6a345f74f07a3e268fd6e440eec02b3d4109b30d9c680c18d29df84586f30d30a2cf2419471d2b45845e9a4ba9f1c835ef577bcfa710e9d907592e678fa3a225e115cac914fde07e503edb901812725c6f25d7585fb2", + "add87361075e48973dfacce50f9caa67077de5a0a3d6e85b8b04772423132387fb2732f839d0de182c65e61553e08af6fa237248acc8e6cfad227ed43c8eed56bd3c1ae929a7c2bc1c5b47dfd2d57a56fd8f3a4f2187c7f94ae1dd203aa9e3bc20a53b7ada0b4f545e0c7a8370be163a582fb321c11446cb9f3b65dc2979f432236aba9b84dbe8182bce25a97ad12186" + ] + ], + "public_share": "711da5ad2a4ac3de6fccb15c803f918ae07e503edb901812725c6f25d7585fb2236aba9b84dbe8182bce25a97ad12186", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + } + ], + "shares": 3, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json new file mode 100644 index 0000000000..f18f47d506 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json @@ -0,0 +1,194 @@ +{ + "agg_param": null, + "agg_result": [ + 256, + 257, + 258, + 259, + 260, + 261, + 262, + 263, + 264, + 265 + ], + "agg_shares": [ + "b43a2f79240602a73fafe498f4596524e2d16ccd2a68978aa0fc3b08cb757afa0e634bcf86a6f9f6066716d8d6ff6fc5d8323c1f04aa8b08948ef2e9e7a7a10e3be55e452c536f004da7d3502d93f9ef835b59067c8de2bec68afff55e15d4923cdab73e57ea28b90b70d15dc110dac2ab8c34f509842b025606222ee32ce920b14cc3ccabdfc4f1f743b9ef3ca0c2b5bd715085b0d76c95daeecfad16278bb6", + "4dc6d086dbf9fd58a4501b670ba69adb202f9332d59768754303c4f7348a8505f59db43079590609dd98e9272900903a2ccec3e0fb5574f74f710d1618585ef1ca1ba1bad3ac90ff96582cafd26c061083a5a6f983721d411d75000aa1ea2b6dcb2648c1a815d746d88f2ea23eef253d5d74cb0af67bd4fd8df9ddd11cd316df58b43c3354203b0eecbb4610c35f3d4a4d8faf7a4f28936a09113052e9d87449" + ], + "bits": 8, + "chunk_length": 9, + "length": 10, + "prep": [ + { + "input_shares": [ + "43118698b73a59751812aa20a73ae412766ef3c4c7559adaf4f08d6d73fbe01849ac4f0da41a26f10b1709d08f56da39953a74ee5cca941b880a5857b143cdeb7065b4b8f6b13b474040cd9e5307fd42850c79e49dc4808a8bf2d976223522179142c2cce38fce9218a371029ac88597283e246464233e9d7cf7048bbe3d18d369dfb8d462dddbe94e33f7ebc07bf0cbe8ecf9e42a156f1fd2b6c434eb62813c0929e78c86cf9bcfad5d54287598c986364fcb6fbbfa0db79dc0f4c1dbaebed54201c88b9e1f93a7fcabc0137d2b6c8ec6f423d7aeeced8f7dbd4c64e7ed595b6e5d76034a16c5686a8982397ef1e882232a95e11e7377d5b758015b716472c4dfaa9021bf2f861e18507f7f8435b55a4a3c8f7357e245596c08975169be3fdf4f2bc8600e680b9013f52b67000959ce3a588caaabdedb7d6201210902695051d808571846039dc672be3d2a7d2d25137baf47f5b71d1d907c9db4d3c20045cb32bdcf9c0094bce467da04ed90e885c9e0765a41d98cc0cc454d1d97efe2255eed21c3b2297d9d0717f8d46d1a016ab89afabd89620aa6090d21ad7226d173f23cbdd31702582ca06b336d277c4f39903414ab2baddfa578bce3be8ba27d68651d720b8401a4ffc61c999f628cdc71c058767c63f23e8b933add17cd3e50ab8540c9ebf935b2912fa26d68e2cc9289e4f894b8d03a81b8d306cadabb209de35c980d4ceea42abc4a0581b6114c77e4cc66c01be07deb7bdb8db23df5d67398497b30ea78518ff759304b5269502f93848838ba2d3e1737aadbbcbd4cde25689fff7a738df9017a4f2986c8fe8b8ba6b6f87b4dd6ec84876ba076c31039cf59b695313060ca1dfdb288c8924ebcaddddf9d067f2be6033af80313292c03996a39281c78299d8549d12cd8427104783575ec604930ab55e288606fdeb863afbeb9df6a009694c055c34d68e19c19ef3fa851363493cdf197c201958449e57e327b15eb5e25d2d347374a85e4685b432a15f4f768fa0b180f6db9f0af65cbbcb0c137a2e12cbb0aadf81e78244e2b8855634a9d0014005d9c9209381943f019df54769b4452a47ce0f223ae52a4d28d725d97e40b37b250499508838bc8a7ccb133f7a02fbfc91fa1c27685786808ae4a45e08cf841c79f3a61b58ae87005dd4e43920089fc2bc23b8c6ac3aaf2081a14edf30a0299f3094410689ec026a8bf8ba2b1c470583987c30d5d8ca6e7ea605d0c7661dba95beef2f4b94f5306317ecfa60010d6b18c2aebb994a4559fad9f3538ef7eaaf35761f7640b807483793ed8ab3ae20672da387979a8171eb1425700e257a912e645a80739e5d494ba6d419dcd4fec13aa806fcfcc84480d7e0e676916aded6f1cf9d69f7e958dceae1edaa11b2569954b7689e647906cccbdcbc2897f139356d9c85168f08ed8990aefc891158a1b89d7c19d3c56ad2a91d3de46ada48ec6338d13efb16c4cb49acd981a044c335240ce7d1db84fde51058290cae528cc7dc5794daa652268d9e5d0fa639a8549c9fdcd3fd126f653f9b970d804fdd4f420e473a31410fe9a84fc43ae415d008ac86ca0881f737382196cd5b6dd4b8673cb515ef70c4624bea32c22a7b72c2f8e1c2fc693a4905215e10580aef647be4bd36baab91c2867bcec745bc5334ce8cda1a0d77f6bb5f1838c60904f8ba7aec00d2529e87c41702b774c6f11c632d35f477988847de39626fd7e83b07ca2de2d7dbd68d07617dc590e00684c79ff1d8ff484a31056b53b29cbe470c8bf99515d7ad2939120d3b9b9ebabfb29d0e7b77cc7bb5ab97fc44591ee036de0206b8331c99c75e8bcc50ac1cb75fec3fb640318010d3ddeaaf423d14d2d715e7cf81ee4d01ad0c0f09c66b2e0b396b93c2bc97b21a42cdafe748aa4b59c250e4639be7173f4cff260339d2797e402653a3bef19a0a17763395889c4269679f6bd0289a356eaf0f06b409d24d4c112ff8f60b9383669677635f20d8eeed5c38d9500e39dca878f578b4980f374ee556aa3458b551628ff9f110d11b7f2497195d9bf3c9557e6f3d11c05f52158aab8f6485cdecfa158e592453351f1866faed652e75b37562a4c696867a89ed8b55355c82c6b571918d3995cb6516f00742a7f0974f62ca846d1306422176a204627930693eaf08951f082629d0a5537aea1d8729693798896fb16830a7cc7b29737f29637308283d5577ee3ea54987f14e4b1b4a51a17f7426a1ea86b42db1410a05064dd773bb5dacdf49702f7cf3ee9695f82fe881ef34c52e8d46e1e415989a757ec94cdd07294a2290e19749606638ed7ab2138cb9f7769a75b169f02dded1bb93c70095ef01be80b96b0ec21588146c8a238abd2bc14a170c5a024fe683c809ff478def04de33f353111c054ff502e7fad8e768bde39cfe419373b0bd40f1ae943d61b6fb824ac689955567fb7526f05d4db0c32f0e7b76cadb917ce200edfda6065129e19fa38ba3855586913baee0bbbade97144bac9c4763c95278f90bcaaa42fbbbfac31fcba0b8291025dbfd1a3660a60cc97763672331ee7db22c0932f46dfc313e7bd60ee86b7e3b4c11b5daaf8cf3e35fcaa124ae0a05bd063ff4944364ee16326b6131422bf08803aa713c771377f5f47cc940f879b2a1763110c22867c7a704c970163b15f702757d87e6e24a4474865877352ecef45294ef3bb7ec9e45f8609da982a161f89a8a9c2a6cf56fc9e8a2d9396fccf4bdd7b8aaf370f4478cb45bd5773f2a5af3d6149b4e41e364cf87c771848716998b070fe95d1d74c9d77466eae8efe0d5a0435de53d50d562c611ed8a2145c752ea54b31101db21f2688fefac5a3df5fc8163f134e5bcfcfcb2106a642ae3e6bcbd15654f09546ccb8c48d84d3bc7d0a18900dba3d66cb02ec33303132333435363738393a3b3c3d3e3f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + ], + "measurement": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "3c1365280c0256e2bf8fa1dda6c8210c", + "4cf0ce9963cd8783355469ad43277e53", + "5ccbc3ef2ce2fdfc4422b2f29caa7aec", + "f565690aac38d90228da50a3a2e2355a", + "c1f6746cb91b25006fe29bc5b9dbfd4f", + "2f1e7357292ff6949783aafc745cf130", + "c39d92bfc7f862e84f259b7440b04896", + "932ebc51032cb90072570bba4b64f80a", + "966e96998e4aeca59e1693fabe8aeb91", + "9b25702c90f2ce3136faef39b2b783e7" + ], + [ + "c5ec9ad7f3fda91d24705e225937def3", + "b60f31669c32787caeab9652bcd881ac", + "a7343c10d31d02039fdd4d0d63558513", + "0f9a96f553c726fdbb25af5c5d1dcaa5", + "44098b9346e4daff741d643a462402b0", + "d7e18ca8d6d0096b4c7c55038ba30ecf", + "44626d4038079d1794da648bbf4fb769", + "75d143aefcd346ff71a8f445b49b07f5", + "7391696671b5135a45e96c054175146e", + "6fda8fd36f0d31cead0510c64d487c18" + ] + ], + "prep_messages": [ + "faa44093d924dc5a7a7964fd9c8ec82b" + ], + "prep_shares": [ + [ + "f9ab3aa30354eb87abdd838ca558b6cbf26345360ccb2dea7deffb9e075c54b422f03470466c54abee94d25dd57eff3a073bf64fcf5eb3d7334b815115b39e6b16ea9cd0bd90f550dd701f3bf288451f17d4c7a3adc44ef5ad49663dfa2e95250320cb7d3fa0323ddcddcdb0d628146f48f6b53badd73c5333fe30cefbca3badd9a688c628f9df7129d7283772dfa0cc630e06a2795703ee70e9a01f64d3a704df997b7b6de7335aedbab9b3a1932989f93e66bb51c72416fc7f1c54bdf6f15d04c07dd5c8c2d5abea0921c5047299cd82f633af0f04fbde479b82628f0e446e781cca6b0548eaa34d8d1e5279078afe906905aa91922bf69977a92b586541d02a80245334e5321901ea62181f121f7aaaaf89061b36b0f9eb5c9ca22ddb5d09bca32696a262178178745830d0c0dee8fcc9033f8f5c98e5f3eaa91fded998019c068644495dcc3fad1eb4b63821a23b", + "0854c55cfcab147838227c735aa7493430369af6251b129c24fca111dc13d34678b16bc625356621f29ea8e47b665ab509578cae546f46e04b013376fc8439d5cde2eb50a36d1303c487fd8456539db6e653b588217b6b273b7b3d79de062a76332662a738cb172c781306cffa8b46f9aceaaf6b663a749763c9db91c5ebb62dd0f94a3d036b82c41b49709fe6c3815e215adf1c2ae55fd9d90f8186c07c37af26d2e0803bbda031317b76cdbcc7b6817529c92ef23b00db2243ffd4767f7c8e9d39781324cef39ddf613e24e4a6351037d62b77ff946d119fb2da47fd757e16d34aa0c53bd7d6fb53472d84ca55f554638e2529702522faa8c177d51394a89bbd4cec850ee6ff565296aad4f2cd6b9f35ad7ff7b7b494b97248e3a894dce393259fa038f067fb28655b6e18edc9a032053e900a2e3d07f7ca52461922710f91f4ec2449a30929eb714d75d9db74f3a7" + ] + ], + "public_share": "9c068644495dcc3fad1eb4b63821a23bf4ec2449a30929eb714d75d9db74f3a7", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + }, + { + "input_shares": [ + "44118698b73a59751812aa20a73ae412766ef3c4c7559adaf4f08d6d73fbe01849ac4f0da41a26f10b1709d08f56da39953a74ee5cca941b880a5857b143cdeb7065b4b8f6b13b474040cd9e5307fd42850c79e49dc4808a8bf2d976223522179142c2cce38fce9218a371029ac88597283e246464233e9d7cf7048bbe3d18d369dfb8d462dddbe94e33f7ebc07bf0cbe8ecf9e42a156f1fd2b6c434eb62813c0929e78c86cf9bcfad5d54287598c986364fcb6fbbfa0db79dc0f4c1dbaebed54201c88b9e1f93a7fcabc0137d2b6c8ec6f423d7aeeced8f7dbd4c64e7ed595b6e5d76034a16c5686a8982397ef1e882232a95e11e7377d5b758015b716472c4e0aa9021bf2f861e18507f7f8435b55a493c8f7357e245596c08975169be3fdf4f2bc8600e680b9013f52b67000959ce3a588caaabdedb7d6201210902695051d808571846039dc672be3d2a7d2d25137baf47f5b71d1d907c9db4d3c20045cb32bdcf9c0094bce467da04ed90e885c9e0765a41d98cc0cc454d1d97efe2255eed21c3b2297d9d0717f8d46d1a016ab899fabd89620aa6090d21ad7226d173f23cbdd31702582ca06b336d277c4f39903414ab2baddfa578bce3be8ba27d68651d720b8401a4ffc61c999f628cdc71c058767c63f23e8b933add17cd3e50ab8540c9ebf935b2912fa26d68e2cc9289e4f894b8d03a81b8d306cadabb209de35c990d4ceea42abc4a0581b6114c77e4cc66c01be07deb7bdb8db23df5d67398497a30ea78518ff759304b5269502f93848838ba2d3e1737aadbbcbd4cde25689fff7a738df9017a4f2986c8fe8b8ba6b6f87b4dd6ec84876ba076c31039cf59b695313060ca1dfdb288c8924ebcaddddf9d067f2be6033af80313292c03996a39281c78299d8549d12cd8427104783575ec604930ab55e288606fdeb863afbeb9de6a009694c055c34d68e19c19ef3fa851363493cdf197c201958449e57e327b15eb5e25d2d347374a85e4685b432a15f4f768fa0b180f6db9f0af65cbbcb0c137a2e12cbb0aadf81e78244e2b8855634a9d0014005d9c9209381943f019df54779b4452a47ce0f223ae52a4d28d725d96e40b37b250499508838bc8a7ccb133f6a02fbfc91fa1c27685786808ae4a45e08cf841c79f3a61b58ae87005dd4e43920089fc2bc23b8c6ac3aaf2081a14edf30a0299f3094410689ec026a8bf8ba2b1c470583987c30d5d8ca6e7ea605d0c7661dba95beef2f4b94f5306317ecfa60010d6b18c2aebb994a4559fad9f3538ee7eaaf35761f7640b807483793ed8ab39e20672da387979a8171eb1425700e257a912e645a80739e5d494ba6d419dcd4fec13aa806fcfcc84480d7e0e676916aded6f1cf9d69f7e958dceae1edaa11b2569954b7689e647906cccbdcbc2897f139356d9c85168f08ed8990aefc891158b1b89d7c19d3c56ad2a91d3de46ada48ec6338d13efb16c4cb49acd981a044c335240ce7d1db84fde51058290cae528cb7dc5794daa652268d9e5d0fa639a8549c9fdcd3fd126f653f9b970d804fdd4f420e473a31410fe9a84fc43ae415d008ac86ca0881f737382196cd5b6dd4b8673cb515ef70c4624bea32c22a7b72c2f8e1c2fc693a4905215e10580aef647be4bd36baab91c2867bcec745bc5334ce8cda1a0d77f6bb5f1838c60904f8ba7aebf0d2529e87c41702b774c6f11c632d35f477988847de39626fd7e83b07ca2de2d7dbd68d07617dc590e00684c79ff1d8ff484a31056b53b29cbe470c8bf99515d7ad2939120d3b9b9ebabfb29d0e7b77cc7bb5ab97fc44591ee036de0206b8331c99c75e8bcc50ac1cb75fec3fb640318010d3ddeaaf423d14d2d715e7cf81ee4d01ad0c0f09c66b2e0b396b93c2bc97b21a42cdafe748aa4b59c250e4639be7173f4cff260339d2797e402653a3bef19a0a17763395889c4269679f6bd0289a356eaf0f06b409d24d4c112ff8f60b9383669677635f20d8eeed5c38d9500e39dca878f578b4980f374ee556aa3458b551628ff9f110d11b7f2497195d9bf3c9557e6f3d11c05f52158aab8f6485cdecfa158e592453351f1866faed652e75b37562a4c696867a89ed8b55355c82c6b571918d3995cb6516f00742a7f0974f62ca846d1306422176a204627930693eaf08951f082629d0a5537aea1d8729693798896fb16830a7cc7b29737f296373045c4b3272022ca8eba72c601043d08da35f439bc7d0100d6aeb7c2a7cb74a82c9abf8982362807bed855c50ebe0e571d2624f06387b4439e7580af40033dccb657fea66e721e9b2c20cdd3dba93c3261c4ec327a89ed4007b7393820f46a60ace5876392117b97b9a358a1286944bcf0e7cf4f471d46694dc37fc670aee1d4cd7fa002020f5c7ea0bc65d0ca4e42729107abeab7a2f7b86d9f663a73485f54c4870609a0789554bd2f623176f563b8d577965464bc1d7ecca70103d13c963f741f6981cb1d83a7eb09878d39d5ec7e007d390fd93c9dba87670e981d6e21069f72602526625fd88a5cafc400b01720fccc97763672331ee7db22c0932f46dfc351a6df904c48d8a976ce693f58706d7f16ffb3c0ea860cc818c14c42c925832c041c075fd291ba417723cb6e68e5deea5716298370a7c6aae23beb7276354591e9c084351aa1ddb79d9067319c93931e5018cc62705ac5dd58f1a8b7439bf4bcff7192ee243138bc26a9a2c42eb57859751a58f04f4f83b4b673254700571cdcb66a38b1187b425df9e234484fa168dd01ab675fb38b167ec06b6b7878311fcf2f20ca9aee115b9d683375ce1dc64f98d93136680c056af071501b2b50ea4b267cab3e117c157683ba9f7a10069efa0afab0ed9ec6444ddf16d5e834834fe2e0dbd0df92d6b6c19697673837bf51d697303132333435363738393a3b3c3d3e3f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + ], + "measurement": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "3d1365280c0256e2bf8fa1dda6c8210c", + "4cf0ce9963cd8783355469ad43277e53", + "5bcbc3ef2ce2fdfc4422b2f29caa7aec", + "f365690aac38d90228da50a3a2e2355a", + "bef6746cb91b25006fe29bc5b9dbfd4f", + "2b1e7357292ff6949783aafc745cf130", + "be9d92bfc7f862e84f259b7440b04896", + "8d2ebc51032cb90072570bba4b64f80a", + "8f6e96998e4aeca59e1693fabe8aeb91", + "9325702c90f2ce3136faef39b2b783e7" + ], + [ + "c5ec9ad7f3fda91d24705e225937def3", + "b60f31669c32787caeab9652bcd881ac", + "a7343c10d31d02039fdd4d0d63558513", + "0f9a96f553c726fdbb25af5c5d1dcaa5", + "44098b9346e4daff741d643a462402b0", + "d7e18ca8d6d0096b4c7c55038ba30ecf", + "44626d4038079d1794da648bbf4fb769", + "75d143aefcd346ff71a8f445b49b07f5", + "7391696671b5135a45e96c054175146e", + "6fda8fd36f0d31cead0510c64d487c18" + ] + ], + "prep_messages": [ + "22b05b9abf6f7798c91fb089ec73d79c" + ], + "prep_shares": [ + [ + "f9ab3aa30354eb87abdd838ca558b6cba06d3c978291ea82c4c856026ce4a3cb3dec40f98bf1cf3db33e3a736043891abbb4629ed714cfb72b9a70be2083cc84c41c02e448c46154ed923d78db089e67c7bbe0ef236ecd77f99c8d5e5272f4aa0320cb7d3fa0323ddcddcdb0d628146f3a94850ce63a023fa1ec776f6082d00e5fef53097f1b9a562fe9c3c4b1d9b03a87131642b49c990eb174e205bf6d68af4248001090e9ee0c2c52614d1778ac60eaf3003e3714c6ef5c99442ad527fb434fea0dce4d6fe6cd3de25237bf75d34a3b619efbec942fe7f466c96521a9672a1b8773d0a3c0009b8020cc9719ddae7aee79d2a751e4405c17493fb96c28b9dfd90c135f76582ed5f72b0867cf2276d0aee16e5c44d6ac86eff63369b58b79fd5f34e68b4406f78664224591044c64f776d62683c1ad354cfd588c2168df20c6374a2b13433b05ee12db5fdd45070eac", + "0854c55cfcab147838227c735aa74934a0198736b579cfe4f87a1ab05d6cecc278b16bc625356621f29ea8e47b665ab59a91a8a0b72799489818a54757992f45cde2eb50a36d1303c487fd8456539db688dec5f51c76fdade09bf05bb59d8f82332662a738cb172c781306cffa8b46f986b9544adb196632fd3464f73faa14d8d0f94a3d036b82c41b49709fe6c3815ee39a9e9f46241986e33eb72c43757e3d26d2e0803bbda031317b76cdbcc7b681efe9a68224da578206e4518bbd64e9b69d39781324cef39ddf613e24e4a6351009ef3a1ca5f6d5b556077ed9c6e12b98d34aa0c53bd7d6fb53472d84ca55f554bff591feeca2f8c458b72bc0dd4a9dc4bd4cec850ee6ff565296aad4f2cd6b9fe2ca244753a83522e0d4496a1c66cdb8259fa038f067fb28655b6e18edc9a032053e900a2e3d07f7ca52461922710f91f4ec2449a30929eb714d75d9db74f3a7" + ] + ], + "public_share": "374a2b13433b05ee12db5fdd45070eacf4ec2449a30929eb714d75d9db74f3a7", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + }, + { + "input_shares": [ + "44118698b73a59751812aa20a73ae412776ef3c4c7559adaf4f08d6d73fbe0184aac4f0da41a26f10b1709d08f56da39963a74ee5cca941b880a5857b143cdeb7165b4b8f6b13b474040cd9e5307fd42860c79e49dc4808a8bf2d976223522179242c2cce38fce9218a371029ac88597293e246464233e9d7cf7048bbe3d18d369dfb8d462dddbe94e33f7ebc07bf0cbe9ecf9e42a156f1fd2b6c434eb62813c0a29e78c86cf9bcfad5d54287598c986374fcb6fbbfa0db79dc0f4c1dbaebed54301c88b9e1f93a7fcabc0137d2b6c8ec7f423d7aeeced8f7dbd4c64e7ed595b6f5d76034a16c5686a8982397ef1e882242a95e11e7377d5b758015b716472c4e0aa9021bf2f861e18507f7f8435b55a4a3c8f7357e245596c08975169be3fdf502bc8600e680b9013f52b67000959ce3b588caaabdedb7d6201210902695051d908571846039dc672be3d2a7d2d25137caf47f5b71d1d907c9db4d3c20045cb33bdcf9c0094bce467da04ed90e885c9e1765a41d98cc0cc454d1d97efe2255eed21c3b2297d9d0717f8d46d1a016ab89afabd89620aa6090d21ad7226d173f23dbdd31702582ca06b336d277c4f39903514ab2baddfa578bce3be8ba27d68651e720b8401a4ffc61c999f628cdc71c059767c63f23e8b933add17cd3e50ab8541c9ebf935b2912fa26d68e2cc9289e4f994b8d03a81b8d306cadabb209de35c990d4ceea42abc4a0581b6114c77e4cc67c01be07deb7bdb8db23df5d67398497b30ea78518ff759304b5269502f93848938ba2d3e1737aadbbcbd4cde25689f007b738df9017a4f2986c8fe8b8ba6b6f97b4dd6ec84876ba076c31039cf59b696313060ca1dfdb288c8924ebcaddddf9e067f2be6033af80313292c03996a39281c78299d8549d12cd8427104783575ed604930ab55e288606fdeb863afbeb9df6a009694c055c34d68e19c19ef3fa852363493cdf197c201958449e57e327b16eb5e25d2d347374a85e4685b432a15f5f768fa0b180f6db9f0af65cbbcb0c138a2e12cbb0aadf81e78244e2b8855634b9d0014005d9c9209381943f019df54779b4452a47ce0f223ae52a4d28d725d97e40b37b250499508838bc8a7ccb133f7a02fbfc91fa1c27685786808ae4a45e18cf841c79f3a61b58ae87005dd4e43930089fc2bc23b8c6ac3aaf2081a14edf40a0299f3094410689ec026a8bf8ba2b2c470583987c30d5d8ca6e7ea605d0c7761dba95beef2f4b94f5306317ecfa60010d6b18c2aebb994a4559fad9f3538ef7eaaf35761f7640b807483793ed8ab3ae20672da387979a8171eb1425700e258a912e645a80739e5d494ba6d419dcd50ec13aa806fcfcc84480d7e0e676916aeed6f1cf9d69f7e958dceae1edaa11b2669954b7689e647906cccbdcbc2897f149356d9c85168f08ed8990aefc891158b1b89d7c19d3c56ad2a91d3de46ada48fc6338d13efb16c4cb49acd981a044c345240ce7d1db84fde51058290cae528cc7dc5794daa652268d9e5d0fa639a854ac9fdcd3fd126f653f9b970d804fdd4f520e473a31410fe9a84fc43ae415d008bc86ca0881f737382196cd5b6dd4b8674cb515ef70c4624bea32c22a7b72c2f8e1c2fc693a4905215e10580aef647be4cd36baab91c2867bcec745bc5334ce8cea1a0d77f6bb5f1838c60904f8ba7aec00d2529e87c41702b774c6f11c632d360477988847de39626fd7e83b07ca2de2e7dbd68d07617dc590e00684c79ff1d90f484a31056b53b29cbe470c8bf99515e7ad2939120d3b9b9ebabfb29d0e7b77cc7bb5ab97fc44591ee036de0206b8331c99c75e8bcc50ac1cb75fec3fb640318010d3ddeaaf423d14d2d715e7cf81ee4d01ad0c0f09c66b2e0b396b93c2bc97b21a42cdafe748aa4b59c250e4639be7173f4cff260339d2797e402653a3bef19a0a17763395889c4269679f6bd0289a356eaf0f06b409d24d4c112ff8f60b9383669677635f20d8eeed5c38d9500e39dca878f578b4980f374ee556aa3458b551628ff9f110d11b7f2497195d9bf3c9557e6f3d11c05f52158aab8f6485cdecfa158e592453351f1866faed652e75b37562a4c696867a89ed8b55355c82c6b571918d3995cb6516f00742a7f0974f62ca846d1306422176a204627930693eaf08951f082629d0a5537aea1d8729693798896fb16830a7cc7b29737f29637303d4b2d335a15f1c48ed11d7948cae1b1efcb5af7c398f535e799f58a13109605cc3afae7e08683e40b1d015cfb8de1f5ca44d2eaa0fbfa549b4aa3933de82380b81ddd451d5e44a8f7f456355dfa125c002c8c5e7b2697e33dbd5cc1ac7ac8bbdfcb08ed49999a24a72685a31cdc25e0c9a27be6eb32af2d260f6d60427108a552cbe2a99ad070aec066c78bbf260e49e7ead7646ddd80d2fd067e7361e83e23aa3df8810cb4a44ee4b1205ecc8c548c064345134bb02e081a65ade1d3ec4523448d81153fa692e852e443120c8aba426dbc11bcef30ab6de561000c5be09b10524cedfab2395b99861a6f0c7e9c820dcc97763672331ee7db22c0932f46dfc3591f66851255b173a26f12c813e393a75c279385a4ef1668e0de195f818a9553d2a096f927333e1b445c8f212b665412b3f546fc56600ff4bc71f71f3c8aedc788a14e5e6f61343cc668e4d7e8d5b22314d9727e7e216f01d26d84168b8b8cad052eed93ec12355123dbbe497b1d0f6a92472c5181623dd46fe47e576cc7e804e23f58098d06504f11e23d87debccc25206b7ab2e8a54e197ecb27785fa834700ce9dab85af30a0cb4e385e6469db3e14a8545b97d72b9b4ffec701ab993457758873ec75af28a865542c437cf00bfc8092eebbb13b15cf9b481804696904c6ffae417be85dc3e8889fc8d2bf1cc7386303132333435363738393a3b3c3d3e3f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + ], + "measurement": [ + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255 + ], + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "3b1465280c0256e2bf8fa1dda6c8210c", + "4af1ce9963cd8783355469ad43277e53", + "59ccc3ef2ce2fdfc4422b2f29caa7aec", + "f166690aac38d90228da50a3a2e2355a", + "bcf7746cb91b25006fe29bc5b9dbfd4f", + "291f7357292ff6949783aafc745cf130", + "bc9e92bfc7f862e84f259b7440b04896", + "8b2fbc51032cb90072570bba4b64f80a", + "8d6f96998e4aeca59e1693fabe8aeb91", + "9126702c90f2ce3136faef39b2b783e7" + ], + [ + "c5ec9ad7f3fda91d24705e225937def3", + "b60f31669c32787caeab9652bcd881ac", + "a7343c10d31d02039fdd4d0d63558513", + "0f9a96f553c726fdbb25af5c5d1dcaa5", + "44098b9346e4daff741d643a462402b0", + "d7e18ca8d6d0096b4c7c55038ba30ecf", + "44626d4038079d1794da648bbf4fb769", + "75d143aefcd346ff71a8f445b49b07f5", + "7391696671b5135a45e96c054175146e", + "6fda8fd36f0d31cead0510c64d487c18" + ] + ], + "prep_messages": [ + "4b28ca5fab189f5689d02be161fe25af" + ], + "prep_shares": [ + [ + "f9ab3aa30354eb87abdd838ca558b6cb4cd1280dfc7d2f12bcb14c5a38a5fa1e4225a50845bc43cc7276668331627f53e6d1debec49fc79a6e0a2382b73e01d1af45275c3e553e9f0df2dce1fb8adf9b7cc9862e001ad0d0059d27c68b40e998a4233df802cb98ef8c94504a86e9b0e423e0661acc82059937329f34832d079f0184e04d6aafecf62dee814f748123de797d05203e140ccc9be383de282e7d377e0e3400af264e528f66cc39c14f6b590939d50e82fe5df4fa1e0aa96c27af32a5540a1ab456284c050fdf4fc7190c71acfc9d952d03d4af955b8df3f10fc64b48f1399d22792b7b18e64c7c09d986b27c4874ee16fff4ecde9d89391d3ca98a14f95ce098c05629305bb26e0db0955be0bafa82ff2a6b48283de372c395862a636d4a9bfdd06a15405a71a1d56a5a30afa2bde6fc55d8a3386fe4bd3c08985014376e4adc53e094949d34b36f1e8b16", + "0854c55cfcab147838227c735aa7493459da23320d129aafa331318931d85cdd78b16bc625356621f29ea8e47b665ab5d29caacc5ba36200516852c360c0a2d9cde2eb50a36d1303c487fd8456539db613567966c72ef1b9f8b8f2e93aebdc1c332662a738cb172c781306cffa8b46f908c1bfd01acb45c5c06c9ecb16265a3fd0f94a3d036b82c41b49709fe6c3815e1af0509da314c9297ca795e4487c9cc326d2e0803bbda031317b76cdbcc7b6819dd6910f3002a99c7075366ab035710a9d39781324cef39ddf613e24e4a635108fbc5c1b9dada07dd81a620426914410d34aa0c53bd7d6fb53472d84ca55f554883acb353f6718ee88b8e595fe5b9373bd4cec850ee6ff565296aad4f2cd6b9f2bdf8fd9fae82be3d2039778cad3aa16259fa038f067fb28655b6e18edc9a032053e900a2e3d07f7ca52461922710f91f4ec2449a30929eb714d75d9db74f3a7" + ] + ], + "public_share": "14376e4adc53e094949d34b36f1e8b16f4ec2449a30929eb714d75d9db74f3a7", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json new file mode 100644 index 0000000000..21fcfa001b --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json @@ -0,0 +1,146 @@ +{ + "agg_param": null, + "agg_result": [ + 45328, + 76286, + 26980 + ], + "agg_shares": [ + "447fb76d69adab4dc1990d2289325675e67772e564baab6396c6b45c58a1c5febe9c72ab66aab2aab4b588ff774cb480", + "47e6ff190ecf95c1c1941e2b03db246104c982f459555c7d30035b353f18e8985d9e4661cd30031dc481a1afdc0df13b", + "864b49788883bef060d1d3b273f2842916e90b2641f0f71e0136f06d684652684a2e47f3cb244a386bc8d550aba55a43" + ], + "bits": 16, + "chunk_length": 7, + "length": 3, + "prep": [ + { + "input_shares": [ + "5d82bd1f81516122465f8a60a3209afef5a5c181fdfd80d20d280edb0ae8ccc4953eff5c0efe473d411cf4f3b2e3fd320c83c6b8f2c626a42d25f89594365561966e130ecf8a778e42ce7cca37b919eb9304560ba6a60a5e5b523f5ad397b378edff4b21af66fba2f59db74e46ffdfa077bcea50472d6e771640a71fa31dd96446a2d8ce308904ea0d94760e7f8721d1531754521de6b338a20bdc8eda1d1acb6f3407a9f6f9d6cf9ccc3696c4d3226e89cf3207643a12d8c30332a8d364c97aaee81f4dc31ad62d49506e422e146492bd92a5cc933532fbfc1ee2e8e33116414358edd4baf633cdd80856f8132124171d9a2d989d3a9cf5d1d2b27baf94a5c523cf7ae624b8fe1c8ffc2229bbeecfc18e91c8683df7c579390d8b31ca87372cb5ebbe716d0edc0fe8f10c54835396a68cbacc670eee07dffa3203f8b202dc414ccb317950b35d8f4da3f0bafe8f4b0d09b5103494ed9cf9075bfd19c47f8bdee607eccea1987b4bf6ba603e29043ef636b1b327e57adf1b29b098d4eadfebb737a5ea3558794f02b97f3611034adf002518d85e769210bb2ed2e4b4390433c55d6140ffda97a5018ee007adf5125f079bebdb6eba6c35d0504d8b7a9cbbf0bd9d57bd5b563fdc052a492a7dad4a3c782b69b711ac2969758cffc3d9089a34716517c45fbb164a6bd15a001d454dfd444becef4c4a7fdbc1aaf3b7e0983b900222674a726db2b1b155190cec29c6afefe3841924dd7b212437fb10bffc8a17cea09a97ec2dfafe897e8ad4c5418946525e0908ac8790580a47a17a8089e7b78498f2a54375778e387b0985293431e2103f51600211e6e9a3f388e53d2df072d486d4c4838d8d8601fad2bd86d51ad3a58aebc0d8f6bac048d77968b26826cf545b44f7513667ac696564df8113529415a6e467d3a9f6bda8630717be753a45b5d688bbc4b95712f3bec044eb26db66f23861bf870cfb30347361e81a451f7f17642f6cbd902e92cc063b7cd4cdffbec78cb3f1957d650f89be7798894f6594ae1965964b5968c67003b247c0e83d3cef1ba2feef4c5c59d42a3efa8309f0ec4e9497b1c5a7c6b72f341d4ce5950bd12be5b6b22f32eade71f969f4ee1c0a864741fb2b5b1ad278c5f2f27000e4237b71cc664a87c50a7088b36bab5ad5a5494d599407fda9df6c538ad53563c222d3242b635116f5246b9dd6b7aba1f5abda8fd607ba18a3155c6e6c877ba0965f4005c8f475e5116bd7f899ba48ad299e5007401e49b85abf0ad681cbad302393975d682f6fb5a0795702ada0cf559198efff5ed8a16b12d1e866545db67d13ea5b7e59557776d458f5872d20ab0a3f6c74d61345bb6cd1f2dec5ee4a8d1c96d22a7b3c8ef21c1284d0785a56143100639cbfc12d1a6582b16b4bf804f6503665f275e5de6c60aac82324be975fedb2dd651c1173635fde95660cc844d347d10f8a24586a75597b1c39e828063364e13921665af885b721addc72a72d9a23bb6aa7aa3169804cf944d523d855c97a71d723b464e3976d1264bef3c266ff630ac23753eb79ad90eb5593ce456db34e977dbb19cfb58c52cbaf4826858368c3cbd8863abb5b2b95c36a447b8a4eef73e276d8bc61be6a420a12dd507bc72ef767bf49ddc9a7dcf61290b191ca4c1444e4863f1438e480a661f860c6868256aa7390e1a5033292afdcb6da8c464298c1cf5bc86bac0ad5ee5f72219e33a356a4cc3bdefd606162636465666768696a6b6c6d6e6f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + ], + "measurement": [ + 10000, + 32000, + 9 + ], + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "22c1e77978e4e319838804b62d66c7d1", + "4eecd0a1213e3921caece61ec83597ff", + "27112639228e3b8e913cd8ff27c4e62a" + ], + [ + "18a2aa085a9adc958c310ab9abf3b675", + "0243d6a6c871c929a8ab73bcbfb2a2dd", + "75df6c20efbaab098480e08f49afa5be" + ], + [ + "d8c36d7d2d813f50b845f19026a681b8", + "b24d59b71550fdb45567a5247817c622", + "6e0f6da6eeb61868ce4247708e8c7316" + ] + ], + "prep_messages": [ + "065f5893e9afb58b358f78e7ed2cc07c" + ], + "prep_shares": [ + [ + "fedaa3d68353f75a2db6a1e49b2397a2bed007840b0f6ccc5ff3d89835264b58afa1771f5d2a277b65bbc2190fcac717b4f07c6d7ac4c692ad519e8a33e6d22479dfdaa6e2d3eb787ff4c9cc9deb4638b69a422203daec5a3a9b28f4eaddda1eef0000c41066465d05570989f605ad679d3d6906a8eba159f5af3995de50bdd1068ba7c0556bbd0724ada90ce58efc5b7c24f02cbc919cdb90bd915098f1f7b4bbc85c69e091f780fd70df4abb883070d02d2e06f76874cd4496526ce4aad58adf2b97e7cfed76951b532ebde9a3518e407992b67cbc6f3ccef64065bc5c214973167fea3f7baea5bf44bc32b85e37fb1f12524e4f720b7d10547ea1b558c569220ea8f5008a9be1e061606e347c3c49", + "cb8307fb467bb023448e58c74d159bf4ed77785c059b1bfe3c5b36ab3bb46cc6051853dd2151e2cc480d5164567c8c41df857ef182519ceaf1c704a25e6c948712d4839078fa72b1e64e8531f3e54c090d01fcc6023c8dc28300ceb5fd722c80211848dd2c787bd764b2099de3139df3e7472bf3c98fc31f1d3e09b8deaada8bb19f2941d9f4660018a051ede752680aa6d05e91c0c2feb5199be821f7eba9e3abe594acb8e9611a81294b8ed708fa93caa4f00ab2df5a298a09a7d71924a9ea0b98b57a0d21fda8ff765c0394041a9a2fce409f56e24f387aba5eec7bb507d18f623f5f376d80e762ee64ef3db152a4eaa42964a69f705f15eb77df0cf6f81589a8eaa4f01fe1b5aa656a0919ae5449", + "39a1542e3531588156bb055416c7cd68c32c28a3ac4eed2bb0f0460d41e3634bc0746eb13013792fcc318698a96b1343b152abb747abd3245a70d95eaf31f330e9e844395897d8d5f475d4644149864ca15c31da48dce96e593075a17d4deff6ae67d137adc6f38ec943c596b6fec177e66c119988225c82ac239141c8448add3f9b5c6e59d9736159ede439854b0532d9253f45dd09cb6b800fab1308b1f265978eab94b6bf4105729f7da8eddcee387a2a1eac1c64418e342368a3478fa335500371d0434c5e6511da60302f9947e84a52c49e6dc731f79ca0543441bff7a4cd909fe76206570074fca8dd8cc511ed104a88289bd3cd4d9e34a6c9a50a03649a431dd8df92d78dd6c0d478dd93c0cb" + ] + ], + "public_share": "220ea8f5008a9be1e061606e347c3c4989a8eaa4f01fe1b5aa656a0919ae54499a431dd8df92d78dd6c0d478dd93c0cb", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + }, + { + "input_shares": [ + "5d82bd1f81516122465f8a60a3209afef6a5c181fdfd80d20d280edb0ae8ccc4963eff5c0efe473d411cf4f3b2e3fd320d83c6b8f2c626a42d25f89594365561956e130ecf8a778e42ce7cca37b919eb9304560ba6a60a5e5b523f5ad397b378edff4b21af66fba2f59db74e46ffdfa078bcea50472d6e771640a71fa31dd96446a2d8ce308904ea0d94760e7f8721d1531754521de6b338a20bdc8eda1d1acb6e3407a9f6f9d6cf9ccc3696c4d3226e8acf3207643a12d8c30332a8d364c97aaee81f4dc31ad62d49506e422e146492bc92a5cc933532fbfc1ee2e8e33116414458edd4baf633cdd80856f8132124171d9a2d989d3a9cf5d1d2b27baf94a5c524cf7ae624b8fe1c8ffc2229bbeecfc18f91c8683df7c579390d8b31ca87372cb6ebbe716d0edc0fe8f10c54835396a68dbacc670eee07dffa3203f8b202dc414dcb317950b35d8f4da3f0bafe8f4b0d09b5103494ed9cf9075bfd19c47f8bdee607eccea1987b4bf6ba603e29043ef637b1b327e57adf1b29b098d4eadfebb736a5ea3558794f02b97f3611034adf002518d85e769210bb2ed2e4b4390433c55d6140ffda97a5018ee007adf5125f079bebdb6eba6c35d0504d8b7a9cbbf0bd9c57bd5b563fdc052a492a7dad4a3c782a69b711ac2969758cffc3d9089a34716517c45fbb164a6bd15a001d454dfd444becef4c4a7fdbc1aaf3b7e0983b900222674a726db2b1b155190cec29c6afefe3841924dd7b212437fb10bffc8a17cea19a97ec2dfafe897e8ad4c5418946525d0908ac8790580a47a17a8089e7b78499f2a54375778e387b0985293431e2104051600211e6e9a3f388e53d2df072d487d4c4838d8d8601fad2bd86d51ad3a58bebc0d8f6bac048d77968b26826cf545c44f7513667ac696564df8113529415a7e467d3a9f6bda8630717be753a45b5d688bbc4b95712f3bec044eb26db66f23961bf870cfb30347361e81a451f7f17642f6cbd902e92cc063b7cd4cdffbec78cb3f1957d650f89be7798894f6594ae1965964b5968c67003b247c0e83d3cef1ba2feef4c5c59d42a3efa8309f0ec4e9497b1c5a7c6b72f341d4ce5950bd12be5b6b22f32eade71f969f4ee1c0a864741fb2b5b1ad278c5f2f27000e4237b71cc664a87c50a7088b36bab5ad5a5494d599407fda9df6c538ad53563c222d3242b635116f5246b9dd6b7aba1f5abda8fd607ba18a3155c6e6c877ba0965f4005c8f475e5116bd7f899ba48ad299e5007401e49b85abf0ad681cbad302393975d682f6fb5a0795702ada0cf559198efff5ed8a16b12d1e866545db67d13ea5b7e59557776d458f5872d20ab0a3f6c74d61345bb6cd1f2dec5ee4a8d1c96d22a7b3c8ef21c1284d0785a56143100639cbfaddd5e94884c05ad97bdc1b9878082a47662898f549754812b390a2bb02ba487c6791eb083959499d8c22ec4b79caf467542aa89e22d69fa2bea599ce1923cb05efda49baa01b0405db15d8cbfe774cf38d520cde78b817177df5ddfdd1b7c5b164c1955aadd97a8ee58a53940041a8feb79ad90eb5593ce456db34e977dbb19e3054823c514afc4e5ca9c5a7abdf60b2ad80e66199c131e1dad4436e5289a51acb7aff16412afc36a49d37a813224bbadcfa7c6ab7e817fab68ed0be42d24ca34df61c2d8a38df8d0fe92416f131481fcc5f12eee6f2e3fa7b8035d631770c4faa15307c8f847e907b1b0ce96f9fbc1606162636465666768696a6b6c6d6e6f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + ], + "measurement": [ + 19342, + 19615, + 3061 + ], + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "a0e5e77978e4e319838804b62d66c7d1", + "edbbd0a1213e3921caece61ec83597ff", + "131d2639228e3b8e913cd8ff27c4e62a" + ], + [ + "18a2aa085a9adc958c310ab9abf3b675", + "0243d6a6c871c929a8ab73bcbfb2a2dd", + "75df6c20efbaab098480e08f49afa5be" + ], + [ + "d8c36d7d2d813f50b845f19026a681b8", + "b24d59b71550fdb45567a5247817c622", + "6e0f6da6eeb61868ce4247708e8c7316" + ] + ], + "prep_messages": [ + "25034fec369564c831e89105a21ed2c7" + ], + "prep_shares": [ + [ + "fedaa3d68353f75a2db6a1e49b2397a29e8bb52fe68533a6e7518d7c431765b09d9fb09303205bd20b7bad45f8ee66e18d4ff77adffd7c0b1990ba9c1c18c0d83c70aab9194ab6e494736b7521bff256e44fb48a11052214545c4fc23b0424f8965526d4d9d8d65bb919f8e823db52d0cd97bbb67e45ed5ae83205b3c379c8b72f4220e4407e1f46c60ea678ed8d47742d82abe8cc8b00055cbeb2bf9c5cf03ee851b53b57812560f8c16902a3ca3e54d95174e928fcb415d903ba75e20b5c824ad2d32f70d2375df7fd78e3a9da48d881c81e5a3126d013776adc18fa8ffbfa1ad84cc857cabdf17c81c8f08d04e9dcf11e92808e461939e811b768e5fd98c3186d21176ab71c0fd31e38c5ce590cae", + "cb8307fb467bb023448e58c74d159bf447187a131bca6a8f66f613129c42c481051853dd2151e2cc480d5164567c8c4164b4ac35f70fe6b64517e65804ca767a12d4839078fa72b1e64e8531f3e54c09efe5a1f7aca60dd9e174711c82596e04211848dd2c787bd764b2099de3139df35aacfef634fc7a8fd7d4cb8f68a8c4eab19f2941d9f4660018a051ede752680abcbc6d60afb6984df051b2a1940016a2abe594acb8e9611a81294b8ed708fa932e03ad037523630eff76925e1a8076900b98b57a0d21fda8ff765c0394041a9ac56ec6717034855e757728c6617c78e28f623f5f376d80e762ee64ef3db152a4eaa42964a69f705f15eb77df0cf6f81589a8eaa4f01fe1b5aa656a0919ae5449", + "39a1542e3531588156bb055416c7cd6884463d0b107893ff1174455e3c438265c0746eb13013792fcc318698a96b1343f33bbecee2d08efabd7facd829d80dafe9e844395897d8d5f475d4644149864c3faef9fbd6b690a3750c76e3721c6667ae67d137adc6f38ec943c596b6fec17750073dadaecc860ca8ce32846d68208c3f9b5c6e59d9736159ede439854b05328ab3d8b398c8d0d7401a8718d9aad830978eab94b6bf4105729f7da8eddcee386ddf59f7d19da2437c7656a1f3d873c2500371d0434c5e6511da60302f9947e8c857cee7aa680bb0dd711dfda75fe0a0cd909fe76206570074fca8dd8cc511ed104a88289bd3cd4d9e34a6c9a50a03649a431dd8df92d78dd6c0d478dd93c0cb" + ] + ], + "public_share": "186d21176ab71c0fd31e38c5ce590cae89a8eaa4f01fe1b5aa656a0919ae54499a431dd8df92d78dd6c0d478dd93c0cb", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + }, + { + "input_shares": [ + "5d82bd1f81516122465f8a60a3209afef6a5c181fdfd80d20d280edb0ae8ccc4953eff5c0efe473d411cf4f3b2e3fd320c83c6b8f2c626a42d25f89594365561966e130ecf8a778e42ce7cca37b919eb9404560ba6a60a5e5b523f5ad397b378eeff4b21af66fba2f59db74e46ffdfa077bcea50472d6e771640a71fa31dd96445a2d8ce308904ea0d94760e7f8721d1531754521de6b338a20bdc8eda1d1acb6f3407a9f6f9d6cf9ccc3696c4d3226e8acf3207643a12d8c30332a8d364c97aafe81f4dc31ad62d49506e422e146492bd92a5cc933532fbfc1ee2e8e33116414358edd4baf633cdd80856f8132124171d9a2d989d3a9cf5d1d2b27baf94a5c524cf7ae624b8fe1c8ffc2229bbeecfc18f91c8683df7c579390d8b31ca87372cb6ebbe716d0edc0fe8f10c54835396a68dbacc670eee07dffa3203f8b202dc414dcb317950b35d8f4da3f0bafe8f4b0d09b5103494ed9cf9075bfd19c47f8bdee707eccea1987b4bf6ba603e29043ef636b1b327e57adf1b29b098d4eadfebb736a5ea3558794f02b97f3611034adf002518d85e769210bb2ed2e4b4390433c55c6140ffda97a5018ee007adf5125f079aebdb6eba6c35d0504d8b7a9cbbf0bd9c57bd5b563fdc052a492a7dad4a3c782b69b711ac2969758cffc3d9089a34716517c45fbb164a6bd15a001d454dfd444becef4c4a7fdbc1aaf3b7e0983b900221674a726db2b1b155190cec29c6afefe4841924dd7b212437fb10bffc8a17cea19a97ec2dfafe897e8ad4c5418946525d0908ac8790580a47a17a8089e7b78498f2a54375778e387b0985293431e2104051600211e6e9a3f388e53d2df072d487d4c4838d8d8601fad2bd86d51ad3a58aebc0d8f6bac048d77968b26826cf545c44f7513667ac696564df8113529415a6e467d3a9f6bda8630717be753a45b5d788bbc4b95712f3bec044eb26db66f23961bf870cfb30347361e81a451f7f17652f6cbd902e92cc063b7cd4cdffbec78cb3f1957d650f89be7798894f6594ae1a65964b5968c67003b247c0e83d3cef1ba2feef4c5c59d42a3efa8309f0ec4e9497b1c5a7c6b72f341d4ce5950bd12be5b6b22f32eade71f969f4ee1c0a864741fb2b5b1ad278c5f2f27000e4237b71cc664a87c50a7088b36bab5ad5a5494d599407fda9df6c538ad53563c222d3242b635116f5246b9dd6b7aba1f5abda8fd607ba18a3155c6e6c877ba0965f4005c8f475e5116bd7f899ba48ad299e5007401e49b85abf0ad681cbad302393975d682f6fb5a0795702ada0cf559198efff5ed8a16b12d1e866545db67d13ea5b7e59557776d458f5872d20ab0a3f6c74d61345bb6cd1f2dec5ee4a8d1c96d22a7b3c8ef21c1284d0785a56143100639cbfc3289478e516bd187dc85011217df3d9cc14a8f70c84bbd98d3a48ee1708913c3bd3c479700f0d9a01bc20a88c2c74202d08300dd1b74ec473f59b9f837fa6643b9a7627923e328512a0d1eaaef78c6fdb44f2789df4d6fea8cd33877405fbb744d075db8e2ea1c6363e0cb892ee5f90eb79ad90eb5593ce456db34e977dbb19ceba123f684af758e4bf0d03e1c085d6d425f0fd60afacc5baab06737d4cad9c375e0928789836c34150e196aca25fe1f4092243bdf49bb57f5dab084241ba1557429036f1660bb41b101fe37f03fce0595620833807d9b175ca2db5cc2df167cc1df780e3a73ecbbfcb4950440fb6c0606162636465666768696a6b6c6d6e6f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + ], + "measurement": [ + 15986, + 24671, + 23910 + ], + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "84d8e77978e4e319838804b62d66c7d1", + "adcfd0a1213e3921caece61ec83597ff", + "846e2639228e3b8e913cd8ff27c4e62a" + ], + [ + "18a2aa085a9adc958c310ab9abf3b675", + "0243d6a6c871c929a8ab73bcbfb2a2dd", + "75df6c20efbaab098480e08f49afa5be" + ], + [ + "d8c36d7d2d813f50b845f19026a681b8", + "b24d59b71550fdb45567a5247817c622", + "6e0f6da6eeb61868ce4247708e8c7316" + ] + ], + "prep_messages": [ + "164bb9a531ed86890f679cfee8e40bd7" + ], + "prep_shares": [ + [ + "fedaa3d68353f75a2db6a1e49b2397a2d951596ce321ca830642b1c9a71f119b750393c6c754d535696c304ff488bcc6977ced640b7644d68067fa674f608e0a5751aaca2e39d7e4f47bec846689f311124c532053e2285de1dd28c7430d205d7bef7f1ff5f36d363f8ca7cf16b9d28d7fe79342273ee2629adb1396910910d4f1243c6e17898c5de5b4e50915995e0ec6b2c92fd59cf001c32018e569d540e26a5512100c73b1dfb9e76c4865fb4c8a98d2382c1bd1bbef9cb6f8fee190a7b2c18bb9c694e107ede1966ba61589e8a1ee07c034878188043745d1a13e9d328c35ab0af3a25ad52a2941d5c87ef54e798f310d45c2a44eb9b8b484c4cf2cb11289979db009d84867e096271383f95f17", + "cb8307fb467bb023448e58c74d159bf49f9b010f8d3342eccac47f456395810c051853dd2151e2cc480d5164567c8c41b406b0bc3e39acaada3e1565084d70c512d4839078fa72b1e64e8531f3e54c09965aa5eacbdfd1c87023b5c2c1751952211848dd2c787bd764b2099de3139df3696d74860c683106e0ba03981fd175ceb19f2941d9f4660018a051ede752680a2e4d31fc97379acf03c3454eb29d0433abe594acb8e9611a81294b8ed708fa932cd4dc5aeb67e4082571e2c1a9e2e9370b98b57a0d21fda8ff765c0394041a9abc294b2171b29cdda805a50345b159548f623f5f376d80e762ee64ef3db152a4eaa42964a69f705f15eb77df0cf6f81589a8eaa4f01fe1b5aa656a0919ae5449", + "39a1542e3531588156bb055416c7cd68bc76b21ba7b0f0ee6be53024718f5ae0c0746eb13013792fcc318698a96b13435bf89e78f7ee3fd7e39a1fdab2ea808be9e844395897d8d5f475d4644149864c3768148cc4a96a193de9ea7fad3ee418ae67d137adc6f38ec943c596b6fec177dc960939e2aa0560144c058bc34cabcb3f9b5c6e59d9736159ede439854b053235b3543dd1ff08e9184d44c28b2e98c8978eab94b6bf4105729f7da8eddcee388df030cba4cd2df0eccbf799ad07d72e500371d0434c5e6511da60302f9947e8a9a78a25434f4d85ce460e1dc1446ea7cd909fe76206570074fca8dd8cc511ed104a88289bd3cd4d9e34a6c9a50a03649a431dd8df92d78dd6c0d478dd93c0cb" + ] + ], + "public_share": "89979db009d84867e096271383f95f1789a8eaa4f01fe1b5aa656a0919ae54499a431dd8df92d78dd6c0d478dd93c0cb", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + } + ], + "shares": 3, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json new file mode 100644 index 0000000000..040e3f1741 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json @@ -0,0 +1,40 @@ +{ + "agg_param": null, + "agg_result": 100, + "agg_shares": [ + "f3d18d266d89cb425fd64a19a436e8bc", + "722e72d9927634bd8429b5e65bc91743" + ], + "bits": 8, + "prep": [ + { + "input_shares": [ + "6dc25550077a71c59f7020e3d0e7ac8da5809fa59c2a1c7da50f49f348a2dd8f46ac57b16cf3a153fb3aa17f19b651354b6e5e2666029f55a6e0d76f25269781bb4f7cf5e79ddd703d07a49094e878e48a68b2a4b901bceeb954375740d2385821e421c0d14a2246d80a4ef53b99eb6dac3738491e6a337c124d1bbdc0e1c752ee2e3b77c8f83cf734b152c7c93caab48127d1fcae79f5dc47d4e8f62463408f5c82435087d2a244e8b54a508f8474307003ff6d76327921cfc1b68e893f1eb8cbaf513ed61bbae3d3580c34c2dfae2ceb8a1120842f5db85c78c2f4225452a6f2b618972d56f013db62e73b92a8ec83107719d35a27f5cdc493d73a772c9f5c7bc67f4280e90dc1eadbe043546a8b5975976a00739136f5f4ab37b8d845f32db1c97a831b3a9d2d3bbec621146d5a5f8788d7e7a1958b2a9382c1d9f538b91d9582bab31f496c9ddc517ae206533a8b18e0b3854587379a3120970b0246aa13758de413cee5f99794170de0bbd7479bdf968c1db98d53b30bea4417d54c9cdcc5f5e71bd7367ad95aacfb02693f25bca1a5fd67cfb3ef6406607ecef3bbe052cab782eacce5d25f6589325d20a1d6f2d9beb14c3c89cb18d0042a5376907c057203feffcd8a36b24ecabc6fe4e0133ec68a1313b669c1771b91ffb86c284646ea5ad270c492b5d5d7a24b27655c2a715af2e797823fa97f87df42184add6f1cc26e9762159d43e9548a6a89da738a8a36159369e3aa7d3b2c25c8cf95b788bfd6293b9e66a42d3bde7b00a5822eb4f97347c91f9882d54a6279c22501ce4f3fa5ebca8fcbfd7baff84e687cb8d77b48e8b4026560d873e2b8c0529d02f3d4f1e5764e498cc9d22a5d64b50fb38edc42491e5f1571244bc6269a7fbbe64406b4303132333435363738393a3b3c3d3e3f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + ], + "measurement": 100, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "f3d18d266d89cb425fd64a19a436e8bc" + ], + [ + "722e72d9927634bd8429b5e65bc91743" + ] + ], + "prep_messages": [ + "aac7d7306c0cdbbd7e23ef394322d54a" + ], + "prep_shares": [ + [ + "5e6f31522c0cb9b5107ad0c560b6ef9a69553124df856a84affd0a814674ea325a2f1c7fc62f1838a8d7aa8d4263ac0d86243c1f5c53992219ddfef99b94f76d", + "a390ceadd3f3464ad3852f3a9f49106571003e04a8d922570934a5812d4a8c45c1cf374cea16117767d4f4ee963acd756d42402e0f2b584af325b34eaa1615ad" + ] + ], + "public_share": "86243c1f5c53992219ddfef99b94f76d6d42402e0f2b584af325b34eaa1615ad", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + } + ], + "shares": 2, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json new file mode 100644 index 0000000000..8baf391f08 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json @@ -0,0 +1,46 @@ +{ + "agg_param": null, + "agg_result": 100, + "agg_shares": [ + "f91bcafa315d7cfa26564999203babdc", + "722e72d9927634bd8429b5e65bc91743", + "fbb5c32b3b2c4f481c80018083fb3ce0" + ], + "bits": 8, + "prep": [ + { + "input_shares": [ + "a48f16f9472cb825154a980720bd436b62db8329758026ed40deaa18e9bccea80cc0d2e40164379e7498b61a280fa86e7080b53acd1baf84604c5270ba2e161b069c2f1187bbead120b10d073d3326c5da5edeca2a2e0322253face85a769c92155d2859b86caac4f2b25d8779b2a99de3af195b2be8a4e5923d2a566833f86a683fdd68189962ea14ca940bcae99c612ca93caf3ec9bfa9ca2bdc0adeb80dba90992e4ea878bd39e321fe43f0cc073d9b5a8f9ff7f38b333e907e510a04499dc78059a620bc2d7201e3c7a4545cb5066add82690fd25269e66e1cf4334211b5578dc556c377753a501da19da81e839e6f3b7f56724ad9ee5e6dbc0a1cdcd3fc36601586eca9a50a620ed1c8941379369ae3a72b13c11c76cbd1f69d5d5acca56da4d8567007cbba3da384aa2d73e1bfba7ff77864c3b508d5a5b69b69a0bc6c092fc84d564e8f9726686e13f32239912a8a0bd92a8849d81f30560618db3bbd7f8b14a68e8a4bb2f61db7fa471573a4bee095db799ff19407b22fd77ecd55206e85f36dabec6323d8aaea77e328a07e3ccbcb3c893f6522fd0aa39f09b79dd9167cb9bccc326e2aaf51cc0e187c46766ccbe75321deb403d470795926b6879f0398a996aa5330734a5f3fed8b0e69e3a2c8a4efcd739fbedda27ae086f7144e655cdc89b07183818b56ce01dddf691d2a57f846c77d8601b203a2caf8a9bb3ec4f340d68702bf320df74e304d2db24de0dd26a6346ccc9a65c6c24e45a31636efb0919a87c8b14c08226807807acb467c29481b03e541c3ad3b2512b89c794687f4dae6b4c5f7fef5b5c348e61cca26629f015fc7babc7e0261b477843df830057f7c69248b4493b2e7a9f5503ba3eee569fc9911b35d0dd6111e8985a42273606162636465666768696a6b6c6d6e6f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + ], + "measurement": 100, + "nonce": "000102030405060708090a0b0c0d0e0f", + "out_shares": [ + [ + "f91bcafa315d7cfa26564999203babdc" + ], + [ + "722e72d9927634bd8429b5e65bc91743" + ], + [ + "fbb5c32b3b2c4f481c80018083fb3ce0" + ] + ], + "prep_messages": [ + "215cd3acf2c12d42b2897cb57fb420a6" + ], + "prep_shares": [ + [ + "8a17e1ae7baf0fcb35b9d89394f8f34e5e965d98db9ffbe0867029fbbdfd7195d7fda8b597d471f0046bd4508be2e2abbf23e0b165f191b5165f0350ae251442", + "6c98be496224df8772c21173ad6fa2b271003e04a8d922570934a5812d4a8c45c1cf374cea16117767d4f4ee963acd756d42402e0f2b584af325b34eaa1615ad", + "0c506007222c11ad1f8415f9bd9769fe526f9e6835c5e2ce8c44b01f27cc5060c4c159a86eb48e1571437659eb32b3e8800a1a73b5ae07e45e4cc67555122b2d" + ] + ], + "public_share": "bf23e0b165f191b5165f0350ae2514426d42402e0f2b584af325b34eaa1615ad800a1a73b5ae07e45e4cc67555122b2d", + "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + } + ], + "shares": 3, + "verify_key": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json b/third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json new file mode 100644 index 0000000000..6a34d6e32e --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json @@ -0,0 +1,8 @@ +{ + "binder": "62696e64657220737472696e67", + "derived_seed": "3805276060157b7376b069305303669b", + "dst": "646f6d61696e2073657061726174696f6e20746167", + "expanded_vec_field128": "3805276060157b7376b069305303669b92beaaa4afa982314428494ba98f3595d49e76d1301b451d6fd79c9acbe9118717cfd0d4b9ef29806b4dce298a2d6aba17d7025e7964a2d7e24a263bd79d19edb11cd1db4bc07ce0ae1a9c6d1f59233e8d7065a66ce1b123ed773e4b370c9217c7032fc805f3a13f6fe2ef6f7961bf9d20fd22b8cd544cefe8e634d9245db7813ba43f630a123dfda73b6bbad8b11a916090a7d5ba8a4d20853f3f5c8222684050a53119e829313fa8de64f92553a44aa522fc90d9ec75f80547ec9637ce60e74afd51baa1d80b549444c5f0a6283ff494698ea6ffaea65964c4e0c2f9cf72a11310000261ddc85661f5068f505d34273295be9b8549b4c6278a80794929093a17cc017cf0b0e68e32e941708cfa58b9e598ac3d5d2ab4e9b33111c9c9fbc0a3682617d0ed1a0d15c9bfb9d5fd2889d1f56dd3a7f2e61ca59b0705d35f915349ffea0341816532bbdaa6dddba42bf27d1699d9e9ef580f3686ea42d687e54a87c3e6dab4f1ee5e1185faa6b809eb1a1e940692b3ba882684e8440b73e23088411000cf77ba69777b3bfa417050f0cef6cd0c9b6e7a47ab5c3da9a0e3de6ec323aed32f4cc3f51ac719e34f0bd9b0cc617e3034581a708f4a3bba587b4b4cb91529cfd47393893c3b5cd430d0456a245b0c45d4398fe423b67faa8682c764d92c514d7e34a89abc16353e71de7d49895527e632a6163d7362549a8e9ab12277460d30d7892e0a5993a4d3922738f07892764b0ceabf280779894ced52aa7fba94100c2ec0fa1973d2b11044e6844ddcdbd59f26e1b321d02c9189414cace4abece30878ca21d198f2e61b84e7cbebb6a0ad83e2abd5bf69d7f8eed193a8e141088a4b7d41fe23a939f678ba94a1d9c9c2", + "length": 40, + "seed": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json b/third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json new file mode 100644 index 0000000000..1e48d1f648 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json @@ -0,0 +1,8 @@ +{ + "binder": "62696e64657220737472696e67", + "derived_seed": "8bac064e720bb1c413040a3f41990075", + "dst": "646f6d61696e2073657061726174696f6e20746167", + "expanded_vec_field128": "8bac064e720bb1c413040a3f419900750ce08494b0f4f2d95171dcf44255ef94606fd5e6ffe3735329f5550e34fe61f0d4704239c107e4beb6623e20cb2e2659662aef8409fcc162a01d2333fc8d8ee7bc31c394c88edeb5904d25bf851d30246d9bf4221a5aec6ff4cb2580dde88dfa726e21b35da18f5b1839a257482ab292615b094b092444013874fce11cbd293fc81fd9a00d1befca7b1aefa2324ad2c84a8d678b02973bd539021e18861647474211e99ccfff5e47483985b25257f83665f44ed3fbce4f5a2b20e5c54239653141f7d5132b255936d33327789e13b145362059f67bd8d5b240dfd1e525d6ac5c0bb6a5b4a0b7b7318a5e22fc91763d2eb9dbd5fd3a3665127ffa63ac5be71a0b67a5ce5ee158d902a4e3a4c580e734ee40682e471373b958853eddee1de30dda6e6f4a3e3a297a79bd7f332ce89b8f0cd50589f03b95408405df362a41f58688e1fb818deaccf36eedbabc1762215102de02125dc79450d47dc04ba88cd507bdf1690ae6c1dbb44352c29687e3f60e0d3d9ed8758aa1495f4976477bda7e3cdbf37078f615dfde8330df46aebe393a665fa3f9b906498ef59ac5a0da50ebeb91c80ac0d8ba3d9bcb4e23f37e416dbe679d633834b8351085a321314d8b0276b24de1dc41091f9bdf765f2879ef0d624927a649bb693386b5a22af2ec5b67b8298abadf1e4ffa10a794ebb9924761d08ad75b595ef11118b33a8f5e649e0b8351600be077a164c806a7ee2aba58de06177ccd18e8822d35c2d6843378f254d64e5a1ee52d9c5b3f63ae262c3d6d5b63baf4e2faf436d51d6318ac9d05cf4fe3e203b2b047bdb1b4f4f8d5645a5d59ab506afc423f3a0ae5691e7f755dc5bff3b6b4f08c61614b62f63b03ce30d35a2c0d", + "length": 40, + "seed": "000102030405060708090a0b0c0d0e0f" +} diff --git a/third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json b/third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json new file mode 100644 index 0000000000..510cc539e1 --- /dev/null +++ b/third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json @@ -0,0 +1,8 @@ +{ + "binder": "62696e64657220737472696e67", + "derived_seed": "e826c9564c620fb63357fbee88dc9bb3de2c41764adb44bea344024e1da124c6", + "dst": "646f6d61696e2073657061726174696f6e20746167", + "expanded_vec_field128": "e826c9564c620fb63357fbee88dc9bb3de2c41764adb44bea344024e1da124c6172f208e79762fed92c73cea422b312860008ee80e30f31d2d87840890604f39db37983f5c3483407333cecdb1b9ea550c26bc4f2d999fda91963054c6cb35a8ad8d28ee74a48e28aa475d67124e7c4417149955e506690d62e17f0730b7d4db8a9754f80603b7720205819d26bcfe4a4663d05c98c12705ea7dc333d5746d9c8ba697bb3d5be95d26ccb73052cb8fb19edfc35eaebaa22779436d3015512c9b536003d98b04a0f46feddbff762007c377c28a04039f72657650885bd40ed37acea63facd3c33d1ecb5048641053af5b4018b0c373d9ed7440da9fc6c76666c2eb8ed2943a64bbf6dae93ac91fcc26d7225c2ae42349161522fcce0b92d209411af8566b0adbaa36a8479737017efd2c359ea43924cdf432650dcd742e358af55ff6c321d0ebaae2abf5812d58b060cc147395e8137f99db58d2c425f2704da067df3a41c0443918375c177fa53545d8190d828c6045bbe5930e4762588ea14dc0a9db6cd903216ccae968ca0b11f0ac04e4dfc69a99986841dc99c851e314c7d4b10f4ef72e1244b543465fed076a7e9f50baca4ad7dccc73bfc55310f2ae6eaeaf7ee7a4d41fec76bff3b04e67d1f83e4da59f1fcb45877adfc3e4a2b1d5e3f136131ca2a02f34bdba1c5d2dafb2178674dc002d247662497b7f5818880cff308e5222e6df0bcdf6f68ebfaa8d0551530fa00ec29646441961e33b50872ada911591e16e3021baa5e7869756d3d812a63e3c7fa2c0ec2dc4cabe11c0256829b360ad9431536ab96efbe5a364cd1c323de8fbe405a2c87b9c58e5740bfb118af0ca1a23afb4a04e9cec3b9d1e57834cbc0fa17d5d7285f1f013df05e92a7343", + "length": 40, + "seed": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +} diff --git a/third_party/rust/prio/src/vdaf/xof.rs b/third_party/rust/prio/src/vdaf/xof.rs index b38d176467..67881419df 100644 --- a/third_party/rust/prio/src/vdaf/xof.rs +++ b/third_party/rust/prio/src/vdaf/xof.rs @@ -1,8 +1,14 @@ // SPDX-License-Identifier: MPL-2.0 -//! Implementations of XOFs specified in [[draft-irtf-cfrg-vdaf-07]]. +//! Implementations of XOFs specified in [[draft-irtf-cfrg-vdaf-08]]. //! -//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ + +/// Value of the domain separation byte "D" used by XofTurboShake128 when invoking TurboSHAKE128. +const XOF_TURBO_SHAKE_128_DOMAIN_SEPARATION: u8 = 1; +/// Value of the domain separation byte "D" used by XofFixedKeyAes128 when invoking TurboSHAKE128. +#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] +const XOF_FIXED_KEY_AES_128_DOMAIN_SEPARATION: u8 = 2; use crate::{ field::FieldElement, @@ -21,13 +27,17 @@ use aes::{ }; #[cfg(feature = "crypto-dependencies")] use ctr::Ctr64BE; +#[cfg(feature = "crypto-dependencies")] +use hmac::{Hmac, Mac}; use rand_core::{ impls::{next_u32_via_fill, next_u64_via_fill}, RngCore, SeedableRng, }; +#[cfg(feature = "crypto-dependencies")] +use sha2::Sha256; use sha3::{ digest::{ExtendableOutput, Update, XofReader}, - Shake128, Shake128Core, Shake128Reader, + TurboShake128, TurboShake128Core, TurboShake128Reader, }; #[cfg(feature = "crypto-dependencies")] use std::fmt::Formatter; @@ -76,8 +86,9 @@ impl ConstantTimeEq for Seed { } impl Encode for Seed { - fn encode(&self, bytes: &mut Vec) { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { bytes.extend_from_slice(&self.0[..]); + Ok(()) } fn encoded_len(&self) -> Option { @@ -105,9 +116,9 @@ impl IntoFieldVec for S { } } -/// An extendable output function (XOF) with the interface specified in [[draft-irtf-cfrg-vdaf-07]]. +/// An extendable output function (XOF) with the interface specified in [[draft-irtf-cfrg-vdaf-08]]. /// -/// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +/// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ pub trait Xof: Clone + Debug { /// The type of stream produced by this XOF. type SeedStream: RngCore + Sized; @@ -145,7 +156,9 @@ pub struct SeedStreamAes128(Ctr64BE); #[cfg(feature = "crypto-dependencies")] impl SeedStreamAes128 { - pub(crate) fn new(key: &[u8], iv: &[u8]) -> Self { + /// Construct an instance of the seed stream with the given AES key `key` and initialization + /// vector `iv`. + pub fn new(key: &[u8], iv: &[u8]) -> Self { SeedStreamAes128( as KeyIvInit>::new(key.into(), iv.into())) } @@ -187,17 +200,19 @@ impl Debug for SeedStreamAes128 { } } -/// The XOF based on SHA-3 as specified in [[draft-irtf-cfrg-vdaf-07]]. +/// The XOF based on TurboSHAKE128 as specified in [[draft-irtf-cfrg-vdaf-08]]. /// -/// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +/// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ #[derive(Clone, Debug)] -pub struct XofShake128(Shake128); +pub struct XofTurboShake128(TurboShake128); -impl Xof<16> for XofShake128 { - type SeedStream = SeedStreamSha3; +impl Xof<16> for XofTurboShake128 { + type SeedStream = SeedStreamTurboShake128; fn init(seed_bytes: &[u8; 16], dst: &[u8]) -> Self { - let mut xof = Self(Shake128::from_core(Shake128Core::default())); + let mut xof = Self(TurboShake128::from_core(TurboShake128Core::new( + XOF_TURBO_SHAKE_128_DOMAIN_SEPARATION, + ))); Update::update( &mut xof.0, &[dst.len().try_into().expect("dst must be at most 255 bytes")], @@ -211,21 +226,21 @@ impl Xof<16> for XofShake128 { Update::update(&mut self.0, data); } - fn into_seed_stream(self) -> SeedStreamSha3 { - SeedStreamSha3::new(self.0.finalize_xof()) + fn into_seed_stream(self) -> SeedStreamTurboShake128 { + SeedStreamTurboShake128::new(self.0.finalize_xof()) } } -/// The seed stream produced by SHAKE128. -pub struct SeedStreamSha3(Shake128Reader); +/// The seed stream produced by TurboSHAKE128. +pub struct SeedStreamTurboShake128(TurboShake128Reader); -impl SeedStreamSha3 { - pub(crate) fn new(reader: Shake128Reader) -> Self { +impl SeedStreamTurboShake128 { + pub(crate) fn new(reader: TurboShake128Reader) -> Self { Self(reader) } } -impl RngCore for SeedStreamSha3 { +impl RngCore for SeedStreamTurboShake128 { fn fill_bytes(&mut self, dest: &mut [u8]) { XofReader::read(&mut self.0, dest); } @@ -244,13 +259,13 @@ impl RngCore for SeedStreamSha3 { } } -/// A `rand`-compatible interface to construct XofShake128 seed streams, with the domain separation tag -/// and binder string both fixed as the empty string. -impl SeedableRng for SeedStreamSha3 { +/// A `rand`-compatible interface to construct XofTurboShake128 seed streams, with the domain +/// separation tag and binder string both fixed as the empty string. +impl SeedableRng for SeedStreamTurboShake128 { type Seed = [u8; 16]; fn from_seed(seed: Self::Seed) -> Self { - XofShake128::init(&seed, b"").into_seed_stream() + XofTurboShake128::init(&seed, b"").into_seed_stream() } } @@ -269,7 +284,9 @@ pub struct XofFixedKeyAes128Key { impl XofFixedKeyAes128Key { /// Derive the fixed key from the domain separation tag and binder string. pub fn new(dst: &[u8], binder: &[u8]) -> Self { - let mut fixed_key_deriver = Shake128::from_core(Shake128Core::default()); + let mut fixed_key_deriver = TurboShake128::from_core(TurboShake128Core::new( + XOF_FIXED_KEY_AES_128_DOMAIN_SEPARATION, + )); Update::update( &mut fixed_key_deriver, &[dst.len().try_into().expect("dst must be at most 255 bytes")], @@ -293,15 +310,15 @@ impl XofFixedKeyAes128Key { } } -/// XofFixedKeyAes128 as specified in [[draft-irtf-cfrg-vdaf-07]]. This XOF is NOT RECOMMENDED for +/// XofFixedKeyAes128 as specified in [[draft-irtf-cfrg-vdaf-08]]. This XOF is NOT RECOMMENDED for /// general use; see Section 9 ("Security Considerations") for details. /// -/// This XOF combines SHA-3 and a fixed-key mode of operation for AES-128. The key is "fixed" in -/// the sense that it is derived (using SHAKE128) from the domain separation tag and binder -/// strings, and depending on the application, these strings can be hard-coded. The seed is used to -/// construct each block of input passed to a hash function built from AES-128. +/// This XOF combines TurboSHAKE128 and a fixed-key mode of operation for AES-128. The key is +/// "fixed" in the sense that it is derived (using TurboSHAKE128) from the domain separation tag and +/// binder strings, and depending on the application, these strings can be hard-coded. The seed is +/// used to construct each block of input passed to a hash function built from AES-128. /// -/// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/ +/// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ #[derive(Clone, Debug)] #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] #[cfg_attr( @@ -309,7 +326,7 @@ impl XofFixedKeyAes128Key { doc(cfg(all(feature = "crypto-dependencies", feature = "experimental"))) )] pub struct XofFixedKeyAes128 { - fixed_key_deriver: Shake128, + fixed_key_deriver: TurboShake128, base_block: Block, } @@ -318,7 +335,7 @@ impl Xof<16> for XofFixedKeyAes128 { type SeedStream = SeedStreamFixedKeyAes128; fn init(seed_bytes: &[u8; 16], dst: &[u8]) -> Self { - let mut fixed_key_deriver = Shake128::from_core(Shake128Core::default()); + let mut fixed_key_deriver = TurboShake128::from_core(TurboShake128Core::new(2u8)); Update::update( &mut fixed_key_deriver, &[dst.len().try_into().expect("dst must be at most 255 bytes")], @@ -433,6 +450,37 @@ impl RngCore for SeedStreamFixedKeyAes128 { } } +/// XOF based on HMAC-SHA256 and AES128. This XOF is not part of the VDAF spec. +#[cfg(feature = "crypto-dependencies")] +#[cfg_attr(docsrs, doc(cfg(feature = "crypto-dependencies")))] +#[derive(Clone, Debug)] +pub struct XofHmacSha256Aes128(Hmac); + +#[cfg(feature = "crypto-dependencies")] +impl Xof<32> for XofHmacSha256Aes128 { + type SeedStream = SeedStreamAes128; + + fn init(seed_bytes: &[u8; 32], dst: &[u8]) -> Self { + let mut mac = as Mac>::new_from_slice(seed_bytes).unwrap(); + Mac::update( + &mut mac, + &[dst.len().try_into().expect("dst must be at most 255 bytes")], + ); + Mac::update(&mut mac, dst); + Self(mac) + } + + fn update(&mut self, data: &[u8]) { + Mac::update(&mut self.0, data); + } + + fn into_seed_stream(self) -> SeedStreamAes128 { + let tag = Mac::finalize(self.0).into_bytes(); + let (key, iv) = tag.split_at(16); + SeedStreamAes128::new(key, iv) + } +} + #[cfg(test)] mod tests { use super::*; @@ -480,10 +528,34 @@ mod tests { } #[test] - fn xof_shake128() { + fn xof_turboshake128() { let t: XofTestVector = - serde_json::from_str(include_str!("test_vec/07/XofShake128.json")).unwrap(); - let mut xof = XofShake128::init(&t.seed.try_into().unwrap(), &t.dst); + serde_json::from_str(include_str!("test_vec/08/XofTurboShake128.json")).unwrap(); + let mut xof = XofTurboShake128::init(&t.seed.try_into().unwrap(), &t.dst); + xof.update(&t.binder); + + assert_eq!( + xof.clone().into_seed(), + Seed(t.derived_seed.try_into().unwrap()) + ); + + let mut bytes = Cursor::new(t.expanded_vec_field128.as_slice()); + let mut want = Vec::with_capacity(t.length); + while (bytes.position() as usize) < t.expanded_vec_field128.len() { + want.push(Field128::decode(&mut bytes).unwrap()) + } + let got: Vec = xof.clone().into_seed_stream().into_field_vec(t.length); + assert_eq!(got, want); + + test_xof::(); + } + + #[test] + fn xof_hmac_sha256_aes128() { + let t: XofTestVector = + serde_json::from_str(include_str!("test_vec/XofHmacSha256Aes128.json")).unwrap(); + + let mut xof = XofHmacSha256Aes128::init(&t.seed.try_into().unwrap(), &t.dst); xof.update(&t.binder); assert_eq!( @@ -499,14 +571,14 @@ mod tests { let got: Vec = xof.clone().into_seed_stream().into_field_vec(t.length); assert_eq!(got, want); - test_xof::(); + test_xof::(); } #[cfg(feature = "experimental")] #[test] fn xof_fixed_key_aes128() { let t: XofTestVector = - serde_json::from_str(include_str!("test_vec/07/XofFixedKeyAes128.json")).unwrap(); + serde_json::from_str(include_str!("test_vec/08/XofFixedKeyAes128.json")).unwrap(); let mut xof = XofFixedKeyAes128::init(&t.seed.try_into().unwrap(), &t.dst); xof.update(&t.binder); diff --git a/third_party/rust/prio/src/vidpf.rs b/third_party/rust/prio/src/vidpf.rs new file mode 100644 index 0000000000..c8ba5db22c --- /dev/null +++ b/third_party/rust/prio/src/vidpf.rs @@ -0,0 +1,827 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! Verifiable Incremental Distributed Point Function (VIDPF). +//! +//! The VIDPF construction is specified in [[draft-mouris-cfrg-mastic]] and builds +//! on techniques from [[MST23]] and [[CP22]] to lift an IDPF to a VIDPF. +//! +//! [CP22]: https://eprint.iacr.org/2021/580 +//! [MST23]: https://eprint.iacr.org/2023/080 +//! [draft-mouris-cfrg-mastic]: https://datatracker.ietf.org/doc/draft-mouris-cfrg-mastic/02/ + +use core::{ + iter::zip, + ops::{Add, AddAssign, BitXor, BitXorAssign, Index, Sub}, +}; + +use bitvec::field::BitField; +use rand_core::RngCore; +use std::io::Cursor; +use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable}; + +use crate::{ + codec::{CodecError, Encode, ParameterizedDecode}, + field::FieldElement, + idpf::{ + conditional_select_seed, conditional_swap_seed, conditional_xor_seeds, xor_seeds, + IdpfInput, IdpfValue, + }, + vdaf::xof::{Seed, Xof, XofFixedKeyAes128, XofTurboShake128}, +}; + +/// VIDPF-related errors. +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum VidpfError { + /// Error when key's identifier are equal. + #[error("key's identifier should be different")] + SameKeyId, + + /// Error when level does not fit in a 32-bit number. + #[error("level is not representable as a 32-bit integer")] + LevelTooBig, + + /// Error during VIDPF evaluation: tried to access a level index out of bounds. + #[error("level index out of bounds")] + IndexLevel, + + /// Error when weight's length mismatches the length in weight's parameter. + #[error("invalid weight length")] + InvalidWeightLength, + + /// Failure when calling getrandom(). + #[error("getrandom: {0}")] + GetRandom(#[from] getrandom::Error), +} + +/// Represents the domain of an incremental point function. +pub type VidpfInput = IdpfInput; + +/// Represents the codomain of an incremental point function. +pub trait VidpfValue: IdpfValue + Clone {} + +/// A VIDPF instance. +pub struct Vidpf { + /// Any parameters required to instantiate a weight value. + weight_parameter: W::ValueParameter, +} + +impl Vidpf { + /// Creates a VIDPF instance. + /// + /// # Arguments + /// + /// * `weight_parameter`, any parameters required to instantiate a weight value. + pub const fn new(weight_parameter: W::ValueParameter) -> Self { + Self { weight_parameter } + } + + /// The [`Vidpf::gen`] method splits an incremental point function `F` into two private keys + /// used by the aggregation servers, and a common public share. + /// + /// The incremental point function is defined as `F`: [`VidpfInput`] --> [`VidpfValue`] + /// such that: + /// + /// ```txt + /// F(x) = weight, if x is a prefix of the input. + /// F(x) = 0, if x is not a prefix of the input. + /// ``` + /// + /// # Arguments + /// + /// * `input`, determines the input of the function. + /// * `weight`, determines the input's weight of the function. + /// * `nonce`, used to cryptographically bind some information. + pub fn gen( + &self, + input: &VidpfInput, + weight: &W, + nonce: &[u8; NONCE_SIZE], + ) -> Result<(VidpfPublicShare, [VidpfKey; 2]), VidpfError> { + let keys = [ + VidpfKey::gen(VidpfServerId::S0)?, + VidpfKey::gen(VidpfServerId::S1)?, + ]; + let public = self.gen_with_keys(&keys, input, weight, nonce)?; + Ok((public, keys)) + } + + /// [`Vidpf::gen_with_keys`] works as the [`Vidpf::gen`] method, except that two different + /// keys must be provided. + fn gen_with_keys( + &self, + keys: &[VidpfKey; 2], + input: &VidpfInput, + weight: &W, + nonce: &[u8; NONCE_SIZE], + ) -> Result, VidpfError> { + if keys[0].id == keys[1].id { + return Err(VidpfError::SameKeyId); + } + + let mut s_i = [keys[0].value, keys[1].value]; + let mut t_i = [Choice::from(keys[0].id), Choice::from(keys[1].id)]; + + let n = input.len(); + let mut cw = Vec::with_capacity(n); + let mut cs = Vec::with_capacity(n); + + for level in 0..n { + let alpha_i = Choice::from(u8::from(input.get(level).ok_or(VidpfError::IndexLevel)?)); + + // If alpha_i == 0 then + // (same_seed, diff_seed) = (right_seed, left_seed) + // else + // (same_seed, diff_seed) = (left_seed, right_seed) + let seq_0 = Self::prg(&s_i[0], nonce); + let (same_seed_0, diff_seed_0) = &mut (seq_0.right_seed, seq_0.left_seed); + conditional_swap_seed(same_seed_0, diff_seed_0, alpha_i); + + let seq_1 = Self::prg(&s_i[1], nonce); + let (same_seed_1, diff_seed_1) = &mut (seq_1.right_seed, seq_1.left_seed); + conditional_swap_seed(same_seed_1, diff_seed_1, alpha_i); + + // If alpha_i == 0 then + // diff_control_bit = left_control_bit + // else + // diff_control_bit = right_control_bit + let diff_control_bit_0 = Choice::conditional_select( + &seq_0.left_control_bit, + &seq_0.right_control_bit, + alpha_i, + ); + let diff_control_bit_1 = Choice::conditional_select( + &seq_1.left_control_bit, + &seq_1.right_control_bit, + alpha_i, + ); + + let s_cw = xor_seeds(same_seed_0, same_seed_1); + let t_cw_l = + seq_0.left_control_bit ^ seq_1.left_control_bit ^ alpha_i ^ Choice::from(1); + let t_cw_r = seq_0.right_control_bit ^ seq_1.right_control_bit ^ alpha_i; + let t_cw_diff = Choice::conditional_select(&t_cw_l, &t_cw_r, alpha_i); + + let s_tilde_i_0 = conditional_xor_seeds(diff_seed_0, &s_cw, t_i[0]); + let s_tilde_i_1 = conditional_xor_seeds(diff_seed_1, &s_cw, t_i[1]); + + t_i[0] = diff_control_bit_0 ^ (t_i[0] & t_cw_diff); + t_i[1] = diff_control_bit_1 ^ (t_i[1] & t_cw_diff); + + let w_i_0; + let w_i_1; + (s_i[0], w_i_0) = self.convert(s_tilde_i_0, nonce); + (s_i[1], w_i_1) = self.convert(s_tilde_i_1, nonce); + + let mut w_cw = w_i_1 - w_i_0 + weight.clone(); + w_cw.conditional_negate(t_i[1]); + + let cw_i = VidpfCorrectionWord { + seed: s_cw, + left_control_bit: t_cw_l, + right_control_bit: t_cw_r, + weight: w_cw, + }; + cw.push(cw_i); + + let pi_tilde_0 = Self::node_proof(input, level, &s_i[0])?; + let pi_tilde_1 = Self::node_proof(input, level, &s_i[1])?; + let cs_i = xor_proof(pi_tilde_0, &pi_tilde_1); + cs.push(cs_i); + } + + Ok(VidpfPublicShare { cw, cs }) + } + + /// [`Vidpf::eval`] evaluates the entire `input` and produces a share of the + /// input's weight. + pub fn eval( + &self, + key: &VidpfKey, + public: &VidpfPublicShare, + input: &VidpfInput, + nonce: &[u8; NONCE_SIZE], + ) -> Result, VidpfError> { + let mut state = VidpfEvalState::init_from_key(key); + let mut share = W::zero(&self.weight_parameter); + + let n = input.len(); + for level in 0..n { + (state, share) = self.eval_next(key.id, public, input, level, &state, nonce)?; + } + + Ok(VidpfValueShare { + share, + proof: state.proof, + }) + } + + /// [`Vidpf::eval_next`] evaluates the `input` at the given level using the provided initial + /// state, and returns a new state and a share of the input's weight at that level. + fn eval_next( + &self, + id: VidpfServerId, + public: &VidpfPublicShare, + input: &VidpfInput, + level: usize, + state: &VidpfEvalState, + nonce: &[u8; NONCE_SIZE], + ) -> Result<(VidpfEvalState, W), VidpfError> { + let cw = public.cw.get(level).ok_or(VidpfError::IndexLevel)?; + + let seq_tilde = Self::prg(&state.seed, nonce); + + let t_i = state.control_bit; + let sl = conditional_xor_seeds(&seq_tilde.left_seed, &cw.seed, t_i); + let sr = conditional_xor_seeds(&seq_tilde.right_seed, &cw.seed, t_i); + let tl = seq_tilde.left_control_bit ^ (t_i & cw.left_control_bit); + let tr = seq_tilde.right_control_bit ^ (t_i & cw.right_control_bit); + + let x_i = Choice::from(u8::from(input.get(level).ok_or(VidpfError::IndexLevel)?)); + let s_tilde_i = conditional_select_seed(x_i, &[sl, sr]); + + let next_control_bit = Choice::conditional_select(&tl, &tr, x_i); + let (next_seed, w_i) = self.convert(s_tilde_i, nonce); + + let zero = ::zero(&self.weight_parameter); + let mut y = ::conditional_select(&zero, &cw.weight, next_control_bit); + y += w_i; + y.conditional_negate(Choice::from(id)); + + let pi_i = &state.proof; + let cs_i = public.cs.get(level).ok_or(VidpfError::IndexLevel)?; + let pi_tilde = Self::node_proof(input, level, &next_seed)?; + let h2_input = xor_proof( + conditional_xor_proof(pi_tilde, cs_i, next_control_bit), + pi_i, + ); + let next_proof = xor_proof(Self::node_proof_adjustment(h2_input), pi_i); + + let next_state = VidpfEvalState { + seed: next_seed, + control_bit: next_control_bit, + proof: next_proof, + }; + + Ok((next_state, y)) + } + + fn prg(seed: &VidpfSeed, nonce: &[u8]) -> VidpfPrgOutput { + let mut rng = XofFixedKeyAes128::seed_stream(&Seed(*seed), VidpfDomainSepTag::PRG, nonce); + + let mut left_seed = VidpfSeed::default(); + let mut right_seed = VidpfSeed::default(); + rng.fill_bytes(&mut left_seed); + rng.fill_bytes(&mut right_seed); + // Use the LSB of seeds as control bits, and clears the bit, + // i.e., seeds produced by `prg` always have their LSB = 0. + // This ensures `prg` costs two AES calls only. + let left_control_bit = Choice::from(left_seed[0] & 0x01); + let right_control_bit = Choice::from(right_seed[0] & 0x01); + left_seed[0] &= 0xFE; + right_seed[0] &= 0xFE; + + VidpfPrgOutput { + left_seed, + left_control_bit, + right_seed, + right_control_bit, + } + } + + fn convert(&self, seed: VidpfSeed, nonce: &[u8; NONCE_SIZE]) -> (VidpfSeed, W) { + let mut rng = + XofFixedKeyAes128::seed_stream(&Seed(seed), VidpfDomainSepTag::CONVERT, nonce); + + let mut out_seed = VidpfSeed::default(); + rng.fill_bytes(&mut out_seed); + let value = ::generate(&mut rng, &self.weight_parameter); + + (out_seed, value) + } + + fn node_proof( + input: &VidpfInput, + level: usize, + seed: &VidpfSeed, + ) -> Result { + let mut shake = XofTurboShake128::init(seed, VidpfDomainSepTag::NODE_PROOF); + for chunk128 in input + .index(..=level) + .chunks(128) + .map(BitField::load_le::) + .map(u128::to_le_bytes) + { + shake.update(&chunk128); + } + shake.update( + &u16::try_from(level) + .map_err(|_e| VidpfError::LevelTooBig)? + .to_le_bytes(), + ); + let mut rng = shake.into_seed_stream(); + + let mut proof = VidpfProof::default(); + rng.fill_bytes(&mut proof); + + Ok(proof) + } + + fn node_proof_adjustment(mut proof: VidpfProof) -> VidpfProof { + let mut rng = XofTurboShake128::seed_stream( + &Seed(Default::default()), + VidpfDomainSepTag::NODE_PROOF_ADJUST, + &proof, + ); + rng.fill_bytes(&mut proof); + + proof + } +} + +/// Contains the domain separation tags for invoking different oracles. +struct VidpfDomainSepTag; +impl VidpfDomainSepTag { + const PRG: &'static [u8] = b"Prg"; + const CONVERT: &'static [u8] = b"Convert"; + const NODE_PROOF: &'static [u8] = b"NodeProof"; + const NODE_PROOF_ADJUST: &'static [u8] = b"NodeProofAdjust"; +} + +/// Private key of an aggregation server. +pub struct VidpfKey { + id: VidpfServerId, + value: [u8; 16], +} + +impl VidpfKey { + /// Generates a key at random. + /// + /// # Errors + /// Triggers an error if the random generator fails. + pub(crate) fn gen(id: VidpfServerId) -> Result { + let mut value = [0; 16]; + getrandom::getrandom(&mut value)?; + Ok(Self { id, value }) + } +} + +/// Identifies the two aggregation servers. +#[derive(Clone, Copy, PartialEq, Eq)] +pub(crate) enum VidpfServerId { + /// S0 is the first server. + S0, + /// S1 is the second server. + S1, +} + +impl From for Choice { + fn from(value: VidpfServerId) -> Self { + match value { + VidpfServerId::S0 => Self::from(0), + VidpfServerId::S1 => Self::from(1), + } + } +} + +/// Adjusts values of shares during the VIDPF evaluation. +#[derive(Debug)] +struct VidpfCorrectionWord { + seed: VidpfSeed, + left_control_bit: Choice, + right_control_bit: Choice, + weight: W, +} + +/// Common public information used by aggregation servers. +#[derive(Debug)] +pub struct VidpfPublicShare { + cw: Vec>, + cs: Vec, +} + +/// Contains the values produced during input evaluation at a given level. +pub struct VidpfEvalState { + seed: VidpfSeed, + control_bit: Choice, + proof: VidpfProof, +} + +impl VidpfEvalState { + fn init_from_key(key: &VidpfKey) -> Self { + Self { + seed: key.value, + control_bit: Choice::from(key.id), + proof: VidpfProof::default(), + } + } +} + +/// Contains a share of the input's weight together with a proof for verification. +pub struct VidpfValueShare { + /// Secret share of the input's weight. + pub share: W, + /// Proof used to verify the share. + pub proof: VidpfProof, +} + +/// Proof size in bytes. +const VIDPF_PROOF_SIZE: usize = 32; + +/// Allows to validate user input and shares after evaluation. +type VidpfProof = [u8; VIDPF_PROOF_SIZE]; + +fn xor_proof(mut lhs: VidpfProof, rhs: &VidpfProof) -> VidpfProof { + zip(&mut lhs, rhs).for_each(|(a, b)| a.bitxor_assign(b)); + lhs +} + +fn conditional_xor_proof(mut lhs: VidpfProof, rhs: &VidpfProof, choice: Choice) -> VidpfProof { + zip(&mut lhs, rhs).for_each(|(a, b)| a.conditional_assign(&a.bitxor(b), choice)); + lhs +} + +/// Feeds a pseudorandom generator during evaluation. +type VidpfSeed = [u8; 16]; + +/// Contains the seeds and control bits produced by [`Vidpf::prg`]. +struct VidpfPrgOutput { + left_seed: VidpfSeed, + left_control_bit: Choice, + right_seed: VidpfSeed, + right_control_bit: Choice, +} + +/// Represents an array of field elements that implements the [`VidpfValue`] trait. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct VidpfWeight(Vec); + +impl From> for VidpfWeight { + fn from(value: Vec) -> Self { + Self(value) + } +} + +impl VidpfValue for VidpfWeight {} + +impl IdpfValue for VidpfWeight { + /// The parameter determines the number of field elements in the vector. + type ValueParameter = usize; + + fn generate(seed_stream: &mut S, length: &Self::ValueParameter) -> Self { + Self( + (0..*length) + .map(|_| ::generate(seed_stream, &())) + .collect(), + ) + } + + fn zero(length: &Self::ValueParameter) -> Self { + Self((0..*length).map(|_| ::zero(&())).collect()) + } + + /// Panics if weight lengths are different. + fn conditional_select(lhs: &Self, rhs: &Self, choice: Choice) -> Self { + assert_eq!( + lhs.0.len(), + rhs.0.len(), + "{}", + VidpfError::InvalidWeightLength + ); + + Self( + zip(&lhs.0, &rhs.0) + .map(|(a, b)| ::conditional_select(a, b, choice)) + .collect(), + ) + } +} + +impl ConditionallyNegatable for VidpfWeight { + fn conditional_negate(&mut self, choice: Choice) { + self.0.iter_mut().for_each(|a| a.conditional_negate(choice)); + } +} + +impl Add for VidpfWeight { + type Output = Self; + + /// Panics if weight lengths are different. + fn add(self, rhs: Self) -> Self::Output { + assert_eq!( + self.0.len(), + rhs.0.len(), + "{}", + VidpfError::InvalidWeightLength + ); + + Self(zip(self.0, rhs.0).map(|(a, b)| a.add(b)).collect()) + } +} + +impl AddAssign for VidpfWeight { + /// Panics if weight lengths are different. + fn add_assign(&mut self, rhs: Self) { + assert_eq!( + self.0.len(), + rhs.0.len(), + "{}", + VidpfError::InvalidWeightLength + ); + + zip(&mut self.0, rhs.0).for_each(|(a, b)| a.add_assign(b)); + } +} + +impl Sub for VidpfWeight { + type Output = Self; + + /// Panics if weight lengths are different. + fn sub(self, rhs: Self) -> Self::Output { + assert_eq!( + self.0.len(), + rhs.0.len(), + "{}", + VidpfError::InvalidWeightLength + ); + + Self(zip(self.0, rhs.0).map(|(a, b)| a.sub(b)).collect()) + } +} + +impl Encode for VidpfWeight { + fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { + for e in &self.0 { + F::encode(e, bytes)?; + } + Ok(()) + } + + fn encoded_len(&self) -> Option { + Some(self.0.len() * F::ENCODED_SIZE) + } +} + +impl ParameterizedDecode<::ValueParameter> for VidpfWeight { + fn decode_with_param( + decoding_parameter: &::ValueParameter, + bytes: &mut Cursor<&[u8]>, + ) -> Result { + let mut v = Vec::with_capacity(*decoding_parameter); + for _ in 0..*decoding_parameter { + v.push(F::decode_with_param(&(), bytes)?); + } + + Ok(Self(v)) + } +} + +#[cfg(test)] +mod tests { + use crate::field::Field128; + + use super::VidpfWeight; + + type TestWeight = VidpfWeight; + const TEST_WEIGHT_LEN: usize = 3; + const TEST_NONCE_SIZE: usize = 16; + const TEST_NONCE: &[u8; TEST_NONCE_SIZE] = b"Test Nonce VIDPF"; + + mod vidpf { + use crate::{ + idpf::IdpfValue, + vidpf::{ + Vidpf, VidpfError, VidpfEvalState, VidpfInput, VidpfKey, VidpfPublicShare, + VidpfServerId, + }, + }; + + use super::{TestWeight, TEST_NONCE, TEST_NONCE_SIZE, TEST_WEIGHT_LEN}; + + fn vidpf_gen_setup( + input: &VidpfInput, + weight: &TestWeight, + ) -> ( + Vidpf, + VidpfPublicShare, + [VidpfKey; 2], + [u8; TEST_NONCE_SIZE], + ) { + let vidpf = Vidpf::new(TEST_WEIGHT_LEN); + let (public, keys) = vidpf.gen(input, weight, TEST_NONCE).unwrap(); + (vidpf, public, keys, *TEST_NONCE) + } + + #[test] + fn gen_with_keys() { + let input = VidpfInput::from_bytes(&[0xFF]); + let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]); + let vidpf = Vidpf::new(TEST_WEIGHT_LEN); + let keys_with_same_id = [ + VidpfKey::gen(VidpfServerId::S0).unwrap(), + VidpfKey::gen(VidpfServerId::S0).unwrap(), + ]; + + let err = vidpf + .gen_with_keys(&keys_with_same_id, &input, &weight, TEST_NONCE) + .unwrap_err(); + + assert_eq!(err.to_string(), VidpfError::SameKeyId.to_string()); + } + + #[test] + fn correctness_at_last_level() { + let input = VidpfInput::from_bytes(&[0xFF]); + let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]); + let (vidpf, public, [key_0, key_1], nonce) = vidpf_gen_setup(&input, &weight); + + let value_share_0 = vidpf.eval(&key_0, &public, &input, &nonce).unwrap(); + let value_share_1 = vidpf.eval(&key_1, &public, &input, &nonce).unwrap(); + + assert_eq!( + value_share_0.share + value_share_1.share, + weight, + "shares must add up to the expected weight", + ); + + assert_eq!( + value_share_0.proof, value_share_1.proof, + "proofs must be equal" + ); + + let bad_input = VidpfInput::from_bytes(&[0x00]); + let zero = TestWeight::zero(&TEST_WEIGHT_LEN); + let value_share_0 = vidpf.eval(&key_0, &public, &bad_input, &nonce).unwrap(); + let value_share_1 = vidpf.eval(&key_1, &public, &bad_input, &nonce).unwrap(); + + assert_eq!( + value_share_0.share + value_share_1.share, + zero, + "shares must add up to zero", + ); + + assert_eq!( + value_share_0.proof, value_share_1.proof, + "proofs must be equal" + ); + } + + #[test] + fn correctness_at_each_level() { + let input = VidpfInput::from_bytes(&[0xFF]); + let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]); + let (vidpf, public, keys, nonce) = vidpf_gen_setup(&input, &weight); + + assert_eval_at_each_level(&vidpf, &keys, &public, &input, &weight, &nonce); + + let bad_input = VidpfInput::from_bytes(&[0x00]); + let zero = TestWeight::zero(&TEST_WEIGHT_LEN); + + assert_eval_at_each_level(&vidpf, &keys, &public, &bad_input, &zero, &nonce); + } + + fn assert_eval_at_each_level( + vidpf: &Vidpf, + [key_0, key_1]: &[VidpfKey; 2], + public: &VidpfPublicShare, + input: &VidpfInput, + weight: &TestWeight, + nonce: &[u8; TEST_NONCE_SIZE], + ) { + let mut state_0 = VidpfEvalState::init_from_key(key_0); + let mut state_1 = VidpfEvalState::init_from_key(key_1); + + let n = input.len(); + for level in 0..n { + let share_0; + let share_1; + (state_0, share_0) = vidpf + .eval_next(key_0.id, public, input, level, &state_0, nonce) + .unwrap(); + (state_1, share_1) = vidpf + .eval_next(key_1.id, public, input, level, &state_1, nonce) + .unwrap(); + + assert_eq!( + share_0 + share_1, + *weight, + "shares must add up to the expected weight at the current level: {:?}", + level + ); + + assert_eq!( + state_0.proof, state_1.proof, + "proofs must be equal at the current level: {:?}", + level + ); + } + } + } + + mod weight { + use std::io::Cursor; + use subtle::{Choice, ConditionallyNegatable}; + + use crate::{ + codec::{Encode, ParameterizedDecode}, + idpf::IdpfValue, + vdaf::xof::{Seed, Xof, XofTurboShake128}, + }; + + use super::{TestWeight, TEST_WEIGHT_LEN}; + + #[test] + fn roundtrip_codec() { + let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]); + + let mut bytes = vec![]; + weight.encode(&mut bytes).unwrap(); + + let expected_bytes = [ + [vec![21], vec![0u8; 15]].concat(), + [vec![22], vec![0u8; 15]].concat(), + [vec![23], vec![0u8; 15]].concat(), + ] + .concat(); + + assert_eq!(weight.encoded_len().unwrap(), expected_bytes.len()); + // Check endianness of encoding + assert_eq!(bytes, expected_bytes); + + let decoded = + TestWeight::decode_with_param(&TEST_WEIGHT_LEN, &mut Cursor::new(&bytes)).unwrap(); + assert_eq!(weight, decoded); + } + + #[test] + fn add_sub() { + let [a, b] = compatible_weights(); + let mut c = a.clone(); + c += a.clone(); + + assert_eq!( + (a.clone() + b.clone()) + (a.clone() - b.clone()), + c, + "a: {:?} b:{:?}", + a, + b + ); + } + + #[test] + fn conditional_negate() { + let [a, _] = compatible_weights(); + let mut c = a.clone(); + c.conditional_negate(Choice::from(0)); + let mut d = a.clone(); + d.conditional_negate(Choice::from(1)); + let zero = TestWeight::zero(&TEST_WEIGHT_LEN); + + assert_eq!(c + d, zero, "a: {:?}", a); + } + + #[test] + #[should_panic = "invalid weight length"] + fn add_panics() { + let [w0, w1] = incompatible_weights(); + let _ = w0 + w1; + } + + #[test] + #[should_panic = "invalid weight length"] + fn add_assign_panics() { + let [mut w0, w1] = incompatible_weights(); + w0 += w1; + } + + #[test] + #[should_panic = "invalid weight length"] + fn sub_panics() { + let [w0, w1] = incompatible_weights(); + let _ = w0 - w1; + } + + #[test] + #[should_panic = "invalid weight length"] + fn conditional_select_panics() { + let [w0, w1] = incompatible_weights(); + TestWeight::conditional_select(&w0, &w1, Choice::from(0)); + } + + fn compatible_weights() -> [TestWeight; 2] { + let mut xof = XofTurboShake128::seed_stream(&Seed(Default::default()), &[], &[]); + [ + TestWeight::generate(&mut xof, &TEST_WEIGHT_LEN), + TestWeight::generate(&mut xof, &TEST_WEIGHT_LEN), + ] + } + + fn incompatible_weights() -> [TestWeight; 2] { + let mut xof = XofTurboShake128::seed_stream(&Seed(Default::default()), &[], &[]); + [ + TestWeight::generate(&mut xof, &TEST_WEIGHT_LEN), + TestWeight::generate(&mut xof, &(2 * TEST_WEIGHT_LEN)), + ] + } + } +} diff --git a/third_party/rust/prio/tests/discrete_gauss.rs b/third_party/rust/prio/tests/discrete_gauss.rs index 5b3ef4c5b3..d72138b64c 100644 --- a/third_party/rust/prio/tests/discrete_gauss.rs +++ b/third_party/rust/prio/tests/discrete_gauss.rs @@ -4,7 +4,7 @@ use num_bigint::{BigInt, BigUint}; use num_rational::Ratio; use num_traits::FromPrimitive; use prio::dp::distributions::DiscreteGaussian; -use prio::vdaf::xof::SeedStreamSha3; +use prio::vdaf::xof::SeedStreamTurboShake128; use rand::distributions::Distribution; use rand::SeedableRng; use serde::Deserialize; @@ -12,7 +12,7 @@ use serde::Deserialize; /// A test vector of discrete Gaussian samples, produced by the python reference /// implementation for [[CKS20]]. The script used to generate the test vector can /// be found in this gist: -/// https://gist.github.com/ooovi/529c00fc8a7eafd068cd076b78fc424e +/// https://gist.github.com/divergentdave/94cab188e84a4764db6cdd1288e6ead3 /// The python reference implementation is here: /// https://github.com/IBM/discrete-gaussian-differential-privacy /// @@ -29,20 +29,15 @@ pub struct DiscreteGaussTestVector { #[test] fn discrete_gauss_reference() { let test_vectors: Vec = vec![ - serde_json::from_str(include_str!(concat!("test_vectors/discrete_gauss_3.json"))).unwrap(), - serde_json::from_str(include_str!(concat!("test_vectors/discrete_gauss_9.json"))).unwrap(), - serde_json::from_str(include_str!(concat!( - "test_vectors/discrete_gauss_100.json" - ))) - .unwrap(), - serde_json::from_str(include_str!(concat!( - "test_vectors/discrete_gauss_41293847.json" - ))) - .unwrap(), - serde_json::from_str(include_str!(concat!( + serde_json::from_str(include_str!("test_vectors/discrete_gauss_3.json")).unwrap(), + serde_json::from_str(include_str!("test_vectors/discrete_gauss_9.json")).unwrap(), + serde_json::from_str(include_str!("test_vectors/discrete_gauss_100.json")).unwrap(), + serde_json::from_str(include_str!("test_vectors/discrete_gauss_41293847.json")).unwrap(), + serde_json::from_str(include_str!( "test_vectors/discrete_gauss_9999999999999999999999.json" - ))) + )) .unwrap(), + serde_json::from_str(include_str!("test_vectors/discrete_gauss_2.342.json")).unwrap(), ]; for test_vector in test_vectors { @@ -53,7 +48,7 @@ fn discrete_gauss_reference() { .unwrap(); // check samples are consistent - let mut rng = SeedStreamSha3::from_seed(test_vector.seed); + let mut rng = SeedStreamTurboShake128::from_seed(test_vector.seed); let samples: Vec = (0..test_vector.samples.len()) .map(|_| sampler.sample(&mut rng)) .collect(); diff --git a/third_party/rust/prio/tests/test_vectors/discrete_gauss_100.json b/third_party/rust/prio/tests/test_vectors/discrete_gauss_100.json index fe8114c258..84425db753 100644 --- a/third_party/rust/prio/tests/test_vectors/discrete_gauss_100.json +++ b/third_party/rust/prio/tests/test_vectors/discrete_gauss_100.json @@ -1,54 +1,54 @@ { "samples": [ - -74, + -54, + 61, + -113, + -98, + 21, + -91, + 72, + 112, + -29, 68, - -15, - 175, - -120, - -2, - -73, - 108, - 40, - 69, - 81, - -135, - 247, - 32, - 107, + 84, + -27, + -109, + -20, + -24, + -69, + -168, + 199, + -122, + 59, + 35, + 282, + 113, + 4, + -91, -61, - 164, - 22, - 118, - 37, - -58, - 147, - 65, - 53, - 9, - -96, - -130, - 100, - 48, + -28, + 137, + 57, + 109, + 2, + 17, + -20, + 38, + -16, + 18, + -63, + 1, + -20, -30, - -2, - -115, - 56, - 95, - 119, - 28, - -101, - 50, - 39, - 21, - -6, - -70, - 131, - 66, - 81, - -18, - 94, - 55, - 20 + -147, + -73, + -28, + -16, + -31, + 10, + -229, + -56, + -254 ], "seed": "000102030405060708090a0b0c0d0e0f", "std_denom": 1, diff --git a/third_party/rust/prio/tests/test_vectors/discrete_gauss_2.342.json b/third_party/rust/prio/tests/test_vectors/discrete_gauss_2.342.json index 7d9508c44e..c70e3b06e1 100644 --- a/third_party/rust/prio/tests/test_vectors/discrete_gauss_2.342.json +++ b/third_party/rust/prio/tests/test_vectors/discrete_gauss_2.342.json @@ -1,54 +1,54 @@ { "samples": [ -1, - 4, - 2, - 0, - 0, - -2, 1, - -5, + 6, 2, + -4, -1, - 0, - 0, - 0, - 3, - -6, - 5, + -2, 2, - 1, - -1, + -2, -3, 0, - 2, - -3, -2, + -1, + 3, 2, - -3, - 1, 1, 2, - -3, - -1, + -7, -1, + 0, 4, - 2, - -2, 1, -1, 0, - -3, + 1, + -2, + 0, 1, 2, + 0, + 6, + -2, + 2, + 0, + -2, + 2, + 6, 1, + 0, + -4, + -3, + -1, -1, - 3, - 1, 2, - -3, + 0, + 0, -2, - 0 + 0, + 2 ], "seed": "000102030405060708090a0b0c0d0e0f", "std_denom": 500, diff --git a/third_party/rust/prio/tests/test_vectors/discrete_gauss_3.json b/third_party/rust/prio/tests/test_vectors/discrete_gauss_3.json index d4a3486db0..363c136eb8 100644 --- a/third_party/rust/prio/tests/test_vectors/discrete_gauss_3.json +++ b/third_party/rust/prio/tests/test_vectors/discrete_gauss_3.json @@ -1,54 +1,54 @@ { "samples": [ - 1, + -3, -1, -2, 1, + 7, -1, - 0, - 1, - -1, - 0, - 2, - 3, - 4, - 1, - 1, -2, - 4, - 6, + 1, -5, + 1, -3, - -1, - 4, - 0, - 6, - 2, + 3, 2, - -4, - -2, -5, + -2, + 5, + -2, + 5, + -1, -3, 2, - 1, - -3, -2, - 1, + -1, -2, - 1, + -2, + -1, 0, - 3, - -4, - -4, 1, - 3, + -1, 2, - 1, - 0, + -3, + 2, + -6, + -4, + -2, + -2, + -6, -1, - 1, 4, - 1 + -1, + 2, + -3, + 1, + -7, + -1, + 6, + 2, + -3, + 5 ], "seed": "000102030405060708090a0b0c0d0e0f", "std_denom": 1, diff --git a/third_party/rust/prio/tests/test_vectors/discrete_gauss_41293847.json b/third_party/rust/prio/tests/test_vectors/discrete_gauss_41293847.json index 213e919c6c..247b2c2451 100644 --- a/third_party/rust/prio/tests/test_vectors/discrete_gauss_41293847.json +++ b/third_party/rust/prio/tests/test_vectors/discrete_gauss_41293847.json @@ -1,54 +1,54 @@ { "samples": [ - -10157810, - -7944688, - 80361481, - -2601121, - -2098394, - -61204295, - 250399, - 62702361, - -35117486, - 14804891, - -5043613, - 34131059, - -34448923, - -24176095, - 106518772, - 44056972, - 15910928, - 63338376, - 12839729, - 11701052, - -54254959, - -11306071, - -6005727, - 29738939, - -30284246, - -47672638, - 11549070, - -17580447, - -2973754, - -298465, - -15349002, - 56970396, - 35612502, - -78720214, - -6082493, - -2759887, - -11374460, - 177253, - -35234082, - 42256563, - 44219644, - 86984413, - -43711428, - -16031438, - 42572889, - 39464625, - -14433332, - -7735634, - 4403776 + -28705712, + 12839166, + 68574447, + 1993202, + 17416465, + 32526761, + 1212638, + -44876888, + 16502539, + -57954542, + -54567452, + -17421605, + 7569207, + 13482762, + -24573436, + 73067636, + -58069630, + -24924404, + 51409721, + -18659663, + -12752706, + 4308454, + -49095581, + -69009203, + -22975883, + 46983148, + 47341228, + -1860382, + 26901791, + -5079023, + -57635595, + -38560402, + 59065470, + 100046871, + -144954761, + -22089238, + -43816191, + -47986043, + 34106023, + 74194716, + -37681692, + 3946618, + 18344461, + -45770607, + -654004, + 31284526, + -50259979, + 28037461, + 2734567 ], "seed": "000102030405060708090a0b0c0d0e0f", "std_denom": 1, diff --git a/third_party/rust/prio/tests/test_vectors/discrete_gauss_9.json b/third_party/rust/prio/tests/test_vectors/discrete_gauss_9.json index 408c7489a7..b5df20d182 100644 --- a/third_party/rust/prio/tests/test_vectors/discrete_gauss_9.json +++ b/third_party/rust/prio/tests/test_vectors/discrete_gauss_9.json @@ -1,54 +1,54 @@ { "samples": [ - 2, - 14, - -12, - 10, - -13, - 1, - 6, - -10, + -6, + 7, + -3, + -7, + -14, + 4, + 11, + -22, -1, + 8, + -9, + 12, + -9, + 20, + -16, + -10, + -8, + -15, + 6, + -8, + 7, + 12, + 1, 4, + -3, + -7, + 20, + 2, + 13, + -4, -5, 1, - -20, - 1, - -14, + 2, + -2, + 4, + -6, 2, -5, - 10, - 3, - 9, - 10, - 12, - -4, - 12, - -4, - -13, - 7, - -10, -6, 2, - 6, - 18, - -7, - -11, - 20, - 1, - -4, - 14, - 11, - 5, - 6, - -1, 2, - 5, - 3, - -8, - -1, - 6, - -8 + -5, + -10, + -9, + -15, + -2, + -3, + 1, + -13 ], "seed": "000102030405060708090a0b0c0d0e0f", "std_denom": 1, diff --git a/third_party/rust/prio/tests/test_vectors/discrete_gauss_9999999999999999999999.json b/third_party/rust/prio/tests/test_vectors/discrete_gauss_9999999999999999999999.json index 396f5a4cf0..1b43f758bd 100644 --- a/third_party/rust/prio/tests/test_vectors/discrete_gauss_9999999999999999999999.json +++ b/third_party/rust/prio/tests/test_vectors/discrete_gauss_9999999999999999999999.json @@ -1,54 +1,54 @@ { "samples": [ - 7826646418794481373730, - 4044429794334089153683, - -13887062284591122240746, - 4816851335312673293131, - 1899078604295677453383, - -7819872990828024151405, - 1164017821807881486579, - -25360379570365624087817, - 5906637163630390455939, - 3730592807287609262846, - 1737147847266613603450, - 18593764766679058926154, - 22724295990478919946193, - -4396717652132313983045, - -7933138830987043774425, - 12204708418993708917398, - 10716232788607487693156, - -7423575920998904747964, - -274262846168968742506, - -24595460253341309777726, - 1880635641243101726137, - 10823060437484007979521, - -2525077352000184270857, - -1421364839539048815904, - -2648842672480402351562, - -7783156811031000955203, - -1831198454606609539077, - 905920470298728568753, - -8805882598094077859729, - 2949974625887521817722, - 13071000629486423981714, - 1311702736683393895126, - -14044034250430823347919, - 1421736709768854180193, - 14824744520414922652958, - 10752031849750698732804, - -522118577625103067952, - 2006618532306506057615, - -7573105805904097888275, - -14482966128638641002042, - -11408400475022385123481, - -17555433966245180572099, - -6120185353438187140929, - -4778266138627264471521, - -19325342657405318133711, - 3725950229250476135126, - -7977400544074383347686, - 2738166449787592433931, - -1321521809406566447071 + -7678632936135800555201, + -9832864446958915374632, + 3796223649719723548306, + -10458306547534276720045, + -9593524715689396783652, + -2184509652523057908030, + -6469904065015921866985, + 8555843521262785582921, + -3275061234860213279391, + -1712551617443682313245, + -4176263950279049852314, + -1041488124720108532833, + 2422891656983904955539, + -5406575579403973625234, + 4031989610743156091985, + -15897376981820943559856, + -9495308497775799052592, + -10542231739931574778478, + -811195020079942319200, + -6168725392123782999911, + 3572639345203916100181, + 9572138148079890711898, + 12973597810318272581841, + -10417671747756128178069, + -4499306785200793424437, + 24392853538076877246695, + 490509578119404728479, + -3153758591414179213424, + -2953031165864251687043, + 7687220020362800379045, + -2894825604535601473288, + -2484898457763802405625, + 2506976850588238983075, + -317271622218426183645, + 3771644622097191550823, + 14048201376263257821999, + 1011626374739477364716, + -7985335097085684878144, + -9834946916794550716888, + -7808156770298839154888, + -10888303506419120919014, + 20441738459254393472434, + -1142146934147582936699, + -380992974206599694131, + 14719724965924743443097, + 2738534455216435603182, + 16889459715609520924993, + 8450917371339563018232, + 3461026365290831355984 ], "seed": "000102030405060708090a0b0c0d0e0f", "std_denom": 1, diff --git a/third_party/rust/qlog/.cargo-checksum.json b/third_party/rust/qlog/.cargo-checksum.json index 4aae6bf3b8..e0db62dc79 100644 --- a/third_party/rust/qlog/.cargo-checksum.json +++ b/third_party/rust/qlog/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"66c6d85a84c84711f3abddaafb163bc6025a8505701fea8b61bfa961851be757","README.md":"597691eb766c2cbd7a6591bda56d3e70e6836b62b6327fb73497523eabd5b53d","src/events/connectivity.rs":"116993412e200e375c97762980ffb638d2244197fd752b9569b5b20baf574308","src/events/h3.rs":"4799179c4d18403a3936a327c483d110bd058d42061f9cdd39601b3e91500c1b","src/events/mod.rs":"75f57b4717fa9777e19d61b99b6a79164f0e8bca9b4681c3ab11b204320c8c55","src/events/qpack.rs":"5c7267c45e3fb947cdfa946f9f9692d3e3e36a166f70124ba293dc27534267d0","src/events/quic.rs":"88b884f5788c671ffee79a3448f367c18f95ee30531262fcc14310d80e662f4a","src/events/security.rs":"e9852d7de16851b62c3e0a886a2c1a31d237e62574ef88428ef62dd179b0b008","src/lib.rs":"bbc190a6d0f484fd723f9df6c1b2a4596f826e0282ad40ee17a0822ea28a5626","src/reader.rs":"4e0069c24aca9cb99d75075c9b784fa02855ea449d2f1528bea944a4e02a9af5","src/streamer.rs":"4774c2abde1a5b0f4448aac06c62c7927208c12f338c46981f80c98703b54074"},"package":"9c0407438c69b3d99714a796a135cbfb2d60744e4747fb2b46a87acd1c1fcd0e"} \ No newline at end of file +{"files":{"Cargo.toml":"f660fd1858ac7bc0cc6a0db2058a311328678b5d19e5f7a2eb1cdebe74155752","README.md":"597691eb766c2cbd7a6591bda56d3e70e6836b62b6327fb73497523eabd5b53d","src/events/connectivity.rs":"116993412e200e375c97762980ffb638d2244197fd752b9569b5b20baf574308","src/events/h3.rs":"4799179c4d18403a3936a327c483d110bd058d42061f9cdd39601b3e91500c1b","src/events/mod.rs":"2e9f00885face20abeb183c7421b11d402c13d841921ce9a8b0061b141e97353","src/events/qpack.rs":"5c7267c45e3fb947cdfa946f9f9692d3e3e36a166f70124ba293dc27534267d0","src/events/quic.rs":"aae0ff30e8cd27219dbb5bcb34d78d11c3f81bbdc099aabdd37b8f7206e3fb9c","src/events/security.rs":"e9852d7de16851b62c3e0a886a2c1a31d237e62574ef88428ef62dd179b0b008","src/lib.rs":"ef7121a53369c995e333a84c6ed0c14c91ca5825588a27a47ae5d92a44cb0b07","src/reader.rs":"4e0069c24aca9cb99d75075c9b784fa02855ea449d2f1528bea944a4e02a9af5","src/streamer.rs":"4774c2abde1a5b0f4448aac06c62c7927208c12f338c46981f80c98703b54074"},"package":"9b5f65b920fa913ce92267bb3c4ed3b9c2f81d05f8e1376c3bbc95455eedb7df"} \ No newline at end of file diff --git a/third_party/rust/qlog/Cargo.toml b/third_party/rust/qlog/Cargo.toml index 4a5eb1ff96..928951a973 100644 --- a/third_party/rust/qlog/Cargo.toml +++ b/third_party/rust/qlog/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "qlog" -version = "0.12.0" +version = "0.13.0" authors = ["Lucas Pardue "] description = "qlog data model for QUIC and HTTP/3" readme = "README.md" diff --git a/third_party/rust/qlog/src/events/mod.rs b/third_party/rust/qlog/src/events/mod.rs index ac18276fd0..dbd35183ef 100644 --- a/third_party/rust/qlog/src/events/mod.rs +++ b/third_party/rust/qlog/src/events/mod.rs @@ -202,6 +202,9 @@ impl From for EventImportance { EventType::ConnectivityEventType( ConnectivityEventType::ConnectionStarted, ) => EventImportance::Base, + EventType::ConnectivityEventType( + ConnectivityEventType::ConnectionClosed, + ) => EventImportance::Base, EventType::ConnectivityEventType( ConnectivityEventType::ConnectionIdUpdated, ) => EventImportance::Base, diff --git a/third_party/rust/qlog/src/events/quic.rs b/third_party/rust/qlog/src/events/quic.rs index a7c1fa3225..e504125a1a 100644 --- a/third_party/rust/qlog/src/events/quic.rs +++ b/third_party/rust/qlog/src/events/quic.rs @@ -384,30 +384,43 @@ pub enum QuicFrameTypeName { // ensure it goes out on the wire. This means that deserialization of frames // also works automatically. pub enum QuicFrame { - Padding, + Padding { + length: Option, + payload_length: u32, + }, - Ping, + Ping { + length: Option, + payload_length: Option, + }, Ack { ack_delay: Option, acked_ranges: Option, ect1: Option, - ect0: Option, - ce: Option, + + length: Option, + payload_length: Option, }, ResetStream { stream_id: u64, error_code: u64, final_size: u64, + + length: Option, + payload_length: Option, }, StopSending { stream_id: u64, error_code: u64, + + length: Option, + payload_length: Option, }, Crypto { diff --git a/third_party/rust/qlog/src/lib.rs b/third_party/rust/qlog/src/lib.rs index 68ff278fcd..ed26570fe0 100644 --- a/third_party/rust/qlog/src/lib.rs +++ b/third_party/rust/qlog/src/lib.rs @@ -332,8 +332,14 @@ //! Some(&dcid), //! ); //! -//! let ping = qlog::events::quic::QuicFrame::Ping; -//! let padding = qlog::events::quic::QuicFrame::Padding; +//! let ping = qlog::events::quic::QuicFrame::Ping { +//! length: None, +//! payload_length: None, +//! }; +//! let padding = qlog::events::quic::QuicFrame::Padding { +//! length: None, +//! payload_length: 1234, +//! }; //! //! let event_data = //! qlog::events::EventData::PacketSent(qlog::events::quic::PacketSent { @@ -790,7 +796,8 @@ mod tests { }, "frames": [ { - "frame_type": "padding" + "frame_type": "padding", + "payload_length": 1234 }, { "frame_type": "ping" @@ -808,14 +815,23 @@ mod tests { let pkt_hdr = make_pkt_hdr(PacketType::Initial); - let frames = - vec![QuicFrame::Padding, QuicFrame::Ping, QuicFrame::Stream { + let frames = vec![ + QuicFrame::Padding { + payload_length: 1234, + length: None, + }, + QuicFrame::Ping { + payload_length: None, + length: None, + }, + QuicFrame::Stream { stream_id: 0, offset: 0, length: 100, fin: Some(true), raw: None, - }]; + }, + ]; let ev_data = EventData::PacketSent(PacketSent { header: pkt_hdr, diff --git a/third_party/rust/relevancy/.cargo-checksum.json b/third_party/rust/relevancy/.cargo-checksum.json index c8d8187c8d..bfa17d066a 100644 --- a/third_party/rust/relevancy/.cargo-checksum.json +++ b/third_party/rust/relevancy/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"76d64a839128f51662d1c10728ceddbb6a9ebdfce803915874cd654117d1b14e","build.rs":"a562bfe527d21c4e8a1a44b892defa83cdff141ec5dd51ed6f3862330e50ddd7","src/bin/generate-test-data.rs":"7f1c9dc445418c7627f89d1f2aa8e550d0f85b3d1f05edb7c378ab9441714f1f","src/db.rs":"0b45180f3031759213a0421231b6f109ed4f5c88aca556df159ce2717416cfec","src/error.rs":"6831fc329044174a8451b8b008c0b96c47404c591eb42e880562e65da0adfd0f","src/interest.rs":"ce6298ef8f69fcb57c8e5797467cbe1c0212a0d94daf828b12845740ac14a166","src/lib.rs":"7a0f0ad0a43f371035d9c0b73d143cf1b387d4b8cfad0d0db79314b5b91fd43c","src/populate_interests.rs":"b8905b52f9fc80719c175253b758413f606b27660e660635094421eec8b24c8f","src/relevancy.udl":"a3fae5097f9e8b39bb6c74ed6789906748c46f22d377e3dcb73b08731908f5bc","src/schema.rs":"f782c712f10c4f1af2f9e1424d6b52f59a2bacfcc452a8feb763f36478f5dd5d","src/url_hash.rs":"5619a249d471e7b642d889bad09e93212559c8b947010d49492c1423da2b310e","test-data":"392fc950363c9953ea6ab144b81d84021c4af1e1177cc0adac4eda5688c8bc33"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"2b7bf33e20b6aa768dd18619845e9d5d22235d86f770e94b250ed0052662ce2d","build.rs":"a562bfe527d21c4e8a1a44b892defa83cdff141ec5dd51ed6f3862330e50ddd7","src/bin/generate-test-data.rs":"7f1c9dc445418c7627f89d1f2aa8e550d0f85b3d1f05edb7c378ab9441714f1f","src/db.rs":"7ca5688c42d44ad6e5320208257d131c5c744be47a1cfe3e1380147abf2aadc3","src/error.rs":"0fe48e211dffb2010f732672c38e1c79b1995df3e70b06398ed8ac43d326c1b1","src/ingest.rs":"d3f528c1d62b4b6af404bb14cb0d431f8d523911ada09e4e1db5836b6cf44e04","src/interest.rs":"adbaa1e0324c7bb32b023f105b45499390a1a83973d1a8c7d727a661a25cc259","src/lib.rs":"29ce35211c9d94d561d62d7e8ef57fc56cc90a9ba42b88b54c2f4c9236a8cd4d","src/relevancy.udl":"b551e7476f30dccdc74cbf2f38fc3b87a3a7d0ec5dfa6c2ea4417b18fbc7475c","src/rs.rs":"b98091d0adca809d8fef38eb5394f885e04d4d382b7c8abd7bd0fe53f64e7bd6","src/schema.rs":"f782c712f10c4f1af2f9e1424d6b52f59a2bacfcc452a8feb763f36478f5dd5d","src/url_hash.rs":"2e908316fb70923644d1990dbf470d69ce2f5e99b0c5c3d95ec691590be8ffa5","test-data":"1ef2cd092d59e7e126cd4a514af983d449ed9f9c98708702fd237464a76c2b5e"},"package":null} \ No newline at end of file diff --git a/third_party/rust/relevancy/Cargo.toml b/third_party/rust/relevancy/Cargo.toml index eddd8fd25c..67c1716ab2 100644 --- a/third_party/rust/relevancy/Cargo.toml +++ b/third_party/rust/relevancy/Cargo.toml @@ -25,9 +25,12 @@ license = "MPL-2.0" name = "generate-test-data" [dependencies] +anyhow = "1.0" +base64 = "0.21.2" log = "0.4" md-5 = "0.10" parking_lot = ">=0.11,<=0.12" +serde_json = "1" thiserror = "1.0" uniffi = "0.27.1" url = "2.5" @@ -35,10 +38,20 @@ url = "2.5" [dependencies.error-support] path = "../support/error" +[dependencies.interrupt-support] +path = "../support/interrupt" + +[dependencies.remote_settings] +path = "../remote_settings" + [dependencies.rusqlite] version = "0.30.0" features = ["bundled"] +[dependencies.serde] +version = "1" +features = ["derive"] + [dependencies.sql-support] path = "../support/sql" diff --git a/third_party/rust/relevancy/src/db.rs b/third_party/rust/relevancy/src/db.rs index 08684c45af..b2dc0b0c83 100644 --- a/third_party/rust/relevancy/src/db.rs +++ b/third_party/rust/relevancy/src/db.rs @@ -8,52 +8,66 @@ use crate::{ url_hash::{hash_url, UrlHash}, Interest, InterestVector, Result, }; -use parking_lot::Mutex; +use interrupt_support::SqlInterruptScope; use rusqlite::{Connection, OpenFlags}; -use sql_support::{open_database::open_database_with_flags, ConnExt}; +use sql_support::{ConnExt, LazyDb}; use std::path::Path; /// A thread-safe wrapper around an SQLite connection to the Relevancy database pub struct RelevancyDb { - pub conn: Mutex, + reader: LazyDb, + writer: LazyDb, } impl RelevancyDb { - pub fn open(path: impl AsRef) -> Result { - let conn = open_database_with_flags( - path, - OpenFlags::SQLITE_OPEN_URI - | OpenFlags::SQLITE_OPEN_NO_MUTEX - | OpenFlags::SQLITE_OPEN_CREATE - | OpenFlags::SQLITE_OPEN_READ_WRITE, - &RelevancyConnectionInitializer, - )?; - Ok(Self { - conn: Mutex::new(conn), - }) + pub fn new(path: impl AsRef) -> Self { + // Note: use `SQLITE_OPEN_READ_WRITE` for both read and write connections. + // Even if we're opening a read connection, we may need to do a write as part of the + // initialization process. + // + // The read-only nature of the connection is enforced by the fact that [RelevancyDb::read] uses a + // shared ref to the `RelevancyDao`. + let db_open_flags = OpenFlags::SQLITE_OPEN_URI + | OpenFlags::SQLITE_OPEN_NO_MUTEX + | OpenFlags::SQLITE_OPEN_CREATE + | OpenFlags::SQLITE_OPEN_READ_WRITE; + Self { + reader: LazyDb::new(path.as_ref(), db_open_flags, RelevancyConnectionInitializer), + writer: LazyDb::new(path.as_ref(), db_open_flags, RelevancyConnectionInitializer), + } + } + + pub fn close(&self) { + self.reader.close(true); + self.writer.close(true); + } + + pub fn interrupt(&self) { + self.reader.interrupt(); + self.writer.interrupt(); } #[cfg(test)] - pub fn open_for_test() -> Self { + pub fn new_for_test() -> Self { use std::sync::atomic::{AtomicU32, Ordering}; static COUNTER: AtomicU32 = AtomicU32::new(0); let count = COUNTER.fetch_add(1, Ordering::Relaxed); - Self::open(format!("file:test{count}.sqlite?mode=memory&cache=shared")).unwrap() + Self::new(format!("file:test{count}.sqlite?mode=memory&cache=shared")) } /// Accesses the Suggest database in a transaction for reading. pub fn read(&self, op: impl FnOnce(&RelevancyDao) -> Result) -> Result { - let mut conn = self.conn.lock(); + let (mut conn, scope) = self.reader.lock()?; let tx = conn.transaction()?; - let dao = RelevancyDao::new(&tx); + let dao = RelevancyDao::new(&tx, scope); op(&dao) } /// Accesses the Suggest database in a transaction for reading and writing. pub fn read_write(&self, op: impl FnOnce(&mut RelevancyDao) -> Result) -> Result { - let mut conn = self.conn.lock(); + let (mut conn, scope) = self.writer.lock()?; let tx = conn.transaction()?; - let mut dao = RelevancyDao::new(&tx); + let mut dao = RelevancyDao::new(&tx, scope); let result = op(&mut dao)?; tx.commit()?; Ok(result) @@ -67,11 +81,17 @@ impl RelevancyDb { /// reference (`&mut self`). pub struct RelevancyDao<'a> { pub conn: &'a Connection, + pub scope: SqlInterruptScope, } impl<'a> RelevancyDao<'a> { - fn new(conn: &'a Connection) -> Self { - Self { conn } + fn new(conn: &'a Connection, scope: SqlInterruptScope) -> Self { + Self { conn, scope } + } + + /// Return Err(Interrupted) if we were interrupted + pub fn err_if_interrupted(&self) -> Result<()> { + Ok(self.scope.err_if_interrupted()?) } /// Associate a URL with an interest @@ -98,7 +118,7 @@ impl<'a> RelevancyDao<'a> { ", )?; let interests = stmt.query_and_then((hash,), |row| -> Result { - Ok(row.get::<_, u32>(0)?.into()) + row.get::<_, u32>(0)?.try_into() })?; let mut interest_vec = InterestVector::default(); diff --git a/third_party/rust/relevancy/src/error.rs b/third_party/rust/relevancy/src/error.rs index 93ca7aabaa..1d42ff2c03 100644 --- a/third_party/rust/relevancy/src/error.rs +++ b/third_party/rust/relevancy/src/error.rs @@ -23,6 +23,21 @@ pub enum Error { #[error("Error fetching interest data")] FetchInterestDataError, + + #[error("Interrupted")] + Interrupted(#[from] interrupt_support::Interrupted), + + #[error("Invalid interest code: {0}")] + InvalidInterestCode(u32), + + #[error("Remote Setting Error: {0}")] + RemoteSettingsError(#[from] remote_settings::RemoteSettingsError), + + #[error("Serde Json Error: {0}")] + SerdeJsonError(#[from] serde_json::Error), + + #[error("Base64 Decode Error: {0}")] + Base64DecodeError(String), } /// Result enum for the public API diff --git a/third_party/rust/relevancy/src/ingest.rs b/third_party/rust/relevancy/src/ingest.rs new file mode 100644 index 0000000000..dc01fbe019 --- /dev/null +++ b/third_party/rust/relevancy/src/ingest.rs @@ -0,0 +1,394 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::db::RelevancyDao; +use crate::rs::{ + RelevancyAttachmentData, RelevancyRecord, RelevancyRemoteSettingsClient, + REMOTE_SETTINGS_COLLECTION, +}; +use crate::url_hash::UrlHash; +use crate::{Error, Interest, RelevancyDb, Result}; +use base64::{engine::general_purpose::STANDARD, Engine}; +use remote_settings::{Client, RemoteSettingsConfig, RemoteSettingsRecord, RemoteSettingsServer}; + +// Number of rows to write when inserting interest data before checking for interruption +const WRITE_CHUNK_SIZE: usize = 100; + +pub fn ensure_interest_data_populated(db: &RelevancyDb) -> Result<()> { + if !db.read(|dao| dao.need_to_load_url_interests())? { + return Ok(()); + } + + match fetch_interest_data() { + Ok(data) => { + db.read_write(move |dao| insert_interest_data(data, dao))?; + } + Err(e) => { + log::warn!("error fetching interest data: {e}"); + return Err(Error::FetchInterestDataError); + } + } + Ok(()) +} + +fn fetch_interest_data() -> Result> { + let rs = Client::new(RemoteSettingsConfig { + collection_name: REMOTE_SETTINGS_COLLECTION.to_string(), + server: Some(RemoteSettingsServer::Prod), + server_url: None, + bucket_name: None, + })?; + fetch_interest_data_inner(rs) +} + +/// Fetch the interest data +fn fetch_interest_data_inner( + rs: impl RelevancyRemoteSettingsClient, +) -> Result> { + let remote_settings_response = rs.get_records()?; + let mut result = vec![]; + + for record in remote_settings_response.records { + let attachment_data = match &record.attachment { + None => return Err(Error::FetchInterestDataError), + Some(a) => rs.get_attachment(&a.location)?, + }; + let interest = get_interest(&record)?; + let urls = get_hash_urls(attachment_data)?; + result.extend(std::iter::repeat(interest).zip(urls)); + } + Ok(result) +} + +fn get_hash_urls(attachment_data: Vec) -> Result> { + let mut hash_urls = vec![]; + + let parsed_attachment_data = + serde_json::from_slice::>(&attachment_data)?; + + for attachment_data in parsed_attachment_data { + let hash_url = STANDARD + .decode(attachment_data.domain) + .map_err(|_| Error::Base64DecodeError("Invalid base64 error".to_string()))?; + let url_hash = hash_url.try_into().map_err(|_| { + Error::Base64DecodeError("Base64 string has wrong number of bytes".to_string()) + })?; + hash_urls.push(url_hash); + } + Ok(hash_urls) +} + +/// Extract Interest from the record info +fn get_interest(record: &RemoteSettingsRecord) -> Result { + let record_fields: RelevancyRecord = + serde_json::from_value(serde_json::Value::Object(record.fields.clone()))?; + let custom_details = record_fields.record_custom_details; + let category_code = custom_details.category_to_domains.category_code; + Interest::try_from(category_code as u32) +} + +/// Insert Interests into Db +fn insert_interest_data(data: Vec<(Interest, UrlHash)>, dao: &mut RelevancyDao) -> Result<()> { + for chunk in data.chunks(WRITE_CHUNK_SIZE) { + dao.err_if_interrupted()?; + for (interest, hash_url) in chunk { + dao.add_url_interest(*hash_url, *interest)?; + } + } + + Ok(()) +} + +#[cfg(test)] +mod test { + + use std::{cell::RefCell, collections::HashMap}; + + use anyhow::Context; + use remote_settings::RemoteSettingsResponse; + use serde_json::json; + + use super::*; + use crate::{rs::RelevancyRemoteSettingsClient, url_hash::hash_url, InterestVector}; + + /// A snapshot containing fake Remote Settings records and attachments for + /// the store to ingest. We use snapshots to test the store's behavior in a + /// data-driven way. + struct Snapshot { + records: Vec, + attachments: HashMap<&'static str, Vec>, + } + + impl Snapshot { + /// Creates a snapshot from a JSON value that represents a collection of + /// Relevancy Remote Settings records. + /// + /// You can use the [`serde_json::json!`] macro to construct the JSON + /// value, then pass it to this function. It's easier to use the + /// `Snapshot::with_records(json!(...))` idiom than to construct the + /// records by hand. + fn with_records(value: serde_json::Value) -> anyhow::Result { + Ok(Self { + records: serde_json::from_value(value) + .context("Couldn't create snapshot with Remote Settings records")?, + attachments: HashMap::new(), + }) + } + + /// Adds a data attachment to the snapshot. + fn with_data( + mut self, + location: &'static str, + value: serde_json::Value, + ) -> anyhow::Result { + self.attachments.insert( + location, + serde_json::to_vec(&value).context("Couldn't add data attachment to snapshot")?, + ); + Ok(self) + } + } + + /// A fake Remote Settings client that returns records and attachments from + /// a snapshot. + struct SnapshotSettingsClient { + /// The current snapshot. You can modify it using + /// [`RefCell::borrow_mut()`] to simulate remote updates in tests. + snapshot: RefCell, + } + + impl SnapshotSettingsClient { + /// Creates a client with an initial snapshot. + fn with_snapshot(snapshot: Snapshot) -> Self { + Self { + snapshot: RefCell::new(snapshot), + } + } + } + + impl RelevancyRemoteSettingsClient for SnapshotSettingsClient { + fn get_records(&self) -> Result { + let records = self.snapshot.borrow().records.clone(); + let last_modified = records + .iter() + .map(|record: &RemoteSettingsRecord| record.last_modified) + .max() + .unwrap_or(0); + Ok(RemoteSettingsResponse { + records, + last_modified, + }) + } + + fn get_attachment(&self, location: &str) -> Result> { + Ok(self + .snapshot + .borrow() + .attachments + .get(location) + .unwrap_or_else(|| unreachable!("Unexpected request for attachment `{}`", location)) + .clone()) + } + } + + #[test] + fn test_interest_vectors() { + let db = RelevancyDb::new_for_test(); + db.read_write(|dao| { + // Test that the interest data matches the values we started from in + // `bin/generate-test-data.rs` + + dao.add_url_interest(hash_url("https://espn.com").unwrap(), Interest::Sports)?; + dao.add_url_interest(hash_url("https://dogs.com").unwrap(), Interest::Animals)?; + dao.add_url_interest(hash_url("https://cars.com").unwrap(), Interest::Autos)?; + dao.add_url_interest( + hash_url("https://www.vouge.com").unwrap(), + Interest::Fashion, + )?; + dao.add_url_interest(hash_url("https://slashdot.org").unwrap(), Interest::Tech)?; + dao.add_url_interest(hash_url("https://www.nascar.com").unwrap(), Interest::Autos)?; + dao.add_url_interest( + hash_url("https://www.nascar.com").unwrap(), + Interest::Sports, + )?; + dao.add_url_interest( + hash_url("https://unknown.url").unwrap(), + Interest::Inconclusive, + )?; + + assert_eq!( + dao.get_url_interest_vector("https://espn.com/").unwrap(), + InterestVector { + sports: 1, + ..InterestVector::default() + } + ); + assert_eq!( + dao.get_url_interest_vector("https://dogs.com/").unwrap(), + InterestVector { + animals: 1, + ..InterestVector::default() + } + ); + assert_eq!( + dao.get_url_interest_vector("https://cars.com/").unwrap(), + InterestVector { + autos: 1, + ..InterestVector::default() + } + ); + assert_eq!( + dao.get_url_interest_vector("https://www.vouge.com/") + .unwrap(), + InterestVector { + fashion: 1, + ..InterestVector::default() + } + ); + assert_eq!( + dao.get_url_interest_vector("https://slashdot.org/") + .unwrap(), + InterestVector { + tech: 1, + ..InterestVector::default() + } + ); + assert_eq!( + dao.get_url_interest_vector("https://www.nascar.com/") + .unwrap(), + InterestVector { + autos: 1, + sports: 1, + ..InterestVector::default() + } + ); + assert_eq!( + dao.get_url_interest_vector("https://unknown.url/").unwrap(), + InterestVector { + inconclusive: 1, + ..InterestVector::default() + } + ); + Ok(()) + }) + .unwrap(); + } + + #[test] + fn test_variations_on_the_url() { + let db = RelevancyDb::new_for_test(); + db.read_write(|dao| { + dao.add_url_interest(hash_url("https://espn.com").unwrap(), Interest::Sports)?; + dao.add_url_interest(hash_url("https://nascar.com").unwrap(), Interest::Autos)?; + dao.add_url_interest(hash_url("https://nascar.com").unwrap(), Interest::Sports)?; + + // Different paths/queries should work + assert_eq!( + dao.get_url_interest_vector("https://espn.com/foo/bar/?baz") + .unwrap(), + InterestVector { + sports: 1, + ..InterestVector::default() + } + ); + // Different schemes should too + assert_eq!( + dao.get_url_interest_vector("http://espn.com/").unwrap(), + InterestVector { + sports: 1, + ..InterestVector::default() + } + ); + // But changes to the domain shouldn't + assert_eq!( + dao.get_url_interest_vector("http://espn2.com/").unwrap(), + InterestVector::default() + ); + // However, extra components past the 2nd one in the domain are ignored + assert_eq!( + dao.get_url_interest_vector("https://www.nascar.com/") + .unwrap(), + InterestVector { + autos: 1, + sports: 1, + ..InterestVector::default() + } + ); + Ok(()) + }) + .unwrap(); + } + + #[test] + fn test_parse_records() -> anyhow::Result<()> { + let snapshot = Snapshot::with_records(json!([{ + "id": "animals-0001", + "last_modified": 15, + "type": "category_to_domains", + "attachment": { + "filename": "data-1.json", + "mimetype": "application/json", + "location": "data-1.json", + "hash": "", + "size": 0 + }, + "record_custom_details": { + "category_to_domains": { + "category": "animals", + "category_code": 1, + "version": 1 + } + } + }]))? + .with_data( + "data-1.json", + json!([ + {"domain": "J2jtyjQtYQ/+/p//xhz43Q=="}, + {"domain": "Zd4awCwGZLkat59nIWje3g=="}]), + )?; + let rs_client = SnapshotSettingsClient::with_snapshot(snapshot); + assert_eq!( + fetch_interest_data_inner(rs_client).unwrap(), + vec![ + (Interest::Animals, hash_url("https://dogs.com").unwrap()), + (Interest::Animals, hash_url("https://cats.com").unwrap()) + ] + ); + + Ok(()) + } + + #[test] + fn test_parse_records_with_bad_domain_strings() -> anyhow::Result<()> { + let snapshot = Snapshot::with_records(json!([{ + "id": "animals-0001", + "last_modified": 15, + "type": "category_to_domains", + "attachment": { + "filename": "data-1.json", + "mimetype": "application/json", + "location": "data-1.json", + "hash": "", + "size": 0 + }, + "record_custom_details": { + "category_to_domains": { + "category": "animals", + "category_code": 1, + "version": 1 + } + } + }]))? + .with_data( + "data-1.json", + json!([ + {"domain": "badString"}, + {"domain": "notBase64"}]), + )?; + let rs_client = SnapshotSettingsClient::with_snapshot(snapshot); + fetch_interest_data_inner(rs_client).expect_err("Invalid base64 error"); + + Ok(()) + } +} diff --git a/third_party/rust/relevancy/src/interest.rs b/third_party/rust/relevancy/src/interest.rs index 0573c743fc..797df11236 100644 --- a/third_party/rust/relevancy/src/interest.rs +++ b/third_party/rust/relevancy/src/interest.rs @@ -2,32 +2,37 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use crate::Error; + /// List of possible interests for a domain. Domains can have be associated with one or multiple /// interests. `Inconclusive` is used for domains in the user's top sites that we can't classify /// because there's no corresponding entry in the interest database. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(u32)] pub enum Interest { - Animals, - Arts, - Autos, - Business, - Career, - Education, - Fashion, - Finance, - Food, - Government, - Health, - Hobbies, - Home, - News, - RealEstate, - Society, - Sports, - Tech, - Travel, - Inconclusive, + // Note: if you change these codes, make sure to update the `TryFrom` implementation and + // the `test_interest_code_conversion` test. + Inconclusive = 0, + Animals = 1, + Arts = 2, + Autos = 3, + Business = 4, + Career = 5, + Education = 6, + Fashion = 7, + Finance = 8, + Food = 9, + Government = 10, + //Disable this per policy consultation + // Health = 11, + Hobbies = 12, + Home = 13, + News = 14, + RealEstate = 15, + Society = 16, + Sports = 17, + Tech = 18, + Travel = 19, } impl From for u32 { @@ -42,22 +47,44 @@ impl From for usize { } } -impl From for Interest { - fn from(code: u32) -> Self { - if code as usize > Self::COUNT { - panic!("Invalid interest code: {code}") +impl TryFrom for Interest { + // On error, return the invalid code back + type Error = Error; + + fn try_from(code: u32) -> Result { + match code { + 0 => Ok(Self::Inconclusive), + 1 => Ok(Self::Animals), + 2 => Ok(Self::Arts), + 3 => Ok(Self::Autos), + 4 => Ok(Self::Business), + 5 => Ok(Self::Career), + 6 => Ok(Self::Education), + 7 => Ok(Self::Fashion), + 8 => Ok(Self::Finance), + 9 => Ok(Self::Food), + 10 => Ok(Self::Government), + //Disable this per policy consultation + // 11 => Ok(Self::Health), + 12 => Ok(Self::Hobbies), + 13 => Ok(Self::Home), + 14 => Ok(Self::News), + 15 => Ok(Self::RealEstate), + 16 => Ok(Self::Society), + 17 => Ok(Self::Sports), + 18 => Ok(Self::Tech), + 19 => Ok(Self::Travel), + n => Err(Error::InvalidInterestCode(n)), } - // Safety: This is safe since Interest has a u32 representation and we've done a bounds - // check - unsafe { std::mem::transmute(code) } } } impl Interest { - const COUNT: usize = 20; + const COUNT: usize = 19; pub fn all() -> [Interest; Self::COUNT] { [ + Self::Inconclusive, Self::Animals, Self::Arts, Self::Autos, @@ -68,7 +95,7 @@ impl Interest { Self::Finance, Self::Food, Self::Government, - Self::Health, + // Self::Health, Self::Hobbies, Self::Home, Self::News, @@ -77,7 +104,6 @@ impl Interest { Self::Sports, Self::Tech, Self::Travel, - Self::Inconclusive, ] } } @@ -88,6 +114,7 @@ impl Interest { /// number of elements. #[derive(Debug, Default, PartialEq, Eq)] pub struct InterestVector { + pub inconclusive: u32, pub animals: u32, pub arts: u32, pub autos: u32, @@ -98,7 +125,7 @@ pub struct InterestVector { pub finance: u32, pub food: u32, pub government: u32, - pub health: u32, + // pub health: u32, pub hobbies: u32, pub home: u32, pub news: u32, @@ -107,7 +134,34 @@ pub struct InterestVector { pub sports: u32, pub tech: u32, pub travel: u32, - pub inconclusive: u32, +} + +impl std::ops::Add for InterestVector { + type Output = Self; + + fn add(self, other: Self) -> Self { + Self { + inconclusive: self.inconclusive + other.inconclusive, + animals: self.animals + other.animals, + arts: self.arts + other.arts, + autos: self.autos + other.autos, + business: self.business + other.business, + career: self.career + other.career, + education: self.education + other.education, + fashion: self.fashion + other.fashion, + finance: self.finance + other.finance, + food: self.food + other.food, + government: self.government + other.government, + hobbies: self.hobbies + other.hobbies, + home: self.home + other.home, + news: self.news + other.news, + real_estate: self.real_estate + other.real_estate, + society: self.society + other.society, + sports: self.sports + other.sports, + tech: self.tech + other.tech, + travel: self.travel + other.travel, + } + } } impl std::ops::Index for InterestVector { @@ -115,6 +169,7 @@ impl std::ops::Index for InterestVector { fn index(&self, index: Interest) -> &u32 { match index { + Interest::Inconclusive => &self.inconclusive, Interest::Animals => &self.animals, Interest::Arts => &self.arts, Interest::Autos => &self.autos, @@ -125,7 +180,7 @@ impl std::ops::Index for InterestVector { Interest::Finance => &self.finance, Interest::Food => &self.food, Interest::Government => &self.government, - Interest::Health => &self.health, + // Interest::Health => &self.health, Interest::Hobbies => &self.hobbies, Interest::Home => &self.home, Interest::News => &self.news, @@ -134,7 +189,6 @@ impl std::ops::Index for InterestVector { Interest::Sports => &self.sports, Interest::Tech => &self.tech, Interest::Travel => &self.travel, - Interest::Inconclusive => &self.inconclusive, } } } @@ -142,6 +196,7 @@ impl std::ops::Index for InterestVector { impl std::ops::IndexMut for InterestVector { fn index_mut(&mut self, index: Interest) -> &mut u32 { match index { + Interest::Inconclusive => &mut self.inconclusive, Interest::Animals => &mut self.animals, Interest::Arts => &mut self.arts, Interest::Autos => &mut self.autos, @@ -152,7 +207,7 @@ impl std::ops::IndexMut for InterestVector { Interest::Finance => &mut self.finance, Interest::Food => &mut self.food, Interest::Government => &mut self.government, - Interest::Health => &mut self.health, + // Interest::Health => &mut self.health, Interest::Hobbies => &mut self.hobbies, Interest::Home => &mut self.home, Interest::News => &mut self.news, @@ -161,7 +216,32 @@ impl std::ops::IndexMut for InterestVector { Interest::Sports => &mut self.sports, Interest::Tech => &mut self.tech, Interest::Travel => &mut self.travel, - Interest::Inconclusive => &mut self.inconclusive, } } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_interest_code_conversion() { + for interest in Interest::all() { + assert_eq!(Interest::try_from(u32::from(interest)).unwrap(), interest) + } + // try_from() for out of bounds codes should return an error + assert!(matches!( + Interest::try_from(20), + Err(Error::InvalidInterestCode(20)) + )); + assert!(matches!( + Interest::try_from(100), + Err(Error::InvalidInterestCode(100)) + )); + // Health is currently disabled, so it's code should return None for now + assert!(matches!( + Interest::try_from(11), + Err(Error::InvalidInterestCode(11)) + )); + } +} diff --git a/third_party/rust/relevancy/src/lib.rs b/third_party/rust/relevancy/src/lib.rs index 157a26277e..4bc774a261 100644 --- a/third_party/rust/relevancy/src/lib.rs +++ b/third_party/rust/relevancy/src/lib.rs @@ -11,8 +11,9 @@ mod db; mod error; +mod ingest; mod interest; -mod populate_interests; +mod rs; mod schema; pub mod url_hash; @@ -28,11 +29,18 @@ pub struct RelevancyStore { /// Top-level API for the Relevancy component impl RelevancyStore { - #[handle_error(Error)] - pub fn new(db_path: String) -> ApiResult { - Ok(Self { - db: RelevancyDb::open(db_path)?, - }) + pub fn new(db_path: String) -> Self { + Self { + db: RelevancyDb::new(db_path), + } + } + + pub fn close(&self) { + self.db.close() + } + + pub fn interrupt(&self) { + self.db.interrupt() } /// Ingest top URLs to build the user's interest vector. @@ -47,9 +55,21 @@ impl RelevancyStore { /// /// This method may execute for a long time and should only be called from a worker thread. #[handle_error(Error)] - pub fn ingest(&self, _top_urls_by_frecency: Vec) -> ApiResult<()> { - populate_interests::ensure_interest_data_populated(&self.db)?; - todo!() + pub fn ingest(&self, top_urls_by_frecency: Vec) -> ApiResult { + ingest::ensure_interest_data_populated(&self.db)?; + self.classify(top_urls_by_frecency) + } + + pub fn classify(&self, top_urls_by_frecency: Vec) -> Result { + // For experimentation purposes we are going to return an interest vector. + // Eventually we would want to store this data in the DB and incrementally update it. + let mut interest_vector = InterestVector::default(); + for url in top_urls_by_frecency { + let interest_count = self.db.read(|dao| dao.get_url_interest_vector(&url))?; + interest_vector = interest_vector + interest_count; + } + + Ok(interest_vector) } /// Calculate metrics for the validation phase @@ -79,3 +99,45 @@ pub struct InterestMetrics { } uniffi::include_scaffolding!("relevancy"); + +#[cfg(test)] +mod test { + use crate::url_hash::hash_url; + + use super::*; + + #[test] + fn test_ingest() { + let top_urls = vec![ + "https://food.com/".to_string(), + "https://hello.com".to_string(), + "https://pasta.com".to_string(), + "https://dog.com".to_string(), + ]; + let relevancy_store = + RelevancyStore::new("file:test_store_data?mode=memory&cache=shared".to_owned()); + relevancy_store + .db + .read_write(|dao| { + dao.add_url_interest(hash_url("https://food.com").unwrap(), Interest::Food)?; + dao.add_url_interest( + hash_url("https://hello.com").unwrap(), + Interest::Inconclusive, + )?; + dao.add_url_interest(hash_url("https://pasta.com").unwrap(), Interest::Food)?; + dao.add_url_interest(hash_url("https://dog.com").unwrap(), Interest::Animals)?; + Ok(()) + }) + .expect("Insert should succeed"); + + assert_eq!( + relevancy_store.ingest(top_urls).unwrap(), + InterestVector { + inconclusive: 1, + animals: 1, + food: 2, + ..InterestVector::default() + } + ); + } +} diff --git a/third_party/rust/relevancy/src/populate_interests.rs b/third_party/rust/relevancy/src/populate_interests.rs deleted file mode 100644 index e33b677dd6..0000000000 --- a/third_party/rust/relevancy/src/populate_interests.rs +++ /dev/null @@ -1,157 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use crate::{url_hash::UrlHash, Error, Interest, RelevancyDb, Result}; -use std::io::{Cursor, Read}; - -pub fn ensure_interest_data_populated(db: &RelevancyDb) -> Result<()> { - if !db.read(|dao| dao.need_to_load_url_interests())? { - return Ok(()); - } - let interest_data = match fetch_interest_data() { - Ok(data) => data, - Err(e) => { - log::warn!("error fetching interest data: {e}"); - return Err(Error::FetchInterestDataError); - } - }; - db.read_write(move |dao| { - for (url_hash, interest) in interest_data { - dao.add_url_interest(url_hash, interest)?; - } - Ok(()) - }) -} - -/// Fetch the interest data -fn fetch_interest_data() -> std::io::Result> { - // TODO: this hack should be replaced with something that fetches from remote settings - let bytes = include_bytes!("../test-data"); - let mut reader = Cursor::new(&bytes); - let mut data = vec![]; - - // Loop over all possible interests - for interest in Interest::all() { - // read the count - let mut buf = [0u8; 4]; - reader.read_exact(&mut buf)?; - let count = u32::from_le_bytes(buf); - for _ in 0..count { - let mut url_hash: UrlHash = [0u8; 16]; - reader.read_exact(&mut url_hash)?; - data.push((url_hash, interest)); - } - } - Ok(data) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::InterestVector; - - #[test] - fn test_interest_vectors() { - let db = RelevancyDb::open_for_test(); - ensure_interest_data_populated(&db).unwrap(); - db.read(|dao| { - // Test that the interest data matches the values we started from in - // `bin/generate-test-data.rs` - assert_eq!( - dao.get_url_interest_vector("https://espn.com/").unwrap(), - InterestVector { - sports: 1, - ..InterestVector::default() - } - ); - assert_eq!( - dao.get_url_interest_vector("https://dogs.com/").unwrap(), - InterestVector { - animals: 1, - ..InterestVector::default() - } - ); - assert_eq!( - dao.get_url_interest_vector("https://cars.com/").unwrap(), - InterestVector { - autos: 1, - ..InterestVector::default() - } - ); - assert_eq!( - dao.get_url_interest_vector("https://www.vouge.com/") - .unwrap(), - InterestVector { - fashion: 1, - ..InterestVector::default() - } - ); - assert_eq!( - dao.get_url_interest_vector("https://slashdot.org/") - .unwrap(), - InterestVector { - tech: 1, - ..InterestVector::default() - } - ); - assert_eq!( - dao.get_url_interest_vector("https://www.nascar.com/") - .unwrap(), - InterestVector { - autos: 1, - sports: 1, - ..InterestVector::default() - } - ); - assert_eq!( - dao.get_url_interest_vector("https://unknown.url/").unwrap(), - InterestVector::default() - ); - Ok(()) - }) - .unwrap(); - } - - #[test] - fn test_variations_on_the_url() { - let db = RelevancyDb::open_for_test(); - ensure_interest_data_populated(&db).unwrap(); - db.read(|dao| { - // Different paths/queries should work - assert_eq!( - dao.get_url_interest_vector("https://espn.com/foo/bar/?baz") - .unwrap(), - InterestVector { - sports: 1, - ..InterestVector::default() - } - ); - // Different schemes should too - assert_eq!( - dao.get_url_interest_vector("http://espn.com/").unwrap(), - InterestVector { - sports: 1, - ..InterestVector::default() - } - ); - // But changes to the domain shouldn't - assert_eq!( - dao.get_url_interest_vector("http://www.espn.com/").unwrap(), - InterestVector::default() - ); - // However, extra components past the 3rd one in the domain are ignored - assert_eq!( - dao.get_url_interest_vector("https://foo.www.nascar.com/") - .unwrap(), - InterestVector { - autos: 1, - sports: 1, - ..InterestVector::default() - } - ); - Ok(()) - }) - .unwrap(); - } -} diff --git a/third_party/rust/relevancy/src/relevancy.udl b/third_party/rust/relevancy/src/relevancy.udl index e07243ec28..ba9eb09969 100644 --- a/third_party/rust/relevancy/src/relevancy.udl +++ b/third_party/rust/relevancy/src/relevancy.udl @@ -8,12 +8,21 @@ interface RelevancyApiError { // Top-level class for the Relevancy component interface RelevancyStore { // Construct a new RelevancyStore - [Throws=RelevancyApiError] + // + // This is non-blocking since databases and other resources are lazily opened. constructor(string dbpath); + // Close any open resources (for example databases) + // + // Calling `close` will interrupt any in-progress queries on other threads. + void close(); + + // Interrupt any current database queries + void interrupt(); + // Ingest the top URLs by frequency to build up the user's interest vector [Throws=RelevancyApiError] - void ingest(sequence top_urls); + InterestVector ingest(sequence top_urls); // Calculate metrics for the user's interest vector in order to measure how strongly we're // identifying interests. See the `InterestMetrics` struct for details. @@ -39,7 +48,7 @@ enum Interest { "Finance", "Food", "Government", - "Health", + // "Health", "Hobbies", "Home", "News", @@ -93,7 +102,7 @@ dictionary InterestVector { u32 finance; u32 food; u32 government; - u32 health; + // u32 health; u32 hobbies; u32 home; u32 news; diff --git a/third_party/rust/relevancy/src/rs.rs b/third_party/rust/relevancy/src/rs.rs new file mode 100644 index 0000000000..bc8cc938e8 --- /dev/null +++ b/third_party/rust/relevancy/src/rs.rs @@ -0,0 +1,60 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +use crate::Result; +use remote_settings::RemoteSettingsResponse; +use serde::Deserialize; +/// The Remote Settings collection name. +pub(crate) const REMOTE_SETTINGS_COLLECTION: &str = "content-relevance"; + +/// A trait for a client that downloads records from Remote Settings. +/// +/// This trait lets tests use a mock client. +pub(crate) trait RelevancyRemoteSettingsClient { + /// Fetches records from the Suggest Remote Settings collection. + fn get_records(&self) -> Result; + + /// Fetches a record's attachment from the Suggest Remote Settings + /// collection. + fn get_attachment(&self, location: &str) -> Result>; +} + +impl RelevancyRemoteSettingsClient for remote_settings::Client { + fn get_records(&self) -> Result { + Ok(remote_settings::Client::get_records(self)?) + } + + fn get_attachment(&self, location: &str) -> Result> { + Ok(remote_settings::Client::get_attachment(self, location)?) + } +} + +/// A record in the Relevancy Remote Settings collection. +#[derive(Clone, Debug, Deserialize)] +pub struct RelevancyRecord { + #[serde(rename = "type")] + pub record_type: String, + pub record_custom_details: RecordCustomDetails, +} + +// Custom details related to category of the record. +#[derive(Clone, Debug, Deserialize)] +pub struct RecordCustomDetails { + pub category_to_domains: CategoryToDomains, +} + +/// Category information related to the record. +#[derive(Clone, Debug, Deserialize)] +pub struct CategoryToDomains { + pub version: i32, + pub category: String, + pub category_code: i32, +} + +/// A downloaded Remote Settings attachment that contains domain data. +#[derive(Clone, Debug, Deserialize)] +pub struct RelevancyAttachmentData { + pub domain: String, +} diff --git a/third_party/rust/relevancy/src/url_hash.rs b/third_party/rust/relevancy/src/url_hash.rs index d31a45d06b..c010dcaf12 100644 --- a/third_party/rust/relevancy/src/url_hash.rs +++ b/third_party/rust/relevancy/src/url_hash.rs @@ -8,11 +8,10 @@ use url::{Host, Url}; pub type UrlHash = [u8; 16]; /// Given a URL, extract the part of it that we want to use to identify it. -/// -/// We currently use the final 3 components of the URL domain. -/// -/// TODO: decide if this should be 3 or 3 components. pub fn url_hash_source(url: &str) -> Option { + // We currently use the final 2 components of the URL domain. + const URL_COMPONENTS_TO_USE: usize = 2; + let url = Url::parse(url).ok()?; let domain = match url.host() { Some(Host::Domain(d)) => d, @@ -20,7 +19,7 @@ pub fn url_hash_source(url: &str) -> Option { }; // This will store indexes of `.` chars as we search backwards. let mut pos = domain.len(); - for _ in 0..3 { + for _ in 0..URL_COMPONENTS_TO_USE { match domain[0..pos].rfind('.') { Some(p) => pos = p, // The domain has less than 3 dots, return it all @@ -47,12 +46,12 @@ mod test { fn test_url_hash_source() { let table = [ ("http://example.com/some-path", Some("example.com")), - ("http://foo.example.com/some-path", Some("foo.example.com")), + ("http://foo.example.com/some-path", Some("example.com")), ( "http://foo.bar.baz.example.com/some-path", - Some("baz.example.com"), + Some("example.com"), ), - ("http://foo.com.uk/some-path", Some("foo.com.uk")), + ("http://foo.com.uk/some-path", Some("com.uk")), ("http://amazon.com/some-path", Some("amazon.com")), ("http://192.168.0.1/some-path", None), ]; diff --git a/third_party/rust/relevancy/test-data b/third_party/rust/relevancy/test-data index c645914143..46fd850189 100644 Binary files a/third_party/rust/relevancy/test-data and b/third_party/rust/relevancy/test-data differ diff --git a/third_party/rust/remote_settings/.cargo-checksum.json b/third_party/rust/remote_settings/.cargo-checksum.json index 619a9d13ca..96d0e51acd 100644 --- a/third_party/rust/remote_settings/.cargo-checksum.json +++ b/third_party/rust/remote_settings/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"1029f571c66d33c4dfc5e9fc55287a780329ce183f5d2b672de79737155c4227","build.rs":"4326f03729cf8f1673e4228e6dc111de1ea4d8bcc06351f7ae563efb2613f866","src/client.rs":"7510ae0d5bcb9fbaa2c43c4773aa0fd518edc78fe0f396c0e1d6dd442446f429","src/config.rs":"7bb678addfae3b4ed5f2892d32263e5b33cc05e5a12a250f664150e78211f94a","src/error.rs":"192ca42af7c6b882f3129378c23b45dab8a0d2b179e23a8813a335ffd56b21dc","src/lib.rs":"416e99894e152f6cea7418ad2fabfd94bc3d907efd9f33fbd2a83fb99452b2df","src/remote_settings.udl":"2e71491ad3894d17e5bde0663d9490bfea6294d99cdbe9d67a36137faeedc593","uniffi.toml":"f8ec8dc593e0d501c2e9e40368ec93ec33b1edd8608e29495e0a54b63144e880"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"1029f571c66d33c4dfc5e9fc55287a780329ce183f5d2b672de79737155c4227","build.rs":"4326f03729cf8f1673e4228e6dc111de1ea4d8bcc06351f7ae563efb2613f866","src/client.rs":"666ef6536a81b107cdd6047b56ffb53a052c0a615b1fa827e630892c0e528a5d","src/config.rs":"52a209256acd8b1fada2b91e9d9f669df0ee6e9609baad7ec34a2111ed2a6541","src/error.rs":"b0cb36fb105d7ae8a2d8c2e5f98f410c106f1fd45c2e3e9bd8e865c0d2eb8726","src/lib.rs":"655559b1b0f09ad221ceba462ace73d9216a6551d70062126ffc8a085d8b89bb","src/remote_settings.udl":"1ffeb10385e4db63606cda79bb59e77170af1d2ca0028da8ab2c4d7622969734","uniffi.toml":"f8ec8dc593e0d501c2e9e40368ec93ec33b1edd8608e29495e0a54b63144e880"},"package":null} \ No newline at end of file diff --git a/third_party/rust/remote_settings/src/client.rs b/third_party/rust/remote_settings/src/client.rs index 2cf26b7319..601b5c451a 100644 --- a/third_party/rust/remote_settings/src/client.rs +++ b/third_party/rust/remote_settings/src/client.rs @@ -4,7 +4,7 @@ use crate::config::RemoteSettingsConfig; use crate::error::{RemoteSettingsError, Result}; -use crate::UniffiCustomTypeConverter; +use crate::{RemoteSettingsServer, UniffiCustomTypeConverter}; use parking_lot::Mutex; use serde::Deserialize; use std::{ @@ -31,11 +31,17 @@ pub struct Client { impl Client { /// Create a new [Client] with properties matching config. pub fn new(config: RemoteSettingsConfig) -> Result { - let server_url = config - .server_url - .unwrap_or_else(|| String::from("https://firefox.settings.services.mozilla.com")); + let server = match (config.server, config.server_url) { + (Some(server), None) => server, + (None, Some(server_url)) => RemoteSettingsServer::Custom { url: server_url }, + (None, None) => RemoteSettingsServer::Prod, + (Some(_), Some(_)) => Err(RemoteSettingsError::ConfigError( + "`RemoteSettingsConfig` takes either `server` or `server_url`, not both".into(), + ))?, + }; + let bucket_name = config.bucket_name.unwrap_or_else(|| String::from("main")); - let base_url = Url::parse(&server_url)?; + let base_url = server.url()?; Ok(Self { base_url, @@ -519,6 +525,7 @@ mod test { #[test] fn test_defaults() { let config = RemoteSettingsConfig { + server: None, server_url: None, bucket_name: None, collection_name: String::from("the-collection"), @@ -531,6 +538,33 @@ mod test { assert_eq!(String::from("main"), client.bucket_name); } + #[test] + fn test_deprecated_server_url() { + let config = RemoteSettingsConfig { + server: None, + server_url: Some("https://example.com".into()), + bucket_name: None, + collection_name: String::from("the-collection"), + }; + let client = Client::new(config).unwrap(); + assert_eq!(Url::parse("https://example.com").unwrap(), client.base_url); + } + + #[test] + fn test_invalid_config() { + let config = RemoteSettingsConfig { + server: Some(RemoteSettingsServer::Prod), + server_url: Some("https://example.com".into()), + bucket_name: None, + collection_name: String::from("the-collection"), + }; + match Client::new(config) { + Ok(_) => panic!("Wanted config error; got client"), + Err(RemoteSettingsError::ConfigError(_)) => {} + Err(err) => panic!("Wanted config error; got {}", err), + } + } + #[test] fn test_attachment_can_be_downloaded() { viaduct_reqwest::use_reqwest_backend(); @@ -552,7 +586,10 @@ mod test { .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, collection_name: String::from("the-collection"), bucket_name: None, }; @@ -588,7 +625,10 @@ mod test { .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, collection_name: String::from("the-collection"), bucket_name: None, }; @@ -617,7 +657,10 @@ mod test { .with_header("etag", "\"1000\"") .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, collection_name: String::from("the-collection"), bucket_name: Some(String::from("the-bucket")), }; @@ -644,7 +687,10 @@ mod test { .with_header("Retry-After", "60") .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, collection_name: String::from("the-collection"), bucket_name: Some(String::from("the-bucket")), }; @@ -686,7 +732,10 @@ mod test { .with_header("etag", "\"1000\"") .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, collection_name: String::from("the-collection"), bucket_name: Some(String::from("the-bucket")), }; @@ -810,7 +859,10 @@ mod test { .with_header("etag", "\"1000\"") .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, collection_name: String::from("the-collection"), bucket_name: Some(String::from("the-bucket")), }; @@ -850,7 +902,10 @@ mod test { .with_header("etag", "\"1000\"") .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, collection_name: String::from("the-collection"), bucket_name: Some(String::from("the-bucket")), }; @@ -953,7 +1008,10 @@ mod test { .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, bucket_name: Some(String::from("the-bucket")), collection_name: String::from("the-collection"), }; @@ -982,7 +1040,10 @@ mod test { .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, bucket_name: Some(String::from("the-bucket")), collection_name: String::from("the-collection"), }; diff --git a/third_party/rust/remote_settings/src/config.rs b/third_party/rust/remote_settings/src/config.rs index 33fab1b500..d9051d06d0 100644 --- a/third_party/rust/remote_settings/src/config.rs +++ b/third_party/rust/remote_settings/src/config.rs @@ -3,19 +3,45 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! This module defines the custom configurations that consumers can set. -//! Those configurations override default values and can be used to set a custom server url, +//! Those configurations override default values and can be used to set a custom server, //! collection name, and bucket name. //! The purpose of the configuration parameters are to allow consumers an easy debugging option, //! and the ability to be explicit about the server. +use url::Url; + +use crate::Result; + /// Custom configuration for the client. /// Currently includes the following: -/// - `server_url`: The optional url for the settings server. If not specified, the standard server will be used. +/// - `server`: The Remote Settings server to use. If not specified, defaults to the production server (`RemoteSettingsServer::Prod`). +/// - `server_url`: An optional custom Remote Settings server URL. Deprecated; please use `server` instead. /// - `bucket_name`: The optional name of the bucket containing the collection on the server. If not specified, the standard bucket will be used. /// - `collection_name`: The name of the collection for the settings server. #[derive(Debug, Clone)] pub struct RemoteSettingsConfig { + pub server: Option, pub server_url: Option, pub bucket_name: Option, pub collection_name: String, } + +/// The Remote Settings server that the client should use. +#[derive(Debug, Clone)] +pub enum RemoteSettingsServer { + Prod, + Stage, + Dev, + Custom { url: String }, +} + +impl RemoteSettingsServer { + pub fn url(&self) -> Result { + Ok(match self { + Self::Prod => Url::parse("https://firefox.settings.services.mozilla.com").unwrap(), + Self::Stage => Url::parse("https://firefox.settings.services.allizom.org").unwrap(), + Self::Dev => Url::parse("https://remote-settings-dev.allizom.org").unwrap(), + Self::Custom { url } => Url::parse(url)?, + }) + } +} diff --git a/third_party/rust/remote_settings/src/error.rs b/third_party/rust/remote_settings/src/error.rs index 120681871b..32563800f0 100644 --- a/third_party/rust/remote_settings/src/error.rs +++ b/third_party/rust/remote_settings/src/error.rs @@ -22,6 +22,8 @@ pub enum RemoteSettingsError { ResponseError(String), #[error("This server doesn't support attachments")] AttachmentsUnsupportedError, + #[error("Error configuring client: {0}")] + ConfigError(String), } pub type Result = std::result::Result; diff --git a/third_party/rust/remote_settings/src/lib.rs b/third_party/rust/remote_settings/src/lib.rs index 9aa6ecbf1a..9380a3fbc7 100644 --- a/third_party/rust/remote_settings/src/lib.rs +++ b/third_party/rust/remote_settings/src/lib.rs @@ -11,7 +11,7 @@ pub use client::{ RsJsonObject, SortOrder, }; pub mod config; -pub use config::RemoteSettingsConfig; +pub use config::{RemoteSettingsConfig, RemoteSettingsServer}; uniffi::include_scaffolding!("remote_settings"); @@ -70,7 +70,10 @@ mod test { .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, bucket_name: Some(String::from("the-bucket")), collection_name: String::from("the-collection"), }; @@ -98,7 +101,10 @@ mod test { .create(); let config = RemoteSettingsConfig { - server_url: Some(mockito::server_url()), + server: Some(RemoteSettingsServer::Custom { + url: mockito::server_url(), + }), + server_url: None, bucket_name: Some(String::from("the-bucket")), collection_name: String::from("the-collection"), }; @@ -119,7 +125,10 @@ mod test { fn test_download() { viaduct_reqwest::use_reqwest_backend(); let config = RemoteSettingsConfig { - server_url: Some("http://localhost:8888".to_string()), + server: Some(RemoteSettingsServer::Custom { + url: "http://localhost:8888".into(), + }), + server_url: None, bucket_name: Some(String::from("the-bucket")), collection_name: String::from("the-collection"), }; diff --git a/third_party/rust/remote_settings/src/remote_settings.udl b/third_party/rust/remote_settings/src/remote_settings.udl index d830b6778f..1da52b833e 100644 --- a/third_party/rust/remote_settings/src/remote_settings.udl +++ b/third_party/rust/remote_settings/src/remote_settings.udl @@ -7,10 +7,19 @@ typedef string RsJsonObject; namespace remote_settings {}; +[Enum] +interface RemoteSettingsServer { + Prod(); + Stage(); + Dev(); + Custom(string url); +}; + dictionary RemoteSettingsConfig { string collection_name; string? bucket_name = null; string? server_url = null; + RemoteSettingsServer? server = null; }; dictionary RemoteSettingsResponse { @@ -43,6 +52,7 @@ enum RemoteSettingsError { "BackoffError", "ResponseError", "AttachmentsUnsupportedError", + "ConfigError", }; interface RemoteSettings { diff --git a/third_party/rust/serde/.cargo-checksum.json b/third_party/rust/serde/.cargo-checksum.json index d55068bd63..65bca8af82 100644 --- a/third_party/rust/serde/.cargo-checksum.json +++ b/third_party/rust/serde/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f03b626efae73a6dd42f07d722dad2da3a4add51f4e653e30a6d696853bab209","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"731c044fc5f98b37a89e9049c9214267db98763309cb63146b45c029640f82a3","build.rs":"f9ba30324b9ce085c903595fb55a5293f8c2348ff36bfe870521b935ae6d105c","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/de/format.rs":"c85071b016df643b161859682d21ce34fa0ebf2a3bdbeeea69859da48f5d934f","src/de/ignored_any.rs":"6480f2b2a83dc4764d01b2eec7309729eef2492eede2e5ee98d23a60b05198eb","src/de/impls.rs":"2857d734176a0b78a41c9358354b0b0b83c6b2d948590be072d98606a8cae9d6","src/de/mod.rs":"fc34da49f692803d2c2f131322d9b48ad8e4f39ed10b2b304d6193ab09d621fb","src/de/seed.rs":"045d890712a04eb33ffc5a021e5d948a63c89402b8ffeea749df2171b7484f8f","src/de/size_hint.rs":"fff83dc39d30e75e8e611991f9c5399188a1aad23a6462dbca2c8b62655cfedb","src/de/value.rs":"0fd511a288c20a1b768718f4baadf9c7d4146d276af6a71ba1d0f7679b28644a","src/integer128.rs":"29ef30b7d94507b34807090e68173767cdc7aff62edccd38affe69e75338dddc","src/lib.rs":"638b231a280519f1861ea5f1bfbe97e2394b2f7662a9701b8e57ed95093dd298","src/macros.rs":"e3486ef4a9a4ed1b27234aa1817ccb25ec0eb026ffc95e2c71c7b917f1f45629","src/private/de.rs":"6557a124fdaf61f9c7cd80163e40f4a453354e45b63a4eb55dafdfe0159f6881","src/private/doc.rs":"9ad740e9ea2eedf861b77116eda9a6fb74bc8553541cd17d1bc5791a3ef3271a","src/private/mod.rs":"b8f0c348621d91dd9da3db83d8877e70bc61ad0a2dc2d6fb57c6fc2c2cbafa26","src/private/ser.rs":"656613691bd8d40cb70a52d4ebe3ee96a993c8a1292d50822d9ca5bdad84426b","src/ser/fmt.rs":"77a5583e5c227ea1982b097ed6378af5c899d43761d71e33440262fd35944695","src/ser/impls.rs":"850619164b399c37cd373d24f5a2c83453f40b34bb978c5722d2c1ae226775b5","src/ser/impossible.rs":"e11b37689ec1395378d546fce74221ca9046d0761744301f12029102fd07e30e","src/ser/mod.rs":"a7fd082203d63cbe4f0fe86d9be16bf4f3b2444653dac6bb61d82e0f4f6b4214","src/std_error.rs":"25a07149e2e468747ffa5a58051c7f93d7b3c0fa0372f012a96c97ec8ab03b97"},"package":"3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"} \ No newline at end of file +{"files":{"Cargo.toml":"fcf211f4e710da1375e944a42621a8cd3de8d683db3e464ab570652216015d87","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"731c044fc5f98b37a89e9049c9214267db98763309cb63146b45c029640f82a3","build.rs":"56b4f43d4061c03fbdd4f6325f30439686b12679bace304223d30c03632a925e","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/de/format.rs":"c85071b016df643b161859682d21ce34fa0ebf2a3bdbeeea69859da48f5d934f","src/de/ignored_any.rs":"6480f2b2a83dc4764d01b2eec7309729eef2492eede2e5ee98d23a60b05198eb","src/de/impls.rs":"cd2781405d8f4568701a701e6b9946e5956eb201571118c8a49038928477779a","src/de/mod.rs":"2be26b699feb8cc0c7f573d58fc11bb92d0b7bd1063bf8fcbd0e71d60f53c99a","src/de/seed.rs":"045d890712a04eb33ffc5a021e5d948a63c89402b8ffeea749df2171b7484f8f","src/de/size_hint.rs":"fff83dc39d30e75e8e611991f9c5399188a1aad23a6462dbca2c8b62655cfedb","src/de/value.rs":"0fd511a288c20a1b768718f4baadf9c7d4146d276af6a71ba1d0f7679b28644a","src/integer128.rs":"29ef30b7d94507b34807090e68173767cdc7aff62edccd38affe69e75338dddc","src/lib.rs":"0e4c06f18a0f2e46d60f54f463e906bf1ba1330ef9820a12173fd28a91b9fcde","src/macros.rs":"e3486ef4a9a4ed1b27234aa1817ccb25ec0eb026ffc95e2c71c7b917f1f45629","src/private/de.rs":"9255ecf2d5c52f0f52b4e0dbf85bdd8c140bc2c1ac96086ee395589e0521aeb4","src/private/doc.rs":"b222decb40321190155209e1b8a5a52e3adfaa470047e379e664b71e0320655a","src/private/mod.rs":"b8f0c348621d91dd9da3db83d8877e70bc61ad0a2dc2d6fb57c6fc2c2cbafa26","src/private/ser.rs":"73577607e779e1b42713c51b9bc7136f99daccf473b4a641c99ceebe46708d47","src/ser/fmt.rs":"d1cfd9623605413e45a23ef778d97f0ac4da4adaed23739f1f9d7414b30e384b","src/ser/impls.rs":"0eebc159f7d3962c46c323e456afb679747ff57563e796c5fd92c64ed074ae70","src/ser/impossible.rs":"5c325da8e0370ab22abe1e15d8af1dc7a1707b127508f61e720cd7f0caa80593","src/ser/mod.rs":"a92d4ce0a6c68eb22a24a61574a5d2e9b0b463b284ff08e62298b8f7ae1a7464","src/std_error.rs":"25a07149e2e468747ffa5a58051c7f93d7b3c0fa0372f012a96c97ec8ab03b97"},"package":"9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"} \ No newline at end of file diff --git a/third_party/rust/serde/Cargo.toml b/third_party/rust/serde/Cargo.toml index 6ba68688ac..b6f335bafd 100644 --- a/third_party/rust/serde/Cargo.toml +++ b/third_party/rust/serde/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" rust-version = "1.31" name = "serde" -version = "1.0.197" +version = "1.0.198" authors = [ "Erick Tryzelaar ", "David Tolnay ", @@ -74,4 +74,4 @@ std = [] unstable = [] [target."cfg(any())".dependencies.serde_derive] -version = "=1.0.197" +version = "=1.0.198" diff --git a/third_party/rust/serde/build.rs b/third_party/rust/serde/build.rs index fe5486a7a5..0074df63f4 100644 --- a/third_party/rust/serde/build.rs +++ b/third_party/rust/serde/build.rs @@ -64,6 +64,12 @@ fn main() { if minor < 64 { println!("cargo:rustc-cfg=no_core_cstr"); } + + // Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74 + // https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis + if minor < 74 { + println!("cargo:rustc-cfg=no_core_num_saturating"); + } } fn rustc_minor_version() -> Option { diff --git a/third_party/rust/serde/src/de/impls.rs b/third_party/rust/serde/src/de/impls.rs index 413c997afd..140878aec6 100644 --- a/third_party/rust/serde/src/de/impls.rs +++ b/third_party/rust/serde/src/de/impls.rs @@ -104,6 +104,28 @@ macro_rules! impl_deserialize_num { deserializer.$deserialize(NonZeroVisitor) } } + + #[cfg(not(no_core_num_saturating))] + impl<'de> Deserialize<'de> for Saturating<$primitive> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SaturatingVisitor; + + impl<'de> Visitor<'de> for SaturatingVisitor { + type Value = Saturating<$primitive>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("integer with support for saturating semantics") + } + + $($($method!(saturating $primitive $val : $visit);)*)* + } + + deserializer.$deserialize(SaturatingVisitor) + } + } }; ($primitive:ident, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => { @@ -154,6 +176,15 @@ macro_rules! num_self { } } }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v)) + } + }; } macro_rules! num_as_self { @@ -179,6 +210,15 @@ macro_rules! num_as_self { } } }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v as $primitive)) + } + }; } macro_rules! num_as_copysign_self { @@ -235,6 +275,21 @@ macro_rules! int_to_int { Err(Error::invalid_value(Unexpected::Signed(v as i64), &self)) } }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if (v as i64) < $primitive::MIN as i64 { + Ok(Saturating($primitive::MIN)) + } else if ($primitive::MAX as i64) < v as i64 { + Ok(Saturating($primitive::MAX)) + } else { + Ok(Saturating(v as $primitive)) + } + } + }; } macro_rules! int_to_uint { @@ -265,6 +320,21 @@ macro_rules! int_to_uint { Err(Error::invalid_value(Unexpected::Signed(v as i64), &self)) } }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if v < 0 { + Ok(Saturating(0)) + } else if ($primitive::MAX as u64) < v as u64 { + Ok(Saturating($primitive::MAX)) + } else { + Ok(Saturating(v as $primitive)) + } + } + }; } macro_rules! uint_to_self { @@ -295,6 +365,19 @@ macro_rules! uint_to_self { Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self)) } }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if v as u64 <= $primitive::MAX as u64 { + Ok(Saturating(v as $primitive)) + } else { + Ok(Saturating($primitive::MAX)) + } + } + }; } impl_deserialize_num! { @@ -427,6 +510,21 @@ macro_rules! num_128 { } } }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if (v as i128) < $primitive::MIN as i128 { + Ok(Saturating($primitive::MIN)) + } else if ($primitive::MAX as u128) < v as u128 { + Ok(Saturating($primitive::MAX)) + } else { + Ok(Saturating(v as $primitive)) + } + } + }; } impl_deserialize_num! { @@ -852,7 +950,10 @@ struct PhantomDataVisitor { marker: PhantomData, } -impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor { +impl<'de, T> Visitor<'de> for PhantomDataVisitor +where + T: ?Sized, +{ type Value = PhantomData; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -868,7 +969,10 @@ impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor { } } -impl<'de, T: ?Sized> Deserialize<'de> for PhantomData { +impl<'de, T> Deserialize<'de> for PhantomData +where + T: ?Sized, +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -1877,9 +1981,9 @@ forwarded_impl! { #[cfg(any(feature = "std", feature = "alloc"))] #[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))] -impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> +impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T> where - T: ToOwned, + T: ?Sized + ToOwned, T::Owned: Deserialize<'de>, { #[inline] @@ -1902,7 +2006,7 @@ where doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) )] -impl<'de, T: ?Sized> Deserialize<'de> for RcWeak +impl<'de, T> Deserialize<'de> for RcWeak where T: Deserialize<'de>, { @@ -1924,7 +2028,7 @@ where doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) )] -impl<'de, T: ?Sized> Deserialize<'de> for ArcWeak +impl<'de, T> Deserialize<'de> for ArcWeak where T: Deserialize<'de>, { @@ -1945,8 +2049,9 @@ macro_rules! box_forwarded_impl { $t:ident ) => { $(#[$attr])* - impl<'de, T: ?Sized> Deserialize<'de> for $t + impl<'de, T> Deserialize<'de> for $t where + T: ?Sized, Box: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result diff --git a/third_party/rust/serde/src/de/mod.rs b/third_party/rust/serde/src/de/mod.rs index 1924fe3d88..4c5a5f9b78 100644 --- a/third_party/rust/serde/src/de/mod.rs +++ b/third_party/rust/serde/src/de/mod.rs @@ -1735,9 +1735,9 @@ pub trait SeqAccess<'de> { } } -impl<'de, 'a, A: ?Sized> SeqAccess<'de> for &'a mut A +impl<'de, 'a, A> SeqAccess<'de> for &'a mut A where - A: SeqAccess<'de>, + A: ?Sized + SeqAccess<'de>, { type Error = A::Error; @@ -1888,9 +1888,9 @@ pub trait MapAccess<'de> { } } -impl<'de, 'a, A: ?Sized> MapAccess<'de> for &'a mut A +impl<'de, 'a, A> MapAccess<'de> for &'a mut A where - A: MapAccess<'de>, + A: ?Sized + MapAccess<'de>, { type Error = A::Error; diff --git a/third_party/rust/serde/src/lib.rs b/third_party/rust/serde/src/lib.rs index 5cf44c1c18..fefbf8fda2 100644 --- a/third_party/rust/serde/src/lib.rs +++ b/third_party/rust/serde/src/lib.rs @@ -95,7 +95,7 @@ //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.197")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.198")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] // Show which crate feature enables conditionally compiled APIs in documentation. @@ -274,6 +274,9 @@ mod lib { pub use std::sync::atomic::{AtomicI64, AtomicU64}; #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))] pub use std::sync::atomic::{AtomicIsize, AtomicUsize}; + + #[cfg(not(no_core_num_saturating))] + pub use self::core::num::Saturating; } // None of this crate's error handling needs the `From::from` error conversion diff --git a/third_party/rust/serde/src/private/de.rs b/third_party/rust/serde/src/private/de.rs index 883e6909c1..c402d2c66a 100644 --- a/third_party/rust/serde/src/private/de.rs +++ b/third_party/rust/serde/src/private/de.rs @@ -313,6 +313,8 @@ mod content { } } + /// Used to capture data in [`Content`] from other deserializers. + /// Cannot capture externally tagged enums, `i128` and `u128`. struct ContentVisitor<'de> { value: PhantomData>, } @@ -528,6 +530,8 @@ mod content { Content(Content<'de>), } + /// Serves as a seed for deserializing a key of internally tagged enum. + /// Cannot capture externally tagged enums, `i128` and `u128`. struct TagOrContentVisitor<'de> { name: &'static str, value: PhantomData>, @@ -814,6 +818,9 @@ mod content { /// Used by generated code to deserialize an internally tagged enum. /// + /// Captures map or sequence from the original deserializer and searches + /// a tag in it (in case of sequence, tag is the first element of sequence). + /// /// Not public API. pub struct TaggedContentVisitor { tag_name: &'static str, diff --git a/third_party/rust/serde/src/private/doc.rs b/third_party/rust/serde/src/private/doc.rs index 1b18fe6b41..1f17c8db53 100644 --- a/third_party/rust/serde/src/private/doc.rs +++ b/third_party/rust/serde/src/private/doc.rs @@ -56,7 +56,10 @@ macro_rules! __serialize_unimplemented { #[macro_export] macro_rules! __serialize_unimplemented_method { ($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => { - fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::__private::Result { + fn $func $(<$t>)* (self $(, _: $arg)*) -> $crate::__private::Result + where + $($t: ?Sized + $crate::Serialize,)* + { unimplemented!() } }; diff --git a/third_party/rust/serde/src/private/ser.rs b/third_party/rust/serde/src/private/ser.rs index 50bcb251e3..40cc6cbdb7 100644 --- a/third_party/rust/serde/src/private/ser.rs +++ b/third_party/rust/serde/src/private/ser.rs @@ -174,9 +174,9 @@ where Err(self.bad_type(Unsupported::Optional)) } - fn serialize_some(self, _: &T) -> Result + fn serialize_some(self, _: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { Err(self.bad_type(Unsupported::Optional)) } @@ -205,18 +205,18 @@ where map.end() } - fn serialize_newtype_struct( + fn serialize_newtype_struct( self, _: &'static str, value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { value.serialize(self) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, _: &'static str, _: u32, @@ -224,7 +224,7 @@ where inner_value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { let mut map = tri!(self.delegate.serialize_map(Some(2))); tri!(map.serialize_entry(self.tag, self.variant_name)); @@ -327,9 +327,9 @@ where } #[cfg(not(any(feature = "std", feature = "alloc")))] - fn collect_str(self, _: &T) -> Result + fn collect_str(self, _: &T) -> Result where - T: Display, + T: ?Sized + Display, { Err(self.bad_type(Unsupported::String)) } @@ -364,9 +364,9 @@ mod content { type Ok = M::Ok; type Error = M::Error; - fn serialize_field(&mut self, value: &T) -> Result<(), M::Error> + fn serialize_field(&mut self, value: &T) -> Result<(), M::Error> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push(value); @@ -404,13 +404,9 @@ mod content { type Ok = M::Ok; type Error = M::Error; - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), M::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), M::Error> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); @@ -635,9 +631,9 @@ mod content { Ok(Content::None) } - fn serialize_some(self, value: &T) -> Result + fn serialize_some(self, value: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { Ok(Content::Some(Box::new(tri!(value.serialize(self))))) } @@ -659,13 +655,9 @@ mod content { Ok(Content::UnitVariant(name, variant_index, variant)) } - fn serialize_newtype_struct( - self, - name: &'static str, - value: &T, - ) -> Result + fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { Ok(Content::NewtypeStruct( name, @@ -673,7 +665,7 @@ mod content { )) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, name: &'static str, variant_index: u32, @@ -681,7 +673,7 @@ mod content { value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { Ok(Content::NewtypeVariant( name, @@ -782,9 +774,9 @@ mod content { type Ok = Content; type Error = E; - fn serialize_element(&mut self, value: &T) -> Result<(), E> + fn serialize_element(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.elements.push(value); @@ -808,9 +800,9 @@ mod content { type Ok = Content; type Error = E; - fn serialize_element(&mut self, value: &T) -> Result<(), E> + fn serialize_element(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.elements.push(value); @@ -835,9 +827,9 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, value: &T) -> Result<(), E> + fn serialize_field(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push(value); @@ -864,9 +856,9 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, value: &T) -> Result<(), E> + fn serialize_field(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push(value); @@ -896,18 +888,18 @@ mod content { type Ok = Content; type Error = E; - fn serialize_key(&mut self, key: &T) -> Result<(), E> + fn serialize_key(&mut self, key: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let key = tri!(key.serialize(ContentSerializer::::new())); self.key = Some(key); Ok(()) } - fn serialize_value(&mut self, value: &T) -> Result<(), E> + fn serialize_value(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let key = self .key @@ -922,10 +914,10 @@ mod content { Ok(Content::Map(self.entries)) } - fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), E> + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), E> where - K: Serialize, - V: Serialize, + K: ?Sized + Serialize, + V: ?Sized + Serialize, { let key = tri!(key.serialize(ContentSerializer::::new())); let value = tri!(value.serialize(ContentSerializer::::new())); @@ -947,9 +939,9 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); @@ -976,9 +968,9 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); @@ -1088,9 +1080,9 @@ where Ok(()) } - fn serialize_some(self, value: &T) -> Result + fn serialize_some(self, value: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { value.serialize(self) } @@ -1112,18 +1104,18 @@ where Err(Self::bad_type(Unsupported::Enum)) } - fn serialize_newtype_struct( + fn serialize_newtype_struct( self, _: &'static str, value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { value.serialize(self) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, _: &'static str, _: u32, @@ -1131,7 +1123,7 @@ where value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { tri!(self.0.serialize_key(variant)); self.0.serialize_value(value) @@ -1202,28 +1194,24 @@ where type Ok = (); type Error = M::Error; - fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { self.0.serialize_key(key) } - fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { self.0.serialize_value(value) } - fn serialize_entry( - &mut self, - key: &K, - value: &V, - ) -> Result<(), Self::Error> + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Self::Error> where - K: Serialize, - V: Serialize, + K: ?Sized + Serialize, + V: ?Sized + Serialize, { self.0.serialize_entry(key, value) } @@ -1244,13 +1232,9 @@ where type Ok = (); type Error = M::Error; - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { self.0.serialize_entry(key, value) } @@ -1289,9 +1273,9 @@ where type Ok = (); type Error = M::Error; - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push(value); @@ -1335,13 +1319,9 @@ where type Ok = (); type Error = M::Error; - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); diff --git a/third_party/rust/serde/src/ser/fmt.rs b/third_party/rust/serde/src/ser/fmt.rs index 0650ab6f12..04684aded0 100644 --- a/third_party/rust/serde/src/ser/fmt.rs +++ b/third_party/rust/serde/src/ser/fmt.rs @@ -74,9 +74,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Display::fmt(variant, self) } - fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> fmt::Result + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> fmt::Result where - T: Serialize, + T: ?Sized + Serialize, { Serialize::serialize(value, self) } @@ -89,9 +89,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Err(fmt::Error) } - fn serialize_some(self, _value: &T) -> fmt::Result + fn serialize_some(self, _value: &T) -> fmt::Result where - T: Serialize, + T: ?Sized + Serialize, { Err(fmt::Error) } @@ -100,7 +100,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Err(fmt::Error) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, @@ -108,7 +108,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { _value: &T, ) -> fmt::Result where - T: Serialize, + T: ?Sized + Serialize, { Err(fmt::Error) } @@ -161,9 +161,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Err(fmt::Error) } - fn collect_str(self, value: &T) -> fmt::Result + fn collect_str(self, value: &T) -> fmt::Result where - T: Display, + T: ?Sized + Display, { Display::fmt(value, self) } diff --git a/third_party/rust/serde/src/ser/impls.rs b/third_party/rust/serde/src/ser/impls.rs index 8c70634af0..ffc4c70f90 100644 --- a/third_party/rust/serde/src/ser/impls.rs +++ b/third_party/rust/serde/src/ser/impls.rs @@ -114,7 +114,10 @@ where //////////////////////////////////////////////////////////////////////////////// -impl Serialize for PhantomData { +impl Serialize for PhantomData +where + T: ?Sized, +{ #[inline] fn serialize(&self, serializer: S) -> Result where @@ -504,17 +507,17 @@ macro_rules! deref_impl { } deref_impl! { - <'a, T: ?Sized> Serialize for &'a T where T: Serialize + <'a, T> Serialize for &'a T where T: ?Sized + Serialize } deref_impl! { - <'a, T: ?Sized> Serialize for &'a mut T where T: Serialize + <'a, T> Serialize for &'a mut T where T: ?Sized + Serialize } deref_impl! { #[cfg(any(feature = "std", feature = "alloc"))] #[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))] - Serialize for Box where T: Serialize + Serialize for Box where T: ?Sized + Serialize } deref_impl! { @@ -528,7 +531,7 @@ deref_impl! { /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] - Serialize for Rc where T: Serialize + Serialize for Rc where T: ?Sized + Serialize } deref_impl! { @@ -542,13 +545,13 @@ deref_impl! { /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] - Serialize for Arc where T: Serialize + Serialize for Arc where T: ?Sized + Serialize } deref_impl! { #[cfg(any(feature = "std", feature = "alloc"))] #[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))] - <'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned + <'a, T> Serialize for Cow<'a, T> where T: ?Sized + Serialize + ToOwned } //////////////////////////////////////////////////////////////////////////////// @@ -561,9 +564,9 @@ deref_impl! { doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) )] -impl Serialize for RcWeak +impl Serialize for RcWeak where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -581,9 +584,9 @@ where doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) )] -impl Serialize for ArcWeak +impl Serialize for ArcWeak where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -641,9 +644,9 @@ where } } -impl Serialize for RefCell +impl Serialize for RefCell where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -658,9 +661,9 @@ where #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] -impl Serialize for Mutex +impl Serialize for Mutex where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -675,9 +678,9 @@ where #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] -impl Serialize for RwLock +impl Serialize for RwLock where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -1023,6 +1026,20 @@ where } } +#[cfg(not(no_core_num_saturating))] +impl Serialize for Saturating +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + impl Serialize for Reverse where T: Serialize, diff --git a/third_party/rust/serde/src/ser/impossible.rs b/third_party/rust/serde/src/ser/impossible.rs index 479be94071..6432d5775a 100644 --- a/third_party/rust/serde/src/ser/impossible.rs +++ b/third_party/rust/serde/src/ser/impossible.rs @@ -72,9 +72,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_element(&mut self, value: &T) -> Result<(), Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -92,9 +92,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_element(&mut self, value: &T) -> Result<(), Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -112,9 +112,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -132,9 +132,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -152,17 +152,17 @@ where type Ok = Ok; type Error = Error; - fn serialize_key(&mut self, key: &T) -> Result<(), Error> + fn serialize_key(&mut self, key: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = key; match self.void {} } - fn serialize_value(&mut self, value: &T) -> Result<(), Error> + fn serialize_value(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -180,9 +180,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = key; let _ = value; @@ -201,9 +201,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = key; let _ = value; diff --git a/third_party/rust/serde/src/ser/mod.rs b/third_party/rust/serde/src/ser/mod.rs index 75c45140e2..74b5e07691 100644 --- a/third_party/rust/serde/src/ser/mod.rs +++ b/third_party/rust/serde/src/ser/mod.rs @@ -796,9 +796,9 @@ pub trait Serializer: Sized { /// ``` /// /// [`Some(T)`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some - fn serialize_some(self, value: &T) -> Result + fn serialize_some(self, value: &T) -> Result where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a `()` value. /// @@ -891,13 +891,13 @@ pub trait Serializer: Sized { /// } /// } /// ``` - fn serialize_newtype_struct( + fn serialize_newtype_struct( self, name: &'static str, value: &T, ) -> Result where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a newtype variant like `E::N` in `enum E { N(u8) }`. /// @@ -925,7 +925,7 @@ pub trait Serializer: Sized { /// } /// } /// ``` - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, name: &'static str, variant_index: u32, @@ -933,7 +933,7 @@ pub trait Serializer: Sized { value: &T, ) -> Result where - T: Serialize; + T: ?Sized + Serialize; /// Begin to serialize a variably sized sequence. This call must be /// followed by zero or more calls to `serialize_element`, then a call to @@ -1170,7 +1170,8 @@ pub trait Serializer: Sized { /// then a call to `end`. /// /// The `name` is the name of the struct and the `len` is the number of - /// data fields that will be serialized. + /// data fields that will be serialized. `len` does not include fields + /// which are skipped with [`SerializeStruct::skip_field`]. /// /// ```edition2021 /// use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -1207,6 +1208,8 @@ pub trait Serializer: Sized { /// The `name` is the name of the enum, the `variant_index` is the index of /// this variant within the enum, the `variant` is the name of the variant, /// and the `len` is the number of data fields that will be serialized. + /// `len` does not include fields which are skipped with + /// [`SerializeStructVariant::skip_field`]. /// /// ```edition2021 /// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; @@ -1346,9 +1349,9 @@ pub trait Serializer: Sized { /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html /// [`serialize_str`]: #tymethod.serialize_str #[cfg(any(feature = "std", feature = "alloc"))] - fn collect_str(self, value: &T) -> Result + fn collect_str(self, value: &T) -> Result where - T: Display, + T: ?Sized + Display, { self.serialize_str(&value.to_string()) } @@ -1379,9 +1382,9 @@ pub trait Serializer: Sized { /// } /// ``` #[cfg(not(any(feature = "std", feature = "alloc")))] - fn collect_str(self, value: &T) -> Result + fn collect_str(self, value: &T) -> Result where - T: Display; + T: ?Sized + Display; /// Determine whether `Serialize` implementations should serialize in /// human-readable form. @@ -1493,9 +1496,9 @@ pub trait SerializeSeq { type Error: Error; /// Serialize a sequence element. - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a sequence. fn end(self) -> Result; @@ -1593,9 +1596,9 @@ pub trait SerializeTuple { type Error: Error; /// Serialize a tuple element. - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a tuple. fn end(self) -> Result; @@ -1638,9 +1641,9 @@ pub trait SerializeTupleStruct { type Error: Error; /// Serialize a tuple struct field. - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a tuple struct. fn end(self) -> Result; @@ -1696,9 +1699,9 @@ pub trait SerializeTupleVariant { type Error: Error; /// Serialize a tuple variant field. - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a tuple variant. fn end(self) -> Result; @@ -1767,9 +1770,9 @@ pub trait SerializeMap { /// `serialize_entry` instead as it may be implemented more efficiently in /// some formats compared to a pair of calls to `serialize_key` and /// `serialize_value`. - fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a map value. /// @@ -1777,9 +1780,9 @@ pub trait SerializeMap { /// /// Calling `serialize_value` before `serialize_key` is incorrect and is /// allowed to panic or produce bogus results. - fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a map entry consisting of a key and a value. /// @@ -1798,14 +1801,10 @@ pub trait SerializeMap { /// [`Serialize`]: ../trait.Serialize.html /// [`serialize_key`]: #tymethod.serialize_key /// [`serialize_value`]: #tymethod.serialize_value - fn serialize_entry( - &mut self, - key: &K, - value: &V, - ) -> Result<(), Self::Error> + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Self::Error> where - K: Serialize, - V: Serialize, + K: ?Sized + Serialize, + V: ?Sized + Serialize, { tri!(self.serialize_key(key)); self.serialize_value(value) @@ -1856,15 +1855,13 @@ pub trait SerializeStruct { type Error: Error; /// Serialize a struct field. - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Indicate that a struct field has been skipped. + /// + /// The default implementation does nothing. #[inline] fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { let _ = key; @@ -1922,15 +1919,13 @@ pub trait SerializeStructVariant { type Error: Error; /// Serialize a struct variant field. - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Indicate that a struct variant field has been skipped. + /// + /// The default implementation does nothing. #[inline] fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { let _ = key; diff --git a/third_party/rust/serde_derive/.cargo-checksum.json b/third_party/rust/serde_derive/.cargo-checksum.json index 331652acd7..4795d909a2 100644 --- a/third_party/rust/serde_derive/.cargo-checksum.json +++ b/third_party/rust/serde_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"daf3d8f8efdf30d3575c7d1e1372ff7287891fb95625223e4a8a2f792c4474e1","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"731c044fc5f98b37a89e9049c9214267db98763309cb63146b45c029640f82a3","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/bound.rs":"6c5c20785ac95af9480f8d0de35a7e844cc36a16012f6468db148acd03cb15c2","src/de.rs":"c221ab2b94a5d80dccff74a37f3448b3d695656552b452595dc289c73b12fb2b","src/dummy.rs":"9533dfee23f20d92ea75734c739022820c2787ded0d54f459feacdeb770ec912","src/fragment.rs":"6757cb4c3131d4300f093572efc273c4ab5a20e3e1efb54a311dcfa52d0bd6eb","src/internals/ast.rs":"7dc997e4090033bbd1d0bdd870e8bb87b096b7f66cfd02047f6b85ebdd569b12","src/internals/attr.rs":"6584c0a02de0d17993877303f3cc2c1bccf235257632220421f98082d82d387a","src/internals/case.rs":"10c8dda2b32d8c6c6b63cf09cdc63d02375af7e95ecefe8fecb34f93b65191bb","src/internals/check.rs":"d842eb9912fd29311060b67f3bc62c438eb7b5d86093355acb4de7eee02a0ef8","src/internals/ctxt.rs":"83a4e6fbe0e439d578478883594407e03f2f340541be479bdf0b04a202633a37","src/internals/mod.rs":"ed021ca635c18132a0e5c3d90f21b7f65def0a61e946421a30200b5b9ab6ad43","src/internals/receiver.rs":"fe8a480669511b5edcfe71f5dd290cf72ccec54c9016ec85f2ac59dce538077f","src/internals/respan.rs":"899753859c58ce5f532a3ec4584796a52f13ed5a0533191e48c953ba5c1b52ff","src/internals/symbol.rs":"d619e88caa3c7a09b03014257f2b349ee922290062d9b97b4dd19d0e64532690","src/lib.rs":"7a6c2796244658f62d398ebc6819c4f3064dac4a1ad7c52b40359f9411f1c266","src/pretend.rs":"7facc10a5b805564dd95735ae11118ec17ca6adcc49a59764e7c920e27b9fc4a","src/ser.rs":"e3341471cea9d7e2fb4043e5d1746862beb9a4e25196170879eeac529d460920","src/this.rs":"87818dc80cbb521b51938a653d09daf10aafc220bb10425948de82ad670fcb85"},"package":"7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"} \ No newline at end of file +{"files":{"Cargo.toml":"a8aac06a59f67cf1f468da3e234ae0cbb87089ad064bdfae4beb72932cd4210f","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"731c044fc5f98b37a89e9049c9214267db98763309cb63146b45c029640f82a3","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/bound.rs":"6c5c20785ac95af9480f8d0de35a7e844cc36a16012f6468db148acd03cb15c2","src/de.rs":"c221ab2b94a5d80dccff74a37f3448b3d695656552b452595dc289c73b12fb2b","src/dummy.rs":"9533dfee23f20d92ea75734c739022820c2787ded0d54f459feacdeb770ec912","src/fragment.rs":"6757cb4c3131d4300f093572efc273c4ab5a20e3e1efb54a311dcfa52d0bd6eb","src/internals/ast.rs":"7dc997e4090033bbd1d0bdd870e8bb87b096b7f66cfd02047f6b85ebdd569b12","src/internals/attr.rs":"6584c0a02de0d17993877303f3cc2c1bccf235257632220421f98082d82d387a","src/internals/case.rs":"10c8dda2b32d8c6c6b63cf09cdc63d02375af7e95ecefe8fecb34f93b65191bb","src/internals/check.rs":"d842eb9912fd29311060b67f3bc62c438eb7b5d86093355acb4de7eee02a0ef8","src/internals/ctxt.rs":"83a4e6fbe0e439d578478883594407e03f2f340541be479bdf0b04a202633a37","src/internals/mod.rs":"ed021ca635c18132a0e5c3d90f21b7f65def0a61e946421a30200b5b9ab6ad43","src/internals/receiver.rs":"fe8a480669511b5edcfe71f5dd290cf72ccec54c9016ec85f2ac59dce538077f","src/internals/respan.rs":"899753859c58ce5f532a3ec4584796a52f13ed5a0533191e48c953ba5c1b52ff","src/internals/symbol.rs":"d619e88caa3c7a09b03014257f2b349ee922290062d9b97b4dd19d0e64532690","src/lib.rs":"fd046746f651890097154a0a8cb5f90c050fda8da4e0bbdf1c8e4826d10794db","src/pretend.rs":"7facc10a5b805564dd95735ae11118ec17ca6adcc49a59764e7c920e27b9fc4a","src/ser.rs":"a5638fa1b42b2a0d23cc12649f9180d4132f4cb7cf9edace1a1caed483f609e9","src/this.rs":"87818dc80cbb521b51938a653d09daf10aafc220bb10425948de82ad670fcb85"},"package":"e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"} \ No newline at end of file diff --git a/third_party/rust/serde_derive/Cargo.toml b/third_party/rust/serde_derive/Cargo.toml index 33642ef04c..881bb3b7a5 100644 --- a/third_party/rust/serde_derive/Cargo.toml +++ b/third_party/rust/serde_derive/Cargo.toml @@ -10,9 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] +edition = "2015" rust-version = "1.56" name = "serde_derive" -version = "1.0.197" +version = "1.0.198" authors = [ "Erick Tryzelaar ", "David Tolnay ", diff --git a/third_party/rust/serde_derive/src/lib.rs b/third_party/rust/serde_derive/src/lib.rs index b91f17b1a9..70b16e9955 100644 --- a/third_party/rust/serde_derive/src/lib.rs +++ b/third_party/rust/serde_derive/src/lib.rs @@ -13,7 +13,7 @@ //! //! [https://serde.rs/derive.html]: https://serde.rs/derive.html -#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.197")] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.198")] // Ignored clippy lints #![allow( // clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054 diff --git a/third_party/rust/serde_derive/src/ser.rs b/third_party/rust/serde_derive/src/ser.rs index 3be51ee52d..7d89d22125 100644 --- a/third_party/rust/serde_derive/src/ser.rs +++ b/third_party/rust/serde_derive/src/ser.rs @@ -289,7 +289,7 @@ fn serialize_tuple_struct( } fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { - assert!(fields.len() as u64 <= u64::from(u32::max_value())); + assert!(fields.len() as u64 <= u64::from(u32::MAX)); if cattrs.has_flatten() { serialize_struct_as_map(params, fields, cattrs) @@ -397,7 +397,7 @@ fn serialize_struct_as_map( } fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment { - assert!(variants.len() as u64 <= u64::from(u32::max_value())); + assert!(variants.len() as u64 <= u64::from(u32::MAX)); let self_var = ¶ms.self_var; diff --git a/third_party/rust/serde_json/.cargo-checksum.json b/third_party/rust/serde_json/.cargo-checksum.json index 369b6fe170..1f61b06b5f 100644 --- a/third_party/rust/serde_json/.cargo-checksum.json +++ b/third_party/rust/serde_json/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"f5270cafba66223a7b51ffc0d286075a17bb7cd88762fc80d333d3102629f4d8","Cargo.toml":"547ec897b43d41db797423629543e838ee4e08c6a4196a0756b5be0ef178adc1","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"1e5a86e6b5e79f92f9e7226d9a8ba16d4ec70567d153c9cacebcb582770378a1","build.rs":"0dd97b63a07aa2d4bbb4c7d0e73b521da130769da9f49f28a7b63332781eb3de","src/de.rs":"5dba95fc6a564917289bf1e404d59c74f95772f22ec92cb91d55053b65e93032","src/error.rs":"abb92a9bf62cb7f47141a733a9fd66ec8c369615d7e6f633d3536fd2a5ac74a2","src/features_check/error.rs":"d7359f864afbfe105a38abea9f563dc423036ebc4c956a5695a4beef144dc7ec","src/features_check/mod.rs":"2209f8d5c46b50c8a3b8dc22338dcaf0135d192e8b05d2f456cbe6a73104e958","src/io/core.rs":"9a4146802391fd202a36bebbf3b14b715ae09d8828cbe8e06a01214c470ebf5c","src/io/mod.rs":"fd1ed5080495cab21117f6f7d3c2c9e3687cad0c69a0cd087b08a145a9e672da","src/iter.rs":"f832c469cd7999d26ba9b76baa69b257a212a7edb3dfdf9b1d1bb35e8da85fa9","src/lexical/algorithm.rs":"4fbeb1994049348d1fc388dd1a29e481f8abb8fe1e28bfebf50f3bbce5fa5fbe","src/lexical/bhcomp.rs":"b7c68d74c0055eb67ec2c1bcf27bbc28bef8f1bbc43db8eb94ba69892230add6","src/lexical/bignum.rs":"4230cde10dc8eae456a713cf90ec4e48dff4b1d0c542621ce7f00f39ade2645e","src/lexical/cached.rs":"0e127398691f8042c19cde209e7f4b0161f0f3150342430145929f711e6fdac8","src/lexical/cached_float80.rs":"0f8f74a22cb7d871322a9893bffd0255ca10bf9dffd13afb2462dd3d7f51805f","src/lexical/digit.rs":"a265b9072194a62a67dfc4df3c86d4213097cf3f82280d025e0012a5a262fd9d","src/lexical/errors.rs":"6bc993febceb7dd96ac1c8c5c53b5f5a30297016c0f813ed8ff8d7938d01534d","src/lexical/exponent.rs":"387e945b97dc7ba48a7091c50d228a0dde3a1c4145703d4ab9c31191a91693b0","src/lexical/float.rs":"fe356213c92a049f4bef2f58bc0e3a26866ca06b8c1d74d0f961c5b883852cad","src/lexical/large_powers.rs":"34537f5c701afce1ec2a1fd3c14950381b2e27c9ad74f002c91f3708e8da9ca5","src/lexical/large_powers32.rs":"d533037c6141e6671102aee490c9cdeaba81e667ddca781b2b99db2c455e4a1a","src/lexical/large_powers64.rs":"745dd7c0cbe499eec027ef586248881011d9df20c7efab7929c1807b59886ba1","src/lexical/math.rs":"27e22b724cdf990cdacd0ccfc3749e6e2eb7529d43ebf6e95b1999560b9e199a","src/lexical/mod.rs":"4b4c5228779c0f135a4cb018700e3bcd495da48b74421a86f6b8b304acdef924","src/lexical/num.rs":"cf705c62612e31d704f43d94a633ea1243c6befad7ef5792e2e881a7fd21e809","src/lexical/parse.rs":"c2bfac4c70a19938ced61e991f4ec606764887cf12bac1a0978b5b5318a56aac","src/lexical/rounding.rs":"697207248ba17b7f4965aedb11d276261ada5b06d9c6265d8fd6246664ff6e3c","src/lexical/shift.rs":"bc1ed053dd63d45ac9c35302f18de9f00d94027f28af4ab749c9248439de832a","src/lexical/small_powers.rs":"4608dd218b8002435db7e1ec79d2d0fef5f47ae257b93353326d52ecc80cccda","src/lib.rs":"f055ef570d978397cfae0d814ddbbf2372b8839ab4ffe8fc4c3308c9b2a332de","src/macros.rs":"c9f23156faec8d5216d72b6a97eebd768efb3f75870a6e2beed824308587b998","src/map.rs":"14fa16650b462ef138bebe1d18cb296b0e1ff404f12f2c212f72ed7c969b3a12","src/number.rs":"425f528c5ec2fcb4dd3c87a633d0b2cd505f7a305a40dffa1f022a643eda938b","src/raw.rs":"6d46836486b8d1c58f2aff563285400b1b0ec163eee34e7be78e0fa7a99aa0e8","src/read.rs":"49b4b1d067b6485cbded28fb961666ab5df82c36661af722dbae756efb6b2891","src/ser.rs":"566ae0b1860861ad70efd17fb0f6ae326e76d60453b6538c783a40d4ce616851","src/value/de.rs":"78f938d960e285f671f3b86ed173d598a815690a14512d6daa94dee43d3ce4cf","src/value/from.rs":"2dcfed837b040447a61eae50bd3938106b090f8a292206aea686022767006625","src/value/index.rs":"8a99d8d50f5674181ced22f6e81dc529eaecb01e543e30346e51fe42cb4b8a5f","src/value/mod.rs":"81c62fcb50e92b2f424e361328df5b02621756781bf80b8e26fd3d13473b57cd","src/value/partial_eq.rs":"95de799d57f7f4310b64a9488c0a7286dee76dba4329cb69a96298a887e58586","src/value/ser.rs":"5ea04bdf30c1c79baeab66b922908b47f1910b07d2f4ed0927a9a2c1ef3fbf60","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/debug.rs":"a8451217c1e127ad6e653ef11e0513525ee350e1e37dd575758a8ee9301b28fb","tests/lexical.rs":"383e06283e15e1db7c6b818da3c84a3afa0059f6e9fc994b069919d81346ab91","tests/lexical/algorithm.rs":"da378df9ee24bfa033968d5c94e91b58e52c39bf6c825dec51c3eb7250cc5874","tests/lexical/exponent.rs":"26ea92abc654a6a88a8281552bca2f76ea1fa4c17d66a1dd6defe14f7d89b666","tests/lexical/float.rs":"0440f2d85c993bcccd925096d7f4136bf624ffd66b3c7ee565d158390685eb11","tests/lexical/math.rs":"4874be2103be5fbe8b8015354414df271ffa00fd815546fc077f15fb4d7a5a37","tests/lexical/num.rs":"6e650c40de85ed72ac06b6bf1487ba161f3824e26d827df6cfdf2bbdb8d05a05","tests/lexical/parse.rs":"17c73e0a59d462716d974b8dd23a291eb6efdc3a933248874e5eab7e7209d67f","tests/lexical/rounding.rs":"6c56e39ba534616c1b2146e8efa6eb57aed322e683bf23183cd32a61fae6447e","tests/macros/mod.rs":"93aa1d54af20bc2c55b6ae8db73c1414cda2626eb9fa7bd57b9d613a3c6e6a19","tests/map.rs":"dcc5212242e4e93703c4335d54f5603b0211b33d6fb5ab410bb630cda6d46b09","tests/regression.rs":"86731134bfb9bb693d9a4fc62393027de80a8bf031109ea6c7ea475b1ebdde8d","tests/regression/issue520.rs":"d146be3472db902b48127d65fe83aa9f698143aca9074c83cd1a9d5dd28e3ec3","tests/regression/issue795.rs":"582e2e7c68113f05a4b1d2cb556a2df7cc77f2ce8164a32c5cc58ae68abb60ec","tests/regression/issue845.rs":"8bd64588fc344e119d0e9e5e7604236e7c168c574b0692033f15278e216a6b9c","tests/regression/issue953.rs":"b2cddc761f5ca6639900c173765a8a5868528a896924e5e925db2696469208f7","tests/stream.rs":"c7d91014538ecd8f495b196d40e999ab2745f2e69fa2ff9e52521605dc6ce856","tests/test.rs":"b9154ff63261cecd6f04443ce3580d285af16f77cdc2c87239408cb8e06009dc","tests/ui/missing_colon.rs":"d07e0c34d98eb43465f0a0310f2c0b5d5b0d26d243b352a1c6bbe6ad3b27eda9","tests/ui/missing_colon.stderr":"3732fd8f4e57b84efc07170cda5f9c5b2b17c707e23c1659222b5a46f652a8d8","tests/ui/missing_comma.rs":"b8a9662f99c3e6dd2b6417892c37640578ce91d3a8365bf10c1f686a3227aa87","tests/ui/missing_comma.stderr":"eae626cf93c97abd105066e624ca4e8cb096784413b9d2564cf9414a8492bc4d","tests/ui/missing_value.rs":"bca25d67127fb88e7c191c7b03af5a4ce8a9abb630f3d2e6a6c1e77e213dc9a4","tests/ui/missing_value.stderr":"b0df8add5cf74e5df30eedd3ca347e4862c04a01c54d802ff45392f2032065b1","tests/ui/not_found.rs":"d0a7adb309879ff65aee115b52cc33d36f4bad353cf97c4effc34a6128c2bee3","tests/ui/not_found.stderr":"359b751c0c21fab6d460daef4d5f73a265f7769c9b578f98ea3cb6cbf2387643","tests/ui/parse_expr.rs":"32e6d51f528db3d1ab0ed1e24765b865be393565c26f77413c5aa39d601ac563","tests/ui/parse_expr.stderr":"4fcd0a014fbce31c9266bab8527d6e6b6806a0e21d9e0275ce713137856073ce","tests/ui/parse_key.rs":"18829b2af320d5cf8a0a5cd3aaf84c7e92cc874651c30e45a3acafb76c2d8b93","tests/ui/parse_key.stderr":"fcb44e060b804a4762b7291e128c41d7010ffa8ab820b8828fd13fbe6d405ca6","tests/ui/unexpected_after_array_element.rs":"a343fc3104431720bdfcf330bcc3cfcd98c8dec3e951133b495242478b0b7eb3","tests/ui/unexpected_after_array_element.stderr":"8df615998fa3057bb9ed865981a35cdbb771625337048f0ad3fba7734e607adf","tests/ui/unexpected_after_map_entry.rs":"6e3bd2def435ca610e346bbc75cdbaf61963eb2ef1885bb5f76781ba1fac37ef","tests/ui/unexpected_after_map_entry.stderr":"b1985c89075ab48b2158bd1705ed766d37854b3d4620ab257cc8bc319d224f17","tests/ui/unexpected_colon.rs":"a313cff3fed4be4c33f1eda5d0c5c98147fb835a56d36470d9f367352c1d61ef","tests/ui/unexpected_colon.stderr":"b2288742fa6a4a7eb65d2ae899bcfed8795b57bd04958da227d60928a8df26c5","tests/ui/unexpected_comma.rs":"55a8b684bde1ce905837cce719fd457d8898b61cebc27e5b420d05cb6be97256","tests/ui/unexpected_comma.stderr":"4c103ca63ff15e2ca659242cc0eae0612bf050e7580da62f1cf50de8082aa7dc"},"package":"cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"f5270cafba66223a7b51ffc0d286075a17bb7cd88762fc80d333d3102629f4d8","Cargo.toml":"f8b789a2b436af04913166cb07fcd87927fb4a89c84332f82fd58f84cc3a4e0b","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"f223b99630bae262eb2b88bb95d0f496db8f1ff4e94e43dbfc8d95d3a6c98d8f","build.rs":"9fa36e0b1bb7026b449a20986ae2f60b3046bcbcf3bf22b5c0e372eb892eaf57","src/de.rs":"c423a0534203713b89c3db544d7ea0988b4a913a0501d0d9cb170f6a66d23dd6","src/error.rs":"a9b5de0a82f95608b51b8e8875c7c49f94fb60b9f976fc6277aec0213926dec9","src/io/core.rs":"60ba28f67a9acaecf8964b611efba416b13f9f2bae4befc329fdf0e037293802","src/io/mod.rs":"fd1ed5080495cab21117f6f7d3c2c9e3687cad0c69a0cd087b08a145a9e672da","src/iter.rs":"f832c469cd7999d26ba9b76baa69b257a212a7edb3dfdf9b1d1bb35e8da85fa9","src/lexical/algorithm.rs":"bd6106e5d8875c9ff1c1d57256b459a4f0992d14a0df1a5fffcd3d3cbdccee8c","src/lexical/bhcomp.rs":"b7c68d74c0055eb67ec2c1bcf27bbc28bef8f1bbc43db8eb94ba69892230add6","src/lexical/bignum.rs":"db688e8112389998d0f91906f6857e28f9b510a8b4065ad476c8e8be2f77becf","src/lexical/cached.rs":"0e127398691f8042c19cde209e7f4b0161f0f3150342430145929f711e6fdac8","src/lexical/cached_float80.rs":"0f8f74a22cb7d871322a9893bffd0255ca10bf9dffd13afb2462dd3d7f51805f","src/lexical/digit.rs":"9502805adbc3da059131d1fac0a802e17065b36cd7472606b3af24e3241d5cb8","src/lexical/errors.rs":"3d9f6de6245533bcb101dfd718cfed61d59dc293f6768cedae28aa13ace164f5","src/lexical/exponent.rs":"51f19443008e8884b15c7d5d4b1f1cfbd5673a9d1da02f1af39fcf20e315f01f","src/lexical/float.rs":"fe356213c92a049f4bef2f58bc0e3a26866ca06b8c1d74d0f961c5b883852cad","src/lexical/large_powers.rs":"34537f5c701afce1ec2a1fd3c14950381b2e27c9ad74f002c91f3708e8da9ca5","src/lexical/large_powers32.rs":"c70b57a727960beec258758a4d4a1050f8eaf3b4e60027c663a2bfb0246e0153","src/lexical/large_powers64.rs":"e7af83ce3159b5fc4669fc5a231e767d8af21bacaece52a0a48951198965b197","src/lexical/math.rs":"240804aa030849495fa03a83a0ee8539d5a5c8639b825f2d69d27b7567b06fb3","src/lexical/mod.rs":"4b4c5228779c0f135a4cb018700e3bcd495da48b74421a86f6b8b304acdef924","src/lexical/num.rs":"dd9f4357b8d5bead413844d4015176d484e907e1a393cf7f583de5c5ccafb2e3","src/lexical/parse.rs":"c2bfac4c70a19938ced61e991f4ec606764887cf12bac1a0978b5b5318a56aac","src/lexical/rounding.rs":"4762af3612880b17468ff2a1bb800c8e99f08330ae439699dd53d8dc5463ad13","src/lexical/shift.rs":"bc1ed053dd63d45ac9c35302f18de9f00d94027f28af4ab749c9248439de832a","src/lexical/small_powers.rs":"4608dd218b8002435db7e1ec79d2d0fef5f47ae257b93353326d52ecc80cccda","src/lib.rs":"161e03a3d34254716ed88d6d3b7c7536f646e674263ca71b5930b99c1c06a4ca","src/macros.rs":"516f69976f433bcc5e48c32b3e29c2e0ab7b549810827d7a9c59171cdf11c1e2","src/map.rs":"aeb07107ba949330e72f4d669d46b215990f83aa4055e06d1da69f2a32ddf642","src/number.rs":"537be73fe2f1f4c654a41e0b6461493ca7e3c20265163b3fb3405d047c163c1a","src/raw.rs":"74f5937706324c9325acc42597ff0a226faeaae38d270ab61ba6283e37616c86","src/read.rs":"7e5928c7f71cfa3848966ab6cc0e6596fd0a3e15cf9f2c59675bf920340ab79f","src/ser.rs":"ee5b6cb04c2ff7058b52cb5d0383218f484505ce0896e5c7fd5076bd9d90952e","src/value/de.rs":"890d88303ce0036a5efd1c57378dab7f8c45dabd798cece2248c2d9db52fa011","src/value/from.rs":"add9687e35db3962729d986c8aa54785cadeb07b8b7121cd4075e3a37ecc73a1","src/value/index.rs":"1a0d59629ae16d6553686de8d7152abd470153f67f9a1b69741e480ba491cd67","src/value/mod.rs":"c1b08509df5ae1ffb5c5e148ac29791923c92eb9957935683739a95bef0007e9","src/value/partial_eq.rs":"655fd0bf3ab1d6669444a55ab849f43bb333032de8ca8f1ee95e1068da43ee22","src/value/ser.rs":"d59f959448de1f4115ed62359e7444081741215e7005bcf97f7584b5e31e3b15","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/debug.rs":"a8451217c1e127ad6e653ef11e0513525ee350e1e37dd575758a8ee9301b28fb","tests/lexical.rs":"8ee6e617ef62a090de49ac2a930130a6913ab5316100781543c7788f89ef99c2","tests/lexical/algorithm.rs":"da378df9ee24bfa033968d5c94e91b58e52c39bf6c825dec51c3eb7250cc5874","tests/lexical/exponent.rs":"dc8fa8d05e561ff256f8b09385291768c7f45e5ad6cb878ef9194757aa014386","tests/lexical/float.rs":"0440f2d85c993bcccd925096d7f4136bf624ffd66b3c7ee565d158390685eb11","tests/lexical/math.rs":"4874be2103be5fbe8b8015354414df271ffa00fd815546fc077f15fb4d7a5a37","tests/lexical/num.rs":"6e650c40de85ed72ac06b6bf1487ba161f3824e26d827df6cfdf2bbdb8d05a05","tests/lexical/parse.rs":"a11f09bb003a3a024548008cf78bf76526ed71b00077d1989f45eb8cebc93b9c","tests/lexical/rounding.rs":"6c56e39ba534616c1b2146e8efa6eb57aed322e683bf23183cd32a61fae6447e","tests/macros/mod.rs":"93aa1d54af20bc2c55b6ae8db73c1414cda2626eb9fa7bd57b9d613a3c6e6a19","tests/map.rs":"89f604c5788bcb8dc82c82e252dc0da47257986e353c09d14e4ef3e58c455f2d","tests/regression.rs":"86731134bfb9bb693d9a4fc62393027de80a8bf031109ea6c7ea475b1ebdde8d","tests/regression/issue1004.rs":"38d7e3b6c515b881078ebd21ca8063d2ca105cd319695d29538f879e37f091b5","tests/regression/issue520.rs":"f95b362e45c57b431720c48eb47f7ddddf4078195d6859df523dc32950ce980a","tests/regression/issue795.rs":"37ff26744b1f950dd212565c6e3f276268882f7724cc589ac8b21ca8bd608413","tests/regression/issue845.rs":"10d2895cd1412cb6630f0a59db367f79ee672edb501151c7581e9921b5a84b92","tests/regression/issue953.rs":"b2cddc761f5ca6639900c173765a8a5868528a896924e5e925db2696469208f7","tests/stream.rs":"c7d91014538ecd8f495b196d40e999ab2745f2e69fa2ff9e52521605dc6ce856","tests/test.rs":"43cd75d02297758365ce6175a62843fa84fb60f4cdb3c9ed3cbfb752db6fcc68","tests/ui/missing_colon.rs":"d07e0c34d98eb43465f0a0310f2c0b5d5b0d26d243b352a1c6bbe6ad3b27eda9","tests/ui/missing_colon.stderr":"3732fd8f4e57b84efc07170cda5f9c5b2b17c707e23c1659222b5a46f652a8d8","tests/ui/missing_comma.rs":"b8a9662f99c3e6dd2b6417892c37640578ce91d3a8365bf10c1f686a3227aa87","tests/ui/missing_comma.stderr":"eae626cf93c97abd105066e624ca4e8cb096784413b9d2564cf9414a8492bc4d","tests/ui/missing_value.rs":"bca25d67127fb88e7c191c7b03af5a4ce8a9abb630f3d2e6a6c1e77e213dc9a4","tests/ui/missing_value.stderr":"b0df8add5cf74e5df30eedd3ca347e4862c04a01c54d802ff45392f2032065b1","tests/ui/not_found.rs":"d0a7adb309879ff65aee115b52cc33d36f4bad353cf97c4effc34a6128c2bee3","tests/ui/not_found.stderr":"359b751c0c21fab6d460daef4d5f73a265f7769c9b578f98ea3cb6cbf2387643","tests/ui/parse_expr.rs":"32e6d51f528db3d1ab0ed1e24765b865be393565c26f77413c5aa39d601ac563","tests/ui/parse_expr.stderr":"4fcd0a014fbce31c9266bab8527d6e6b6806a0e21d9e0275ce713137856073ce","tests/ui/parse_key.rs":"18829b2af320d5cf8a0a5cd3aaf84c7e92cc874651c30e45a3acafb76c2d8b93","tests/ui/parse_key.stderr":"20cf0d2898749f3c36780fc065f5049ee809e74cb6f0ef776f43f45e01596ee3","tests/ui/unexpected_after_array_element.rs":"a343fc3104431720bdfcf330bcc3cfcd98c8dec3e951133b495242478b0b7eb3","tests/ui/unexpected_after_array_element.stderr":"8df615998fa3057bb9ed865981a35cdbb771625337048f0ad3fba7734e607adf","tests/ui/unexpected_after_map_entry.rs":"6e3bd2def435ca610e346bbc75cdbaf61963eb2ef1885bb5f76781ba1fac37ef","tests/ui/unexpected_after_map_entry.stderr":"b1985c89075ab48b2158bd1705ed766d37854b3d4620ab257cc8bc319d224f17","tests/ui/unexpected_colon.rs":"a313cff3fed4be4c33f1eda5d0c5c98147fb835a56d36470d9f367352c1d61ef","tests/ui/unexpected_colon.stderr":"b2288742fa6a4a7eb65d2ae899bcfed8795b57bd04958da227d60928a8df26c5","tests/ui/unexpected_comma.rs":"55a8b684bde1ce905837cce719fd457d8898b61cebc27e5b420d05cb6be97256","tests/ui/unexpected_comma.stderr":"4c103ca63ff15e2ca659242cc0eae0612bf050e7580da62f1cf50de8082aa7dc"},"package":"3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"} \ No newline at end of file diff --git a/third_party/rust/serde_json/Cargo.toml b/third_party/rust/serde_json/Cargo.toml index cff28cd7b2..9941fdd86b 100644 --- a/third_party/rust/serde_json/Cargo.toml +++ b/third_party/rust/serde_json/Cargo.toml @@ -10,10 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2018" -rust-version = "1.36" +edition = "2021" +rust-version = "1.56" name = "serde_json" -version = "1.0.93" +version = "1.0.116" authors = [ "Erick Tryzelaar ", "David Tolnay ", @@ -36,14 +36,16 @@ repository = "https://github.com/serde-rs/json" [package.metadata.docs.rs] features = [ + "preserve_order", "raw_value", "unbounded_depth", ] -targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = [ "--cfg", "docsrs", + "--generate-link-to-definition", ] +targets = ["x86_64-unknown-linux-gnu"] [package.metadata.playground] features = ["raw_value"] @@ -52,8 +54,7 @@ features = ["raw_value"] doc-scrape-examples = false [dependencies.indexmap] -version = "1.5.2" -features = ["std"] +version = "2.2.1" optional = true [dependencies.itoa] @@ -63,36 +64,36 @@ version = "1.0" version = "1.0" [dependencies.serde] -version = "1.0.100" +version = "1.0.194" default-features = false [dev-dependencies.automod] -version = "1.0" +version = "1.0.11" [dev-dependencies.indoc] -version = "2.0" +version = "2.0.2" [dev-dependencies.ref-cast] -version = "1.0" +version = "1.0.18" [dev-dependencies.rustversion] -version = "1.0" +version = "1.0.13" [dev-dependencies.serde] -version = "1.0.100" +version = "1.0.194" features = ["derive"] [dev-dependencies.serde_bytes] -version = "0.11" +version = "0.11.10" [dev-dependencies.serde_derive] -version = "1.0" +version = "1.0.166" [dev-dependencies.serde_stacker] -version = "0.1" +version = "0.1.8" [dev-dependencies.trybuild] -version = "1.0.49" +version = "1.0.81" features = ["diff"] [features] diff --git a/third_party/rust/serde_json/README.md b/third_party/rust/serde_json/README.md index d704979247..be70b7b06d 100644 --- a/third_party/rust/serde_json/README.md +++ b/third_party/rust/serde_json/README.md @@ -76,7 +76,7 @@ enum Value { A string of JSON data can be parsed into a `serde_json::Value` by the [`serde_json::from_str`][from_str] function. There is also -[`from_slice`][from_slice] for parsing from a byte slice &[u8] and +[`from_slice`][from_slice] for parsing from a byte slice `&[u8]` and [`from_reader`][from_reader] for parsing from any `io::Read` like a File or a TCP stream. diff --git a/third_party/rust/serde_json/build.rs b/third_party/rust/serde_json/build.rs index 0e12602e46..dd09e62a3e 100644 --- a/third_party/rust/serde_json/build.rs +++ b/third_party/rust/serde_json/build.rs @@ -1,6 +1,4 @@ use std::env; -use std::process::Command; -use std::str::{self, FromStr}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -9,46 +7,11 @@ fn main() { // src/lexical/math.rs for where this has an effect. let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); match target_arch.as_str() { - "aarch64" | "mips64" | "powerpc64" | "x86_64" => { + "aarch64" | "mips64" | "powerpc64" | "x86_64" | "loongarch64" => { println!("cargo:rustc-cfg=limb_width_64"); } _ => { println!("cargo:rustc-cfg=limb_width_32"); } } - - let minor = match rustc_minor_version() { - Some(minor) => minor, - None => return, - }; - - // BTreeMap::get_key_value - // https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html#additions-to-the-standard-library - if minor < 40 { - println!("cargo:rustc-cfg=no_btreemap_get_key_value"); - } - - // BTreeMap::remove_entry - // https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html#library-changes - if minor < 45 { - println!("cargo:rustc-cfg=no_btreemap_remove_entry"); - } - - // BTreeMap::retain - // https://blog.rust-lang.org/2021/06/17/Rust-1.53.0.html#stabilized-apis - if minor < 53 { - println!("cargo:rustc-cfg=no_btreemap_retain"); - } -} - -fn rustc_minor_version() -> Option { - let rustc = env::var_os("RUSTC")?; - let output = Command::new(rustc).arg("--version").output().ok()?; - let version = str::from_utf8(&output.stdout).ok()?; - let mut pieces = version.split('.'); - if pieces.next() != Some("rustc 1") { - return None; - } - let next = pieces.next()?; - u32::from_str(next).ok() } diff --git a/third_party/rust/serde_json/src/de.rs b/third_party/rust/serde_json/src/de.rs index 88d0f2624d..c7774f6873 100644 --- a/third_party/rust/serde_json/src/de.rs +++ b/third_party/rust/serde_json/src/de.rs @@ -22,6 +22,7 @@ use crate::number::NumberDeserializer; pub use crate::read::{Read, SliceRead, StrRead}; #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub use crate::read::IoRead; ////////////////////////////////////////////////////////////////////////////// @@ -209,7 +210,7 @@ impl<'de, R: Read<'de>> Deserializer { self.disable_recursion_limit = true; } - fn peek(&mut self) -> Result> { + pub(crate) fn peek(&mut self) -> Result> { self.read.peek() } @@ -248,7 +249,7 @@ impl<'de, R: Read<'de>> Deserializer { fn parse_whitespace(&mut self) -> Result> { loop { match tri!(self.peek()) { - Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') => { + Some(b' ' | b'\n' | b'\t' | b'\r') => { self.eat_char(); } other => { @@ -309,9 +310,9 @@ impl<'de, R: Read<'de>> Deserializer { self.fix_position(err) } - fn deserialize_number(&mut self, visitor: V) -> Result + pub(crate) fn deserialize_number<'any, V>(&mut self, visitor: V) -> Result where - V: de::Visitor<'de>, + V: de::Visitor<'any>, { let peek = match tri!(self.parse_whitespace()) { Some(b) => b, @@ -335,6 +336,79 @@ impl<'de, R: Read<'de>> Deserializer { } } + #[cfg(feature = "float_roundtrip")] + pub(crate) fn do_deserialize_f32<'any, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'any>, + { + self.single_precision = true; + let val = self.deserialize_number(visitor); + self.single_precision = false; + val + } + + pub(crate) fn do_deserialize_i128<'any, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'any>, + { + let mut buf = String::new(); + + match tri!(self.parse_whitespace()) { + Some(b'-') => { + self.eat_char(); + buf.push('-'); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + tri!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_i128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + pub(crate) fn do_deserialize_u128<'any, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'any>, + { + match tri!(self.parse_whitespace()) { + Some(b'-') => { + return Err(self.peek_error(ErrorCode::NumberOutOfRange)); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + } + + let mut buf = String::new(); + tri!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_u128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + fn scan_integer128(&mut self, buf: &mut String) -> Result<()> { match tri!(self.next_char_or_null()) { b'0' => { @@ -407,7 +481,7 @@ impl<'de, R: Read<'de>> Deserializer { // try to keep the number as a `u64` until we grow // too large. At that point, switch to parsing the // value as a `f64`. - if overflow!(significand * 10 + digit, u64::max_value()) { + if overflow!(significand * 10 + digit, u64::MAX) { return Ok(ParserNumber::F64(tri!( self.parse_long_integer(positive, significand), ))); @@ -459,7 +533,7 @@ impl<'de, R: Read<'de>> Deserializer { while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { let digit = (c - b'0') as u64; - if overflow!(significand * 10 + digit, u64::max_value()) { + if overflow!(significand * 10 + digit, u64::MAX) { let exponent = exponent_before_decimal_point + exponent_after_decimal_point; return self.parse_decimal_overflow(positive, significand, exponent); } @@ -523,7 +597,7 @@ impl<'de, R: Read<'de>> Deserializer { self.eat_char(); let digit = (c - b'0') as i32; - if overflow!(exp * 10 + digit, i32::max_value()) { + if overflow!(exp * 10 + digit, i32::MAX) { let zero_significand = significand == 0; return self.parse_exponent_overflow(positive, zero_significand, positive_exp); } @@ -715,7 +789,7 @@ impl<'de, R: Read<'de>> Deserializer { self.eat_char(); let digit = (c - b'0') as i32; - if overflow!(exp * 10 + digit, i32::max_value()) { + if overflow!(exp * 10 + digit, i32::MAX) { let zero_significand = self.scratch.iter().all(|&digit| digit == b'0'); return self.parse_exponent_overflow(positive, zero_significand, positive_exp); } @@ -860,7 +934,7 @@ impl<'de, R: Read<'de>> Deserializer { if !positive { buf.push('-'); } - self.scan_integer(&mut buf)?; + tri!(self.scan_integer(&mut buf)); if positive { if let Ok(unsigned) = buf.parse() { return Ok(ParserNumber::U64(unsigned)); @@ -913,7 +987,7 @@ impl<'de, R: Read<'de>> Deserializer { fn scan_number(&mut self, buf: &mut String) -> Result<()> { match tri!(self.peek_or_null()) { b'.' => self.scan_decimal(buf), - e @ b'e' | e @ b'E' => self.scan_exponent(e as char, buf), + e @ (b'e' | b'E') => self.scan_exponent(e as char, buf), _ => Ok(()), } } @@ -938,7 +1012,7 @@ impl<'de, R: Read<'de>> Deserializer { } match tri!(self.peek_or_null()) { - e @ b'e' | e @ b'E' => self.scan_exponent(e as char, buf), + e @ (b'e' | b'E') => self.scan_exponent(e as char, buf), _ => Ok(()), } } @@ -1059,7 +1133,7 @@ impl<'de, R: Read<'de>> Deserializer { tri!(self.read.ignore_str()); None } - frame @ b'[' | frame @ b'{' => { + frame @ (b'[' | b'{') => { self.scratch.extend(enclosing.take()); self.eat_char(); Some(frame) @@ -1204,9 +1278,9 @@ impl<'de, R: Read<'de>> Deserializer { where V: de::Visitor<'de>, { - self.parse_whitespace()?; + tri!(self.parse_whitespace()); self.read.begin_raw_buffering(); - self.ignore_value()?; + tri!(self.ignore_value()); self.read.end_raw_buffering(visitor) } } @@ -1258,11 +1332,15 @@ static POW10: [f64; 309] = [ macro_rules! deserialize_number { ($method:ident) => { + deserialize_number!($method, deserialize_number); + }; + + ($method:ident, $using:ident) => { fn $method(self, visitor: V) -> Result where V: de::Visitor<'de>, { - self.deserialize_number(visitor) + self.$using(visitor) } }; } @@ -1424,77 +1502,9 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer { deserialize_number!(deserialize_f64); #[cfg(feature = "float_roundtrip")] - fn deserialize_f32(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - self.single_precision = true; - let val = self.deserialize_number(visitor); - self.single_precision = false; - val - } - - fn deserialize_i128(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - let mut buf = String::new(); - - match tri!(self.parse_whitespace()) { - Some(b'-') => { - self.eat_char(); - buf.push('-'); - } - Some(_) => {} - None => { - return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); - } - }; - - tri!(self.scan_integer128(&mut buf)); - - let value = match buf.parse() { - Ok(int) => visitor.visit_i128(int), - Err(_) => { - return Err(self.error(ErrorCode::NumberOutOfRange)); - } - }; - - match value { - Ok(value) => Ok(value), - Err(err) => Err(self.fix_position(err)), - } - } - - fn deserialize_u128(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - match tri!(self.parse_whitespace()) { - Some(b'-') => { - return Err(self.peek_error(ErrorCode::NumberOutOfRange)); - } - Some(_) => {} - None => { - return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); - } - } - - let mut buf = String::new(); - tri!(self.scan_integer128(&mut buf)); - - let value = match buf.parse() { - Ok(int) => visitor.visit_u128(int), - Err(_) => { - return Err(self.error(ErrorCode::NumberOutOfRange)); - } - }; - - match value { - Ok(value) => Ok(value), - Err(err) => Err(self.fix_position(err)), - } - } + deserialize_number!(deserialize_f32, do_deserialize_f32); + deserialize_number!(deserialize_i128, do_deserialize_i128); + deserialize_number!(deserialize_u128, do_deserialize_u128); fn deserialize_char(self, visitor: V) -> Result where @@ -2118,24 +2128,47 @@ struct MapKey<'a, R: 'a> { de: &'a mut Deserializer, } -macro_rules! deserialize_integer_key { - ($method:ident => $visit:ident) => { +macro_rules! deserialize_numeric_key { + ($method:ident) => { + fn $method(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_number(visitor) + } + }; + + ($method:ident, $delegate:ident) => { fn $method(self, visitor: V) -> Result where V: de::Visitor<'de>, { self.de.eat_char(); - self.de.scratch.clear(); - let string = tri!(self.de.read.parse_str(&mut self.de.scratch)); - match (string.parse(), string) { - (Ok(integer), _) => visitor.$visit(integer), - (Err(_), Reference::Borrowed(s)) => visitor.visit_borrowed_str(s), - (Err(_), Reference::Copied(s)) => visitor.visit_str(s), + + match tri!(self.de.peek()) { + Some(b'0'..=b'9' | b'-') => {} + _ => return Err(self.de.error(ErrorCode::ExpectedNumericKey)), + } + + let value = tri!(self.de.$delegate(visitor)); + + match tri!(self.de.peek()) { + Some(b'"') => self.de.eat_char(), + _ => return Err(self.de.peek_error(ErrorCode::ExpectedDoubleQuote)), } + + Ok(value) } }; } +impl<'de, 'a, R> MapKey<'a, R> +where + R: Read<'de>, +{ + deserialize_numeric_key!(deserialize_number, deserialize_number); +} + impl<'de, 'a, R> de::Deserializer<'de> for MapKey<'a, R> where R: Read<'de>, @@ -2155,16 +2188,56 @@ where } } - deserialize_integer_key!(deserialize_i8 => visit_i8); - deserialize_integer_key!(deserialize_i16 => visit_i16); - deserialize_integer_key!(deserialize_i32 => visit_i32); - deserialize_integer_key!(deserialize_i64 => visit_i64); - deserialize_integer_key!(deserialize_i128 => visit_i128); - deserialize_integer_key!(deserialize_u8 => visit_u8); - deserialize_integer_key!(deserialize_u16 => visit_u16); - deserialize_integer_key!(deserialize_u32 => visit_u32); - deserialize_integer_key!(deserialize_u64 => visit_u64); - deserialize_integer_key!(deserialize_u128 => visit_u128); + deserialize_numeric_key!(deserialize_i8); + deserialize_numeric_key!(deserialize_i16); + deserialize_numeric_key!(deserialize_i32); + deserialize_numeric_key!(deserialize_i64); + deserialize_numeric_key!(deserialize_i128, deserialize_i128); + deserialize_numeric_key!(deserialize_u8); + deserialize_numeric_key!(deserialize_u16); + deserialize_numeric_key!(deserialize_u32); + deserialize_numeric_key!(deserialize_u64); + deserialize_numeric_key!(deserialize_u128, deserialize_u128); + #[cfg(not(feature = "float_roundtrip"))] + deserialize_numeric_key!(deserialize_f32); + #[cfg(feature = "float_roundtrip")] + deserialize_numeric_key!(deserialize_f32, deserialize_f32); + deserialize_numeric_key!(deserialize_f64); + + fn deserialize_bool(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.de.eat_char(); + + let peek = match tri!(self.de.next_char()) { + Some(b) => b, + None => { + return Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b't' => { + tri!(self.de.parse_ident(b"rue\"")); + visitor.visit_bool(true) + } + b'f' => { + tri!(self.de.parse_ident(b"alse\"")); + visitor.visit_bool(false) + } + _ => { + self.de.scratch.clear(); + let s = tri!(self.de.read.parse_str(&mut self.de.scratch)); + Err(de::Error::invalid_type(Unexpected::Str(&s), &visitor)) + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.de.fix_position(err)), + } + } #[inline] fn deserialize_option(self, visitor: V) -> Result @@ -2221,8 +2294,8 @@ where } forward_to_deserialize_any! { - bool f32 f64 char str string unit unit_struct seq tuple tuple_struct map - struct identifier ignored_any + char str string unit unit_struct seq tuple tuple_struct map struct + identifier ignored_any } } @@ -2318,8 +2391,8 @@ where fn peek_end_of_value(&mut self) -> Result<()> { match tri!(self.de.peek()) { - Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') | Some(b'"') | Some(b'[') - | Some(b']') | Some(b'{') | Some(b'}') | Some(b',') | Some(b':') | None => Ok(()), + Some(b' ' | b'\n' | b'\t' | b'\r' | b'"' | b'[' | b']' | b'{' | b'}' | b',' | b':') + | None => Ok(()), Some(_) => { let position = self.de.read.peek_position(); Err(Error::syntax( @@ -2369,7 +2442,7 @@ where if self_delineated_value { Ok(value) } else { - self.peek_end_of_value().map(|_| value) + self.peek_end_of_value().map(|()| value) } } Err(e) => { @@ -2408,9 +2481,9 @@ where Ok(value) } -/// Deserialize an instance of type `T` from an IO stream of JSON. +/// Deserialize an instance of type `T` from an I/O stream of JSON. /// -/// The content of the IO stream is deserialized directly from the stream +/// The content of the I/O stream is deserialized directly from the stream /// without being buffered in memory by serde_json. /// /// When reading from a source against which short reads are not efficient, such diff --git a/third_party/rust/serde_json/src/error.rs b/third_party/rust/serde_json/src/error.rs index 1875ef08b0..fbf9eb14e5 100644 --- a/third_party/rust/serde_json/src/error.rs +++ b/third_party/rust/serde_json/src/error.rs @@ -9,6 +9,8 @@ use core::str::FromStr; use serde::{de, ser}; #[cfg(feature = "std")] use std::error; +#[cfg(feature = "std")] +use std::io::ErrorKind; /// This type represents all possible errors that can occur when serializing or /// deserializing JSON data. @@ -36,15 +38,16 @@ impl Error { /// The first character in the input and any characters immediately /// following a newline character are in column 1. /// - /// Note that errors may occur in column 0, for example if a read from an IO - /// stream fails immediately following a previously read newline character. + /// Note that errors may occur in column 0, for example if a read from an + /// I/O stream fails immediately following a previously read newline + /// character. pub fn column(&self) -> usize { self.err.column } /// Categorizes the cause of this error. /// - /// - `Category::Io` - failure to read or write bytes on an IO stream + /// - `Category::Io` - failure to read or write bytes on an I/O stream /// - `Category::Syntax` - input that is not syntactically valid JSON /// - `Category::Data` - input data that is semantically incorrect /// - `Category::Eof` - unexpected end of the input data @@ -61,12 +64,15 @@ impl Error { | ErrorCode::ExpectedObjectCommaOrEnd | ErrorCode::ExpectedSomeIdent | ErrorCode::ExpectedSomeValue + | ErrorCode::ExpectedDoubleQuote | ErrorCode::InvalidEscape | ErrorCode::InvalidNumber | ErrorCode::NumberOutOfRange | ErrorCode::InvalidUnicodeCodePoint | ErrorCode::ControlCharacterWhileParsingString | ErrorCode::KeyMustBeAString + | ErrorCode::ExpectedNumericKey + | ErrorCode::FloatKeyMustBeFinite | ErrorCode::LoneLeadingSurrogateInHexEscape | ErrorCode::TrailingComma | ErrorCode::TrailingCharacters @@ -76,7 +82,7 @@ impl Error { } /// Returns true if this error was caused by a failure to read or write - /// bytes on an IO stream. + /// bytes on an I/O stream. pub fn is_io(&self) -> bool { self.classify() == Category::Io } @@ -104,12 +110,61 @@ impl Error { pub fn is_eof(&self) -> bool { self.classify() == Category::Eof } + + /// The kind reported by the underlying standard library I/O error, if this + /// error was caused by a failure to read or write bytes on an I/O stream. + /// + /// # Example + /// + /// ``` + /// use serde_json::Value; + /// use std::io::{self, ErrorKind, Read}; + /// use std::process; + /// + /// struct ReaderThatWillTimeOut<'a>(&'a [u8]); + /// + /// impl<'a> Read for ReaderThatWillTimeOut<'a> { + /// fn read(&mut self, buf: &mut [u8]) -> io::Result { + /// if self.0.is_empty() { + /// Err(io::Error::new(ErrorKind::TimedOut, "timed out")) + /// } else { + /// self.0.read(buf) + /// } + /// } + /// } + /// + /// fn main() { + /// let reader = ReaderThatWillTimeOut(br#" {"k": "#); + /// + /// let _: Value = match serde_json::from_reader(reader) { + /// Ok(value) => value, + /// Err(error) => { + /// if error.io_error_kind() == Some(ErrorKind::TimedOut) { + /// // Maybe this application needs to retry certain kinds of errors. + /// + /// # return; + /// } else { + /// eprintln!("error: {}", error); + /// process::exit(1); + /// } + /// } + /// }; + /// } + /// ``` + #[cfg(feature = "std")] + pub fn io_error_kind(&self) -> Option { + if let ErrorCode::Io(io_error) = &self.err.code { + Some(io_error.kind()) + } else { + None + } + } } /// Categorizes the cause of a `serde_json::Error`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Category { - /// The error was caused by a failure to read or write bytes on an IO + /// The error was caused by a failure to read or write bytes on an I/O /// stream. Io, @@ -134,8 +189,8 @@ pub enum Category { impl From for io::Error { /// Convert a `serde_json::Error` into an `io::Error`. /// - /// JSON syntax and data errors are turned into `InvalidData` IO errors. - /// EOF errors are turned into `UnexpectedEof` IO errors. + /// JSON syntax and data errors are turned into `InvalidData` I/O errors. + /// EOF errors are turned into `UnexpectedEof` I/O errors. /// /// ``` /// use std::io; @@ -165,8 +220,8 @@ impl From for io::Error { } else { match j.classify() { Category::Io => unreachable!(), - Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j), - Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j), + Category::Syntax | Category::Data => io::Error::new(ErrorKind::InvalidData, j), + Category::Eof => io::Error::new(ErrorKind::UnexpectedEof, j), } } } @@ -182,7 +237,7 @@ pub(crate) enum ErrorCode { /// Catchall for syntax error messages Message(Box), - /// Some IO error occurred while serializing or deserializing. + /// Some I/O error occurred while serializing or deserializing. Io(io::Error), /// EOF while parsing a list. @@ -212,6 +267,9 @@ pub(crate) enum ErrorCode { /// Expected this character to start a JSON value. ExpectedSomeValue, + /// Expected this character to be a `"`. + ExpectedDoubleQuote, + /// Invalid hex escape code. InvalidEscape, @@ -230,6 +288,12 @@ pub(crate) enum ErrorCode { /// Object key is not a string. KeyMustBeAString, + /// Contents of key were supposed to be a number. + ExpectedNumericKey, + + /// Object key is a non-finite float value. + FloatKeyMustBeFinite, + /// Lone leading surrogate in hex escape. LoneLeadingSurrogateInHexEscape, @@ -296,6 +360,7 @@ impl Display for ErrorCode { ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"), ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"), ErrorCode::ExpectedSomeValue => f.write_str("expected value"), + ErrorCode::ExpectedDoubleQuote => f.write_str("expected `\"`"), ErrorCode::InvalidEscape => f.write_str("invalid escape"), ErrorCode::InvalidNumber => f.write_str("invalid number"), ErrorCode::NumberOutOfRange => f.write_str("number out of range"), @@ -304,6 +369,12 @@ impl Display for ErrorCode { f.write_str("control character (\\u0000-\\u001F) found while parsing a string") } ErrorCode::KeyMustBeAString => f.write_str("key must be a string"), + ErrorCode::ExpectedNumericKey => { + f.write_str("invalid value: expected key to be a number in quotes") + } + ErrorCode::FloatKeyMustBeFinite => { + f.write_str("float key must be finite (got NaN or +/-inf)") + } ErrorCode::LoneLeadingSurrogateInHexEscape => { f.write_str("lone leading surrogate in hex escape") } @@ -319,7 +390,7 @@ impl serde::de::StdError for Error { #[cfg(feature = "std")] fn source(&self) -> Option<&(dyn error::Error + 'static)> { match &self.err.code { - ErrorCode::Io(err) => Some(err), + ErrorCode::Io(err) => err.source(), _ => None, } } @@ -367,11 +438,20 @@ impl de::Error for Error { #[cold] fn invalid_type(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { - if let de::Unexpected::Unit = unexp { - Error::custom(format_args!("invalid type: null, expected {}", exp)) - } else { - Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) - } + Error::custom(format_args!( + "invalid type: {}, expected {}", + JsonUnexpected(unexp), + exp, + )) + } + + #[cold] + fn invalid_value(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { + Error::custom(format_args!( + "invalid value: {}, expected {}", + JsonUnexpected(unexp), + exp, + )) } } @@ -382,6 +462,22 @@ impl ser::Error for Error { } } +struct JsonUnexpected<'a>(de::Unexpected<'a>); + +impl<'a> Display for JsonUnexpected<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + de::Unexpected::Unit => formatter.write_str("null"), + de::Unexpected::Float(value) => write!( + formatter, + "floating point `{}`", + ryu::Buffer::new().format(value), + ), + unexp => Display::fmt(&unexp, formatter), + } + } +} + // Parse our own error message that looks like "{} at line {} column {}" to work // around erased-serde round-tripping the error through de::Error::custom. fn make_error(mut msg: String) -> Error { diff --git a/third_party/rust/serde_json/src/features_check/error.rs b/third_party/rust/serde_json/src/features_check/error.rs deleted file mode 100644 index 22e58235c7..0000000000 --- a/third_party/rust/serde_json/src/features_check/error.rs +++ /dev/null @@ -1 +0,0 @@ -"serde_json requires that either `std` (default) or `alloc` feature is enabled" diff --git a/third_party/rust/serde_json/src/features_check/mod.rs b/third_party/rust/serde_json/src/features_check/mod.rs deleted file mode 100644 index d12032cef8..0000000000 --- a/third_party/rust/serde_json/src/features_check/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Shows a user-friendly compiler error on incompatible selected features. - -#[allow(unused_macros)] -macro_rules! hide_from_rustfmt { - ($mod:item) => { - $mod - }; -} - -#[cfg(not(any(feature = "std", feature = "alloc")))] -hide_from_rustfmt! { - mod error; -} diff --git a/third_party/rust/serde_json/src/io/core.rs b/third_party/rust/serde_json/src/io/core.rs index 465ab8b249..54c8ddfda4 100644 --- a/third_party/rust/serde_json/src/io/core.rs +++ b/third_party/rust/serde_json/src/io/core.rs @@ -9,7 +9,7 @@ pub enum ErrorKind { Other, } -// IO errors can never occur in no-std mode. All our no-std IO implementations +// I/O errors can never occur in no-std mode. All our no-std I/O implementations // are infallible. pub struct Error; diff --git a/third_party/rust/serde_json/src/lexical/algorithm.rs b/third_party/rust/serde_json/src/lexical/algorithm.rs index a2cbf18aff..eaa5e7ebc2 100644 --- a/third_party/rust/serde_json/src/lexical/algorithm.rs +++ b/third_party/rust/serde_json/src/lexical/algorithm.rs @@ -51,7 +51,10 @@ where // Compute the product of the power, if it overflows, // prematurely return early, otherwise, if we didn't overshoot, // we can get an exact value. - let value = mantissa.checked_mul(power)?; + let value = match mantissa.checked_mul(power) { + None => return None, + Some(value) => value, + }; if value >> mantissa_size != 0 { None } else { diff --git a/third_party/rust/serde_json/src/lexical/bignum.rs b/third_party/rust/serde_json/src/lexical/bignum.rs index f9551f534f..4fa7eed6dd 100644 --- a/third_party/rust/serde_json/src/lexical/bignum.rs +++ b/third_party/rust/serde_json/src/lexical/bignum.rs @@ -3,6 +3,7 @@ //! Big integer type definition. use super::math::*; +#[allow(unused_imports)] use alloc::vec::Vec; /// Storage for a big integer type. diff --git a/third_party/rust/serde_json/src/lexical/digit.rs b/third_party/rust/serde_json/src/lexical/digit.rs index 882aa9eef2..3d150a1afe 100644 --- a/third_party/rust/serde_json/src/lexical/digit.rs +++ b/third_party/rust/serde_json/src/lexical/digit.rs @@ -11,5 +11,8 @@ pub(crate) fn to_digit(c: u8) -> Option { // Add digit to mantissa. #[inline] pub(crate) fn add_digit(value: u64, digit: u32) -> Option { - value.checked_mul(10)?.checked_add(digit as u64) + match value.checked_mul(10) { + None => None, + Some(n) => n.checked_add(digit as u64), + } } diff --git a/third_party/rust/serde_json/src/lexical/errors.rs b/third_party/rust/serde_json/src/lexical/errors.rs index cad4bd3d58..f4f41cdc5a 100644 --- a/third_party/rust/serde_json/src/lexical/errors.rs +++ b/third_party/rust/serde_json/src/lexical/errors.rs @@ -5,8 +5,7 @@ //! This estimates the error in a floating-point representation. //! //! This implementation is loosely based off the Golang implementation, -//! found here: -//! https://golang.org/src/strconv/atof.go +//! found here: use super::float::*; use super::num::*; diff --git a/third_party/rust/serde_json/src/lexical/exponent.rs b/third_party/rust/serde_json/src/lexical/exponent.rs index 6fc51977ed..5e27de893f 100644 --- a/third_party/rust/serde_json/src/lexical/exponent.rs +++ b/third_party/rust/serde_json/src/lexical/exponent.rs @@ -8,8 +8,8 @@ /// the mantissa we do not overflow for comically-long exponents. #[inline] fn into_i32(value: usize) -> i32 { - if value > i32::max_value() as usize { - i32::max_value() + if value > i32::MAX as usize { + i32::MAX } else { value as i32 } diff --git a/third_party/rust/serde_json/src/lexical/large_powers32.rs b/third_party/rust/serde_json/src/lexical/large_powers32.rs index 7991197262..eb8582f5f0 100644 --- a/third_party/rust/serde_json/src/lexical/large_powers32.rs +++ b/third_party/rust/serde_json/src/lexical/large_powers32.rs @@ -2,7 +2,7 @@ //! Precalculated large powers for 32-bit limbs. -/// Large powers (&[u32]) for base5 operations. +/// Large powers (`&[u32]`) for base5 operations. const POW5_1: [u32; 1] = [5]; const POW5_2: [u32; 1] = [25]; const POW5_3: [u32; 1] = [625]; diff --git a/third_party/rust/serde_json/src/lexical/large_powers64.rs b/third_party/rust/serde_json/src/lexical/large_powers64.rs index ee36561088..96554eac1c 100644 --- a/third_party/rust/serde_json/src/lexical/large_powers64.rs +++ b/third_party/rust/serde_json/src/lexical/large_powers64.rs @@ -2,7 +2,7 @@ //! Precalculated large powers for 64-bit limbs. -/// Large powers (&[u64]) for base5 operations. +/// Large powers (`&[u64]`) for base5 operations. const POW5_1: [u64; 1] = [5]; const POW5_2: [u64; 1] = [25]; const POW5_3: [u64; 1] = [625]; diff --git a/third_party/rust/serde_json/src/lexical/math.rs b/third_party/rust/serde_json/src/lexical/math.rs index 37cc1d24ad..d7122bffaf 100644 --- a/third_party/rust/serde_json/src/lexical/math.rs +++ b/third_party/rust/serde_json/src/lexical/math.rs @@ -336,7 +336,7 @@ mod small { pub fn imul(x: &mut Vec, y: Limb) { // Multiply iteratively over all elements, adding the carry each time. let mut carry: Limb = 0; - for xi in x.iter_mut() { + for xi in &mut *x { carry = scalar::imul(xi, y, carry); } @@ -482,7 +482,7 @@ mod small { let rshift = bits - n; let lshift = n; let mut prev: Limb = 0; - for xi in x.iter_mut() { + for xi in &mut *x { let tmp = *xi; *xi <<= lshift; *xi |= prev >> rshift; diff --git a/third_party/rust/serde_json/src/lexical/num.rs b/third_party/rust/serde_json/src/lexical/num.rs index e47e003419..75eee01b81 100644 --- a/third_party/rust/serde_json/src/lexical/num.rs +++ b/third_party/rust/serde_json/src/lexical/num.rs @@ -223,7 +223,7 @@ pub trait Float: Number { const NEGATIVE_INFINITY_BITS: Self::Unsigned; /// Size of the significand (mantissa) without hidden bit. const MANTISSA_SIZE: i32; - /// Bias of the exponet + /// Bias of the exponent const EXPONENT_BIAS: i32; /// Exponent portion of a denormal float. const DENORMAL_EXPONENT: i32; @@ -248,7 +248,6 @@ pub trait Float: Number { fn from_bits(u: Self::Unsigned) -> Self; fn to_bits(self) -> Self::Unsigned; fn is_sign_positive(self) -> bool; - fn is_sign_negative(self) -> bool; /// Returns true if the float is a denormal. #[inline] @@ -368,11 +367,6 @@ impl Float for f32 { fn is_sign_positive(self) -> bool { f32::is_sign_positive(self) } - - #[inline] - fn is_sign_negative(self) -> bool { - f32::is_sign_negative(self) - } } impl Float for f64 { @@ -432,9 +426,4 @@ impl Float for f64 { fn is_sign_positive(self) -> bool { f64::is_sign_positive(self) } - - #[inline] - fn is_sign_negative(self) -> bool { - f64::is_sign_negative(self) - } } diff --git a/third_party/rust/serde_json/src/lexical/rounding.rs b/third_party/rust/serde_json/src/lexical/rounding.rs index 6ec1292aa5..6344875227 100644 --- a/third_party/rust/serde_json/src/lexical/rounding.rs +++ b/third_party/rust/serde_json/src/lexical/rounding.rs @@ -25,7 +25,7 @@ pub(crate) fn lower_n_mask(n: u64) -> u64 { debug_assert!(n <= bits, "lower_n_mask() overflow in shl."); if n == bits { - u64::max_value() + u64::MAX } else { (1 << n) - 1 } diff --git a/third_party/rust/serde_json/src/lib.rs b/third_party/rust/serde_json/src/lib.rs index 48d0fe2191..eabd169f53 100644 --- a/third_party/rust/serde_json/src/lib.rs +++ b/third_party/rust/serde_json/src/lib.rs @@ -55,10 +55,9 @@ //! ``` //! //! A string of JSON data can be parsed into a `serde_json::Value` by the -//! [`serde_json::from_str`][from_str] function. There is also -//! [`from_slice`][from_slice] for parsing from a byte slice &[u8] and -//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or -//! a TCP stream. +//! [`serde_json::from_str`][from_str] function. There is also [`from_slice`] +//! for parsing from a byte slice `&[u8]` and [`from_reader`] for parsing from +//! any `io::Read` like a File or a TCP stream. //! //! ``` //! use serde_json::{Result, Value}; @@ -300,7 +299,7 @@ //! [macro]: crate::json //! [`serde-json-core`]: https://github.com/rust-embedded-community/serde-json-core -#![doc(html_root_url = "https://docs.rs/serde_json/1.0.93")] +#![doc(html_root_url = "https://docs.rs/serde_json/1.0.116")] // Ignored clippy lints #![allow( clippy::collapsible_else_if, @@ -315,18 +314,13 @@ clippy::match_single_binding, clippy::needless_doctest_main, clippy::needless_late_init, - // clippy bug: https://github.com/rust-lang/rust-clippy/issues/8366 - clippy::ptr_arg, clippy::return_self_not_must_use, clippy::transmute_ptr_to_ptr, - clippy::unnecessary_wraps, - // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 - clippy::unnested_or_patterns, + clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133 + clippy::unnecessary_wraps )] // Ignored clippy_pedantic lints #![allow( - // buggy - clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285 // Deserializer::from_str, into_iter clippy::should_implement_trait, // integer and float ser/de requires these sorts of casts @@ -338,6 +332,7 @@ clippy::enum_glob_use, clippy::if_not_else, clippy::integer_division, + clippy::let_underscore_untyped, clippy::map_err_ignore, clippy::match_same_arms, clippy::similar_names, @@ -361,14 +356,25 @@ clippy::missing_errors_doc, clippy::must_use_candidate, )] +// Restrictions +#![deny(clippy::question_mark_used)] #![allow(non_upper_case_globals)] #![deny(missing_docs)] -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] +#[cfg(not(any(feature = "std", feature = "alloc")))] +compile_error! { + "serde_json requires that either `std` (default) or `alloc` feature is enabled" +} + extern crate alloc; #[cfg(feature = "std")] +extern crate std; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[doc(inline)] pub use crate::de::from_reader; #[doc(inline)] @@ -378,6 +384,7 @@ pub use crate::error::{Error, Result}; #[doc(inline)] pub use crate::ser::{to_string, to_string_pretty, to_vec, to_vec_pretty}; #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[doc(inline)] pub use crate::ser::{to_writer, to_writer_pretty, Serializer}; #[doc(inline)] @@ -407,8 +414,6 @@ pub mod ser; mod ser; pub mod value; -mod features_check; - mod io; #[cfg(feature = "std")] mod iter; diff --git a/third_party/rust/serde_json/src/macros.rs b/third_party/rust/serde_json/src/macros.rs index 5287998b46..e8c6cd2ca4 100644 --- a/third_party/rust/serde_json/src/macros.rs +++ b/third_party/rust/serde_json/src/macros.rs @@ -10,7 +10,8 @@ /// "features": [ /// "serde", /// "json" -/// ] +/// ], +/// "homepage": null /// } /// }); /// ``` diff --git a/third_party/rust/serde_json/src/map.rs b/third_party/rust/serde_json/src/map.rs index 3e8a3814c9..520cd6cf53 100644 --- a/third_party/rust/serde_json/src/map.rs +++ b/third_party/rust/serde_json/src/map.rs @@ -11,7 +11,7 @@ use alloc::string::String; use core::borrow::Borrow; use core::fmt::{self, Debug}; use core::hash::Hash; -use core::iter::{FromIterator, FusedIterator}; +use core::iter::FusedIterator; #[cfg(feature = "preserve_order")] use core::mem; use core::ops; @@ -20,7 +20,7 @@ use serde::de; #[cfg(not(feature = "preserve_order"))] use alloc::collections::{btree_map, BTreeMap}; #[cfg(feature = "preserve_order")] -use indexmap::{self, IndexMap}; +use indexmap::IndexMap; /// Represents a JSON key/value type. pub struct Map { @@ -106,7 +106,6 @@ impl Map { /// The key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. #[inline] - #[cfg(any(feature = "preserve_order", not(no_btreemap_get_key_value)))] pub fn get_key_value(&self, key: &Q) -> Option<(&String, &Value)> where String: Borrow, @@ -131,6 +130,12 @@ impl Map { /// /// The key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. + /// + /// If serde_json's "preserve_order" is enabled, `.remove(key)` is + /// equivalent to [`.swap_remove(key)`][Self::swap_remove], replacing this + /// entry's position with the last element. If you need to preserve the + /// relative order of the keys in the map, use + /// [`.shift_remove(key)`][Self::shift_remove] instead. #[inline] pub fn remove(&mut self, key: &Q) -> Option where @@ -138,7 +143,7 @@ impl Map { Q: ?Sized + Ord + Eq + Hash, { #[cfg(feature = "preserve_order")] - return self.map.swap_remove(key); + return self.swap_remove(key); #[cfg(not(feature = "preserve_order"))] return self.map.remove(key); } @@ -148,49 +153,94 @@ impl Map { /// /// The key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. + /// + /// If serde_json's "preserve_order" is enabled, `.remove_entry(key)` is + /// equivalent to [`.swap_remove_entry(key)`][Self::swap_remove_entry], + /// replacing this entry's position with the last element. If you need to + /// preserve the relative order of the keys in the map, use + /// [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead. + #[inline] pub fn remove_entry(&mut self, key: &Q) -> Option<(String, Value)> where String: Borrow, Q: ?Sized + Ord + Eq + Hash, { - #[cfg(any(feature = "preserve_order", not(no_btreemap_remove_entry)))] + #[cfg(feature = "preserve_order")] + return self.swap_remove_entry(key); + #[cfg(not(feature = "preserve_order"))] return self.map.remove_entry(key); - #[cfg(all( - not(feature = "preserve_order"), - no_btreemap_remove_entry, - not(no_btreemap_get_key_value), - ))] - { - let (key, _value) = self.map.get_key_value(key)?; - let key = key.clone(); - let value = self.map.remove::(&key)?; - Some((key, value)) - } - #[cfg(all( - not(feature = "preserve_order"), - no_btreemap_remove_entry, - no_btreemap_get_key_value, - ))] - { - use core::ops::{Bound, RangeBounds}; - - struct Key<'a, Q: ?Sized>(&'a Q); - - impl<'a, Q: ?Sized> RangeBounds for Key<'a, Q> { - fn start_bound(&self) -> Bound<&Q> { - Bound::Included(self.0) - } - fn end_bound(&self) -> Bound<&Q> { - Bound::Included(self.0) - } - } + } - let mut range = self.map.range(Key(key)); - let (key, _value) = range.next()?; - let key = key.clone(); - let value = self.map.remove::(&key)?; - Some((key, value)) - } + /// Removes and returns the value corresponding to the key from the map. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + /// + /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn swap_remove(&mut self, key: &Q) -> Option + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.swap_remove(key) + } + + /// Remove and return the key-value pair. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + /// + /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn swap_remove_entry(&mut self, key: &Q) -> Option<(String, Value)> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.swap_remove_entry(key) + } + + /// Removes and returns the value corresponding to the key from the map. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + /// + /// [`Vec::remove`]: std::vec::Vec::remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn shift_remove(&mut self, key: &Q) -> Option + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.shift_remove(key) + } + + /// Remove and return the key-value pair. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + /// + /// [`Vec::remove`]: std::vec::Vec::remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn shift_remove_entry(&mut self, key: &Q) -> Option<(String, Value)> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.shift_remove_entry(key) } /// Moves all elements from other into self, leaving other empty. @@ -276,7 +326,6 @@ impl Map { /// /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` /// returns `false`. - #[cfg(not(no_btreemap_retain))] #[inline] pub fn retain(&mut self, f: F) where diff --git a/third_party/rust/serde_json/src/number.rs b/third_party/rust/serde_json/src/number.rs index 21a76411cc..878a3dcb20 100644 --- a/third_party/rust/serde_json/src/number.rs +++ b/third_party/rust/serde_json/src/number.rs @@ -82,7 +82,7 @@ impl Number { /// ``` /// # use serde_json::json; /// # - /// let big = i64::max_value() as u64 + 10; + /// let big = i64::MAX as u64 + 10; /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); /// /// assert!(v["a"].is_i64()); @@ -97,7 +97,7 @@ impl Number { pub fn is_i64(&self) -> bool { #[cfg(not(feature = "arbitrary_precision"))] match self.n { - N::PosInt(v) => v <= i64::max_value() as u64, + N::PosInt(v) => v <= i64::MAX as u64, N::NegInt(_) => true, N::Float(_) => false, } @@ -177,7 +177,7 @@ impl Number { /// ``` /// # use serde_json::json; /// # - /// let big = i64::max_value() as u64 + 10; + /// let big = i64::MAX as u64 + 10; /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); /// /// assert_eq!(v["a"].as_i64(), Some(64)); @@ -189,7 +189,7 @@ impl Number { #[cfg(not(feature = "arbitrary_precision"))] match self.n { N::PosInt(n) => { - if n <= i64::max_value() as u64 { + if n <= i64::MAX as u64 { Some(n as i64) } else { None @@ -279,6 +279,62 @@ impl Number { } } + /// Returns the exact original JSON representation that this Number was + /// parsed from. + /// + /// For numbers constructed not via parsing, such as by `From`, returns + /// the JSON representation that serde\_json would serialize for this + /// number. + /// + /// ``` + /// # use serde_json::Number; + /// for value in [ + /// "7", + /// "12.34", + /// "34e-56789", + /// "0.0123456789000000012345678900000001234567890000123456789", + /// "343412345678910111213141516171819202122232425262728293034", + /// "-343412345678910111213141516171819202122232425262728293031", + /// ] { + /// let number: Number = serde_json::from_str(value).unwrap(); + /// assert_eq!(number.as_str(), value); + /// } + /// ``` + #[cfg(feature = "arbitrary_precision")] + #[cfg_attr(docsrs, doc(cfg(feature = "arbitrary_precision")))] + pub fn as_str(&self) -> &str { + &self.n + } + + pub(crate) fn as_f32(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n as f32), + N::NegInt(n) => Some(n as f32), + N::Float(n) => Some(n as f32), + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse::().ok().filter(|float| float.is_finite()) + } + + pub(crate) fn from_f32(f: f32) -> Option { + if f.is_finite() { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::Float(f as f64) + } + #[cfg(feature = "arbitrary_precision")] + { + ryu::Buffer::new().format_finite(f).to_owned() + } + }; + Some(Number { n }) + } else { + None + } + } + #[cfg(feature = "arbitrary_precision")] /// Not public API. Only tests use this. #[doc(hidden)] @@ -332,8 +388,8 @@ impl Serialize for Number { { use serde::ser::SerializeStruct; - let mut s = serializer.serialize_struct(TOKEN, 1)?; - s.serialize_field(TOKEN, &self.n)?; + let mut s = tri!(serializer.serialize_struct(TOKEN, 1)); + tri!(s.serialize_field(TOKEN, &self.n)); s.end() } } @@ -377,11 +433,11 @@ impl<'de> Deserialize<'de> for Number { where V: de::MapAccess<'de>, { - let value = visitor.next_key::()?; + let value = tri!(visitor.next_key::()); if value.is_none() { return Err(de::Error::invalid_type(Unexpected::Map, &self)); } - let v: NumberFromString = visitor.next_value()?; + let v: NumberFromString = tri!(visitor.next_value()); Ok(v.value) } } @@ -420,7 +476,7 @@ impl<'de> de::Deserialize<'de> for NumberKey { } } - deserializer.deserialize_identifier(FieldVisitor)?; + tri!(deserializer.deserialize_identifier(FieldVisitor)); Ok(NumberKey) } } @@ -523,7 +579,7 @@ macro_rules! deserialize_number { where V: de::Visitor<'de>, { - visitor.$visit(self.n.parse().map_err(|_| invalid_number())?) + visitor.$visit(tri!(self.n.parse().map_err(|_| invalid_number()))) } }; } diff --git a/third_party/rust/serde_json/src/raw.rs b/third_party/rust/serde_json/src/raw.rs index 6aa4ffcb61..22d14441ec 100644 --- a/third_party/rust/serde_json/src/raw.rs +++ b/third_party/rust/serde_json/src/raw.rs @@ -112,8 +112,8 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; /// raw_value: Box, /// } /// ``` -#[cfg_attr(not(doc), repr(transparent))] #[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] +#[repr(transparent)] pub struct RawValue { json: str, } @@ -177,11 +177,9 @@ impl RawValue { /// - the input has no leading or trailing whitespace, and /// - the input has capacity equal to its length. pub fn from_string(json: String) -> Result, Error> { - { - let borrowed = crate::from_str::<&Self>(&json)?; - if borrowed.json.len() < json.len() { - return Ok(borrowed.to_owned()); - } + let borrowed = tri!(crate::from_str::<&Self>(&json)); + if borrowed.json.len() < json.len() { + return Ok(borrowed.to_owned()); } Ok(Self::from_owned(json.into_boxed_str())) } @@ -287,7 +285,7 @@ pub fn to_raw_value(value: &T) -> Result, Error> where T: ?Sized + Serialize, { - let json_string = crate::to_string(value)?; + let json_string = tri!(crate::to_string(value)); Ok(RawValue::from_owned(json_string.into_boxed_str())) } @@ -298,8 +296,8 @@ impl Serialize for RawValue { where S: Serializer, { - let mut s = serializer.serialize_struct(TOKEN, 1)?; - s.serialize_field(TOKEN, &self.json)?; + let mut s = tri!(serializer.serialize_struct(TOKEN, 1)); + tri!(s.serialize_field(TOKEN, &self.json)); s.end() } } @@ -322,7 +320,7 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawValue { where V: MapAccess<'de>, { - let value = visitor.next_key::()?; + let value = tri!(visitor.next_key::()); if value.is_none() { return Err(de::Error::invalid_type(Unexpected::Map, &self)); } @@ -352,7 +350,7 @@ impl<'de> Deserialize<'de> for Box { where V: MapAccess<'de>, { - let value = visitor.next_key::()?; + let value = tri!(visitor.next_key::()); if value.is_none() { return Err(de::Error::invalid_type(Unexpected::Map, &self)); } @@ -392,7 +390,7 @@ impl<'de> Deserialize<'de> for RawKey { } } - deserializer.deserialize_identifier(FieldVisitor)?; + tri!(deserializer.deserialize_identifier(FieldVisitor)); Ok(RawKey) } } @@ -529,3 +527,251 @@ impl<'de> MapAccess<'de> for BorrowedRawDeserializer<'de> { seed.deserialize(BorrowedStrDeserializer::new(self.raw_value.take().unwrap())) } } + +impl<'de> IntoDeserializer<'de, Error> for &'de RawValue { + type Deserializer = &'de RawValue; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> Deserializer<'de> for &'de RawValue { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_any(visitor) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_bool(visitor) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i8(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i16(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i32(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i64(visitor) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i128(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u8(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u16(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u32(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u64(visitor) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u128(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_f32(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_f64(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_char(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_str(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_string(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_bytes(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_byte_buf(visitor) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_option(visitor) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_unit(visitor) + } + + fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_unit_struct(name, visitor) + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_newtype_struct(name, visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_seq(visitor) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_tuple(len, visitor) + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_tuple_struct(name, len, visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_map(visitor) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_struct(name, fields, visitor) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_enum(name, variants, visitor) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_identifier(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_ignored_any(visitor) + } +} diff --git a/third_party/rust/serde_json/src/read.rs b/third_party/rust/serde_json/src/read.rs index fc3a3ca748..a426911c7d 100644 --- a/third_party/rust/serde_json/src/read.rs +++ b/third_party/rust/serde_json/src/read.rs @@ -14,11 +14,13 @@ use crate::iter::LineColIterator; use crate::raw::BorrowedRawDeserializer; #[cfg(all(feature = "raw_value", feature = "std"))] use crate::raw::OwnedRawDeserializer; +#[cfg(all(feature = "raw_value", feature = "std"))] +use alloc::string::String; #[cfg(feature = "raw_value")] use serde::de::Visitor; /// Trait used by the deserializer for iterating over input. This is manually -/// "specialized" for iterating over &[u8]. Once feature(specialization) is +/// "specialized" for iterating over `&[u8]`. Once feature(specialization) is /// stable we can use actual specialization. /// /// This trait is sealed and cannot be implemented for types outside of @@ -81,7 +83,7 @@ pub trait Read<'de>: private::Sealed { #[doc(hidden)] fn ignore_str(&mut self) -> Result<()>; - /// Assumes the previous byte was a hex escape sequnce ('\u') in a string. + /// Assumes the previous byte was a hex escape sequence ('\u') in a string. /// Parses next hexadecimal sequence. #[doc(hidden)] fn decode_hex_escape(&mut self) -> Result; diff --git a/third_party/rust/serde_json/src/ser.rs b/third_party/rust/serde_json/src/ser.rs index 80c2deb0c1..3742e0bef4 100644 --- a/third_party/rust/serde_json/src/ser.rs +++ b/third_party/rust/serde_json/src/ser.rs @@ -189,12 +189,9 @@ where #[inline] fn serialize_bytes(self, value: &[u8]) -> Result<()> { - use serde::ser::SerializeSeq; - let mut seq = tri!(self.serialize_seq(Some(value.len()))); - for byte in value { - tri!(seq.serialize_element(byte)); - } - seq.end() + self.formatter + .write_byte_array(&mut self.writer, value) + .map_err(Error::io) } #[inline] @@ -439,17 +436,15 @@ where .formatter .begin_string(&mut self.writer) .map_err(Error::io)); - { - let mut adapter = Adapter { - writer: &mut self.writer, - formatter: &mut self.formatter, - error: None, - }; - match write!(adapter, "{}", value) { - Ok(()) => debug_assert!(adapter.error.is_none()), - Err(fmt::Error) => { - return Err(Error::io(adapter.error.expect("there should be an error"))); - } + let mut adapter = Adapter { + writer: &mut self.writer, + formatter: &mut self.formatter, + error: None, + }; + match write!(adapter, "{}", value) { + Ok(()) => debug_assert!(adapter.error.is_none()), + Err(fmt::Error) => { + return Err(Error::io(adapter.error.expect("there should be an error"))); } } self.formatter @@ -789,6 +784,10 @@ fn key_must_be_a_string() -> Error { Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) } +fn float_key_must_be_finite() -> Error { + Error::syntax(ErrorCode::FloatKeyMustBeFinite, 0, 0) +} + impl<'a, W, F> ser::Serializer for MapKeySerializer<'a, W, F> where W: io::Write, @@ -828,8 +827,21 @@ where type SerializeStruct = Impossible<(), Error>; type SerializeStructVariant = Impossible<(), Error>; - fn serialize_bool(self, _value: bool) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_bool(self, value: bool) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_bool(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) } fn serialize_i8(self, value: i8) -> Result<()> { @@ -1002,12 +1014,46 @@ where .map_err(Error::io) } - fn serialize_f32(self, _value: f32) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_f32(self, value: f32) -> Result<()> { + if !value.is_finite() { + return Err(float_key_must_be_finite()); + } + + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_f32(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) } - fn serialize_f64(self, _value: f64) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_f64(self, value: f64) -> Result<()> { + if !value.is_finite() { + return Err(float_key_must_be_finite()); + } + + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_f64(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) } fn serialize_char(self, value: char) -> Result<()> { @@ -1043,11 +1089,11 @@ where Err(key_must_be_a_string()) } - fn serialize_some(self, _value: &T) -> Result<()> + fn serialize_some(self, value: &T) -> Result<()> where T: ?Sized + Serialize, { - Err(key_must_be_a_string()) + value.serialize(self) } fn serialize_seq(self, _len: Option) -> Result { @@ -1734,6 +1780,24 @@ pub trait Formatter { writer.write_all(s) } + /// Writes the representation of a byte array. Formatters can choose whether + /// to represent bytes as a JSON array of integers (the default), or some + /// JSON string encoding like hex or base64. + fn write_byte_array(&mut self, writer: &mut W, value: &[u8]) -> io::Result<()> + where + W: ?Sized + io::Write, + { + tri!(self.begin_array(writer)); + let mut first = true; + for byte in value { + tri!(self.begin_array_value(writer, first)); + tri!(self.write_u8(writer, *byte)); + tri!(self.end_array_value(writer)); + first = false; + } + self.end_array(writer) + } + /// Called before every array. Writes a `[` to the specified /// writer. #[inline] @@ -2062,7 +2126,9 @@ static ESCAPE: [u8; 256] = [ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F ]; -/// Serialize the given data structure as JSON into the IO stream. +/// Serialize the given data structure as JSON into the I/O stream. +/// +/// Serialization guarantees it only feeds valid UTF-8 sequences to the writer. /// /// # Errors /// @@ -2079,9 +2145,11 @@ where value.serialize(&mut ser) } -/// Serialize the given data structure as pretty-printed JSON into the IO +/// Serialize the given data structure as pretty-printed JSON into the I/O /// stream. /// +/// Serialization guarantees it only feeds valid UTF-8 sequences to the writer. +/// /// # Errors /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to diff --git a/third_party/rust/serde_json/src/value/de.rs b/third_party/rust/serde_json/src/value/de.rs index 9c266d08ae..936725635f 100644 --- a/third_party/rust/serde_json/src/value/de.rs +++ b/third_party/rust/serde_json/src/value/de.rs @@ -1,4 +1,4 @@ -use crate::error::Error; +use crate::error::{Error, ErrorCode}; use crate::map::Map; use crate::number::Number; use crate::value::Value; @@ -106,15 +106,15 @@ impl<'de> Deserialize<'de> for Value { where V: MapAccess<'de>, { - match visitor.next_key_seed(KeyClassifier)? { + match tri!(visitor.next_key_seed(KeyClassifier)) { #[cfg(feature = "arbitrary_precision")] Some(KeyClass::Number) => { - let number: NumberFromString = visitor.next_value()?; + let number: NumberFromString = tri!(visitor.next_value()); Ok(Value::Number(number.value)) } #[cfg(feature = "raw_value")] Some(KeyClass::RawValue) => { - let value = visitor.next_value_seed(crate::raw::BoxedFromString)?; + let value = tri!(visitor.next_value_seed(crate::raw::BoxedFromString)); crate::from_str(value.get()).map_err(de::Error::custom) } Some(KeyClass::Map(first_key)) => { @@ -219,6 +219,8 @@ impl<'de> serde::Deserializer<'de> for Value { Value::Number(n) => n.deserialize_any(visitor), #[cfg(any(feature = "std", feature = "alloc"))] Value::String(v) => visitor.visit_string(v), + #[cfg(not(any(feature = "std", feature = "alloc")))] + Value::String(_) => unreachable!(), Value::Array(v) => visit_array(v, visitor), Value::Object(v) => visit_object(v, visitor), } @@ -482,6 +484,14 @@ impl<'de> IntoDeserializer<'de, Error> for Value { } } +impl<'de> IntoDeserializer<'de, Error> for &'de Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + struct VariantDeserializer { value: Option, } @@ -1120,18 +1130,30 @@ struct MapKeyDeserializer<'de> { key: Cow<'de, str>, } -macro_rules! deserialize_integer_key { - ($method:ident => $visit:ident) => { +macro_rules! deserialize_numeric_key { + ($method:ident) => { + deserialize_numeric_key!($method, deserialize_number); + }; + + ($method:ident, $using:ident) => { fn $method(self, visitor: V) -> Result where V: Visitor<'de>, { - match (self.key.parse(), self.key) { - (Ok(integer), _) => visitor.$visit(integer), - (Err(_), Cow::Borrowed(s)) => visitor.visit_borrowed_str(s), - #[cfg(any(feature = "std", feature = "alloc"))] - (Err(_), Cow::Owned(s)) => visitor.visit_string(s), + let mut de = crate::Deserializer::from_str(&self.key); + + match tri!(de.peek()) { + Some(b'0'..=b'9' | b'-') => {} + _ => return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0)), + } + + let number = tri!(de.$using(visitor)); + + if tri!(de.peek()).is_some() { + return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0)); } + + Ok(number) } }; } @@ -1146,16 +1168,38 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { BorrowedCowStrDeserializer::new(self.key).deserialize_any(visitor) } - deserialize_integer_key!(deserialize_i8 => visit_i8); - deserialize_integer_key!(deserialize_i16 => visit_i16); - deserialize_integer_key!(deserialize_i32 => visit_i32); - deserialize_integer_key!(deserialize_i64 => visit_i64); - deserialize_integer_key!(deserialize_i128 => visit_i128); - deserialize_integer_key!(deserialize_u8 => visit_u8); - deserialize_integer_key!(deserialize_u16 => visit_u16); - deserialize_integer_key!(deserialize_u32 => visit_u32); - deserialize_integer_key!(deserialize_u64 => visit_u64); - deserialize_integer_key!(deserialize_u128 => visit_u128); + deserialize_numeric_key!(deserialize_i8); + deserialize_numeric_key!(deserialize_i16); + deserialize_numeric_key!(deserialize_i32); + deserialize_numeric_key!(deserialize_i64); + deserialize_numeric_key!(deserialize_u8); + deserialize_numeric_key!(deserialize_u16); + deserialize_numeric_key!(deserialize_u32); + deserialize_numeric_key!(deserialize_u64); + #[cfg(not(feature = "float_roundtrip"))] + deserialize_numeric_key!(deserialize_f32); + deserialize_numeric_key!(deserialize_f64); + + #[cfg(feature = "float_roundtrip")] + deserialize_numeric_key!(deserialize_f32, do_deserialize_f32); + deserialize_numeric_key!(deserialize_i128, do_deserialize_i128); + deserialize_numeric_key!(deserialize_u128, do_deserialize_u128); + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + if self.key == "true" { + visitor.visit_bool(true) + } else if self.key == "false" { + visitor.visit_bool(false) + } else { + Err(serde::de::Error::invalid_type( + Unexpected::Str(&self.key), + &visitor, + )) + } + } #[inline] fn deserialize_option(self, visitor: V) -> Result @@ -1193,8 +1237,8 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { } forward_to_deserialize_any! { - bool f32 f64 char str string bytes byte_buf unit unit_struct seq tuple - tuple_struct map struct identifier ignored_any + char str string bytes byte_buf unit unit_struct seq tuple tuple_struct + map struct identifier ignored_any } } @@ -1297,6 +1341,8 @@ impl<'de> de::Deserializer<'de> for BorrowedCowStrDeserializer<'de> { Cow::Borrowed(string) => visitor.visit_borrowed_str(string), #[cfg(any(feature = "std", feature = "alloc"))] Cow::Owned(string) => visitor.visit_string(string), + #[cfg(not(any(feature = "std", feature = "alloc")))] + Cow::Owned(_) => unreachable!(), } } @@ -1327,7 +1373,7 @@ impl<'de> de::EnumAccess<'de> for BorrowedCowStrDeserializer<'de> { where T: de::DeserializeSeed<'de>, { - let value = seed.deserialize(self)?; + let value = tri!(seed.deserialize(self)); Ok((value, UnitOnly)) } } diff --git a/third_party/rust/serde_json/src/value/from.rs b/third_party/rust/serde_json/src/value/from.rs index c5a6a3960b..ed1e3338b0 100644 --- a/third_party/rust/serde_json/src/value/from.rs +++ b/third_party/rust/serde_json/src/value/from.rs @@ -4,7 +4,6 @@ use crate::number::Number; use alloc::borrow::Cow; use alloc::string::{String, ToString}; use alloc::vec::Vec; -use core::iter::FromIterator; macro_rules! from_integer { ($($ty:ident)*) => { @@ -29,7 +28,8 @@ from_integer! { } impl From for Value { - /// Convert 32-bit floating point number to `Value` + /// Convert 32-bit floating point number to `Value::Number`, or + /// `Value::Null` if infinite or NaN. /// /// # Examples /// @@ -40,12 +40,13 @@ impl From for Value { /// let x: Value = f.into(); /// ``` fn from(f: f32) -> Self { - From::from(f as f64) + Number::from_f32(f).map_or(Value::Null, Value::Number) } } impl From for Value { - /// Convert 64-bit floating point number to `Value` + /// Convert 64-bit floating point number to `Value::Number`, or + /// `Value::Null` if infinite or NaN. /// /// # Examples /// @@ -61,7 +62,7 @@ impl From for Value { } impl From for Value { - /// Convert boolean to `Value` + /// Convert boolean to `Value::Bool`. /// /// # Examples /// @@ -77,7 +78,7 @@ impl From for Value { } impl From for Value { - /// Convert `String` to `Value` + /// Convert `String` to `Value::String`. /// /// # Examples /// @@ -92,8 +93,8 @@ impl From for Value { } } -impl<'a> From<&'a str> for Value { - /// Convert string slice to `Value` +impl From<&str> for Value { + /// Convert string slice to `Value::String`. /// /// # Examples /// @@ -109,7 +110,7 @@ impl<'a> From<&'a str> for Value { } impl<'a> From> for Value { - /// Convert copy-on-write string to `Value` + /// Convert copy-on-write string to `Value::String`. /// /// # Examples /// @@ -134,7 +135,7 @@ impl<'a> From> for Value { } impl From for Value { - /// Convert `Number` to `Value` + /// Convert `Number` to `Value::Number`. /// /// # Examples /// @@ -150,7 +151,7 @@ impl From for Value { } impl From> for Value { - /// Convert map (with string keys) to `Value` + /// Convert map (with string keys) to `Value::Object`. /// /// # Examples /// @@ -167,7 +168,7 @@ impl From> for Value { } impl> From> for Value { - /// Convert a `Vec` to `Value` + /// Convert a `Vec` to `Value::Array`. /// /// # Examples /// @@ -182,8 +183,8 @@ impl> From> for Value { } } -impl<'a, T: Clone + Into> From<&'a [T]> for Value { - /// Convert a slice to `Value` +impl> From<&[T]> for Value { + /// Convert a slice to `Value::Array`. /// /// # Examples /// @@ -193,13 +194,13 @@ impl<'a, T: Clone + Into> From<&'a [T]> for Value { /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; /// let x: Value = v.into(); /// ``` - fn from(f: &'a [T]) -> Self { + fn from(f: &[T]) -> Self { Value::Array(f.iter().cloned().map(Into::into).collect()) } } impl> FromIterator for Value { - /// Convert an iteratable type to a `Value` + /// Create a `Value::Array` by collecting an iterator of array elements. /// /// # Examples /// @@ -229,7 +230,7 @@ impl> FromIterator for Value { } impl, V: Into> FromIterator<(K, V)> for Value { - /// Convert an iteratable type to a `Value` + /// Create a `Value::Object` by collecting an iterator of key-value pairs. /// /// # Examples /// @@ -249,7 +250,7 @@ impl, V: Into> FromIterator<(K, V)> for Value { } impl From<()> for Value { - /// Convert `()` to `Value` + /// Convert `()` to `Value::Null`. /// /// # Examples /// diff --git a/third_party/rust/serde_json/src/value/index.rs b/third_party/rust/serde_json/src/value/index.rs index c74042b75a..891ca8ef73 100644 --- a/third_party/rust/serde_json/src/value/index.rs +++ b/third_party/rust/serde_json/src/value/index.rs @@ -116,7 +116,7 @@ impl Index for String { } } -impl<'a, T> Index for &'a T +impl Index for &T where T: ?Sized + Index, { diff --git a/third_party/rust/serde_json/src/value/mod.rs b/third_party/rust/serde_json/src/value/mod.rs index 470b6b24da..b3f51ea0db 100644 --- a/third_party/rust/serde_json/src/value/mod.rs +++ b/third_party/rust/serde_json/src/value/mod.rs @@ -106,6 +106,7 @@ pub use crate::map::Map; pub use crate::number::Number; #[cfg(feature = "raw_value")] +#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] pub use crate::raw::{to_raw_value, RawValue}; /// Represents any valid JSON value. @@ -182,11 +183,11 @@ impl Debug for Value { Value::Number(number) => Debug::fmt(number, formatter), Value::String(string) => write!(formatter, "String({:?})", string), Value::Array(vec) => { - formatter.write_str("Array ")?; + tri!(formatter.write_str("Array ")); Debug::fmt(vec, formatter) } Value::Object(map) => { - formatter.write_str("Object ")?; + tri!(formatter.write_str("Object ")); Debug::fmt(map, formatter) } } @@ -514,6 +515,28 @@ impl Value { } } + /// If the `Value` is a Number, returns the associated [`Number`]. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_json::{json, Number}; + /// # + /// let v = json!({ "a": 1, "b": 2.2, "c": -3, "d": "4" }); + /// + /// assert_eq!(v["a"].as_number(), Some(&Number::from(1u64))); + /// assert_eq!(v["b"].as_number(), Some(&Number::from_f64(2.2).unwrap())); + /// assert_eq!(v["c"].as_number(), Some(&Number::from(-3i64))); + /// + /// // The string `"4"` is not a number. + /// assert_eq!(v["d"].as_number(), None); + /// ``` + pub fn as_number(&self) -> Option<&Number> { + match self { + Value::Number(number) => Some(number), + _ => None, + } + } + /// Returns true if the `Value` is an integer between `i64::MIN` and /// `i64::MAX`. /// @@ -889,7 +912,6 @@ mod ser; /// ``` /// use serde::Serialize; /// use serde_json::json; -/// /// use std::error::Error; /// /// #[derive(Serialize)] @@ -898,7 +920,7 @@ mod ser; /// location: String, /// } /// -/// fn compare_json_values() -> Result<(), Box> { +/// fn compare_json_values() -> Result<(), Box> { /// let u = User { /// fingerprint: "0xF9BA143B95FF6D82".to_owned(), /// location: "Menlo Park, CA".to_owned(), diff --git a/third_party/rust/serde_json/src/value/partial_eq.rs b/third_party/rust/serde_json/src/value/partial_eq.rs index b4ef84c4f3..46c1dbc33b 100644 --- a/third_party/rust/serde_json/src/value/partial_eq.rs +++ b/third_party/rust/serde_json/src/value/partial_eq.rs @@ -9,6 +9,13 @@ fn eq_u64(value: &Value, other: u64) -> bool { value.as_u64().map_or(false, |i| i == other) } +fn eq_f32(value: &Value, other: f32) -> bool { + match value { + Value::Number(n) => n.as_f32().map_or(false, |i| i == other), + _ => false, + } +} + fn eq_f64(value: &Value, other: f64) -> bool { value.as_f64().map_or(false, |i| i == other) } @@ -27,7 +34,7 @@ impl PartialEq for Value { } } -impl<'a> PartialEq<&'a str> for Value { +impl PartialEq<&str> for Value { fn eq(&self, other: &&str) -> bool { eq_str(self, *other) } @@ -39,7 +46,7 @@ impl PartialEq for str { } } -impl<'a> PartialEq for &'a str { +impl PartialEq for &str { fn eq(&self, other: &Value) -> bool { eq_str(other, *self) } @@ -90,6 +97,7 @@ macro_rules! partialeq_numeric { partialeq_numeric! { eq_i64[i8 i16 i32 i64 isize] eq_u64[u8 u16 u32 u64 usize] - eq_f64[f32 f64] + eq_f32[f32] + eq_f64[f64] eq_bool[bool] } diff --git a/third_party/rust/serde_json/src/value/ser.rs b/third_party/rust/serde_json/src/value/ser.rs index a29814e92a..e869ae160f 100644 --- a/third_party/rust/serde_json/src/value/ser.rs +++ b/third_party/rust/serde_json/src/value/ser.rs @@ -1,12 +1,9 @@ use crate::error::{Error, ErrorCode, Result}; use crate::map::Map; -use crate::number::Number; use crate::value::{to_value, Value}; use alloc::borrow::ToOwned; use alloc::string::{String, ToString}; use alloc::vec::Vec; -#[cfg(not(feature = "arbitrary_precision"))] -use core::convert::TryFrom; use core::fmt::Display; use core::result; use serde::ser::{Impossible, Serialize}; @@ -32,6 +29,8 @@ impl Serialize for Value { } map.end() } + #[cfg(not(any(feature = "std", feature = "alloc")))] + Value::Object(_) => unreachable!(), } } } @@ -149,13 +148,13 @@ impl serde::Serializer for Serializer { } #[inline] - fn serialize_f32(self, value: f32) -> Result { - self.serialize_f64(value as f64) + fn serialize_f32(self, float: f32) -> Result { + Ok(Value::from(float)) } #[inline] - fn serialize_f64(self, value: f64) -> Result { - Ok(Number::from_f64(value).map_or(Value::Null, Value::Number)) + fn serialize_f64(self, float: f64) -> Result { + Ok(Value::from(float)) } #[inline] @@ -452,6 +451,10 @@ fn key_must_be_a_string() -> Error { Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) } +fn float_key_must_be_finite() -> Error { + Error::syntax(ErrorCode::FloatKeyMustBeFinite, 0, 0) +} + impl serde::Serializer for MapKeySerializer { type Ok = String; type Error = Error; @@ -482,8 +485,8 @@ impl serde::Serializer for MapKeySerializer { value.serialize(self) } - fn serialize_bool(self, _value: bool) -> Result { - Err(key_must_be_a_string()) + fn serialize_bool(self, value: bool) -> Result { + Ok(value.to_string()) } fn serialize_i8(self, value: i8) -> Result { @@ -518,12 +521,20 @@ impl serde::Serializer for MapKeySerializer { Ok(value.to_string()) } - fn serialize_f32(self, _value: f32) -> Result { - Err(key_must_be_a_string()) + fn serialize_f32(self, value: f32) -> Result { + if value.is_finite() { + Ok(ryu::Buffer::new().format_finite(value).to_owned()) + } else { + Err(float_key_must_be_finite()) + } } - fn serialize_f64(self, _value: f64) -> Result { - Err(key_must_be_a_string()) + fn serialize_f64(self, value: f64) -> Result { + if value.is_finite() { + Ok(ryu::Buffer::new().format_finite(value).to_owned()) + } else { + Err(float_key_must_be_finite()) + } } #[inline] @@ -641,7 +652,7 @@ impl serde::ser::SerializeStruct for SerializeMap { #[cfg(feature = "arbitrary_precision")] SerializeMap::Number { out_value } => { if key == crate::number::TOKEN { - *out_value = Some(value.serialize(NumberValueEmitter)?); + *out_value = Some(tri!(value.serialize(NumberValueEmitter))); Ok(()) } else { Err(invalid_number()) @@ -650,7 +661,7 @@ impl serde::ser::SerializeStruct for SerializeMap { #[cfg(feature = "raw_value")] SerializeMap::RawValue { out_value } => { if key == crate::raw::TOKEN { - *out_value = Some(value.serialize(RawValueEmitter)?); + *out_value = Some(tri!(value.serialize(RawValueEmitter))); Ok(()) } else { Err(invalid_raw_value()) diff --git a/third_party/rust/serde_json/tests/lexical.rs b/third_party/rust/serde_json/tests/lexical.rs index 6e0f07b8c3..368c84478e 100644 --- a/third_party/rust/serde_json/tests/lexical.rs +++ b/third_party/rust/serde_json/tests/lexical.rs @@ -9,6 +9,7 @@ clippy::excessive_precision, clippy::float_cmp, clippy::if_not_else, + clippy::let_underscore_untyped, clippy::module_name_repetitions, clippy::needless_late_init, clippy::shadow_unrelated, @@ -25,11 +26,6 @@ extern crate alloc; #[path = "../src/lexical/mod.rs"] mod lexical; -mod lib { - pub use std::vec::Vec; - pub use std::{cmp, iter, mem, ops}; -} - #[path = "lexical/algorithm.rs"] mod algorithm; diff --git a/third_party/rust/serde_json/tests/lexical/exponent.rs b/third_party/rust/serde_json/tests/lexical/exponent.rs index f7a847be38..c109ff07df 100644 --- a/third_party/rust/serde_json/tests/lexical/exponent.rs +++ b/third_party/rust/serde_json/tests/lexical/exponent.rs @@ -17,38 +17,20 @@ fn scientific_exponent_test() { assert_eq!(scientific_exponent(-10, 2, 20), -9); // Underflow - assert_eq!( - scientific_exponent(i32::min_value(), 0, 0), - i32::min_value() - ); - assert_eq!( - scientific_exponent(i32::min_value(), 0, 5), - i32::min_value() - ); + assert_eq!(scientific_exponent(i32::MIN, 0, 0), i32::MIN); + assert_eq!(scientific_exponent(i32::MIN, 0, 5), i32::MIN); // Overflow - assert_eq!( - scientific_exponent(i32::max_value(), 0, 0), - i32::max_value() - 1 - ); - assert_eq!( - scientific_exponent(i32::max_value(), 5, 0), - i32::max_value() - ); + assert_eq!(scientific_exponent(i32::MAX, 0, 0), i32::MAX - 1); + assert_eq!(scientific_exponent(i32::MAX, 5, 0), i32::MAX); } #[test] fn mantissa_exponent_test() { assert_eq!(mantissa_exponent(10, 5, 0), 5); assert_eq!(mantissa_exponent(0, 5, 0), -5); - assert_eq!( - mantissa_exponent(i32::max_value(), 5, 0), - i32::max_value() - 5 - ); - assert_eq!(mantissa_exponent(i32::max_value(), 0, 5), i32::max_value()); - assert_eq!(mantissa_exponent(i32::min_value(), 5, 0), i32::min_value()); - assert_eq!( - mantissa_exponent(i32::min_value(), 0, 5), - i32::min_value() + 5 - ); + assert_eq!(mantissa_exponent(i32::MAX, 5, 0), i32::MAX - 5); + assert_eq!(mantissa_exponent(i32::MAX, 0, 5), i32::MAX); + assert_eq!(mantissa_exponent(i32::MIN, 5, 0), i32::MIN); + assert_eq!(mantissa_exponent(i32::MIN, 0, 5), i32::MIN + 5); } diff --git a/third_party/rust/serde_json/tests/lexical/parse.rs b/third_party/rust/serde_json/tests/lexical/parse.rs index 80ca25e772..03ec1a9a63 100644 --- a/third_party/rust/serde_json/tests/lexical/parse.rs +++ b/third_party/rust/serde_json/tests/lexical/parse.rs @@ -1,7 +1,7 @@ // Adapted from https://github.com/Alexhuszagh/rust-lexical. use crate::lexical::num::Float; -use crate::lexical::parse::{parse_concise_float, parse_truncated_float}; +use crate::lexical::{parse_concise_float, parse_truncated_float}; use core::f64; use core::fmt::Debug; diff --git a/third_party/rust/serde_json/tests/map.rs b/third_party/rust/serde_json/tests/map.rs index ae01969561..538cd16ae0 100644 --- a/third_party/rust/serde_json/tests/map.rs +++ b/third_party/rust/serde_json/tests/map.rs @@ -35,7 +35,6 @@ fn test_append() { assert!(val.is_empty()); } -#[cfg(not(no_btreemap_retain))] #[test] fn test_retain() { let mut v: Value = from_str(r#"{"b":null,"a":null,"c":null}"#).unwrap(); diff --git a/third_party/rust/serde_json/tests/regression/issue1004.rs b/third_party/rust/serde_json/tests/regression/issue1004.rs new file mode 100644 index 0000000000..c09fb96108 --- /dev/null +++ b/third_party/rust/serde_json/tests/regression/issue1004.rs @@ -0,0 +1,12 @@ +#![cfg(feature = "arbitrary_precision")] + +#[test] +fn test() { + let float = 5.55f32; + let value = serde_json::to_value(float).unwrap(); + let json = serde_json::to_string(&value).unwrap(); + + // If the f32 were cast to f64 by Value before serialization, then this + // would incorrectly serialize as 5.550000190734863. + assert_eq!(json, "5.55"); +} diff --git a/third_party/rust/serde_json/tests/regression/issue520.rs b/third_party/rust/serde_json/tests/regression/issue520.rs index 9ed367731b..730ecc60a8 100644 --- a/third_party/rust/serde_json/tests/regression/issue520.rs +++ b/third_party/rust/serde_json/tests/regression/issue520.rs @@ -1,6 +1,6 @@ #![allow(clippy::float_cmp)] -use serde_derive::{Serialize, Deserialize}; +use serde_derive::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type", content = "data")] diff --git a/third_party/rust/serde_json/tests/regression/issue795.rs b/third_party/rust/serde_json/tests/regression/issue795.rs index bb82852c54..411e8af5d3 100644 --- a/third_party/rust/serde_json/tests/regression/issue795.rs +++ b/third_party/rust/serde_json/tests/regression/issue795.rs @@ -8,7 +8,10 @@ use std::fmt; #[derive(Debug)] pub enum Enum { - Variant { x: u8 }, + Variant { + #[allow(dead_code)] + x: u8, + }, } impl<'de> Deserialize<'de> for Enum { diff --git a/third_party/rust/serde_json/tests/regression/issue845.rs b/third_party/rust/serde_json/tests/regression/issue845.rs index 56037ae669..7b6564dadb 100644 --- a/third_party/rust/serde_json/tests/regression/issue845.rs +++ b/third_party/rust/serde_json/tests/regression/issue845.rs @@ -1,7 +1,6 @@ #![allow(clippy::trait_duplication_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/8757 use serde::{Deserialize, Deserializer}; -use std::convert::TryFrom; use std::fmt::{self, Display}; use std::marker::PhantomData; use std::str::FromStr; @@ -61,6 +60,7 @@ where #[derive(Deserialize, Debug)] pub struct Struct { #[serde(deserialize_with = "deserialize_integer_or_string")] + #[allow(dead_code)] pub i: i64, } diff --git a/third_party/rust/serde_json/tests/test.rs b/third_party/rust/serde_json/tests/test.rs index f62a545e7f..7e6adad76f 100644 --- a/third_party/rust/serde_json/tests/test.rs +++ b/third_party/rust/serde_json/tests/test.rs @@ -5,7 +5,9 @@ clippy::derive_partial_eq_without_eq, clippy::excessive_precision, clippy::float_cmp, + clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257 clippy::items_after_statements, + clippy::let_underscore_untyped, clippy::shadow_unrelated, clippy::too_many_lines, clippy::unreadable_literal, @@ -13,9 +15,6 @@ clippy::vec_init_then_push, clippy::zero_sized_map_values )] -#![cfg_attr(feature = "trace-macros", feature(trace_macros))] -#[cfg(feature = "trace-macros")] -trace_macros!(true); #[macro_use] mod macros; @@ -32,27 +31,25 @@ use serde_json::{ from_reader, from_slice, from_str, from_value, json, to_string, to_string_pretty, to_value, to_vec, Deserializer, Number, Value, }; -use std::collections::hash_map::DefaultHasher; use std::collections::BTreeMap; #[cfg(feature = "raw_value")] use std::collections::HashMap; use std::fmt::{self, Debug}; +use std::hash::BuildHasher; +#[cfg(feature = "raw_value")] use std::hash::{Hash, Hasher}; use std::io; use std::iter; use std::marker::PhantomData; use std::mem; use std::str::FromStr; -use std::string::ToString; use std::{f32, f64}; -use std::{i16, i32, i64, i8}; -use std::{u16, u32, u64, u8}; macro_rules! treemap { () => { BTreeMap::new() }; - ($($k:expr => $v:expr),+) => { + ($($k:expr => $v:expr),+ $(,)?) => { { let mut m = BTreeMap::new(); $( @@ -159,16 +156,28 @@ fn test_write_f64() { #[test] fn test_encode_nonfinite_float_yields_null() { - let v = to_value(::std::f64::NAN).unwrap(); + let v = to_value(f64::NAN.copysign(1.0)).unwrap(); + assert!(v.is_null()); + + let v = to_value(f64::NAN.copysign(-1.0)).unwrap(); assert!(v.is_null()); - let v = to_value(::std::f64::INFINITY).unwrap(); + let v = to_value(f64::INFINITY).unwrap(); assert!(v.is_null()); - let v = to_value(::std::f32::NAN).unwrap(); + let v = to_value(-f64::INFINITY).unwrap(); assert!(v.is_null()); - let v = to_value(::std::f32::INFINITY).unwrap(); + let v = to_value(f32::NAN.copysign(1.0)).unwrap(); + assert!(v.is_null()); + + let v = to_value(f32::NAN.copysign(-1.0)).unwrap(); + assert!(v.is_null()); + + let v = to_value(f32::INFINITY).unwrap(); + assert!(v.is_null()); + + let v = to_value(-f32::INFINITY).unwrap(); assert!(v.is_null()); } @@ -263,7 +272,7 @@ fn test_write_object() { ( treemap!( "a".to_string() => true, - "b".to_string() => false + "b".to_string() => false, ), "{\"a\":true,\"b\":false}", ), @@ -274,7 +283,7 @@ fn test_write_object() { treemap![ "a".to_string() => treemap![], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], "{\"a\":{},\"b\":{},\"c\":{}}", ), @@ -283,10 +292,10 @@ fn test_write_object() { "a".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], "{\"a\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"b\":{},\"c\":{}}", ), @@ -296,9 +305,9 @@ fn test_write_object() { "b".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], "{\"a\":{},\"b\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"c\":{}}", ), @@ -309,8 +318,8 @@ fn test_write_object() { "c".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![] - ] + "c".to_string() => treemap![], + ], ], "{\"a\":{},\"b\":{},\"c\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}}}", ), @@ -323,7 +332,7 @@ fn test_write_object() { treemap![ "a".to_string() => treemap![], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], pretty_str!({ "a": {}, @@ -336,10 +345,10 @@ fn test_write_object() { "a".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], pretty_str!({ "a": { @@ -363,9 +372,9 @@ fn test_write_object() { "b".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], - "c".to_string() => treemap![] + "c".to_string() => treemap![], ], pretty_str!({ "a": {}, @@ -390,8 +399,8 @@ fn test_write_object() { "c".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![] - ] + "c".to_string() => treemap![], + ], ], pretty_str!({ "a": {}, @@ -422,7 +431,7 @@ fn test_write_object() { ( treemap!( "a".to_string() => true, - "b".to_string() => false + "b".to_string() => false, ), pretty_str!( { "a": true, @@ -1191,8 +1200,8 @@ fn test_parse_object() { treemap!( "a".to_string() => treemap!( "b".to_string() => 3u64, - "c".to_string() => 4 - ) + "c".to_string() => 4, + ), ), )]); @@ -1368,7 +1377,7 @@ fn test_parse_enum() { ), treemap!( "a".to_string() => Animal::Dog, - "b".to_string() => Animal::Frog("Henry".to_string(), vec![]) + "b".to_string() => Animal::Frog("Henry".to_string(), vec![]), ), )]); } @@ -1451,7 +1460,6 @@ fn test_serialize_seq_with_no_len() { where T: ser::Serialize, { - #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, @@ -1478,7 +1486,6 @@ fn test_serialize_seq_with_no_len() { formatter.write_str("array") } - #[inline] fn visit_unit(self) -> Result, E> where E: de::Error, @@ -1486,7 +1493,6 @@ fn test_serialize_seq_with_no_len() { Ok(MyVec(Vec::new())) } - #[inline] fn visit_seq(self, mut visitor: V) -> Result, V::Error> where V: de::SeqAccess<'de>, @@ -1537,7 +1543,6 @@ fn test_serialize_map_with_no_len() { K: ser::Serialize + Ord, V: ser::Serialize, { - #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, @@ -1565,7 +1570,6 @@ fn test_serialize_map_with_no_len() { formatter.write_str("map") } - #[inline] fn visit_unit(self) -> Result, E> where E: de::Error, @@ -1573,7 +1577,6 @@ fn test_serialize_map_with_no_len() { Ok(MyMap(BTreeMap::new())) } - #[inline] fn visit_map(self, mut visitor: Visitor) -> Result, Visitor::Error> where Visitor: de::MapAccess<'de>, @@ -1659,23 +1662,12 @@ fn test_deserialize_from_stream() { assert_eq!(request, response); } -#[test] -fn test_serialize_rejects_bool_keys() { - let map = treemap!( - true => 2, - false => 4 - ); - - let err = to_vec(&map).unwrap_err(); - assert_eq!(err.to_string(), "key must be a string"); -} - #[test] fn test_serialize_rejects_adt_keys() { let map = treemap!( Some("a") => 2, Some("b") => 4, - None => 6 + None => 6, ); let err = to_vec(&map).unwrap_err(); @@ -1889,23 +1881,41 @@ fn test_integer_key() { // map with integer keys let map = treemap!( 1 => 2, - -1 => 6 + -1 => 6, ); let j = r#"{"-1":6,"1":2}"#; test_encode_ok(&[(&map, j)]); test_parse_ok(vec![(j, map)]); - let j = r#"{"x":null}"#; - test_parse_err::>(&[( - j, - "invalid type: string \"x\", expected i32 at line 1 column 4", - )]); + test_parse_err::>(&[ + ( + r#"{"x":null}"#, + "invalid value: expected key to be a number in quotes at line 1 column 2", + ), + ( + r#"{" 123":null}"#, + "invalid value: expected key to be a number in quotes at line 1 column 2", + ), + (r#"{"123 ":null}"#, "expected `\"` at line 1 column 6"), + ]); + + let err = from_value::>(json!({" 123":null})).unwrap_err(); + assert_eq!( + err.to_string(), + "invalid value: expected key to be a number in quotes", + ); + + let err = from_value::>(json!({"123 ":null})).unwrap_err(); + assert_eq!( + err.to_string(), + "invalid value: expected key to be a number in quotes", + ); } #[test] fn test_integer128_key() { let map = treemap! { - 100000000000000000000000000000000000000u128 => () + 100000000000000000000000000000000000000u128 => (), }; let j = r#"{"100000000000000000000000000000000000000":null}"#; assert_eq!(to_string(&map).unwrap(), j); @@ -1913,23 +1923,106 @@ fn test_integer128_key() { } #[test] -fn test_deny_float_key() { - #[derive(Eq, PartialEq, Ord, PartialOrd)] +fn test_float_key() { + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] struct Float; impl Serialize for Float { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - serializer.serialize_f32(1.0) + serializer.serialize_f32(1.23) + } + } + impl<'de> Deserialize<'de> for Float { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + f32::deserialize(deserializer).map(|_| Float) } } // map with float key - let map = treemap!(Float => "x"); + let map = treemap!(Float => "x".to_owned()); + let j = r#"{"1.23":"x"}"#; + + test_encode_ok(&[(&map, j)]); + test_parse_ok(vec![(j, map)]); + + let j = r#"{"x": null}"#; + test_parse_err::>(&[( + j, + "invalid value: expected key to be a number in quotes at line 1 column 2", + )]); +} + +#[test] +fn test_deny_non_finite_f32_key() { + // We store float bits so that we can derive Ord, and other traits. In a + // real context the code might involve a crate like ordered-float. + + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] + struct F32Bits(u32); + impl Serialize for F32Bits { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_f32(f32::from_bits(self.0)) + } + } + + let map = treemap!(F32Bits(f32::INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F32Bits(f32::NEG_INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F32Bits(f32::NAN.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); assert!(serde_json::to_value(map).is_err()); } +#[test] +fn test_deny_non_finite_f64_key() { + // We store float bits so that we can derive Ord, and other traits. In a + // real context the code might involve a crate like ordered-float. + + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] + struct F64Bits(u64); + impl Serialize for F64Bits { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_f64(f64::from_bits(self.0)) + } + } + + let map = treemap!(F64Bits(f64::INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F64Bits(f64::NEG_INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F64Bits(f64::NAN.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); +} + +#[test] +fn test_boolean_key() { + let map = treemap!(false => 0, true => 1); + let j = r#"{"false":0,"true":1}"#; + test_encode_ok(&[(&map, j)]); + test_parse_ok(vec![(j, map)]); +} + #[test] fn test_borrowed_key() { let map: BTreeMap<&str, ()> = from_str("{\"borrowed\":null}").unwrap(); @@ -1953,7 +2046,7 @@ fn test_effectively_string_keys() { } let map = treemap! { Enum::One => 1, - Enum::Two => 2 + Enum::Two => 2, }; let expected = r#"{"One":1,"Two":2}"#; test_encode_ok(&[(&map, expected)]); @@ -1963,7 +2056,7 @@ fn test_effectively_string_keys() { struct Wrapper(String); let map = treemap! { Wrapper("zero".to_owned()) => 0, - Wrapper("one".to_owned()) => 1 + Wrapper("one".to_owned()) => 1, }; let expected = r#"{"one":1,"zero":0}"#; test_encode_ok(&[(&map, expected)]); @@ -2145,8 +2238,8 @@ fn null_invalid_type() { #[test] fn test_integer128() { - let signed = &[i128::min_value(), -1, 0, 1, i128::max_value()]; - let unsigned = &[0, 1, u128::max_value()]; + let signed = &[i128::MIN, -1, 0, 1, i128::MAX]; + let unsigned = &[0, 1, u128::MAX]; for integer128 in signed { let expected = integer128.to_string(); @@ -2182,8 +2275,8 @@ fn test_integer128() { #[test] fn test_integer128_to_value() { - let signed = &[i128::from(i64::min_value()), i128::from(u64::max_value())]; - let unsigned = &[0, u128::from(u64::max_value())]; + let signed = &[i128::from(i64::MIN), i128::from(u64::MAX)]; + let unsigned = &[0, u128::from(u64::MAX)]; for integer128 in signed { let expected = integer128.to_string(); @@ -2196,7 +2289,7 @@ fn test_integer128_to_value() { } if !cfg!(feature = "arbitrary_precision") { - let err = to_value(u128::from(u64::max_value()) + 1).unwrap_err(); + let err = to_value(u128::from(u64::MAX) + 1).unwrap_err(); assert_eq!(err.to_string(), "number out of range"); } } @@ -2240,6 +2333,8 @@ fn test_raw_value_in_map_key() { #[repr(transparent)] struct RawMapKey(RawValue); + #[allow(unknown_lints)] + #[allow(non_local_definitions)] // false positive: https://github.com/rust-lang/rust/issues/121621 impl<'de> Deserialize<'de> for &'de RawMapKey { fn deserialize(deserializer: D) -> Result where @@ -2384,25 +2479,27 @@ fn test_value_into_deserializer() { let mut map = BTreeMap::new(); map.insert("inner", json!({ "string": "Hello World" })); + let outer = Outer::deserialize(serde::de::value::MapDeserializer::new( + map.iter().map(|(k, v)| (*k, v)), + )) + .unwrap(); + assert_eq!(outer.inner.string, "Hello World"); + let outer = Outer::deserialize(map.into_deserializer()).unwrap(); assert_eq!(outer.inner.string, "Hello World"); } #[test] fn hash_positive_and_negative_zero() { - fn hash(obj: impl Hash) -> u64 { - let mut hasher = DefaultHasher::new(); - obj.hash(&mut hasher); - hasher.finish() - } + let rand = std::hash::RandomState::new(); let k1 = serde_json::from_str::("0.0").unwrap(); let k2 = serde_json::from_str::("-0.0").unwrap(); if cfg!(feature = "arbitrary_precision") { assert_ne!(k1, k2); - assert_ne!(hash(k1), hash(k2)); + assert_ne!(rand.hash_one(k1), rand.hash_one(k2)); } else { assert_eq!(k1, k2); - assert_eq!(hash(k1), hash(k2)); + assert_eq!(rand.hash_one(k1), rand.hash_one(k2)); } } diff --git a/third_party/rust/serde_json/tests/ui/parse_key.stderr b/third_party/rust/serde_json/tests/ui/parse_key.stderr index f10c21800e..15662dc507 100644 --- a/third_party/rust/serde_json/tests/ui/parse_key.stderr +++ b/third_party/rust/serde_json/tests/ui/parse_key.stderr @@ -2,4 +2,4 @@ error[E0609]: no field `s` on type `&'static str` --> tests/ui/parse_key.rs:4:16 | 4 | json!({ "".s : true }); - | ^ + | ^ unknown field diff --git a/third_party/rust/sfv/.cargo-checksum.json b/third_party/rust/sfv/.cargo-checksum.json index b34463089b..38fd1a552e 100644 --- a/third_party/rust/sfv/.cargo-checksum.json +++ b/third_party/rust/sfv/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"cf545d5d3384e757f96bffb58f35f1df6236a340e9aac13ae3398a8b9127fe30","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5318787a14e32720b1652f08a24408aaea67fdb5154ceda0f46a6069a0c5e5e3","README.md":"50a8b83ce705a34030957a3502c768674541220a5c2952a965f70c31faaed559","benches/bench.rs":"bbc60db4b542abb3738eba80f5c7c54ac39301ed5e48e2ae2a94cecfdb42e33f","src/lib.rs":"d6c579a4b35078c2f86d6515c957040eb54d9b7ecd65e74f90186d977986b358","src/parser.rs":"1c54f855a5bdd270b9b83b8cb95de670fdf14bce2154f683fba920b447adc94f","src/ref_serializer.rs":"8806ee50e2b2ae466a49788d7e972a47329c0e2c842d669673a152286e81c5d9","src/serializer.rs":"937541e0bdda7f3b043c55eb44ef2c431bdbf636498ce99af4ca47d773790178","src/test_parser.rs":"7a2728e7cbdcb1f3bb42e009045ec0dcfca241316a2aee4905925d4b1ce0bb3a","src/test_serializer.rs":"2419279c9a9a4f48952836d63f3822281c18691d86c146749a573c52a41d6ff0","src/utils.rs":"94c8f79f4747973819b9da2c1a9f6246bf3b5ea7450b376a98eb055f6acf8e73"},"package":"b4f1641177943b4e6faf7622463ae6dfe0f143eb88799e91e2e2e68ede568af5"} \ No newline at end of file +{"files":{"Cargo.toml":"8ef5c3d39d05e807adfcb2b26639f0735b9c1c99c8373d09d32173786d1ec3ac","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5318787a14e32720b1652f08a24408aaea67fdb5154ceda0f46a6069a0c5e5e3","README.md":"50a8b83ce705a34030957a3502c768674541220a5c2952a965f70c31faaed559","benches/bench.rs":"bbc60db4b542abb3738eba80f5c7c54ac39301ed5e48e2ae2a94cecfdb42e33f","src/lib.rs":"d6c579a4b35078c2f86d6515c957040eb54d9b7ecd65e74f90186d977986b358","src/parser.rs":"1c54f855a5bdd270b9b83b8cb95de670fdf14bce2154f683fba920b447adc94f","src/ref_serializer.rs":"8806ee50e2b2ae466a49788d7e972a47329c0e2c842d669673a152286e81c5d9","src/serializer.rs":"937541e0bdda7f3b043c55eb44ef2c431bdbf636498ce99af4ca47d773790178","src/test_parser.rs":"7a2728e7cbdcb1f3bb42e009045ec0dcfca241316a2aee4905925d4b1ce0bb3a","src/test_serializer.rs":"2419279c9a9a4f48952836d63f3822281c18691d86c146749a573c52a41d6ff0","src/utils.rs":"94c8f79f4747973819b9da2c1a9f6246bf3b5ea7450b376a98eb055f6acf8e73"},"package":"f27daf6ed3fc7ffd5ea3ce9f684fe351c47e50f2fdbb6236e2bad0b440dbe408"} \ No newline at end of file diff --git a/third_party/rust/sfv/Cargo.toml b/third_party/rust/sfv/Cargo.toml index 1827d69d5d..8134440708 100644 --- a/third_party/rust/sfv/Cargo.toml +++ b/third_party/rust/sfv/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "sfv" -version = "0.9.3" +version = "0.9.4" authors = ["Tania Batieva "] exclude = [ "tests/**", @@ -38,7 +38,7 @@ harness = false version = "2.3.2" [dependencies.indexmap] -version = "1.8.0" +version = "2" [dependencies.rust_decimal] version = "1.20.0" diff --git a/third_party/rust/sql-support/.cargo-checksum.json b/third_party/rust/sql-support/.cargo-checksum.json index 93cef6e94d..ecf062beaf 100644 --- a/third_party/rust/sql-support/.cargo-checksum.json +++ b/third_party/rust/sql-support/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"812811e5a8e00abe3ec345cd8fd435e27fec7cb8f2e45a0e93e5becf564c46ad","src/conn_ext.rs":"e48e862e47c000c545dcc766fc1889498a8709bee00e240ed68d247b0fbef577","src/debug_tools.rs":"bece2bc3d35379b81ea2f942a0a3e909e0ab0553656505904745548eacaf402a","src/each_chunk.rs":"8aaba842e43b002fbc0fee95d14ce08faa7187b1979c765b2e270cd4802607a5","src/lib.rs":"af704ec04beb6c2c388d4566710e1167b18fb64acb248ccf37a67679daffddb6","src/maybe_cached.rs":"0b18425595055883a98807fbd62ff27a79c18af34e7cb3439f8c3438463ef2dd","src/open_database.rs":"ba290bfb39468e96f9b3ea865e0c13c2cc5a731ea8877a9feb6b1de4f7d666c4","src/repeat.rs":"b4c5ff5d083afba7f9f153f54aba2e6859b78b85c82d48dbd6bd58f67da9e6b9"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"2a0d414052d959098dcb3c22fce0eb008710ab594a6d0e5c58056b2dd497a359","src/conn_ext.rs":"e48e862e47c000c545dcc766fc1889498a8709bee00e240ed68d247b0fbef577","src/debug_tools.rs":"bece2bc3d35379b81ea2f942a0a3e909e0ab0553656505904745548eacaf402a","src/each_chunk.rs":"8aaba842e43b002fbc0fee95d14ce08faa7187b1979c765b2e270cd4802607a5","src/lazy.rs":"a96b4f4ec572538b49cdfa8fee981dcf5143a5f51163fb8a573d3ac128df70f9","src/lib.rs":"b2c120db4928c3e4abdd96405fd4c1016255699bdbc38c8cd60dbd3431fc0a12","src/maybe_cached.rs":"0b18425595055883a98807fbd62ff27a79c18af34e7cb3439f8c3438463ef2dd","src/open_database.rs":"dfc6f68354bf35ee1fc235986e5563e9f8c5cf7920dfe77a9a3d3ad4cfd3723f","src/repeat.rs":"b4c5ff5d083afba7f9f153f54aba2e6859b78b85c82d48dbd6bd58f67da9e6b9"},"package":null} \ No newline at end of file diff --git a/third_party/rust/sql-support/Cargo.toml b/third_party/rust/sql-support/Cargo.toml index 0e6137ddbf..c09933b165 100644 --- a/third_party/rust/sql-support/Cargo.toml +++ b/third_party/rust/sql-support/Cargo.toml @@ -20,6 +20,7 @@ license = "MPL-2.0" ffi-support = "0.4" lazy_static = "1.4" log = "0.4" +parking_lot = ">=0.11,<=0.12" tempfile = "3.1.0" thiserror = "1.0" diff --git a/third_party/rust/sql-support/src/lazy.rs b/third_party/rust/sql-support/src/lazy.rs new file mode 100644 index 0000000000..b22d9c39e3 --- /dev/null +++ b/third_party/rust/sql-support/src/lazy.rs @@ -0,0 +1,151 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::open_database::{open_database_with_flags, ConnectionInitializer, Error}; +use interrupt_support::{register_interrupt, SqlInterruptHandle, SqlInterruptScope}; +use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; +use rusqlite::{Connection, OpenFlags}; +use std::{ + path::{Path, PathBuf}, + sync::{Arc, Weak}, +}; + +/// Lazily-loaded database with interruption support +/// +/// In addition to the [Self::interrupt] method, LazyDb also calls +/// [interrupt_support::register_interrupt] on any opened database. This means that if +/// [interrupt_support::shutdown] is called it will interrupt this database if it's open and +/// in-use. +pub struct LazyDb { + path: PathBuf, + open_flags: OpenFlags, + connection_initializer: CI, + // Note: if you're going to lock both mutexes at once, make sure to lock the connection mutex + // first. Otherwise, you risk creating a deadlock where two threads each hold one of the locks + // and is waiting for the other. + connection: Mutex>, + // It's important to use a separate mutex for the interrupt handle, since the whole point is to + // interrupt while another thread holds the connection mutex. Since the only mutation is + // setting/unsetting the Arc, maybe this could be sped up by using something like + // `arc_swap::ArcSwap`, but that seems like overkill for our purposes. This mutex should rarely + // be contested and interrupt operations execute quickly. + interrupt_handle: Mutex>>, +} + +impl LazyDb { + /// Create a new LazyDb + /// + /// This does not open the connection and is non-blocking + pub fn new(path: &Path, open_flags: OpenFlags, connection_initializer: CI) -> Self { + Self { + path: path.to_owned(), + open_flags, + connection_initializer, + connection: Mutex::new(None), + interrupt_handle: Mutex::new(None), + } + } + + /// Lock the database mutex and get a connection and interrupt scope. + /// + /// If the connection is closed, it will be opened. + /// + /// Calling `lock` again, or calling `close`, from the same thread while the mutex guard is + /// still alive will cause a deadlock. + pub fn lock(&self) -> Result<(MappedMutexGuard<'_, Connection>, SqlInterruptScope), Error> { + // Call get_conn first, then get_scope to ensure we acquire the locks in the correct order + let conn = self.get_conn()?; + let scope = self.get_scope(&conn)?; + Ok((conn, scope)) + } + + fn get_conn(&self) -> Result, Error> { + let mut guard = self.connection.lock(); + // Open the database if it wasn't opened before. Do this outside of the MutexGuard::map call to simplify the error handling + if guard.is_none() { + *guard = Some(open_database_with_flags( + &self.path, + self.open_flags, + &self.connection_initializer, + )?); + }; + // Use MutexGuard::map to get a Connection rather than Option. The unwrap() + // call can't fail because of the previous code. + Ok(MutexGuard::map(guard, |conn_option| { + conn_option.as_mut().unwrap() + })) + } + + fn get_scope(&self, conn: &Connection) -> Result { + let mut handle_guard = self.interrupt_handle.lock(); + let result = match handle_guard.as_ref() { + Some(handle) => handle.begin_interrupt_scope(), + None => { + let handle = Arc::new(SqlInterruptHandle::new(conn)); + register_interrupt( + Arc::downgrade(&handle) as Weak + Send + Sync> + ); + handle_guard.insert(handle).begin_interrupt_scope() + } + }; + // If we see an Interrupted error when beginning the scope, it means that we're in shutdown + // mode. + result.map_err(|_| Error::Shutdown) + } + + /// Close the database if it's open + /// + /// Pass interrupt=true to interrupt any in-progress queries before closing the database. + /// + /// Do not call `close` if you already have a lock on the database in the current thread, as + /// this will cause a deadlock. + pub fn close(&self, interrupt: bool) { + let mut interrupt_handle = self.interrupt_handle.lock(); + if let Some(handle) = interrupt_handle.as_ref() { + if interrupt { + handle.interrupt(); + } + *interrupt_handle = None; + } + // Drop the interrupt handle lock to avoid holding both locks at once. + drop(interrupt_handle); + *self.connection.lock() = None; + } + + /// Interrupt any in-progress queries + pub fn interrupt(&self) { + if let Some(handle) = self.interrupt_handle.lock().as_ref() { + handle.interrupt(); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::open_database::test_utils::TestConnectionInitializer; + + fn open_test_db() -> LazyDb { + LazyDb::new( + Path::new(":memory:"), + OpenFlags::default(), + TestConnectionInitializer::new(), + ) + } + + #[test] + fn test_interrupt() { + let lazy_db = open_test_db(); + let (_, scope) = lazy_db.lock().unwrap(); + assert!(!scope.was_interrupted()); + lazy_db.interrupt(); + assert!(scope.was_interrupted()); + } + + #[test] + fn interrupt_before_db_is_opened_should_not_fail() { + let lazy_db = open_test_db(); + lazy_db.interrupt(); + } +} diff --git a/third_party/rust/sql-support/src/lib.rs b/third_party/rust/sql-support/src/lib.rs index 2ece560b4d..5e8dfcea29 100644 --- a/third_party/rust/sql-support/src/lib.rs +++ b/third_party/rust/sql-support/src/lib.rs @@ -10,14 +10,16 @@ mod conn_ext; pub mod debug_tools; mod each_chunk; +mod lazy; mod maybe_cached; pub mod open_database; mod repeat; -pub use crate::conn_ext::*; -pub use crate::each_chunk::*; -pub use crate::maybe_cached::*; -pub use crate::repeat::*; +pub use conn_ext::*; +pub use each_chunk::*; +pub use lazy::*; +pub use maybe_cached::*; +pub use repeat::*; /// In PRAGMA foo='bar', `'bar'` must be a constant string (it cannot be a /// bound parameter), so we need to escape manually. According to diff --git a/third_party/rust/sql-support/src/open_database.rs b/third_party/rust/sql-support/src/open_database.rs index d92a94a9ed..9096b796a3 100644 --- a/third_party/rust/sql-support/src/open_database.rs +++ b/third_party/rust/sql-support/src/open_database.rs @@ -46,6 +46,8 @@ pub enum Error { SqlError(rusqlite::Error), #[error("Failed to recover a corrupt database due to an error deleting the file: {0}")] RecoveryError(std::io::Error), + #[error("In shutdown mode")] + Shutdown, } impl From for Error { @@ -241,99 +243,28 @@ fn set_schema_version(conn: &Connection, version: u32) -> Result<()> { // our other crates. pub mod test_utils { use super::*; - use std::path::PathBuf; + use std::{cell::RefCell, collections::HashSet, path::PathBuf}; use tempfile::TempDir; - // Database file that we can programatically run upgrades on - // - // We purposefully don't keep a connection to the database around to force upgrades to always - // run against a newly opened DB, like they would in the real world. See #4106 for - // details. - pub struct MigratedDatabaseFile { - // Keep around a TempDir to ensure the database file stays around until this struct is - // dropped - _tempdir: TempDir, - pub connection_initializer: CI, - pub path: PathBuf, + pub struct TestConnectionInitializer { + pub calls: RefCell>, + pub buggy_v3_upgrade: bool, } - impl MigratedDatabaseFile { - pub fn new(connection_initializer: CI, init_sql: &str) -> Self { - Self::new_with_flags(connection_initializer, init_sql, OpenFlags::default()) - } - - pub fn new_with_flags( - connection_initializer: CI, - init_sql: &str, - open_flags: OpenFlags, - ) -> Self { - let tempdir = tempfile::tempdir().unwrap(); - let path = tempdir.path().join(Path::new("db.sql")); - let conn = Connection::open_with_flags(&path, open_flags).unwrap(); - conn.execute_batch(init_sql).unwrap(); - Self { - _tempdir: tempdir, - connection_initializer, - path, - } - } - - /// Attempt to run all upgrades up to a specific version. - /// - /// This will result in a panic if an upgrade fails to run. - pub fn upgrade_to(&self, version: u32) { - let mut conn = self.open(); - let tx = conn.transaction().unwrap(); - let mut current_version = get_schema_version(&tx).unwrap(); - while current_version < version { - self.connection_initializer - .upgrade_from(&tx, current_version) - .unwrap(); - current_version += 1; - } - set_schema_version(&tx, current_version).unwrap(); - self.connection_initializer.finish(&tx).unwrap(); - tx.commit().unwrap(); - } - - /// Attempt to run all upgrades - /// - /// This will result in a panic if an upgrade fails to run. - pub fn run_all_upgrades(&self) { - let current_version = get_schema_version(&self.open()).unwrap(); - for version in current_version..CI::END_VERSION { - self.upgrade_to(version + 1); - } - } - - pub fn open(&self) -> Connection { - Connection::open(&self.path).unwrap() + impl Default for TestConnectionInitializer { + fn default() -> Self { + Self::new() } } -} - -#[cfg(test)] -mod test { - use super::test_utils::MigratedDatabaseFile; - use super::*; - use std::cell::RefCell; - use std::io::Write; - - struct TestConnectionInitializer { - pub calls: RefCell>, - pub buggy_v3_upgrade: bool, - } impl TestConnectionInitializer { pub fn new() -> Self { - let _ = env_logger::try_init(); Self { calls: RefCell::new(Vec::new()), buggy_v3_upgrade: false, } } pub fn new_with_buggy_logic() -> Self { - let _ = env_logger::try_init(); Self { calls: RefCell::new(Vec::new()), buggy_v3_upgrade: true, @@ -427,6 +358,123 @@ mod test { } } + // Database file that we can programatically run upgrades on + // + // We purposefully don't keep a connection to the database around to force upgrades to always + // run against a newly opened DB, like they would in the real world. See #4106 for + // details. + pub struct MigratedDatabaseFile { + // Keep around a TempDir to ensure the database file stays around until this struct is + // dropped + _tempdir: TempDir, + pub connection_initializer: CI, + pub path: PathBuf, + } + + impl MigratedDatabaseFile { + pub fn new(connection_initializer: CI, init_sql: &str) -> Self { + Self::new_with_flags(connection_initializer, init_sql, OpenFlags::default()) + } + + pub fn new_with_flags( + connection_initializer: CI, + init_sql: &str, + open_flags: OpenFlags, + ) -> Self { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join(Path::new("db.sql")); + let conn = Connection::open_with_flags(&path, open_flags).unwrap(); + conn.execute_batch(init_sql).unwrap(); + Self { + _tempdir: tempdir, + connection_initializer, + path, + } + } + + /// Attempt to run all upgrades up to a specific version. + /// + /// This will result in a panic if an upgrade fails to run. + pub fn upgrade_to(&self, version: u32) { + let mut conn = self.open(); + let tx = conn.transaction().unwrap(); + let mut current_version = get_schema_version(&tx).unwrap(); + while current_version < version { + self.connection_initializer + .upgrade_from(&tx, current_version) + .unwrap(); + current_version += 1; + } + set_schema_version(&tx, current_version).unwrap(); + self.connection_initializer.finish(&tx).unwrap(); + tx.commit().unwrap(); + } + + /// Attempt to run all upgrades + /// + /// This will result in a panic if an upgrade fails to run. + pub fn run_all_upgrades(&self) { + let current_version = get_schema_version(&self.open()).unwrap(); + for version in current_version..CI::END_VERSION { + self.upgrade_to(version + 1); + } + } + + pub fn assert_schema_matches_new_database(&self) { + let db = self.open(); + let new_db = open_memory_database(&self.connection_initializer).unwrap(); + let table_names = get_table_names(&db); + let new_db_table_names = get_table_names(&new_db); + let extra_tables = Vec::from_iter(table_names.difference(&new_db_table_names)); + if !extra_tables.is_empty() { + panic!("Extra tables not present in new database: {extra_tables:?}"); + } + let new_db_extra_tables = Vec::from_iter(new_db_table_names.difference(&table_names)); + if !new_db_extra_tables.is_empty() { + panic!("Extra tables only present in new database: {new_db_extra_tables:?}"); + } + + for table_name in table_names { + assert_eq!( + get_table_sql(&db, &table_name), + get_table_sql(&new_db, &table_name), + "sql differs for table: {table_name}", + ); + } + } + + pub fn open(&self) -> Connection { + Connection::open(&self.path).unwrap() + } + } + + fn get_table_names(conn: &Connection) -> HashSet { + conn.query_rows_and_then( + "SELECT name FROM sqlite_master WHERE type='table'", + (), + |row| row.get(0), + ) + .unwrap() + .into_iter() + .collect() + } + + fn get_table_sql(conn: &Connection, table_name: &str) -> String { + conn.query_row_and_then( + "SELECT sql FROM sqlite_master WHERE name = ? AND type='table'", + (&table_name,), + |row| row.get::<_, String>(0), + ) + .unwrap() + } +} + +#[cfg(test)] +mod test { + use super::test_utils::{MigratedDatabaseFile, TestConnectionInitializer}; + use super::*; + use std::io::Write; + // A special schema used to test the upgrade that forces the database to be // replaced. static INIT_V1: &str = " diff --git a/third_party/rust/suggest/.cargo-checksum.json b/third_party/rust/suggest/.cargo-checksum.json index 120a503f29..8ead78a91c 100644 --- a/third_party/rust/suggest/.cargo-checksum.json +++ b/third_party/rust/suggest/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"05e4d7f7b3649a3e3fa441c4af53a633d18f20bb04fd761ed33fc9d461fd0dee","README.md":"fb72d0028586cab1421b853ef529d7ce78ad7316818b7733a4f3488b0fba67f7","benches/benchmark_all.rs":"c2343c9197b6d9ccb0798d7701b1b0d2569d494dd31a975d21d7ec6f26e32879","build.rs":"78780c5cccfe22c3ff4198624b9e188559c437c3e6fa1c8bb66548eee6aa66bf","src/benchmarks/README.md":"ee6d50df2c31cfd80a5bc047011b518dcf57f1ef928a811bb770f1a09f41b3de","src/benchmarks/client.rs":"5d5db3f6e132654c06532feba15f98576122f6b9572ab5fa27b0c67d5b39ecb6","src/benchmarks/ingest.rs":"1ffdc403fb945ea0b58353df9773ba45ab0e9082d61dd5330ad49fad8cbb5d9f","src/benchmarks/mod.rs":"fe1898ba4d783213525da10d92858ee84cebfd22749bad7aeb461d338fe5504a","src/bin/debug_ingestion_sizes.rs":"ce6e810be7b3fc19e826d75b622b82cfab5a1a99397a6d0833c2c4eebff2d364","src/config.rs":"206ae9dc768c755649cb0c88a7b1fc3c926c715441784f61e9dc06a8a02fc568","src/db.rs":"734f5fd9f36f03c07a508a9a353872b81107f5fe09f27294ba27d7e1249e3988","src/error.rs":"f563210a6c050d98ec85e0f6d9401e7373bfb816e865e8edabbabb23d848ba13","src/keyword.rs":"988d0ab021c0df19cfd3c519df7d37f606bf984cd14d0efca4e5a7aff88344dd","src/lib.rs":"91ebbe0e1ffb99eefde204f81bc6bb199b4941976347baf1f132fd0ede20479c","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"fe76f19a223f5cac056c7d48525087ca2c26bf0629b0e11b1f8dc98d165c8bb2","src/rs.rs":"e3eabde58c859ebe1154bf8da56ca134ace135934e3f280acc8186b4204399b3","src/schema.rs":"8b21006940e872658d722b52ba171280c96789eecf614b837d8cdbc9153ab576","src/store.rs":"413779074db3ce4589c31cd4fb0a050d44d1cbad1df3c94101d03e98efdf09cb","src/suggest.udl":"de50ea5c7ece0ae0ff4798979e0e12a5227b42bf024d48b6f585ea30a5133eb3","src/suggestion.rs":"f31227779d13d1b03a622e08a417ceba4afb161885a01c2bc87a6a652b5e8be5","src/yelp.rs":"9c0dc02a994cc05df524aa4ef337d10f575d1891259193b6419fed6fe279cb54","uniffi.toml":"f26317442ddb5b3281245bef6e60ffcb78bb95d29fe4a351a56dbb88d4ec8aab"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"05e4d7f7b3649a3e3fa441c4af53a633d18f20bb04fd761ed33fc9d461fd0dee","README.md":"fb72d0028586cab1421b853ef529d7ce78ad7316818b7733a4f3488b0fba67f7","benches/benchmark_all.rs":"c2343c9197b6d9ccb0798d7701b1b0d2569d494dd31a975d21d7ec6f26e32879","build.rs":"78780c5cccfe22c3ff4198624b9e188559c437c3e6fa1c8bb66548eee6aa66bf","src/benchmarks/README.md":"ee6d50df2c31cfd80a5bc047011b518dcf57f1ef928a811bb770f1a09f41b3de","src/benchmarks/client.rs":"4b2125031d740ca1ab468e76bbea777ac0bc4cc221b03b7bc2da773bed61dac5","src/benchmarks/ingest.rs":"1ffdc403fb945ea0b58353df9773ba45ab0e9082d61dd5330ad49fad8cbb5d9f","src/benchmarks/mod.rs":"fe1898ba4d783213525da10d92858ee84cebfd22749bad7aeb461d338fe5504a","src/bin/debug_ingestion_sizes.rs":"ce6e810be7b3fc19e826d75b622b82cfab5a1a99397a6d0833c2c4eebff2d364","src/config.rs":"206ae9dc768c755649cb0c88a7b1fc3c926c715441784f61e9dc06a8a02fc568","src/db.rs":"a4e18b9f45e0473ea64b5ecdf6d1d67e0519f9629d495c157b0bd1b47c3e2f4f","src/error.rs":"f563210a6c050d98ec85e0f6d9401e7373bfb816e865e8edabbabb23d848ba13","src/keyword.rs":"988d0ab021c0df19cfd3c519df7d37f606bf984cd14d0efca4e5a7aff88344dd","src/lib.rs":"18f988eb49626c6e186c8bc65a51b4a40d796f36d3de8905506f76c6e5e876cd","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"fe76f19a223f5cac056c7d48525087ca2c26bf0629b0e11b1f8dc98d165c8bb2","src/rs.rs":"e3eabde58c859ebe1154bf8da56ca134ace135934e3f280acc8186b4204399b3","src/schema.rs":"88ff3ae6b652fa5a5cff4dc504d11a7fc33f1b2ee9716b970f646d9f9ca90ab7","src/store.rs":"aad193774eecec739a7debd1c9e4fd46df384e7a524203e5e5f0354b93f73c1c","src/suggest.udl":"bfa653aa88c954860a9728a597daad8f4a7db8c81bc156725bf801f7cddf8459","src/suggestion.rs":"f31227779d13d1b03a622e08a417ceba4afb161885a01c2bc87a6a652b5e8be5","src/yelp.rs":"9c0dc02a994cc05df524aa4ef337d10f575d1891259193b6419fed6fe279cb54","uniffi.toml":"f26317442ddb5b3281245bef6e60ffcb78bb95d29fe4a351a56dbb88d4ec8aab"},"package":null} \ No newline at end of file diff --git a/third_party/rust/suggest/src/benchmarks/client.rs b/third_party/rust/suggest/src/benchmarks/client.rs index f5a21fd9cc..713bd7752b 100644 --- a/third_party/rust/suggest/src/benchmarks/client.rs +++ b/third_party/rust/suggest/src/benchmarks/client.rs @@ -22,6 +22,7 @@ impl RemoteSettingsWarmUpClient { pub fn new() -> Self { Self { client: Client::new(RemoteSettingsConfig { + server: None, server_url: None, bucket_name: None, collection_name: crate::rs::REMOTE_SETTINGS_COLLECTION.into(), diff --git a/third_party/rust/suggest/src/db.rs b/third_party/rust/suggest/src/db.rs index 0412c50d8f..6b6603ab71 100644 --- a/third_party/rust/suggest/src/db.rs +++ b/third_party/rust/suggest/src/db.rs @@ -188,6 +188,12 @@ impl<'a> SuggestDao<'a> { // // These methods implement CRUD operations + pub fn suggestions_table_empty(&self) -> Result { + Ok(self + .conn + .query_one::("SELECT NOT EXISTS (SELECT 1 FROM suggestions)")?) + } + /// Fetches suggestions that match the given query from the database. pub fn fetch_suggestions(&self, query: &SuggestionQuery) -> Result> { let unique_providers = query.providers.iter().collect::>(); diff --git a/third_party/rust/suggest/src/lib.rs b/third_party/rust/suggest/src/lib.rs index 15746614d0..93b456b8b4 100644 --- a/third_party/rust/suggest/src/lib.rs +++ b/third_party/rust/suggest/src/lib.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use remote_settings::RemoteSettingsConfig; +use remote_settings::{RemoteSettingsConfig, RemoteSettingsServer}; #[cfg(feature = "benchmark_api")] pub mod benchmarks; mod config; diff --git a/third_party/rust/suggest/src/schema.rs b/third_party/rust/suggest/src/schema.rs index b304363de5..76a0deed39 100644 --- a/third_party/rust/suggest/src/schema.rs +++ b/third_party/rust/suggest/src/schema.rs @@ -15,118 +15,118 @@ use sql_support::open_database::{self, ConnectionInitializer}; /// [`SuggestConnectionInitializer::upgrade_from`]. /// a. If suggestions should be re-ingested after the migration, call `clear_database()` inside /// the migration. -pub const VERSION: u32 = 18; +pub const VERSION: u32 = 19; /// The current Suggest database schema. pub const SQL: &str = " - CREATE TABLE meta( - key TEXT PRIMARY KEY, - value NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE keywords( - keyword TEXT NOT NULL, - suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, - full_keyword_id INTEGER NULL REFERENCES full_keywords(id) ON DELETE SET NULL, - rank INTEGER NOT NULL, - PRIMARY KEY (keyword, suggestion_id) - ) WITHOUT ROWID; - - -- full keywords are what we display to the user when a (partial) keyword matches - -- The FK to suggestion_id makes it so full keywords get deleted when the parent suggestion is deleted. - CREATE TABLE full_keywords( - id INTEGER PRIMARY KEY, - suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, - full_keyword TEXT NOT NULL - ); - - CREATE TABLE prefix_keywords( - keyword_prefix TEXT NOT NULL, - keyword_suffix TEXT NOT NULL DEFAULT '', - confidence INTEGER NOT NULL DEFAULT 0, - rank INTEGER NOT NULL, - suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, - PRIMARY KEY (keyword_prefix, keyword_suffix, suggestion_id) - ) WITHOUT ROWID; - - CREATE UNIQUE INDEX keywords_suggestion_id_rank ON keywords(suggestion_id, rank); - - CREATE TABLE suggestions( - id INTEGER PRIMARY KEY, - record_id TEXT NOT NULL, - provider INTEGER NOT NULL, - title TEXT NOT NULL, - url TEXT NOT NULL, - score REAL NOT NULL - ); - - CREATE TABLE amp_custom_details( - suggestion_id INTEGER PRIMARY KEY, - advertiser TEXT NOT NULL, - block_id INTEGER NOT NULL, - iab_category TEXT NOT NULL, - impression_url TEXT NOT NULL, - click_url TEXT NOT NULL, - icon_id TEXT NOT NULL, - FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE - ); - - CREATE TABLE wikipedia_custom_details( - suggestion_id INTEGER PRIMARY KEY REFERENCES suggestions(id) ON DELETE CASCADE, - icon_id TEXT NOT NULL - ); - - CREATE TABLE amo_custom_details( - suggestion_id INTEGER PRIMARY KEY, - description TEXT NOT NULL, - guid TEXT NOT NULL, - icon_url TEXT NOT NULL, - rating TEXT, - number_of_ratings INTEGER NOT NULL, - FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE - ); - - CREATE INDEX suggestions_record_id ON suggestions(record_id); - - CREATE TABLE icons( - id TEXT PRIMARY KEY, - data BLOB NOT NULL, - mimetype TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE yelp_subjects( - keyword TEXT PRIMARY KEY, - record_id TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE yelp_modifiers( - type INTEGER NOT NULL, - keyword TEXT NOT NULL, - record_id TEXT NOT NULL, - PRIMARY KEY (type, keyword) - ) WITHOUT ROWID; - - CREATE TABLE yelp_location_signs( - keyword TEXT PRIMARY KEY, - need_location INTEGER NOT NULL, - record_id TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE yelp_custom_details( - icon_id TEXT PRIMARY KEY, - score REAL NOT NULL, - record_id TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE mdn_custom_details( - suggestion_id INTEGER PRIMARY KEY, - description TEXT NOT NULL, - FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE - ); - - CREATE TABLE dismissed_suggestions ( - url TEXT PRIMARY KEY - ) WITHOUT ROWID; +CREATE TABLE meta( + key TEXT PRIMARY KEY, + value NOT NULL +) WITHOUT ROWID; + +CREATE TABLE keywords( + keyword TEXT NOT NULL, + suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, + full_keyword_id INTEGER NULL REFERENCES full_keywords(id) ON DELETE SET NULL, + rank INTEGER NOT NULL, + PRIMARY KEY (keyword, suggestion_id) +) WITHOUT ROWID; + +-- full keywords are what we display to the user when a (partial) keyword matches +-- The FK to suggestion_id makes it so full keywords get deleted when the parent suggestion is deleted. +CREATE TABLE full_keywords( + id INTEGER PRIMARY KEY, + suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, + full_keyword TEXT NOT NULL +); + +CREATE TABLE prefix_keywords( + keyword_prefix TEXT NOT NULL, + keyword_suffix TEXT NOT NULL DEFAULT '', + confidence INTEGER NOT NULL DEFAULT 0, + rank INTEGER NOT NULL, + suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, + PRIMARY KEY (keyword_prefix, keyword_suffix, suggestion_id) +) WITHOUT ROWID; + +CREATE UNIQUE INDEX keywords_suggestion_id_rank ON keywords(suggestion_id, rank); + +CREATE TABLE suggestions( + id INTEGER PRIMARY KEY, + record_id TEXT NOT NULL, + provider INTEGER NOT NULL, + title TEXT NOT NULL, + url TEXT NOT NULL, + score REAL NOT NULL +); + +CREATE TABLE amp_custom_details( + suggestion_id INTEGER PRIMARY KEY, + advertiser TEXT NOT NULL, + block_id INTEGER NOT NULL, + iab_category TEXT NOT NULL, + impression_url TEXT NOT NULL, + click_url TEXT NOT NULL, + icon_id TEXT NOT NULL, + FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE +); + +CREATE TABLE wikipedia_custom_details( + suggestion_id INTEGER PRIMARY KEY REFERENCES suggestions(id) ON DELETE CASCADE, + icon_id TEXT NOT NULL +); + +CREATE TABLE amo_custom_details( + suggestion_id INTEGER PRIMARY KEY, + description TEXT NOT NULL, + guid TEXT NOT NULL, + icon_url TEXT NOT NULL, + rating TEXT, + number_of_ratings INTEGER NOT NULL, + FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE +); + +CREATE INDEX suggestions_record_id ON suggestions(record_id); + +CREATE TABLE icons( + id TEXT PRIMARY KEY, + data BLOB NOT NULL, + mimetype TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE yelp_subjects( + keyword TEXT PRIMARY KEY, + record_id TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE yelp_modifiers( + type INTEGER NOT NULL, + keyword TEXT NOT NULL, + record_id TEXT NOT NULL, + PRIMARY KEY (type, keyword) +) WITHOUT ROWID; + +CREATE TABLE yelp_location_signs( + keyword TEXT PRIMARY KEY, + need_location INTEGER NOT NULL, + record_id TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE yelp_custom_details( + icon_id TEXT PRIMARY KEY, + score REAL NOT NULL, + record_id TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE mdn_custom_details( + suggestion_id INTEGER PRIMARY KEY, + description TEXT NOT NULL, + FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE +); + +CREATE TABLE dismissed_suggestions ( + url TEXT PRIMARY KEY +) WITHOUT ROWID; "; /// Initializes an SQLite connection to the Suggest database, performing @@ -166,9 +166,9 @@ impl ConnectionInitializer for SuggestConnectionInitializer { 16 => { tx.execute( " - CREATE TABLE dismissed_suggestions ( - url_hash INTEGER PRIMARY KEY - ) WITHOUT ROWID;", +CREATE TABLE dismissed_suggestions ( + url_hash INTEGER PRIMARY KEY +) WITHOUT ROWID;", (), )?; Ok(()) @@ -176,14 +176,23 @@ impl ConnectionInitializer for SuggestConnectionInitializer { 17 => { tx.execute( " - DROP TABLE dismissed_suggestions; - CREATE TABLE dismissed_suggestions ( - url TEXT PRIMARY KEY - ) WITHOUT ROWID;", +DROP TABLE dismissed_suggestions; +CREATE TABLE dismissed_suggestions ( + url TEXT PRIMARY KEY +) WITHOUT ROWID;", (), )?; Ok(()) } + 18 => { + tx.execute_batch( + " +CREATE TABLE IF NOT EXISTS dismissed_suggestions ( + url TEXT PRIMARY KEY +) WITHOUT ROWID;", + )?; + Ok(()) + } _ => Err(open_database::Error::IncompatibleVersion(version)), } } @@ -212,112 +221,112 @@ mod test { // Snapshot of the v16 schema. We use this to test that we can migrate from there to the // current schema. const V16_SCHEMA: &str = r#" - CREATE TABLE meta( - key TEXT PRIMARY KEY, - value NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE keywords( - keyword TEXT NOT NULL, - suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, - full_keyword_id INTEGER NULL REFERENCES full_keywords(id) ON DELETE SET NULL, - rank INTEGER NOT NULL, - PRIMARY KEY (keyword, suggestion_id) - ) WITHOUT ROWID; - - -- full keywords are what we display to the user when a (partial) keyword matches - -- The FK to suggestion_id makes it so full keywords get deleted when the parent suggestion is deleted. - CREATE TABLE full_keywords( - id INTEGER PRIMARY KEY, - suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, - full_keyword TEXT NOT NULL - ); - - CREATE TABLE prefix_keywords( - keyword_prefix TEXT NOT NULL, - keyword_suffix TEXT NOT NULL DEFAULT '', - confidence INTEGER NOT NULL DEFAULT 0, - rank INTEGER NOT NULL, - suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, - PRIMARY KEY (keyword_prefix, keyword_suffix, suggestion_id) - ) WITHOUT ROWID; - - CREATE UNIQUE INDEX keywords_suggestion_id_rank ON keywords(suggestion_id, rank); - - CREATE TABLE suggestions( - id INTEGER PRIMARY KEY, - record_id TEXT NOT NULL, - provider INTEGER NOT NULL, - title TEXT NOT NULL, - url TEXT NOT NULL, - score REAL NOT NULL - ); - - CREATE TABLE amp_custom_details( - suggestion_id INTEGER PRIMARY KEY, - advertiser TEXT NOT NULL, - block_id INTEGER NOT NULL, - iab_category TEXT NOT NULL, - impression_url TEXT NOT NULL, - click_url TEXT NOT NULL, - icon_id TEXT NOT NULL, - FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE - ); - - CREATE TABLE wikipedia_custom_details( - suggestion_id INTEGER PRIMARY KEY REFERENCES suggestions(id) ON DELETE CASCADE, - icon_id TEXT NOT NULL - ); - - CREATE TABLE amo_custom_details( - suggestion_id INTEGER PRIMARY KEY, - description TEXT NOT NULL, - guid TEXT NOT NULL, - icon_url TEXT NOT NULL, - rating TEXT, - number_of_ratings INTEGER NOT NULL, - FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE - ); - - CREATE INDEX suggestions_record_id ON suggestions(record_id); - - CREATE TABLE icons( - id TEXT PRIMARY KEY, - data BLOB NOT NULL, - mimetype TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE yelp_subjects( - keyword TEXT PRIMARY KEY, - record_id TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE yelp_modifiers( - type INTEGER NOT NULL, - keyword TEXT NOT NULL, - record_id TEXT NOT NULL, - PRIMARY KEY (type, keyword) - ) WITHOUT ROWID; - - CREATE TABLE yelp_location_signs( - keyword TEXT PRIMARY KEY, - need_location INTEGER NOT NULL, - record_id TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE yelp_custom_details( - icon_id TEXT PRIMARY KEY, - score REAL NOT NULL, - record_id TEXT NOT NULL - ) WITHOUT ROWID; - - CREATE TABLE mdn_custom_details( - suggestion_id INTEGER PRIMARY KEY, - description TEXT NOT NULL, - FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE - ); - - PRAGMA user_version=16; +CREATE TABLE meta( + key TEXT PRIMARY KEY, + value NOT NULL +) WITHOUT ROWID; + +CREATE TABLE keywords( + keyword TEXT NOT NULL, + suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, + full_keyword_id INTEGER NULL REFERENCES full_keywords(id) ON DELETE SET NULL, + rank INTEGER NOT NULL, + PRIMARY KEY (keyword, suggestion_id) +) WITHOUT ROWID; + +-- full keywords are what we display to the user when a (partial) keyword matches +-- The FK to suggestion_id makes it so full keywords get deleted when the parent suggestion is deleted. +CREATE TABLE full_keywords( + id INTEGER PRIMARY KEY, + suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, + full_keyword TEXT NOT NULL +); + +CREATE TABLE prefix_keywords( + keyword_prefix TEXT NOT NULL, + keyword_suffix TEXT NOT NULL DEFAULT '', + confidence INTEGER NOT NULL DEFAULT 0, + rank INTEGER NOT NULL, + suggestion_id INTEGER NOT NULL REFERENCES suggestions(id) ON DELETE CASCADE, + PRIMARY KEY (keyword_prefix, keyword_suffix, suggestion_id) +) WITHOUT ROWID; + +CREATE UNIQUE INDEX keywords_suggestion_id_rank ON keywords(suggestion_id, rank); + +CREATE TABLE suggestions( + id INTEGER PRIMARY KEY, + record_id TEXT NOT NULL, + provider INTEGER NOT NULL, + title TEXT NOT NULL, + url TEXT NOT NULL, + score REAL NOT NULL +); + +CREATE TABLE amp_custom_details( + suggestion_id INTEGER PRIMARY KEY, + advertiser TEXT NOT NULL, + block_id INTEGER NOT NULL, + iab_category TEXT NOT NULL, + impression_url TEXT NOT NULL, + click_url TEXT NOT NULL, + icon_id TEXT NOT NULL, + FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE +); + +CREATE TABLE wikipedia_custom_details( + suggestion_id INTEGER PRIMARY KEY REFERENCES suggestions(id) ON DELETE CASCADE, + icon_id TEXT NOT NULL +); + +CREATE TABLE amo_custom_details( + suggestion_id INTEGER PRIMARY KEY, + description TEXT NOT NULL, + guid TEXT NOT NULL, + icon_url TEXT NOT NULL, + rating TEXT, + number_of_ratings INTEGER NOT NULL, + FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE +); + +CREATE INDEX suggestions_record_id ON suggestions(record_id); + +CREATE TABLE icons( + id TEXT PRIMARY KEY, + data BLOB NOT NULL, + mimetype TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE yelp_subjects( + keyword TEXT PRIMARY KEY, + record_id TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE yelp_modifiers( + type INTEGER NOT NULL, + keyword TEXT NOT NULL, + record_id TEXT NOT NULL, + PRIMARY KEY (type, keyword) +) WITHOUT ROWID; + +CREATE TABLE yelp_location_signs( + keyword TEXT PRIMARY KEY, + need_location INTEGER NOT NULL, + record_id TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE yelp_custom_details( + icon_id TEXT PRIMARY KEY, + score REAL NOT NULL, + record_id TEXT NOT NULL +) WITHOUT ROWID; + +CREATE TABLE mdn_custom_details( + suggestion_id INTEGER PRIMARY KEY, + description TEXT NOT NULL, + FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE +); + +PRAGMA user_version=16; "#; /// Test running all schema upgrades from V16, which was the first schema with a "real" @@ -328,5 +337,6 @@ mod test { fn test_all_upgrades() { let db_file = MigratedDatabaseFile::new(SuggestConnectionInitializer, V16_SCHEMA); db_file.run_all_upgrades(); + db_file.assert_schema_matches_new_database(); } } diff --git a/third_party/rust/suggest/src/store.rs b/third_party/rust/suggest/src/store.rs index c55cffc7f5..19886b22b8 100644 --- a/third_party/rust/suggest/src/store.rs +++ b/third_party/rust/suggest/src/store.rs @@ -13,7 +13,8 @@ use error_support::handle_error; use once_cell::sync::OnceCell; use parking_lot::Mutex; use remote_settings::{ - self, GetItemsOptions, RemoteSettingsConfig, RemoteSettingsRecord, SortOrder, + self, GetItemsOptions, RemoteSettingsConfig, RemoteSettingsRecord, RemoteSettingsServer, + SortOrder, }; use rusqlite::{ types::{FromSql, ToSqlOutput}, @@ -50,6 +51,7 @@ pub struct SuggestStoreBuilder(Mutex); #[derive(Default)] struct SuggestStoreBuilderInner { data_path: Option, + remote_settings_server: Option, remote_settings_config: Option, } @@ -79,6 +81,11 @@ impl SuggestStoreBuilder { self } + pub fn remote_settings_server(self: Arc, server: RemoteSettingsServer) -> Arc { + self.0.lock().remote_settings_server = Some(server); + self + } + #[handle_error(Error)] pub fn build(&self) -> SuggestApiResult> { let inner = self.0.lock(); @@ -86,14 +93,29 @@ impl SuggestStoreBuilder { .data_path .clone() .ok_or_else(|| Error::SuggestStoreBuilder("data_path not specified".to_owned()))?; - let settings_client = - remote_settings::Client::new(inner.remote_settings_config.clone().unwrap_or_else( - || RemoteSettingsConfig { - server_url: None, - bucket_name: None, - collection_name: REMOTE_SETTINGS_COLLECTION.into(), - }, - ))?; + let remote_settings_config = match ( + inner.remote_settings_server.as_ref(), + inner.remote_settings_config.as_ref(), + ) { + (Some(server), None) => RemoteSettingsConfig { + server: Some(server.clone()), + server_url: None, + bucket_name: None, + collection_name: REMOTE_SETTINGS_COLLECTION.into(), + }, + (None, Some(remote_settings_config)) => remote_settings_config.clone(), + (None, None) => RemoteSettingsConfig { + server: None, + server_url: None, + bucket_name: None, + collection_name: REMOTE_SETTINGS_COLLECTION.into(), + }, + (Some(_), Some(_)) => Err(Error::SuggestStoreBuilder( + "can't specify both `remote_settings_server` and `remote_settings_config`" + .to_owned(), + ))?, + }; + let settings_client = remote_settings::Client::new(remote_settings_config)?; Ok(Arc::new(SuggestStore { inner: SuggestStoreInner::new(data_path, settings_client), })) @@ -172,6 +194,7 @@ impl SuggestStore { let settings_client = || -> Result<_> { Ok(remote_settings::Client::new( settings_config.unwrap_or_else(|| RemoteSettingsConfig { + server: None, server_url: None, bucket_name: None, collection_name: REMOTE_SETTINGS_COLLECTION.into(), @@ -252,6 +275,8 @@ pub struct SuggestIngestionConstraints { /// soft limit, and the store might ingest more than requested. pub max_suggestions: Option, pub providers: Option>, + /// Only run ingestion if the table `suggestions` is empty + pub empty_only: bool, } /// The implementation of the store. This is generic over the Remote Settings @@ -334,6 +359,10 @@ where pub fn ingest(&self, constraints: SuggestIngestionConstraints) -> Result<()> { let writer = &self.dbs()?.writer; + if constraints.empty_only && !writer.read(|dao| dao.suggestions_table_empty())? { + return Ok(()); + } + if let Some(unparsable_records) = writer.read(|dao| dao.get_meta::(UNPARSABLE_RECORDS_META_KEY))? { @@ -865,6 +894,12 @@ mod tests { let store = unique_test_store(SnapshotSettingsClient::with_snapshot(snapshot)); + // suggestions_table_empty returns true before the ingestion is complete + assert!(store + .dbs()? + .reader + .read(|dao| dao.suggestions_table_empty())?); + store.ingest(SuggestIngestionConstraints::default())?; store.dbs()?.reader.read(|dao| { @@ -904,6 +939,153 @@ mod tests { Ok(()) })?; + // suggestions_table_empty returns false after the ingestion is complete + assert!(!store + .dbs()? + .reader + .read(|dao| dao.suggestions_table_empty())?); + + Ok(()) + } + + /// Tests ingesting suggestions into an empty database. + #[test] + fn ingest_empty_only() -> anyhow::Result<()> { + before_each(); + + // This ingestion should run, since the DB is empty + let snapshot = Snapshot::with_records(json!([{ + "id": "1234", + "type": "data", + "last_modified": 15, + "attachment": { + "filename": "data-1.json", + "mimetype": "application/json", + "location": "data-1.json", + "hash": "", + "size": 0, + }, + }]))? + .with_data( + "data-1.json", + json!([{ + "id": 0, + "advertiser": "Los Pollos Hermanos", + "iab_category": "8 - Food & Drink", + "keywords": ["lo", "los", "los p", "los pollos", "los pollos h", "los pollos hermanos"], + "title": "Los Pollos Hermanos - Albuquerque", + "url": "https://www.lph-nm.biz", + "icon": "5678", + "impression_url": "https://example.com/impression_url", + "click_url": "https://example.com/click_url", + "score": 0.3 + }]), + )?; + let mut store = unique_test_store(SnapshotSettingsClient::with_snapshot(snapshot)); + store.ingest(SuggestIngestionConstraints { + empty_only: true, + ..SuggestIngestionConstraints::default() + })?; + + store.dbs()?.reader.read(|dao| { + expect![[r#" + [ + Amp { + title: "Los Pollos Hermanos - Albuquerque", + url: "https://www.lph-nm.biz", + raw_url: "https://www.lph-nm.biz", + icon: None, + icon_mimetype: None, + full_keyword: "los", + block_id: 0, + advertiser: "Los Pollos Hermanos", + iab_category: "8 - Food & Drink", + impression_url: "https://example.com/impression_url", + click_url: "https://example.com/click_url", + raw_click_url: "https://example.com/click_url", + score: 0.3, + }, + ] + "#]] + .assert_debug_eq(&dao.fetch_suggestions(&SuggestionQuery { + keyword: "lo".into(), + providers: vec![SuggestionProvider::Amp], + limit: None, + })?); + + Ok(()) + })?; + + // ingestion should run with SuggestIngestionConstraints::empty_only = true, since the DB + // is empty + store.settings_client = SnapshotSettingsClient::with_snapshot(Snapshot::with_records(json!([{ + "id": "1234", + "type": "data", + "last_modified": 15, + "attachment": { + "filename": "data-1.json", + "mimetype": "application/json", + "location": "data-1.json", + "hash": "", + "size": 0, + }, + }, { + "id": "12345", + "type": "data", + "last_modified": 15, + "attachment": { + "filename": "data-2.json", + "mimetype": "application/json", + "location": "data-2.json", + "hash": "", + "size": 0, + }, + }]))? + .with_data( + "data-1.json", + json!([{ + "id": 0, + "advertiser": "Los Pollos Hermanos", + "iab_category": "8 - Food & Drink", + "keywords": ["lo", "los", "los p", "los pollos", "los pollos h", "los pollos hermanos"], + "title": "Los Pollos Hermanos - Albuquerque", + "url": "https://www.lph-nm.biz", + "icon": "5678", + "impression_url": "https://example.com/impression_url", + "click_url": "https://example.com/click_url", + "score": 0.3 + }]) + )? + .with_data("data-2.json", json!([{ + "id": 1, + "advertiser": "Good Place Eats", + "iab_category": "8 - Food & Drink", + "keywords": ["la", "las", "lasa", "lasagna", "lasagna come out tomorrow"], + "title": "Lasagna Come Out Tomorrow", + "url": "https://www.lasagna.restaurant", + "icon": "2", + "impression_url": "https://example.com/impression_url", + "click_url": "https://example.com/click_url" + }]), + )?); + store.ingest(SuggestIngestionConstraints { + empty_only: true, + ..SuggestIngestionConstraints::default() + })?; + + store.dbs()?.reader.read(|dao| { + expect![[r#" + [] + "#]] + .assert_debug_eq(&dao.fetch_suggestions(&SuggestionQuery { + keyword: "la".into(), + providers: vec![SuggestionProvider::Amp], + limit: None, + })?); + + Ok(()) + })?; + Ok(()) } @@ -2189,6 +2371,7 @@ mod tests { store.ingest(SuggestIngestionConstraints { max_suggestions: Some(max_suggestions), providers: Some(vec![SuggestionProvider::Amp]), + ..SuggestIngestionConstraints::default() })?; let actual_limit = store .settings_client @@ -5021,10 +5204,10 @@ mod tests { UnparsableRecords( { "clippy-2": UnparsableRecord { - schema_version: 18, + schema_version: 19, }, "fancy-new-suggestions-1": UnparsableRecord { - schema_version: 18, + schema_version: 19, }, }, ), @@ -5093,10 +5276,10 @@ mod tests { UnparsableRecords( { "clippy-2": UnparsableRecord { - schema_version: 18, + schema_version: 19, }, "fancy-new-suggestions-1": UnparsableRecord { - schema_version: 18, + schema_version: 19, }, }, ), @@ -5178,6 +5361,7 @@ mod tests { let constraints = SuggestIngestionConstraints { max_suggestions: Some(100), providers: Some(vec![SuggestionProvider::Amp, SuggestionProvider::Pocket]), + ..SuggestIngestionConstraints::default() }; store.ingest(constraints)?; @@ -5292,10 +5476,10 @@ mod tests { UnparsableRecords( { "clippy-2": UnparsableRecord { - schema_version: 18, + schema_version: 19, }, "fancy-new-suggestions-1": UnparsableRecord { - schema_version: 18, + schema_version: 19, }, }, ), @@ -5381,7 +5565,7 @@ mod tests { UnparsableRecords( { "invalid-attachment": UnparsableRecord { - schema_version: 18, + schema_version: 19, }, }, ), diff --git a/third_party/rust/suggest/src/suggest.udl b/third_party/rust/suggest/src/suggest.udl index 4a4e3fe9a0..0c4781b951 100644 --- a/third_party/rust/suggest/src/suggest.udl +++ b/third_party/rust/suggest/src/suggest.udl @@ -6,6 +6,9 @@ [External="remote_settings"] typedef extern RemoteSettingsConfig; +[External="remote_settings"] +typedef extern RemoteSettingsServer; + namespace suggest { boolean raw_suggestion_url_matches([ByRef] string raw_url, [ByRef] string url); @@ -103,6 +106,14 @@ dictionary SuggestionQuery { dictionary SuggestIngestionConstraints { u64? max_suggestions = null; sequence? providers = null; + // Only ingest if the table `suggestions` is empty. + // + // This is indented to handle periodic updates. Consumers can schedule an ingest with + // `empty_only=true` on startup and a regular ingest with `empty_only=false` to run on a long periodic schedule (maybe + // once a day). This allows ingestion to normally be run at a slow, periodic rate. However, if + // there is a schema upgrade that causes the database to be thrown away, then the + // `empty_only=true` ingestion that runs on startup will repopulate it. + boolean empty_only = false; }; dictionary SuggestGlobalConfig { @@ -154,6 +165,10 @@ interface SuggestStoreBuilder { [Self=ByArc] SuggestStoreBuilder cache_path(string path); + [Self=ByArc] + SuggestStoreBuilder remote_settings_server(RemoteSettingsServer server); + + // Deprecated: Use `remote_settings_server()` instead. [Self=ByArc] SuggestStoreBuilder remote_settings_config(RemoteSettingsConfig config); diff --git a/third_party/rust/thiserror-impl/.cargo-checksum.json b/third_party/rust/thiserror-impl/.cargo-checksum.json index 6adcf117c2..e4016f1165 100644 --- a/third_party/rust/thiserror-impl/.cargo-checksum.json +++ b/third_party/rust/thiserror-impl/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"0a1dbd3bcb92455b7ed1d661e0c05958a64fd694a18357d3c61a8e1f2cffb9bd","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","src/ast.rs":"e2fbc32e91cd462757107c1f8ab2f888f08c865ac71270583f9e11b83e3c32ca","src/attr.rs":"7451fc0b0a06649e62679c7558e5aeb0e2019400c170cde54c23289ef44188f7","src/expand.rs":"9469753e0949556848183084e0f22521c6300d38ca0de196441446c50f350d3c","src/fmt.rs":"5d1cefc012403c2d4ff7ab2513c0ec559166df4271d5983a6463939b5ec8c3e1","src/generics.rs":"2076cde22271be355a8131a77add4b93f83ab0af4317cd2df5471fffa4f95c66","src/lib.rs":"5eea86c771e643328ad9bc3b881cce4bf9d50adae1b33e0d07645bdd9044003d","src/prop.rs":"5ba613e38430831259f20b258f33d57dcb783fbaeeb49e5faffa7b2a7be99e67","src/span.rs":"430460a4fa0d1fa9c627c1ddd575d2b101778fea84217591e1a93a5f6a2a0132","src/valid.rs":"ac95253944fd360d3578d0643a7baabb2cfa6bf9fbced7a6ce1f7b0529a3bb98"},"package":"a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"} \ No newline at end of file +{"files":{"Cargo.toml":"27f9696d64a97df170dc620366a6b6b0b162917a686511e6b878586b04846226","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","src/ast.rs":"9b6cd6b1553483c99cd7e36aa422d37f4353c99b15da55534d28822f7fa7fd08","src/attr.rs":"99fca8c65a1907ee2f43f7ec28ce465bae22336c529bd7148738f9ce35375101","src/expand.rs":"2736a714372a4b81ac5438783dd2c0f656d624bec5cc4089af96ceecaeee011e","src/fmt.rs":"5d1cefc012403c2d4ff7ab2513c0ec559166df4271d5983a6463939b5ec8c3e1","src/generics.rs":"2076cde22271be355a8131a77add4b93f83ab0af4317cd2df5471fffa4f95c66","src/lib.rs":"5eea86c771e643328ad9bc3b881cce4bf9d50adae1b33e0d07645bdd9044003d","src/prop.rs":"5ba613e38430831259f20b258f33d57dcb783fbaeeb49e5faffa7b2a7be99e67","src/span.rs":"430460a4fa0d1fa9c627c1ddd575d2b101778fea84217591e1a93a5f6a2a0132","src/valid.rs":"ac95253944fd360d3578d0643a7baabb2cfa6bf9fbced7a6ce1f7b0529a3bb98"},"package":"d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"} \ No newline at end of file diff --git a/third_party/rust/thiserror-impl/Cargo.toml b/third_party/rust/thiserror-impl/Cargo.toml index 5445c126ec..757302d6af 100644 --- a/third_party/rust/thiserror-impl/Cargo.toml +++ b/third_party/rust/thiserror-impl/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.56" name = "thiserror-impl" -version = "1.0.57" +version = "1.0.59" authors = ["David Tolnay "] description = "Implementation detail of the `thiserror` crate" license = "MIT OR Apache-2.0" diff --git a/third_party/rust/thiserror-impl/src/ast.rs b/third_party/rust/thiserror-impl/src/ast.rs index 9e06928980..4739d58beb 100644 --- a/third_party/rust/thiserror-impl/src/ast.rs +++ b/third_party/rust/thiserror-impl/src/ast.rs @@ -82,7 +82,7 @@ impl<'a> Enum<'a> { .map(|node| { let mut variant = Variant::from_syn(node, &scope, span)?; if let display @ None = &mut variant.attrs.display { - *display = attrs.display.clone(); + display.clone_from(&attrs.display); } if let Some(display) = &mut variant.attrs.display { display.expand_shorthand(&variant.fields); diff --git a/third_party/rust/thiserror-impl/src/attr.rs b/third_party/rust/thiserror-impl/src/attr.rs index 269c69eca5..395edb1f5a 100644 --- a/third_party/rust/thiserror-impl/src/attr.rs +++ b/third_party/rust/thiserror-impl/src/attr.rs @@ -230,7 +230,18 @@ impl ToTokens for Display<'_> { impl ToTokens for Trait { fn to_tokens(&self, tokens: &mut TokenStream) { - let trait_name = format_ident!("{}", format!("{:?}", self)); - tokens.extend(quote!(::core::fmt::#trait_name)); + let trait_name = match self { + Trait::Debug => "Debug", + Trait::Display => "Display", + Trait::Octal => "Octal", + Trait::LowerHex => "LowerHex", + Trait::UpperHex => "UpperHex", + Trait::Pointer => "Pointer", + Trait::Binary => "Binary", + Trait::LowerExp => "LowerExp", + Trait::UpperExp => "UpperExp", + }; + let ident = Ident::new(trait_name, Span::call_site()); + tokens.extend(quote!(::core::fmt::#ident)); } } diff --git a/third_party/rust/thiserror-impl/src/expand.rs b/third_party/rust/thiserror-impl/src/expand.rs index 1b44513a23..296b567bdc 100644 --- a/third_party/rust/thiserror-impl/src/expand.rs +++ b/third_party/rust/thiserror-impl/src/expand.rs @@ -155,7 +155,7 @@ fn impl_struct(input: Struct) -> TokenStream { ::core::fmt::Display::fmt(&self.#only_field, __formatter) }) } else if let Some(display) = &input.attrs.display { - display_implied_bounds = display.implied_bounds.clone(); + display_implied_bounds.clone_from(&display.implied_bounds); let use_as_display = use_as_display(display.has_bonus_display); let pat = fields_pat(&input.fields); Some(quote! { @@ -399,7 +399,7 @@ fn impl_enum(input: Enum) -> TokenStream { let mut display_implied_bounds = Set::new(); let display = match &variant.attrs.display { Some(display) => { - display_implied_bounds = display.implied_bounds.clone(); + display_implied_bounds.clone_from(&display.implied_bounds); display.to_token_stream() } None => { diff --git a/third_party/rust/thiserror/.cargo-checksum.json b/third_party/rust/thiserror/.cargo-checksum.json index efb4bd5017..f7e22ca1ee 100644 --- a/third_party/rust/thiserror/.cargo-checksum.json +++ b/third_party/rust/thiserror/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"315a0379d474f762b74a40fb83f8a52b7efe0f5a352e7a7ab0b9d118f32f609e","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"106c5a937767d49503e1fc5eae1b924f57f15decd8583720a3c652483e348a64","build.rs":"532f6ac494cdddfad3267067a46969a8052b02c1bd94567361f7103ab0dc8c28","build/probe.rs":"3245569a228727091f335db44c7c2f729729b2dfac9f46c1143eb179439f223d","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/aserror.rs":"cf3c98abb2b9e06afa3c4aba0df14938417c3e330315863437561cbb3573888b","src/display.rs":"0adeeeb524c6bee06de179d54e82a43dc12d2c5b7f69f6fd268ba4611ebf5233","src/lib.rs":"6903e561c2a83901061ed717061040a1d0ffb4296c2c52e19e617e1ca6c07211","src/provide.rs":"8007e22953bacfcc57bb7d12a03fbeb0acece5d2ec889cf55522a4e071d26df3","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/test_backtrace.rs":"a8f038490fb881463c0e8c36557617c47cf2d181f16c00525d4d139c7964fade","tests/test_deprecated.rs":"7b80a10f090a3982da017556d3d71398abcead59afd8278c7b9d9b1f7b66c7b3","tests/test_display.rs":"91a6bf704fd78a5565330f438f30ae4088aa8bc7ac5e1412401e440072408c03","tests/test_error.rs":"d06dca3c38f22d7ce4e27dadd6c0f78e5cefe3a2ebbc5fe44abc9ddd5ee1985f","tests/test_expr.rs":"d35b11040ebc547467f52571051854e3e094d52b8e229fa3d44700d5f40959a2","tests/test_from.rs":"36bd22be7b048cd187a19076aeac1456040f20a0b677b01c6003998b63439ea1","tests/test_generics.rs":"adc61f0d5fe8d53796848d44fb0373be5eab19a1eeb6a7172bc6f0dd7b91199c","tests/test_lints.rs":"c17d79d77edfcdd4b8f6dcdcd1c70ad065cfbc747e1a618ac6343315d0b59ea4","tests/test_option.rs":"ac30d929c019d6c54d1c1792b09e43c18dc0e4123b82051ff9e5db5e63c15e43","tests/test_path.rs":"ef5452c7e828a0179f5ace7e19f95b9762aa887caf10244adbfe36ded712c090","tests/test_source.rs":"f2f04f11bf8a709eddb1c68f113cda0c2be87e56800d6b9d991bedd545b4642f","tests/test_transparent.rs":"cd8d5be14d00d610a1782104bea6c013618501dab5c3625178ecfcf66e31f939","tests/ui/bad-field-attr.rs":"c5b567e3091969a01061843fb2d95c5e1aa3fa81edfeecdf416a84a6fba40aa8","tests/ui/bad-field-attr.stderr":"78f576d5ec66464a77f1cdf0f5bb7dcdf18f7f04f1165983a6239ec59d908ea3","tests/ui/concat-display.rs":"3995bd6b3bdd67df7bb16499775d89600c0dd20895633fe807396a64c117078d","tests/ui/concat-display.stderr":"256dfde61ee689ebe51588b135e2e030bdf95ba5adef1cb59f588c797bbdeef2","tests/ui/duplicate-enum-source.rs":"bfe28ce18042d446a76c7411aa233598211ce1157fdd3cb87bff3b3fa7c33131","tests/ui/duplicate-enum-source.stderr":"3d32fead420b27b4497be49080bc3b78f7f0ba339ead3de6c94e5dc20302c18f","tests/ui/duplicate-fmt.rs":"af53b66445bcce076a114376747f176b42c060a156563a41ccb638ae14c451fd","tests/ui/duplicate-fmt.stderr":"998bb121ce6f1595fd99529a7a1b06451b6bf476924337dce5524a83a7a5f1a1","tests/ui/duplicate-struct-source.rs":"f3d5f8e3d6fccfcdbb630db291353709583a920c6bf46f9f9de9966b67ea4c0f","tests/ui/duplicate-struct-source.stderr":"fb761d76668ac42357cf37b03c0abdbae5de0a828034990850291c9cb6ab766d","tests/ui/duplicate-transparent.rs":"41a9447e85f1a47027023442acde55c3d8610ec46d91b39bd43a42d7a004d747","tests/ui/duplicate-transparent.stderr":"4975abad43e973df158f18098d9bcb9dc39f8e75d3e733ed5d6620d1ee065c11","tests/ui/fallback-impl-with-display.rs":"141a8efbabe3fdac584bec8a61e6cceb58a34a70b825f6277037bf9d591150eb","tests/ui/fallback-impl-with-display.stderr":"1b3dad712b97598fbee70125471de1a8106eb161d42ce1f790ae07be8c8984ba","tests/ui/from-backtrace-backtrace.rs":"0caac64486c0eb9c076553c0502d468fbc477602a9a2595165a1dcd95524e5ff","tests/ui/from-backtrace-backtrace.stderr":"e24156ae0828878f3282341732b6e032eaa8cb4b4db366a6b5437ed0731d40a7","tests/ui/from-not-source.rs":"744a55aeffe11066830159ac023c33aaa5576e313b341fa24440ee13dfe3ac98","tests/ui/from-not-source.stderr":"525038e8b841707b927434cca4549168f73bd305faca17552a0d1fffa542ccc4","tests/ui/invalid-input-impl-anyway.rs":"6de91f71ddf038dffa3b9da33763a2ec3a5aa0047528e19ba998d5efe3aada5b","tests/ui/invalid-input-impl-anyway.stderr":"fa2725053cd87fc37f87546b377e6e5eed95c45e2a960863303b21a1935fdddb","tests/ui/lifetime.rs":"e72e0391695e47fcd07edbf3819f114e468e2097086ec687781c7c8d6b4b7da7","tests/ui/lifetime.stderr":"d889a23f71324afe95dafc5f9d15337fbdbc9977cb8924f0cafe3a3becf4ced7","tests/ui/missing-display.rs":"c1fd1bc0ec0fb103d7f7b128837f717d49485662839899d570b3c983f1332888","tests/ui/missing-display.stderr":"a8de0f1559da9320ee99ef334937d532d9e9f40a32ed7f8ce56fb465628bff96","tests/ui/missing-fmt.rs":"bc9e2830e54c2474ff6c27a766ed3dee88d29e40f93f30e8d64d63233866c17d","tests/ui/missing-fmt.stderr":"9a20ccee9b660fe31a5b3199307b48580bb8305cb9ce33d97d3fc767a0cfc614","tests/ui/no-display.rs":"962245372272d23e9833311c15e73221b3c7da822a2ff90189613af56ffb5c2e","tests/ui/no-display.stderr":"c145dbdd39e145b5c6f26f8504fbf1e33efa2eada37e09900b39dd62667f22d7","tests/ui/source-enum-not-error.rs":"3add5e7b4503d964bcae0848904822e1473c1d08c5a146c2df5347314ce1b8df","tests/ui/source-enum-not-error.stderr":"aeba0a8a0084833e470b6be2250370809f53c279ad603232af5302b9de9f8cce","tests/ui/source-enum-unnamed-field-not-error.rs":"a98989e908b84a8e6e6dceef02af7bdd1098a444d229950f67ed4f54d55c62e7","tests/ui/source-enum-unnamed-field-not-error.stderr":"4f3d90525dd462e67f633e83b26acec75d9af3626e40d28ded2c2438e0c73192","tests/ui/source-struct-not-error.rs":"09fb7713637242dca9192585a6daeb8d732dc1c1d0fa522b74f1c98618e6d949","tests/ui/source-struct-not-error.stderr":"b45eb66f078fec68d44feff1f8d6a676c341e9e9d9acb35daa58ec1ea20f9dae","tests/ui/source-struct-unnamed-field-not-error.rs":"eee605a9aafbb093666393e25cef4f7d7b8e90d518b9fadbdbed9685c66ccfcd","tests/ui/source-struct-unnamed-field-not-error.stderr":"10e408f71c1b61880b1d52739f222ec58a66be70a1df17e44c536fe0f9ffe2a6","tests/ui/transparent-display.rs":"b3c59583eb64b0b5a246444456d03cf52d51bcdc08885023600dbb44fd87e5f2","tests/ui/transparent-display.stderr":"16d538914e0d92026bde4b4bec75660217da9ecc6b621d12d2eb81d33ed1d1da","tests/ui/transparent-enum-many.rs":"2a40a764fb4683bff57973eec61507a6c00f7d4d7a32da6e7bd0190c2e445434","tests/ui/transparent-enum-many.stderr":"f1d78c1d6d8edbef153420db4fb9ca3dc6076fa043b5b1bc0cd291daa417a3ea","tests/ui/transparent-enum-not-error.rs":"f6315993e68bc71d6d4d39afa4d059695308ef785f92cc0d1df3e9ff55be2a9a","tests/ui/transparent-enum-not-error.stderr":"3a5fe056cd4566f402b03cb591394e0ba85bd74da53df3c8d50bda4a05c2e5ba","tests/ui/transparent-enum-source.rs":"18f606a98ac0a53f08dc56f5f923b9cbe75d25ed34479c777b48dac305d5968c","tests/ui/transparent-enum-source.stderr":"1b2e0ac53951034575d43ec0396c4e2b3cfb272db2aef8d6baa13a7e1632cc84","tests/ui/transparent-enum-unnamed-field-not-error.rs":"0c720567e9e0f87921055dfa9f607661725377633445e01a4b5048c7a7a50a85","tests/ui/transparent-enum-unnamed-field-not-error.stderr":"6d84e9a7f4e88daba12931a6c1508be60bb19125d06e44fa2fa205126d953bb1","tests/ui/transparent-struct-many.rs":"72c6b6c1a44c203d3bc68989b2f1ec092531ef75b745432824c3776c290326f6","tests/ui/transparent-struct-many.stderr":"7bd0536dbb54a0ce7d4a8e66ca7624a1b132d8a1d1e4fecca642ec77494ac01c","tests/ui/transparent-struct-not-error.rs":"fd814d3141c9182b1267b558d9daef8dd6e8b6462e1ad42b197f3a1c0703dce2","tests/ui/transparent-struct-not-error.stderr":"ac7634ea72096d8a5c1a91fd4f1b45ef870130a2698d9ae7c6530cec2f9799d5","tests/ui/transparent-struct-source.rs":"863fa691ed7d27e8767da58d9ee11fd40d6642274b36338ca1074c07964ea2b3","tests/ui/transparent-struct-source.stderr":"267dab65929e67d32347fb467a00b43af931f8205d727d7671938580217fc70e","tests/ui/transparent-struct-unnamed-field-not-error.rs":"fbff5874be44a5dcc347693d7929537256b187dfec467ed72c9968c095228d8d","tests/ui/transparent-struct-unnamed-field-not-error.stderr":"ea99d5422348c2588ad7374360e2a24649f040b9c5614c9308eff958f61960ec","tests/ui/unexpected-field-fmt.rs":"29fba7b4d81c642ec8e47cfe053aa515acf9080a86d65e685363a48993becfe3","tests/ui/unexpected-field-fmt.stderr":"20731c4a08af04bed3ff513903adadd690b6bc532b15604557e7f25575a8338f","tests/ui/unexpected-struct-source.rs":"c6cbe882d622635c216feb8290b1bd536ce0ec4feee16bc087667a21b3641d5c","tests/ui/unexpected-struct-source.stderr":"7c8227513478f6cc09e8a28be337c8a0e758a06ca5978d774c91bd43c4a54043","tests/ui/union.rs":"331adff27cebd8b95b03b6742cc8247331fda1f961e1590ed39c8d39f50cf1d8","tests/ui/union.stderr":"5f67ad29753d6fb14bc03aef7d4a1f660ee7796e469c037efbf8b13456934ad3"},"package":"1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"} \ No newline at end of file +{"files":{"Cargo.toml":"7df807832514d69476a436a1466ed9cefde6d73f8fff7829718096c8bf6bb88e","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"106c5a937767d49503e1fc5eae1b924f57f15decd8583720a3c652483e348a64","build.rs":"e93f4e6f8b7d24c9b119a85ea134067d2c2a7f78e082c1ab1e541c41225d5a36","build/probe.rs":"3245569a228727091f335db44c7c2f729729b2dfac9f46c1143eb179439f223d","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/aserror.rs":"cf3c98abb2b9e06afa3c4aba0df14938417c3e330315863437561cbb3573888b","src/display.rs":"0adeeeb524c6bee06de179d54e82a43dc12d2c5b7f69f6fd268ba4611ebf5233","src/lib.rs":"6a823f259101ba3c28fc8824afbe6ce66c1c4ffa7bea183172b25b891dfa1695","src/provide.rs":"8007e22953bacfcc57bb7d12a03fbeb0acece5d2ec889cf55522a4e071d26df3","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/test_backtrace.rs":"a8f038490fb881463c0e8c36557617c47cf2d181f16c00525d4d139c7964fade","tests/test_deprecated.rs":"7b80a10f090a3982da017556d3d71398abcead59afd8278c7b9d9b1f7b66c7b3","tests/test_display.rs":"91a6bf704fd78a5565330f438f30ae4088aa8bc7ac5e1412401e440072408c03","tests/test_error.rs":"d06dca3c38f22d7ce4e27dadd6c0f78e5cefe3a2ebbc5fe44abc9ddd5ee1985f","tests/test_expr.rs":"d35b11040ebc547467f52571051854e3e094d52b8e229fa3d44700d5f40959a2","tests/test_from.rs":"36bd22be7b048cd187a19076aeac1456040f20a0b677b01c6003998b63439ea1","tests/test_generics.rs":"adc61f0d5fe8d53796848d44fb0373be5eab19a1eeb6a7172bc6f0dd7b91199c","tests/test_lints.rs":"93d66ea5b6b91634ddf18a520b455f8bc65f3e9bbf90874e239f45ab15b0c125","tests/test_option.rs":"ac30d929c019d6c54d1c1792b09e43c18dc0e4123b82051ff9e5db5e63c15e43","tests/test_path.rs":"ef5452c7e828a0179f5ace7e19f95b9762aa887caf10244adbfe36ded712c090","tests/test_source.rs":"f2f04f11bf8a709eddb1c68f113cda0c2be87e56800d6b9d991bedd545b4642f","tests/test_transparent.rs":"cd8d5be14d00d610a1782104bea6c013618501dab5c3625178ecfcf66e31f939","tests/ui/bad-field-attr.rs":"c5b567e3091969a01061843fb2d95c5e1aa3fa81edfeecdf416a84a6fba40aa8","tests/ui/bad-field-attr.stderr":"78f576d5ec66464a77f1cdf0f5bb7dcdf18f7f04f1165983a6239ec59d908ea3","tests/ui/concat-display.rs":"3995bd6b3bdd67df7bb16499775d89600c0dd20895633fe807396a64c117078d","tests/ui/concat-display.stderr":"256dfde61ee689ebe51588b135e2e030bdf95ba5adef1cb59f588c797bbdeef2","tests/ui/duplicate-enum-source.rs":"bfe28ce18042d446a76c7411aa233598211ce1157fdd3cb87bff3b3fa7c33131","tests/ui/duplicate-enum-source.stderr":"3d32fead420b27b4497be49080bc3b78f7f0ba339ead3de6c94e5dc20302c18f","tests/ui/duplicate-fmt.rs":"af53b66445bcce076a114376747f176b42c060a156563a41ccb638ae14c451fd","tests/ui/duplicate-fmt.stderr":"998bb121ce6f1595fd99529a7a1b06451b6bf476924337dce5524a83a7a5f1a1","tests/ui/duplicate-struct-source.rs":"f3d5f8e3d6fccfcdbb630db291353709583a920c6bf46f9f9de9966b67ea4c0f","tests/ui/duplicate-struct-source.stderr":"fb761d76668ac42357cf37b03c0abdbae5de0a828034990850291c9cb6ab766d","tests/ui/duplicate-transparent.rs":"41a9447e85f1a47027023442acde55c3d8610ec46d91b39bd43a42d7a004d747","tests/ui/duplicate-transparent.stderr":"4975abad43e973df158f18098d9bcb9dc39f8e75d3e733ed5d6620d1ee065c11","tests/ui/fallback-impl-with-display.rs":"141a8efbabe3fdac584bec8a61e6cceb58a34a70b825f6277037bf9d591150eb","tests/ui/fallback-impl-with-display.stderr":"1b3dad712b97598fbee70125471de1a8106eb161d42ce1f790ae07be8c8984ba","tests/ui/from-backtrace-backtrace.rs":"0caac64486c0eb9c076553c0502d468fbc477602a9a2595165a1dcd95524e5ff","tests/ui/from-backtrace-backtrace.stderr":"e24156ae0828878f3282341732b6e032eaa8cb4b4db366a6b5437ed0731d40a7","tests/ui/from-not-source.rs":"744a55aeffe11066830159ac023c33aaa5576e313b341fa24440ee13dfe3ac98","tests/ui/from-not-source.stderr":"525038e8b841707b927434cca4549168f73bd305faca17552a0d1fffa542ccc4","tests/ui/invalid-input-impl-anyway.rs":"6de91f71ddf038dffa3b9da33763a2ec3a5aa0047528e19ba998d5efe3aada5b","tests/ui/invalid-input-impl-anyway.stderr":"fa2725053cd87fc37f87546b377e6e5eed95c45e2a960863303b21a1935fdddb","tests/ui/lifetime.rs":"e72e0391695e47fcd07edbf3819f114e468e2097086ec687781c7c8d6b4b7da7","tests/ui/lifetime.stderr":"d889a23f71324afe95dafc5f9d15337fbdbc9977cb8924f0cafe3a3becf4ced7","tests/ui/missing-display.rs":"c1fd1bc0ec0fb103d7f7b128837f717d49485662839899d570b3c983f1332888","tests/ui/missing-display.stderr":"a8de0f1559da9320ee99ef334937d532d9e9f40a32ed7f8ce56fb465628bff96","tests/ui/missing-fmt.rs":"bc9e2830e54c2474ff6c27a766ed3dee88d29e40f93f30e8d64d63233866c17d","tests/ui/missing-fmt.stderr":"9a20ccee9b660fe31a5b3199307b48580bb8305cb9ce33d97d3fc767a0cfc614","tests/ui/no-display.rs":"962245372272d23e9833311c15e73221b3c7da822a2ff90189613af56ffb5c2e","tests/ui/no-display.stderr":"c145dbdd39e145b5c6f26f8504fbf1e33efa2eada37e09900b39dd62667f22d7","tests/ui/source-enum-not-error.rs":"3add5e7b4503d964bcae0848904822e1473c1d08c5a146c2df5347314ce1b8df","tests/ui/source-enum-not-error.stderr":"aeba0a8a0084833e470b6be2250370809f53c279ad603232af5302b9de9f8cce","tests/ui/source-enum-unnamed-field-not-error.rs":"a98989e908b84a8e6e6dceef02af7bdd1098a444d229950f67ed4f54d55c62e7","tests/ui/source-enum-unnamed-field-not-error.stderr":"4f3d90525dd462e67f633e83b26acec75d9af3626e40d28ded2c2438e0c73192","tests/ui/source-struct-not-error.rs":"09fb7713637242dca9192585a6daeb8d732dc1c1d0fa522b74f1c98618e6d949","tests/ui/source-struct-not-error.stderr":"b45eb66f078fec68d44feff1f8d6a676c341e9e9d9acb35daa58ec1ea20f9dae","tests/ui/source-struct-unnamed-field-not-error.rs":"eee605a9aafbb093666393e25cef4f7d7b8e90d518b9fadbdbed9685c66ccfcd","tests/ui/source-struct-unnamed-field-not-error.stderr":"10e408f71c1b61880b1d52739f222ec58a66be70a1df17e44c536fe0f9ffe2a6","tests/ui/transparent-display.rs":"b3c59583eb64b0b5a246444456d03cf52d51bcdc08885023600dbb44fd87e5f2","tests/ui/transparent-display.stderr":"16d538914e0d92026bde4b4bec75660217da9ecc6b621d12d2eb81d33ed1d1da","tests/ui/transparent-enum-many.rs":"2a40a764fb4683bff57973eec61507a6c00f7d4d7a32da6e7bd0190c2e445434","tests/ui/transparent-enum-many.stderr":"f1d78c1d6d8edbef153420db4fb9ca3dc6076fa043b5b1bc0cd291daa417a3ea","tests/ui/transparent-enum-not-error.rs":"f6315993e68bc71d6d4d39afa4d059695308ef785f92cc0d1df3e9ff55be2a9a","tests/ui/transparent-enum-not-error.stderr":"3a5fe056cd4566f402b03cb591394e0ba85bd74da53df3c8d50bda4a05c2e5ba","tests/ui/transparent-enum-source.rs":"18f606a98ac0a53f08dc56f5f923b9cbe75d25ed34479c777b48dac305d5968c","tests/ui/transparent-enum-source.stderr":"1b2e0ac53951034575d43ec0396c4e2b3cfb272db2aef8d6baa13a7e1632cc84","tests/ui/transparent-enum-unnamed-field-not-error.rs":"0c720567e9e0f87921055dfa9f607661725377633445e01a4b5048c7a7a50a85","tests/ui/transparent-enum-unnamed-field-not-error.stderr":"6d84e9a7f4e88daba12931a6c1508be60bb19125d06e44fa2fa205126d953bb1","tests/ui/transparent-struct-many.rs":"72c6b6c1a44c203d3bc68989b2f1ec092531ef75b745432824c3776c290326f6","tests/ui/transparent-struct-many.stderr":"7bd0536dbb54a0ce7d4a8e66ca7624a1b132d8a1d1e4fecca642ec77494ac01c","tests/ui/transparent-struct-not-error.rs":"fd814d3141c9182b1267b558d9daef8dd6e8b6462e1ad42b197f3a1c0703dce2","tests/ui/transparent-struct-not-error.stderr":"ac7634ea72096d8a5c1a91fd4f1b45ef870130a2698d9ae7c6530cec2f9799d5","tests/ui/transparent-struct-source.rs":"863fa691ed7d27e8767da58d9ee11fd40d6642274b36338ca1074c07964ea2b3","tests/ui/transparent-struct-source.stderr":"267dab65929e67d32347fb467a00b43af931f8205d727d7671938580217fc70e","tests/ui/transparent-struct-unnamed-field-not-error.rs":"fbff5874be44a5dcc347693d7929537256b187dfec467ed72c9968c095228d8d","tests/ui/transparent-struct-unnamed-field-not-error.stderr":"ea99d5422348c2588ad7374360e2a24649f040b9c5614c9308eff958f61960ec","tests/ui/unexpected-field-fmt.rs":"29fba7b4d81c642ec8e47cfe053aa515acf9080a86d65e685363a48993becfe3","tests/ui/unexpected-field-fmt.stderr":"20731c4a08af04bed3ff513903adadd690b6bc532b15604557e7f25575a8338f","tests/ui/unexpected-struct-source.rs":"c6cbe882d622635c216feb8290b1bd536ce0ec4feee16bc087667a21b3641d5c","tests/ui/unexpected-struct-source.stderr":"7c8227513478f6cc09e8a28be337c8a0e758a06ca5978d774c91bd43c4a54043","tests/ui/union.rs":"331adff27cebd8b95b03b6742cc8247331fda1f961e1590ed39c8d39f50cf1d8","tests/ui/union.stderr":"5f67ad29753d6fb14bc03aef7d4a1f660ee7796e469c037efbf8b13456934ad3"},"package":"f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"} \ No newline at end of file diff --git a/third_party/rust/thiserror/Cargo.toml b/third_party/rust/thiserror/Cargo.toml index bb7315063c..b22f808e28 100644 --- a/third_party/rust/thiserror/Cargo.toml +++ b/third_party/rust/thiserror/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.56" name = "thiserror" -version = "1.0.57" +version = "1.0.59" authors = ["David Tolnay "] description = "derive(Error)" documentation = "https://docs.rs/thiserror" @@ -32,7 +32,7 @@ rustdoc-args = ["--generate-link-to-definition"] targets = ["x86_64-unknown-linux-gnu"] [dependencies.thiserror-impl] -version = "=1.0.57" +version = "=1.0.59" [dev-dependencies.anyhow] version = "1.0.73" diff --git a/third_party/rust/thiserror/build.rs b/third_party/rust/thiserror/build.rs index 0b995d8ea0..ad42f256f5 100644 --- a/third_party/rust/thiserror/build.rs +++ b/third_party/rust/thiserror/build.rs @@ -1,5 +1,6 @@ use std::env; use std::ffi::OsString; +use std::iter; use std::path::Path; use std::process::{self, Command, Stdio}; @@ -66,15 +67,15 @@ fn compile_probe(rustc_bootstrap: bool) -> bool { let out_dir = cargo_env_var("OUT_DIR"); let probefile = Path::new("build").join("probe.rs"); - // Make sure to pick up Cargo rustc configuration. - let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") { - let mut cmd = Command::new(wrapper); - // The wrapper's first argument is supposed to be the path to rustc. - cmd.arg(rustc); - cmd - } else { - Command::new(rustc) - }; + let rustc_wrapper = env::var_os("RUSTC_WRAPPER").filter(|wrapper| !wrapper.is_empty()); + let rustc_workspace_wrapper = + env::var_os("RUSTC_WORKSPACE_WRAPPER").filter(|wrapper| !wrapper.is_empty()); + let mut rustc = rustc_wrapper + .into_iter() + .chain(rustc_workspace_wrapper) + .chain(iter::once(rustc)); + let mut cmd = Command::new(rustc.next().unwrap()); + cmd.args(rustc); if !rustc_bootstrap { cmd.env_remove("RUSTC_BOOTSTRAP"); @@ -84,6 +85,7 @@ fn compile_probe(rustc_bootstrap: bool) -> bool { .arg("--edition=2018") .arg("--crate-name=thiserror") .arg("--crate-type=lib") + .arg("--cap-lints=allow") .arg("--emit=dep-info,metadata") .arg("--out-dir") .arg(out_dir) diff --git a/third_party/rust/thiserror/src/lib.rs b/third_party/rust/thiserror/src/lib.rs index 717cdc6f19..5b07dca600 100644 --- a/third_party/rust/thiserror/src/lib.rs +++ b/third_party/rust/thiserror/src/lib.rs @@ -228,7 +228,7 @@ //! //! [`anyhow`]: https://github.com/dtolnay/anyhow -#![doc(html_root_url = "https://docs.rs/thiserror/1.0.57")] +#![doc(html_root_url = "https://docs.rs/thiserror/1.0.59")] #![allow( clippy::module_name_repetitions, clippy::needless_lifetimes, diff --git a/third_party/rust/thiserror/tests/test_lints.rs b/third_party/rust/thiserror/tests/test_lints.rs index 59699a4a3f..cafcbc0f36 100644 --- a/third_party/rust/thiserror/tests/test_lints.rs +++ b/third_party/rust/thiserror/tests/test_lints.rs @@ -1,3 +1,5 @@ +#![allow(clippy::mixed_attributes_style)] + use thiserror::Error; pub use std::error::Error; diff --git a/third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json b/third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json deleted file mode 100644 index 33a5447821..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"359cffb76e0eac82aeec6a667f7670fa4b88346c2dd7c17febe71731fd6df58b","build.rs":"7d98b49c1d9c868c4199f0417eaa017ab459cdd536e9a29851d5f707941f9ead","src/arithmetic.udl":"8554c6907ece627645f6b896f71430e5412bf19b0ac6becf63eb9a69868d0f7a","src/lib.rs":"c454193443e92d49f997c760f4131192fb66bf213bbac1710c1ebde19e765e5d","tests/bindings/test_arithmetic.kts":"e0e9347755db4e18f70b1b74c2d5a4aa328373015090ed959b46d65c2a205d92","tests/bindings/test_arithmetic.py":"3e41d69e21e96a6830197c760f3b7bddd754edc0c5515b7bd33b79cccb10f941","tests/bindings/test_arithmetic.rb":"ea0fdce0a4c7b557b427db77521da05240cd6e87d60a128ac2307fab3bbbc76d","tests/bindings/test_arithmetic.swift":"455b87d95fc690af9c35f9e43676e9c855dedddd2fc1c9e1cbaa6a02835c2d4c","tests/test_generated_bindings.rs":"26b92d6b3e648f6fadd4182cbdba4f412b73da48a789785fd98cd486b29abf05","uniffi.toml":"a2d4f46fa51dc1be1e8bcdf67ec13223637fc1b6c6437455cf53c2dae065fb45"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-arithmetic/Cargo.toml b/third_party/rust/uniffi-example-arithmetic/Cargo.toml deleted file mode 100644 index 52f08bb9f6..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "uniffi-example-arithmetic" -version = "0.22.0" -authors = ["Firefox Sync Team "] -publish = false -license = "MPL-2.0" - -[lib] -name = "arithmetical" -crate-type = [ - "lib", - "cdylib", -] - -[dependencies] -thiserror = "1.0" - -[dependencies.uniffi] -version = "0.27" -path = "../../uniffi" - -[dev-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["bindgen-tests"] - -[build-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["build"] diff --git a/third_party/rust/uniffi-example-arithmetic/build.rs b/third_party/rust/uniffi-example-arithmetic/build.rs deleted file mode 100644 index 303ac22d8d..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -fn main() { - uniffi::generate_scaffolding("src/arithmetic.udl").unwrap(); -} diff --git a/third_party/rust/uniffi-example-arithmetic/src/arithmetic.udl b/third_party/rust/uniffi-example-arithmetic/src/arithmetic.udl deleted file mode 100644 index 117df4834a..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/src/arithmetic.udl +++ /dev/null @@ -1,16 +0,0 @@ -[Error] -enum ArithmeticError { - "IntegerOverflow", -}; - -namespace arithmetic { - [Throws=ArithmeticError] - u64 add(u64 a, u64 b); - - [Throws=ArithmeticError] - u64 sub(u64 a, u64 b); - - u64 div(u64 dividend, u64 divisor); - - boolean equal(u64 a, u64 b); -}; diff --git a/third_party/rust/uniffi-example-arithmetic/src/lib.rs b/third_party/rust/uniffi-example-arithmetic/src/lib.rs deleted file mode 100644 index 92ab8c072b..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#[derive(Debug, thiserror::Error)] -pub enum ArithmeticError { - #[error("Integer overflow on an operation with {a} and {b}")] - IntegerOverflow { a: u64, b: u64 }, -} - -fn add(a: u64, b: u64) -> Result { - a.checked_add(b) - .ok_or(ArithmeticError::IntegerOverflow { a, b }) -} - -fn sub(a: u64, b: u64) -> Result { - a.checked_sub(b) - .ok_or(ArithmeticError::IntegerOverflow { a, b }) -} - -fn div(dividend: u64, divisor: u64) -> u64 { - if divisor == 0 { - panic!("Can't divide by zero"); - } - dividend / divisor -} - -fn equal(a: u64, b: u64) -> bool { - a == b -} - -type Result = std::result::Result; - -uniffi::include_scaffolding!("arithmetic"); diff --git a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.kts b/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.kts deleted file mode 100644 index ef11850ae2..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.kts +++ /dev/null @@ -1,29 +0,0 @@ -import org.mozilla.uniffi.example.arithmetic.*; - -assert(add(2u, 4u) == 6uL) -assert(add(4u, 8u) == 12uL) - -try { - sub(0u, 2u) - throw RuntimeException("Should have thrown a IntegerOverflow exception!") -} catch (e: ArithmeticException) { - // It's okay! -} - -assert(sub(4u, 2u) == 2uL) -assert(sub(8u, 4u) == 4uL) - -assert(div(8u, 4u) == 2uL) - -try { - div(8u, 0u) - throw RuntimeException("Should have panicked when dividing by zero") -} catch (e: InternalException) { - // It's okay! -} - -assert(equal(2u, 2uL)) -assert(equal(4u, 4uL)) - -assert(!equal(2u, 4uL)) -assert(!equal(4u, 8uL)) diff --git a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.py b/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.py deleted file mode 100644 index 0d4e666fbf..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.py +++ /dev/null @@ -1,37 +0,0 @@ -from arithmetic import * - -try: - add(18446744073709551615, 1) - assert(not("Should have thrown a IntegerOverflow exception!")) -except ArithmeticError.IntegerOverflow: - # It's okay! - pass - -assert add(2, 4) == 6 -assert add(4, 8) == 12 - -try: - sub(0, 1) - assert(not("Should have thrown a IntegerOverflow exception!")) -except ArithmeticError.IntegerOverflow: - # It's okay! - pass - -assert sub(4, 2) == 2 -assert sub(8, 4) == 4 - -assert div(8, 4) == 2 - -try: - div(8, 0) -except InternalError: - # It's okay! - pass -else: - assert(not("Should have panicked when dividing by zero")) - -assert equal(2, 2) -assert equal(4, 4) - -assert not equal(2, 4) -assert not equal(4, 8) diff --git a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.rb b/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.rb deleted file mode 100644 index 6669eb279f..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require 'test/unit' -require 'arithmetic' - -include Test::Unit::Assertions - -assert_raise Arithmetic::ArithmeticError::IntegerOverflow do - Arithmetic.add 18_446_744_073_709_551_615, 1 -end - -assert_equal Arithmetic.add(2, 4), 6 -assert_equal Arithmetic.add(4, 8), 12 - -assert_raise Arithmetic::ArithmeticError::IntegerOverflow do - Arithmetic.sub 0, 1 -end - -assert_equal Arithmetic.sub(4, 2), 2 -assert_equal Arithmetic.sub(8, 4), 4 -assert_equal Arithmetic.div(8, 4), 2 - -assert_raise Arithmetic::InternalError do - Arithmetic.div 8, 0 -end - -assert Arithmetic.equal(2, 2) -assert Arithmetic.equal(4, 4) - -assert !Arithmetic.equal(2, 4) -assert !Arithmetic.equal(4, 8) diff --git a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.swift b/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.swift deleted file mode 100644 index a8e34680e4..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/tests/bindings/test_arithmetic.swift +++ /dev/null @@ -1,32 +0,0 @@ -import arithmetic - -do { - let _ = try add(a: 18446744073709551615, b: 1) - fatalError("Should have thrown a IntegerOverflow exception!") -} catch ArithmeticError.IntegerOverflow { - // It's okay! -} - -assert(try! add(a: 2, b: 4) == 6, "add work") -assert(try! add(a: 4, b: 8) == 12, "add work") - -do { - let _ = try sub(a: 0, b: 1) - fatalError("Should have thrown a IntegerOverflow exception!") -} catch ArithmeticError.IntegerOverflow { - // It's okay! -} - -assert(try! sub(a: 4, b: 2) == 2, "sub work") -assert(try! sub(a: 8, b: 4) == 4, "sub work") - -assert(div(dividend: 8, divisor: 4) == 2, "div works") - -// We can't test panicking in Swift because we force unwrap the error in -// `div`, which we can't catch. - -assert(equal(a: 2, b: 2), "equal works") -assert(equal(a: 4, b: 4), "equal works") - -assert(!equal(a: 2, b: 4), "non-equal works") -assert(!equal(a: 4, b: 8), "non-equal works") diff --git a/third_party/rust/uniffi-example-arithmetic/tests/test_generated_bindings.rs b/third_party/rust/uniffi-example-arithmetic/tests/test_generated_bindings.rs deleted file mode 100644 index 168e6e1d4c..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/tests/test_generated_bindings.rs +++ /dev/null @@ -1,6 +0,0 @@ -uniffi::build_foreign_language_testcases!( - "tests/bindings/test_arithmetic.rb", - "tests/bindings/test_arithmetic.py", - "tests/bindings/test_arithmetic.kts", - "tests/bindings/test_arithmetic.swift", -); diff --git a/third_party/rust/uniffi-example-arithmetic/uniffi.toml b/third_party/rust/uniffi-example-arithmetic/uniffi.toml deleted file mode 100644 index 883231dcaa..0000000000 --- a/third_party/rust/uniffi-example-arithmetic/uniffi.toml +++ /dev/null @@ -1,2 +0,0 @@ -[bindings.kotlin] -package_name = "org.mozilla.uniffi.example.arithmetic" diff --git a/third_party/rust/uniffi-example-geometry/.cargo-checksum.json b/third_party/rust/uniffi-example-geometry/.cargo-checksum.json deleted file mode 100644 index 52b8ef33db..0000000000 --- a/third_party/rust/uniffi-example-geometry/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"2d2c1ec66f7e2aaa4553b5338e68a7b64d68b84152547e1ccc4eeb019ca97103","build.rs":"fc5da645c8862e15f3b6879db179a1e5eec6161dc1cfbf95a4db9daf107a133f","src/geometry.udl":"7da7a6ec080c7117ec3c25206e23f9ed436e60b1a26fba34f991547680443550","src/lib.rs":"f9d004c97efb1a719368169f0aab181f27439eda3520c1afaca2420433226682","tests/bindings/test_geometry.kts":"e537185e3c699df1c0468525700e8a38f9a504b2a663c38442146b951e38e9a7","tests/bindings/test_geometry.py":"600e74ba0eba4e35d824c8f6d5bd5a2120a470017e8465c32d1e954a1939d323","tests/bindings/test_geometry.rb":"651de70af595f8b52ef030a03356939e8c1d0b40e44b4155b45d565d1d1dcbed","tests/bindings/test_geometry.swift":"a61fec6bfe16020809e20e4da372748c24366767138c5672a0bfff85c4b62d78","tests/test_generated_bindings.rs":"ff8fc093ccb6ee3ee2235c09276c7bb87234ad143667429cb721e46379577f3d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-geometry/Cargo.toml b/third_party/rust/uniffi-example-geometry/Cargo.toml deleted file mode 100644 index b9c8a0beb6..0000000000 --- a/third_party/rust/uniffi-example-geometry/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "uniffi-example-geometry" -version = "0.22.0" -authors = ["Firefox Sync Team "] -publish = false -license = "MPL-2.0" - -[lib] -name = "uniffi_geometry" -crate-type = [ - "lib", - "cdylib", -] - -[dependencies.uniffi] -version = "0.27" -path = "../../uniffi" - -[dev-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["bindgen-tests"] - -[build-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["build"] diff --git a/third_party/rust/uniffi-example-geometry/build.rs b/third_party/rust/uniffi-example-geometry/build.rs deleted file mode 100644 index 2dd1c96bc3..0000000000 --- a/third_party/rust/uniffi-example-geometry/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -fn main() { - uniffi::generate_scaffolding("src/geometry.udl").unwrap(); -} diff --git a/third_party/rust/uniffi-example-geometry/src/geometry.udl b/third_party/rust/uniffi-example-geometry/src/geometry.udl deleted file mode 100644 index af60d429bf..0000000000 --- a/third_party/rust/uniffi-example-geometry/src/geometry.udl +++ /dev/null @@ -1,15 +0,0 @@ - -namespace geometry { - double gradient(Line ln); - Point? intersection(Line ln1, Line ln2); -}; - -dictionary Point { - double coord_x; - double coord_y; -}; - -dictionary Line { - Point start; - Point end; -}; diff --git a/third_party/rust/uniffi-example-geometry/src/lib.rs b/third_party/rust/uniffi-example-geometry/src/lib.rs deleted file mode 100644 index d710b150bb..0000000000 --- a/third_party/rust/uniffi-example-geometry/src/lib.rs +++ /dev/null @@ -1,47 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp -// Silence, clippy! -const EPSILON: f64 = 0.0001f64; - -#[derive(Debug, Clone)] -pub struct Point { - coord_x: f64, - coord_y: f64, -} - -#[derive(Debug, Clone)] -pub struct Line { - start: Point, - end: Point, -} - -pub fn gradient(ln: Line) -> f64 { - let rise = ln.end.coord_y - ln.start.coord_y; - let run = ln.end.coord_x - ln.start.coord_x; - rise / run -} - -pub fn intersection(ln1: Line, ln2: Line) -> Option { - // TODO: yuck, should be able to take &Line as argument here - // and have rust figure it out with a bunch of annotations... - let g1 = gradient(ln1.clone()); - let z1 = ln1.start.coord_y - g1 * ln1.start.coord_x; - let g2 = gradient(ln2.clone()); - let z2 = ln2.start.coord_y - g2 * ln2.start.coord_x; - // Parallel lines do not intersect. - if (g1 - g2).abs() < EPSILON { - return None; - } - // Otherwise, they intersect at this fancy calculation that - // I found on wikipedia. - let x = (z2 - z1) / (g1 - g2); - Some(Point { - coord_x: x, - coord_y: g1 * x + z1, - }) -} - -uniffi::include_scaffolding!("geometry"); diff --git a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.kts b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.kts deleted file mode 100644 index 77bb9932ec..0000000000 --- a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.kts +++ /dev/null @@ -1,10 +0,0 @@ -import uniffi.geometry.*; - -val ln1 = Line(Point(0.0,0.0), Point(1.0,2.0)) -val ln2 = Line(Point(1.0,1.0), Point(2.0,2.0)) - -assert( gradient(ln1) == 2.0 ) -assert( gradient(ln2) == 1.0 ) - -assert( intersection(ln1, ln2) == Point(0.0, 0.0) ) -assert( intersection(ln1, ln1) == null ) diff --git a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py deleted file mode 100644 index fd6772be24..0000000000 --- a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py +++ /dev/null @@ -1,10 +0,0 @@ -from geometry import * - -ln1 = Line(start=Point(coord_x=0, coord_y=0), end=Point(coord_x=1, coord_y=2)) -ln2 = Line(start=Point(coord_x=1, coord_y=1), end=Point(coord_x=2, coord_y=2)) - -assert gradient(ln1) == 2 -assert gradient(ln2) == 1 - -assert intersection(ln1, ln2) == Point(coord_x=0, coord_y=0) -assert intersection(ln1, ln1) is None diff --git a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb deleted file mode 100644 index 90fdff684e..0000000000 --- a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'test/unit' -require 'geometry' - -include Test::Unit::Assertions -include Geometry - -ln1 = Line.new(start: Point.new(coord_x: 0.0, coord_y: 0.0), _end: Point.new(coord_x: 1.0, coord_y: 2.0)) -ln2 = Line.new(start: Point.new(coord_x: 1.0, coord_y: 1.0), _end: Point.new(coord_x: 2.0, coord_y: 2.0)) - -assert_equal Geometry.gradient(ln1), 2 -assert_equal Geometry.gradient(ln2), 1 - -assert_equal Geometry.intersection(ln1, ln2), Point.new(coord_x: 0, coord_y: 0) -assert Geometry.intersection(ln1, ln1).nil? diff --git a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.swift b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.swift deleted file mode 100644 index 58bd65607f..0000000000 --- a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.swift +++ /dev/null @@ -1,10 +0,0 @@ -import geometry - -let ln1 = Line(start: Point(coordX: 0, coordY: 0), end: Point(coordX: 1, coordY: 2)) -let ln2 = Line(start: Point(coordX: 1, coordY: 1), end: Point(coordX: 2, coordY: 2)) - -assert(gradient(ln: ln1) == 2.0) -assert(gradient(ln: ln2) == 1.0) - -assert(intersection(ln1: ln1, ln2: ln2) == Point(coordX: 0, coordY: 0)) -assert(intersection(ln1: ln1, ln2: ln1) == nil) diff --git a/third_party/rust/uniffi-example-geometry/tests/test_generated_bindings.rs b/third_party/rust/uniffi-example-geometry/tests/test_generated_bindings.rs deleted file mode 100644 index 4638d847c8..0000000000 --- a/third_party/rust/uniffi-example-geometry/tests/test_generated_bindings.rs +++ /dev/null @@ -1,6 +0,0 @@ -uniffi::build_foreign_language_testcases!( - "tests/bindings/test_geometry.py", - "tests/bindings/test_geometry.rb", - "tests/bindings/test_geometry.kts", - "tests/bindings/test_geometry.swift", -); diff --git a/third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json b/third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json deleted file mode 100644 index 2f1f261a13..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"c0706abf631a178bfbc2e53b0b714d4a7b73059c46e1326efa4f52d235dc05f5","build.rs":"ba88cce38ecd3321a7a93623755e3339e255360a7f946d3779ded804662c081a","src/lib.rs":"740d70ab5ca22eefcc291a56a9e4ed84e9669f4cfe3890e7d79bc56ae4b991a3","src/rondpoint.udl":"c903cb8c95b3ec1b103350857c3c3bc428bfd90c86a6c48089db9e0fc6e41eb5","tests/bindings/test_rondpoint.kts":"4aac8353278807f4add95c81f4c6c61187204b9767f882fd64872ed8ac1f6451","tests/bindings/test_rondpoint.py":"af25a56c35da9a934fb9f098c25f57329c53d461be378e4c5089b12a45efa28b","tests/bindings/test_rondpoint.rb":"d4b4523084534266ea7ef3161021b9903cb8d7a75cf4624c59055af9f02d22f9","tests/bindings/test_rondpoint.swift":"fa806e7e09c22ed44496658f6e0781765447bbdd250d7adf4b1152248ed70e69","tests/test_generated_bindings.rs":"5464f89e91c458f164b83a454c6df67a2953873e8a785a4720a2253d843f88e5"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-rondpoint/Cargo.toml b/third_party/rust/uniffi-example-rondpoint/Cargo.toml deleted file mode 100644 index 44d9628df4..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "uniffi-example-rondpoint" -version = "0.22.0" -authors = ["Firefox Sync Team "] -publish = false -license = "MPL-2.0" - -[lib] -name = "uniffi_rondpoint" -crate-type = [ - "lib", - "cdylib", -] - -[dependencies.uniffi] -version = "0.27" -path = "../../uniffi" - -[dev-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["bindgen-tests"] - -[build-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["build"] diff --git a/third_party/rust/uniffi-example-rondpoint/build.rs b/third_party/rust/uniffi-example-rondpoint/build.rs deleted file mode 100644 index f830879d09..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -fn main() { - uniffi::generate_scaffolding("src/rondpoint.udl").unwrap(); -} diff --git a/third_party/rust/uniffi-example-rondpoint/src/lib.rs b/third_party/rust/uniffi-example-rondpoint/src/lib.rs deleted file mode 100644 index 3f2233ddaa..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/src/lib.rs +++ /dev/null @@ -1,293 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use std::collections::HashMap; - -#[derive(Debug, Clone)] -pub struct Dictionnaire { - un: Enumeration, - deux: bool, - petit_nombre: u8, - gros_nombre: u64, -} - -#[derive(Debug, Clone)] -pub struct DictionnaireNombres { - petit_nombre: u8, - court_nombre: u16, - nombre_simple: u32, - gros_nombre: u64, -} - -#[derive(Debug, Clone)] -pub struct DictionnaireNombresSignes { - petit_nombre: i8, - court_nombre: i16, - nombre_simple: i32, - gros_nombre: i64, -} - -#[derive(Debug, Clone)] -pub enum Enumeration { - Un, - Deux, - Trois, -} - -#[derive(Debug, Clone)] -pub enum EnumerationAvecDonnees { - Zero, - Un { premier: u32 }, - Deux { premier: u32, second: String }, -} - -#[allow(non_camel_case_types)] -#[allow(non_snake_case)] -pub struct minusculeMAJUSCULEDict { - minusculeMAJUSCULEField: bool, -} - -#[allow(non_camel_case_types)] -pub enum minusculeMAJUSCULEEnum { - minusculeMAJUSCULEVariant, -} - -fn copie_enumeration(e: Enumeration) -> Enumeration { - e -} - -fn copie_enumerations(e: Vec) -> Vec { - e -} - -fn copie_carte( - e: HashMap, -) -> HashMap { - e -} - -fn copie_dictionnaire(d: Dictionnaire) -> Dictionnaire { - d -} - -fn switcheroo(b: bool) -> bool { - !b -} - -// Test that values can traverse both ways across the FFI. -// Even if roundtripping works, it's possible we have -// symmetrical errors that cancel each other out. -#[derive(Debug, Clone)] -struct Retourneur; -impl Retourneur { - fn new() -> Self { - Retourneur - } - fn identique_i8(&self, value: i8) -> i8 { - value - } - fn identique_u8(&self, value: u8) -> u8 { - value - } - fn identique_i16(&self, value: i16) -> i16 { - value - } - fn identique_u16(&self, value: u16) -> u16 { - value - } - fn identique_i32(&self, value: i32) -> i32 { - value - } - fn identique_u32(&self, value: u32) -> u32 { - value - } - fn identique_i64(&self, value: i64) -> i64 { - value - } - fn identique_u64(&self, value: u64) -> u64 { - value - } - fn identique_float(&self, value: f32) -> f32 { - value - } - fn identique_double(&self, value: f64) -> f64 { - value - } - fn identique_boolean(&self, value: bool) -> bool { - value - } - fn identique_string(&self, value: String) -> String { - value - } - fn identique_nombres_signes( - &self, - value: DictionnaireNombresSignes, - ) -> DictionnaireNombresSignes { - value - } - fn identique_nombres(&self, value: DictionnaireNombres) -> DictionnaireNombres { - value - } - fn identique_optionneur_dictionnaire( - &self, - value: OptionneurDictionnaire, - ) -> OptionneurDictionnaire { - value - } -} - -#[derive(Debug, Clone)] -struct Stringifier; - -#[allow(dead_code)] -impl Stringifier { - fn new() -> Self { - Stringifier - } - fn to_string_i8(&self, value: i8) -> String { - value.to_string() - } - fn to_string_u8(&self, value: u8) -> String { - value.to_string() - } - fn to_string_i16(&self, value: i16) -> String { - value.to_string() - } - fn to_string_u16(&self, value: u16) -> String { - value.to_string() - } - fn to_string_i32(&self, value: i32) -> String { - value.to_string() - } - fn to_string_u32(&self, value: u32) -> String { - value.to_string() - } - fn to_string_i64(&self, value: i64) -> String { - value.to_string() - } - fn to_string_u64(&self, value: u64) -> String { - value.to_string() - } - fn to_string_float(&self, value: f32) -> String { - value.to_string() - } - fn to_string_double(&self, value: f64) -> String { - value.to_string() - } - fn to_string_boolean(&self, value: bool) -> String { - value.to_string() - } - fn well_known_string(&self, value: String) -> String { - format!("uniffi 💚 {value}!") - } -} - -#[derive(Debug, Clone)] -struct Optionneur; -impl Optionneur { - fn new() -> Self { - Optionneur - } - fn sinon_string(&self, value: String) -> String { - value - } - fn sinon_null(&self, value: Option) -> Option { - value - } - fn sinon_boolean(&self, value: bool) -> bool { - value - } - fn sinon_sequence(&self, value: Vec) -> Vec { - value - } - - fn sinon_zero(&self, value: Option) -> Option { - value - } - - fn sinon_u8_dec(&self, value: u8) -> u8 { - value - } - fn sinon_i8_dec(&self, value: i8) -> i8 { - value - } - fn sinon_u16_dec(&self, value: u16) -> u16 { - value - } - fn sinon_i16_dec(&self, value: i16) -> i16 { - value - } - fn sinon_u32_dec(&self, value: u32) -> u32 { - value - } - fn sinon_i32_dec(&self, value: i32) -> i32 { - value - } - fn sinon_u64_dec(&self, value: u64) -> u64 { - value - } - fn sinon_i64_dec(&self, value: i64) -> i64 { - value - } - - fn sinon_u8_hex(&self, value: u8) -> u8 { - value - } - fn sinon_i8_hex(&self, value: i8) -> i8 { - value - } - fn sinon_u16_hex(&self, value: u16) -> u16 { - value - } - fn sinon_i16_hex(&self, value: i16) -> i16 { - value - } - fn sinon_u32_hex(&self, value: u32) -> u32 { - value - } - fn sinon_i32_hex(&self, value: i32) -> i32 { - value - } - fn sinon_u64_hex(&self, value: u64) -> u64 { - value - } - fn sinon_i64_hex(&self, value: i64) -> i64 { - value - } - - fn sinon_u32_oct(&self, value: u32) -> u32 { - value - } - - fn sinon_f32(&self, value: f32) -> f32 { - value - } - fn sinon_f64(&self, value: f64) -> f64 { - value - } - - fn sinon_enum(&self, value: Enumeration) -> Enumeration { - value - } -} - -pub struct OptionneurDictionnaire { - i8_var: i8, - u8_var: u8, - i16_var: i16, - u16_var: u16, - i32_var: i32, - u32_var: u32, - i64_var: i64, - u64_var: u64, - float_var: f32, - double_var: f64, - boolean_var: bool, - string_var: String, - list_var: Vec, - enumeration_var: Enumeration, - dictionnaire_var: Option, -} - -uniffi::include_scaffolding!("rondpoint"); diff --git a/third_party/rust/uniffi-example-rondpoint/src/rondpoint.udl b/third_party/rust/uniffi-example-rondpoint/src/rondpoint.udl deleted file mode 100644 index 7c8261d74e..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/src/rondpoint.udl +++ /dev/null @@ -1,146 +0,0 @@ -namespace rondpoint { - Dictionnaire copie_dictionnaire(Dictionnaire d); - Enumeration copie_enumeration(Enumeration e); - sequence copie_enumerations(sequence e); - record copie_carte(record c); - boolean switcheroo(boolean b); -}; - -dictionary minusculeMAJUSCULEDict { - boolean minusculeMAJUSCULEField; -}; - -enum minusculeMAJUSCULEEnum { - "minusculeMAJUSCULEVariant", -}; - -enum Enumeration { - "Un", - "Deux", - "Trois", -}; - -[Enum] -interface EnumerationAvecDonnees { - Zero(); - Un(u32 premier); - Deux(u32 premier, string second); -}; - -dictionary Dictionnaire { - Enumeration un; - boolean deux; - u8 petit_nombre; - u64 gros_nombre; -}; - -dictionary DictionnaireNombres { - u8 petit_nombre; - u16 court_nombre; - u32 nombre_simple; - u64 gros_nombre; -}; - -dictionary DictionnaireNombresSignes { - i8 petit_nombre; - i16 court_nombre; - i32 nombre_simple; - i64 gros_nombre; -}; - -interface Retourneur { - constructor(); - i8 identique_i8(i8 value); - u8 identique_u8(u8 value); - i16 identique_i16(i16 value); - u16 identique_u16(u16 value); - i32 identique_i32(i32 value); - u32 identique_u32(u32 value); - i64 identique_i64(i64 value); - u64 identique_u64(u64 value); - float identique_float(float value); - double identique_double(double value); - boolean identique_boolean(boolean value); - string identique_string(string value); - - DictionnaireNombresSignes identique_nombres_signes(DictionnaireNombresSignes value); - DictionnaireNombres identique_nombres(DictionnaireNombres value); - OptionneurDictionnaire identique_optionneur_dictionnaire(OptionneurDictionnaire value); -}; - -interface Stringifier { - constructor(); - string well_known_string(string value); - - string to_string_i8(i8 value); - string to_string_u8(u8 value); - string to_string_i16(i16 value); - string to_string_u16(u16 value); - string to_string_i32(i32 value); - string to_string_u32(u32 value); - string to_string_i64(i64 value); - string to_string_u64(u64 value); - string to_string_float(float value); - string to_string_double(double value); - string to_string_boolean(boolean value); -}; - -interface Optionneur { - constructor(); - boolean sinon_boolean(optional boolean value = false); - string sinon_string(optional string value = "default"); - - sequence sinon_sequence(optional sequence value = []); - - // Either sides of nullable. - string? sinon_null(optional string? value = null); - i32? sinon_zero(optional i32? value = 0); - - // Decimal integers, all 42. - u8 sinon_u8_dec(optional u8 value = 42); - i8 sinon_i8_dec(optional i8 value = -42); - u16 sinon_u16_dec(optional u16 value = 42); - i16 sinon_i16_dec(optional i16 value = 42); - u32 sinon_u32_dec(optional u32 value = 42); - i32 sinon_i32_dec(optional i32 value = 42); - u64 sinon_u64_dec(optional u64 value = 42); - i64 sinon_i64_dec(optional i64 value = 42); - - // Hexadecimal, including negatgives. - u8 sinon_u8_hex(optional u8 value = 0xff); - i8 sinon_i8_hex(optional i8 value = -0x7f); - u16 sinon_u16_hex(optional u16 value = 0xffff); - i16 sinon_i16_hex(optional i16 value = 0x7f); - u32 sinon_u32_hex(optional u32 value = 0xffffffff); - i32 sinon_i32_hex(optional i32 value = 0x7fffffff); - u64 sinon_u64_hex(optional u64 value = 0xffffffffffffffff); - i64 sinon_i64_hex(optional i64 value = 0x7fffffffffffffff); - - // Octal, FWIW. - u32 sinon_u32_oct(optional u32 value = 0755); - - // Floats - f32 sinon_f32(optional f32 value = 42.0); - f64 sinon_f64(optional f64 value = 42.1); - - // Enums, which we have to treat as strings in the UDL frontend. - Enumeration sinon_enum(optional Enumeration value = "Trois"); -}; - -dictionary OptionneurDictionnaire { - i8 i8_var = -8; - u8 u8_var = 8; - i16 i16_var = -0x10; - u16 u16_var = 0x10; - i32 i32_var = -32; - u32 u32_var = 32; - i64 i64_var = -64; - u64 u64_var = 64; - float float_var = 4.0; - double double_var = 8.0; - boolean boolean_var = true; - string string_var = "default"; - sequence list_var = []; - Enumeration enumeration_var = "DEUX"; - minusculeMAJUSCULEEnum? dictionnaire_var = null; -}; diff --git a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.kts b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.kts deleted file mode 100644 index cc5ddf2a86..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.kts +++ /dev/null @@ -1,250 +0,0 @@ -import uniffi.rondpoint.* - -val dico = Dictionnaire(Enumeration.DEUX, true, 0u, 123456789u) -val copyDico = copieDictionnaire(dico) -assert(dico == copyDico) - -assert(copieEnumeration(Enumeration.DEUX) == Enumeration.DEUX) -assert(copieEnumerations(listOf(Enumeration.UN, Enumeration.DEUX)) == listOf(Enumeration.UN, Enumeration.DEUX)) -assert(copieCarte(mapOf( - "0" to EnumerationAvecDonnees.Zero, - "1" to EnumerationAvecDonnees.Un(1u), - "2" to EnumerationAvecDonnees.Deux(2u, "deux") -)) == mapOf( - "0" to EnumerationAvecDonnees.Zero, - "1" to EnumerationAvecDonnees.Un(1u), - "2" to EnumerationAvecDonnees.Deux(2u, "deux") -)) - -val var1: EnumerationAvecDonnees = EnumerationAvecDonnees.Zero -val var2: EnumerationAvecDonnees = EnumerationAvecDonnees.Un(1u) -val var3: EnumerationAvecDonnees = EnumerationAvecDonnees.Un(2u) -assert(var1 != var2) -assert(var2 != var3) -assert(var1 == EnumerationAvecDonnees.Zero) -assert(var1 != EnumerationAvecDonnees.Un(1u)) -assert(var2 == EnumerationAvecDonnees.Un(1u)) - -assert(switcheroo(false)) - -// Test the roundtrip across the FFI. -// This shows that the values we send come back in exactly the same state as we sent them. -// i.e. it shows that lowering from kotlin and lifting into rust is symmetrical with -// lowering from rust and lifting into kotlin. -val rt = Retourneur() - -fun List.affirmAllerRetour(fn: (T) -> T) { - this.forEach { v -> - assert(fn.invoke(v) == v) { "$fn($v)" } - } -} - -// Booleans -listOf(true, false).affirmAllerRetour(rt::identiqueBoolean) - -// Bytes. -listOf(Byte.MIN_VALUE, Byte.MAX_VALUE).affirmAllerRetour(rt::identiqueI8) -listOf(0x00, 0xFF).map { it.toUByte() }.affirmAllerRetour(rt::identiqueU8) - -// Shorts -listOf(Short.MIN_VALUE, Short.MAX_VALUE).affirmAllerRetour(rt::identiqueI16) -listOf(0x0000, 0xFFFF).map { it.toUShort() }.affirmAllerRetour(rt::identiqueU16) - -// Ints -listOf(0, 1, -1, Int.MIN_VALUE, Int.MAX_VALUE).affirmAllerRetour(rt::identiqueI32) -listOf(0x00000000, 0xFFFFFFFF).map { it.toUInt() }.affirmAllerRetour(rt::identiqueU32) - -// Longs -listOf(0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE).affirmAllerRetour(rt::identiqueI64) -listOf(0u, 1u, ULong.MIN_VALUE, ULong.MAX_VALUE).affirmAllerRetour(rt::identiqueU64) - -// Floats -listOf(0.0F, 0.5F, 0.25F, Float.MIN_VALUE, Float.MAX_VALUE).affirmAllerRetour(rt::identiqueFloat) - -// Doubles -listOf(0.0, 1.0, Double.MIN_VALUE, Double.MAX_VALUE).affirmAllerRetour(rt::identiqueDouble) - -// Strings -listOf("", "abc", "null\u0000byte", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨‍👧‍👦multi-emoji, 🇨🇭a flag, a canal, panama") - .affirmAllerRetour(rt::identiqueString) - -listOf(-1, 0, 1).map { DictionnaireNombresSignes(it.toByte(), it.toShort(), it.toInt(), it.toLong()) } - .affirmAllerRetour(rt::identiqueNombresSignes) - -listOf(0, 1).map { DictionnaireNombres(it.toUByte(), it.toUShort(), it.toUInt(), it.toULong()) } - .affirmAllerRetour(rt::identiqueNombres) - - -rt.destroy() - -// Test one way across the FFI. -// -// We send one representation of a value to lib.rs, and it transforms it into another, a string. -// lib.rs sends the string back, and then we compare here in kotlin. -// -// This shows that the values are transformed into strings the same way in both kotlin and rust. -// i.e. if we assume that the string return works (we test this assumption elsewhere) -// we show that lowering from kotlin and lifting into rust has values that both kotlin and rust -// both stringify in the same way. i.e. the same values. -// -// If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust t here, -// and this convinces us that lowering/lifting from here to rust is correct, then -// together, we've shown the correctness of the return leg. -val st = Stringifier() - -typealias StringyEquals = (observed: String, expected: T) -> Boolean -fun List.affirmEnchaine( - fn: (T) -> String, - equals: StringyEquals = { obs, exp -> obs == exp.toString() } -) { - this.forEach { exp -> - val obs = fn.invoke(exp) - assert(equals(obs, exp)) { "$fn($exp): observed=$obs, expected=$exp" } - } -} - -// Test the efficacy of the string transport from rust. If this fails, but everything else -// works, then things are very weird. -val wellKnown = st.wellKnownString("kotlin") -assert("uniffi 💚 kotlin!" == wellKnown) { "wellKnownString 'uniffi 💚 kotlin!' == '$wellKnown'" } - -// Booleans -listOf(true, false).affirmEnchaine(st::toStringBoolean) - -// Bytes. -listOf(Byte.MIN_VALUE, Byte.MAX_VALUE).affirmEnchaine(st::toStringI8) -listOf(UByte.MIN_VALUE, UByte.MAX_VALUE).affirmEnchaine(st::toStringU8) - -// Shorts -listOf(Short.MIN_VALUE, Short.MAX_VALUE).affirmEnchaine(st::toStringI16) -listOf(UShort.MIN_VALUE, UShort.MAX_VALUE).affirmEnchaine(st::toStringU16) - -// Ints -listOf(0, 1, -1, Int.MIN_VALUE, Int.MAX_VALUE).affirmEnchaine(st::toStringI32) -listOf(0u, 1u, UInt.MIN_VALUE, UInt.MAX_VALUE).affirmEnchaine(st::toStringU32) - -// Longs -listOf(0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE).affirmEnchaine(st::toStringI64) -listOf(0u, 1u, ULong.MIN_VALUE, ULong.MAX_VALUE).affirmEnchaine(st::toStringU64) - -// Floats -// MIN_VALUE is 1.4E-45. Accuracy and formatting get weird at small sizes. -listOf(0.0F, 1.0F, -1.0F, Float.MIN_VALUE, Float.MAX_VALUE).affirmEnchaine(st::toStringFloat) { s, n -> s.toFloat() == n } - -// Doubles -// MIN_VALUE is 4.9E-324. Accuracy and formatting get weird at small sizes. -listOf(0.0, 1.0, -1.0, Double.MIN_VALUE, Double.MAX_VALUE).affirmEnchaine(st::toStringDouble) { s, n -> s.toDouble() == n } - -st.destroy() - -// Prove to ourselves that default arguments are being used. -// Step 1: call the methods without arguments, and check against the UDL. -val op = Optionneur() - -assert(op.sinonString() == "default") - -assert(op.sinonBoolean() == false) - -assert(op.sinonSequence() == listOf()) - -// optionals -assert(op.sinonNull() == null) -assert(op.sinonZero() == 0) - -// decimal integers -assert(op.sinonI8Dec() == (-42).toByte()) -assert(op.sinonU8Dec() == 42.toUByte()) -assert(op.sinonI16Dec() == 42.toShort()) -assert(op.sinonU16Dec() == 42.toUShort()) -assert(op.sinonI32Dec() == 42) -assert(op.sinonU32Dec() == 42.toUInt()) -assert(op.sinonI64Dec() == 42L) -assert(op.sinonU64Dec() == 42uL) - -// hexadecimal integers -assert(op.sinonI8Hex() == (-0x7f).toByte()) -assert(op.sinonU8Hex() == 0xff.toUByte()) -assert(op.sinonI16Hex() == 0x7f.toShort()) -assert(op.sinonU16Hex() == 0xffff.toUShort()) -assert(op.sinonI32Hex() == 0x7fffffff) -assert(op.sinonU32Hex() == 0xffffffff.toUInt()) -assert(op.sinonI64Hex() == 0x7fffffffffffffffL) -assert(op.sinonU64Hex() == 0xffffffffffffffffuL) - -// octal integers -assert(op.sinonU32Oct() == 493u) // 0o755 - -// floats -assert(op.sinonF32() == 42.0f) -assert(op.sinonF64() == 42.1) - -// enums -assert(op.sinonEnum() == Enumeration.TROIS) - -// Step 2. Convince ourselves that if we pass something else, then that changes the output. -// We have shown something coming out of the sinon methods, but without eyeballing the Rust -// we can't be sure that the arguments will change the return value. -listOf("foo", "bar").affirmAllerRetour(op::sinonString) -listOf(true, false).affirmAllerRetour(op::sinonBoolean) -listOf(listOf("a", "b"), listOf()).affirmAllerRetour(op::sinonSequence) - -// optionals -listOf("0", "1").affirmAllerRetour(op::sinonNull) -listOf(0, 1).affirmAllerRetour(op::sinonZero) - -// integers -listOf(0, 1).map { it.toUByte() }.affirmAllerRetour(op::sinonU8Dec) -listOf(0, 1).map { it.toByte() }.affirmAllerRetour(op::sinonI8Dec) -listOf(0, 1).map { it.toUShort() }.affirmAllerRetour(op::sinonU16Dec) -listOf(0, 1).map { it.toShort() }.affirmAllerRetour(op::sinonI16Dec) -listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Dec) -listOf(0, 1).map { it.toInt() }.affirmAllerRetour(op::sinonI32Dec) -listOf(0, 1).map { it.toULong() }.affirmAllerRetour(op::sinonU64Dec) -listOf(0, 1).map { it.toLong() }.affirmAllerRetour(op::sinonI64Dec) - -listOf(0, 1).map { it.toUByte() }.affirmAllerRetour(op::sinonU8Hex) -listOf(0, 1).map { it.toByte() }.affirmAllerRetour(op::sinonI8Hex) -listOf(0, 1).map { it.toUShort() }.affirmAllerRetour(op::sinonU16Hex) -listOf(0, 1).map { it.toShort() }.affirmAllerRetour(op::sinonI16Hex) -listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Hex) -listOf(0, 1).map { it.toInt() }.affirmAllerRetour(op::sinonI32Hex) -listOf(0, 1).map { it.toULong() }.affirmAllerRetour(op::sinonU64Hex) -listOf(0, 1).map { it.toLong() }.affirmAllerRetour(op::sinonI64Hex) - -listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Oct) - -// floats -listOf(0.0f, 1.0f).affirmAllerRetour(op::sinonF32) -listOf(0.0, 1.0).affirmAllerRetour(op::sinonF64) - -// enums -Enumeration.values().toList().affirmAllerRetour(op::sinonEnum) - -op.destroy() - -// Testing defaulting properties in record types. -val defaultes = OptionneurDictionnaire() -val explicites = OptionneurDictionnaire( - i8Var = -8, - u8Var = 8u, - i16Var = -16, - u16Var = 0x10u, - i32Var = -32, - u32Var = 32u, - i64Var = -64L, - u64Var = 64uL, - floatVar = 4.0f, - doubleVar = 8.0, - booleanVar = true, - stringVar = "default", - listVar = listOf(), - enumerationVar = Enumeration.DEUX, - dictionnaireVar = null -) -assert(defaultes == explicites) - -// …and makes sure they travel across and back the FFI. -val rt2 = Retourneur() -listOf(defaultes).affirmAllerRetour(rt2::identiqueOptionneurDictionnaire) - -rt2.destroy() diff --git a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py deleted file mode 100644 index 0b47c0fa5a..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py +++ /dev/null @@ -1,146 +0,0 @@ -import sys -import ctypes -from rondpoint import * - -dico = Dictionnaire(un=Enumeration.DEUX, deux=True, petit_nombre=0, gros_nombre=123456789) -copyDico = copie_dictionnaire(dico) -assert dico == copyDico - -assert copie_enumeration(Enumeration.DEUX) == Enumeration.DEUX -assert copie_enumerations([Enumeration.UN, Enumeration.DEUX]) == [Enumeration.UN, Enumeration.DEUX] -assert copie_carte({ - "0": EnumerationAvecDonnees.ZERO(), - "1": EnumerationAvecDonnees.UN(1), - "2": EnumerationAvecDonnees.DEUX(2, "deux"), -}) == { - "0": EnumerationAvecDonnees.ZERO(), - "1": EnumerationAvecDonnees.UN(1), - "2": EnumerationAvecDonnees.DEUX(2, "deux"), -} - -assert switcheroo(False) is True - -assert EnumerationAvecDonnees.ZERO() != EnumerationAvecDonnees.UN(1) -assert EnumerationAvecDonnees.UN(1) == EnumerationAvecDonnees.UN(1) -assert EnumerationAvecDonnees.UN(1) != EnumerationAvecDonnees.UN(2) - -# Test the roundtrip across the FFI. -# This shows that the values we send come back in exactly the same state as we sent them. -# i.e. it shows that lowering from python and lifting into rust is symmetrical with -# lowering from rust and lifting into python. -rt = Retourneur() - -def affirmAllerRetour(vals, identique): - for v in vals: - id_v = identique(v) - assert id_v == v, f"Round-trip failure: {v} => {id_v}" - -MIN_I8 = -1 * 2**7 -MAX_I8 = 2**7 - 1 -MIN_I16 = -1 * 2**15 -MAX_I16 = 2**15 - 1 -MIN_I32 = -1 * 2**31 -MAX_I32 = 2**31 - 1 -MIN_I64 = -1 * 2**31 -MAX_I64 = 2**31 - 1 - -# Python floats are always doubles, so won't round-trip through f32 correctly. -# This truncates them appropriately. -F32_ONE_THIRD = ctypes.c_float(1.0 / 3).value - -# Booleans -affirmAllerRetour([True, False], rt.identique_boolean) - -# Bytes. -affirmAllerRetour([MIN_I8, -1, 0, 1, MAX_I8], rt.identique_i8) -affirmAllerRetour([0x00, 0x12, 0xFF], rt.identique_u8) - -# Shorts -affirmAllerRetour([MIN_I16, -1, 0, 1, MAX_I16], rt.identique_i16) -affirmAllerRetour([0x0000, 0x1234, 0xFFFF], rt.identique_u16) - -# Ints -affirmAllerRetour([MIN_I32, -1, 0, 1, MAX_I32], rt.identique_i32) -affirmAllerRetour([0x00000000, 0x12345678, 0xFFFFFFFF], rt.identique_u32) - -# Longs -affirmAllerRetour([MIN_I64, -1, 0, 1, MAX_I64], rt.identique_i64) -affirmAllerRetour([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], rt.identique_u64) - -# Floats -affirmAllerRetour([0.0, 0.5, 0.25, 1.0, F32_ONE_THIRD], rt.identique_float) - -# Doubles -affirmAllerRetour( - [0.0, 0.5, 0.25, 1.0, 1.0 / 3, sys.float_info.max, sys.float_info.min], - rt.identique_double -) - -# Strings -affirmAllerRetour( - ["", "abc", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨‍👧‍👦multi-emoji, 🇨🇭a flag, a canal, panama"], - rt.identique_string -) - -# Test one way across the FFI. -# -# We send one representation of a value to lib.rs, and it transforms it into another, a string. -# lib.rs sends the string back, and then we compare here in python. -# -# This shows that the values are transformed into strings the same way in both python and rust. -# i.e. if we assume that the string return works (we test this assumption elsewhere) -# we show that lowering from python and lifting into rust has values that both python and rust -# both stringify in the same way. i.e. the same values. -# -# If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust to here, -# and this convinces us that lowering/lifting from here to rust is correct, then -# together, we've shown the correctness of the return leg. -st = Stringifier() - -def affirmEnchaine(vals, toString, rustyStringify=lambda v: str(v).lower()): - for v in vals: - str_v = toString(v) - assert rustyStringify(v) == str_v, f"String compare error {v} => {str_v}" - -# Test the efficacy of the string transport from rust. If this fails, but everything else -# works, then things are very weird. -wellKnown = st.well_known_string("python") -assert "uniffi 💚 python!" == wellKnown - -# Booleans -affirmEnchaine([True, False], st.to_string_boolean) - -# Bytes. -affirmEnchaine([MIN_I8, -1, 0, 1, MAX_I8], st.to_string_i8) -affirmEnchaine([0x00, 0x12, 0xFF], st.to_string_u8) - -# Shorts -affirmEnchaine([MIN_I16, -1, 0, 1, MAX_I16], st.to_string_i16) -affirmEnchaine([0x0000, 0x1234, 0xFFFF], st.to_string_u16) - -# Ints -affirmEnchaine([MIN_I32, -1, 0, 1, MAX_I32], st.to_string_i32) -affirmEnchaine([0x00000000, 0x12345678, 0xFFFFFFFF], st.to_string_u32) - -# Longs -affirmEnchaine([MIN_I64, -1, 0, 1, MAX_I64], st.to_string_i64) -affirmEnchaine([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], st.to_string_u64) - -# Floats -def rustyFloatToStr(v): - """Stringify a float in the same way that rust seems to.""" - # Rust doesn't include the decimal part of whole enumber floats when stringifying. - if int(v) == v: - return str(int(v)) - return str(v) - -affirmEnchaine([0.0, 0.5, 0.25, 1.0], st.to_string_float, rustyFloatToStr) -assert st.to_string_float(F32_ONE_THIRD) == "0.33333334" # annoyingly different string repr - -# Doubles -# TODO: float_info.max/float_info.min don't stringify-roundtrip properly yet, TBD. -affirmEnchaine( - [0.0, 0.5, 0.25, 1.0, 1.0 / 3], - st.to_string_double, - rustyFloatToStr, -) diff --git a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb deleted file mode 100644 index faa4062019..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb +++ /dev/null @@ -1,147 +0,0 @@ -# frozen_string_literal: true - -require 'test/unit' -require 'rondpoint' - -include Test::Unit::Assertions -include Rondpoint - -dico = Dictionnaire.new( - un: Enumeration::DEUX, - deux: true, - petit_nombre: 0, - gros_nombre: 123_456_789 -) - -assert_equal dico, Rondpoint.copie_dictionnaire(dico) - -assert_equal Rondpoint.copie_enumeration(Enumeration::DEUX), Enumeration::DEUX - -assert_equal Rondpoint.copie_enumerations([ - Enumeration::UN, - Enumeration::DEUX - ]), [Enumeration::UN, Enumeration::DEUX] - -assert_equal Rondpoint.copie_carte({ - '0' => EnumerationAvecDonnees::ZERO.new, - '1' => EnumerationAvecDonnees::UN.new(1), - '2' => EnumerationAvecDonnees::DEUX.new(2, 'deux') - }), { - '0' => EnumerationAvecDonnees::ZERO.new, - '1' => EnumerationAvecDonnees::UN.new(1), - '2' => EnumerationAvecDonnees::DEUX.new(2, 'deux') - } - -assert Rondpoint.switcheroo(false) - -assert_not_equal EnumerationAvecDonnees::ZERO.new, EnumerationAvecDonnees::UN.new(1) -assert_equal EnumerationAvecDonnees::UN.new(1), EnumerationAvecDonnees::UN.new(1) -assert_not_equal EnumerationAvecDonnees::UN.new(1), EnumerationAvecDonnees::UN.new(2) - -# Test the roundtrip across the FFI. -# This shows that the values we send come back in exactly the same state as we sent them. -# i.e. it shows that lowering from ruby and lifting into rust is symmetrical with -# lowering from rust and lifting into ruby. -RT = Retourneur.new - -def affirm_aller_retour(vals, fn_name) - vals.each do |v| - id_v = RT.public_send fn_name, v - - assert_equal id_v, v, "Round-trip failure: #{v} => #{id_v}" - end -end - -MIN_I8 = -1 * 2**7 -MAX_I8 = 2**7 - 1 -MIN_I16 = -1 * 2**15 -MAX_I16 = 2**15 - 1 -MIN_I32 = -1 * 2**31 -MAX_I32 = 2**31 - 1 -MIN_I64 = -1 * 2**31 -MAX_I64 = 2**31 - 1 - -# Ruby floats are always doubles, so won't round-trip through f32 correctly. -# This truncates them appropriately. -F32_ONE_THIRD = [1.0 / 3].pack('f').unpack('f')[0] - -# Booleans -affirm_aller_retour([true, false], :identique_boolean) - -# Bytes. -affirm_aller_retour([MIN_I8, -1, 0, 1, MAX_I8], :identique_i8) -affirm_aller_retour([0x00, 0x12, 0xFF], :identique_u8) - -# Shorts -affirm_aller_retour([MIN_I16, -1, 0, 1, MAX_I16], :identique_i16) -affirm_aller_retour([0x0000, 0x1234, 0xFFFF], :identique_u16) - -# Ints -affirm_aller_retour([MIN_I32, -1, 0, 1, MAX_I32], :identique_i32) -affirm_aller_retour([0x00000000, 0x12345678, 0xFFFFFFFF], :identique_u32) - -# Longs -affirm_aller_retour([MIN_I64, -1, 0, 1, MAX_I64], :identique_i64) -affirm_aller_retour([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], :identique_u64) - -# Floats -affirm_aller_retour([0.0, 0.5, 0.25, 1.0, F32_ONE_THIRD], :identique_float) - -# Doubles -affirm_aller_retour( - [0.0, 0.5, 0.25, 1.0, 1.0 / 3, Float::MAX, Float::MIN], - :identique_double -) - -# Strings -affirm_aller_retour( - ['', 'abc', 'été', 'ښي لاس ته لوستلو لوستل', - '😻emoji 👨‍👧‍👦multi-emoji, 🇨🇭a flag, a canal, panama'], - :identique_string -) - -# Test one way across the FFI. -# -# We send one representation of a value to lib.rs, and it transforms it into another, a string. -# lib.rs sends the string back, and then we compare here in ruby. -# -# This shows that the values are transformed into strings the same way in both ruby and rust. -# i.e. if we assume that the string return works (we test this assumption elsewhere) -# we show that lowering from ruby and lifting into rust has values that both ruby and rust -# both stringify in the same way. i.e. the same values. -# -# If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust to here, -# and this convinces us that lowering/lifting from here to rust is correct, then -# together, we've shown the correctness of the return leg. -ST = Stringifier.new - -def affirm_enchaine(vals, fn_name) - vals.each do |v| - str_v = ST.public_send fn_name, v - - assert_equal v.to_s, str_v, "String compare error #{v} => #{str_v}" - end -end - -# Test the efficacy of the string transport from rust. If this fails, but everything else -# works, then things are very weird. -assert_equal ST.well_known_string('ruby'), 'uniffi 💚 ruby!' - -# Booleans -affirm_enchaine([true, false], :to_string_boolean) - -# Bytes. -affirm_enchaine([MIN_I8, -1, 0, 1, MAX_I8], :to_string_i8) -affirm_enchaine([0x00, 0x12, 0xFF], :to_string_u8) - -# Shorts -affirm_enchaine([MIN_I16, -1, 0, 1, MAX_I16], :to_string_i16) -affirm_enchaine([0x0000, 0x1234, 0xFFFF], :to_string_u16) - -# Ints -affirm_enchaine([MIN_I32, -1, 0, 1, MAX_I32], :to_string_i32) -affirm_enchaine([0x00000000, 0x12345678, 0xFFFFFFFF], :to_string_u32) - -# Longs -affirm_enchaine([MIN_I64, -1, 0, 1, MAX_I64], :to_string_i64) -affirm_enchaine([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], :to_string_u64) diff --git a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.swift b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.swift deleted file mode 100644 index d9f47058ed..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.swift +++ /dev/null @@ -1,232 +0,0 @@ -import rondpoint - -let dico = Dictionnaire(un: .deux, deux: false, petitNombre: 0, grosNombre: 123456789) -let copyDico = copieDictionnaire(d: dico) -assert(dico == copyDico) - -assert(copieEnumeration(e: .deux) == .deux) -assert(copieEnumerations(e: [.un, .deux]) == [.un, .deux]) -assert(copieCarte(c: - ["0": .zero, - "1": .un(premier: 1), - "2": .deux(premier: 2, second: "deux") -]) == [ - "0": .zero, - "1": .un(premier: 1), - "2": .deux(premier: 2, second: "deux") -]) - -assert(EnumerationAvecDonnees.zero != EnumerationAvecDonnees.un(premier: 1)) -assert(EnumerationAvecDonnees.un(premier: 1) == EnumerationAvecDonnees.un(premier: 1)) -assert(EnumerationAvecDonnees.un(premier: 1) != EnumerationAvecDonnees.un(premier: 2)) - - -assert(switcheroo(b: false)) - -// Test the roundtrip across the FFI. -// This shows that the values we send come back in exactly the same state as we sent them. -// i.e. it shows that lowering from swift and lifting into rust is symmetrical with -// lowering from rust and lifting into swift. -let rt = Retourneur() - -// Booleans -[true, false].affirmAllerRetour(rt.identiqueBoolean) - -// Bytes. -[.min, .max].affirmAllerRetour(rt.identiqueI8) -[0x00, 0xFF].map { $0 as UInt8 }.affirmAllerRetour(rt.identiqueU8) - -// Shorts -[.min, .max].affirmAllerRetour(rt.identiqueI16) -[0x0000, 0xFFFF].map { $0 as UInt16 }.affirmAllerRetour(rt.identiqueU16) - -// Ints -[0, 1, -1, .min, .max].affirmAllerRetour(rt.identiqueI32) -[0x00000000, 0xFFFFFFFF].map { $0 as UInt32 }.affirmAllerRetour(rt.identiqueU32) - -// Longs -[.zero, 1, -1, .min, .max].affirmAllerRetour(rt.identiqueI64) -[.zero, 1, .min, .max].affirmAllerRetour(rt.identiqueU64) - -// Floats -[.zero, 1, 0.25, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmAllerRetour(rt.identiqueFloat) - -// Doubles -[0.0, 1.0, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmAllerRetour(rt.identiqueDouble) - -// Strings -["", "abc", "null\0byte", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨‍👧‍👦multi-emoji, 🇨🇭a flag, a canal, panama"] - .affirmAllerRetour(rt.identiqueString) - -// Test one way across the FFI. -// -// We send one representation of a value to lib.rs, and it transforms it into another, a string. -// lib.rs sends the string back, and then we compare here in swift. -// -// This shows that the values are transformed into strings the same way in both swift and rust. -// i.e. if we assume that the string return works (we test this assumption elsewhere) -// we show that lowering from swift and lifting into rust has values that both swift and rust -// both stringify in the same way. i.e. the same values. -// -// If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust t here, -// and this convinces us that lowering/lifting from here to rust is correct, then -// together, we've shown the correctness of the return leg. -let st = Stringifier() - -// Test the effigacy of the string transport from rust. If this fails, but everything else -// works, then things are very weird. -let wellKnown = st.wellKnownString(value: "swift") -assert("uniffi 💚 swift!" == wellKnown, "wellKnownString 'uniffi 💚 swift!' == '\(wellKnown)'") - -// Booleans -[true, false].affirmEnchaine(st.toStringBoolean) - -// Bytes. -[.min, .max].affirmEnchaine(st.toStringI8) -[.min, .max].affirmEnchaine(st.toStringU8) - -// Shorts -[.min, .max].affirmEnchaine(st.toStringI16) -[.min, .max].affirmEnchaine(st.toStringU16) - -// Ints -[0, 1, -1, .min, .max].affirmEnchaine(st.toStringI32) -[0, 1, .min, .max].affirmEnchaine(st.toStringU32) - -// Longs -[.zero, 1, -1, .min, .max].affirmEnchaine(st.toStringI64) -[.zero, 1, .min, .max].affirmEnchaine(st.toStringU64) - -// Floats -[.zero, 1, -1, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmEnchaine(st.toStringFloat) { Float.init($0) == $1 } - -// Doubles -[.zero, 1, -1, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmEnchaine(st.toStringDouble) { Double.init($0) == $1 } - -// Some extension functions for testing the results of roundtripping and stringifying -extension Array where Element: Equatable { - static func defaultEquals(_ observed: String, expected: Element) -> Bool { - let exp = "\(expected)" - return observed == exp - } - - func affirmEnchaine(_ fn: (Element) -> String, equals: (String, Element) -> Bool = defaultEquals) { - self.forEach { v in - let obs = fn(v) - assert(equals(obs, v), "toString_\(type(of:v))(\(v)): observed=\(obs), expected=\(v)") - } - } - - func affirmAllerRetour(_ fn: (Element) -> Element) { - self.forEach { v in - assert(fn(v) == v, "identique_\(type(of:v))(\(v))") - } - } -} - -// Prove to ourselves that default arguments are being used. -// Step 1: call the methods without arguments, and check against the UDL. -let op = Optionneur() - -assert(op.sinonString() == "default") - -assert(op.sinonBoolean() == false) - -assert(op.sinonSequence() == []) - -// optionals -assert(op.sinonNull() == nil) -assert(op.sinonZero() == 0) - -// decimal integers -assert(op.sinonU8Dec() == UInt8(42)) -assert(op.sinonI8Dec() == Int8(-42)) -assert(op.sinonU16Dec() == UInt16(42)) -assert(op.sinonI16Dec() == Int16(42)) -assert(op.sinonU32Dec() == UInt32(42)) -assert(op.sinonI32Dec() == Int32(42)) -assert(op.sinonU64Dec() == UInt64(42)) -assert(op.sinonI64Dec() == Int64(42)) - -// hexadecimal integers -assert(op.sinonU8Hex() == UInt8(0xff)) -assert(op.sinonI8Hex() == Int8(-0x7f)) -assert(op.sinonU16Hex() == UInt16(0xffff)) -assert(op.sinonI16Hex() == Int16(0x7f)) -assert(op.sinonU32Hex() == UInt32(0xffffffff)) -assert(op.sinonI32Hex() == Int32(0x7fffffff)) -assert(op.sinonU64Hex() == UInt64(0xffffffffffffffff)) -assert(op.sinonI64Hex() == Int64(0x7fffffffffffffff)) - -// octal integers -assert(op.sinonU32Oct() == UInt32(0o755)) - -// floats -assert(op.sinonF32() == 42.0) -assert(op.sinonF64() == Double(42.1)) - -// enums -assert(op.sinonEnum() == .trois) - -// Step 2. Convince ourselves that if we pass something else, then that changes the output. -// We have shown something coming out of the sinon methods, but without eyeballing the Rust -// we can't be sure that the arguments will change the return value. -["foo", "bar"].affirmAllerRetour(op.sinonString) -[true, false].affirmAllerRetour(op.sinonBoolean) -[["a", "b"], []].affirmAllerRetour(op.sinonSequence) - -// optionals -["0", "1"].affirmAllerRetour(op.sinonNull) -[0, 1].affirmAllerRetour(op.sinonZero) - -// integers -[0, 1].affirmAllerRetour(op.sinonU8Dec) -[0, 1].affirmAllerRetour(op.sinonI8Dec) -[0, 1].affirmAllerRetour(op.sinonU16Dec) -[0, 1].affirmAllerRetour(op.sinonI16Dec) -[0, 1].affirmAllerRetour(op.sinonU32Dec) -[0, 1].affirmAllerRetour(op.sinonI32Dec) -[0, 1].affirmAllerRetour(op.sinonU64Dec) -[0, 1].affirmAllerRetour(op.sinonI64Dec) - -[0, 1].affirmAllerRetour(op.sinonU8Hex) -[0, 1].affirmAllerRetour(op.sinonI8Hex) -[0, 1].affirmAllerRetour(op.sinonU16Hex) -[0, 1].affirmAllerRetour(op.sinonI16Hex) -[0, 1].affirmAllerRetour(op.sinonU32Hex) -[0, 1].affirmAllerRetour(op.sinonI32Hex) -[0, 1].affirmAllerRetour(op.sinonU64Hex) -[0, 1].affirmAllerRetour(op.sinonI64Hex) - -[0, 1].affirmAllerRetour(op.sinonU32Oct) - -// floats -[0.0, 1.0].affirmAllerRetour(op.sinonF32) -[0.0, 1.0].affirmAllerRetour(op.sinonF64) - -// enums -[.un, .deux, .trois].affirmAllerRetour(op.sinonEnum) - -// Testing defaulting properties in record types. -let defaultes = OptionneurDictionnaire() -let explicites = OptionneurDictionnaire( - i8Var: Int8(-8), - u8Var: UInt8(8), - i16Var: Int16(-16), - u16Var: UInt16(0x10), - i32Var: -32, - u32Var: UInt32(32), - i64Var: Int64(-64), - u64Var: UInt64(64), - floatVar: Float(4.0), - doubleVar: Double(8.0), - booleanVar: true, - stringVar: "default", - listVar: [], - enumerationVar: .deux, - dictionnaireVar: nil -) - -// …and makes sure they travel across and back the FFI. -assert(defaultes == explicites) -[defaultes].affirmAllerRetour(rt.identiqueOptionneurDictionnaire) diff --git a/third_party/rust/uniffi-example-rondpoint/tests/test_generated_bindings.rs b/third_party/rust/uniffi-example-rondpoint/tests/test_generated_bindings.rs deleted file mode 100644 index d337374334..0000000000 --- a/third_party/rust/uniffi-example-rondpoint/tests/test_generated_bindings.rs +++ /dev/null @@ -1,6 +0,0 @@ -uniffi::build_foreign_language_testcases!( - "tests/bindings/test_rondpoint.kts", - "tests/bindings/test_rondpoint.swift", - "tests/bindings/test_rondpoint.py", - "tests/bindings/test_rondpoint.rb", -); diff --git a/third_party/rust/uniffi-example-sprites/.cargo-checksum.json b/third_party/rust/uniffi-example-sprites/.cargo-checksum.json deleted file mode 100644 index 8a890fb65c..0000000000 --- a/third_party/rust/uniffi-example-sprites/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"94385b28fdc7e33b7019fada486124c027d29b3d2b11b57e8d488658386f7974","build.rs":"7e9d92d7c8fc17b359a29117b137ffc4d32f6c10b450d03e30a396339d8c9099","src/lib.rs":"d7984c0c10011b1bd939bce71dae7437ebb9090583b5d1b1cc133c2e5f60ab66","src/sprites.udl":"bfd35f04ba0549301189dfb8fc45b0f39bad00956c324f33be0e845fb7ff78aa","tests/bindings/test_sprites.kts":"06ed115325f37ce59ed6f33e2d651cd2aa352fddcc644580f62a6da6ca075844","tests/bindings/test_sprites.py":"f976f2be7ab8b88e8b84def760a849c0d98f4c7b481f054f92b566325d78d52d","tests/bindings/test_sprites.rb":"009d545bb7167b7218211430cfaeeb143cc30617eedcf3e51baafe752ad43241","tests/bindings/test_sprites.swift":"b2c0a6f4d5edfd7de7c2ba77b838865ffda153a6f364f273456175192d3e6e00","tests/test_generated_bindings.rs":"9a22d693c97fc6d90031cc60f61ece1d9279165ad6a92c9fe937448e126e8de6"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-sprites/Cargo.toml b/third_party/rust/uniffi-example-sprites/Cargo.toml deleted file mode 100644 index c6dc9d1f4b..0000000000 --- a/third_party/rust/uniffi-example-sprites/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "uniffi-example-sprites" -version = "0.22.0" -authors = ["Firefox Sync Team "] -publish = false -license = "MPL-2.0" - -[lib] -name = "uniffi_sprites" -crate-type = [ - "lib", - "cdylib", -] - -[dependencies.uniffi] -version = "0.27" -path = "../../uniffi" - -[dev-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["bindgen-tests"] - -[build-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["build"] diff --git a/third_party/rust/uniffi-example-sprites/build.rs b/third_party/rust/uniffi-example-sprites/build.rs deleted file mode 100644 index 26ac3085b8..0000000000 --- a/third_party/rust/uniffi-example-sprites/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -fn main() { - uniffi::generate_scaffolding("src/sprites.udl").unwrap(); -} diff --git a/third_party/rust/uniffi-example-sprites/src/lib.rs b/third_party/rust/uniffi-example-sprites/src/lib.rs deleted file mode 100644 index d3cc11e408..0000000000 --- a/third_party/rust/uniffi-example-sprites/src/lib.rs +++ /dev/null @@ -1,65 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use std::sync::RwLock; - -// A point in two-dimensional space. -#[derive(Debug, Clone)] -pub struct Point { - x: f64, - y: f64, -} - -// A magnitude and direction in two-dimensional space. -// For simplicity we represent this as a point relative to the origin. -#[derive(Debug, Clone)] -pub struct Vector { - dx: f64, - dy: f64, -} - -// Move from the given Point, according to the given Vector. -pub fn translate(p: &Point, v: Vector) -> Point { - Point { - x: p.x + v.dx, - y: p.y + v.dy, - } -} - -// An entity in our imaginary world, which occupies a position in space -// and which can move about over time. -#[derive(Debug)] -pub struct Sprite { - // We must use interior mutability for managing mutable state, hence the `RwLock`. - current_position: RwLock, -} - -impl Sprite { - fn new(initial_position: Option) -> Sprite { - Sprite { - current_position: RwLock::new(initial_position.unwrap_or(Point { x: 0.0, y: 0.0 })), - } - } - - fn new_relative_to(reference: Point, direction: Vector) -> Sprite { - Sprite { - current_position: RwLock::new(translate(&reference, direction)), - } - } - - fn get_position(&self) -> Point { - self.current_position.read().unwrap().clone() - } - - fn move_to(&self, position: Point) { - *self.current_position.write().unwrap() = position; - } - - fn move_by(&self, direction: Vector) { - let mut current_position = self.current_position.write().unwrap(); - *current_position = translate(¤t_position, direction) - } -} - -uniffi::include_scaffolding!("sprites"); diff --git a/third_party/rust/uniffi-example-sprites/src/sprites.udl b/third_party/rust/uniffi-example-sprites/src/sprites.udl deleted file mode 100644 index 6781c6cee5..0000000000 --- a/third_party/rust/uniffi-example-sprites/src/sprites.udl +++ /dev/null @@ -1,22 +0,0 @@ - -namespace sprites { - Point translate([ByRef] Point position, Vector direction); -}; - -dictionary Point { - double x; - double y; -}; - -dictionary Vector { - double dx; - double dy; -}; - -interface Sprite { - constructor(Point? initial_position); - [Name=new_relative_to] constructor(Point reference, Vector direction); - Point get_position(); - void move_to(Point position); - void move_by(Vector direction); -}; diff --git a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.kts b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.kts deleted file mode 100644 index 42451f28dd..0000000000 --- a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.kts +++ /dev/null @@ -1,25 +0,0 @@ -import uniffi.sprites.*; - -val sempty = Sprite(null) -assert( sempty.getPosition() == Point(0.0, 0.0) ) - -val s = Sprite(Point(0.0, 1.0)) -assert( s.getPosition() == Point(0.0, 1.0) ) - -s.moveTo(Point(1.0, 2.0)) -assert( s.getPosition() == Point(1.0, 2.0) ) - -s.moveBy(Vector(-4.0, 2.0)) -assert( s.getPosition() == Point(-3.0, 4.0) ) - -s.destroy() -try { - s.moveBy(Vector(0.0, 0.0)) - assert(false) { "Should not be able to call anything after `destroy`" } -} catch(e: IllegalStateException) { - assert(true) -} - -val srel = Sprite.newRelativeTo(Point(0.0, 1.0), Vector(1.0, 1.5)) -assert( srel.getPosition() == Point(1.0, 2.5) ) - diff --git a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py deleted file mode 100644 index d04742e076..0000000000 --- a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py +++ /dev/null @@ -1,17 +0,0 @@ -from sprites import * - -sempty = Sprite(None) -assert sempty.get_position() == Point(x=0, y=0) - -s = Sprite(Point(x=0, y=1)) -assert s.get_position() == Point(x=0, y=1) - -s.move_to(Point(x=1, y=2)) -assert s.get_position() == Point(x=1, y=2) - -s.move_by(Vector(dx=-4, dy=2)) -assert s.get_position() == Point(x=-3, y=4) - -srel = Sprite.new_relative_to(Point(x=0, y=1), Vector(dx=1, dy=1.5)) -assert srel.get_position() == Point(x=1, y=2.5) - diff --git a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb deleted file mode 100644 index fa73043979..0000000000 --- a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'test/unit' -require 'sprites' - -include Test::Unit::Assertions -include Sprites - -sempty = Sprite.new(nil) -assert_equal sempty.get_position, Point.new(x: 0, y: 0) - -s = Sprite.new(Point.new(x: 0, y: 1)) -assert_equal s.get_position, Point.new(x: 0, y: 1) - -s.move_to(Point.new(x: 1, y: 2)) -assert_equal s.get_position, Point.new(x: 1, y: 2) - -s.move_by(Vector.new(dx: -4, dy: 2)) -assert_equal s.get_position, Point.new(x: -3, y: 4) - -srel = Sprite.new_relative_to(Point.new(x: 0, y: 1), Vector.new(dx: 1, dy: 1.5)) -assert_equal srel.get_position, Point.new(x: 1, y: 2.5) diff --git a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.swift b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.swift deleted file mode 100644 index d5428ac679..0000000000 --- a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.swift +++ /dev/null @@ -1,16 +0,0 @@ -import sprites - -let sempty = Sprite(initialPosition: nil) -assert( sempty.getPosition() == Point(x: 0, y: 0)) - -let s = Sprite(initialPosition: Point(x: 0, y: 1)) -assert( s.getPosition() == Point(x: 0, y: 1)) - -s.moveTo(position: Point(x: 1.0, y: 2.0)) -assert( s.getPosition() == Point(x: 1, y: 2)) - -s.moveBy(direction: Vector(dx: -4, dy: 2)) -assert( s.getPosition() == Point(x: -3, y: 4)) - -let srel = Sprite.newRelativeTo(reference: Point(x: 0.0, y: 1.0), direction: Vector(dx: 1, dy: 1.5)) -assert( srel.getPosition() == Point(x: 1.0, y: 2.5) ) diff --git a/third_party/rust/uniffi-example-sprites/tests/test_generated_bindings.rs b/third_party/rust/uniffi-example-sprites/tests/test_generated_bindings.rs deleted file mode 100644 index 00dd779d68..0000000000 --- a/third_party/rust/uniffi-example-sprites/tests/test_generated_bindings.rs +++ /dev/null @@ -1,6 +0,0 @@ -uniffi::build_foreign_language_testcases!( - "tests/bindings/test_sprites.py", - "tests/bindings/test_sprites.rb", - "tests/bindings/test_sprites.kts", - "tests/bindings/test_sprites.swift", -); diff --git a/third_party/rust/uniffi-example-todolist/.cargo-checksum.json b/third_party/rust/uniffi-example-todolist/.cargo-checksum.json deleted file mode 100644 index 6b3a53fc5e..0000000000 --- a/third_party/rust/uniffi-example-todolist/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"9b182bf2d363240fe1f7b41c73da4bde96d87562812885e4f3175cb6b92ea56b","build.rs":"709d073560a66876d2b975f5145a2dc36e1e3420d79328c8b62666526cae5b2d","src/lib.rs":"ccf6851beb2a3e481541dd8a3c3e3d2fbd513a410eef820221942098212a8184","src/todolist.udl":"1f8a24049c2340b9184e95facfc191ecdcb91541729ae7f20b4625d67685f13c","tests/bindings/test_todolist.kts":"f3d29b48e0193563fc4f131d91ea697f758174dcdb80ea554f233949e575bf55","tests/bindings/test_todolist.py":"8ea1377fe336adaf4cade0fe073ae5825c3b38c63e46b7f4e92b87c0fe57c036","tests/bindings/test_todolist.rb":"e8840eb81477048718a56c5fa02c0fb2e28cf0a598a20c9393ba2262d6ffb89b","tests/bindings/test_todolist.swift":"d1911b85fe0c8c0b42e5421b5af5d7359c9a65bba477d23560eb4b0f52e80662","tests/test_generated_bindings.rs":"46ef1fbedaac0c4867812ef2632a641eab36ab0ee12f5757567dd037aeddcbd3"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-todolist/Cargo.toml b/third_party/rust/uniffi-example-todolist/Cargo.toml deleted file mode 100644 index cf4de491cd..0000000000 --- a/third_party/rust/uniffi-example-todolist/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "uniffi-example-todolist" -version = "0.22.0" -authors = ["Firefox Sync Team "] -publish = false -license = "MPL-2.0" - -[lib] -name = "uniffi_todolist" -crate-type = [ - "lib", - "cdylib", -] - -[dependencies] -once_cell = "1.12" -thiserror = "1.0" - -[dependencies.uniffi] -version = "0.27" -path = "../../uniffi" - -[dev-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["bindgen-tests"] - -[build-dependencies.uniffi] -version = "0.27" -path = "../../uniffi" -features = ["build"] diff --git a/third_party/rust/uniffi-example-todolist/build.rs b/third_party/rust/uniffi-example-todolist/build.rs deleted file mode 100644 index 2dd2f68b75..0000000000 --- a/third_party/rust/uniffi-example-todolist/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -fn main() { - uniffi::generate_scaffolding("src/todolist.udl").unwrap(); -} diff --git a/third_party/rust/uniffi-example-todolist/src/lib.rs b/third_party/rust/uniffi-example-todolist/src/lib.rs deleted file mode 100644 index 11cdc63aee..0000000000 --- a/third_party/rust/uniffi-example-todolist/src/lib.rs +++ /dev/null @@ -1,150 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use std::sync::{Arc, RwLock}; - -use once_cell::sync::Lazy; - -#[derive(Debug, Clone)] -pub struct TodoEntry { - text: String, -} - -// There is a single "default" TodoList that can be shared -// by all consumers of this component. Depending on requirements, -// a real app might like to use a `Weak<>` rather than an `Arc<>` -// here to reduce the risk of circular references. -static DEFAULT_LIST: Lazy>>> = Lazy::new(|| RwLock::new(None)); - -#[derive(Debug, thiserror::Error)] -pub enum TodoError { - #[error("The todo does not exist!")] - TodoDoesNotExist, - #[error("The todolist is empty!")] - EmptyTodoList, - #[error("That todo already exists!")] - DuplicateTodo, - #[error("Empty String error!: {0}")] - EmptyString(String), - #[error("I am a delegated Error: {0}")] - DeligatedError(#[from] std::io::Error), -} - -/// Get a reference to the global default TodoList, if set. -/// -fn get_default_list() -> Option> { - DEFAULT_LIST.read().unwrap().clone() -} - -/// Set the global default TodoList. -/// -/// This will silently drop any previously set value. -/// -fn set_default_list(list: Arc) { - *DEFAULT_LIST.write().unwrap() = Some(list); -} - -/// Create a new TodoEntry from the given string. -/// -fn create_entry_with>(item: S) -> Result { - let text = item.into(); - if text.is_empty() { - return Err(TodoError::EmptyString( - "Cannot add empty string as entry".to_string(), - )); - } - Ok(TodoEntry { text }) -} - -type Result = std::result::Result; - -// A simple Todolist. -// UniFFI requires that we use interior mutability for managing mutable state, so we wrap our `Vec` in a RwLock. -// (A Mutex would also work, but a RwLock is more appropriate for this use-case, so we use it). -#[derive(Debug)] -pub struct TodoList { - items: RwLock>, -} - -impl TodoList { - fn new() -> Self { - Self { - items: RwLock::new(Vec::new()), - } - } - - fn add_item>(&self, item: S) -> Result<()> { - let item = item.into(); - if item.is_empty() { - return Err(TodoError::EmptyString( - "Cannot add empty string as item".to_string(), - )); - } - let mut items = self.items.write().unwrap(); - if items.contains(&item) { - return Err(TodoError::DuplicateTodo); - } - items.push(item); - Ok(()) - } - - fn get_last(&self) -> Result { - let items = self.items.read().unwrap(); - items.last().cloned().ok_or(TodoError::EmptyTodoList) - } - - fn get_first(&self) -> Result { - let items = self.items.read().unwrap(); - items.first().cloned().ok_or(TodoError::EmptyTodoList) - } - - fn add_entries(&self, entries: Vec) { - let mut items = self.items.write().unwrap(); - items.extend(entries.into_iter().map(|e| e.text)) - } - - fn add_entry(&self, entry: TodoEntry) -> Result<()> { - self.add_item(entry.text) - } - - fn add_items>(&self, items: Vec) { - let mut my_items = self.items.write().unwrap(); - my_items.extend(items.into_iter().map(Into::into)) - } - - fn get_items(&self) -> Vec { - let items = self.items.read().unwrap(); - items.clone() - } - - fn get_entries(&self) -> Vec { - let items = self.items.read().unwrap(); - items - .iter() - .map(|text| TodoEntry { text: text.clone() }) - .collect() - } - - fn get_last_entry(&self) -> Result { - let text = self.get_last()?; - Ok(TodoEntry { text }) - } - - fn clear_item>(&self, item: S) -> Result<()> { - let item = item.into(); - let mut items = self.items.write().unwrap(); - let idx = items - .iter() - .position(|s| s == &item) - .ok_or(TodoError::TodoDoesNotExist)?; - items.remove(idx); - Ok(()) - } - - fn make_default(self: Arc) { - set_default_list(self); - } -} - -uniffi::include_scaffolding!("todolist"); diff --git a/third_party/rust/uniffi-example-todolist/src/todolist.udl b/third_party/rust/uniffi-example-todolist/src/todolist.udl deleted file mode 100644 index 5c923314cd..0000000000 --- a/third_party/rust/uniffi-example-todolist/src/todolist.udl +++ /dev/null @@ -1,38 +0,0 @@ -namespace todolist { - TodoList? get_default_list(); - undefined set_default_list(TodoList list); - - [Throws=TodoError] - TodoEntry create_entry_with(string todo); -}; - -dictionary TodoEntry { - string text; -}; - -[Error] -enum TodoError { - "TodoDoesNotExist", "EmptyTodoList", "DuplicateTodo", "EmptyString", "DeligatedError" -}; - -interface TodoList { - constructor(); - [Throws=TodoError] - void add_item(string todo); - [Throws=TodoError] - void add_entry(TodoEntry entry); - sequence get_entries(); - sequence get_items(); - void add_entries(sequence entries); - void add_items(sequence items); - [Throws=TodoError] - TodoEntry get_last_entry(); - [Throws=TodoError] - string get_last(); - [Throws=TodoError] - string get_first(); - [Throws=TodoError] - void clear_item(string todo); - [Self=ByArc] - undefined make_default(); -}; diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts deleted file mode 100644 index bb2b292224..0000000000 --- a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts +++ /dev/null @@ -1,83 +0,0 @@ -import uniffi.todolist.* - -val todo = TodoList() - -// This throws an exception: -try { - todo.getLast() - throw RuntimeException("Should have thrown a TodoError!") -} catch (e: TodoException.EmptyTodoList) { - // It's okay, we don't have any items yet! -} - -try { - createEntryWith("") - throw RuntimeException("Should have thrown a TodoError!") -} catch (e: TodoException) { - // It's okay, the string was empty! - assert(e is TodoException.EmptyString) - assert(e !is TodoException.EmptyTodoList) -} - -todo.addItem("Write strings support") - -assert(todo.getLast() == "Write strings support") - -todo.addItem("Write tests for strings support") - -assert(todo.getLast() == "Write tests for strings support") - -val entry = createEntryWith("Write bindings for strings as record members") - -todo.addEntry(entry) -assert(todo.getLast() == "Write bindings for strings as record members") -assert(todo.getLastEntry().text == "Write bindings for strings as record members") - -todo.addItem("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") -assert(todo.getLast() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") - -val entry2 = TodoEntry("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") -todo.addEntry(entry2) -assert(todo.getLastEntry().text == "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") - -assert(todo.getEntries().size == 5) - -todo.addEntries(listOf(TodoEntry("foo"), TodoEntry("bar"))) -assert(todo.getEntries().size == 7) -assert(todo.getLastEntry().text == "bar") - -todo.addItems(listOf("bobo", "fofo")) -assert(todo.getItems().size == 9) -assert(todo.getItems()[7] == "bobo") - -assert(getDefaultList() == null) - -// Note that each individual object instance needs to be explicitly destroyed, -// either by using the `.use` helper or explicitly calling its `.destroy` method. -// Failure to do so will leak the underlying Rust object. -TodoList().use { todo2 -> - setDefaultList(todo) - getDefaultList()!!.use { default -> - assert(todo.getEntries() == default.getEntries()) - assert(todo2.getEntries() != default.getEntries()) - } - - todo2.makeDefault() - getDefaultList()!!.use { default -> - assert(todo.getEntries() != default.getEntries()) - assert(todo2.getEntries() == default.getEntries()) - } - - todo.addItem("Test liveness after being demoted from default") - assert(todo.getLast() == "Test liveness after being demoted from default") - - todo2.addItem("Test shared state through local vs default reference") - getDefaultList()!!.use { default -> - assert(default.getLast() == "Test shared state through local vs default reference") - } -} - -// Ensure the kotlin version of deinit doesn't crash, and is idempotent. -todo.destroy() -todo.destroy() - diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py deleted file mode 100644 index 7b676c83de..0000000000 --- a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py +++ /dev/null @@ -1,44 +0,0 @@ -from todolist import * - -todo = TodoList() - -entry = TodoEntry(text="Write bindings for strings in records") - -todo.add_item("Write python bindings") - -assert(todo.get_last() == "Write python bindings") - -todo.add_item("Write tests for bindings") - -assert(todo.get_last() == "Write tests for bindings") - -todo.add_entry(entry) - -assert(todo.get_last() == "Write bindings for strings in records") -assert(todo.get_last_entry().text == "Write bindings for strings in records") - -todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") -assert(todo.get_last() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") - -entry2 = TodoEntry(text="Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") -todo.add_entry(entry2) -assert(todo.get_last_entry().text == "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") - -todo2 = TodoList() -assert(todo != todo2) -assert(todo is not todo2) - -assert(get_default_list() is None) - -set_default_list(todo) -assert(todo.get_items() == get_default_list().get_items()) - -todo2.make_default() -assert(todo2.get_items() == get_default_list().get_items()) - -todo.add_item("Test liveness after being demoted from default") -assert(todo.get_last() == "Test liveness after being demoted from default") - -todo2.add_item("Test shared state through local vs default reference") -assert(get_default_list().get_last() == "Test shared state through local vs default reference") - diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb deleted file mode 100644 index fc1a823f52..0000000000 --- a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require 'test/unit' -require 'todolist' - -include Test::Unit::Assertions -include Todolist - -todo = TodoList.new -entry = TodoEntry.new(text: 'Write bindings for strings in records') - -todo.add_item('Write ruby bindings') - -assert_equal todo.get_last, 'Write ruby bindings' - -todo.add_item('Write tests for bindings') - -assert_equal todo.get_last, 'Write tests for bindings' - -todo.add_entry(entry) - -assert_equal todo.get_last, 'Write bindings for strings in records' -assert_equal todo.get_last_entry.text, 'Write bindings for strings in records' - -todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") -assert_equal todo.get_last, "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣" - -entry2 = TodoEntry.new(text: "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") -todo.add_entry(entry2) -assert_equal todo.get_last_entry.text, "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣" - -todo2 = TodoList.new -assert todo2.get_items != todo.get_items - -assert Todolist.get_default_list == nil - -Todolist.set_default_list todo -assert todo.get_items == Todolist.get_default_list.get_items - -todo2.make_default -assert todo2.get_items == Todolist.get_default_list.get_items - -todo.add_item "Test liveness after being demoted from default" -assert todo.get_last == "Test liveness after being demoted from default" - -todo2.add_item "Test shared state through local vs default reference" -assert Todolist.get_default_list.get_last == "Test shared state through local vs default reference" diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift deleted file mode 100644 index 6ce72cadb2..0000000000 --- a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift +++ /dev/null @@ -1,69 +0,0 @@ -import todolist - - -let todo = TodoList() -do { - let _ = try todo.getLast() - fatalError("Should have thrown an EmptyTodoList error!") -} catch TodoError.EmptyTodoList{ - //It's okay! There are not todos! -} -try! todo.addItem(todo: "Write swift bindings") -assert( try! todo.getLast() == "Write swift bindings") - -try! todo.addItem(todo: "Write tests for bindings") -assert(try! todo.getLast() == "Write tests for bindings") - -let entry = TodoEntry(text: "Write bindings for strings as record members") -try! todo.addEntry(entry: entry) -assert(try! todo.getLast() == "Write bindings for strings as record members") - -try! todo.addItem(todo: "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") -assert(try! todo.getLast() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") - -do { - let _ = try createEntryWith(todo: "") - fatalError("Should have thrown an EmptyString error!") -} catch TodoError.EmptyString { - // It's okay! It was an empty string -} - -let entry2 = TodoEntry(text: "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") -try! todo.addEntry(entry: entry2) -assert(try! todo.getLastEntry() == entry2) - -assert(todo.getEntries().count == 5) - -todo.addEntries(entries: [TodoEntry(text: "foo"), TodoEntry(text: "bar")]) -assert(todo.getEntries().count == 7) -assert(todo.getItems().count == 7) -assert(try! todo.getLast() == "bar") - -todo.addItems(items: ["bobo", "fofo"]) -assert(todo.getItems().count == 9) -assert(todo.getItems()[7] == "bobo") - -// Ensure deinit doesn't crash. -for _ in 0..<10 { - let list = TodoList() - try! list.addItem(todo: "todo") -} - -let todo2 = TodoList() - -assert(getDefaultList() == nil) - -setDefaultList(list: todo) -assert(todo.getItems() == getDefaultList()!.getItems()) -assert(todo2.getItems() != getDefaultList()!.getItems()) - -todo2.makeDefault() -assert(todo.getItems() != getDefaultList()!.getItems()) -assert(todo2.getItems() == getDefaultList()!.getItems()) - -try! todo.addItem(todo: "Test liveness after being demoted from default") -assert(try! todo.getLast() == "Test liveness after being demoted from default") - -try! todo2.addItem(todo: "Test shared state through local vs default reference") -assert(try! getDefaultList()!.getLast() == "Test shared state through local vs default reference") - diff --git a/third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs b/third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs deleted file mode 100644 index cefdbfe1dc..0000000000 --- a/third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs +++ /dev/null @@ -1,6 +0,0 @@ -uniffi::build_foreign_language_testcases!( - "tests/bindings/test_todolist.kts", - "tests/bindings/test_todolist.swift", - "tests/bindings/test_todolist.rb", - "tests/bindings/test_todolist.py" -); diff --git a/third_party/rust/wasm-encoder/.cargo-checksum.json b/third_party/rust/wasm-encoder/.cargo-checksum.json index b9591f5309..ca7d8944ba 100644 --- a/third_party/rust/wasm-encoder/.cargo-checksum.json +++ b/third_party/rust/wasm-encoder/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e0d334beb383d7a06a870e93a43cee25fb37c9c416b01e056a8c5589e9b5ae0c","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"ac016c4843a7e1a5737255b39418732783592222dc518020730edf9dd46a1c13","src/component.rs":"700351503077106eadf612f46079418e0b437ed0a6179dc16979768205b2ecbf","src/component/aliases.rs":"be5215154b872ed5664f3bfe2aa1391f36a2575aa9d53971ab61868a1c446e9d","src/component/builder.rs":"ea35c74cb0369181e9c0ce9729ff175d25f05bd63b48dcbbf703a53dfc113c7c","src/component/canonicals.rs":"a4f9c7a2b8ac3783d7337a5579cf71df2f33b315b354965980bd2c483d3aa141","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"1af747401f153ccd5c5adfcab55dc4d75e241536cbbdc62624c3a07dd7620056","src/component/imports.rs":"a6cd7f914de7706a1a93a40fb8d0031b4b140786a347da636c70d093401079cd","src/component/instances.rs":"a76c5e7ba0ef73ae4bff5569d177198b7f3a9959dbe9f5c1b4bae7d1a9c839b1","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/names.rs":"ca2f46a6dbc872a9cdb297d58c958e16acaf8893318bfdba30e468841107d886","src/component/start.rs":"4055553d5c99c99abbc01bb8abb928ecb8b909d148b647a9977fbd444bb464a3","src/component/types.rs":"f44501e9b356e5588767323f1844e768221e00843a33354ff2597a76f32def46","src/core.rs":"a00656f82a623656c59a2d7230b40a5849a5083e117bc57061746f6e3022c7bb","src/core/code.rs":"23f96e90b57b1334b304bc66c9c39518d9d8baee1e2a7f5e3045f817019c62da","src/core/custom.rs":"4b9f07b701dc7b6990d92fb43016c28fb971411670bb6a48553b92b1c35eb9a3","src/core/data.rs":"c9d59eab2ab811bd950da52e6766c7df2367986c7a3a0d94d7aeb47d86f203ac","src/core/dump.rs":"8feaa532e3851186277ec1f4906e7fdc82c6399b211b8c928b16e293db1205b0","src/core/elements.rs":"2df1ad85f683b5cf3ce43c8cfef3f08f74a17cec9171537e3f24205dc067b4f7","src/core/exports.rs":"9e1eb3db0e0f73e00b66d82431257923feec8c052ac8b98717c8f36ffcc03537","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"0ed5f033489318d91e974090e8bf240720baa1ba621d0b5e0956dbd68e2165c1","src/core/imports.rs":"b4b096a6b1f449c4429efff605ca597549ea31873e18a9e6e55c616b4edc76db","src/core/linking.rs":"2f1053d9c2671e91a2b6e253dd38921bfc5f1b8a1a047b10c843033fe0f492de","src/core/memories.rs":"42e11ff5e8b2634bcd87810aef3fb9057c5d0b23c68ca9862a1e99aab5ecad72","src/core/names.rs":"2624a58835b27b17260fdbd20704856dce04e1826eb2b3b6196f8f1ffcf560ef","src/core/producers.rs":"f4916c1cf61e26170cd10fe350de7dad18005461c362909b9557c16c507517bc","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"c8286f5624ff429d42879932dedf45975513abfd98071a4084271860225af078","src/core/tags.rs":"66251072d5108dfde8177039cef95deac21606a361cddb04f37c08b8a8969db4","src/core/types.rs":"eb61f4f53a6c283ff6788c9724ffb728d2f525a62230bd13494a797ee23fbfef","src/lib.rs":"e61325ab8de1b4c404f4ee7665eef404fca2d23322a9c8f94efec8426edc166b","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a"} \ No newline at end of file +{"files":{"Cargo.toml":"dd8325b9b609ebb74c8fb1472fb2147bae3053bb7b481cf5375e4da172aa05c7","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"ac016c4843a7e1a5737255b39418732783592222dc518020730edf9dd46a1c13","src/component.rs":"700351503077106eadf612f46079418e0b437ed0a6179dc16979768205b2ecbf","src/component/aliases.rs":"be5215154b872ed5664f3bfe2aa1391f36a2575aa9d53971ab61868a1c446e9d","src/component/builder.rs":"ea35c74cb0369181e9c0ce9729ff175d25f05bd63b48dcbbf703a53dfc113c7c","src/component/canonicals.rs":"a4f9c7a2b8ac3783d7337a5579cf71df2f33b315b354965980bd2c483d3aa141","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"1af747401f153ccd5c5adfcab55dc4d75e241536cbbdc62624c3a07dd7620056","src/component/imports.rs":"a6cd7f914de7706a1a93a40fb8d0031b4b140786a347da636c70d093401079cd","src/component/instances.rs":"a76c5e7ba0ef73ae4bff5569d177198b7f3a9959dbe9f5c1b4bae7d1a9c839b1","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/names.rs":"ca2f46a6dbc872a9cdb297d58c958e16acaf8893318bfdba30e468841107d886","src/component/start.rs":"4055553d5c99c99abbc01bb8abb928ecb8b909d148b647a9977fbd444bb464a3","src/component/types.rs":"069f0ee5fc4001c26a0db4bab32c8db268af68a11bf50a55f07c9365f2317e5f","src/core.rs":"a00656f82a623656c59a2d7230b40a5849a5083e117bc57061746f6e3022c7bb","src/core/code.rs":"49d8b8414f62d2851e7dc1bb5965037a12d2ef2a02bec8f96349779b352e7d9e","src/core/custom.rs":"4b9f07b701dc7b6990d92fb43016c28fb971411670bb6a48553b92b1c35eb9a3","src/core/data.rs":"f209e23710ab75600dd200af176e23940c88fac8a6ca31c3df67b97a911f2c55","src/core/dump.rs":"8feaa532e3851186277ec1f4906e7fdc82c6399b211b8c928b16e293db1205b0","src/core/elements.rs":"2df1ad85f683b5cf3ce43c8cfef3f08f74a17cec9171537e3f24205dc067b4f7","src/core/exports.rs":"9e1eb3db0e0f73e00b66d82431257923feec8c052ac8b98717c8f36ffcc03537","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"15408072945d2d96d16c1020ec1a029a348fbe22da26eb35d02d695527f675ba","src/core/imports.rs":"af26ca7dd09cb2b8ecfbe347378252f4d12b92e23818e23d72512591ceee671c","src/core/linking.rs":"2f1053d9c2671e91a2b6e253dd38921bfc5f1b8a1a047b10c843033fe0f492de","src/core/memories.rs":"9e437e878e61933bc731ef20994aefedb0ac4ac6b9464e36b38a8cdc26019dd8","src/core/names.rs":"2624a58835b27b17260fdbd20704856dce04e1826eb2b3b6196f8f1ffcf560ef","src/core/producers.rs":"f4916c1cf61e26170cd10fe350de7dad18005461c362909b9557c16c507517bc","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"c8286f5624ff429d42879932dedf45975513abfd98071a4084271860225af078","src/core/tags.rs":"66251072d5108dfde8177039cef95deac21606a361cddb04f37c08b8a8969db4","src/core/types.rs":"1f3f5b2bc09ea6f4a569ddfb7e343bf3fb450d8508b3bf338915dad98aad9582","src/lib.rs":"e61325ab8de1b4c404f4ee7665eef404fca2d23322a9c8f94efec8426edc166b","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"90e95b3563d164f33c1cfb0a7efbd5940c37710019be10cd09f800fdec8b0e5c"} \ No newline at end of file diff --git a/third_party/rust/wasm-encoder/Cargo.toml b/third_party/rust/wasm-encoder/Cargo.toml index aa4ce5bc7c..9fd28b544d 100644 --- a/third_party/rust/wasm-encoder/Cargo.toml +++ b/third_party/rust/wasm-encoder/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "wasm-encoder" -version = "0.201.0" +version = "0.205.0" authors = ["Nick Fitzgerald "] description = """ A low-level WebAssembly encoder. @@ -27,7 +27,7 @@ repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wa version = "0.2.4" [dependencies.wasmparser] -version = "0.201.0" +version = "0.205.0" optional = true [dev-dependencies.anyhow] diff --git a/third_party/rust/wasm-encoder/src/component/types.rs b/third_party/rust/wasm-encoder/src/component/types.rs index 537e8c5a00..72e0034b6b 100644 --- a/third_party/rust/wasm-encoder/src/component/types.rs +++ b/third_party/rust/wasm-encoder/src/component/types.rs @@ -497,10 +497,10 @@ pub enum PrimitiveValType { S64, /// The type is an unsigned 64-bit integer. U64, - /// The type is a 32-bit floating point number. - Float32, - /// The type is a 64-bit floating point number. - Float64, + /// The type is a 32-bit floating point number with only one NaN. + F32, + /// The type is a 64-bit floating point number with only one NaN. + F64, /// The type is a Unicode character. Char, /// The type is a string. @@ -519,8 +519,8 @@ impl Encode for PrimitiveValType { Self::U32 => 0x79, Self::S64 => 0x78, Self::U64 => 0x77, - Self::Float32 => 0x76, - Self::Float64 => 0x75, + Self::F32 => 0x76, + Self::F64 => 0x75, Self::Char => 0x74, Self::String => 0x73, }); @@ -540,8 +540,8 @@ impl From for PrimitiveValType { wasmparser::PrimitiveValType::U32 => PrimitiveValType::U32, wasmparser::PrimitiveValType::S64 => PrimitiveValType::S64, wasmparser::PrimitiveValType::U64 => PrimitiveValType::U64, - wasmparser::PrimitiveValType::Float32 => PrimitiveValType::Float32, - wasmparser::PrimitiveValType::Float64 => PrimitiveValType::Float64, + wasmparser::PrimitiveValType::F32 => PrimitiveValType::F32, + wasmparser::PrimitiveValType::F64 => PrimitiveValType::F64, wasmparser::PrimitiveValType::Char => PrimitiveValType::Char, wasmparser::PrimitiveValType::String => PrimitiveValType::String, } diff --git a/third_party/rust/wasm-encoder/src/core/code.rs b/third_party/rust/wasm-encoder/src/core/code.rs index 76bfd7afde..4b04b0b72b 100644 --- a/third_party/rust/wasm-encoder/src/core/code.rs +++ b/third_party/rust/wasm-encoder/src/core/code.rs @@ -274,6 +274,34 @@ impl Encode for MemArg { } } +/// The memory ordering for atomic instructions. +/// +/// For an in-depth explanation of memory orderings, see the C++ documentation +/// for [`memory_order`] or the Rust documentation for [`atomic::Ordering`]. +/// +/// [`memory_order`]: https://en.cppreference.com/w/cpp/atomic/memory_order +/// [`atomic::Ordering`]: https://doc.rust-lang.org/std/sync/atomic/enum.Ordering.html +#[derive(Clone, Copy, Debug)] +pub enum Ordering { + /// For a load, it acquires; this orders all operations before the last + /// "releasing" store. For a store, it releases; this orders all operations + /// before it at the next "acquiring" load. + AcqRel, + /// Like `AcqRel` but all threads see all sequentially consistent operations + /// in the same order. + SeqCst, +} + +impl Encode for Ordering { + fn encode(&self, sink: &mut Vec) { + let flag: u8 = match self { + Ordering::SeqCst => 0, + Ordering::AcqRel => 1, + }; + sink.push(flag); + } +} + /// Describe an unchecked SIMD lane index. pub type Lane = u8; @@ -980,6 +1008,16 @@ pub enum Instruction<'a> { I64AtomicRmw8CmpxchgU(MemArg), I64AtomicRmw16CmpxchgU(MemArg), I64AtomicRmw32CmpxchgU(MemArg), + + // More atomic instructions (the shared-everything-threads proposal) + GlobalAtomicGet { + ordering: Ordering, + global_index: u32, + }, + GlobalAtomicSet { + ordering: Ordering, + global_index: u32, + }, } impl Encode for Instruction<'_> { @@ -2787,7 +2825,7 @@ impl Encode for Instruction<'_> { 0x113u32.encode(sink); } - // Atmoic instructions from the thread proposal + // Atomic instructions from the thread proposal Instruction::MemoryAtomicNotify(memarg) => { sink.push(0xFE); sink.push(0x00); @@ -3123,6 +3161,26 @@ impl Encode for Instruction<'_> { sink.push(0x4E); memarg.encode(sink); } + + // Atomic instructions from the shared-everything-threads proposal + Instruction::GlobalAtomicGet { + ordering, + global_index, + } => { + sink.push(0xFE); + sink.push(0x4F); + ordering.encode(sink); + global_index.encode(sink); + } + Instruction::GlobalAtomicSet { + ordering, + global_index, + } => { + sink.push(0xFE); + sink.push(0x50); + ordering.encode(sink); + global_index.encode(sink); + } } } } diff --git a/third_party/rust/wasm-encoder/src/core/data.rs b/third_party/rust/wasm-encoder/src/core/data.rs index 6439b66e2e..6f408befe5 100644 --- a/third_party/rust/wasm-encoder/src/core/data.rs +++ b/third_party/rust/wasm-encoder/src/core/data.rs @@ -18,6 +18,7 @@ use crate::{encode_section, encoding_size, ConstExpr, Encode, Section, SectionId /// maximum: None, /// memory64: false, /// shared: false, +/// page_size_log2: None, /// }); /// /// let mut data = DataSection::new(); diff --git a/third_party/rust/wasm-encoder/src/core/globals.rs b/third_party/rust/wasm-encoder/src/core/globals.rs index 64fec982cd..291ca80472 100644 --- a/third_party/rust/wasm-encoder/src/core/globals.rs +++ b/third_party/rust/wasm-encoder/src/core/globals.rs @@ -14,6 +14,7 @@ use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; /// GlobalType { /// val_type: ValType::I32, /// mutable: false, +/// shared: false, /// }, /// &ConstExpr::i32_const(42), /// ); @@ -80,12 +81,21 @@ pub struct GlobalType { pub val_type: ValType, /// Whether this global is mutable or not. pub mutable: bool, + /// Whether this global is shared or not. + pub shared: bool, } impl Encode for GlobalType { fn encode(&self, sink: &mut Vec) { self.val_type.encode(sink); - sink.push(self.mutable as u8); + let mut flag = 0; + if self.mutable { + flag |= 0b01; + } + if self.shared { + flag |= 0b10; + } + sink.push(flag); } } @@ -96,6 +106,7 @@ impl TryFrom for GlobalType { Ok(GlobalType { val_type: global_ty.content_type.try_into()?, mutable: global_ty.mutable, + shared: global_ty.shared, }) } } diff --git a/third_party/rust/wasm-encoder/src/core/imports.rs b/third_party/rust/wasm-encoder/src/core/imports.rs index 0030d640e6..d4db2e65c5 100644 --- a/third_party/rust/wasm-encoder/src/core/imports.rs +++ b/third_party/rust/wasm-encoder/src/core/imports.rs @@ -103,6 +103,7 @@ impl TryFrom for EntityType { /// maximum: None, /// memory64: false, /// shared: false, +/// page_size_log2: None, /// } /// ); /// diff --git a/third_party/rust/wasm-encoder/src/core/memories.rs b/third_party/rust/wasm-encoder/src/core/memories.rs index 892545eb98..d64ef01210 100644 --- a/third_party/rust/wasm-encoder/src/core/memories.rs +++ b/third_party/rust/wasm-encoder/src/core/memories.rs @@ -15,6 +15,7 @@ use crate::{encode_section, Encode, Section, SectionId}; /// maximum: None, /// memory64: false, /// shared: false, +/// page_size_log2: None, /// }); /// /// let mut module = Module::new(); @@ -75,26 +76,41 @@ pub struct MemoryType { pub memory64: bool, /// Whether or not this memory is shared. pub shared: bool, + /// The log base 2 of a custom page size for this memory. + /// + /// The default page size for Wasm memories is 64KiB, i.e. 216 or + /// `65536`. + /// + /// After the introduction of [the custom-page-sizes + /// proposal](https://github.com/WebAssembly/custom-page-sizes), Wasm can + /// customize the page size. It must be a power of two that is less than or + /// equal to 64KiB. Attempting to encode an invalid page size may panic. + pub page_size_log2: Option, } impl Encode for MemoryType { fn encode(&self, sink: &mut Vec) { let mut flags = 0; if self.maximum.is_some() { - flags |= 0b001; + flags |= 0b0001; } if self.shared { - flags |= 0b010; + flags |= 0b0010; } if self.memory64 { - flags |= 0b100; + flags |= 0b0100; + } + if self.page_size_log2.is_some() { + flags |= 0b1000; } - sink.push(flags); self.minimum.encode(sink); if let Some(max) = self.maximum { max.encode(sink); } + if let Some(p) = self.page_size_log2 { + p.encode(sink); + } } } @@ -106,6 +122,7 @@ impl From for MemoryType { maximum: memory_ty.maximum, memory64: memory_ty.memory64, shared: memory_ty.shared, + page_size_log2: memory_ty.page_size_log2, } } } diff --git a/third_party/rust/wasm-encoder/src/core/types.rs b/third_party/rust/wasm-encoder/src/core/types.rs index bfc54ae1e3..8b5f340bb6 100644 --- a/third_party/rust/wasm-encoder/src/core/types.rs +++ b/third_party/rust/wasm-encoder/src/core/types.rs @@ -450,9 +450,12 @@ pub enum HeapType { /// The unboxed `i31` heap type. I31, - /// The abstract` exception` heap type. + /// The abstract `exception` heap type. Exn, + /// The abstract `noexn` heap type. + NoExn, + /// A concrete Wasm-defined type at the given index. Concrete(u32), } @@ -471,6 +474,7 @@ impl Encode for HeapType { HeapType::Array => sink.push(0x6A), HeapType::I31 => sink.push(0x6C), HeapType::Exn => sink.push(0x69), + HeapType::NoExn => sink.push(0x74), // Note that this is encoded as a signed type rather than unsigned // as it's decoded as an s33 HeapType::Concrete(i) => i64::from(*i).encode(sink), @@ -496,6 +500,7 @@ impl TryFrom for HeapType { wasmparser::HeapType::Array => HeapType::Array, wasmparser::HeapType::I31 => HeapType::I31, wasmparser::HeapType::Exn => HeapType::Exn, + wasmparser::HeapType::NoExn => HeapType::NoExn, }) } } @@ -645,6 +650,8 @@ impl Section for TypeSection { #[cfg(test)] mod tests { + use wasmparser::WasmFeatures; + use super::*; use crate::Module; @@ -661,10 +668,8 @@ mod tests { module.section(&types); let wasm_bytes = module.finish(); - let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { - gc: false, - ..Default::default() - }); + let mut validator = + wasmparser::Validator::new_with_features(WasmFeatures::default() & !WasmFeatures::GC); validator.validate_all(&wasm_bytes).expect( "Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding", diff --git a/third_party/rust/wasm-smith/.cargo-checksum.json b/third_party/rust/wasm-smith/.cargo-checksum.json index d61edb195b..fd68c5102e 100644 --- a/third_party/rust/wasm-smith/.cargo-checksum.json +++ b/third_party/rust/wasm-smith/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"b911aa53dc1f5c0cb04a77e15b43c31cee98893c7bcb98b6d73405aeca6b447c","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e7b2a96cf39834aa19aed7cad8658e33445cdec7c4957658ba39e3b82cc4254b","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"253cf8d8abf785e4b5a5c614561a85b032e7f7bdec366f83d9db0702f73d2122","src/component/encode.rs":"5985e3f412595e07372a0787ec3db6c3018840df2bcfc638ab8798fd74b22778","src/config.rs":"e75d93c0a6a5ba07ff3ec1164a9b58601fadc0a0899149e14a77e8f0ab4595e4","src/core.rs":"35d3854c8caa1f61494b2f8e2b5e150d67cf88582243feeeb198e2aa93247339","src/core/code_builder.rs":"a8b27f652c8ae4b964e05933df313016ab7ffc297ca76005faca3da2792e3afc","src/core/code_builder/no_traps.rs":"2f36c548a32a6a003e6bb22a8fe7c75517b9be00c5a299212836a7e2431a8693","src/core/encode.rs":"77e1395c78ecf1b688a3c515a58be6efe1aa58d450a20a50d69598c54f7162de","src/core/terminate.rs":"c7c5f5618d393e5d9e44ae5e9bbde4b81bfa1ca3d2111d1eea875e2490f0f64b","src/lib.rs":"d393ae9daba211ba68a48dbdee545e0570cb8298e4c62319b8c8a8b9355cd6e3","tests/available_imports.rs":"6d4c1b111f35fefce55b668474ac9ba25edf7fc3e3decb88696b644aec13d603","tests/common/mod.rs":"9d0712a0b3e30030934b04785fb8632576bdcc31921ee8f524e0b2c903dee28d","tests/component.rs":"44684e990e832590a0b348ce33fadf39ee55dec52fdfa9353570edcbf65325ee","tests/core.rs":"408a50da4438be4e5343b116aa80f5ce344ba9508fad413cc5c32cd0aa2164fb","tests/exports.rs":"dcac4e18f277cbdb821f4ad7eda0a900bd73924e0818cf1b408700c9b7bba789"},"package":"61ff53a54a853f174b0df74cdb1553f1451e7bcdc23b26b1379f664ee1913d1a"} \ No newline at end of file +{"files":{"Cargo.toml":"4efe2ea2adda65b88d8ebcc59c881faaa54aa0a259f705d5a387c5e0c4a5a5d6","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e7b2a96cf39834aa19aed7cad8658e33445cdec7c4957658ba39e3b82cc4254b","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"7846fba1f588bb8cee539d4ae162c564332fd382abc54958ab72d31f5678e191","src/component/encode.rs":"5985e3f412595e07372a0787ec3db6c3018840df2bcfc638ab8798fd74b22778","src/config.rs":"207c1ed2535f11cfdc275b2388c03b2c9fe27b6f28d5c428c6c5cf6a81abe8af","src/core.rs":"b1ec6d747677dbf54ea1892e8b0928a68c641d6e56df4151cd8f9f9ae0f89a4f","src/core/code_builder.rs":"77d216064374edf0fcd273b2d6ddf3c4f90fd792be83f85c1e198bdea0138387","src/core/code_builder/no_traps.rs":"14dab911427934dd6394b36eea9761c8722c47611b3ebf9fde1d54bebd7c4e55","src/core/encode.rs":"77e1395c78ecf1b688a3c515a58be6efe1aa58d450a20a50d69598c54f7162de","src/core/terminate.rs":"e07fe450c1fee58726bace161c5747a6f01539e8b2937724064cc7370562555c","src/lib.rs":"21abe6dc08ab1fe40e6e9a063ee93c901318278c051a45f94519b8e4f402e2dc","tests/available_imports.rs":"6d4c1b111f35fefce55b668474ac9ba25edf7fc3e3decb88696b644aec13d603","tests/common/mod.rs":"815532619bf27593765c6238173644cdda33fbd0ba80e45fef165bbd9717934d","tests/component.rs":"bbde2e2d75680184724515a82babbe93b259e14c12c55c665d266967ede8b8f1","tests/core.rs":"4500bf8ec2a51c27a7cb01ef7c117c6e1acf12f1609579fd8761961c0d6c223a","tests/exports.rs":"518fea2a776cec51b059a31420908a73ddf7303aa143104afe32c52b09f88eda"},"package":"1218f393276f7a13f6c54467434633144b46c33ecbc3cbafdc938033f0315d1a"} \ No newline at end of file diff --git a/third_party/rust/wasm-smith/Cargo.toml b/third_party/rust/wasm-smith/Cargo.toml index 3847409e33..3221e77872 100644 --- a/third_party/rust/wasm-smith/Cargo.toml +++ b/third_party/rust/wasm-smith/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "wasm-smith" -version = "0.201.0" +version = "0.205.0" authors = ["Nick Fitzgerald "] exclude = ["/benches/corpus"] description = "A WebAssembly test case generator" @@ -61,14 +61,14 @@ version = "1.0.166" optional = true [dependencies.wasm-encoder] -version = "0.201.0" +version = "0.205.0" [dependencies.wasmparser] -version = "0.201.0" +version = "0.205.0" optional = true [dependencies.wat] -version = "1.201.0" +version = "1.205.0" optional = true [dev-dependencies.criterion] @@ -79,7 +79,7 @@ version = "0.8.4" features = ["small_rng"] [dev-dependencies.wasmparser] -version = "0.201.0" +version = "0.205.0" [features] _internal_cli = [ diff --git a/third_party/rust/wasm-smith/src/component.rs b/third_party/rust/wasm-smith/src/component.rs index 7a85b2bf10..35bf93231b 100644 --- a/third_party/rust/wasm-smith/src/component.rs +++ b/third_party/rust/wasm-smith/src/component.rs @@ -952,6 +952,7 @@ impl ComponentBuilder { Ok(crate::core::GlobalType { val_type: self.arbitrary_core_valtype(u)?, mutable: u.arbitrary()?, + shared: false, }) } @@ -1308,8 +1309,8 @@ impl ComponentBuilder { 6 => Ok(PrimitiveValType::U32), 7 => Ok(PrimitiveValType::S64), 8 => Ok(PrimitiveValType::U64), - 9 => Ok(PrimitiveValType::Float32), - 10 => Ok(PrimitiveValType::Float64), + 9 => Ok(PrimitiveValType::F32), + 10 => Ok(PrimitiveValType::F64), 11 => Ok(PrimitiveValType::Char), 12 => Ok(PrimitiveValType::String), _ => unreachable!(), @@ -1773,8 +1774,8 @@ fn canonical_abi_for(func_ty: &FuncType) -> Rc { | PrimitiveValType::S32 | PrimitiveValType::U32 => ValType::I32, PrimitiveValType::S64 | PrimitiveValType::U64 => ValType::I64, - PrimitiveValType::Float32 => ValType::F32, - PrimitiveValType::Float64 => ValType::F64, + PrimitiveValType::F32 => ValType::F32, + PrimitiveValType::F64 => ValType::F64, PrimitiveValType::String => { unimplemented!("non-scalar types are not supported yet") } @@ -1819,8 +1820,8 @@ fn inverse_scalar_canonical_abi_for( ComponentValType::Primitive(PrimitiveValType::U64), ]) .cloned(), - ValType::F32 => Ok(ComponentValType::Primitive(PrimitiveValType::Float32)), - ValType::F64 => Ok(ComponentValType::Primitive(PrimitiveValType::Float64)), + ValType::F32 => Ok(ComponentValType::Primitive(PrimitiveValType::F32)), + ValType::F64 => Ok(ComponentValType::Primitive(PrimitiveValType::F64)), ValType::V128 | ValType::Ref(_) => { unreachable!("not used in canonical ABI") } @@ -2055,8 +2056,8 @@ fn is_scalar(ty: &ComponentValType) -> bool { | PrimitiveValType::U32 | PrimitiveValType::S64 | PrimitiveValType::U64 - | PrimitiveValType::Float32 - | PrimitiveValType::Float64 + | PrimitiveValType::F32 + | PrimitiveValType::F64 | PrimitiveValType::Char => true, PrimitiveValType::String => false, }, diff --git a/third_party/rust/wasm-smith/src/config.rs b/third_party/rust/wasm-smith/src/config.rs index 43dbecceb8..57bd25be24 100644 --- a/third_party/rust/wasm-smith/src/config.rs +++ b/third_party/rust/wasm-smith/src/config.rs @@ -313,6 +313,12 @@ define_config! { /// Defaults to `false`. pub gc_enabled: bool = false, + /// Determines whether the custom-page-sizes proposal is enabled when + /// generating a Wasm module. + /// + /// Defaults to `false`. + pub custom_page_sizes_enabled: bool = false, + /// Returns whether we should generate custom sections or not. Defaults /// to false. pub generate_custom_sections: bool = false, @@ -681,6 +687,7 @@ impl<'a> Arbitrary<'a> for Config { }, table_max_size_required: u.arbitrary()?, max_table_elements: u.int_in_range(0..=1_000_000)?, + disallow_traps: u.arbitrary()?, // These fields, unlike the ones above, are less useful to set. // They either make weird inputs or are for features not widely @@ -712,9 +719,9 @@ impl<'a> Arbitrary<'a> for Config { exports: None, threads_enabled: false, export_everything: false, - disallow_traps: false, tail_call_enabled: false, gc_enabled: false, + custom_page_sizes_enabled: false, generate_custom_sections: false, allow_invalid_funcs: false, }) diff --git a/third_party/rust/wasm-smith/src/core.rs b/third_party/rust/wasm-smith/src/core.rs index 194d2101ae..db9bb2e546 100644 --- a/third_party/rust/wasm-smith/src/core.rs +++ b/third_party/rust/wasm-smith/src/core.rs @@ -146,6 +146,11 @@ pub struct Module { /// What the maximum type index that can be referenced is. max_type_limit: MaxTypeLimit, + + /// Some known-interesting values, such as powers of two, values just before + /// or just after a memory size, etc... + interesting_values32: Vec, + interesting_values64: Vec, } impl<'a> Arbitrary<'a> for Module { @@ -232,15 +237,12 @@ impl Module { export_names: HashSet::new(), const_expr_choices: Vec::new(), max_type_limit: MaxTypeLimit::ModuleTypes, + interesting_values32: Vec::new(), + interesting_values64: Vec::new(), } } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub(crate) struct RecGroup { - pub(crate) types: Vec, -} - #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub(crate) struct SubType { pub(crate) is_final: bool, @@ -494,6 +496,8 @@ impl Module { matches!(self.ty(b).composite_type, CompositeType::Func(_)) } + (HT::NoExn, HT::Exn) => true, + // Nothing else matches. (Avoid full wildcard matches so that // adding/modifying variants is easier in the future.) (HT::Concrete(_), _) @@ -506,11 +510,9 @@ impl Module { | (HT::Eq, _) | (HT::Struct, _) | (HT::Array, _) - | (HT::I31, _) => false, - - // TODO: `exn` probably will be its own type hierarchy and will - // probably get `noexn` as well. - (HT::Exn, _) => false, + | (HT::I31, _) + | (HT::Exn, _) + | (HT::NoExn, _) => false, } } @@ -779,7 +781,7 @@ impl Module { HT::Extern => { choices.push(HT::NoExtern); } - HT::Exn | HT::None | HT::NoExtern | HT::NoFunc => {} + HT::Exn | HT::NoExn | HT::None | HT::NoExtern | HT::NoFunc => {} } Ok(*u.choose(&choices)?) } @@ -858,6 +860,9 @@ impl Module { choices.extend(self.func_types.iter().copied().map(HT::Concrete)); choices.push(HT::Func); } + HT::NoExn => { + choices.push(HT::Exn); + } HT::Concrete(mut idx) => { match &self .types @@ -1422,6 +1427,7 @@ impl Module { Ok(GlobalType { val_type: self.arbitrary_valtype(u)?, mutable: u.arbitrary()?, + shared: false, }) } @@ -1645,6 +1651,7 @@ impl Module { wasmparser::HeapType::Array => HeapType::Array, wasmparser::HeapType::I31 => HeapType::I31, wasmparser::HeapType::Exn => HeapType::Exn, + wasmparser::HeapType::NoExn => HeapType::NoExn, } } @@ -1754,6 +1761,7 @@ impl Module { GlobalType { val_type: convert_val_type(&global_type.content_type), mutable: global_type.mutable, + shared: global_type.shared, }, u, )?, @@ -2039,6 +2047,8 @@ impl Module { } fn arbitrary_code(&mut self, u: &mut Unstructured) -> Result<()> { + self.compute_interesting_values(); + self.code.reserve(self.num_defined_funcs); let mut allocs = CodeBuilderAllocations::new(self, self.config.exports.is_some()); for (_, ty) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() { @@ -2224,6 +2234,170 @@ impl Module { } }) } + + fn compute_interesting_values(&mut self) { + debug_assert!(self.interesting_values32.is_empty()); + debug_assert!(self.interesting_values64.is_empty()); + + let mut interesting_values32 = HashSet::new(); + let mut interesting_values64 = HashSet::new(); + + let mut interesting = |val: u64| { + interesting_values32.insert(val as u32); + interesting_values64.insert(val); + }; + + // Zero is always interesting. + interesting(0); + + // Max values are always interesting. + interesting(u8::MAX as _); + interesting(u16::MAX as _); + interesting(u32::MAX as _); + interesting(u64::MAX); + + // Min values are always interesting. + interesting(i8::MIN as _); + interesting(i16::MIN as _); + interesting(i32::MIN as _); + interesting(i64::MIN as _); + + for i in 0..64 { + // Powers of two. + interesting(1 << i); + + // Inverted powers of two. + interesting(!(1 << i)); + + // Powers of two minus one, AKA high bits unset and low bits set. + interesting((1 << i) - 1); + + // Negative powers of two, AKA high bits set and low bits unset. + interesting(((1_i64 << 63) >> i) as _); + } + + // Some repeating bit patterns. + for pattern in [0b01010101, 0b00010001, 0b00010001, 0b00000001] { + for b in [pattern, !pattern] { + interesting(u64::from_ne_bytes([b, b, b, b, b, b, b, b])); + } + } + + // Interesting float values. + let mut interesting_f64 = |x: f64| interesting(x.to_bits()); + interesting_f64(0.0); + interesting_f64(-0.0); + interesting_f64(f64::INFINITY); + interesting_f64(f64::NEG_INFINITY); + interesting_f64(f64::EPSILON); + interesting_f64(-f64::EPSILON); + interesting_f64(f64::MIN); + interesting_f64(f64::MIN_POSITIVE); + interesting_f64(f64::MAX); + interesting_f64(f64::NAN); + let mut interesting_f32 = |x: f32| interesting(x.to_bits() as _); + interesting_f32(0.0); + interesting_f32(-0.0); + interesting_f32(f32::INFINITY); + interesting_f32(f32::NEG_INFINITY); + interesting_f32(f32::EPSILON); + interesting_f32(-f32::EPSILON); + interesting_f32(f32::MIN); + interesting_f32(f32::MIN_POSITIVE); + interesting_f32(f32::MAX); + interesting_f32(f32::NAN); + + // Interesting values related to table bounds. + for t in self.tables.iter() { + interesting(t.minimum as _); + if let Some(x) = t.minimum.checked_add(1) { + interesting(x as _); + } + + if let Some(x) = t.maximum { + interesting(x as _); + if let Some(y) = x.checked_add(1) { + interesting(y as _); + } + } + } + + // Interesting values related to memory bounds. + for m in self.memories.iter() { + let min = m.minimum.saturating_mul(crate::page_size(m).into()); + interesting(min); + for i in 0..5 { + if let Some(x) = min.checked_add(1 << i) { + interesting(x); + } + if let Some(x) = min.checked_sub(1 << i) { + interesting(x); + } + } + + if let Some(max) = m.maximum { + let max = max.saturating_mul(crate::page_size(m).into()); + interesting(max); + for i in 0..5 { + if let Some(x) = max.checked_add(1 << i) { + interesting(x); + } + if let Some(x) = max.checked_sub(1 << i) { + interesting(x); + } + } + } + } + + self.interesting_values32.extend(interesting_values32); + self.interesting_values64.extend(interesting_values64); + + // Sort for determinism. + self.interesting_values32.sort(); + self.interesting_values64.sort(); + } + + fn arbitrary_const_instruction( + &self, + ty: ValType, + u: &mut Unstructured<'_>, + ) -> Result { + debug_assert!(self.interesting_values32.len() > 0); + debug_assert!(self.interesting_values64.len() > 0); + match ty { + ValType::I32 => Ok(Instruction::I32Const(if u.arbitrary()? { + *u.choose(&self.interesting_values32)? as i32 + } else { + u.arbitrary()? + })), + ValType::I64 => Ok(Instruction::I64Const(if u.arbitrary()? { + *u.choose(&self.interesting_values64)? as i64 + } else { + u.arbitrary()? + })), + ValType::F32 => Ok(Instruction::F32Const(if u.arbitrary()? { + f32::from_bits(*u.choose(&self.interesting_values32)?) + } else { + u.arbitrary()? + })), + ValType::F64 => Ok(Instruction::F64Const(if u.arbitrary()? { + f64::from_bits(*u.choose(&self.interesting_values64)?) + } else { + u.arbitrary()? + })), + ValType::V128 => Ok(Instruction::V128Const(if u.arbitrary()? { + let upper = (*u.choose(&self.interesting_values64)? as i128) << 64; + let lower = *u.choose(&self.interesting_values64)? as i128; + upper | lower + } else { + u.arbitrary()? + })), + ValType::Ref(ty) => { + assert!(ty.nullable); + Ok(Instruction::RefNull(ty.heap_type)) + } + } + } } pub(crate) fn arbitrary_limits32( @@ -2344,6 +2518,11 @@ pub(crate) fn arbitrary_memtype(u: &mut Unstructured, config: &Config) -> Result // We want to favor memories <= 1gb in size, allocate at most 16k pages, // depending on the maximum number of memories. let memory64 = config.memory64_enabled && u.arbitrary()?; + let page_size = if config.custom_page_sizes_enabled && u.arbitrary()? { + Some(1 << u.int_in_range(0..=16)?) + } else { + None + }; let max_inbounds = 16 * 1024 / u64::try_from(config.max_memories).unwrap(); let min_pages = if config.disallow_traps { Some(1) } else { None }; let max_pages = min_pages.unwrap_or(0).max(if memory64 { @@ -2363,6 +2542,7 @@ pub(crate) fn arbitrary_memtype(u: &mut Unstructured, config: &Config) -> Result maximum, memory64, shared, + page_size_log2: page_size, }) } diff --git a/third_party/rust/wasm-smith/src/core/code_builder.rs b/third_party/rust/wasm-smith/src/core/code_builder.rs index a55c5aafda..150572d930 100644 --- a/third_party/rust/wasm-smith/src/core/code_builder.rs +++ b/third_party/rust/wasm-smith/src/core/code_builder.rs @@ -870,6 +870,7 @@ impl CodeBuilderAllocations { module.globals.push(GlobalType { val_type: ty, mutable: true, + shared: false, }); module.defined_globals.push((global_idx, init)); @@ -1435,7 +1436,7 @@ impl CodeBuilder<'_> { } operands = &[]; } - instructions.push(arbitrary_val(*expected, u)); + instructions.push(module.arbitrary_const_instruction(*expected, u)?); } Ok(()) } @@ -1544,20 +1545,6 @@ impl CodeBuilder<'_> { } } -fn arbitrary_val(ty: ValType, u: &mut Unstructured<'_>) -> Instruction { - match ty { - ValType::I32 => Instruction::I32Const(u.arbitrary().unwrap_or(0)), - ValType::I64 => Instruction::I64Const(u.arbitrary().unwrap_or(0)), - ValType::F32 => Instruction::F32Const(u.arbitrary().unwrap_or(0.0)), - ValType::F64 => Instruction::F64Const(u.arbitrary().unwrap_or(0.0)), - ValType::V128 => Instruction::V128Const(u.arbitrary().unwrap_or(0)), - ValType::Ref(ty) => { - assert!(ty.nullable); - Instruction::RefNull(ty.heap_type) - } - } -} - #[inline] fn unreachable_valid(module: &Module, _: &mut CodeBuilder) -> bool { !module.config.disallow_traps @@ -1617,13 +1604,24 @@ fn try_table( let i = i as u32; let label_types = ctrl.label_types(); + + // Empty labels are candidates for a `catch_all` since nothing is + // pushed in that case. if label_types.is_empty() { catch_options.push(Box::new(move |_, _| Ok(Catch::All { label: i }))); } + + // Labels with just an `externref` are suitable for `catch_all_refs`, + // which first pushes nothing since there's no tag and then pushes + // the caught exception value. if label_types == [ValType::EXNREF] { catch_options.push(Box::new(move |_, _| Ok(Catch::AllRef { label: i }))); } + // If there is a tag which exactly matches the types of the label we're + // looking at then that tag can be used as part of a `catch` branch. + // That tag's parameters, which are the except values, are pushed + // for the label. if builder.allocs.tags.contains_key(label_types) { let label_types = label_types.to_vec(); catch_options.push(Box::new(move |u, builder| { @@ -1634,15 +1632,20 @@ fn try_table( })); } - let mut label_types_with_exnref = label_types.to_vec(); - label_types_with_exnref.push(ValType::EXNREF); - if builder.allocs.tags.contains_key(&label_types_with_exnref) { - catch_options.push(Box::new(move |u, builder| { - Ok(Catch::OneRef { - tag: *u.choose(&builder.allocs.tags[&label_types_with_exnref])?, - label: i, - }) - })); + // And finally the last type of catch label, `catch_ref`. If the label + // ends with `exnref`, then use everything except the last `exnref` to + // see if there's a matching tag. If so then `catch_ref` can be used + // with that tag when branching to this label. + if let Some((&ValType::EXNREF, rest)) = label_types.split_last() { + if builder.allocs.tags.contains_key(rest) { + let rest = rest.to_vec(); + catch_options.push(Box::new(move |u, builder| { + Ok(Catch::OneRef { + tag: *u.choose(&builder.allocs.tags[&rest])?, + label: i, + }) + })); + } } } @@ -3403,49 +3406,45 @@ fn data_drop( fn i32_const( u: &mut Unstructured, - _module: &Module, + module: &Module, builder: &mut CodeBuilder, instructions: &mut Vec, ) -> Result<()> { - let x = u.arbitrary()?; builder.push_operands(&[ValType::I32]); - instructions.push(Instruction::I32Const(x)); + instructions.push(module.arbitrary_const_instruction(ValType::I32, u)?); Ok(()) } fn i64_const( u: &mut Unstructured, - _module: &Module, + module: &Module, builder: &mut CodeBuilder, instructions: &mut Vec, ) -> Result<()> { - let x = u.arbitrary()?; builder.push_operands(&[ValType::I64]); - instructions.push(Instruction::I64Const(x)); + instructions.push(module.arbitrary_const_instruction(ValType::I64, u)?); Ok(()) } fn f32_const( u: &mut Unstructured, - _module: &Module, + module: &Module, builder: &mut CodeBuilder, instructions: &mut Vec, ) -> Result<()> { - let x = u.arbitrary()?; builder.push_operands(&[ValType::F32]); - instructions.push(Instruction::F32Const(x)); + instructions.push(module.arbitrary_const_instruction(ValType::F32, u)?); Ok(()) } fn f64_const( u: &mut Unstructured, - _module: &Module, + module: &Module, builder: &mut CodeBuilder, instructions: &mut Vec, ) -> Result<()> { - let x = u.arbitrary()?; builder.push_operands(&[ValType::F64]); - instructions.push(Instruction::F64Const(x)); + instructions.push(module.arbitrary_const_instruction(ValType::F64, u)?); Ok(()) } @@ -5204,10 +5203,12 @@ fn memory_offset(u: &mut Unstructured, module: &Module, memory_index: u32) -> Re assert!(a + b + c != 0); let memory_type = &module.memories[memory_index as usize]; - let min = memory_type.minimum.saturating_mul(65536); + let min = memory_type + .minimum + .saturating_mul(crate::page_size(memory_type).into()); let max = memory_type .maximum - .map(|max| max.saturating_mul(65536)) + .map(|max| max.saturating_mul(crate::page_size(memory_type).into())) .unwrap_or(u64::MAX); let (min, max, true_max) = match (memory_type.memory64, module.config.disallow_traps) { diff --git a/third_party/rust/wasm-smith/src/core/code_builder/no_traps.rs b/third_party/rust/wasm-smith/src/core/code_builder/no_traps.rs index 4f8b31ca9f..5ced1fa391 100644 --- a/third_party/rust/wasm-smith/src/core/code_builder/no_traps.rs +++ b/third_party/rust/wasm-smith/src/core/code_builder/no_traps.rs @@ -37,7 +37,10 @@ pub(crate) fn load<'a>( // [] insts.push(Instruction::MemorySize(memarg.memory_index)); // [mem_size_in_pages:address_type] - insts.push(int_const_inst(address_type, 65_536)); + insts.push(int_const_inst( + address_type, + crate::page_size(memory).into(), + )); // [mem_size_in_pages:address_type wasm_page_size:address_type] insts.push(int_mul_inst(address_type)); // [mem_size_in_bytes:address_type] @@ -116,7 +119,10 @@ pub(crate) fn store<'a>( // [] insts.push(Instruction::MemorySize(memarg.memory_index)); // [mem_size_in_pages:address_type] - insts.push(int_const_inst(address_type, 65_536)); + insts.push(int_const_inst( + address_type, + crate::page_size(memory).into(), + )); // [mem_size_in_pages:address_type wasm_page_size:address_type] insts.push(int_mul_inst(address_type)); // [mem_size_in_bytes:address_type] diff --git a/third_party/rust/wasm-smith/src/core/terminate.rs b/third_party/rust/wasm-smith/src/core/terminate.rs index 7983c35be6..33aff2639c 100644 --- a/third_party/rust/wasm-smith/src/core/terminate.rs +++ b/third_party/rust/wasm-smith/src/core/terminate.rs @@ -23,6 +23,7 @@ impl Module { self.globals.push(GlobalType { val_type: ValType::I32, mutable: true, + shared: false, }); self.defined_globals .push((fuel_global, ConstExpr::i32_const(default_fuel as i32))); diff --git a/third_party/rust/wasm-smith/src/lib.rs b/third_party/rust/wasm-smith/src/lib.rs index b985791aae..59d4ddb640 100644 --- a/third_party/rust/wasm-smith/src/lib.rs +++ b/third_party/rust/wasm-smith/src/lib.rs @@ -63,10 +63,16 @@ use arbitrary::{Result, Unstructured}; pub use component::Component; pub use config::{Config, MemoryOffsetChoices}; use std::{collections::HashSet, fmt::Write, str}; +use wasm_encoder::MemoryType; #[cfg(feature = "_internal_cli")] pub use config::InternalOptionalConfig; +pub(crate) fn page_size(mem: &MemoryType) -> u32 { + const DEFAULT_WASM_PAGE_SIZE: u32 = 65_536; + mem.page_size_log2.unwrap_or(DEFAULT_WASM_PAGE_SIZE) +} + /// Do something an arbitrary number of times. /// /// The callback can return `false` to exit the loop early. diff --git a/third_party/rust/wasm-smith/tests/common/mod.rs b/third_party/rust/wasm-smith/tests/common/mod.rs index cc24eed278..8a238776d6 100644 --- a/third_party/rust/wasm-smith/tests/common/mod.rs +++ b/third_party/rust/wasm-smith/tests/common/mod.rs @@ -2,30 +2,34 @@ use wasm_smith::Config; use wasmparser::{types::Types, Validator, WasmFeatures}; pub fn parser_features_from_config(config: &Config) -> WasmFeatures { - WasmFeatures { - mutable_global: true, - saturating_float_to_int: config.saturating_float_to_int_enabled, - sign_extension: config.sign_extension_ops_enabled, - reference_types: config.reference_types_enabled, - multi_value: config.multi_value_enabled, - bulk_memory: config.bulk_memory_enabled, - simd: config.simd_enabled, - relaxed_simd: config.relaxed_simd_enabled, - multi_memory: config.max_memories > 1, - exceptions: config.exceptions_enabled, - memory64: config.memory64_enabled, - tail_call: config.tail_call_enabled, - function_references: config.gc_enabled, - gc: config.gc_enabled, - - threads: false, - floats: true, - extended_const: false, - component_model: false, - memory_control: false, - component_model_values: false, - component_model_nested_names: false, - } + let mut features = WasmFeatures::MUTABLE_GLOBAL | WasmFeatures::FLOATS; + features.set( + WasmFeatures::SATURATING_FLOAT_TO_INT, + config.saturating_float_to_int_enabled, + ); + features.set( + WasmFeatures::SIGN_EXTENSION, + config.sign_extension_ops_enabled, + ); + features.set( + WasmFeatures::REFERENCE_TYPES, + config.reference_types_enabled, + ); + features.set(WasmFeatures::MULTI_VALUE, config.multi_value_enabled); + features.set(WasmFeatures::BULK_MEMORY, config.bulk_memory_enabled); + features.set(WasmFeatures::SIMD, config.simd_enabled); + features.set(WasmFeatures::RELAXED_SIMD, config.relaxed_simd_enabled); + features.set(WasmFeatures::MULTI_MEMORY, config.max_memories > 1); + features.set(WasmFeatures::EXCEPTIONS, config.exceptions_enabled); + features.set(WasmFeatures::MEMORY64, config.memory64_enabled); + features.set(WasmFeatures::TAIL_CALL, config.tail_call_enabled); + features.set(WasmFeatures::FUNCTION_REFERENCES, config.gc_enabled); + features.set(WasmFeatures::GC, config.gc_enabled); + features.set( + WasmFeatures::CUSTOM_PAGE_SIZES, + config.custom_page_sizes_enabled, + ); + features } pub fn validate(validator: &mut Validator, bytes: &[u8]) -> Types { diff --git a/third_party/rust/wasm-smith/tests/component.rs b/third_party/rust/wasm-smith/tests/component.rs index 7d5a40159c..89fdebffaa 100644 --- a/third_party/rust/wasm-smith/tests/component.rs +++ b/third_party/rust/wasm-smith/tests/component.rs @@ -18,11 +18,9 @@ fn smoke_test_component() { ok_count += 1; let component = component.to_bytes(); - let mut validator = - wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { - component_model: true, - ..Default::default() - }); + let mut validator = wasmparser::Validator::new_with_features( + wasmparser::WasmFeatures::default() | wasmparser::WasmFeatures::COMPONENT_MODEL, + ); if let Err(e) = validator.validate_all(&component) { std::fs::write("component.wasm", &component).unwrap(); panic!( diff --git a/third_party/rust/wasm-smith/tests/core.rs b/third_party/rust/wasm-smith/tests/core.rs index 7286952dc6..9b18fcdeaf 100644 --- a/third_party/rust/wasm-smith/tests/core.rs +++ b/third_party/rust/wasm-smith/tests/core.rs @@ -3,6 +3,9 @@ use rand::{rngs::SmallRng, RngCore, SeedableRng}; use wasm_smith::{Config, Module}; use wasmparser::{Validator, WasmFeatures}; +mod common; +use common::{parser_features_from_config, validate}; + #[test] fn smoke_test_module() { let mut rng = SmallRng::seed_from_u64(0); @@ -66,7 +69,7 @@ fn multi_value_disabled() { if let Ok(module) = Module::new(cfg, &mut u) { let wasm_bytes = module.to_bytes(); let mut features = wasm_features(); - features.multi_value = false; + features.remove(WasmFeatures::MULTI_VALUE); let mut validator = Validator::new_with_features(features); validate(&mut validator, &wasm_bytes); } @@ -140,53 +143,5 @@ fn smoke_test_wasm_gc() { } fn wasm_features() -> WasmFeatures { - WasmFeatures { - multi_memory: true, - relaxed_simd: true, - memory64: true, - exceptions: true, - tail_call: true, - function_references: true, - gc: true, - ..WasmFeatures::default() - } -} - -fn parser_features_from_config(config: &Config) -> WasmFeatures { - WasmFeatures { - mutable_global: true, - saturating_float_to_int: config.saturating_float_to_int_enabled, - sign_extension: config.sign_extension_ops_enabled, - reference_types: config.reference_types_enabled, - multi_value: config.multi_value_enabled, - bulk_memory: config.bulk_memory_enabled, - simd: config.simd_enabled, - relaxed_simd: config.relaxed_simd_enabled, - multi_memory: config.max_memories > 1, - exceptions: config.exceptions_enabled, - memory64: config.memory64_enabled, - tail_call: config.tail_call_enabled, - - threads: false, - floats: true, - extended_const: false, - component_model: false, - function_references: false, - memory_control: false, - gc: false, - component_model_values: false, - component_model_nested_names: false, - } -} - -fn validate(validator: &mut Validator, bytes: &[u8]) { - let err = match validator.validate_all(bytes) { - Ok(_) => return, - Err(e) => e, - }; - drop(std::fs::write("test.wasm", &bytes)); - if let Ok(text) = wasmprinter::print_bytes(bytes) { - drop(std::fs::write("test.wat", &text)); - } - panic!("wasm failed to validate: {}", err); + WasmFeatures::all() } diff --git a/third_party/rust/wasm-smith/tests/exports.rs b/third_party/rust/wasm-smith/tests/exports.rs index ff1dac0cbe..6d3e4451a2 100644 --- a/third_party/rust/wasm-smith/tests/exports.rs +++ b/third_party/rust/wasm-smith/tests/exports.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "wasmparser")] + use arbitrary::{Arbitrary, Unstructured}; use rand::{rngs::SmallRng, RngCore, SeedableRng}; use wasm_smith::{Config, Module}; @@ -18,9 +20,9 @@ enum ExportType { fn smoke_test_single_export() { let test = r#" (module - (func (export "foo") (param i32) (result i64) - unreachable - ) + (func (export "foo") (param i32) (result i64) + unreachable + ) ) "#; smoke_test_exports(test, 11) @@ -30,15 +32,15 @@ fn smoke_test_single_export() { fn smoke_test_multiple_exports() { let test = r#" (module - (func (export "a") (param i32) (result i64) - unreachable - ) - (func (export "b") - unreachable - ) - (func (export "c") - unreachable - ) + (func (export "a") (param i32) (result i64) + unreachable + ) + (func (export "b") + unreachable + ) + (func (export "c") + unreachable + ) ) "#; smoke_test_exports(test, 12) @@ -48,9 +50,9 @@ fn smoke_test_multiple_exports() { fn smoke_test_exported_global() { let test = r#" (module - (func (export "a") (param i32 i32 f32 f64) (result f32) - unreachable - ) + (func (export "a") (param i32 i32 f32 f64) (result f32) + unreachable + ) (global (export "glob") f64 f64.const 0) ) "#; diff --git a/third_party/rust/wast/.cargo-checksum.json b/third_party/rust/wast/.cargo-checksum.json index 3852650553..98ffcfa204 100644 --- a/third_party/rust/wast/.cargo-checksum.json +++ b/third_party/rust/wast/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"53d3c5b19092b2144bdfe0d4cd843c2b42ce0fddfca703fd09fec319232468dc","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"5a0d2b894a3ac74ee2be74715a2f22c40a08520cb4ac59183f4e7356f34ac566","src/component.rs":"23a62f4f2774ccfaf60f68e9d9416e68ba203eea782ce0c39cf553ad293f1df4","src/component/alias.rs":"5ec26333e179dc3778dead489f1273815fe9c1c808ba6a7e60eff54072fad795","src/component/binary.rs":"02b07602dc755fd5cec95b6348dd919c75f368c16a81402072201cf911be5f0d","src/component/component.rs":"0c49ff1c1c4b8fe6d330eb41bce8ad176c7208c4178090b7325e9994e83c1f20","src/component/custom.rs":"f5b23c34b73a716a986fd999fc8d8c9e24c341e83292088fe83325cd82dab4f5","src/component/expand.rs":"71b2e23f50957b4a15d758df7f8651fdbaf5cf8f44fbfeb134b412318dbd8921","src/component/export.rs":"f51e824c839d8bb0884eca509622f376c8cce3335be324b2b25033af6216fd2a","src/component/func.rs":"4f69de6c38cc6fe77b638ed7d8000c8a170d7053a11a6585dcd5b4877a06804c","src/component/import.rs":"ffe6e4ab8f2cec68b1022c753135d675ab27ecd1315bd38517472ceaffd0610c","src/component/instance.rs":"e550a7ee9af092ae084dd41e2c0ae756b7dca8da4b91d672d90265a6a15dff83","src/component/item_ref.rs":"e9c426ccc0210dc0c37bb0448468f5f4d9e52656b72d4ff0f2dc65c89957fe60","src/component/module.rs":"d27a28199d1dea1c64294a514329a524432319288515b0a0e3091fa7d3a33f74","src/component/resolve.rs":"4bc58161f3e38499cf0d7fddcbaec875579e8c48e0f347f1c820db21b8aa2d86","src/component/types.rs":"c854a2df9613145c38720d41cda571d0d01408fc09789bd22740874628cbff99","src/component/wast.rs":"36f9440618be7755db0a2994e5ff14187392c25543cdde2069e4c69111a7f490","src/core.rs":"24b71d1ab2ad874c4e37b4dd709b6532989b60e6bc503194434f95029cc1cda7","src/core/binary.rs":"59462baaf8ccb7eb44a39721b71c3627c5ff2cf5e4f24c89a158c5372732f026","src/core/custom.rs":"edd6044b75d79ec873c28d803fb8dc9a53724f1bba474bcdef2bc77196e0a4d2","src/core/export.rs":"1322a120d9e1dd6f3aa1485ee0bbc4294961028ae8a7584a24170af5823b73b1","src/core/expr.rs":"c3b66daa6d2ad3f47d1d3c6a69bd1652d289e248ab3244e448f2fba7ea291b55","src/core/func.rs":"f87239645e45b7e40ecf7f8f2b707a7cfc0620cd2632cfdaca3cb155a06da732","src/core/global.rs":"dec0abecadd2fde9298acb729259deba1ef3c4733ae5afcb4fe8cd4a633f5349","src/core/import.rs":"602a13aed2fd5fa63e2562246586546199861df57f304c2906561ab77810cadd","src/core/memory.rs":"de66cc6d6a9238428ed39ea5dccfa5ff065b4f3ec96d6cfc8405cbb16742791d","src/core/module.rs":"2b608a3cfee4df1ceeefaa046863dc964172bd6f52f6678d96078091fae7657a","src/core/resolve/deinline_import_export.rs":"41226cb8c654e7ed5a22bdb774b3901c73bed52c23a4ed6f5d0302950e02c30b","src/core/resolve/mod.rs":"9b2680b00a1cafad2dbbfdac86aa1c135ea67203bbc4dee939302b27f4aff6d0","src/core/resolve/names.rs":"afa1df4d75555dd7235a117a3c7217d1ec774b062e3a7c98d7470447561c97af","src/core/resolve/types.rs":"ff34eed438539cd88ea6c2c51e49ed42eee0d8be566d40c799254bf08125cfa8","src/core/table.rs":"6b611622d7d4f83cbe8e1a82139937c0294996d5f8208ade0886d680d8ef0b5d","src/core/tag.rs":"8a3d4fcdb86dedd68cdaf25abd930ef52a461cf2a0e9393bb9cb6f425afaaf2e","src/core/types.rs":"608f59af8c41f83c0d6db41c03f187fd30d3f85a021540a5de522464b011d52a","src/core/wast.rs":"a7307f93fb20274f0c99952deeefb51c28d4afe017702ee75d96324285346442","src/encode.rs":"0b165176db54fb9136202c54180adabda843a88e5436b96c19be9d41623912a3","src/error.rs":"4526260299c7983696a49ffe30a80139beb0d081fa8f42decc5e3283b361b1cb","src/gensym.rs":"b5e02e34443085f01deb5b657e541be7dc5d6dc952304e434a0b08320ea6c185","src/lexer.rs":"bc65c4d71c6f16a55670585a31ee615c9fcfc40a4bfa165e020ed03a9a27930d","src/lib.rs":"3b1e7af5e618b9d3ac680e7f8e9b0114fedf502496fb0e62dc95d3dbc1633772","src/names.rs":"81d49fecbff3b2abbbc323595271f32d912f03cd55a5685b7216d7cead32c420","src/parser.rs":"fe6a3727c68c8075c38422de545eb189fd8f5747ca681f6704982ed5c8ea4476","src/token.rs":"d18c2f304ffbc017a3b0a7764daeb879a8c653c330cdb6b1eae431ae6c6dd14e","src/wast.rs":"af6e208c2a37028461a6ad9101967fbfa5c7fc343fe5eb6ecad54f948c74e15d","src/wat.rs":"6fd57cf40795fabe977bdae50913f0e75c3dad3a0c0ace95df2de4f92be8aaf5","tests/annotations.rs":"06294077550600f93a5a8c0d7e3ac38b47f00bb8933f9dc390ff31868e873afb","tests/comments.rs":"694e8a3467e9c837f723a43c729be0c6f6dfe3441ad9692759b1d55fd63055a2","tests/parse-fail.rs":"0f1d5dffd1e6145105571222096703c89c4f4a46e25c848faa730f731155ea1c","tests/parse-fail/bad-core-func-alias.wat":"b71372064c3fce9d4a616418605040fe5e1356030a709b798b4769d3619cbbfb","tests/parse-fail/bad-core-func-alias.wat.err":"bb63274c26d3a21209bad794767f48372834bdc10cfbebf568a0c65d52803c90","tests/parse-fail/bad-func-alias.wat":"237c07149e1e74afe3b991a1fee6acb63167c1ca8931341614c435000339b887","tests/parse-fail/bad-func-alias.wat.err":"4a4bfc691b06d20fdf71e1dbac04649a52c76787048415599978987d761308fa","tests/parse-fail/bad-index.wat":"d21489daeec3a35327dcc9e2ba2d0acdd05f4aeaff2272cca608fda4d2338497","tests/parse-fail/bad-index.wat.err":"dc11070de0c9160573006ea4e5fa3c4d28e71bc39b24b1938cf6ff3b03ea7154","tests/parse-fail/bad-name.wat":"e5ff5d410007779a0de6609ea4cc693f0e603d36a106b8f5098c1980dd9f8124","tests/parse-fail/bad-name.wat.err":"fb5638476c1b85d9d1919e3dbcb0f16f82d088a4a22d4a0c186d7b8ba6e1902b","tests/parse-fail/bad-name2.wat":"5a6a4d0c19e5f2e48d7cebf361aca9b9000b7ef0c652997b5bd0ffaadbd2ca8a","tests/parse-fail/bad-name2.wat.err":"129707cce45f1e3cfb3e2ca5c702182e16ca5eeb2dbb2edd0710b004a8e194a5","tests/parse-fail/bad-name3.wat":"c19133d738cc84e9174301f27d4050c216bda81c7e9918d03ac792b088f24a05","tests/parse-fail/bad-name3.wat.err":"84ea63d40a619a0782ec6e94fce63921188ab87b1c3875eacae0a371144ed83a","tests/parse-fail/block1.wat":"91e74b5c3b43be692e7a6ae74fbfa674c4b6197299eb61338c4eccf282b18f17","tests/parse-fail/block1.wat.err":"40a083ae496b41dee7002cc6a664c5db0c5e4d904ae03b815773a769c4493fca","tests/parse-fail/block2.wat":"a8c07b4c09d51f10a8ffdf19806586022552398701cd90eb6d09816d45df06e5","tests/parse-fail/block2.wat.err":"33c842ec5dd0f2fdd3a9ce8187dd98b45ceee48c12810802af809d05b9cd25e9","tests/parse-fail/block3.wat":"29739abfbabd7c55f00ddfbbb9ebd818b4a114ef2336d50514f0842f7e075905","tests/parse-fail/block3.wat.err":"fc667ae2e71a260f62a3c7393bc97272e7c0ff38b17594f4370847b8a5019060","tests/parse-fail/confusing-block-comment0.wat":"8f27c9d0d212bbb1862ea89ffd7cbeafde5dfd755d695c1ba696cd520aba1a1d","tests/parse-fail/confusing-block-comment0.wat.err":"b53cbaef7bcec3862c64e09c084b92cd61bd29b954125482b2d083db250cd9e2","tests/parse-fail/confusing-block-comment1.wat":"b1a0447c9a8eaab8938d15cd33bd4adbb8bb69c2d710209b604023991a4347cb","tests/parse-fail/confusing-block-comment1.wat.err":"2fc3b3e4f98416326e1e5ec034026301069b6a98fa24451bc7573e16b8cb3811","tests/parse-fail/confusing-block-comment2.wat":"e3f49c7a388fba81081beb25d87bbd7db0acce5dd8e3eaa04574905ed7ec420c","tests/parse-fail/confusing-block-comment2.wat.err":"2183231d6acd0b5a117f9aea747c3d5c12e758450a6cd74027bb954a3134cf19","tests/parse-fail/confusing-block-comment3.wat":"d83f89c582501eb8833e772b8462c8974984a2f7fbb80b1452dc399fac74e5ed","tests/parse-fail/confusing-block-comment3.wat.err":"8b2096a4833627905c63f49cdabe44be24336646578dcfbdc67e9bfb35cbc601","tests/parse-fail/confusing-block-comment4.wat":"b7c6c68844d918e9ef6dd5ab9c40c7de7b38f04f94fadad630eda4e596f3e0f8","tests/parse-fail/confusing-block-comment4.wat.err":"2f790cc511edfcd89a12c9207901be16039fc1a06a584d73095e77a52f861cd9","tests/parse-fail/confusing-block-comment5.wat":"a159808032638cc914fa80ac4354a68b0af4f435a09cbe3e2d577582e183eb0a","tests/parse-fail/confusing-block-comment5.wat.err":"6fe0d99894307442f83fe93beaa5da706e06c9bdaf8e39d7cbae4c4fffafcb94","tests/parse-fail/confusing-block-comment6.wat":"abe48bcba2587dca98bc80ddde4e813f94fbc8a3538704a0775ea85bca0f8466","tests/parse-fail/confusing-block-comment6.wat.err":"3c97b9bf1112bbb7335d7fe4be5befb6f91eea7bec7dd3e6b543792231003c56","tests/parse-fail/confusing-block-comment7.wat":"e125c416ea5fa0ac35a58295a83a6f345438e2d7ddc6a39bd76c8e89885b3f0e","tests/parse-fail/confusing-block-comment7.wat.err":"5c34528ff2019cd3f0b3df34fd42523c0b66120706321da2c88ec05793478d2e","tests/parse-fail/confusing-block-comment8.wat":"200cc4c0e5af21a25529d7a81633a03642cff807255d6cd72eb45cdccc605cec","tests/parse-fail/confusing-block-comment8.wat.err":"9b81237d150a784b71791eee88fb6264a8bd6412862660f7392945203809e517","tests/parse-fail/confusing-line-comment0.wat":"bcec4c5a1e52b3e392e07c6711c979aa8d7db8baaf2bcdf270ba16d1aa528d26","tests/parse-fail/confusing-line-comment0.wat.err":"41ec5a075dc6b73afe1aec6b3198c5c4ae3a1a900e1610115879058ce034d6f6","tests/parse-fail/confusing-line-comment1.wat":"a2afbcab00ec957dfd9e9bf21fa4238852247b27f0b054f4a00f6b172dddf853","tests/parse-fail/confusing-line-comment1.wat.err":"f19a645e6fb5cbd7a0dd2308732741edcf83dbae0ef62549972029856a9e7fc6","tests/parse-fail/confusing-line-comment2.wat":"7f2a68229d02aac56ec4dfccf139bf2d617a0e89430357b30444dc4239d8aa89","tests/parse-fail/confusing-line-comment2.wat.err":"08add3d33e10e1ab6b4f3ae431f5db61d6f6c0a2b7d6828482a1e51b3a2d3851","tests/parse-fail/confusing-line-comment3.wat":"61173ae54782f6de86685f9555ffb94bbe2cf20b234daf660abb69ba3326f1ff","tests/parse-fail/confusing-line-comment3.wat.err":"4a5333dc02efa3c1eeab9cafa7c707f78abe92defdb01a71d6fe20944e4785f0","tests/parse-fail/confusing-line-comment4.wat":"9ecbbbe82c750e6475af1bfb46fe7a06115e4446a437d19fc08ca3d002f2a1c9","tests/parse-fail/confusing-line-comment4.wat.err":"ddb8aee8006265253b09c313cf5eb5c2dc4da66f502b4f6d3e2e1de77b35aec9","tests/parse-fail/confusing-line-comment5.wat":"8a4c8d342111bc9d37c16dbdf67c52027e1a42632abc9f359b3e4f07a85748b5","tests/parse-fail/confusing-line-comment5.wat.err":"34e368719fc0eab2f1a43c9f8e6f1b31aa9be9f971085d72374e49bde39cbfe5","tests/parse-fail/confusing-line-comment6.wat":"15f0dcdec23736ce92db84b3a7cdfe8689c97f2a7d0b9b0bfb0dcd2675163ed1","tests/parse-fail/confusing-line-comment6.wat.err":"0570be2ede803f071925d249f3858d3a417b5a6d678c9da40fc851d788d12983","tests/parse-fail/confusing-line-comment7.wat":"c7ee59301a701dd52d56cad02df78b0ad3584460bc18efa42ee137fe0c35aef6","tests/parse-fail/confusing-line-comment7.wat.err":"feebbeee8c85d8b3b85cec89435ae18f3ade9f754ca180d747a41406b64ca07a","tests/parse-fail/confusing-line-comment8.wat":"17632a8142154624de88b3cf93516147ed3419d785200bcd7049499eca8e8f04","tests/parse-fail/confusing-line-comment8.wat.err":"9c209285f2295cd2bc999aa7a9534a654932493308ab1f102839ed15a4d04d17","tests/parse-fail/confusing-string0.wat":"497b679b32baddcd6a158f4cadd3d9a9dea3457bac2a8c2c3d4e09b7c2d80842","tests/parse-fail/confusing-string0.wat.err":"cb3d737f2319346675a038716694354cd3b272453daa8a96e32e9861a9277f7b","tests/parse-fail/confusing-string1.wat":"46654cbed1ea6aab5019aef3d20098a391e40dacafa1ad5e83bf4ec384109fce","tests/parse-fail/confusing-string1.wat.err":"de7e7da516dc6c244bd0e4f012577b69f0cacbcc10f727fadb4b50bb04e0e2b4","tests/parse-fail/confusing-string2.wat":"11938f217c14387c05312735130f00c91d9df2d3ff9df7f13395e0f2b81dad54","tests/parse-fail/confusing-string2.wat.err":"e7bd08b146a855d681fefaf9e0576a9c333a2d10044f8e268b916b22a54227c9","tests/parse-fail/confusing-string3.wat":"e0ca4903fcafb9a54a91cf99e5eac95d25c6d2eb67b076f88191ad396f839cb6","tests/parse-fail/confusing-string3.wat.err":"b88d5db9e445c798eb24f95b7661b9c0368934d27ee8208477cd1c99351b939a","tests/parse-fail/confusing-string4.wat":"3ee2aee7f77604d051519c6f1795634469c12e98ae347a98f0c8445eecf1ff3d","tests/parse-fail/confusing-string4.wat.err":"1edc65bb09d8d3eed6ff69e7d9a7a4b5941dc823fa3436fa375657510255f6f4","tests/parse-fail/confusing-string5.wat":"024e50943128840d53f17e31a9b9332ce4f0ee70a847a043015f435b1c3c6e76","tests/parse-fail/confusing-string5.wat.err":"a0f13ec40d596ea2d8b0c4292b0d28775a5116ab7e11d7de88b295d25428c661","tests/parse-fail/confusing-string6.wat":"79cf157e29319800d2652c5a7f3dc90e07ebe2145c9904a70fc12027cdee84b7","tests/parse-fail/confusing-string6.wat.err":"860555e7aa13e3de3639cc2a530d6a42b974b629c4659593e972cbb0f306abae","tests/parse-fail/confusing-string7.wat":"7d8e403766dfb4e569754160d31ed0f9a27f908ed6cff96be43ab3d37f5975d5","tests/parse-fail/confusing-string7.wat.err":"658b6a02ba6d769254485f35c20984e7135d914b4266929963d723f26a40be4a","tests/parse-fail/confusing-string8.wat":"5a9b222e578655d57ee6e9f19bc1ea8e29aa52d652975fac685213444ed6458f","tests/parse-fail/confusing-string8.wat.err":"9a4e1a510330c800a1df7966998ebc3cde931eda20b249e5360f5e9a905dce11","tests/parse-fail/inline1.wat":"4e9767d67207aace2ac5e6f63a30e7510e4aa245ba35420539509e2254470272","tests/parse-fail/inline1.wat.err":"0143017a9825e518baa6009bae2c8d63520051dedd3437705bbe36b038a57f41","tests/parse-fail/newline-in-string.wat":"5c01cf709544ade0a6cdfcc39a3836a3bc018b633dc42a6cd872b6defc763ea7","tests/parse-fail/newline-in-string.wat.err":"1504209cc37a78b2aee778f23eacf78606daf964cf7bff251f5700efcd27ffd7","tests/parse-fail/string1.wat":"620d46d585ce94b382b5fde628c1399f3e562014b7a44af46e92f7bd045ca86e","tests/parse-fail/string1.wat.err":"fc53f3a1c4a65d8f25e5af51dec7699f45cecba114ca9c7871781bc70f664320","tests/parse-fail/string10.wat":"f7409dd45e153a1b11cb23e38f4ed87da12bedde38f8f0ccfe91037b0a4d97bd","tests/parse-fail/string10.wat.err":"ce677db5e37e0ed81ca357ed6b5edb21d85c27303ee194855bea7a88457efb6a","tests/parse-fail/string11.wat":"f6e0400b8c6a2014efa1ac676c567e140d8f86b5f4d5129773e6d67af537b615","tests/parse-fail/string11.wat.err":"4c6a550d29eda38a4e1bf7a589596f11655dc779479d7b8d466cfc53f815a742","tests/parse-fail/string12.wat":"23e30070eef22271651cce096a801fc4f79f3c37343c88bb8d2fc99b32d3b8b9","tests/parse-fail/string12.wat.err":"b5ec59f2996b88b2ee157e22d1774dc3e36fc08ed5bfc621aea830d30f66f586","tests/parse-fail/string13.wat":"81a305b981159ee10e140749ea3220c9edaaff53605e63c21995de47382b5faf","tests/parse-fail/string13.wat.err":"959f26c6b54e0d367b51d11d1addd8a53b5b8ff3caf70ebdd46bbea8ccfa2418","tests/parse-fail/string14.wat":"c45c2cc9f7afbfbd4be8e513106d22f7e5e817091448576c6bdf0701b81d95dd","tests/parse-fail/string14.wat.err":"50b5bccba905ddbe275938edb7ed0b09a5ca53dcdad36a7ff736ce9bc8e7a338","tests/parse-fail/string15.wat":"b5e0d5ade40de53b2d767a132e28376bb8c7a6f6238c4d8c248ae717c41d7f1f","tests/parse-fail/string15.wat.err":"0e9fc502cc90f96d1f592a3f63369fd2a3574bc4a2345a70365dbb76804e870f","tests/parse-fail/string16.wat":"38c3688cee80a9d089d239aa06eb1d27c5364ad2bd270aca57d05997c20aa682","tests/parse-fail/string16.wat.err":"4274b3bbe4df4cf0373619b1fcd082d0c802990817d2aca26ed885168c80e489","tests/parse-fail/string2.wat":"1172964aed31537b8c466d1f045f3e756926e7b221f80b2aff4a9a6721ea0beb","tests/parse-fail/string2.wat.err":"4618d3b20a78a077337eb5d6cae14ac39d9853762f011fbd23cff8921618dbde","tests/parse-fail/string3.wat":"07e0fbcd6270c1db100917c151ee4ac3f935e4ee1b27bce3c453b22b4b74f4d6","tests/parse-fail/string3.wat.err":"08ffc6158a9e030b2e211d53bdb8aeacfd879815c7b284d6a83b030566e35928","tests/parse-fail/string4.wat":"c970da2051b0613bdd1de4664f10424e14f2ebabe604175d4fb9b763b37af577","tests/parse-fail/string4.wat.err":"406706594d305c560fabd66417ad4fc276939990b5e701bd9d13fc223d207219","tests/parse-fail/string5.wat":"386cf314bb05acdaaabdf4da1caf140167271a26bd08bf34c3a7427d4bc4431f","tests/parse-fail/string5.wat.err":"1e56b44a23a37b2b2ad05aa9dd7e1e18191b5cc22151f93bbcf9d618779a57bd","tests/parse-fail/string6.wat":"8f1fe2825ff96f2acee9130a7721f86fcc93c221baa9411bf1fb6f0870d38ccb","tests/parse-fail/string6.wat.err":"d55dfd84d94e893f167ae73b7a080aefb2bfb05cc8a1ec201c4d3066fb8549b4","tests/parse-fail/string7.wat":"b12f8c75313d7f834489d3c353422f90bc945b37139586446eda82e334a97cde","tests/parse-fail/string7.wat.err":"4cee0ca61992c249dd0faaf2529a073cf8deeb36111a3f69b43695e5682560a2","tests/parse-fail/string8.wat":"4c2e0e1f883bb4e8cba9313497ed792130e5848e62bde7716102788d7467be10","tests/parse-fail/string8.wat.err":"840c6def7c60dd7c2b7261549cab435ba78c9b3a937adf6d5d9595ff8af01c91","tests/parse-fail/string9.wat":"2b7670caed2b0688d535de6e4e416f35fa717cfbe096a6cc764a669085c8f52f","tests/parse-fail/string9.wat.err":"37b5a9c3af9631500f31f9e5e3efa821b8d96063c57d60fd01df6be6a5c323e1","tests/parse-fail/unbalanced.wat":"f664fbef53a0308f864ba496d38044eb90482636e32586512939d4930729f3fe","tests/parse-fail/unbalanced.wat.err":"aba579f7b836856e69afe05da8328aabe0643d94e369898e686aa7bb0b07e9c9","tests/recursive.rs":"ad8a2b07bf955121a7c9e326ed35f9b2bc56b440c8cc0bbde24d423a79945c1a"},"package":"1ef6e1ef34d7da3e2b374fd2b1a9c0227aff6cad596e1b24df9b58d0f6222faa"} \ No newline at end of file +{"files":{"Cargo.toml":"3e223e7ed5faa9b3eaf4893e03596e1e40688df9dc2e0863fc3c44e443d88ef9","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"5a0d2b894a3ac74ee2be74715a2f22c40a08520cb4ac59183f4e7356f34ac566","src/component.rs":"23a62f4f2774ccfaf60f68e9d9416e68ba203eea782ce0c39cf553ad293f1df4","src/component/alias.rs":"5ec26333e179dc3778dead489f1273815fe9c1c808ba6a7e60eff54072fad795","src/component/binary.rs":"310940e2c455129c5e2a4219e64fca51121755818269306f943792216810c8b2","src/component/component.rs":"0c49ff1c1c4b8fe6d330eb41bce8ad176c7208c4178090b7325e9994e83c1f20","src/component/custom.rs":"f5b23c34b73a716a986fd999fc8d8c9e24c341e83292088fe83325cd82dab4f5","src/component/expand.rs":"71b2e23f50957b4a15d758df7f8651fdbaf5cf8f44fbfeb134b412318dbd8921","src/component/export.rs":"f51e824c839d8bb0884eca509622f376c8cce3335be324b2b25033af6216fd2a","src/component/func.rs":"4f69de6c38cc6fe77b638ed7d8000c8a170d7053a11a6585dcd5b4877a06804c","src/component/import.rs":"ffe6e4ab8f2cec68b1022c753135d675ab27ecd1315bd38517472ceaffd0610c","src/component/instance.rs":"e550a7ee9af092ae084dd41e2c0ae756b7dca8da4b91d672d90265a6a15dff83","src/component/item_ref.rs":"e9c426ccc0210dc0c37bb0448468f5f4d9e52656b72d4ff0f2dc65c89957fe60","src/component/module.rs":"d27a28199d1dea1c64294a514329a524432319288515b0a0e3091fa7d3a33f74","src/component/resolve.rs":"6454c289407e9e0c904c4e27af0cc5a40fbcd9a0d874ac5a64475b08264d2f39","src/component/types.rs":"65b2250f147f8b132e7d13ee809cf72d4fa5ed26a55f1a35f1ef665421b7e750","src/component/wast.rs":"aa39db0ea0acd38744dc3cbd35903c9b00b5de90a5bfc8b76e6b6a7581d7c4c0","src/core.rs":"24b71d1ab2ad874c4e37b4dd709b6532989b60e6bc503194434f95029cc1cda7","src/core/binary.rs":"2e7e1145273582d149398991a26c8252a9b6e325be8c277ab597b3be581fc795","src/core/custom.rs":"edd6044b75d79ec873c28d803fb8dc9a53724f1bba474bcdef2bc77196e0a4d2","src/core/export.rs":"1322a120d9e1dd6f3aa1485ee0bbc4294961028ae8a7584a24170af5823b73b1","src/core/expr.rs":"e521d86433d30b0669a160a913e0638e3bb78d8233fa570173b75e04b56abe26","src/core/func.rs":"f87239645e45b7e40ecf7f8f2b707a7cfc0620cd2632cfdaca3cb155a06da732","src/core/global.rs":"dec0abecadd2fde9298acb729259deba1ef3c4733ae5afcb4fe8cd4a633f5349","src/core/import.rs":"602a13aed2fd5fa63e2562246586546199861df57f304c2906561ab77810cadd","src/core/memory.rs":"be4b5067c4febb0e5718186e59ffee69305b01801f3133730a9933e2e7193bc1","src/core/module.rs":"2b608a3cfee4df1ceeefaa046863dc964172bd6f52f6678d96078091fae7657a","src/core/resolve/deinline_import_export.rs":"696b58d4b4267210e6453b7617c521b57f8c768970b740665c5b475575fc2160","src/core/resolve/mod.rs":"9b2680b00a1cafad2dbbfdac86aa1c135ea67203bbc4dee939302b27f4aff6d0","src/core/resolve/names.rs":"d869983d60e36b432a38edf60f53900f230cc5ab6248d3368ced229e69a259f0","src/core/resolve/types.rs":"6099b59c44aec7879996d6cdcb0d0ac2e25991a52291c5b15ab23b8d7e07cde9","src/core/table.rs":"6b611622d7d4f83cbe8e1a82139937c0294996d5f8208ade0886d680d8ef0b5d","src/core/tag.rs":"8a3d4fcdb86dedd68cdaf25abd930ef52a461cf2a0e9393bb9cb6f425afaaf2e","src/core/types.rs":"1d4afbeb9ed8a465d9c727e5bdc5be798216505fc4034d3fef64859808ff6e0a","src/core/wast.rs":"dda114d05e1b1fcf65a1ca6124786261cf0b885eb61ad10ab258f80ff6dd2c2e","src/encode.rs":"0b165176db54fb9136202c54180adabda843a88e5436b96c19be9d41623912a3","src/error.rs":"4526260299c7983696a49ffe30a80139beb0d081fa8f42decc5e3283b361b1cb","src/gensym.rs":"b5e02e34443085f01deb5b657e541be7dc5d6dc952304e434a0b08320ea6c185","src/lexer.rs":"bc65c4d71c6f16a55670585a31ee615c9fcfc40a4bfa165e020ed03a9a27930d","src/lib.rs":"bcf1814d97dca75bbd6f49123f5811472a3ca1e93788dfe23cb079804e9294d0","src/names.rs":"81d49fecbff3b2abbbc323595271f32d912f03cd55a5685b7216d7cead32c420","src/parser.rs":"fe6a3727c68c8075c38422de545eb189fd8f5747ca681f6704982ed5c8ea4476","src/token.rs":"292d0cc8871990ba7a757d49edcbe5a9c94c346131f10df2ce517789f25e7fd8","src/wast.rs":"692dc20c1912acd2ed1db7427d305a5c9eab31dfc8675f037ffc475b6db15d58","src/wat.rs":"2ff97b6af77da19b0a8e0dfd136f58dbfa8247896c476726d1c9f88a3630cac2","tests/annotations.rs":"06294077550600f93a5a8c0d7e3ac38b47f00bb8933f9dc390ff31868e873afb","tests/comments.rs":"694e8a3467e9c837f723a43c729be0c6f6dfe3441ad9692759b1d55fd63055a2","tests/parse-fail.rs":"162023ac21f74ea856ec5916f4925a762d769b425eaf721c223c54b3efec6a53","tests/parse-fail/bad-core-func-alias.wat":"b71372064c3fce9d4a616418605040fe5e1356030a709b798b4769d3619cbbfb","tests/parse-fail/bad-core-func-alias.wat.err":"bb63274c26d3a21209bad794767f48372834bdc10cfbebf568a0c65d52803c90","tests/parse-fail/bad-func-alias.wat":"237c07149e1e74afe3b991a1fee6acb63167c1ca8931341614c435000339b887","tests/parse-fail/bad-func-alias.wat.err":"4a4bfc691b06d20fdf71e1dbac04649a52c76787048415599978987d761308fa","tests/parse-fail/bad-index.wat":"d21489daeec3a35327dcc9e2ba2d0acdd05f4aeaff2272cca608fda4d2338497","tests/parse-fail/bad-index.wat.err":"dc11070de0c9160573006ea4e5fa3c4d28e71bc39b24b1938cf6ff3b03ea7154","tests/parse-fail/bad-name.wat":"e5ff5d410007779a0de6609ea4cc693f0e603d36a106b8f5098c1980dd9f8124","tests/parse-fail/bad-name.wat.err":"fb5638476c1b85d9d1919e3dbcb0f16f82d088a4a22d4a0c186d7b8ba6e1902b","tests/parse-fail/bad-name2.wat":"5a6a4d0c19e5f2e48d7cebf361aca9b9000b7ef0c652997b5bd0ffaadbd2ca8a","tests/parse-fail/bad-name2.wat.err":"129707cce45f1e3cfb3e2ca5c702182e16ca5eeb2dbb2edd0710b004a8e194a5","tests/parse-fail/bad-name3.wat":"c19133d738cc84e9174301f27d4050c216bda81c7e9918d03ac792b088f24a05","tests/parse-fail/bad-name3.wat.err":"84ea63d40a619a0782ec6e94fce63921188ab87b1c3875eacae0a371144ed83a","tests/parse-fail/block1.wat":"91e74b5c3b43be692e7a6ae74fbfa674c4b6197299eb61338c4eccf282b18f17","tests/parse-fail/block1.wat.err":"40a083ae496b41dee7002cc6a664c5db0c5e4d904ae03b815773a769c4493fca","tests/parse-fail/block2.wat":"a8c07b4c09d51f10a8ffdf19806586022552398701cd90eb6d09816d45df06e5","tests/parse-fail/block2.wat.err":"33c842ec5dd0f2fdd3a9ce8187dd98b45ceee48c12810802af809d05b9cd25e9","tests/parse-fail/block3.wat":"29739abfbabd7c55f00ddfbbb9ebd818b4a114ef2336d50514f0842f7e075905","tests/parse-fail/block3.wat.err":"fc667ae2e71a260f62a3c7393bc97272e7c0ff38b17594f4370847b8a5019060","tests/parse-fail/confusing-block-comment0.wat":"8f27c9d0d212bbb1862ea89ffd7cbeafde5dfd755d695c1ba696cd520aba1a1d","tests/parse-fail/confusing-block-comment0.wat.err":"b53cbaef7bcec3862c64e09c084b92cd61bd29b954125482b2d083db250cd9e2","tests/parse-fail/confusing-block-comment1.wat":"b1a0447c9a8eaab8938d15cd33bd4adbb8bb69c2d710209b604023991a4347cb","tests/parse-fail/confusing-block-comment1.wat.err":"2fc3b3e4f98416326e1e5ec034026301069b6a98fa24451bc7573e16b8cb3811","tests/parse-fail/confusing-block-comment2.wat":"e3f49c7a388fba81081beb25d87bbd7db0acce5dd8e3eaa04574905ed7ec420c","tests/parse-fail/confusing-block-comment2.wat.err":"2183231d6acd0b5a117f9aea747c3d5c12e758450a6cd74027bb954a3134cf19","tests/parse-fail/confusing-block-comment3.wat":"d83f89c582501eb8833e772b8462c8974984a2f7fbb80b1452dc399fac74e5ed","tests/parse-fail/confusing-block-comment3.wat.err":"8b2096a4833627905c63f49cdabe44be24336646578dcfbdc67e9bfb35cbc601","tests/parse-fail/confusing-block-comment4.wat":"b7c6c68844d918e9ef6dd5ab9c40c7de7b38f04f94fadad630eda4e596f3e0f8","tests/parse-fail/confusing-block-comment4.wat.err":"2f790cc511edfcd89a12c9207901be16039fc1a06a584d73095e77a52f861cd9","tests/parse-fail/confusing-block-comment5.wat":"a159808032638cc914fa80ac4354a68b0af4f435a09cbe3e2d577582e183eb0a","tests/parse-fail/confusing-block-comment5.wat.err":"6fe0d99894307442f83fe93beaa5da706e06c9bdaf8e39d7cbae4c4fffafcb94","tests/parse-fail/confusing-block-comment6.wat":"abe48bcba2587dca98bc80ddde4e813f94fbc8a3538704a0775ea85bca0f8466","tests/parse-fail/confusing-block-comment6.wat.err":"3c97b9bf1112bbb7335d7fe4be5befb6f91eea7bec7dd3e6b543792231003c56","tests/parse-fail/confusing-block-comment7.wat":"e125c416ea5fa0ac35a58295a83a6f345438e2d7ddc6a39bd76c8e89885b3f0e","tests/parse-fail/confusing-block-comment7.wat.err":"5c34528ff2019cd3f0b3df34fd42523c0b66120706321da2c88ec05793478d2e","tests/parse-fail/confusing-block-comment8.wat":"200cc4c0e5af21a25529d7a81633a03642cff807255d6cd72eb45cdccc605cec","tests/parse-fail/confusing-block-comment8.wat.err":"9b81237d150a784b71791eee88fb6264a8bd6412862660f7392945203809e517","tests/parse-fail/confusing-line-comment0.wat":"bcec4c5a1e52b3e392e07c6711c979aa8d7db8baaf2bcdf270ba16d1aa528d26","tests/parse-fail/confusing-line-comment0.wat.err":"41ec5a075dc6b73afe1aec6b3198c5c4ae3a1a900e1610115879058ce034d6f6","tests/parse-fail/confusing-line-comment1.wat":"a2afbcab00ec957dfd9e9bf21fa4238852247b27f0b054f4a00f6b172dddf853","tests/parse-fail/confusing-line-comment1.wat.err":"f19a645e6fb5cbd7a0dd2308732741edcf83dbae0ef62549972029856a9e7fc6","tests/parse-fail/confusing-line-comment2.wat":"7f2a68229d02aac56ec4dfccf139bf2d617a0e89430357b30444dc4239d8aa89","tests/parse-fail/confusing-line-comment2.wat.err":"08add3d33e10e1ab6b4f3ae431f5db61d6f6c0a2b7d6828482a1e51b3a2d3851","tests/parse-fail/confusing-line-comment3.wat":"61173ae54782f6de86685f9555ffb94bbe2cf20b234daf660abb69ba3326f1ff","tests/parse-fail/confusing-line-comment3.wat.err":"4a5333dc02efa3c1eeab9cafa7c707f78abe92defdb01a71d6fe20944e4785f0","tests/parse-fail/confusing-line-comment4.wat":"9ecbbbe82c750e6475af1bfb46fe7a06115e4446a437d19fc08ca3d002f2a1c9","tests/parse-fail/confusing-line-comment4.wat.err":"ddb8aee8006265253b09c313cf5eb5c2dc4da66f502b4f6d3e2e1de77b35aec9","tests/parse-fail/confusing-line-comment5.wat":"8a4c8d342111bc9d37c16dbdf67c52027e1a42632abc9f359b3e4f07a85748b5","tests/parse-fail/confusing-line-comment5.wat.err":"34e368719fc0eab2f1a43c9f8e6f1b31aa9be9f971085d72374e49bde39cbfe5","tests/parse-fail/confusing-line-comment6.wat":"15f0dcdec23736ce92db84b3a7cdfe8689c97f2a7d0b9b0bfb0dcd2675163ed1","tests/parse-fail/confusing-line-comment6.wat.err":"0570be2ede803f071925d249f3858d3a417b5a6d678c9da40fc851d788d12983","tests/parse-fail/confusing-line-comment7.wat":"c7ee59301a701dd52d56cad02df78b0ad3584460bc18efa42ee137fe0c35aef6","tests/parse-fail/confusing-line-comment7.wat.err":"feebbeee8c85d8b3b85cec89435ae18f3ade9f754ca180d747a41406b64ca07a","tests/parse-fail/confusing-line-comment8.wat":"17632a8142154624de88b3cf93516147ed3419d785200bcd7049499eca8e8f04","tests/parse-fail/confusing-line-comment8.wat.err":"9c209285f2295cd2bc999aa7a9534a654932493308ab1f102839ed15a4d04d17","tests/parse-fail/confusing-string0.wat":"497b679b32baddcd6a158f4cadd3d9a9dea3457bac2a8c2c3d4e09b7c2d80842","tests/parse-fail/confusing-string0.wat.err":"cb3d737f2319346675a038716694354cd3b272453daa8a96e32e9861a9277f7b","tests/parse-fail/confusing-string1.wat":"46654cbed1ea6aab5019aef3d20098a391e40dacafa1ad5e83bf4ec384109fce","tests/parse-fail/confusing-string1.wat.err":"de7e7da516dc6c244bd0e4f012577b69f0cacbcc10f727fadb4b50bb04e0e2b4","tests/parse-fail/confusing-string2.wat":"11938f217c14387c05312735130f00c91d9df2d3ff9df7f13395e0f2b81dad54","tests/parse-fail/confusing-string2.wat.err":"e7bd08b146a855d681fefaf9e0576a9c333a2d10044f8e268b916b22a54227c9","tests/parse-fail/confusing-string3.wat":"e0ca4903fcafb9a54a91cf99e5eac95d25c6d2eb67b076f88191ad396f839cb6","tests/parse-fail/confusing-string3.wat.err":"b88d5db9e445c798eb24f95b7661b9c0368934d27ee8208477cd1c99351b939a","tests/parse-fail/confusing-string4.wat":"3ee2aee7f77604d051519c6f1795634469c12e98ae347a98f0c8445eecf1ff3d","tests/parse-fail/confusing-string4.wat.err":"1edc65bb09d8d3eed6ff69e7d9a7a4b5941dc823fa3436fa375657510255f6f4","tests/parse-fail/confusing-string5.wat":"024e50943128840d53f17e31a9b9332ce4f0ee70a847a043015f435b1c3c6e76","tests/parse-fail/confusing-string5.wat.err":"a0f13ec40d596ea2d8b0c4292b0d28775a5116ab7e11d7de88b295d25428c661","tests/parse-fail/confusing-string6.wat":"79cf157e29319800d2652c5a7f3dc90e07ebe2145c9904a70fc12027cdee84b7","tests/parse-fail/confusing-string6.wat.err":"860555e7aa13e3de3639cc2a530d6a42b974b629c4659593e972cbb0f306abae","tests/parse-fail/confusing-string7.wat":"7d8e403766dfb4e569754160d31ed0f9a27f908ed6cff96be43ab3d37f5975d5","tests/parse-fail/confusing-string7.wat.err":"658b6a02ba6d769254485f35c20984e7135d914b4266929963d723f26a40be4a","tests/parse-fail/confusing-string8.wat":"5a9b222e578655d57ee6e9f19bc1ea8e29aa52d652975fac685213444ed6458f","tests/parse-fail/confusing-string8.wat.err":"9a4e1a510330c800a1df7966998ebc3cde931eda20b249e5360f5e9a905dce11","tests/parse-fail/inline1.wat":"4e9767d67207aace2ac5e6f63a30e7510e4aa245ba35420539509e2254470272","tests/parse-fail/inline1.wat.err":"0143017a9825e518baa6009bae2c8d63520051dedd3437705bbe36b038a57f41","tests/parse-fail/newline-in-string.wat":"5c01cf709544ade0a6cdfcc39a3836a3bc018b633dc42a6cd872b6defc763ea7","tests/parse-fail/newline-in-string.wat.err":"1504209cc37a78b2aee778f23eacf78606daf964cf7bff251f5700efcd27ffd7","tests/parse-fail/string1.wat":"620d46d585ce94b382b5fde628c1399f3e562014b7a44af46e92f7bd045ca86e","tests/parse-fail/string1.wat.err":"fc53f3a1c4a65d8f25e5af51dec7699f45cecba114ca9c7871781bc70f664320","tests/parse-fail/string10.wat":"f7409dd45e153a1b11cb23e38f4ed87da12bedde38f8f0ccfe91037b0a4d97bd","tests/parse-fail/string10.wat.err":"ce677db5e37e0ed81ca357ed6b5edb21d85c27303ee194855bea7a88457efb6a","tests/parse-fail/string11.wat":"f6e0400b8c6a2014efa1ac676c567e140d8f86b5f4d5129773e6d67af537b615","tests/parse-fail/string11.wat.err":"4c6a550d29eda38a4e1bf7a589596f11655dc779479d7b8d466cfc53f815a742","tests/parse-fail/string12.wat":"23e30070eef22271651cce096a801fc4f79f3c37343c88bb8d2fc99b32d3b8b9","tests/parse-fail/string12.wat.err":"b5ec59f2996b88b2ee157e22d1774dc3e36fc08ed5bfc621aea830d30f66f586","tests/parse-fail/string13.wat":"81a305b981159ee10e140749ea3220c9edaaff53605e63c21995de47382b5faf","tests/parse-fail/string13.wat.err":"959f26c6b54e0d367b51d11d1addd8a53b5b8ff3caf70ebdd46bbea8ccfa2418","tests/parse-fail/string14.wat":"c45c2cc9f7afbfbd4be8e513106d22f7e5e817091448576c6bdf0701b81d95dd","tests/parse-fail/string14.wat.err":"50b5bccba905ddbe275938edb7ed0b09a5ca53dcdad36a7ff736ce9bc8e7a338","tests/parse-fail/string15.wat":"b5e0d5ade40de53b2d767a132e28376bb8c7a6f6238c4d8c248ae717c41d7f1f","tests/parse-fail/string15.wat.err":"0e9fc502cc90f96d1f592a3f63369fd2a3574bc4a2345a70365dbb76804e870f","tests/parse-fail/string16.wat":"38c3688cee80a9d089d239aa06eb1d27c5364ad2bd270aca57d05997c20aa682","tests/parse-fail/string16.wat.err":"4274b3bbe4df4cf0373619b1fcd082d0c802990817d2aca26ed885168c80e489","tests/parse-fail/string2.wat":"1172964aed31537b8c466d1f045f3e756926e7b221f80b2aff4a9a6721ea0beb","tests/parse-fail/string2.wat.err":"4618d3b20a78a077337eb5d6cae14ac39d9853762f011fbd23cff8921618dbde","tests/parse-fail/string3.wat":"07e0fbcd6270c1db100917c151ee4ac3f935e4ee1b27bce3c453b22b4b74f4d6","tests/parse-fail/string3.wat.err":"08ffc6158a9e030b2e211d53bdb8aeacfd879815c7b284d6a83b030566e35928","tests/parse-fail/string4.wat":"c970da2051b0613bdd1de4664f10424e14f2ebabe604175d4fb9b763b37af577","tests/parse-fail/string4.wat.err":"406706594d305c560fabd66417ad4fc276939990b5e701bd9d13fc223d207219","tests/parse-fail/string5.wat":"386cf314bb05acdaaabdf4da1caf140167271a26bd08bf34c3a7427d4bc4431f","tests/parse-fail/string5.wat.err":"1e56b44a23a37b2b2ad05aa9dd7e1e18191b5cc22151f93bbcf9d618779a57bd","tests/parse-fail/string6.wat":"8f1fe2825ff96f2acee9130a7721f86fcc93c221baa9411bf1fb6f0870d38ccb","tests/parse-fail/string6.wat.err":"d55dfd84d94e893f167ae73b7a080aefb2bfb05cc8a1ec201c4d3066fb8549b4","tests/parse-fail/string7.wat":"b12f8c75313d7f834489d3c353422f90bc945b37139586446eda82e334a97cde","tests/parse-fail/string7.wat.err":"4cee0ca61992c249dd0faaf2529a073cf8deeb36111a3f69b43695e5682560a2","tests/parse-fail/string8.wat":"4c2e0e1f883bb4e8cba9313497ed792130e5848e62bde7716102788d7467be10","tests/parse-fail/string8.wat.err":"840c6def7c60dd7c2b7261549cab435ba78c9b3a937adf6d5d9595ff8af01c91","tests/parse-fail/string9.wat":"2b7670caed2b0688d535de6e4e416f35fa717cfbe096a6cc764a669085c8f52f","tests/parse-fail/string9.wat.err":"37b5a9c3af9631500f31f9e5e3efa821b8d96063c57d60fd01df6be6a5c323e1","tests/parse-fail/unbalanced.wat":"f664fbef53a0308f864ba496d38044eb90482636e32586512939d4930729f3fe","tests/parse-fail/unbalanced.wat.err":"aba579f7b836856e69afe05da8328aabe0643d94e369898e686aa7bb0b07e9c9","tests/recursive.rs":"ad8a2b07bf955121a7c9e326ed35f9b2bc56b440c8cc0bbde24d423a79945c1a"},"package":"441a6a195b3b5245e26d450bbcc91366c6b652382a22f63cbe3c73240e13b2bb"} \ No newline at end of file diff --git a/third_party/rust/wast/Cargo.toml b/third_party/rust/wast/Cargo.toml index 7f2d159a8b..8c07c94112 100644 --- a/third_party/rust/wast/Cargo.toml +++ b/third_party/rust/wast/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "wast" -version = "201.0.0" +version = "205.0.0" authors = ["Alex Crichton "] description = """ Customizable Rust parsers for the WebAssembly Text formats WAT and WAST @@ -40,13 +40,13 @@ version = "2.4.1" version = "0.1.9" [dependencies.wasm-encoder] -version = "0.201.0" +version = "0.205.0" [dev-dependencies.anyhow] version = "1.0.58" -[dev-dependencies.rayon] -version = "1.3" +[dev-dependencies.libtest-mimic] +version = "0.7.0" [features] default = ["wasm-module"] diff --git a/third_party/rust/wast/src/component/binary.rs b/third_party/rust/wast/src/component/binary.rs index a57cc0f912..a04343269f 100644 --- a/third_party/rust/wast/src/component/binary.rs +++ b/third_party/rust/wast/src/component/binary.rs @@ -597,7 +597,7 @@ impl From> for wasm_encoder::HeapType { match r { core::HeapType::Func => Self::Func, core::HeapType::Extern => Self::Extern, - core::HeapType::Exn => { + core::HeapType::Exn | core::HeapType::NoExn => { todo!("encoding of exceptions proposal types not yet implemented") } core::HeapType::Concrete(Index::Num(i, _)) => Self::Concrete(i), @@ -640,11 +640,23 @@ impl From> for wasm_encoder::TableType { impl From for wasm_encoder::MemoryType { fn from(ty: core::MemoryType) -> Self { - let (minimum, maximum, memory64, shared) = match ty { - core::MemoryType::B32 { limits, shared } => { - (limits.min.into(), limits.max.map(Into::into), false, shared) - } - core::MemoryType::B64 { limits, shared } => (limits.min, limits.max, true, shared), + let (minimum, maximum, memory64, shared, page_size_log2) = match ty { + core::MemoryType::B32 { + limits, + shared, + page_size_log2, + } => ( + limits.min.into(), + limits.max.map(Into::into), + false, + shared, + page_size_log2, + ), + core::MemoryType::B64 { + limits, + shared, + page_size_log2, + } => (limits.min, limits.max, true, shared, page_size_log2), }; Self { @@ -652,6 +664,7 @@ impl From for wasm_encoder::MemoryType { maximum, memory64, shared, + page_size_log2, } } } @@ -661,6 +674,7 @@ impl From> for wasm_encoder::GlobalType { Self { val_type: ty.ty.into(), mutable: ty.mutable, + shared: ty.shared, } } } @@ -780,8 +794,8 @@ impl From for wasm_encoder::PrimitiveValType { PrimitiveValType::U32 => Self::U32, PrimitiveValType::S64 => Self::S64, PrimitiveValType::U64 => Self::U64, - PrimitiveValType::Float32 => Self::Float32, - PrimitiveValType::Float64 => Self::Float64, + PrimitiveValType::F32 => Self::F32, + PrimitiveValType::F64 => Self::F64, PrimitiveValType::Char => Self::Char, PrimitiveValType::String => Self::String, } diff --git a/third_party/rust/wast/src/component/resolve.rs b/third_party/rust/wast/src/component/resolve.rs index c0122ef73f..0f33df564a 100644 --- a/third_party/rust/wast/src/component/resolve.rs +++ b/third_party/rust/wast/src/component/resolve.rs @@ -531,7 +531,8 @@ impl<'a> Resolver<'a> { | core::HeapType::Struct | core::HeapType::None | core::HeapType::NoFunc - | core::HeapType::NoExtern => {} + | core::HeapType::NoExtern + | core::HeapType::NoExn => {} core::HeapType::Concrete(id) => { self.resolve_ns(id, Ns::Type)?; } diff --git a/third_party/rust/wast/src/component/types.rs b/third_party/rust/wast/src/component/types.rs index 72eced02a8..dc8a91fd6b 100644 --- a/third_party/rust/wast/src/component/types.rs +++ b/third_party/rust/wast/src/component/types.rs @@ -230,8 +230,8 @@ pub enum PrimitiveValType { U32, S64, U64, - Float32, - Float64, + F32, + F64, Char, String, } @@ -266,12 +266,18 @@ impl<'a> Parse<'a> for PrimitiveValType { } else if l.peek::()? { parser.parse::()?; Ok(Self::U64) + } else if l.peek::()? { + parser.parse::()?; + Ok(Self::F32) + } else if l.peek::()? { + parser.parse::()?; + Ok(Self::F64) } else if l.peek::()? { parser.parse::()?; - Ok(Self::Float32) + Ok(Self::F32) } else if l.peek::()? { parser.parse::()?; - Ok(Self::Float64) + Ok(Self::F64) } else if l.peek::()? { parser.parse::()?; Ok(Self::Char) @@ -297,6 +303,8 @@ impl Peek for PrimitiveValType { | Some(("u32", _)) | Some(("s64", _)) | Some(("u64", _)) + | Some(("f32", _)) + | Some(("f64", _)) | Some(("float32", _)) | Some(("float64", _)) | Some(("char", _)) diff --git a/third_party/rust/wast/src/component/wast.rs b/third_party/rust/wast/src/component/wast.rs index 72d8bf15bc..28f1ce267c 100644 --- a/third_party/rust/wast/src/component/wast.rs +++ b/third_party/rust/wast/src/component/wast.rs @@ -1,6 +1,6 @@ use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; -use crate::token::{Float32, Float64}; +use crate::token::{F32, F64}; /// Expression that can be used inside of `invoke` expressions for core wasm /// functions. @@ -16,8 +16,8 @@ pub enum WastVal<'a> { S32(i32), U64(u64), S64(i64), - Float32(Float32), - Float64(Float64), + F32(F32), + F64(F64), Char(char), String(&'a str), List(Vec>), @@ -53,8 +53,8 @@ static CASES: &[(&str, fn(Parser<'_>) -> Result>)] = { ("s32.const", |p| Ok(S32(p.parse()?))), ("u64.const", |p| Ok(U64(p.parse()?))), ("s64.const", |p| Ok(S64(p.parse()?))), - ("f32.const", |p| Ok(Float32(p.parse()?))), - ("f64.const", |p| Ok(Float64(p.parse()?))), + ("f32.const", |p| Ok(F32(p.parse()?))), + ("f64.const", |p| Ok(F64(p.parse()?))), ("char.const", |p| { let s = p.parse::<&str>()?; let mut ch = s.chars(); diff --git a/third_party/rust/wast/src/core/binary.rs b/third_party/rust/wast/src/core/binary.rs index da94da0241..769e120112 100644 --- a/third_party/rust/wast/src/core/binary.rs +++ b/third_party/rust/wast/src/core/binary.rs @@ -295,6 +295,7 @@ impl<'a> Encode for HeapType<'a> { HeapType::I31 => e.push(0x6c), HeapType::NoFunc => e.push(0x73), HeapType::NoExtern => e.push(0x72), + HeapType::NoExn => e.push(0x74), HeapType::None => e.push(0x71), // Note that this is encoded as a signed leb128 so be sure to cast // to an i64 first @@ -349,6 +350,11 @@ impl<'a> Encode for RefType<'a> { nullable: true, heap: HeapType::NoExtern, } => e.push(0x72), + // The 'nullexnref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::NoExn, + } => e.push(0x74), // The 'nullref' binary abbreviation RefType { nullable: true, @@ -466,25 +472,45 @@ impl Encode for Limits { impl Encode for MemoryType { fn encode(&self, e: &mut Vec) { match self { - MemoryType::B32 { limits, shared } => { + MemoryType::B32 { + limits, + shared, + page_size_log2, + } => { let flag_max = limits.max.is_some() as u8; let flag_shared = *shared as u8; - let flags = flag_max | (flag_shared << 1); + let flag_page_size = page_size_log2.is_some() as u8; + let flags = flag_max | (flag_shared << 1) | (flag_page_size << 3); e.push(flags); limits.min.encode(e); if let Some(max) = limits.max { max.encode(e); } + if let Some(p) = page_size_log2 { + p.encode(e); + } } - MemoryType::B64 { limits, shared } => { - let flag_max = limits.max.is_some() as u8; - let flag_shared = *shared as u8; - let flags = flag_max | (flag_shared << 1) | 0x04; + MemoryType::B64 { + limits, + shared, + page_size_log2, + } => { + let flag_max = limits.max.is_some(); + let flag_shared = *shared; + let flag_mem64 = true; + let flag_page_size = page_size_log2.is_some(); + let flags = ((flag_max as u8) << 0) + | ((flag_shared as u8) << 1) + | ((flag_mem64 as u8) << 2) + | ((flag_page_size as u8) << 3); e.push(flags); limits.min.encode(e); if let Some(max) = limits.max { max.encode(e); } + if let Some(p) = page_size_log2 { + p.encode(e); + } } } } @@ -493,11 +519,14 @@ impl Encode for MemoryType { impl<'a> Encode for GlobalType<'a> { fn encode(&self, e: &mut Vec) { self.ty.encode(e); + let mut flags = 0; if self.mutable { - e.push(0x01); - } else { - e.push(0x00); + flags |= 0b01; + } + if self.shared { + flags |= 0b10; } + e.push(flags); } } @@ -749,19 +778,6 @@ impl Encode for BlockType<'_> { } } -impl Encode for FuncBindType<'_> { - fn encode(&self, e: &mut Vec) { - self.ty.encode(e); - } -} - -impl Encode for LetType<'_> { - fn encode(&self, e: &mut Vec) { - self.block.encode(e); - self.locals.encode(e); - } -} - impl Encode for LaneArg { fn encode(&self, e: &mut Vec) { self.lane.encode(e); @@ -784,6 +800,23 @@ impl Encode for MemArg<'_> { } } +impl Encode for Ordering { + fn encode(&self, buf: &mut Vec) { + let flag: u8 = match self { + Ordering::SeqCst => 0, + Ordering::AcqRel => 1, + }; + flag.encode(buf); + } +} + +impl Encode for OrderedAccess<'_> { + fn encode(&self, buf: &mut Vec) { + self.ordering.encode(buf); + self.index.encode(buf); + } +} + impl Encode for LoadOrStoreLane<'_> { fn encode(&self, e: &mut Vec) { self.memarg.encode(e); @@ -845,13 +878,13 @@ impl Encode for BrTableIndices<'_> { } } -impl Encode for Float32 { +impl Encode for F32 { fn encode(&self, e: &mut Vec) { e.extend_from_slice(&self.bits.to_le_bytes()); } } -impl Encode for Float64 { +impl Encode for F64 { fn encode(&self, e: &mut Vec) { e.extend_from_slice(&self.bits.to_le_bytes()); } @@ -994,8 +1027,7 @@ fn find_names<'a>( | Instruction::Block(block) | Instruction::Loop(block) | Instruction::Try(block) - | Instruction::TryTable(TryTable { block, .. }) - | Instruction::Let(LetType { block, .. }) => { + | Instruction::TryTable(TryTable { block, .. }) => { if let Some(name) = get_name(&block.label, &block.label_name) { label_names.push((label_idx, name)); } diff --git a/third_party/rust/wast/src/core/expr.rs b/third_party/rust/wast/src/core/expr.rs index b45950b896..df0abb7cd0 100644 --- a/third_party/rust/wast/src/core/expr.rs +++ b/third_party/rust/wast/src/core/expr.rs @@ -184,7 +184,6 @@ impl<'a> ExpressionParser<'a> { // seen i @ Instruction::Block(_) | i @ Instruction::Loop(_) - | i @ Instruction::Let(_) | i @ Instruction::TryTable(_) => { self.instrs.push(i); self.stack.push(Level::EndWith(Instruction::End(None))); @@ -350,7 +349,7 @@ macro_rules! instructions { }) => ( /// A listing of all WebAssembly instructions that can be in a module /// that this crate currently parses. - #[derive(Debug)] + #[derive(Debug, Clone)] #[allow(missing_docs)] pub enum Instruction<'a> { $( @@ -468,8 +467,6 @@ instructions! { // function-references proposal CallRef(Index<'a>) : [0x14] : "call_ref", ReturnCallRef(Index<'a>) : [0x15] : "return_call_ref", - FuncBind(FuncBindType<'a>) : [0x16] : "func.bind", - Let(LetType<'a>) : [0x17] : "let", Drop : [0x1a] : "drop", Select(SelectTypes<'a>) : [] : "select", @@ -574,8 +571,8 @@ instructions! { I32Const(i32) : [0x41] : "i32.const", I64Const(i64) : [0x42] : "i64.const", - F32Const(Float32) : [0x43] : "f32.const", - F64Const(Float64) : [0x44] : "f64.const", + F32Const(F32) : [0x43] : "f32.const", + F64Const(F64) : [0x44] : "f64.const", I32Clz : [0x67] : "i32.clz", I32Ctz : [0x68] : "i32.ctz", @@ -803,6 +800,10 @@ instructions! { I64AtomicRmw16CmpxchgU(MemArg<2>) : [0xfe, 0x4d] : "i64.atomic.rmw16.cmpxchg_u", I64AtomicRmw32CmpxchgU(MemArg<4>) : [0xfe, 0x4e] : "i64.atomic.rmw32.cmpxchg_u", + // proposal: shared-everything-threads + GlobalAtomicGet(OrderedAccess<'a>) : [0xfe, 0x4f] : "global.atomic.get", + GlobalAtomicSet(OrderedAccess<'a>) : [0xfe, 0x50] : "global.atomic.set", + // proposal: simd // // https://webassembly.github.io/simd/core/binary/instructions.html @@ -1123,7 +1124,7 @@ impl<'a> Instruction<'a> { /// /// This is used to label blocks and also annotate what types are expected for /// the block. -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(missing_docs)] pub struct BlockType<'a> { pub label: Option>, @@ -1143,7 +1144,7 @@ impl<'a> Parse<'a> for BlockType<'a> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(missing_docs)] pub struct TryTable<'a> { pub block: Box>, @@ -1187,7 +1188,7 @@ impl<'a> Parse<'a> for TryTable<'a> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(missing_docs)] pub enum TryTableCatchKind<'a> { // Catch a tagged exception, do not capture an exnref. @@ -1210,50 +1211,16 @@ impl<'a> TryTableCatchKind<'a> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(missing_docs)] pub struct TryTableCatch<'a> { pub kind: TryTableCatchKind<'a>, pub label: Index<'a>, } -/// Extra information associated with the func.bind instruction. -#[derive(Debug)] -#[allow(missing_docs)] -pub struct FuncBindType<'a> { - pub ty: TypeUse<'a, FunctionType<'a>>, -} - -impl<'a> Parse<'a> for FuncBindType<'a> { - fn parse(parser: Parser<'a>) -> Result { - Ok(FuncBindType { - ty: parser - .parse::>>()? - .into(), - }) - } -} - -/// Extra information associated with the let instruction. -#[derive(Debug)] -#[allow(missing_docs)] -pub struct LetType<'a> { - pub block: Box>, - pub locals: Box<[Local<'a>]>, -} - -impl<'a> Parse<'a> for LetType<'a> { - fn parse(parser: Parser<'a>) -> Result { - Ok(LetType { - block: parser.parse()?, - locals: Local::parse_remainder(parser)?.into(), - }) - } -} - /// Extra information associated with the `br_table` instruction. #[allow(missing_docs)] -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BrTableIndices<'a> { pub labels: Vec>, pub default: Index<'a>, @@ -1271,7 +1238,7 @@ impl<'a> Parse<'a> for BrTableIndices<'a> { } /// Payload for lane-related instructions. Unsigned with no + prefix. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct LaneArg { /// The lane argument. pub lane: u8, @@ -1299,7 +1266,7 @@ impl<'a> Parse<'a> for LaneArg { /// Payload for memory-related instructions indicating offset/alignment of /// memory accesses. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MemArg<'a> { /// The alignment of this access. /// @@ -1374,7 +1341,7 @@ impl<'a> MemArg<'a> { } /// Extra data associated with the `loadN_lane` and `storeN_lane` instructions. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct LoadOrStoreLane<'a> { /// The memory argument for this instruction. pub memarg: MemArg<'a>, @@ -1428,7 +1395,7 @@ impl<'a> LoadOrStoreLane<'a> { } /// Extra data associated with the `call_indirect` instruction. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CallIndirect<'a> { /// The table that this call is going to be indexing. pub table: Index<'a>, @@ -1449,7 +1416,7 @@ impl<'a> Parse<'a> for CallIndirect<'a> { } /// Extra data associated with the `table.init` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TableInit<'a> { /// The index of the table we're copying into. pub table: Index<'a>, @@ -1471,7 +1438,7 @@ impl<'a> Parse<'a> for TableInit<'a> { } /// Extra data associated with the `table.copy` instruction. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TableCopy<'a> { /// The index of the destination table to copy into. pub dst: Index<'a>, @@ -1493,7 +1460,7 @@ impl<'a> Parse<'a> for TableCopy<'a> { } /// Extra data associated with unary table instructions. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TableArg<'a> { /// The index of the table argument. pub dst: Index<'a>, @@ -1511,7 +1478,7 @@ impl<'a> Parse<'a> for TableArg<'a> { } /// Extra data associated with unary memory instructions. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MemoryArg<'a> { /// The index of the memory space. pub mem: Index<'a>, @@ -1529,7 +1496,7 @@ impl<'a> Parse<'a> for MemoryArg<'a> { } /// Extra data associated with the `memory.init` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MemoryInit<'a> { /// The index of the data segment we're copying into memory. pub data: Index<'a>, @@ -1551,7 +1518,7 @@ impl<'a> Parse<'a> for MemoryInit<'a> { } /// Extra data associated with the `memory.copy` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MemoryCopy<'a> { /// The index of the memory we're copying from. pub src: Index<'a>, @@ -1573,7 +1540,7 @@ impl<'a> Parse<'a> for MemoryCopy<'a> { } /// Extra data associated with the `struct.get/set` instructions -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct StructAccess<'a> { /// The index of the struct type we're accessing. pub r#struct: Index<'a>, @@ -1591,7 +1558,7 @@ impl<'a> Parse<'a> for StructAccess<'a> { } /// Extra data associated with the `array.fill` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArrayFill<'a> { /// The index of the array type we're filling. pub array: Index<'a>, @@ -1606,7 +1573,7 @@ impl<'a> Parse<'a> for ArrayFill<'a> { } /// Extra data associated with the `array.copy` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArrayCopy<'a> { /// The index of the array type we're copying to. pub dest_array: Index<'a>, @@ -1624,7 +1591,7 @@ impl<'a> Parse<'a> for ArrayCopy<'a> { } /// Extra data associated with the `array.init_[data/elem]` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArrayInit<'a> { /// The index of the array type we're initializing. pub array: Index<'a>, @@ -1642,7 +1609,7 @@ impl<'a> Parse<'a> for ArrayInit<'a> { } /// Extra data associated with the `array.new_fixed` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArrayNewFixed<'a> { /// The index of the array type we're accessing. pub array: Index<'a>, @@ -1660,7 +1627,7 @@ impl<'a> Parse<'a> for ArrayNewFixed<'a> { } /// Extra data associated with the `array.new_data` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArrayNewData<'a> { /// The index of the array type we're accessing. pub array: Index<'a>, @@ -1678,7 +1645,7 @@ impl<'a> Parse<'a> for ArrayNewData<'a> { } /// Extra data associated with the `array.new_elem` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArrayNewElem<'a> { /// The index of the array type we're accessing. pub array: Index<'a>, @@ -1696,7 +1663,7 @@ impl<'a> Parse<'a> for ArrayNewElem<'a> { } /// Extra data associated with the `ref.cast` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RefCast<'a> { /// The type to cast to. pub r#type: RefType<'a>, @@ -1711,7 +1678,7 @@ impl<'a> Parse<'a> for RefCast<'a> { } /// Extra data associated with the `ref.test` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RefTest<'a> { /// The type to test for. pub r#type: RefType<'a>, @@ -1726,7 +1693,7 @@ impl<'a> Parse<'a> for RefTest<'a> { } /// Extra data associated with the `br_on_cast` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BrOnCast<'a> { /// The label to branch to. pub label: Index<'a>, @@ -1747,7 +1714,7 @@ impl<'a> Parse<'a> for BrOnCast<'a> { } /// Extra data associated with the `br_on_cast_fail` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BrOnCastFail<'a> { /// The label to branch to. pub label: Index<'a>, @@ -1767,16 +1734,65 @@ impl<'a> Parse<'a> for BrOnCastFail<'a> { } } +/// The memory ordering for atomic instructions. +/// +/// For an in-depth explanation of memory orderings, see the C++ documentation +/// for [`memory_order`] or the Rust documentation for [`atomic::Ordering`]. +/// +/// [`memory_order`]: https://en.cppreference.com/w/cpp/atomic/memory_order +/// [`atomic::Ordering`]: https://doc.rust-lang.org/std/sync/atomic/enum.Ordering.html +#[derive(Clone, Debug)] +pub enum Ordering { + /// Like `AcqRel` but all threads see all sequentially consistent operations + /// in the same order. + AcqRel, + /// For a load, it acquires; this orders all operations before the last + /// "releasing" store. For a store, it releases; this orders all operations + /// before it at the next "acquiring" load. + SeqCst, +} + +impl<'a> Parse<'a> for Ordering { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::()? { + parser.parse::()?; + Ok(Ordering::SeqCst) + } else if parser.peek::()? { + parser.parse::()?; + Ok(Ordering::AcqRel) + } else { + Err(parser.error("expected a memory ordering: `seq_cst` or `acq_rel`")) + } + } +} + +/// Extra data associated with the `global.atomic.*` instructions. +#[derive(Clone, Debug)] +pub struct OrderedAccess<'a> { + /// The memory ordering for this atomic instruction. + pub ordering: Ordering, + /// The index of the global to access. + pub index: Index<'a>, +} + +impl<'a> Parse<'a> for OrderedAccess<'a> { + fn parse(parser: Parser<'a>) -> Result { + let ordering = parser.parse()?; + let index = parser.parse()?; + Ok(OrderedAccess { ordering, index }) + } +} + /// Different ways to specify a `v128.const` instruction -#[derive(Debug)] +#[derive(Clone, Debug)] #[allow(missing_docs)] pub enum V128Const { I8x16([i8; 16]), I16x8([i16; 8]), I32x4([i32; 4]), I64x2([i64; 2]), - F32x4([Float32; 4]), - F64x2([Float64; 2]), + F32x4([F32; 4]), + F64x2([F64; 2]), } impl V128Const { @@ -1934,7 +1950,7 @@ impl<'a> Parse<'a> for V128Const { } /// Lanes being shuffled in the `i8x16.shuffle` instruction -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct I8x16Shuffle { #[allow(missing_docs)] pub lanes: [u8; 16], @@ -1966,7 +1982,7 @@ impl<'a> Parse<'a> for I8x16Shuffle { } /// Payload of the `select` instructions -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SelectTypes<'a> { #[allow(missing_docs)] pub tys: Option>>, diff --git a/third_party/rust/wast/src/core/memory.rs b/third_party/rust/wast/src/core/memory.rs index eb1baa1a95..5f5f051109 100644 --- a/third_party/rust/wast/src/core/memory.rs +++ b/third_party/rust/wast/src/core/memory.rs @@ -59,7 +59,10 @@ impl<'a> Parse<'a> for Memory<'a> { import, ty: parser.parse()?, } - } else if l.peek::()? || parser.peek2::()? { + } else if l.peek::()? + || ((parser.peek::()? || parser.peek::()?) + && parser.peek2::()?) + { let is_32 = if parser.parse::>()?.is_some() { true } else { @@ -133,7 +136,7 @@ impl<'a> Parse<'a> for Data<'a> { let id = parser.parse()?; let name = parser.parse()?; - let kind = if parser.peek::<&[u8]>()? { + let kind = if parser.peek::<&[u8]>()? || parser.peek::()? { DataKind::Passive // ... and otherwise we must be attached to a particular memory as well @@ -248,8 +251,8 @@ impl<'a> Parse<'a> for DataVal<'a> { || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? - || consume::(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))? - || consume::(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))? + || consume::(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))? + || consume::(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))? || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? { Ok(DataVal::Integral(result)) diff --git a/third_party/rust/wast/src/core/resolve/deinline_import_export.rs b/third_party/rust/wast/src/core/resolve/deinline_import_export.rs index 98e680b58a..f2d12e9a52 100644 --- a/third_party/rust/wast/src/core/resolve/deinline_import_export.rs +++ b/third_party/rust/wast/src/core/resolve/deinline_import_export.rs @@ -50,7 +50,7 @@ pub fn run(fields: &mut Vec) { // field here instead, switching this to a `Normal` memory. MemoryKind::Inline { is_32, ref data } => { let len = data.iter().map(|l| l.len()).sum::() as u32; - let pages = (len + page_size() - 1) / page_size(); + let pages = (len + default_page_size() - 1) / default_page_size(); let kind = MemoryKind::Normal(if is_32 { MemoryType::B32 { limits: Limits { @@ -58,6 +58,7 @@ pub fn run(fields: &mut Vec) { max: Some(pages), }, shared: false, + page_size_log2: None, } } else { MemoryType::B64 { @@ -66,6 +67,7 @@ pub fn run(fields: &mut Vec) { max: Some(u64::from(pages)), }, shared: false, + page_size_log2: None, } }); let data = match mem::replace(&mut m.kind, kind) { @@ -212,7 +214,7 @@ pub fn run(fields: &mut Vec) { fields.push(item); } - fn page_size() -> u32 { + fn default_page_size() -> u32 { 1 << 16 } } diff --git a/third_party/rust/wast/src/core/resolve/names.rs b/third_party/rust/wast/src/core/resolve/names.rs index 05894e9a1e..f17590bbd1 100644 --- a/third_party/rust/wast/src/core/resolve/names.rs +++ b/third_party/rust/wast/src/core/resolve/names.rs @@ -457,6 +457,10 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.resolve(i, Ns::Global)?; } + GlobalAtomicSet(i) | GlobalAtomicGet(i) => { + self.resolver.resolve(&mut i.index, Ns::Global)?; + } + LocalSet(i) | LocalGet(i) | LocalTee(i) => { assert!(self.scopes.len() > 0); // Resolve a local by iterating over scopes from most recent @@ -490,30 +494,6 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.resolve(i, Ns::Type)?; } - FuncBind(b) => { - self.resolver.resolve_type_use(&mut b.ty)?; - } - - Let(t) => { - // Resolve (ref T) in locals - for local in t.locals.iter_mut() { - self.resolver.resolve_valtype(&mut local.ty)?; - } - - // Register all locals defined in this let - let mut scope = Namespace::default(); - for local in t.locals.iter() { - scope.register(local.id, "local")?; - } - self.scopes.push(scope); - self.blocks.push(ExprBlock { - label: t.block.label, - pushed_scope: true, - }); - - self.resolve_block_type(&mut t.block)?; - } - Block(bt) | If(bt) | Loop(bt) | Try(bt) => { self.blocks.push(ExprBlock { label: bt.label, diff --git a/third_party/rust/wast/src/core/resolve/types.rs b/third_party/rust/wast/src/core/resolve/types.rs index bfb996b4b6..84b0e516e4 100644 --- a/third_party/rust/wast/src/core/resolve/types.rs +++ b/third_party/rust/wast/src/core/resolve/types.rs @@ -139,7 +139,6 @@ impl<'a> Expander<'a> { Instruction::Block(bt) | Instruction::If(bt) | Instruction::Loop(bt) - | Instruction::Let(LetType { block: bt, .. }) | Instruction::Try(bt) | Instruction::TryTable(TryTable { block: bt, .. }) => { // No expansion necessary, a type reference is already here. @@ -174,9 +173,6 @@ impl<'a> Expander<'a> { } self.expand_type_use(&mut bt.ty); } - Instruction::FuncBind(b) => { - self.expand_type_use(&mut b.ty); - } Instruction::CallIndirect(c) | Instruction::ReturnCallIndirect(c) => { self.expand_type_use(&mut c.ty); } diff --git a/third_party/rust/wast/src/core/types.rs b/third_party/rust/wast/src/core/types.rs index 179a62b9b8..160317c1c3 100644 --- a/third_party/rust/wast/src/core/types.rs +++ b/third_party/rust/wast/src/core/types.rs @@ -2,6 +2,7 @@ use crate::core::*; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; +use crate::Error; use std::mem; /// The value types for a wasm module. @@ -86,6 +87,8 @@ pub enum HeapType<'a> { NoExtern, /// The bottom type of the anyref hierarchy. Part of the GC proposal. None, + /// The bottom type of the exnref hierarchy. Part of the exceptions proposal. + NoExn, /// A reference to a concrete function, struct, or array type defined by /// Wasm: `ref T`. This is part of the function references and GC proposals. Concrete(Index<'a>), @@ -124,6 +127,9 @@ impl<'a> Parse<'a> for HeapType<'a> { } else if l.peek::()? { parser.parse::()?; Ok(HeapType::NoExtern) + } else if l.peek::()? { + parser.parse::()?; + Ok(HeapType::NoExn) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::None) @@ -147,6 +153,7 @@ impl<'a> Peek for HeapType<'a> { || kw::i31::peek(cursor)? || kw::nofunc::peek(cursor)? || kw::noextern::peek(cursor)? + || kw::noexn::peek(cursor)? || kw::none::peek(cursor)? || (LParen::peek(cursor)? && kw::r#type::peek2(cursor)?)) } @@ -251,6 +258,14 @@ impl<'a> RefType<'a> { heap: HeapType::None, } } + + /// A `nullexnref` as an abbreviation for `(ref null noexn)`. + pub fn nullexnref() -> Self { + RefType { + nullable: true, + heap: HeapType::NoExn, + } + } } impl<'a> Parse<'a> for RefType<'a> { @@ -286,6 +301,9 @@ impl<'a> Parse<'a> for RefType<'a> { } else if l.peek::()? { parser.parse::()?; Ok(RefType::nullexternref()) + } else if l.peek::()? { + parser.parse::()?; + Ok(RefType::nullexnref()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::nullref()) @@ -327,6 +345,7 @@ impl<'a> Peek for RefType<'a> { || kw::i31ref::peek(cursor)? || kw::nullfuncref::peek(cursor)? || kw::nullexternref::peek(cursor)? + || kw::nullexnref::peek(cursor)? || kw::nullref::peek(cursor)? || (LParen::peek(cursor)? && kw::r#ref::peek2(cursor)?)) } @@ -368,22 +387,35 @@ pub struct GlobalType<'a> { pub ty: ValType<'a>, /// Whether or not the global is mutable or not. pub mutable: bool, + /// Whether or not the global is shared. + pub shared: bool, } impl<'a> Parse<'a> for GlobalType<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek2::()? { + if parser.peek2::()? || parser.peek2::()? { parser.parens(|p| { - p.parse::()?; + let mut shared = false; + let mut mutable = false; + if p.peek::()? { + p.parse::()?; + shared = true; + } + if p.peek::()? { + p.parse::()?; + mutable = true; + } Ok(GlobalType { - ty: parser.parse()?, - mutable: true, + ty: p.parse()?, + mutable, + shared, }) }) } else { Ok(GlobalType { ty: parser.parse()?, mutable: false, + shared: false, }) } } @@ -458,6 +490,8 @@ pub enum MemoryType { limits: Limits, /// Whether or not this is a shared (atomic) memory type shared: bool, + /// The custom page size for this memory, if any. + page_size_log2: Option, }, /// A 64-bit memory B64 { @@ -465,21 +499,53 @@ pub enum MemoryType { limits: Limits64, /// Whether or not this is a shared (atomic) memory type shared: bool, + /// The custom page size for this memory, if any. + page_size_log2: Option, }, } +fn page_size(parser: Parser<'_>) -> Result> { + if parser.peek::()? { + Ok(Some(parser.parens(|parser| { + parser.parse::()?; + let span = parser.cur_span(); + let size = parser.parse::()?; + if size.is_power_of_two() { + Ok(size.ilog2()) + } else { + Err(Error::new( + span, + format!("invalid custom page size: {size}"), + )) + } + })?)) + } else { + Ok(None) + } +} + impl<'a> Parse<'a> for MemoryType { fn parse(parser: Parser<'a>) -> Result { if parser.peek::()? { parser.parse::()?; let limits = parser.parse()?; let shared = parser.parse::>()?.is_some(); - Ok(MemoryType::B64 { limits, shared }) + let page_size = page_size(parser)?; + Ok(MemoryType::B64 { + limits, + shared, + page_size_log2: page_size, + }) } else { parser.parse::>()?; let limits = parser.parse()?; let shared = parser.parse::>()?.is_some(); - Ok(MemoryType::B32 { limits, shared }) + let page_size = page_size(parser)?; + Ok(MemoryType::B32 { + limits, + shared, + page_size_log2: page_size, + }) } } } diff --git a/third_party/rust/wast/src/core/wast.rs b/third_party/rust/wast/src/core/wast.rs index 2d3b51b061..9dd9a92391 100644 --- a/third_party/rust/wast/src/core/wast.rs +++ b/third_party/rust/wast/src/core/wast.rs @@ -1,7 +1,7 @@ use crate::core::{HeapType, V128Const}; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; -use crate::token::{Float32, Float64, Index}; +use crate::token::{Index, F32, F64}; /// Expression that can be used inside of `invoke` expressions for core wasm /// functions. @@ -10,8 +10,8 @@ use crate::token::{Float32, Float64, Index}; pub enum WastArgCore<'a> { I32(i32), I64(i64), - F32(Float32), - F64(Float64), + F32(F32), + F64(F64), V128(V128Const), RefNull(HeapType<'a>), RefExtern(u32), @@ -67,8 +67,8 @@ impl Peek for WastArgCore<'_> { pub enum WastRetCore<'a> { I32(i32), I64(i64), - F32(NanPattern), - F64(NanPattern), + F32(NanPattern), + F64(NanPattern), V128(V128Pattern), /// A null reference is expected, optionally with a specified type. @@ -151,7 +151,7 @@ impl Peek for WastRetCore<'_> { } /// Either a NaN pattern (`nan:canonical`, `nan:arithmetic`) or a value of type `T`. -#[derive(Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] #[allow(missing_docs)] pub enum NanPattern { CanonicalNan, @@ -181,15 +181,15 @@ where /// /// This implementation is necessary because only float types can include NaN patterns; otherwise /// it is largely similar to the implementation of `V128Const`. -#[derive(Debug)] +#[derive(Clone, Debug)] #[allow(missing_docs)] pub enum V128Pattern { I8x16([i8; 16]), I16x8([i16; 8]), I32x4([i32; 4]), I64x2([i64; 2]), - F32x4([NanPattern; 4]), - F64x2([NanPattern; 2]), + F32x4([NanPattern; 4]), + F64x2([NanPattern; 2]), } impl<'a> Parse<'a> for V128Pattern { diff --git a/third_party/rust/wast/src/lib.rs b/third_party/rust/wast/src/lib.rs index bb16574177..4964e8df0f 100644 --- a/third_party/rust/wast/src/lib.rs +++ b/third_party/rust/wast/src/lib.rs @@ -447,14 +447,17 @@ pub mod kw { custom_keyword!(nan_canonical = "nan:canonical"); custom_keyword!(nofunc); custom_keyword!(noextern); + custom_keyword!(noexn); custom_keyword!(none); custom_keyword!(null); custom_keyword!(nullfuncref); custom_keyword!(nullexternref); + custom_keyword!(nullexnref); custom_keyword!(nullref); custom_keyword!(offset); custom_keyword!(outer); custom_keyword!(own); + custom_keyword!(pagesize); custom_keyword!(param); custom_keyword!(parent); custom_keyword!(passive); @@ -469,12 +472,14 @@ pub mod kw { custom_keyword!(ref_null = "ref.null"); custom_keyword!(register); custom_keyword!(rec); + custom_keyword!(acq_rel); custom_keyword!(rep); custom_keyword!(resource); custom_keyword!(resource_new = "resource.new"); custom_keyword!(resource_drop = "resource.drop"); custom_keyword!(resource_rep = "resource.rep"); custom_keyword!(result); + custom_keyword!(seq_cst); custom_keyword!(shared); custom_keyword!(start); custom_keyword!(sub); diff --git a/third_party/rust/wast/src/token.rs b/third_party/rust/wast/src/token.rs index 9dd15f97a8..b296341096 100644 --- a/third_party/rust/wast/src/token.rs +++ b/third_party/rust/wast/src/token.rs @@ -639,13 +639,13 @@ macro_rules! float { } float! { - Float32 => { + F32 => { bits: u32, float: f32, exponent_bits: 8, name: strtof, } - Float64 => { + F64 => { bits: u64, float: f64, exponent_bits: 11, @@ -677,6 +677,22 @@ impl Peek for LParen { } } +/// A convenience type to use with [`Parser::peek`](crate::parser::Parser::peek) +/// to see if the next token is the end of an s-expression. +pub struct RParen { + _priv: (), +} + +impl Peek for RParen { + fn peek(cursor: Cursor<'_>) -> Result { + cursor.peek_rparen() + } + + fn display() -> &'static str { + "right paren" + } +} + #[cfg(test)] mod tests { #[test] diff --git a/third_party/rust/wast/src/wast.rs b/third_party/rust/wast/src/wast.rs index 5e18f517d0..418bc83fc7 100644 --- a/third_party/rust/wast/src/wast.rs +++ b/third_party/rust/wast/src/wast.rs @@ -113,8 +113,7 @@ impl WastDirective<'_> { /// Returns the location in the source that this directive was defined at pub fn span(&self) -> Span { match self { - WastDirective::Wat(QuoteWat::Wat(Wat::Module(m))) => m.span, - WastDirective::Wat(QuoteWat::Wat(Wat::Component(c))) => c.span, + WastDirective::Wat(QuoteWat::Wat(w)) => w.span(), WastDirective::Wat(QuoteWat::QuoteModule(span, _)) => *span, WastDirective::Wat(QuoteWat::QuoteComponent(span, _)) => *span, WastDirective::AssertMalformed { span, .. } @@ -219,11 +218,23 @@ pub enum WastExecute<'a> { Invoke(WastInvoke<'a>), Wat(Wat<'a>), Get { + span: Span, module: Option>, global: &'a str, }, } +impl<'a> WastExecute<'a> { + /// Returns the first span for this execute statement. + pub fn span(&self) -> Span { + match self { + WastExecute::Invoke(i) => i.span, + WastExecute::Wat(i) => i.span(), + WastExecute::Get { span, .. } => *span, + } + } +} + impl<'a> Parse<'a> for WastExecute<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); @@ -232,8 +243,9 @@ impl<'a> Parse<'a> for WastExecute<'a> { } else if l.peek::()? || l.peek::()? { Ok(WastExecute::Wat(parse_wat(parser)?)) } else if l.peek::()? { - parser.parse::()?; + let span = parser.parse::()?.0; Ok(WastExecute::Get { + span, module: parser.parse()?, global: parser.parse()?, }) @@ -296,28 +308,47 @@ impl QuoteWat<'_> { /// Encodes this module to bytes, either by encoding the module directly or /// parsing the contents and then encoding it. pub fn encode(&mut self) -> Result, Error> { + match self.to_test()? { + QuoteWatTest::Binary(bytes) => Ok(bytes), + QuoteWatTest::Text(text) => { + let text = std::str::from_utf8(&text).map_err(|_| { + let span = self.span(); + Error::new(span, "malformed UTF-8 encoding".to_string()) + })?; + let buf = ParseBuffer::new(&text)?; + let mut wat = parser::parse::>(&buf)?; + wat.encode() + } + } + } + + /// Converts this to either a `QuoteWatTest::Binary` or + /// `QuoteWatTest::Text` depending on what it is internally. + pub fn to_test(&mut self) -> Result { let (source, prefix) = match self { - QuoteWat::Wat(m) => return m.encode(), + QuoteWat::Wat(m) => return m.encode().map(QuoteWatTest::Binary), QuoteWat::QuoteModule(_, source) => (source, None), QuoteWat::QuoteComponent(_, source) => (source, Some("(component")), }; - let mut ret = String::new(); - for (span, src) in source { - match std::str::from_utf8(src) { - Ok(s) => ret.push_str(s), - Err(_) => { - return Err(Error::new(*span, "malformed UTF-8 encoding".to_string())); - } - } - ret.push(' '); + let mut ret = Vec::new(); + for (_, src) in source { + ret.extend_from_slice(src); + ret.push(b' '); } if let Some(prefix) = prefix { - ret.insert_str(0, prefix); - ret.push(')'); + ret.splice(0..0, prefix.as_bytes().iter().copied()); + ret.push(b')'); + } + Ok(QuoteWatTest::Text(ret)) + } + + /// Returns the defining span of this module. + pub fn span(&self) -> Span { + match self { + QuoteWat::Wat(w) => w.span(), + QuoteWat::QuoteModule(span, _) => *span, + QuoteWat::QuoteComponent(span, _) => *span, } - let buf = ParseBuffer::new(&ret)?; - let mut wat = parser::parse::>(&buf)?; - wat.encode() } } @@ -345,6 +376,14 @@ impl<'a> Parse<'a> for QuoteWat<'a> { } } +/// Returned from [`QuoteWat::to_test`]. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum QuoteWatTest { + Binary(Vec), + Text(Vec), +} + #[derive(Debug)] #[allow(missing_docs)] pub enum WastArg<'a> { diff --git a/third_party/rust/wast/src/wat.rs b/third_party/rust/wast/src/wat.rs index 6d9a233359..d4982264fa 100644 --- a/third_party/rust/wast/src/wat.rs +++ b/third_party/rust/wast/src/wat.rs @@ -32,6 +32,14 @@ impl Wat<'_> { Wat::Component(c) => c.encode(), } } + + /// Returns the defining span of this file. + pub fn span(&self) -> Span { + match self { + Wat::Module(m) => m.span, + Wat::Component(c) => c.span, + } + } } impl<'a> Parse<'a> for Wat<'a> { diff --git a/third_party/rust/wast/tests/parse-fail.rs b/third_party/rust/wast/tests/parse-fail.rs index 3ae1817a4a..a8d4f34456 100644 --- a/third_party/rust/wast/tests/parse-fail.rs +++ b/third_party/rust/wast/tests/parse-fail.rs @@ -4,46 +4,28 @@ //! Use `BLESS=1` in the environment to auto-update `*.err` files. Be sure to //! look at the diff! -use rayon::prelude::*; +use libtest_mimic::{Arguments, Trial}; use std::env; use std::path::{Path, PathBuf}; fn main() { let mut tests = Vec::new(); find_tests("tests/parse-fail".as_ref(), &mut tests); - let filter = std::env::args().nth(1); - let bless = env::var("BLESS").is_ok(); - let tests = tests - .iter() - .filter(|test| { - if let Some(filter) = &filter { - if let Some(s) = test.file_name().and_then(|s| s.to_str()) { - if !s.contains(filter) { - return false; - } - } - } - true - }) - .collect::>(); - - println!("running {} tests\n", tests.len()); - - let errors = tests - .par_iter() - .filter_map(|test| run_test(test, bless).err()) - .collect::>(); - if !errors.is_empty() { - for msg in errors.iter() { - eprintln!("{}", msg); - } - - panic!("{} tests failed", errors.len()) + let mut trials = Vec::new(); + for test in tests { + let trial = Trial::test(format!("{test:?}"), move || { + run_test(&test, bless).map_err(|e| format!("{e:?}").into()) + }); + trials.push(trial); } - println!("test result: ok. {} passed\n", tests.len()); + let mut args = Arguments::from_args(); + if cfg!(target_family = "wasm") && !cfg!(target_feature = "atomics") { + args.test_threads = Some(1); + } + libtest_mimic::run(&args, trials).exit(); } fn run_test(test: &Path, bless: bool) -> anyhow::Result<()> { diff --git a/third_party/rust/wgpu-core/.cargo-checksum.json b/third_party/rust/wgpu-core/.cargo-checksum.json index f025f2ccaa..a4f8ad5e63 100644 --- a/third_party/rust/wgpu-core/.cargo-checksum.json +++ b/third_party/rust/wgpu-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"3f5fa464854359b0150d4fe82cf5b0c17874dbb3c3c708b2a9cc24ebc1a61349","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"a99478d7f63fb41429e3834f4d0e5cd333f94ba1834c68295f929170e16987de","src/any_surface.rs":"1c032bc1894a222a47f0116b976f1543c1140c0534678502ee1172d4f77fc515","src/binding_model.rs":"bb4aefad17957e770a5f70f00bf5853dc13da1d9f836493c9aa9adbbe7bb8147","src/command/bind.rs":"a37f042484b65d9fdea4cdab3667381623ee9a8943a6d32683d410b92736d306","src/command/bundle.rs":"3435ea21daba6f5a26f9a4158b342d0b9a1839da39b82fa8c23d84ee144b9da0","src/command/clear.rs":"2eb9c323c3ae3644563cab1bb1d26e4a17a54f5a120698c7f09ef9f9e9077780","src/command/compute.rs":"1ad1d8b83774422bd73c7c67c153205e451fd71602b37f34162b59e5f7dbbc75","src/command/draw.rs":"15f9ad857504d8098279f9c789317feba321c9b6b8f0de20b8ba98f358c99d89","src/command/memory_init.rs":"71550dabbf7cc3c3ff6aa4ccd31af080bb5e1cb1e21422daea63fee30294476f","src/command/mod.rs":"1d347e1746194f7a07d1f75bd3a9d3cbe121fbaa479c25ba6b8c16e9d699e06b","src/command/query.rs":"43b78a163eb0eb5f1427b7a57b6d39a2748c25f880ba024c91e2f71e2a6a817d","src/command/render.rs":"875545efa83e56face9a857c5d8c814bc46f4b0538a152933265533176ad1e84","src/command/transfer.rs":"63042151145825c5cac6459a5a254a82142c86d299895f72bef2682f71de7ad1","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"65f47b58939b60f88f47861e65d5d45209492df8e73e7c1b60b3b459f510c09e","src/device/bgl.rs":"ec8bdd6e9b4cd50c25bed317275863d0c16bb6619f62ed85bf0464948010dfc1","src/device/global.rs":"6a08dcc25059f2194999c4f5e3a57a1a96b17031873b1a871095dc58115470fb","src/device/life.rs":"efba75c8632e0bd9c655dbff1f8ff027900f388b6eeb357a9c02ddad24474b23","src/device/mod.rs":"e578d03253a9af314e1e81168d45ea8cc0a8f56df79e440dc1ade945d75277ec","src/device/queue.rs":"4405a6b8ea29093239f1556e5352f7c777f4f6b783fd5dea458fde22556741ca","src/device/resource.rs":"65f84150c467aa50615a097d15f6b4dba3514b0adf2de1e9b9837e5084619a80","src/device/trace.rs":"9deb1b083165e07253b4928ac2f564aba06f9089c3aca1c0a1d438d87d981542","src/error.rs":"e3b6b7a69877437f4e46af7f0e8ca1db1822beae7c8448db41c2bae0f64b2bb4","src/global.rs":"0966475959706650fd036a18d51441a8e14c3ef10107db617f597614ca47e50a","src/hal_api.rs":"1cd9c3fe1c9d8c3a24e3e7f963a2ef26e056a2b26d529b840dbc969090aaf201","src/hash_utils.rs":"e8d484027c7ce81978e4679a5e20af9416ab7d2fa595f1ca95992b29d625b0ca","src/hub.rs":"352a1b75d4535f24b06d16134421db98f910e6e719f50f863a204df6768e3369","src/id.rs":"9f67dbef5d7a416eb740281ecf8a94673f624da16f21ec33c425c11d9ed01e90","src/identity.rs":"12b820eb4b8bd7b226e15eec97d0f100a695f6b9be7acd79ad2421f2d0fe1985","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"a0f64730cc025113b656b4690f9dcb0ec18b8770bc7ef24c7b4ad8bebae03d24","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"b6de2a371ef3b43d3217102fe87e423dd1eb12da86b65f54b902d9eaa38b6b9f","src/lib.rs":"4ad9979442cf88557fb3b9f8d3b26c7b929a710c60cabcd1f51788917c95aecb","src/pipeline.rs":"89d88de4b8b8e1dd2bc834d101a1bdf34816ebcaa616dc795f604e9183a21cd0","src/pool.rs":"778ea1c23fcfaaa5001606e686f712f606826039d60dd5a3cd26e7de91ac057a","src/present.rs":"f69580ee0baf181162f9dd82b159596c738558d8abb60db93047effbe1436b2f","src/registry.rs":"913e651dc585ff12fe7659443c38d635a2904881e56cb7159c5ca72d45ae5800","src/resource.rs":"59731bc9a207d87b07b6db9c897e20d64be27c144bb8eb8ab2505807163acfc4","src/snatch.rs":"5cf0e4e4611083e8256092696ecf0caa9e855dd680c18fc7dbb227d071aa2548","src/storage.rs":"f0c41461b8f9cdc862dbd3de04c8e720ee416c7c57310696f6f4fd22183fcc85","src/track/buffer.rs":"d1b4c85dfaf1bcc93013d7f51ba677f97c36245c9de224fb328595aa15109cf6","src/track/metadata.rs":"7016911136bc5b97053f54241b01d344f5d65c4337a292c8aa32bb142a26be0c","src/track/mod.rs":"5365c532a531d224a958bd8217769ef59d67d293b4f95972c10db71f6bff1a80","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"305e0a493fb1cd0a325274c0757e99c19f9d14deaa8ca11ada41c1399a4ae5c4","src/track/texture.rs":"da83403d5990021c5db78f1ffdf69198eadb99cc77a6bc481648337a5403295c","src/validation.rs":"026168ac4f23bc6a58a90c78fd3eb73485b3c1aad630ef43755604d1babade79"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"ef0dc61297a9dd672d3e0e71ced2973a97f0abdb705432816874867ec4dc873b","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"a99478d7f63fb41429e3834f4d0e5cd333f94ba1834c68295f929170e16987de","src/binding_model.rs":"f1279d3cd1f84eab37dc85658f32bb4b4f2687c9086f4b4f30e8a4b0d7c1a582","src/command/allocator.rs":"5ca1e40a735f7cb0531d3e5298767963a3c0ee9e264b44d3a356cd7ef16bcb52","src/command/bind.rs":"a37f042484b65d9fdea4cdab3667381623ee9a8943a6d32683d410b92736d306","src/command/bundle.rs":"1c7fceda77668ae5a055bf1d0184b78cc7362f7763d6b6a3c9d1687e4782f908","src/command/clear.rs":"1eb475a48e04a011be381720a420047a3d65fc85be3b9b55e6874c7fd14e40a8","src/command/compute.rs":"7a58ff8f492dc8926ab8cd580c7ae8bf8703df4472f093f4a027f4969f55b0f9","src/command/compute_command.rs":"b00623d80e9aa3bb78c1d8d24ccbc0cbd6f945ef3c9206b8fba5c3ce86753f5e","src/command/draw.rs":"15f9ad857504d8098279f9c789317feba321c9b6b8f0de20b8ba98f358c99d89","src/command/memory_init.rs":"71550dabbf7cc3c3ff6aa4ccd31af080bb5e1cb1e21422daea63fee30294476f","src/command/mod.rs":"947c0dc1e82301e5571579031f0b1b0627d1f6d9c8d3b5e510c37673ea661fc1","src/command/query.rs":"92b5aff8580631c51bc1ba72a45605e704c997684fc6a891640da945712db5ec","src/command/render.rs":"6d02d9a9f0c1e58a448cbd30e62e51dca5b8b61e576ece15655c343cc51e84b9","src/command/transfer.rs":"d0324465a5637e8346276a0427446377c21acbb285ff819091673ba5fc365a9c","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"8802f6d9d7fa9cd0b02c5ed57412a2ef01b9ad2b47182e18a914ce4ad5e24fde","src/device/bgl.rs":"f1c372cd632deacb9d0f0880846844c7cbe5f1ca88592ed35dbd59966958b33d","src/device/global.rs":"1881c6729b86423a4ab75db1ae0e3d6a8d34ab4600f3cd5e38bf8768d07b6905","src/device/life.rs":"a65cab56e0eb688d0776e719da785372a742d6a87bd3f3bef9042e9428453c3a","src/device/mod.rs":"aa16ac918714c844820142b4d321ac4e9a51ffef37501c6f5ca48e3817353d16","src/device/queue.rs":"33cc4bb3337d49810dc74bfc2eb8ad97a82023ad263d80700c769d0c0ad9bfe4","src/device/resource.rs":"b0a55d496ca59056854d5d41264f519992b342a4049d1b65a13220d8a76902a1","src/device/trace.rs":"9deb1b083165e07253b4928ac2f564aba06f9089c3aca1c0a1d438d87d981542","src/error.rs":"e3b6b7a69877437f4e46af7f0e8ca1db1822beae7c8448db41c2bae0f64b2bb4","src/global.rs":"fe1ddd4863d50568780bf04382a4fd0d3d8441dd7baff9dacf57e860811b87c9","src/hal_api.rs":"fb65bfab0334cb8b0bbe823b1da6d1e82cd4a312c60a332ce65df9fbc2f74482","src/hash_utils.rs":"e8d484027c7ce81978e4679a5e20af9416ab7d2fa595f1ca95992b29d625b0ca","src/hub.rs":"59aeb5c902fd6707f651994fc9e335a6e7fdd998faebd29c087171e226101405","src/id.rs":"23634dec36eb171cb95c672519e69705d466044dcea29028b58d2288de35f8db","src/identity.rs":"b27d4e06b1f6c25ca2f4ad276fdf8c09a5d71f890b06cbabef7ef62369cb4df6","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"a0f64730cc025113b656b4690f9dcb0ec18b8770bc7ef24c7b4ad8bebae03d24","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"d4c46ff5d0cc13b09c7b364d6445d30eaf7ea6f50ac9d49b0022b3a6e9377445","src/lib.rs":"77ec01c43b6f5daab174e0831bd98771a708cdfd42b0203f45490b6977ef2923","src/lock/mod.rs":"c7069f05341f1c63f478ed9176f4fbd1a6f633ea71f124c3b4d6c1b02d1febe8","src/lock/rank.rs":"acc3ef80c39297a440a53ec33e437be7fbb56a4bb09e326cfeb3d4bf76f60ac8","src/lock/ranked.rs":"94c2d929b54bc4ea68258bb4d58b692b61accc394dd48dbab5e69f1bdafaeb56","src/lock/vanilla.rs":"a6cd5cc3c1900271783ba146adf07e28424f6fecc5466d54624dbda237770fb4","src/pipeline.rs":"033335a759b801de7c606baf3f2ac8c706b1bbe27b209bcca73093569b604c0e","src/pool.rs":"7899e74874da17c83ec39a88b360de12f564ef4bee2bb1240c37becdaeb57a86","src/present.rs":"1147399ff3a62b69c944001639cd1cf19295e13cf0ddd3850b2736afdb0720b4","src/registry.rs":"1104d6972dad982c6cc6dfd25cbc52d0b8279d7989525d78ed49551434fa3cea","src/resource.rs":"ce469bbd6ae54efb989770b04079ee1a9c248b95f31ad5dae79603f87574878d","src/snatch.rs":"f9849b1050adba708c1b9be5a21ce806c83eef71c4f79b513768918f857fe814","src/storage.rs":"0c5a8a732e33ea565528b3a02e7a6c15178bc8dbc49a9cedcd76f8ebb1039b48","src/track/buffer.rs":"8571ebd57302ab9aba4aef4a310a02fe0848485f57ac3a7197393fbfbaddff2e","src/track/metadata.rs":"4b85341adc3b725e326dec0fe691f7e8e6c4e7c0a1ada1d86dd72a0a0b6397e6","src/track/mod.rs":"0056f0299fa71cc3acca9aa6becba15e0845b8e9000a11780d0b78da2ee01beb","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"b49192d248434570c024078cf204ad47f9030ed7a541324bad525881b78f75a4","src/track/texture.rs":"f962f97b582d4b528483f09df8662484159b6f5d19b376de53462d411421cee5","src/validation.rs":"1433e035d656afda97ee047b3247cb1a63844360174d575acf52cac868e27a3c"},"package":null} \ No newline at end of file diff --git a/third_party/rust/wgpu-core/Cargo.toml b/third_party/rust/wgpu-core/Cargo.toml index aef86b3bbf..a4d1530917 100644 --- a/third_party/rust/wgpu-core/Cargo.toml +++ b/third_party/rust/wgpu-core/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.74" name = "wgpu-core" -version = "0.19.0" +version = "0.20.0" authors = ["gfx-rs developers"] description = "WebGPU core logic on wgpu-hal" homepage = "https://wgpu.rs/" @@ -40,7 +40,6 @@ targets = [ arrayvec = "0.7" bit-vec = "0.6" bitflags = "2" -codespan-reporting = "0.11" document-features = "0.2.8" indexmap = "2" log = "0.4" @@ -55,15 +54,14 @@ version = "1.14" optional = true [dependencies.hal] -version = "0.19.0" +version = "0.20.0" path = "../wgpu-hal" default_features = false package = "wgpu-hal" [dependencies.naga] -version = "0.19.0" +version = "0.20.0" path = "../naga" -features = ["clone"] [dependencies.profiling] version = "1" @@ -83,7 +81,7 @@ features = ["serde_derive"] optional = true [dependencies.wgt] -version = "0.19.0" +version = "0.20.0" path = "../wgpu-types" package = "wgpu-types" diff --git a/third_party/rust/wgpu-core/src/any_surface.rs b/third_party/rust/wgpu-core/src/any_surface.rs deleted file mode 100644 index 94edfc4433..0000000000 --- a/third_party/rust/wgpu-core/src/any_surface.rs +++ /dev/null @@ -1,95 +0,0 @@ -use wgt::Backend; - -/// The `AnySurface` type: a `Arc` of a `A::Surface` for any backend `A`. -use crate::hal_api::HalApi; - -use std::fmt; -use std::mem::ManuallyDrop; -use std::ptr::NonNull; - -struct AnySurfaceVtable { - // We oppurtunistically store the backend here, since we now it will be used - // with backend selection and it can be stored in static memory. - backend: Backend, - // Drop glue which knows how to drop the stored data. - drop: unsafe fn(*mut ()), -} - -/// An `A::Surface`, for any backend `A`. -/// -/// Any `AnySurface` is just like an `A::Surface`, except that the `A` type -/// parameter is erased. To access the `Surface`, you must downcast to a -/// particular backend with the \[`downcast_ref`\] or \[`take`\] methods. -pub struct AnySurface { - data: NonNull<()>, - vtable: &'static AnySurfaceVtable, -} - -impl AnySurface { - /// Construct an `AnySurface` that owns an `A::Surface`. - pub fn new(surface: A::Surface) -> AnySurface { - unsafe fn drop_glue(ptr: *mut ()) { - unsafe { - _ = Box::from_raw(ptr.cast::()); - } - } - - let data = NonNull::from(Box::leak(Box::new(surface))); - - AnySurface { - data: data.cast(), - vtable: &AnySurfaceVtable { - backend: A::VARIANT, - drop: drop_glue::, - }, - } - } - - /// Get the backend this surface was created through. - pub fn backend(&self) -> Backend { - self.vtable.backend - } - - /// If `self` refers to an `A::Surface`, returns a reference to it. - pub fn downcast_ref(&self) -> Option<&A::Surface> { - if A::VARIANT != self.vtable.backend { - return None; - } - - // SAFETY: We just checked the instance above implicitly by the backend - // that it was statically constructed through. - Some(unsafe { &*self.data.as_ptr().cast::() }) - } - - /// If `self` is an `Arc`, returns that. - pub fn take(self) -> Option { - if A::VARIANT != self.vtable.backend { - return None; - } - - // Disable drop glue, since we're returning the owned surface. The - // caller will be responsible for dropping it. - let this = ManuallyDrop::new(self); - - // SAFETY: We just checked the instance above implicitly by the backend - // that it was statically constructed through. - Some(unsafe { *Box::from_raw(this.data.as_ptr().cast::()) }) - } -} - -impl Drop for AnySurface { - fn drop(&mut self) { - unsafe { (self.vtable.drop)(self.data.as_ptr()) } - } -} - -impl fmt::Debug for AnySurface { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "AnySurface<{}>", self.vtable.backend) - } -} - -#[cfg(send_sync)] -unsafe impl Send for AnySurface {} -#[cfg(send_sync)] -unsafe impl Sync for AnySurface {} diff --git a/third_party/rust/wgpu-core/src/binding_model.rs b/third_party/rust/wgpu-core/src/binding_model.rs index 8689af2ac1..bea63b0ba4 100644 --- a/third_party/rust/wgpu-core/src/binding_model.rs +++ b/third_party/rust/wgpu-core/src/binding_model.rs @@ -462,8 +462,6 @@ pub struct BindGroupLayoutDescriptor<'a> { pub entries: Cow<'a, [wgt::BindGroupLayoutEntry]>, } -pub type BindGroupLayouts = crate::storage::Storage>; - /// Bind group layout. #[derive(Debug)] pub struct BindGroupLayout { diff --git a/third_party/rust/wgpu-core/src/command/allocator.rs b/third_party/rust/wgpu-core/src/command/allocator.rs new file mode 100644 index 0000000000..e17fd08d76 --- /dev/null +++ b/third_party/rust/wgpu-core/src/command/allocator.rs @@ -0,0 +1,67 @@ +use crate::hal_api::HalApi; +use crate::resource_log; +use hal::Device as _; + +use crate::lock::{rank, Mutex}; + +/// A pool of free [`wgpu_hal::CommandEncoder`]s, owned by a `Device`. +/// +/// Each encoder in this list is in the "closed" state. +/// +/// Since a raw [`CommandEncoder`][ce] is itself a pool for allocating +/// raw [`CommandBuffer`][cb]s, this is a pool of pools. +/// +/// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder +/// [ce]: hal::CommandEncoder +/// [cb]: hal::Api::CommandBuffer +pub(crate) struct CommandAllocator { + free_encoders: Mutex>, +} + +impl CommandAllocator { + pub(crate) fn new() -> Self { + Self { + free_encoders: Mutex::new(rank::COMMAND_ALLOCATOR_FREE_ENCODERS, Vec::new()), + } + } + + /// Return a fresh [`wgpu_hal::CommandEncoder`] in the "closed" state. + /// + /// If we have free encoders in the pool, take one of those. Otherwise, + /// create a new one on `device`. + /// + /// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder + pub(crate) fn acquire_encoder( + &self, + device: &A::Device, + queue: &A::Queue, + ) -> Result { + let mut free_encoders = self.free_encoders.lock(); + match free_encoders.pop() { + Some(encoder) => Ok(encoder), + None => unsafe { + let hal_desc = hal::CommandEncoderDescriptor { label: None, queue }; + device.create_command_encoder(&hal_desc) + }, + } + } + + /// Add `encoder` back to the free pool. + pub(crate) fn release_encoder(&self, encoder: A::CommandEncoder) { + let mut free_encoders = self.free_encoders.lock(); + free_encoders.push(encoder); + } + + /// Free the pool of command encoders. + /// + /// This is only called when the `Device` is dropped. + pub(crate) fn dispose(&self, device: &A::Device) { + let mut free_encoders = self.free_encoders.lock(); + resource_log!("CommandAllocator::dispose encoders {}", free_encoders.len()); + for cmd_encoder in free_encoders.drain(..) { + unsafe { + device.destroy_command_encoder(cmd_encoder); + } + } + } +} diff --git a/third_party/rust/wgpu-core/src/command/bundle.rs b/third_party/rust/wgpu-core/src/command/bundle.rs index 47beda8ec6..d9d821c533 100644 --- a/third_party/rust/wgpu-core/src/command/bundle.rs +++ b/third_party/rust/wgpu-core/src/command/bundle.rs @@ -73,7 +73,7 @@ index format changes. [Gdcrbe]: crate::global::Global::device_create_render_bundle_encoder [Grbef]: crate::global::Global::render_bundle_encoder_finish -[wrpeb]: crate::command::render_ffi::wgpu_render_pass_execute_bundles +[wrpeb]: crate::command::render::render_commands::wgpu_render_pass_execute_bundles !*/ #![allow(clippy::reversed_empty_ranges)] @@ -113,7 +113,7 @@ use hal::CommandEncoder as _; use super::ArcRenderCommand; -/// https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw +/// fn validate_draw( vertex: &[Option>], step: &[VertexStep], @@ -1548,15 +1548,14 @@ pub mod bundle_ffi { offsets: *const DynamicOffset, offset_length: usize, ) { - let redundant = unsafe { - bundle.current_bind_groups.set_and_check_redundant( - bind_group_id, - index, - &mut bundle.base.dynamic_offsets, - offsets, - offset_length, - ) - }; + let offsets = unsafe { slice::from_raw_parts(offsets, offset_length) }; + + let redundant = bundle.current_bind_groups.set_and_check_redundant( + bind_group_id, + index, + &mut bundle.base.dynamic_offsets, + offsets, + ); if redundant { return; diff --git a/third_party/rust/wgpu-core/src/command/clear.rs b/third_party/rust/wgpu-core/src/command/clear.rs index 72c923f82e..faff177928 100644 --- a/third_party/rust/wgpu-core/src/command/clear.rs +++ b/third_party/rust/wgpu-core/src/command/clear.rs @@ -104,6 +104,11 @@ impl Global { let dst_buffer = buffer_guard .get(dst) .map_err(|_| ClearError::InvalidBuffer(dst))?; + + if dst_buffer.device.as_info().id() != cmd_buf.device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + cmd_buf_data .trackers .buffers @@ -200,6 +205,10 @@ impl Global { .get(dst) .map_err(|_| ClearError::InvalidTexture(dst))?; + if dst_texture.device.as_info().id() != cmd_buf.device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + // Check if subresource aspects are valid. let clear_aspects = hal::FormatAspects::new(dst_texture.desc.format, subresource_range.aspect); diff --git a/third_party/rust/wgpu-core/src/command/compute.rs b/third_party/rust/wgpu-core/src/command/compute.rs index b38324984c..4ee48f0086 100644 --- a/third_party/rust/wgpu-core/src/command/compute.rs +++ b/third_party/rust/wgpu-core/src/command/compute.rs @@ -1,3 +1,4 @@ +use crate::command::compute_command::{ArcComputeCommand, ComputeCommand}; use crate::device::DeviceError; use crate::resource::Resource; use crate::snatch::SnatchGuard; @@ -20,7 +21,6 @@ use crate::{ hal_label, id, id::DeviceId, init_tracker::MemoryInitKind, - pipeline, resource::{self}, storage::Storage, track::{Tracker, UsageConflict, UsageScope}, @@ -36,61 +36,9 @@ use serde::Serialize; use thiserror::Error; +use std::sync::Arc; use std::{fmt, mem, str}; -#[doc(hidden)] -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ComputeCommand { - SetBindGroup { - index: u32, - num_dynamic_offsets: usize, - bind_group_id: id::BindGroupId, - }, - SetPipeline(id::ComputePipelineId), - - /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. - SetPushConstant { - /// The byte offset within the push constant storage to write to. This - /// must be a multiple of four. - offset: u32, - - /// The number of bytes to write. This must be a multiple of four. - size_bytes: u32, - - /// Index in [`BasePass::push_constant_data`] of the start of the data - /// to be written. - /// - /// Note: this is not a byte offset like `offset`. Rather, it is the - /// index of the first `u32` element in `push_constant_data` to read. - values_offset: u32, - }, - - Dispatch([u32; 3]), - DispatchIndirect { - buffer_id: id::BufferId, - offset: wgt::BufferAddress, - }, - PushDebugGroup { - color: u32, - len: usize, - }, - PopDebugGroup, - InsertDebugMarker { - color: u32, - len: usize, - }, - WriteTimestamp { - query_set_id: id::QuerySetId, - query_index: u32, - }, - BeginPipelineStatisticsQuery { - query_set_id: id::QuerySetId, - query_index: u32, - }, - EndPipelineStatisticsQuery, -} - #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct ComputePass { base: BasePass, @@ -184,7 +132,7 @@ pub enum ComputePassErrorInner { #[error(transparent)] Encoder(#[from] CommandEncoderError), #[error("Bind group at index {0:?} is invalid")] - InvalidBindGroup(usize), + InvalidBindGroup(u32), #[error("Device {0:?} is invalid")] InvalidDevice(DeviceId), #[error("Bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")] @@ -249,7 +197,7 @@ impl PrettyError for ComputePassErrorInner { pub struct ComputePassError { pub scope: PassErrorScope, #[source] - inner: ComputePassErrorInner, + pub(super) inner: ComputePassErrorInner, } impl PrettyError for ComputePassError { fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { @@ -346,7 +294,8 @@ impl Global { encoder_id: id::CommandEncoderId, pass: &ComputePass, ) -> Result<(), ComputePassError> { - self.command_encoder_run_compute_pass_impl::( + // TODO: This should go directly to `command_encoder_run_compute_pass_impl` by means of storing `ArcComputeCommand` internally. + self.command_encoder_run_compute_pass_with_unresolved_commands::( encoder_id, pass.base.as_ref(), pass.timestamp_writes.as_ref(), @@ -354,18 +303,41 @@ impl Global { } #[doc(hidden)] - pub fn command_encoder_run_compute_pass_impl( + pub fn command_encoder_run_compute_pass_with_unresolved_commands( &self, encoder_id: id::CommandEncoderId, base: BasePassRef, timestamp_writes: Option<&ComputePassTimestampWrites>, + ) -> Result<(), ComputePassError> { + let resolved_commands = + ComputeCommand::resolve_compute_command_ids(A::hub(self), base.commands)?; + + self.command_encoder_run_compute_pass_impl::( + encoder_id, + BasePassRef { + label: base.label, + commands: &resolved_commands, + dynamic_offsets: base.dynamic_offsets, + string_data: base.string_data, + push_constant_data: base.push_constant_data, + }, + timestamp_writes, + ) + } + + fn command_encoder_run_compute_pass_impl( + &self, + encoder_id: id::CommandEncoderId, + base: BasePassRef>, + timestamp_writes: Option<&ComputePassTimestampWrites>, ) -> Result<(), ComputePassError> { profiling::scope!("CommandEncoder::run_compute_pass"); let pass_scope = PassErrorScope::Pass(encoder_id); let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, encoder_id).map_pass_err(pass_scope)?; + let cmd_buf: Arc> = + CommandBuffer::get_encoder(hub, encoder_id).map_pass_err(pass_scope)?; let device = &cmd_buf.device; if !device.is_valid() { return Err(ComputePassErrorInner::InvalidDevice( @@ -380,7 +352,13 @@ impl Global { #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(crate::device::trace::Command::RunComputePass { - base: BasePass::from_ref(base), + base: BasePass { + label: base.label.map(str::to_string), + commands: base.commands.iter().map(Into::into).collect(), + dynamic_offsets: base.dynamic_offsets.to_vec(), + string_data: base.string_data.to_vec(), + push_constant_data: base.push_constant_data.to_vec(), + }, timestamp_writes: timestamp_writes.cloned(), }); } @@ -400,9 +378,7 @@ impl Global { let raw = encoder.open().map_pass_err(pass_scope)?; let bind_group_guard = hub.bind_groups.read(); - let pipeline_guard = hub.compute_pipelines.read(); let query_set_guard = hub.query_sets.read(); - let buffer_guard = hub.buffers.read(); let mut state = State { binder: Binder::new(), @@ -480,19 +456,21 @@ impl Global { // be inserted before texture reads. let mut pending_discard_init_fixups = SurfacesInDiscardState::new(); + // TODO: We should be draining the commands here, avoiding extra copies in the process. + // (A command encoder can't be executed twice!) for command in base.commands { - match *command { - ComputeCommand::SetBindGroup { + match command { + ArcComputeCommand::SetBindGroup { index, num_dynamic_offsets, - bind_group_id, + bind_group, } => { - let scope = PassErrorScope::SetBindGroup(bind_group_id); + let scope = PassErrorScope::SetBindGroup(bind_group.as_info().id()); let max_bind_groups = cmd_buf.limits.max_bind_groups; - if index >= max_bind_groups { + if index >= &max_bind_groups { return Err(ComputePassErrorInner::BindGroupIndexOutOfRange { - index, + index: *index, max: max_bind_groups, }) .map_pass_err(scope); @@ -505,13 +483,9 @@ impl Global { ); dynamic_offset_count += num_dynamic_offsets; - let bind_group = tracker - .bind_groups - .add_single(&*bind_group_guard, bind_group_id) - .ok_or(ComputePassErrorInner::InvalidBindGroup(index as usize)) - .map_pass_err(scope)?; + let bind_group = tracker.bind_groups.insert_single(bind_group.clone()); bind_group - .validate_dynamic_bindings(index, &temp_offsets, &cmd_buf.limits) + .validate_dynamic_bindings(*index, &temp_offsets, &cmd_buf.limits) .map_pass_err(scope)?; buffer_memory_init_actions.extend( @@ -533,14 +507,14 @@ impl Global { let entries = state .binder - .assign_group(index as usize, bind_group, &temp_offsets); + .assign_group(*index as usize, bind_group, &temp_offsets); if !entries.is_empty() && pipeline_layout.is_some() { let pipeline_layout = pipeline_layout.as_ref().unwrap().raw(); for (i, e) in entries.iter().enumerate() { if let Some(group) = e.group.as_ref() { let raw_bg = group .raw(&snatch_guard) - .ok_or(ComputePassErrorInner::InvalidBindGroup(i)) + .ok_or(ComputePassErrorInner::InvalidBindGroup(i as u32)) .map_pass_err(scope)?; unsafe { raw.set_bind_group( @@ -554,16 +528,13 @@ impl Global { } } } - ComputeCommand::SetPipeline(pipeline_id) => { + ArcComputeCommand::SetPipeline(pipeline) => { + let pipeline_id = pipeline.as_info().id(); let scope = PassErrorScope::SetPipelineCompute(pipeline_id); state.pipeline = Some(pipeline_id); - let pipeline: &pipeline::ComputePipeline = tracker - .compute_pipelines - .add_single(&*pipeline_guard, pipeline_id) - .ok_or(ComputePassErrorInner::InvalidPipeline(pipeline_id)) - .map_pass_err(scope)?; + tracker.compute_pipelines.insert_single(pipeline.clone()); unsafe { raw.set_compute_pipeline(pipeline.raw()); @@ -587,7 +558,7 @@ impl Global { if let Some(group) = e.group.as_ref() { let raw_bg = group .raw(&snatch_guard) - .ok_or(ComputePassErrorInner::InvalidBindGroup(i)) + .ok_or(ComputePassErrorInner::InvalidBindGroup(i as u32)) .map_pass_err(scope)?; unsafe { raw.set_bind_group( @@ -623,7 +594,7 @@ impl Global { } } } - ComputeCommand::SetPushConstant { + ArcComputeCommand::SetPushConstant { offset, size_bytes, values_offset, @@ -634,7 +605,7 @@ impl Global { let values_end_offset = (values_offset + size_bytes / wgt::PUSH_CONSTANT_ALIGNMENT) as usize; let data_slice = - &base.push_constant_data[(values_offset as usize)..values_end_offset]; + &base.push_constant_data[(*values_offset as usize)..values_end_offset]; let pipeline_layout = state .binder @@ -649,7 +620,7 @@ impl Global { pipeline_layout .validate_push_constant_ranges( wgt::ShaderStages::COMPUTE, - offset, + *offset, end_offset_bytes, ) .map_pass_err(scope)?; @@ -658,12 +629,12 @@ impl Global { raw.set_push_constants( pipeline_layout.raw(), wgt::ShaderStages::COMPUTE, - offset, + *offset, data_slice, ); } } - ComputeCommand::Dispatch(groups) => { + ArcComputeCommand::Dispatch(groups) => { let scope = PassErrorScope::Dispatch { indirect: false, pipeline: state.pipeline, @@ -688,7 +659,7 @@ impl Global { { return Err(ComputePassErrorInner::Dispatch( DispatchError::InvalidGroupSize { - current: groups, + current: *groups, limit: groups_size_limit, }, )) @@ -696,10 +667,11 @@ impl Global { } unsafe { - raw.dispatch(groups); + raw.dispatch(*groups); } } - ComputeCommand::DispatchIndirect { buffer_id, offset } => { + ArcComputeCommand::DispatchIndirect { buffer, offset } => { + let buffer_id = buffer.as_info().id(); let scope = PassErrorScope::Dispatch { indirect: true, pipeline: state.pipeline, @@ -711,29 +683,25 @@ impl Global { .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) .map_pass_err(scope)?; - let indirect_buffer = state + state .scope .buffers - .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) + .insert_merge_single(buffer.clone(), hal::BufferUses::INDIRECT) + .map_pass_err(scope)?; + check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::INDIRECT) .map_pass_err(scope)?; - check_buffer_usage( - buffer_id, - indirect_buffer.usage, - wgt::BufferUsages::INDIRECT, - ) - .map_pass_err(scope)?; let end_offset = offset + mem::size_of::() as u64; - if end_offset > indirect_buffer.size { + if end_offset > buffer.size { return Err(ComputePassErrorInner::IndirectBufferOverrun { - offset, + offset: *offset, end_offset, - buffer_size: indirect_buffer.size, + buffer_size: buffer.size, }) .map_pass_err(scope); } - let buf_raw = indirect_buffer + let buf_raw = buffer .raw .get(&snatch_guard) .ok_or(ComputePassErrorInner::InvalidIndirectBuffer(buffer_id)) @@ -742,9 +710,9 @@ impl Global { let stride = 3 * 4; // 3 integers, x/y/z group size buffer_memory_init_actions.extend( - indirect_buffer.initialization_status.read().create_action( - indirect_buffer, - offset..(offset + stride), + buffer.initialization_status.read().create_action( + buffer, + *offset..(*offset + stride), MemoryInitKind::NeedsInitializedMemory, ), ); @@ -754,15 +722,15 @@ impl Global { raw, &mut intermediate_trackers, &*bind_group_guard, - Some(indirect_buffer.as_info().tracker_index()), + Some(buffer.as_info().tracker_index()), &snatch_guard, ) .map_pass_err(scope)?; unsafe { - raw.dispatch_indirect(buf_raw, offset); + raw.dispatch_indirect(buf_raw, *offset); } } - ComputeCommand::PushDebugGroup { color: _, len } => { + ArcComputeCommand::PushDebugGroup { color: _, len } => { state.debug_scope_depth += 1; if !discard_hal_labels { let label = @@ -774,7 +742,7 @@ impl Global { } string_offset += len; } - ComputeCommand::PopDebugGroup => { + ArcComputeCommand::PopDebugGroup => { let scope = PassErrorScope::PopDebugGroup; if state.debug_scope_depth == 0 { @@ -788,7 +756,7 @@ impl Global { } } } - ComputeCommand::InsertDebugMarker { color: _, len } => { + ArcComputeCommand::InsertDebugMarker { color: _, len } => { if !discard_hal_labels { let label = str::from_utf8(&base.string_data[string_offset..string_offset + len]) @@ -797,49 +765,43 @@ impl Global { } string_offset += len; } - ComputeCommand::WriteTimestamp { - query_set_id, + ArcComputeCommand::WriteTimestamp { + query_set, query_index, } => { + let query_set_id = query_set.as_info().id(); let scope = PassErrorScope::WriteTimestamp; device .require_features(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES) .map_pass_err(scope)?; - let query_set: &resource::QuerySet = tracker - .query_sets - .add_single(&*query_set_guard, query_set_id) - .ok_or(ComputePassErrorInner::InvalidQuerySet(query_set_id)) - .map_pass_err(scope)?; + let query_set = tracker.query_sets.insert_single(query_set.clone()); query_set - .validate_and_write_timestamp(raw, query_set_id, query_index, None) + .validate_and_write_timestamp(raw, query_set_id, *query_index, None) .map_pass_err(scope)?; } - ComputeCommand::BeginPipelineStatisticsQuery { - query_set_id, + ArcComputeCommand::BeginPipelineStatisticsQuery { + query_set, query_index, } => { + let query_set_id = query_set.as_info().id(); let scope = PassErrorScope::BeginPipelineStatisticsQuery; - let query_set: &resource::QuerySet = tracker - .query_sets - .add_single(&*query_set_guard, query_set_id) - .ok_or(ComputePassErrorInner::InvalidQuerySet(query_set_id)) - .map_pass_err(scope)?; + let query_set = tracker.query_sets.insert_single(query_set.clone()); query_set .validate_and_begin_pipeline_statistics_query( raw, query_set_id, - query_index, + *query_index, None, &mut active_query, ) .map_pass_err(scope)?; } - ComputeCommand::EndPipelineStatisticsQuery => { + ArcComputeCommand::EndPipelineStatisticsQuery => { let scope = PassErrorScope::EndPipelineStatisticsQuery; end_pipeline_statistics_query(raw, &*query_set_guard, &mut active_query) @@ -883,33 +845,24 @@ impl Global { } } -pub mod compute_ffi { +pub mod compute_commands { use super::{ComputeCommand, ComputePass}; - use crate::{id, RawString}; - use std::{convert::TryInto, ffi, slice}; + use crate::id; + use std::convert::TryInto; use wgt::{BufferAddress, DynamicOffset}; - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given pointer is - /// valid for `offset_length` elements. - #[no_mangle] - pub unsafe extern "C" fn wgpu_compute_pass_set_bind_group( + pub fn wgpu_compute_pass_set_bind_group( pass: &mut ComputePass, index: u32, bind_group_id: id::BindGroupId, - offsets: *const DynamicOffset, - offset_length: usize, + offsets: &[DynamicOffset], ) { - let redundant = unsafe { - pass.current_bind_groups.set_and_check_redundant( - bind_group_id, - index, - &mut pass.base.dynamic_offsets, - offsets, - offset_length, - ) - }; + let redundant = pass.current_bind_groups.set_and_check_redundant( + bind_group_id, + index, + &mut pass.base.dynamic_offsets, + offsets, + ); if redundant { return; @@ -917,13 +870,12 @@ pub mod compute_ffi { pass.base.commands.push(ComputeCommand::SetBindGroup { index, - num_dynamic_offsets: offset_length, + num_dynamic_offsets: offsets.len(), bind_group_id, }); } - #[no_mangle] - pub extern "C" fn wgpu_compute_pass_set_pipeline( + pub fn wgpu_compute_pass_set_pipeline( pass: &mut ComputePass, pipeline_id: id::ComputePipelineId, ) { @@ -936,47 +888,34 @@ pub mod compute_ffi { .push(ComputeCommand::SetPipeline(pipeline_id)); } - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given pointer is - /// valid for `size_bytes` bytes. - #[no_mangle] - pub unsafe extern "C" fn wgpu_compute_pass_set_push_constant( - pass: &mut ComputePass, - offset: u32, - size_bytes: u32, - data: *const u8, - ) { + pub fn wgpu_compute_pass_set_push_constant(pass: &mut ComputePass, offset: u32, data: &[u8]) { assert_eq!( offset & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), 0, "Push constant offset must be aligned to 4 bytes." ); assert_eq!( - size_bytes & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), + data.len() as u32 & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), 0, "Push constant size must be aligned to 4 bytes." ); - let data_slice = unsafe { slice::from_raw_parts(data, size_bytes as usize) }; let value_offset = pass.base.push_constant_data.len().try_into().expect( "Ran out of push constant space. Don't set 4gb of push constants per ComputePass.", ); pass.base.push_constant_data.extend( - data_slice - .chunks_exact(wgt::PUSH_CONSTANT_ALIGNMENT as usize) + data.chunks_exact(wgt::PUSH_CONSTANT_ALIGNMENT as usize) .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])), ); pass.base.commands.push(ComputeCommand::SetPushConstant { offset, - size_bytes, + size_bytes: data.len() as u32, values_offset: value_offset, }); } - #[no_mangle] - pub extern "C" fn wgpu_compute_pass_dispatch_workgroups( + pub fn wgpu_compute_pass_dispatch_workgroups( pass: &mut ComputePass, groups_x: u32, groups_y: u32, @@ -987,8 +926,7 @@ pub mod compute_ffi { .push(ComputeCommand::Dispatch([groups_x, groups_y, groups_z])); } - #[no_mangle] - pub extern "C" fn wgpu_compute_pass_dispatch_workgroups_indirect( + pub fn wgpu_compute_pass_dispatch_workgroups_indirect( pass: &mut ComputePass, buffer_id: id::BufferId, offset: BufferAddress, @@ -998,17 +936,8 @@ pub mod compute_ffi { .push(ComputeCommand::DispatchIndirect { buffer_id, offset }); } - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given `label` - /// is a valid null-terminated string. - #[no_mangle] - pub unsafe extern "C" fn wgpu_compute_pass_push_debug_group( - pass: &mut ComputePass, - label: RawString, - color: u32, - ) { - let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pub fn wgpu_compute_pass_push_debug_group(pass: &mut ComputePass, label: &str, color: u32) { + let bytes = label.as_bytes(); pass.base.string_data.extend_from_slice(bytes); pass.base.commands.push(ComputeCommand::PushDebugGroup { @@ -1017,22 +946,12 @@ pub mod compute_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_compute_pass_pop_debug_group(pass: &mut ComputePass) { + pub fn wgpu_compute_pass_pop_debug_group(pass: &mut ComputePass) { pass.base.commands.push(ComputeCommand::PopDebugGroup); } - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given `label` - /// is a valid null-terminated string. - #[no_mangle] - pub unsafe extern "C" fn wgpu_compute_pass_insert_debug_marker( - pass: &mut ComputePass, - label: RawString, - color: u32, - ) { - let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pub fn wgpu_compute_pass_insert_debug_marker(pass: &mut ComputePass, label: &str, color: u32) { + let bytes = label.as_bytes(); pass.base.string_data.extend_from_slice(bytes); pass.base.commands.push(ComputeCommand::InsertDebugMarker { @@ -1041,8 +960,7 @@ pub mod compute_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_compute_pass_write_timestamp( + pub fn wgpu_compute_pass_write_timestamp( pass: &mut ComputePass, query_set_id: id::QuerySetId, query_index: u32, @@ -1053,8 +971,7 @@ pub mod compute_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_compute_pass_begin_pipeline_statistics_query( + pub fn wgpu_compute_pass_begin_pipeline_statistics_query( pass: &mut ComputePass, query_set_id: id::QuerySetId, query_index: u32, @@ -1067,8 +984,7 @@ pub mod compute_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_compute_pass_end_pipeline_statistics_query(pass: &mut ComputePass) { + pub fn wgpu_compute_pass_end_pipeline_statistics_query(pass: &mut ComputePass) { pass.base .commands .push(ComputeCommand::EndPipelineStatisticsQuery); diff --git a/third_party/rust/wgpu-core/src/command/compute_command.rs b/third_party/rust/wgpu-core/src/command/compute_command.rs new file mode 100644 index 0000000000..49fdbbec24 --- /dev/null +++ b/third_party/rust/wgpu-core/src/command/compute_command.rs @@ -0,0 +1,322 @@ +use std::sync::Arc; + +use crate::{ + binding_model::BindGroup, + hal_api::HalApi, + id, + pipeline::ComputePipeline, + resource::{Buffer, QuerySet}, +}; + +use super::{ComputePassError, ComputePassErrorInner, PassErrorScope}; + +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum ComputeCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group_id: id::BindGroupId, + }, + + SetPipeline(id::ComputePipelineId), + + /// Set a range of push constants to values stored in `push_constant_data`. + SetPushConstant { + /// The byte offset within the push constant storage to write to. This + /// must be a multiple of four. + offset: u32, + + /// The number of bytes to write. This must be a multiple of four. + size_bytes: u32, + + /// Index in `push_constant_data` of the start of the data + /// to be written. + /// + /// Note: this is not a byte offset like `offset`. Rather, it is the + /// index of the first `u32` element in `push_constant_data` to read. + values_offset: u32, + }, + + Dispatch([u32; 3]), + + DispatchIndirect { + buffer_id: id::BufferId, + offset: wgt::BufferAddress, + }, + + PushDebugGroup { + color: u32, + len: usize, + }, + + PopDebugGroup, + + InsertDebugMarker { + color: u32, + len: usize, + }, + + WriteTimestamp { + query_set_id: id::QuerySetId, + query_index: u32, + }, + + BeginPipelineStatisticsQuery { + query_set_id: id::QuerySetId, + query_index: u32, + }, + + EndPipelineStatisticsQuery, +} + +impl ComputeCommand { + /// Resolves all ids in a list of commands into the corresponding resource Arc. + /// + // TODO: Once resolving is done on-the-fly during recording, this function should be only needed with the replay feature: + // #[cfg(feature = "replay")] + pub fn resolve_compute_command_ids( + hub: &crate::hub::Hub, + commands: &[ComputeCommand], + ) -> Result>, ComputePassError> { + let buffers_guard = hub.buffers.read(); + let bind_group_guard = hub.bind_groups.read(); + let query_set_guard = hub.query_sets.read(); + let pipelines_guard = hub.compute_pipelines.read(); + + let resolved_commands: Vec> = commands + .iter() + .map(|c| -> Result, ComputePassError> { + Ok(match *c { + ComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group_id, + } => ArcComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: bind_group_guard.get_owned(bind_group_id).map_err(|_| { + ComputePassError { + scope: PassErrorScope::SetBindGroup(bind_group_id), + inner: ComputePassErrorInner::InvalidBindGroup(index), + } + })?, + }, + + ComputeCommand::SetPipeline(pipeline_id) => ArcComputeCommand::SetPipeline( + pipelines_guard + .get_owned(pipeline_id) + .map_err(|_| ComputePassError { + scope: PassErrorScope::SetPipelineCompute(pipeline_id), + inner: ComputePassErrorInner::InvalidPipeline(pipeline_id), + })?, + ), + + ComputeCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + } => ArcComputeCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + }, + + ComputeCommand::Dispatch(dim) => ArcComputeCommand::Dispatch(dim), + + ComputeCommand::DispatchIndirect { buffer_id, offset } => { + ArcComputeCommand::DispatchIndirect { + buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { + ComputePassError { + scope: PassErrorScope::Dispatch { + indirect: true, + pipeline: None, // TODO: not used right now, but once we do the resolve during recording we can use this again. + }, + inner: ComputePassErrorInner::InvalidBuffer(buffer_id), + } + })?, + offset, + } + } + + ComputeCommand::PushDebugGroup { color, len } => { + ArcComputeCommand::PushDebugGroup { color, len } + } + + ComputeCommand::PopDebugGroup => ArcComputeCommand::PopDebugGroup, + + ComputeCommand::InsertDebugMarker { color, len } => { + ArcComputeCommand::InsertDebugMarker { color, len } + } + + ComputeCommand::WriteTimestamp { + query_set_id, + query_index, + } => ArcComputeCommand::WriteTimestamp { + query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { + ComputePassError { + scope: PassErrorScope::WriteTimestamp, + inner: ComputePassErrorInner::InvalidQuerySet(query_set_id), + } + })?, + query_index, + }, + + ComputeCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + } => ArcComputeCommand::BeginPipelineStatisticsQuery { + query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { + ComputePassError { + scope: PassErrorScope::BeginPipelineStatisticsQuery, + inner: ComputePassErrorInner::InvalidQuerySet(query_set_id), + } + })?, + query_index, + }, + + ComputeCommand::EndPipelineStatisticsQuery => { + ArcComputeCommand::EndPipelineStatisticsQuery + } + }) + }) + .collect::, ComputePassError>>()?; + Ok(resolved_commands) + } +} + +/// Equivalent to `ComputeCommand` but the Ids resolved into resource Arcs. +#[derive(Clone, Debug)] +pub enum ArcComputeCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group: Arc>, + }, + + SetPipeline(Arc>), + + /// Set a range of push constants to values stored in `push_constant_data`. + SetPushConstant { + /// The byte offset within the push constant storage to write to. This + /// must be a multiple of four. + offset: u32, + + /// The number of bytes to write. This must be a multiple of four. + size_bytes: u32, + + /// Index in `push_constant_data` of the start of the data + /// to be written. + /// + /// Note: this is not a byte offset like `offset`. Rather, it is the + /// index of the first `u32` element in `push_constant_data` to read. + values_offset: u32, + }, + + Dispatch([u32; 3]), + + DispatchIndirect { + buffer: Arc>, + offset: wgt::BufferAddress, + }, + + PushDebugGroup { + color: u32, + len: usize, + }, + + PopDebugGroup, + + InsertDebugMarker { + color: u32, + len: usize, + }, + + WriteTimestamp { + query_set: Arc>, + query_index: u32, + }, + + BeginPipelineStatisticsQuery { + query_set: Arc>, + query_index: u32, + }, + + EndPipelineStatisticsQuery, +} + +#[cfg(feature = "trace")] +impl From<&ArcComputeCommand> for ComputeCommand { + fn from(value: &ArcComputeCommand) -> Self { + use crate::resource::Resource as _; + + match value { + ArcComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group, + } => ComputeCommand::SetBindGroup { + index: *index, + num_dynamic_offsets: *num_dynamic_offsets, + bind_group_id: bind_group.as_info().id(), + }, + + ArcComputeCommand::SetPipeline(pipeline) => { + ComputeCommand::SetPipeline(pipeline.as_info().id()) + } + + ArcComputeCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + } => ComputeCommand::SetPushConstant { + offset: *offset, + size_bytes: *size_bytes, + values_offset: *values_offset, + }, + + ArcComputeCommand::Dispatch(dim) => ComputeCommand::Dispatch(*dim), + + ArcComputeCommand::DispatchIndirect { buffer, offset } => { + ComputeCommand::DispatchIndirect { + buffer_id: buffer.as_info().id(), + offset: *offset, + } + } + + ArcComputeCommand::PushDebugGroup { color, len } => ComputeCommand::PushDebugGroup { + color: *color, + len: *len, + }, + + ArcComputeCommand::PopDebugGroup => ComputeCommand::PopDebugGroup, + + ArcComputeCommand::InsertDebugMarker { color, len } => { + ComputeCommand::InsertDebugMarker { + color: *color, + len: *len, + } + } + + ArcComputeCommand::WriteTimestamp { + query_set, + query_index, + } => ComputeCommand::WriteTimestamp { + query_set_id: query_set.as_info().id(), + query_index: *query_index, + }, + + ArcComputeCommand::BeginPipelineStatisticsQuery { + query_set, + query_index, + } => ComputeCommand::BeginPipelineStatisticsQuery { + query_set_id: query_set.as_info().id(), + query_index: *query_index, + }, + + ArcComputeCommand::EndPipelineStatisticsQuery => { + ComputeCommand::EndPipelineStatisticsQuery + } + } + } +} diff --git a/third_party/rust/wgpu-core/src/command/mod.rs b/third_party/rust/wgpu-core/src/command/mod.rs index febed4fc97..d53f47bf42 100644 --- a/third_party/rust/wgpu-core/src/command/mod.rs +++ b/third_party/rust/wgpu-core/src/command/mod.rs @@ -1,20 +1,23 @@ +mod allocator; mod bind; mod bundle; mod clear; mod compute; +mod compute_command; mod draw; mod memory_init; mod query; mod render; mod transfer; -use std::slice; use std::sync::Arc; pub(crate) use self::clear::clear_texture; pub use self::{ - bundle::*, clear::ClearError, compute::*, draw::*, query::*, render::*, transfer::*, + bundle::*, clear::ClearError, compute::*, compute_command::ComputeCommand, draw::*, query::*, + render::*, transfer::*, }; +pub(crate) use allocator::CommandAllocator; use self::memory_init::CommandBufferTextureMemoryActions; @@ -22,6 +25,7 @@ use crate::device::{Device, DeviceError}; use crate::error::{ErrorFormatter, PrettyError}; use crate::hub::Hub; use crate::id::CommandBufferId; +use crate::lock::{rank, Mutex}; use crate::snatch::SnatchGuard; use crate::init_tracker::BufferInitTrackerAction; @@ -30,7 +34,6 @@ use crate::track::{Tracker, UsageScope}; use crate::{api_log, global::Global, hal_api::HalApi, id, resource_log, Label}; use hal::CommandEncoder as _; -use parking_lot::Mutex; use thiserror::Error; #[cfg(feature = "trace")] @@ -38,23 +41,122 @@ use crate::device::trace::Command as TraceCommand; const PUSH_CONSTANT_CLEAR_ARRAY: &[u32] = &[0_u32; 64]; +/// The current state of a [`CommandBuffer`]. #[derive(Debug)] pub(crate) enum CommandEncoderStatus { + /// Ready to record commands. An encoder's initial state. + /// + /// Command building methods like [`command_encoder_clear_buffer`] and + /// [`command_encoder_run_compute_pass`] require the encoder to be in this + /// state. + /// + /// [`command_encoder_clear_buffer`]: Global::command_encoder_clear_buffer + /// [`command_encoder_run_compute_pass`]: Global::command_encoder_run_compute_pass Recording, + + /// Command recording is complete, and the buffer is ready for submission. + /// + /// [`Global::command_encoder_finish`] transitions a + /// `CommandBuffer` from the `Recording` state into this state. + /// + /// [`Global::queue_submit`] drops command buffers unless they are + /// in this state. Finished, + + /// An error occurred while recording a compute or render pass. + /// + /// When a `CommandEncoder` is left in this state, we have also + /// returned an error result from the function that encountered + /// the problem. Future attempts to use the encoder (that is, + /// calls to [`CommandBuffer::get_encoder`]) will also return + /// errors. + /// + /// Calling [`Global::command_encoder_finish`] in this state + /// discards the command buffer under construction. Error, } +/// A raw [`CommandEncoder`][rce], and the raw [`CommandBuffer`][rcb]s built from it. +/// +/// Each wgpu-core [`CommandBuffer`] owns an instance of this type, which is +/// where the commands are actually stored. +/// +/// This holds a `Vec` of raw [`CommandBuffer`][rcb]s, not just one. We are not +/// always able to record commands in the order in which they must ultimately be +/// submitted to the queue, but raw command buffers don't permit inserting new +/// commands into the middle of a recorded stream. However, hal queue submission +/// accepts a series of command buffers at once, so we can simply break the +/// stream up into multiple buffers, and then reorder the buffers. See +/// [`CommandEncoder::close_and_swap`] for a specific example of this. +/// +/// Note that a [`CommandEncoderId`] actually refers to a [`CommandBuffer`]. +/// Methods that take a command encoder id actually look up the command buffer, +/// and then use its encoder. +/// +/// [rce]: hal::Api::CommandEncoder +/// [rcb]: hal::Api::CommandBuffer +/// [`CommandEncoderId`]: crate::id::CommandEncoderId pub(crate) struct CommandEncoder { + /// The underlying `wgpu_hal` [`CommandEncoder`]. + /// + /// Successfully executed command buffers' encoders are saved in a + /// [`CommandAllocator`] for recycling. + /// + /// [`CommandEncoder`]: hal::Api::CommandEncoder + /// [`CommandAllocator`]: crate::command::CommandAllocator raw: A::CommandEncoder, + + /// All the raw command buffers for our owning [`CommandBuffer`], in + /// submission order. + /// + /// These command buffers were all constructed with `raw`. The + /// [`wgpu_hal::CommandEncoder`] trait forbids these from outliving `raw`, + /// and requires that we provide all of these when we call + /// [`raw.reset_all()`][CE::ra], so the encoder and its buffers travel + /// together. + /// + /// [CE::ra]: hal::CommandEncoder::reset_all + /// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder list: Vec, + + /// True if `raw` is in the "recording" state. + /// + /// See the documentation for [`wgpu_hal::CommandEncoder`] for + /// details on the states `raw` can be in. + /// + /// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder is_open: bool, + label: Option, } //TODO: handle errors better impl CommandEncoder { - /// Closes the live encoder + /// Finish the current command buffer, if any, and place it + /// at the second-to-last position in our list. + /// + /// If we have opened this command encoder, finish its current + /// command buffer, and insert it just before the last element in + /// [`self.list`][l]. If this command buffer is closed, do nothing. + /// + /// On return, the underlying hal encoder is closed. + /// + /// What is this for? + /// + /// The `wgpu_hal` contract requires that each render or compute pass's + /// commands be preceded by calls to [`transition_buffers`] and + /// [`transition_textures`], to put the resources the pass operates on in + /// the appropriate state. Unfortunately, we don't know which transitions + /// are needed until we're done recording the pass itself. Rather than + /// iterating over the pass twice, we note the necessary transitions as we + /// record its commands, finish the raw command buffer for the actual pass, + /// record a new raw command buffer for the transitions, and jam that buffer + /// in just before the pass's. This is the function that jams in the + /// transitions' command buffer. + /// + /// [l]: CommandEncoder::list + /// [`transition_buffers`]: hal::CommandEncoder::transition_buffers + /// [`transition_textures`]: hal::CommandEncoder::transition_textures fn close_and_swap(&mut self) -> Result<(), DeviceError> { if self.is_open { self.is_open = false; @@ -65,6 +167,16 @@ impl CommandEncoder { Ok(()) } + /// Finish the current command buffer, if any, and add it to the + /// end of [`self.list`][l]. + /// + /// If we have opened this command encoder, finish its current + /// command buffer, and push it onto the end of [`self.list`][l]. + /// If this command buffer is closed, do nothing. + /// + /// On return, the underlying hal encoder is closed. + /// + /// [l]: CommandEncoder::list fn close(&mut self) -> Result<(), DeviceError> { if self.is_open { self.is_open = false; @@ -75,6 +187,9 @@ impl CommandEncoder { Ok(()) } + /// Discard the command buffer under construction, if any. + /// + /// The underlying hal encoder is closed, if it was recording. pub(crate) fn discard(&mut self) { if self.is_open { self.is_open = false; @@ -82,7 +197,10 @@ impl CommandEncoder { } } - fn open(&mut self) -> Result<&mut A::CommandEncoder, DeviceError> { + /// Begin recording a new command buffer, if we haven't already. + /// + /// The underlying hal encoder is put in the "recording" state. + pub(crate) fn open(&mut self) -> Result<&mut A::CommandEncoder, DeviceError> { if !self.is_open { self.is_open = true; let label = self.label.as_deref(); @@ -92,6 +210,10 @@ impl CommandEncoder { Ok(&mut self.raw) } + /// Begin recording a new command buffer for a render pass, with + /// its own label. + /// + /// The underlying hal encoder is put in the "recording" state. fn open_pass(&mut self, label: Option<&str>) -> Result<(), DeviceError> { self.is_open = true; unsafe { self.raw.begin_encoding(label)? }; @@ -100,7 +222,7 @@ impl CommandEncoder { } } -pub struct BakedCommands { +pub(crate) struct BakedCommands { pub(crate) encoder: A::CommandEncoder, pub(crate) list: Vec, pub(crate) trackers: Tracker, @@ -111,12 +233,29 @@ pub struct BakedCommands { pub(crate) struct DestroyedBufferError(pub id::BufferId); pub(crate) struct DestroyedTextureError(pub id::TextureId); +/// The mutable state of a [`CommandBuffer`]. pub struct CommandBufferMutable { + /// The [`wgpu_hal::Api::CommandBuffer`]s we've built so far, and the encoder + /// they belong to. + /// + /// [`wgpu_hal::Api::CommandBuffer`]: hal::Api::CommandBuffer pub(crate) encoder: CommandEncoder, + + /// The current state of this command buffer's encoder. status: CommandEncoderStatus, + + /// All the resources that the commands recorded so far have referred to. pub(crate) trackers: Tracker, + + /// The regions of buffers and textures these commands will read and write. + /// + /// This is used to determine which portions of which + /// buffers/textures we actually need to initialize. If we're + /// definitely going to write to something before we read from it, + /// we don't need to clear its contents. buffer_memory_init_actions: Vec>, texture_memory_actions: CommandBufferTextureMemoryActions, + pub(crate) pending_query_resets: QueryResetMap, #[cfg(feature = "trace")] pub(crate) commands: Option>, @@ -133,11 +272,36 @@ impl CommandBufferMutable { } } +/// A buffer of commands to be submitted to the GPU for execution. +/// +/// Whereas the WebGPU API uses two separate types for command buffers and +/// encoders, this type is a fusion of the two: +/// +/// - During command recording, this holds a [`CommandEncoder`] accepting this +/// buffer's commands. In this state, the [`CommandBuffer`] type behaves like +/// a WebGPU `GPUCommandEncoder`. +/// +/// - Once command recording is finished by calling +/// [`Global::command_encoder_finish`], no further recording is allowed. The +/// internal [`CommandEncoder`] is retained solely as a storage pool for the +/// raw command buffers. In this state, the value behaves like a WebGPU +/// `GPUCommandBuffer`. +/// +/// - Once a command buffer is submitted to the queue, it is removed from the id +/// registry, and its contents are taken to construct a [`BakedCommands`], +/// whose contents eventually become the property of the submission queue. pub struct CommandBuffer { pub(crate) device: Arc>, limits: wgt::Limits, support_clear_texture: bool, pub(crate) info: ResourceInfo>, + + /// The mutable state of this command buffer. + /// + /// This `Option` is populated when the command buffer is first created. + /// When this is submitted, dropped, or destroyed, its contents are + /// extracted into a [`BakedCommands`] by + /// [`CommandBuffer::extract_baked_commands`]. pub(crate) data: Mutex>>, } @@ -176,25 +340,28 @@ impl CommandBuffer { .as_str(), None, ), - data: Mutex::new(Some(CommandBufferMutable { - encoder: CommandEncoder { - raw: encoder, - is_open: false, - list: Vec::new(), - label, - }, - status: CommandEncoderStatus::Recording, - trackers: Tracker::new(), - buffer_memory_init_actions: Default::default(), - texture_memory_actions: Default::default(), - pending_query_resets: QueryResetMap::new(), - #[cfg(feature = "trace")] - commands: if enable_tracing { - Some(Vec::new()) - } else { - None - }, - })), + data: Mutex::new( + rank::COMMAND_BUFFER_DATA, + Some(CommandBufferMutable { + encoder: CommandEncoder { + raw: encoder, + is_open: false, + list: Vec::new(), + label, + }, + status: CommandEncoderStatus::Recording, + trackers: Tracker::new(), + buffer_memory_init_actions: Default::default(), + texture_memory_actions: Default::default(), + pending_query_resets: QueryResetMap::new(), + #[cfg(feature = "trace")] + commands: if enable_tracing { + Some(Vec::new()) + } else { + None + }, + }), + ), } } @@ -248,12 +415,18 @@ impl CommandBuffer { } impl CommandBuffer { + /// Return the [`CommandBuffer`] for `id`, for recording new commands. + /// + /// In `wgpu_core`, the [`CommandBuffer`] type serves both as encoder and + /// buffer, which is why this function takes an [`id::CommandEncoderId`] but + /// returns a [`CommandBuffer`]. The returned command buffer must be in the + /// "recording" state. Otherwise, an error is returned. fn get_encoder( hub: &Hub, id: id::CommandEncoderId, ) -> Result, CommandEncoderError> { let storage = hub.command_buffers.read(); - match storage.get(id.transmute()) { + match storage.get(id.into_command_buffer_id()) { Ok(cmd_buf) => match cmd_buf.data.lock().as_ref().unwrap().status { CommandEncoderStatus::Recording => Ok(cmd_buf.clone()), CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording), @@ -286,11 +459,9 @@ impl CommandBuffer { } pub(crate) fn from_arc_into_baked(self: Arc) -> BakedCommands { - if let Some(mut command_buffer) = Arc::into_inner(self) { - command_buffer.extract_baked_commands() - } else { - panic!("CommandBuffer cannot be destroyed because is still in use"); - } + let mut command_buffer = Arc::into_inner(self) + .expect("CommandBuffer cannot be destroyed because is still in use"); + command_buffer.extract_baked_commands() } } @@ -418,7 +589,7 @@ impl Global { let hub = A::hub(self); - let error = match hub.command_buffers.get(encoder_id.transmute()) { + let error = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { Ok(cmd_buf) => { let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -444,7 +615,7 @@ impl Global { Err(_) => Some(CommandEncoderError::Invalid), }; - (encoder_id.transmute(), error) + (encoder_id.into_command_buffer_id(), error) } pub fn command_encoder_push_debug_group( @@ -599,16 +770,15 @@ impl BindGroupStateChange { } } - unsafe fn set_and_check_redundant( + fn set_and_check_redundant( &mut self, bind_group_id: id::BindGroupId, index: u32, dynamic_offsets: &mut Vec, - offsets: *const wgt::DynamicOffset, - offset_length: usize, + offsets: &[wgt::DynamicOffset], ) -> bool { // For now never deduplicate bind groups with dynamic offsets. - if offset_length == 0 { + if offsets.is_empty() { // If this get returns None, that means we're well over the limit, // so let the call through to get a proper error if let Some(current_bind_group) = self.last_states.get_mut(index as usize) { @@ -624,8 +794,7 @@ impl BindGroupStateChange { if let Some(current_bind_group) = self.last_states.get_mut(index as usize) { current_bind_group.reset(); } - dynamic_offsets - .extend_from_slice(unsafe { slice::from_raw_parts(offsets, offset_length) }); + dynamic_offsets.extend_from_slice(offsets); } false } @@ -700,7 +869,7 @@ impl PrettyError for PassErrorScope { // This error is not in the error chain, only notes are needed match *self { Self::Pass(id) => { - fmt.command_buffer_label(&id.transmute()); + fmt.command_buffer_label(&id.into_command_buffer_id()); } Self::SetBindGroup(id) => { fmt.bind_group_label(&id); diff --git a/third_party/rust/wgpu-core/src/command/query.rs b/third_party/rust/wgpu-core/src/command/query.rs index 89cba6fbf3..fd3360cc00 100644 --- a/third_party/rust/wgpu-core/src/command/query.rs +++ b/third_party/rust/wgpu-core/src/command/query.rs @@ -9,7 +9,7 @@ use crate::{ hal_api::HalApi, id::{self, Id}, init_tracker::MemoryInitKind, - resource::QuerySet, + resource::{QuerySet, Resource}, storage::Storage, Epoch, FastHashMap, Index, }; @@ -429,11 +429,20 @@ impl Global { .add_single(&*query_set_guard, query_set_id) .ok_or(QueryError::InvalidQuerySet(query_set_id))?; + if query_set.device.as_info().id() != cmd_buf.device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + let (dst_buffer, dst_pending) = { let buffer_guard = hub.buffers.read(); let dst_buffer = buffer_guard .get(destination) .map_err(|_| QueryError::InvalidBuffer(destination))?; + + if dst_buffer.device.as_info().id() != cmd_buf.device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + tracker .buffers .set_single(dst_buffer, hal::BufferUses::COPY_DST) diff --git a/third_party/rust/wgpu-core/src/command/render.rs b/third_party/rust/wgpu-core/src/command/render.rs index 7e859e3cc8..87dc9aac16 100644 --- a/third_party/rust/wgpu-core/src/command/render.rs +++ b/third_party/rust/wgpu-core/src/command/render.rs @@ -1343,7 +1343,8 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, encoder_id).map_pass_err(pass_scope)?; + let cmd_buf: Arc> = + CommandBuffer::get_encoder(hub, encoder_id).map_pass_err(pass_scope)?; let device = &cmd_buf.device; let snatch_guard = device.snatchable_lock.read(); @@ -2409,7 +2410,10 @@ impl Global { (trackers, pending_discard_init_fixups) }; - let cmd_buf = hub.command_buffers.get(encoder_id.transmute()).unwrap(); + let cmd_buf = hub + .command_buffers + .get(encoder_id.into_command_buffer_id()) + .unwrap(); let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -2455,36 +2459,27 @@ impl Global { } } -pub mod render_ffi { +pub mod render_commands { use super::{ super::{Rect, RenderCommand}, RenderPass, }; - use crate::{id, RawString}; - use std::{convert::TryInto, ffi, num::NonZeroU32, slice}; + use crate::id; + use std::{convert::TryInto, num::NonZeroU32}; use wgt::{BufferAddress, BufferSize, Color, DynamicOffset, IndexFormat}; - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given pointer is - /// valid for `offset_length` elements. - #[no_mangle] - pub unsafe extern "C" fn wgpu_render_pass_set_bind_group( + pub fn wgpu_render_pass_set_bind_group( pass: &mut RenderPass, index: u32, bind_group_id: id::BindGroupId, - offsets: *const DynamicOffset, - offset_length: usize, + offsets: &[DynamicOffset], ) { - let redundant = unsafe { - pass.current_bind_groups.set_and_check_redundant( - bind_group_id, - index, - &mut pass.base.dynamic_offsets, - offsets, - offset_length, - ) - }; + let redundant = pass.current_bind_groups.set_and_check_redundant( + bind_group_id, + index, + &mut pass.base.dynamic_offsets, + offsets, + ); if redundant { return; @@ -2492,16 +2487,12 @@ pub mod render_ffi { pass.base.commands.push(RenderCommand::SetBindGroup { index, - num_dynamic_offsets: offset_length, + num_dynamic_offsets: offsets.len(), bind_group_id, }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_pipeline( - pass: &mut RenderPass, - pipeline_id: id::RenderPipelineId, - ) { + pub fn wgpu_render_pass_set_pipeline(pass: &mut RenderPass, pipeline_id: id::RenderPipelineId) { if pass.current_pipeline.set_and_check_redundant(pipeline_id) { return; } @@ -2511,8 +2502,7 @@ pub mod render_ffi { .push(RenderCommand::SetPipeline(pipeline_id)); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_vertex_buffer( + pub fn wgpu_render_pass_set_vertex_buffer( pass: &mut RenderPass, slot: u32, buffer_id: id::BufferId, @@ -2527,8 +2517,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_index_buffer( + pub fn wgpu_render_pass_set_index_buffer( pass: &mut RenderPass, buffer: id::BufferId, index_format: IndexFormat, @@ -2538,22 +2527,19 @@ pub mod render_ffi { pass.set_index_buffer(buffer, index_format, offset, size); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_blend_constant(pass: &mut RenderPass, color: &Color) { + pub fn wgpu_render_pass_set_blend_constant(pass: &mut RenderPass, color: &Color) { pass.base .commands .push(RenderCommand::SetBlendConstant(*color)); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_stencil_reference(pass: &mut RenderPass, value: u32) { + pub fn wgpu_render_pass_set_stencil_reference(pass: &mut RenderPass, value: u32) { pass.base .commands .push(RenderCommand::SetStencilReference(value)); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_viewport( + pub fn wgpu_render_pass_set_viewport( pass: &mut RenderPass, x: f32, y: f32, @@ -2569,8 +2555,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_scissor_rect( + pub fn wgpu_render_pass_set_scissor_rect( pass: &mut RenderPass, x: u32, y: u32, @@ -2582,17 +2567,11 @@ pub mod render_ffi { .push(RenderCommand::SetScissor(Rect { x, y, w, h })); } - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given pointer is - /// valid for `size_bytes` bytes. - #[no_mangle] - pub unsafe extern "C" fn wgpu_render_pass_set_push_constants( + pub fn wgpu_render_pass_set_push_constants( pass: &mut RenderPass, stages: wgt::ShaderStages, offset: u32, - size_bytes: u32, - data: *const u8, + data: &[u8], ) { assert_eq!( offset & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), @@ -2600,31 +2579,28 @@ pub mod render_ffi { "Push constant offset must be aligned to 4 bytes." ); assert_eq!( - size_bytes & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), + data.len() as u32 & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), 0, "Push constant size must be aligned to 4 bytes." ); - let data_slice = unsafe { slice::from_raw_parts(data, size_bytes as usize) }; let value_offset = pass.base.push_constant_data.len().try_into().expect( "Ran out of push constant space. Don't set 4gb of push constants per RenderPass.", ); pass.base.push_constant_data.extend( - data_slice - .chunks_exact(wgt::PUSH_CONSTANT_ALIGNMENT as usize) + data.chunks_exact(wgt::PUSH_CONSTANT_ALIGNMENT as usize) .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])), ); pass.base.commands.push(RenderCommand::SetPushConstant { stages, offset, - size_bytes, + size_bytes: data.len() as u32, values_offset: Some(value_offset), }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_draw( + pub fn wgpu_render_pass_draw( pass: &mut RenderPass, vertex_count: u32, instance_count: u32, @@ -2639,8 +2615,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_draw_indexed( + pub fn wgpu_render_pass_draw_indexed( pass: &mut RenderPass, index_count: u32, instance_count: u32, @@ -2657,8 +2632,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_draw_indirect( + pub fn wgpu_render_pass_draw_indirect( pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, @@ -2671,8 +2645,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_draw_indexed_indirect( + pub fn wgpu_render_pass_draw_indexed_indirect( pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, @@ -2685,8 +2658,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_multi_draw_indirect( + pub fn wgpu_render_pass_multi_draw_indirect( pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, @@ -2700,8 +2672,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_multi_draw_indexed_indirect( + pub fn wgpu_render_pass_multi_draw_indexed_indirect( pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, @@ -2715,8 +2686,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_multi_draw_indirect_count( + pub fn wgpu_render_pass_multi_draw_indirect_count( pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, @@ -2736,8 +2706,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_multi_draw_indexed_indirect_count( + pub fn wgpu_render_pass_multi_draw_indexed_indirect_count( pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, @@ -2757,17 +2726,8 @@ pub mod render_ffi { }); } - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given `label` - /// is a valid null-terminated string. - #[no_mangle] - pub unsafe extern "C" fn wgpu_render_pass_push_debug_group( - pass: &mut RenderPass, - label: RawString, - color: u32, - ) { - let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pub fn wgpu_render_pass_push_debug_group(pass: &mut RenderPass, label: &str, color: u32) { + let bytes = label.as_bytes(); pass.base.string_data.extend_from_slice(bytes); pass.base.commands.push(RenderCommand::PushDebugGroup { @@ -2776,22 +2736,12 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_pop_debug_group(pass: &mut RenderPass) { + pub fn wgpu_render_pass_pop_debug_group(pass: &mut RenderPass) { pass.base.commands.push(RenderCommand::PopDebugGroup); } - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given `label` - /// is a valid null-terminated string. - #[no_mangle] - pub unsafe extern "C" fn wgpu_render_pass_insert_debug_marker( - pass: &mut RenderPass, - label: RawString, - color: u32, - ) { - let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pub fn wgpu_render_pass_insert_debug_marker(pass: &mut RenderPass, label: &str, color: u32) { + let bytes = label.as_bytes(); pass.base.string_data.extend_from_slice(bytes); pass.base.commands.push(RenderCommand::InsertDebugMarker { @@ -2800,8 +2750,7 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_write_timestamp( + pub fn wgpu_render_pass_write_timestamp( pass: &mut RenderPass, query_set_id: id::QuerySetId, query_index: u32, @@ -2812,23 +2761,17 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_begin_occlusion_query( - pass: &mut RenderPass, - query_index: u32, - ) { + pub fn wgpu_render_pass_begin_occlusion_query(pass: &mut RenderPass, query_index: u32) { pass.base .commands .push(RenderCommand::BeginOcclusionQuery { query_index }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_end_occlusion_query(pass: &mut RenderPass) { + pub fn wgpu_render_pass_end_occlusion_query(pass: &mut RenderPass) { pass.base.commands.push(RenderCommand::EndOcclusionQuery); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_begin_pipeline_statistics_query( + pub fn wgpu_render_pass_begin_pipeline_statistics_query( pass: &mut RenderPass, query_set_id: id::QuerySetId, query_index: u32, @@ -2841,26 +2784,17 @@ pub mod render_ffi { }); } - #[no_mangle] - pub extern "C" fn wgpu_render_pass_end_pipeline_statistics_query(pass: &mut RenderPass) { + pub fn wgpu_render_pass_end_pipeline_statistics_query(pass: &mut RenderPass) { pass.base .commands .push(RenderCommand::EndPipelineStatisticsQuery); } - /// # Safety - /// - /// This function is unsafe as there is no guarantee that the given pointer is - /// valid for `render_bundle_ids_length` elements. - #[no_mangle] - pub unsafe extern "C" fn wgpu_render_pass_execute_bundles( + pub fn wgpu_render_pass_execute_bundles( pass: &mut RenderPass, - render_bundle_ids: *const id::RenderBundleId, - render_bundle_ids_length: usize, + render_bundle_ids: &[id::RenderBundleId], ) { - for &bundle_id in - unsafe { slice::from_raw_parts(render_bundle_ids, render_bundle_ids_length) } - { + for &bundle_id in render_bundle_ids { pass.base .commands .push(RenderCommand::ExecuteBundle(bundle_id)); diff --git a/third_party/rust/wgpu-core/src/command/transfer.rs b/third_party/rust/wgpu-core/src/command/transfer.rs index 8e98a4c9b9..84bc88e723 100644 --- a/third_party/rust/wgpu-core/src/command/transfer.rs +++ b/third_party/rust/wgpu-core/src/command/transfer.rs @@ -607,6 +607,11 @@ impl Global { let src_buffer = buffer_guard .get(source) .map_err(|_| TransferError::InvalidBuffer(source))?; + + if src_buffer.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + cmd_buf_data .trackers .buffers @@ -628,6 +633,11 @@ impl Global { let dst_buffer = buffer_guard .get(destination) .map_err(|_| TransferError::InvalidBuffer(destination))?; + + if dst_buffer.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + cmd_buf_data .trackers .buffers @@ -777,6 +787,10 @@ impl Global { .get(destination.texture) .map_err(|_| TransferError::InvalidTexture(destination.texture))?; + if dst_texture.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + let (hal_copy_size, array_layer_count) = validate_texture_copy_range( destination, &dst_texture.desc, @@ -807,6 +821,11 @@ impl Global { let src_buffer = buffer_guard .get(source.buffer) .map_err(|_| TransferError::InvalidBuffer(source.buffer))?; + + if src_buffer.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + tracker .buffers .set_single(src_buffer, hal::BufferUses::COPY_SRC) @@ -938,6 +957,10 @@ impl Global { .get(source.texture) .map_err(|_| TransferError::InvalidTexture(source.texture))?; + if src_texture.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + let (hal_copy_size, array_layer_count) = validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?; @@ -989,6 +1012,11 @@ impl Global { let dst_buffer = buffer_guard .get(destination.buffer) .map_err(|_| TransferError::InvalidBuffer(destination.buffer))?; + + if dst_buffer.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + tracker .buffers .set_single(dst_buffer, hal::BufferUses::COPY_DST) @@ -1117,6 +1145,13 @@ impl Global { .get(destination.texture) .map_err(|_| TransferError::InvalidTexture(source.texture))?; + if src_texture.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + if dst_texture.device.as_info().id() != device.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + // src and dst texture format must be copy-compatible // https://gpuweb.github.io/gpuweb/#copy-compatible if src_texture.desc.format.remove_srgb_suffix() diff --git a/third_party/rust/wgpu-core/src/device/any_device.rs b/third_party/rust/wgpu-core/src/device/any_device.rs index 693155a753..9e459c1a94 100644 --- a/third_party/rust/wgpu-core/src/device/any_device.rs +++ b/third_party/rust/wgpu-core/src/device/any_device.rs @@ -34,7 +34,7 @@ impl AnyDevice { unsafe fn drop_glue(ptr: *mut ()) { // Drop the arc this instance is holding. unsafe { - _ = Arc::from_raw(ptr.cast::()); + _ = Arc::from_raw(ptr.cast::()); } } diff --git a/third_party/rust/wgpu-core/src/device/bgl.rs b/third_party/rust/wgpu-core/src/device/bgl.rs index d606f049a3..911ac8a435 100644 --- a/third_party/rust/wgpu-core/src/device/bgl.rs +++ b/third_party/rust/wgpu-core/src/device/bgl.rs @@ -58,7 +58,7 @@ impl EntryMap { assert!(self.sorted); } - /// Create a new [`BindGroupLayoutEntryMap`] from a slice of [`wgt::BindGroupLayoutEntry`]s. + /// Create a new [`EntryMap`] from a slice of [`wgt::BindGroupLayoutEntry`]s. /// /// Errors if there are duplicate bindings or if any binding index is greater than /// the device's limits. diff --git a/third_party/rust/wgpu-core/src/device/global.rs b/third_party/rust/wgpu-core/src/device/global.rs index 0c97e1b504..be524840b8 100644 --- a/third_party/rust/wgpu-core/src/device/global.rs +++ b/third_party/rust/wgpu-core/src/device/global.rs @@ -11,6 +11,7 @@ use crate::{ id::{self, AdapterId, DeviceId, QueueId, SurfaceId}, init_tracker::TextureInitTracker, instance::{self, Adapter, Surface}, + lock::{rank, RwLock}, pipeline, present, resource::{self, BufferAccessResult}, resource::{BufferAccessError, BufferMapOperation, CreateBufferError, Resource}, @@ -20,7 +21,6 @@ use crate::{ use arrayvec::ArrayVec; use hal::Device as _; -use parking_lot::RwLock; use wgt::{BufferAddress, TextureFormat}; @@ -257,7 +257,7 @@ impl Global { hal::BufferUses::COPY_DST }; - let (id, resource) = fid.assign(buffer); + let (id, resource) = fid.assign(Arc::new(buffer)); api_log!("Device::create_buffer({desc:?}) -> {id:?}"); device @@ -572,7 +572,7 @@ impl Global { Err(error) => break error, }; - let (id, resource) = fid.assign(texture); + let (id, resource) = fid.assign(Arc::new(texture)); api_log!("Device::create_texture({desc:?}) -> {id:?}"); device @@ -643,10 +643,12 @@ impl Global { texture.hal_usage |= hal::TextureUses::COPY_DST; } - texture.initialization_status = - RwLock::new(TextureInitTracker::new(desc.mip_level_count, 0)); + texture.initialization_status = RwLock::new( + rank::TEXTURE_INITIALIZATION_STATUS, + TextureInitTracker::new(desc.mip_level_count, 0), + ); - let (id, resource) = fid.assign(texture); + let (id, resource) = fid.assign(Arc::new(texture)); api_log!("Device::create_texture({desc:?}) -> {id:?}"); device @@ -699,7 +701,7 @@ impl Global { let buffer = device.create_buffer_from_hal(hal_buffer, desc); - let (id, buffer) = fid.assign(buffer); + let (id, buffer) = fid.assign(Arc::new(buffer)); api_log!("Device::create_buffer -> {id:?}"); device @@ -818,7 +820,7 @@ impl Global { Err(e) => break e, }; - let (id, resource) = fid.assign(view); + let (id, resource) = fid.assign(Arc::new(view)); { let mut views = texture.views.lock(); @@ -900,7 +902,7 @@ impl Global { Err(e) => break e, }; - let (id, resource) = fid.assign(sampler); + let (id, resource) = fid.assign(Arc::new(sampler)); api_log!("Device::create_sampler -> {id:?}"); device.trackers.lock().samplers.insert_single(resource); @@ -982,7 +984,7 @@ impl Global { let bgl = device.create_bind_group_layout(&desc.label, entry_map, bgl::Origin::Pool)?; - let (id_inner, arc) = fid.take().unwrap().assign(bgl); + let (id_inner, arc) = fid.take().unwrap().assign(Arc::new(bgl)); id = Some(id_inner); Ok(arc) @@ -1063,7 +1065,7 @@ impl Global { Err(e) => break e, }; - let (id, _) = fid.assign(layout); + let (id, _) = fid.assign(Arc::new(layout)); api_log!("Device::create_pipeline_layout -> {id:?}"); return (id, None); }; @@ -1130,7 +1132,7 @@ impl Global { Err(e) => break e, }; - let (id, resource) = fid.assign(bind_group); + let (id, resource) = fid.assign(Arc::new(bind_group)); let weak_ref = Arc::downgrade(&resource); for range in &resource.used_texture_ranges { @@ -1170,6 +1172,20 @@ impl Global { } } + /// Create a shader module with the given `source`. + /// + ///

    pub fn device_create_shader_module( &self, device_id: DeviceId, @@ -1231,7 +1247,7 @@ impl Global { Err(e) => break e, }; - let (id, _) = fid.assign(shader); + let (id, _) = fid.assign(Arc::new(shader)); api_log!("Device::create_shader_module -> {id:?}"); return (id, None); }; @@ -1288,7 +1304,7 @@ impl Global { Ok(shader) => shader, Err(e) => break e, }; - let (id, _) = fid.assign(shader); + let (id, _) = fid.assign(Arc::new(shader)); api_log!("Device::create_shader_module_spirv -> {id:?}"); return (id, None); }; @@ -1320,7 +1336,9 @@ impl Global { profiling::scope!("Device::create_command_encoder"); let hub = A::hub(self); - let fid = hub.command_buffers.prepare(id_in.map(|id| id.transmute())); + let fid = hub + .command_buffers + .prepare(id_in.map(|id| id.into_command_buffer_id())); let error = loop { let device = match hub.devices.get(device_id) { @@ -1335,9 +1353,6 @@ impl Global { }; let encoder = match device .command_allocator - .lock() - .as_mut() - .unwrap() .acquire_encoder(device.raw(), queue.raw.as_ref().unwrap()) { Ok(raw) => raw, @@ -1353,13 +1368,13 @@ impl Global { .map(|s| s.to_string()), ); - let (id, _) = fid.assign(command_buffer); + let (id, _) = fid.assign(Arc::new(command_buffer)); api_log!("Device::create_command_encoder -> {id:?}"); - return (id.transmute(), None); + return (id.into_command_encoder_id(), None); }; let id = fid.assign_error(desc.label.borrow_or_default()); - (id.transmute(), Some(error)) + (id.into_command_encoder_id(), Some(error)) } pub fn command_buffer_label(&self, id: id::CommandBufferId) -> String { @@ -1374,7 +1389,7 @@ impl Global { if let Some(cmd_buf) = hub .command_buffers - .unregister(command_encoder_id.transmute()) + .unregister(command_encoder_id.into_command_buffer_id()) { cmd_buf.data.lock().as_mut().unwrap().encoder.discard(); cmd_buf @@ -1386,7 +1401,7 @@ impl Global { pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) { profiling::scope!("CommandBuffer::drop"); api_log!("CommandBuffer::drop {command_buffer_id:?}"); - self.command_encoder_drop::(command_buffer_id.transmute()) + self.command_encoder_drop::(command_buffer_id.into_command_encoder_id()) } pub fn device_create_render_bundle_encoder( @@ -1446,7 +1461,7 @@ impl Global { Err(e) => break e, }; - let (id, resource) = fid.assign(render_bundle); + let (id, resource) = fid.assign(Arc::new(render_bundle)); api_log!("RenderBundleEncoder::finish -> {id:?}"); device.trackers.lock().bundles.insert_single(resource); return (id, None); @@ -1509,7 +1524,7 @@ impl Global { Err(err) => break err, }; - let (id, resource) = fid.assign(query_set); + let (id, resource) = fid.assign(Arc::new(query_set)); api_log!("Device::create_query_set -> {id:?}"); device.trackers.lock().query_sets.insert_single(resource); @@ -1587,7 +1602,7 @@ impl Global { Err(e) => break e, }; - let (id, resource) = fid.assign(pipeline); + let (id, resource) = fid.assign(Arc::new(pipeline)); api_log!("Device::create_render_pipeline -> {id:?}"); device @@ -1720,7 +1735,7 @@ impl Global { Err(e) => break e, }; - let (id, resource) = fid.assign(pipeline); + let (id, resource) = fid.assign(Arc::new(pipeline)); api_log!("Device::create_compute_pipeline -> {id:?}"); device @@ -1956,7 +1971,7 @@ impl Global { }; let caps = unsafe { - let suf = A::get_surface(surface); + let suf = A::surface_as_hal(surface); let adapter = &device.adapter; match adapter.raw.adapter.surface_capabilities(suf.unwrap()) { Some(caps) => caps, @@ -2018,7 +2033,6 @@ impl Global { // Wait for all work to finish before configuring the surface. let snatch_guard = device.snatchable_lock.read(); let fence = device.fence.read(); - let fence = fence.as_ref().unwrap(); match device.maintain(fence, wgt::Maintain::Wait, snatch_guard) { Ok((closures, _)) => { user_callbacks = closures; @@ -2042,7 +2056,7 @@ impl Global { // https://github.com/gfx-rs/wgpu/issues/4105 match unsafe { - A::get_surface(surface) + A::surface_as_hal(surface) .unwrap() .configure(device.raw(), &hal_config) } { @@ -2107,7 +2121,7 @@ impl Global { .map_err(|_| DeviceError::Invalid)?; if let wgt::Maintain::WaitForSubmissionIndex(submission_index) = maintain { - if submission_index.queue_id != device_id.transmute() { + if submission_index.queue_id != device_id.into_queue_id() { return Err(WaitIdleError::WrongSubmissionIndex( submission_index.queue_id, device_id, @@ -2131,7 +2145,6 @@ impl Global { ) -> Result { let snatch_guard = device.snatchable_lock.read(); let fence = device.fence.read(); - let fence = fence.as_ref().unwrap(); let (closures, queue_empty) = device.maintain(fence, maintain, snatch_guard)?; // Some deferred destroys are scheduled in maintain so run this right after diff --git a/third_party/rust/wgpu-core/src/device/life.rs b/third_party/rust/wgpu-core/src/device/life.rs index af345015df..0df580e6e6 100644 --- a/third_party/rust/wgpu-core/src/device/life.rs +++ b/third_party/rust/wgpu-core/src/device/life.rs @@ -7,6 +7,7 @@ use crate::{ }, hal_api::HalApi, id, + lock::Mutex, pipeline::{ComputePipeline, RenderPipeline}, resource::{ self, Buffer, DestroyedBuffer, DestroyedTexture, QuerySet, Resource, Sampler, @@ -18,12 +19,10 @@ use crate::{ }; use smallvec::SmallVec; -use parking_lot::Mutex; use std::sync::Arc; use thiserror::Error; /// A struct that keeps lists of resources that are no longer needed by the user. -#[derive(Default)] pub(crate) struct ResourceMaps { pub buffers: FastHashMap>>, pub staging_buffers: FastHashMap>>, @@ -94,7 +93,7 @@ impl ResourceMaps { destroyed_textures.clear(); } - pub(crate) fn extend(&mut self, mut other: Self) { + pub(crate) fn extend(&mut self, other: &mut Self) { let ResourceMaps { buffers, staging_buffers, @@ -128,7 +127,37 @@ impl ResourceMaps { } } -/// Resources used by a queue submission, and work to be done once it completes. +/// A command submitted to the GPU for execution. +/// +/// ## Keeping resources alive while the GPU is using them +/// +/// [`wgpu_hal`] requires that, when a command is submitted to a queue, all the +/// resources it uses must remain alive until it has finished executing. +/// +/// The natural way to satisfy this would be for `ActiveSubmission` to hold +/// strong references to all the resources used by its commands. However, that +/// would entail dropping those strong references every time a queue submission +/// finishes, adjusting the reference counts of all the resources it used. This +/// is usually needless work: it's rare for the active submission queue to be +/// the final reference to an object. Usually the user is still holding on to +/// it. +/// +/// To avoid this, an `ActiveSubmission` does not initially hold any strong +/// references to its commands' resources. Instead, each resource tracks the +/// most recent submission index at which it has been used in +/// [`ResourceInfo::submission_index`]. When the user drops a resource, if the +/// submission in which it was last used is still present in the device's queue, +/// we add the resource to [`ActiveSubmission::last_resources`]. Finally, when +/// this `ActiveSubmission` is dequeued and dropped in +/// [`LifetimeTracker::triage_submissions`], we drop `last_resources` along with +/// it. Thus, unless a resource is dropped by the user, it doesn't need to be +/// touched at all when processing completed work. +/// +/// However, it's not clear that this is effective. See [#5560]. +/// +/// [`wgpu_hal`]: hal +/// [`ResourceInfo::submission_index`]: crate::resource::ResourceInfo +/// [#5560]: https://github.com/gfx-rs/wgpu/issues/5560 struct ActiveSubmission { /// The index of the submission we track. /// @@ -150,6 +179,18 @@ struct ActiveSubmission { /// Buffers to be mapped once this submission has completed. mapped: Vec>>, + /// Command buffers used by this submission, and the encoder that owns them. + /// + /// [`wgpu_hal::Queue::submit`] requires the submitted command buffers to + /// remain alive until the submission has completed execution. Command + /// encoders double as allocation pools for command buffers, so holding them + /// here and cleaning them up in [`LifetimeTracker::triage_submissions`] + /// satisfies that requirement. + /// + /// Once this submission has completed, the command buffers are reset and + /// the command encoder is recycled. + /// + /// [`wgpu_hal::Queue::submit`]: hal::Queue::submit encoders: Vec>, /// List of queue "on_submitted_work_done" closures to be called once this @@ -330,28 +371,25 @@ impl LifetimeTracker { /// /// Assume that all submissions up through `last_done` have completed. /// - /// - Buffers used by those submissions are now ready to map, if - /// requested. Add any buffers in the submission's [`mapped`] list to - /// [`self.ready_to_map`], where [`LifetimeTracker::handle_mapping`] will find - /// them. + /// - Buffers used by those submissions are now ready to map, if requested. + /// Add any buffers in the submission's [`mapped`] list to + /// [`self.ready_to_map`], where [`LifetimeTracker::handle_mapping`] + /// will find them. /// /// - Resources whose final use was in those submissions are now ready to - /// free. Add any resources in the submission's [`last_resources`] table - /// to [`self.free_resources`], where [`LifetimeTracker::cleanup`] will find - /// them. + /// free. Dropping the submission's [`last_resources`] table does so. /// /// Return a list of [`SubmittedWorkDoneClosure`]s to run. /// /// [`mapped`]: ActiveSubmission::mapped /// [`self.ready_to_map`]: LifetimeTracker::ready_to_map /// [`last_resources`]: ActiveSubmission::last_resources - /// [`self.free_resources`]: LifetimeTracker::free_resources /// [`SubmittedWorkDoneClosure`]: crate::device::queue::SubmittedWorkDoneClosure #[must_use] pub fn triage_submissions( &mut self, last_done: SubmissionIndex, - command_allocator: &mut super::CommandAllocator, + command_allocator: &crate::command::CommandAllocator, ) -> SmallVec<[SubmittedWorkDoneClosure; 1]> { profiling::scope!("triage_submissions"); @@ -558,6 +596,18 @@ impl LifetimeTracker { &mut trackers.textures, |maps| &mut maps.textures, ); + + // We may have been suspected because a texture view or bind group + // referring to us was dropped. Remove stale weak references, so that + // the backlink table doesn't grow without bound. + for texture in self.suspected_resources.textures.values() { + texture.views.lock().retain(|view| view.strong_count() > 0); + texture + .bind_groups + .lock() + .retain(|bg| bg.strong_count() > 0); + } + self } @@ -583,6 +633,13 @@ impl LifetimeTracker { |maps| &mut maps.buffers, ); + // We may have been suspected because a bind group referring to us was + // dropped. Remove stale weak references, so that the backlink table + // doesn't grow without bound. + for buffer in self.suspected_resources.buffers.values() { + buffer.bind_groups.lock().retain(|bg| bg.strong_count() > 0); + } + self } @@ -693,13 +750,10 @@ impl LifetimeTracker { /// Identify resources to free, according to `trackers` and `self.suspected_resources`. /// - /// Given `trackers`, the [`Tracker`] belonging to same [`Device`] as - /// `self`, and `hub`, the [`Hub`] to which that `Device` belongs: - /// - /// Remove from `trackers` each resource mentioned in - /// [`self.suspected_resources`]. If `trackers` held the final reference to - /// that resource, add it to the appropriate free list, to be destroyed by - /// the hal: + /// Remove from `trackers`, the [`Tracker`] belonging to same [`Device`] as + /// `self`, each resource mentioned in [`self.suspected_resources`]. If + /// `trackers` held the final reference to that resource, add it to the + /// appropriate free list, to be destroyed by the hal: /// /// - Add resources used by queue submissions still in flight to the /// [`last_resources`] table of the last such submission's entry in @@ -799,29 +853,33 @@ impl LifetimeTracker { *buffer.map_state.lock() = resource::BufferMapState::Idle; log::trace!("Buffer ready to map {tracker_index:?} is not tracked anymore"); } else { - let mapping = match std::mem::replace( + // This _cannot_ be inlined into the match. If it is, the lock will be held + // open through the whole match, resulting in a deadlock when we try to re-lock + // the buffer back to active. + let mapping = std::mem::replace( &mut *buffer.map_state.lock(), resource::BufferMapState::Idle, - ) { + ); + let pending_mapping = match mapping { resource::BufferMapState::Waiting(pending_mapping) => pending_mapping, // Mapping cancelled resource::BufferMapState::Idle => continue, // Mapping queued at least twice by map -> unmap -> map // and was already successfully mapped below - active @ resource::BufferMapState::Active { .. } => { - *buffer.map_state.lock() = active; + resource::BufferMapState::Active { .. } => { + *buffer.map_state.lock() = mapping; continue; } _ => panic!("No pending mapping."), }; - let status = if mapping.range.start != mapping.range.end { + let status = if pending_mapping.range.start != pending_mapping.range.end { log::debug!("Buffer {tracker_index:?} map state -> Active"); - let host = mapping.op.host; - let size = mapping.range.end - mapping.range.start; + let host = pending_mapping.op.host; + let size = pending_mapping.range.end - pending_mapping.range.start; match super::map_buffer( raw, &buffer, - mapping.range.start, + pending_mapping.range.start, size, host, snatch_guard, @@ -829,7 +887,8 @@ impl LifetimeTracker { Ok(ptr) => { *buffer.map_state.lock() = resource::BufferMapState::Active { ptr, - range: mapping.range.start..mapping.range.start + size, + range: pending_mapping.range.start + ..pending_mapping.range.start + size, host, }; Ok(()) @@ -842,12 +901,12 @@ impl LifetimeTracker { } else { *buffer.map_state.lock() = resource::BufferMapState::Active { ptr: std::ptr::NonNull::dangling(), - range: mapping.range, - host: mapping.op.host, + range: pending_mapping.range, + host: pending_mapping.op.host, }; Ok(()) }; - pending_callbacks.push((mapping.op, status)); + pending_callbacks.push((pending_mapping.op, status)); } } pending_callbacks diff --git a/third_party/rust/wgpu-core/src/device/mod.rs b/third_party/rust/wgpu-core/src/device/mod.rs index e2ab6c2690..e9da11b7a8 100644 --- a/third_party/rust/wgpu-core/src/device/mod.rs +++ b/third_party/rust/wgpu-core/src/device/mod.rs @@ -4,7 +4,6 @@ use crate::{ hub::Hub, id::{BindGroupLayoutId, PipelineLayoutId}, resource::{Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation}, - resource_log, snatch::SnatchGuard, Label, DOWNLEVEL_ERROR_MESSAGE, }; @@ -377,42 +376,6 @@ fn map_buffer( Ok(mapping.ptr) } -pub(crate) struct CommandAllocator { - free_encoders: Vec, -} - -impl CommandAllocator { - fn acquire_encoder( - &mut self, - device: &A::Device, - queue: &A::Queue, - ) -> Result { - match self.free_encoders.pop() { - Some(encoder) => Ok(encoder), - None => unsafe { - let hal_desc = hal::CommandEncoderDescriptor { label: None, queue }; - device.create_command_encoder(&hal_desc) - }, - } - } - - fn release_encoder(&mut self, encoder: A::CommandEncoder) { - self.free_encoders.push(encoder); - } - - fn dispose(self, device: &A::Device) { - resource_log!( - "CommandAllocator::dispose encoders {}", - self.free_encoders.len() - ); - for cmd_encoder in self.free_encoders { - unsafe { - device.destroy_command_encoder(cmd_encoder); - } - } - } -} - #[derive(Clone, Debug, Error)] #[error("Device is invalid")] pub struct InvalidDevice; diff --git a/third_party/rust/wgpu-core/src/device/queue.rs b/third_party/rust/wgpu-core/src/device/queue.rs index 3cb5f695a7..f0db961ffc 100644 --- a/third_party/rust/wgpu-core/src/device/queue.rs +++ b/third_party/rust/wgpu-core/src/device/queue.rs @@ -4,16 +4,17 @@ use crate::{ api_log, command::{ extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range, - ClearError, CommandBuffer, CopySide, ImageCopyTexture, TransferError, + ClearError, CommandAllocator, CommandBuffer, CopySide, ImageCopyTexture, TransferError, }, conv, - device::{life::ResourceMaps, DeviceError, WaitIdleError}, + device::{DeviceError, WaitIdleError}, get_lowest_common_denom, global::Global, hal_api::HalApi, hal_label, id::{self, DeviceId, QueueId}, init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange}, + lock::{rank, Mutex, RwLockWriteGuard}, resource::{ Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource, ResourceInfo, ResourceType, StagingBuffer, Texture, TextureInner, @@ -22,7 +23,6 @@ use crate::{ }; use hal::{CommandEncoder as _, Device as _, Queue as _}; -use parking_lot::Mutex; use smallvec::SmallVec; use std::{ @@ -34,9 +34,9 @@ use thiserror::Error; use super::Device; pub struct Queue { - pub device: Option>>, - pub raw: Option, - pub info: ResourceInfo>, + pub(crate) device: Option>>, + pub(crate) raw: Option, + pub(crate) info: ResourceInfo>, } impl Resource for Queue { @@ -152,13 +152,21 @@ pub enum TempResource { Texture(Arc>), } -/// A queue execution for a particular command encoder. +/// A series of raw [`CommandBuffer`]s that have been submitted to a +/// queue, and the [`wgpu_hal::CommandEncoder`] that built them. +/// +/// [`CommandBuffer`]: hal::Api::CommandBuffer +/// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder pub(crate) struct EncoderInFlight { raw: A::CommandEncoder, cmd_buffers: Vec, } impl EncoderInFlight { + /// Free all of our command buffers. + /// + /// Return the command encoder, fully reset and ready to be + /// reused. pub(crate) unsafe fn land(mut self) -> A::CommandEncoder { unsafe { self.raw.reset_all(self.cmd_buffers.into_iter()) }; self.raw @@ -192,6 +200,8 @@ pub(crate) struct PendingWrites { /// True if `command_encoder` is in the "recording" state, as /// described in the docs for the [`wgpu_hal::CommandEncoder`] /// trait. + /// + /// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder pub is_recording: bool, pub temp_resources: Vec>, @@ -253,7 +263,7 @@ impl PendingWrites { #[must_use] fn post_submit( &mut self, - command_allocator: &mut super::CommandAllocator, + command_allocator: &CommandAllocator, device: &A::Device, queue: &A::Queue, ) -> Option> { @@ -307,7 +317,7 @@ fn prepare_staging_buffer( let mapping = unsafe { device.raw().map_buffer(&buffer, 0..size) }?; let staging_buffer = StagingBuffer { - raw: Mutex::new(Some(buffer)), + raw: Mutex::new(rank::STAGING_BUFFER_RAW, Some(buffer)), device: device.clone(), size, info: ResourceInfo::new( @@ -490,7 +500,7 @@ impl Global { prepare_staging_buffer(device, buffer_size.get(), device.instance_flags)?; let fid = hub.staging_buffers.prepare(id_in); - let (id, _) = fid.assign(staging_buffer); + let (id, _) = fid.assign(Arc::new(staging_buffer)); resource_log!("Queue::create_staging_buffer {id:?}"); Ok((id, staging_buffer_ptr)) @@ -707,7 +717,7 @@ impl Global { .get(destination.texture) .map_err(|_| TransferError::InvalidTexture(destination.texture))?; - if dst.device.as_info().id() != queue_id.transmute() { + if dst.device.as_info().id().into_queue_id() != queue_id { return Err(DeviceError::WrongDevice.into()); } @@ -1152,8 +1162,8 @@ impl Global { let snatch_guard = device.snatchable_lock.read(); // Fence lock must be acquired after the snatch lock everywhere to avoid deadlocks. - let mut fence = device.fence.write(); - let fence = fence.as_mut().unwrap(); + let mut fence_guard = device.fence.write(); + let fence = fence_guard.as_mut().unwrap(); let submit_index = device .active_submission_index .fetch_add(1, Ordering::Relaxed) @@ -1173,11 +1183,6 @@ impl Global { //TODO: if multiple command buffers are submitted, we can re-use the last // native command buffer of the previous chain instead of always creating // a temporary one, since the chains are not finished. - let mut temp_suspected = device.temp_suspected.lock(); - { - let mut suspected = temp_suspected.replace(ResourceMaps::new()).unwrap(); - suspected.clear(); - } // finish all the command buffers first for &cmb_id in command_buffer_ids { @@ -1191,7 +1196,7 @@ impl Global { Err(_) => continue, }; - if cmdbuf.device.as_info().id() != queue_id.transmute() { + if cmdbuf.device.as_info().id().into_queue_id() != queue_id { return Err(DeviceError::WrongDevice.into()); } @@ -1210,13 +1215,10 @@ impl Global { )); } if !cmdbuf.is_finished() { - if let Some(cmdbuf) = Arc::into_inner(cmdbuf) { - device.destroy_command_buffer(cmdbuf); - } else { - panic!( - "Command buffer cannot be destroyed because is still in use" - ); - } + let cmdbuf = Arc::into_inner(cmdbuf).expect( + "Command buffer cannot be destroyed because is still in use", + ); + device.destroy_command_buffer(cmdbuf); continue; } @@ -1228,41 +1230,23 @@ impl Global { // update submission IDs for buffer in cmd_buf_trackers.buffers.used_resources() { - let tracker_index = buffer.info.tracker_index(); - let raw_buf = match buffer.raw.get(&snatch_guard) { - Some(raw) => raw, - None => { - return Err(QueueSubmitError::DestroyedBuffer( - buffer.info.id(), - )); - } - }; + if buffer.raw.get(&snatch_guard).is_none() { + return Err(QueueSubmitError::DestroyedBuffer( + buffer.info.id(), + )); + } buffer.info.use_at(submit_index); - if buffer.is_unique() { - if let BufferMapState::Active { .. } = *buffer.map_state.lock() - { - log::warn!("Dropped buffer has a pending mapping."); - unsafe { device.raw().unmap_buffer(raw_buf) } - .map_err(DeviceError::from)?; - } - temp_suspected - .as_mut() - .unwrap() - .buffers - .insert(tracker_index, buffer.clone()); - } else { - match *buffer.map_state.lock() { - BufferMapState::Idle => (), - _ => { - return Err(QueueSubmitError::BufferStillMapped( - buffer.info.id(), - )) - } + + match *buffer.map_state.lock() { + BufferMapState::Idle => (), + _ => { + return Err(QueueSubmitError::BufferStillMapped( + buffer.info.id(), + )) } } } for texture in cmd_buf_trackers.textures.used_resources() { - let tracker_index = texture.info.tracker_index(); let should_extend = match texture.inner.get(&snatch_guard) { None => { return Err(QueueSubmitError::DestroyedTexture( @@ -1279,13 +1263,6 @@ impl Global { } }; texture.info.use_at(submit_index); - if texture.is_unique() { - temp_suspected - .as_mut() - .unwrap() - .textures - .insert(tracker_index, texture.clone()); - } if should_extend { unsafe { used_surface_textures @@ -1296,12 +1273,6 @@ impl Global { } for texture_view in cmd_buf_trackers.views.used_resources() { texture_view.info.use_at(submit_index); - if texture_view.is_unique() { - temp_suspected.as_mut().unwrap().texture_views.insert( - texture_view.as_info().tracker_index(), - texture_view.clone(), - ); - } } { for bg in cmd_buf_trackers.bind_groups.used_resources() { @@ -1315,13 +1286,6 @@ impl Global { for sampler in bg.used.samplers.used_resources() { sampler.info.use_at(submit_index); } - if bg.is_unique() { - temp_suspected - .as_mut() - .unwrap() - .bind_groups - .insert(bg.as_info().tracker_index(), bg.clone()); - } } } // assert!(cmd_buf_trackers.samplers.is_empty()); @@ -1329,32 +1293,14 @@ impl Global { cmd_buf_trackers.compute_pipelines.used_resources() { compute_pipeline.info.use_at(submit_index); - if compute_pipeline.is_unique() { - temp_suspected.as_mut().unwrap().compute_pipelines.insert( - compute_pipeline.as_info().tracker_index(), - compute_pipeline.clone(), - ); - } } for render_pipeline in cmd_buf_trackers.render_pipelines.used_resources() { render_pipeline.info.use_at(submit_index); - if render_pipeline.is_unique() { - temp_suspected.as_mut().unwrap().render_pipelines.insert( - render_pipeline.as_info().tracker_index(), - render_pipeline.clone(), - ); - } } for query_set in cmd_buf_trackers.query_sets.used_resources() { query_set.info.use_at(submit_index); - if query_set.is_unique() { - temp_suspected.as_mut().unwrap().query_sets.insert( - query_set.as_info().tracker_index(), - query_set.clone(), - ); - } } for bundle in cmd_buf_trackers.bundles.used_resources() { bundle.info.use_at(submit_index); @@ -1369,13 +1315,6 @@ impl Global { for query_set in bundle.used.query_sets.read().used_resources() { query_set.info.use_at(submit_index); } - if bundle.is_unique() { - temp_suspected - .as_mut() - .unwrap() - .render_bundles - .insert(bundle.as_info().tracker_index(), bundle.clone()); - } } } let mut baked = cmdbuf.from_arc_into_baked(); @@ -1452,8 +1391,8 @@ impl Global { } } - let mut pending_writes = device.pending_writes.lock(); - let pending_writes = pending_writes.as_mut().unwrap(); + let mut pending_writes_guard = device.pending_writes.lock(); + let pending_writes = pending_writes_guard.as_mut().unwrap(); { used_surface_textures.set_size(hub.textures.read().len()); @@ -1528,7 +1467,7 @@ impl Global { profiling::scope!("cleanup"); if let Some(pending_execution) = pending_writes.post_submit( - device.command_allocator.lock().as_mut().unwrap(), + &device.command_allocator, device.raw(), queue.raw.as_ref().unwrap(), ) { @@ -1543,18 +1482,22 @@ impl Global { active_executions, ); - // This will schedule destruction of all resources that are no longer needed - // by the user but used in the command stream, among other things. - let (closures, _) = match device.maintain(fence, wgt::Maintain::Poll, snatch_guard) { - Ok(closures) => closures, - Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)), - Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu), - Err(WaitIdleError::WrongSubmissionIndex(..)) => unreachable!(), - }; - // pending_write_resources has been drained, so it's empty, but we // want to retain its heap allocation. pending_writes.temp_resources = pending_write_resources; + drop(pending_writes_guard); + + // This will schedule destruction of all resources that are no longer needed + // by the user but used in the command stream, among other things. + let fence_guard = RwLockWriteGuard::downgrade(fence_guard); + let (closures, _) = + match device.maintain(fence_guard, wgt::Maintain::Poll, snatch_guard) { + Ok(closures) => closures, + Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)), + Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu), + Err(WaitIdleError::WrongSubmissionIndex(..)) => unreachable!(), + }; + device.lock_life().post_submit(); (submit_index, closures) diff --git a/third_party/rust/wgpu-core/src/device/resource.rs b/third_party/rust/wgpu-core/src/device/resource.rs index 4892aecb75..2541af7c70 100644 --- a/third_party/rust/wgpu-core/src/device/resource.rs +++ b/third_party/rust/wgpu-core/src/device/resource.rs @@ -7,18 +7,20 @@ use crate::{ bgl, life::{LifetimeTracker, WaitIdleError}, queue::PendingWrites, - AttachmentData, CommandAllocator, DeviceLostInvocation, MissingDownlevelFlags, - MissingFeatures, RenderPassContext, CLEANUP_WAIT_MS, + AttachmentData, DeviceLostInvocation, MissingDownlevelFlags, MissingFeatures, + RenderPassContext, CLEANUP_WAIT_MS, }, hal_api::HalApi, hal_label, hub::Hub, + id, init_tracker::{ BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange, TextureInitTracker, TextureInitTrackerAction, }, instance::Adapter, - pipeline, + lock::{rank, Mutex, MutexGuard, RwLock}, + pipeline::{self}, pool::ResourcePool, registry::Registry, resource::{ @@ -41,7 +43,6 @@ use crate::{ use arrayvec::ArrayVec; use hal::{CommandEncoder as _, Device as _}; use once_cell::sync::OnceCell; -use parking_lot::{Mutex, MutexGuard, RwLock}; use smallvec::SmallVec; use thiserror::Error; @@ -97,7 +98,7 @@ pub struct Device { pub(crate) zero_buffer: Option, pub(crate) info: ResourceInfo>, - pub(crate) command_allocator: Mutex>>, + pub(crate) command_allocator: command::CommandAllocator, //Note: The submission index here corresponds to the last submission that is done. pub(crate) active_submission_index: AtomicU64, //SubmissionIndex, // NOTE: if both are needed, the `snatchable_lock` must be consistently acquired before the @@ -126,9 +127,6 @@ pub struct Device { pub(crate) tracker_indices: TrackerIndexAllocators, // Life tracker should be locked right after the device and before anything else. life_tracker: Mutex>, - /// Temporary storage for resource management functions. Cleared at the end - /// of every call (unless an error occurs). - pub(crate) temp_suspected: Mutex>>, /// Pool of bind group layouts, allowing deduplication. pub(crate) bgl_pool: ResourcePool>, pub(crate) alignments: hal::Alignments, @@ -141,6 +139,10 @@ pub struct Device { #[cfg(feature = "trace")] pub(crate) trace: Mutex>, pub(crate) usage_scopes: UsageScopePool, + + /// Temporary storage, cleared at the start of every call, + /// retained only to save allocations. + temp_suspected: Mutex>>, } pub(crate) enum DeferredDestroy { @@ -165,7 +167,7 @@ impl Drop for Device { let raw = self.raw.take().unwrap(); let pending_writes = self.pending_writes.lock().take().unwrap(); pending_writes.dispose(&raw); - self.command_allocator.lock().take().unwrap().dispose(&raw); + self.command_allocator.dispose(&raw); unsafe { raw.destroy_buffer(self.zero_buffer.take().unwrap()); raw.destroy_fence(self.fence.write().take().unwrap()); @@ -223,10 +225,8 @@ impl Device { let fence = unsafe { raw_device.create_fence() }.map_err(|_| CreateDeviceError::OutOfMemory)?; - let mut com_alloc = CommandAllocator { - free_encoders: Vec::new(), - }; - let pending_encoder = com_alloc + let command_allocator = command::CommandAllocator::new(); + let pending_encoder = command_allocator .acquire_encoder(&raw_device, raw_queue) .map_err(|_| CreateDeviceError::OutOfMemory)?; let mut pending_writes = queue::PendingWrites::::new(pending_encoder); @@ -271,38 +271,44 @@ impl Device { queue_to_drop: OnceCell::new(), zero_buffer: Some(zero_buffer), info: ResourceInfo::new("", None), - command_allocator: Mutex::new(Some(com_alloc)), + command_allocator, active_submission_index: AtomicU64::new(0), - fence: RwLock::new(Some(fence)), - snatchable_lock: unsafe { SnatchLock::new() }, + fence: RwLock::new(rank::DEVICE_FENCE, Some(fence)), + snatchable_lock: unsafe { SnatchLock::new(rank::DEVICE_SNATCHABLE_LOCK) }, valid: AtomicBool::new(true), - trackers: Mutex::new(Tracker::new()), + trackers: Mutex::new(rank::DEVICE_TRACKERS, Tracker::new()), tracker_indices: TrackerIndexAllocators::new(), - life_tracker: Mutex::new(life::LifetimeTracker::new()), - temp_suspected: Mutex::new(Some(life::ResourceMaps::new())), + life_tracker: Mutex::new(rank::DEVICE_LIFE_TRACKER, life::LifetimeTracker::new()), + temp_suspected: Mutex::new( + rank::DEVICE_TEMP_SUSPECTED, + Some(life::ResourceMaps::new()), + ), bgl_pool: ResourcePool::new(), #[cfg(feature = "trace")] - trace: Mutex::new(trace_path.and_then(|path| match trace::Trace::new(path) { - Ok(mut trace) => { - trace.add(trace::Action::Init { - desc: desc.clone(), - backend: A::VARIANT, - }); - Some(trace) - } - Err(e) => { - log::error!("Unable to start a trace in '{path:?}': {e}"); - None - } - })), + trace: Mutex::new( + rank::DEVICE_TRACE, + trace_path.and_then(|path| match trace::Trace::new(path) { + Ok(mut trace) => { + trace.add(trace::Action::Init { + desc: desc.clone(), + backend: A::VARIANT, + }); + Some(trace) + } + Err(e) => { + log::error!("Unable to start a trace in '{path:?}': {e}"); + None + } + }), + ), alignments, limits: desc.required_limits.clone(), features: desc.required_features, downlevel, instance_flags, - pending_writes: Mutex::new(Some(pending_writes)), - deferred_destroy: Mutex::new(Vec::new()), - usage_scopes: Default::default(), + pending_writes: Mutex::new(rank::DEVICE_PENDING_WRITES, Some(pending_writes)), + deferred_destroy: Mutex::new(rank::DEVICE_DEFERRED_DESTROY, Vec::new()), + usage_scopes: Mutex::new(rank::DEVICE_USAGE_SCOPES, Default::default()), }) } @@ -379,7 +385,7 @@ impl Device { /// Check this device for completed commands. /// - /// The `maintain` argument tells how the maintence function should behave, either + /// The `maintain` argument tells how the maintenance function should behave, either /// blocking or just polling the current state of the gpu. /// /// Return a pair `(closures, queue_empty)`, where: @@ -392,11 +398,12 @@ impl Device { /// return it to our callers.) pub(crate) fn maintain<'this>( &'this self, - fence: &A::Fence, + fence_guard: crate::lock::RwLockReadGuard>, maintain: wgt::Maintain, snatch_guard: SnatchGuard, ) -> Result<(UserClosures, bool), WaitIdleError> { profiling::scope!("Device::maintain"); + let fence = fence_guard.as_ref().unwrap(); let last_done_index = if maintain.is_wait() { let index_to_wait_for = match maintain { wgt::Maintain::WaitForSubmissionIndex(submission_index) => { @@ -425,28 +432,12 @@ impl Device { }; let mut life_tracker = self.lock_life(); - let submission_closures = life_tracker.triage_submissions( - last_done_index, - self.command_allocator.lock().as_mut().unwrap(), - ); - - { - // Normally, `temp_suspected` exists only to save heap - // allocations: it's cleared at the start of the function - // call, and cleared by the end. But `Global::queue_submit` is - // fallible; if it exits early, it may leave some resources in - // `temp_suspected`. - let temp_suspected = self - .temp_suspected - .lock() - .replace(ResourceMaps::new()) - .unwrap(); + let submission_closures = + life_tracker.triage_submissions(last_done_index, &self.command_allocator); - life_tracker.suspected_resources.extend(temp_suspected); + life_tracker.triage_suspected(&self.trackers); - life_tracker.triage_suspected(&self.trackers); - life_tracker.triage_mapped(); - } + life_tracker.triage_mapped(); let mapping_closures = life_tracker.handle_mapping(self.raw(), &self.trackers, &snatch_guard); @@ -478,6 +469,7 @@ impl Device { // Don't hold the locks while calling release_gpu_resources. drop(life_tracker); + drop(fence_guard); drop(snatch_guard); if should_release_gpu_resource { @@ -493,12 +485,14 @@ impl Device { } pub(crate) fn untrack(&self, trackers: &Tracker) { + // If we have a previously allocated `ResourceMap`, just use that. let mut temp_suspected = self .temp_suspected .lock() - .replace(ResourceMaps::new()) - .unwrap(); + .take() + .unwrap_or_else(|| ResourceMaps::new()); temp_suspected.clear(); + // As the tracker is cleared/dropped, we need to consider all the resources // that it references for destruction in the next GC pass. { @@ -559,7 +553,11 @@ impl Device { } } } - self.lock_life().suspected_resources.extend(temp_suspected); + self.lock_life() + .suspected_resources + .extend(&mut temp_suspected); + // Save this resource map for later reuse. + *self.temp_suspected.lock() = Some(temp_suspected); } pub(crate) fn create_buffer( @@ -653,14 +651,17 @@ impl Device { device: self.clone(), usage: desc.usage, size: desc.size, - initialization_status: RwLock::new(BufferInitTracker::new(aligned_size)), - sync_mapped_writes: Mutex::new(None), - map_state: Mutex::new(resource::BufferMapState::Idle), + initialization_status: RwLock::new( + rank::BUFFER_INITIALIZATION_STATUS, + BufferInitTracker::new(aligned_size), + ), + sync_mapped_writes: Mutex::new(rank::BUFFER_SYNC_MAPPED_WRITES, None), + map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle), info: ResourceInfo::new( desc.label.borrow_or_default(), Some(self.tracker_indices.buffers.clone()), ), - bind_groups: Mutex::new(Vec::new()), + bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, Vec::new()), }) } @@ -680,10 +681,10 @@ impl Device { desc: desc.map_label(|_| ()), hal_usage, format_features, - initialization_status: RwLock::new(TextureInitTracker::new( - desc.mip_level_count, - desc.array_layer_count(), - )), + initialization_status: RwLock::new( + rank::TEXTURE_INITIALIZATION_STATUS, + TextureInitTracker::new(desc.mip_level_count, desc.array_layer_count()), + ), full_range: TextureSelector { mips: 0..desc.mip_level_count, layers: 0..desc.array_layer_count(), @@ -692,9 +693,9 @@ impl Device { desc.label.borrow_or_default(), Some(self.tracker_indices.textures.clone()), ), - clear_mode: RwLock::new(clear_mode), - views: Mutex::new(Vec::new()), - bind_groups: Mutex::new(Vec::new()), + clear_mode: RwLock::new(rank::TEXTURE_CLEAR_MODE, clear_mode), + views: Mutex::new(rank::TEXTURE_VIEWS, Vec::new()), + bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, Vec::new()), } } @@ -710,14 +711,17 @@ impl Device { device: self.clone(), usage: desc.usage, size: desc.size, - initialization_status: RwLock::new(BufferInitTracker::new(0)), - sync_mapped_writes: Mutex::new(None), - map_state: Mutex::new(resource::BufferMapState::Idle), + initialization_status: RwLock::new( + rank::BUFFER_INITIALIZATION_STATUS, + BufferInitTracker::new(0), + ), + sync_mapped_writes: Mutex::new(rank::BUFFER_SYNC_MAPPED_WRITES, None), + map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle), info: ResourceInfo::new( desc.label.borrow_or_default(), Some(self.tracker_indices.buffers.clone()), ), - bind_groups: Mutex::new(Vec::new()), + bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, Vec::new()), } } @@ -1421,7 +1425,7 @@ impl Device { pipeline::ShaderModuleSource::Wgsl(code) => { profiling::scope!("naga::front::wgsl::parse_str"); let module = naga::front::wgsl::parse_str(&code).map_err(|inner| { - pipeline::CreateShaderModuleError::Parsing(pipeline::ShaderError { + pipeline::CreateShaderModuleError::Parsing(naga::error::ShaderError { source: code.to_string(), label: desc.label.as_ref().map(|l| l.to_string()), inner: Box::new(inner), @@ -1434,7 +1438,7 @@ impl Device { let parser = naga::front::spv::Frontend::new(spv.iter().cloned(), &options); profiling::scope!("naga::front::spv::Frontend"); let module = parser.parse().map_err(|inner| { - pipeline::CreateShaderModuleError::ParsingSpirV(pipeline::ShaderError { + pipeline::CreateShaderModuleError::ParsingSpirV(naga::error::ShaderError { source: String::new(), label: desc.label.as_ref().map(|l| l.to_string()), inner: Box::new(inner), @@ -1447,7 +1451,7 @@ impl Device { let mut parser = naga::front::glsl::Frontend::default(); profiling::scope!("naga::front::glsl::Frontend.parse"); let module = parser.parse(&options, &code).map_err(|inner| { - pipeline::CreateShaderModuleError::ParsingGlsl(pipeline::ShaderError { + pipeline::CreateShaderModuleError::ParsingGlsl(naga::error::ShaderError { source: code.to_string(), label: desc.label.as_ref().map(|l| l.to_string()), inner: Box::new(inner), @@ -1471,9 +1475,78 @@ impl Device { }; } - use naga::valid::Capabilities as Caps; profiling::scope!("naga::validate"); + let debug_source = + if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() { + Some(hal::DebugSource { + file_name: Cow::Owned( + desc.label + .as_ref() + .map_or("shader".to_string(), |l| l.to_string()), + ), + source_code: Cow::Owned(source.clone()), + }) + } else { + None + }; + + let info = self + .create_validator(naga::valid::ValidationFlags::all()) + .validate(&module) + .map_err(|inner| { + pipeline::CreateShaderModuleError::Validation(naga::error::ShaderError { + source, + label: desc.label.as_ref().map(|l| l.to_string()), + inner: Box::new(inner), + }) + })?; + + let interface = + validation::Interface::new(&module, &info, self.limits.clone(), self.features); + let hal_shader = hal::ShaderInput::Naga(hal::NagaShader { + module, + info, + debug_source, + }); + let hal_desc = hal::ShaderModuleDescriptor { + label: desc.label.to_hal(self.instance_flags), + runtime_checks: desc.shader_bound_checks.runtime_checks(), + }; + let raw = match unsafe { + self.raw + .as_ref() + .unwrap() + .create_shader_module(&hal_desc, hal_shader) + } { + Ok(raw) => raw, + Err(error) => { + return Err(match error { + hal::ShaderError::Device(error) => { + pipeline::CreateShaderModuleError::Device(error.into()) + } + hal::ShaderError::Compilation(ref msg) => { + log::error!("Shader error: {}", msg); + pipeline::CreateShaderModuleError::Generation + } + }) + } + }; + + Ok(pipeline::ShaderModule { + raw: Some(raw), + device: self.clone(), + interface: Some(interface), + info: ResourceInfo::new(desc.label.borrow_or_default(), None), + label: desc.label.borrow_or_default().to_string(), + }) + } + /// Create a validator with the given validation flags. + pub fn create_validator( + self: &Arc, + flags: naga::valid::ValidationFlags, + ) -> naga::valid::Validator { + use naga::valid::Capabilities as Caps; let mut caps = Caps::empty(); caps.set( Caps::PUSH_CONSTANT, @@ -1541,69 +1614,36 @@ impl Device { .flags .contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES), ); + caps.set( + Caps::SUBGROUP, + self.features + .intersects(wgt::Features::SUBGROUP | wgt::Features::SUBGROUP_VERTEX), + ); + caps.set( + Caps::SUBGROUP_BARRIER, + self.features.intersects(wgt::Features::SUBGROUP_BARRIER), + ); - let debug_source = - if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() { - Some(hal::DebugSource { - file_name: Cow::Owned( - desc.label - .as_ref() - .map_or("shader".to_string(), |l| l.to_string()), - ), - source_code: Cow::Owned(source.clone()), - }) - } else { - None - }; - - let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps) - .validate(&module) - .map_err(|inner| { - pipeline::CreateShaderModuleError::Validation(pipeline::ShaderError { - source, - label: desc.label.as_ref().map(|l| l.to_string()), - inner: Box::new(inner), - }) - })?; + let mut subgroup_stages = naga::valid::ShaderStages::empty(); + subgroup_stages.set( + naga::valid::ShaderStages::COMPUTE | naga::valid::ShaderStages::FRAGMENT, + self.features.contains(wgt::Features::SUBGROUP), + ); + subgroup_stages.set( + naga::valid::ShaderStages::VERTEX, + self.features.contains(wgt::Features::SUBGROUP_VERTEX), + ); - let interface = - validation::Interface::new(&module, &info, self.limits.clone(), self.features); - let hal_shader = hal::ShaderInput::Naga(hal::NagaShader { - module, - info, - debug_source, - }); - let hal_desc = hal::ShaderModuleDescriptor { - label: desc.label.to_hal(self.instance_flags), - runtime_checks: desc.shader_bound_checks.runtime_checks(), - }; - let raw = match unsafe { - self.raw - .as_ref() - .unwrap() - .create_shader_module(&hal_desc, hal_shader) - } { - Ok(raw) => raw, - Err(error) => { - return Err(match error { - hal::ShaderError::Device(error) => { - pipeline::CreateShaderModuleError::Device(error.into()) - } - hal::ShaderError::Compilation(ref msg) => { - log::error!("Shader error: {}", msg); - pipeline::CreateShaderModuleError::Generation - } - }) - } + let subgroup_operations = if caps.contains(Caps::SUBGROUP) { + use naga::valid::SubgroupOperationSet as S; + S::BASIC | S::VOTE | S::ARITHMETIC | S::BALLOT | S::SHUFFLE | S::SHUFFLE_RELATIVE + } else { + naga::valid::SubgroupOperationSet::empty() }; - - Ok(pipeline::ShaderModule { - raw: Some(raw), - device: self.clone(), - interface: Some(interface), - info: ResourceInfo::new(desc.label.borrow_or_default(), None), - label: desc.label.borrow_or_default().to_string(), - }) + let mut validator = naga::valid::Validator::new(flags, caps); + validator.subgroup_stages(subgroup_stages); + validator.subgroup_operations(subgroup_operations); + validator } #[allow(unused_unsafe)] @@ -1913,6 +1953,7 @@ impl Device { used: &mut BindGroupStates, storage: &'a Storage>, limits: &wgt::Limits, + device_id: id::Id, snatch_guard: &'a SnatchGuard<'a>, ) -> Result, binding_model::CreateBindGroupError> { use crate::binding_model::CreateBindGroupError as Error; @@ -1931,6 +1972,7 @@ impl Device { }) } }; + let (pub_usage, internal_use, range_limit) = match binding_ty { wgt::BufferBindingType::Uniform => ( wgt::BufferUsages::UNIFORM, @@ -1963,6 +2005,10 @@ impl Device { .add_single(storage, bb.buffer_id, internal_use) .ok_or(Error::InvalidBuffer(bb.buffer_id))?; + if buffer.device.as_info().id() != device_id { + return Err(DeviceError::WrongDevice.into()); + } + check_buffer_usage(bb.buffer_id, buffer.usage, pub_usage)?; let raw_buffer = buffer .raw @@ -2041,13 +2087,53 @@ impl Device { }) } - pub(crate) fn create_texture_binding( - view: &TextureView, - internal_use: hal::TextureUses, - pub_usage: wgt::TextureUsages, + fn create_sampler_binding<'a>( + used: &BindGroupStates, + storage: &'a Storage>, + id: id::Id, + device_id: id::Id, + ) -> Result<&'a Sampler, binding_model::CreateBindGroupError> { + use crate::binding_model::CreateBindGroupError as Error; + + let sampler = used + .samplers + .add_single(storage, id) + .ok_or(Error::InvalidSampler(id))?; + + if sampler.device.as_info().id() != device_id { + return Err(DeviceError::WrongDevice.into()); + } + + Ok(sampler) + } + + pub(crate) fn create_texture_binding<'a>( + self: &Arc, + binding: u32, + decl: &wgt::BindGroupLayoutEntry, + storage: &'a Storage>, + id: id::Id, used: &mut BindGroupStates, used_texture_ranges: &mut Vec>, - ) -> Result<(), binding_model::CreateBindGroupError> { + snatch_guard: &'a SnatchGuard<'a>, + ) -> Result, binding_model::CreateBindGroupError> { + use crate::binding_model::CreateBindGroupError as Error; + + let view = used + .views + .add_single(storage, id) + .ok_or(Error::InvalidTextureView(id))?; + + if view.device.as_info().id() != self.as_info().id() { + return Err(DeviceError::WrongDevice.into()); + } + + let (pub_usage, internal_use) = self.texture_use_parameters( + binding, + decl, + view, + "SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture", + )?; let texture = &view.parent; let texture_id = texture.as_info().id(); // Careful here: the texture may no longer have its own ref count, @@ -2077,7 +2163,12 @@ impl Device { kind: MemoryInitKind::NeedsInitializedMemory, }); - Ok(()) + Ok(hal::TextureBinding { + view: view + .raw(snatch_guard) + .ok_or(Error::InvalidTextureView(id))?, + usage: internal_use, + }) } // This function expects the provided bind group layout to be resolved @@ -2139,6 +2230,7 @@ impl Device { &mut used, &*buffer_guard, &self.limits, + self.as_info().id(), &snatch_guard, )?; @@ -2162,105 +2254,86 @@ impl Device { &mut used, &*buffer_guard, &self.limits, + self.as_info().id(), &snatch_guard, )?; hal_buffers.push(bb); } (res_index, num_bindings) } - Br::Sampler(id) => { - match decl.ty { - wgt::BindingType::Sampler(ty) => { - let sampler = used - .samplers - .add_single(&*sampler_guard, id) - .ok_or(Error::InvalidSampler(id))?; - - if sampler.device.as_info().id() != self.as_info().id() { - return Err(DeviceError::WrongDevice.into()); - } - - // Allowed sampler values for filtering and comparison - let (allowed_filtering, allowed_comparison) = match ty { - wgt::SamplerBindingType::Filtering => (None, false), - wgt::SamplerBindingType::NonFiltering => (Some(false), false), - wgt::SamplerBindingType::Comparison => (None, true), - }; - - if let Some(allowed_filtering) = allowed_filtering { - if allowed_filtering != sampler.filtering { - return Err(Error::WrongSamplerFiltering { - binding, - layout_flt: allowed_filtering, - sampler_flt: sampler.filtering, - }); - } - } + Br::Sampler(id) => match decl.ty { + wgt::BindingType::Sampler(ty) => { + let sampler = Self::create_sampler_binding( + &used, + &sampler_guard, + id, + self.as_info().id(), + )?; - if allowed_comparison != sampler.comparison { - return Err(Error::WrongSamplerComparison { + let (allowed_filtering, allowed_comparison) = match ty { + wgt::SamplerBindingType::Filtering => (None, false), + wgt::SamplerBindingType::NonFiltering => (Some(false), false), + wgt::SamplerBindingType::Comparison => (None, true), + }; + if let Some(allowed_filtering) = allowed_filtering { + if allowed_filtering != sampler.filtering { + return Err(Error::WrongSamplerFiltering { binding, - layout_cmp: allowed_comparison, - sampler_cmp: sampler.comparison, + layout_flt: allowed_filtering, + sampler_flt: sampler.filtering, }); } - - let res_index = hal_samplers.len(); - hal_samplers.push(sampler.raw()); - (res_index, 1) } - _ => { - return Err(Error::WrongBindingType { + if allowed_comparison != sampler.comparison { + return Err(Error::WrongSamplerComparison { binding, - actual: decl.ty, - expected: "Sampler", - }) + layout_cmp: allowed_comparison, + sampler_cmp: sampler.comparison, + }); } + + let res_index = hal_samplers.len(); + hal_samplers.push(sampler.raw()); + (res_index, 1) } - } + _ => { + return Err(Error::WrongBindingType { + binding, + actual: decl.ty, + expected: "Sampler", + }) + } + }, Br::SamplerArray(ref bindings_array) => { let num_bindings = bindings_array.len(); Self::check_array_binding(self.features, decl.count, num_bindings)?; let res_index = hal_samplers.len(); for &id in bindings_array.iter() { - let sampler = used - .samplers - .add_single(&*sampler_guard, id) - .ok_or(Error::InvalidSampler(id))?; - if sampler.device.as_info().id() != self.as_info().id() { - return Err(DeviceError::WrongDevice.into()); - } + let sampler = Self::create_sampler_binding( + &used, + &sampler_guard, + id, + self.as_info().id(), + )?; + hal_samplers.push(sampler.raw()); } (res_index, num_bindings) } Br::TextureView(id) => { - let view = used - .views - .add_single(&*texture_view_guard, id) - .ok_or(Error::InvalidTextureView(id))?; - let (pub_usage, internal_use) = self.texture_use_parameters( + let tb = self.create_texture_binding( binding, decl, - view, - "SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture", - )?; - Self::create_texture_binding( - view, - internal_use, - pub_usage, + &texture_view_guard, + id, &mut used, &mut used_texture_ranges, + &snatch_guard, )?; let res_index = hal_textures.len(); - hal_textures.push(hal::TextureBinding { - view: view - .raw(&snatch_guard) - .ok_or(Error::InvalidTextureView(id))?, - usage: internal_use, - }); + hal_textures.push(tb); (res_index, 1) } Br::TextureViewArray(ref bindings_array) => { @@ -2269,26 +2342,17 @@ impl Device { let res_index = hal_textures.len(); for &id in bindings_array.iter() { - let view = used - .views - .add_single(&*texture_view_guard, id) - .ok_or(Error::InvalidTextureView(id))?; - let (pub_usage, internal_use) = - self.texture_use_parameters(binding, decl, view, - "SampledTextureArray, ReadonlyStorageTextureArray or WriteonlyStorageTextureArray")?; - Self::create_texture_binding( - view, - internal_use, - pub_usage, + let tb = self.create_texture_binding( + binding, + decl, + &texture_view_guard, + id, &mut used, &mut used_texture_ranges, + &snatch_guard, )?; - hal_textures.push(hal::TextureBinding { - view: view - .raw(&snatch_guard) - .ok_or(Error::InvalidTextureView(id))?, - usage: internal_use, - }); + + hal_textures.push(tb); } (res_index, num_bindings) @@ -2762,8 +2826,10 @@ impl Device { label: desc.label.to_hal(self.instance_flags), layout: pipeline_layout.raw(), stage: hal::ProgrammableStage { - entry_point: final_entry_point_name.as_ref(), module: shader_module.raw(), + entry_point: final_entry_point_name.as_ref(), + constants: desc.stage.constants.as_ref(), + zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory, }, }; @@ -3178,6 +3244,8 @@ impl Device { hal::ProgrammableStage { module: vertex_shader_module.raw(), entry_point: &vertex_entry_point_name, + constants: stage_desc.constants.as_ref(), + zero_initialize_workgroup_memory: stage_desc.zero_initialize_workgroup_memory, } }; @@ -3237,6 +3305,10 @@ impl Device { Some(hal::ProgrammableStage { module: shader_module.raw(), entry_point: &fragment_entry_point_name, + constants: fragment_state.stage.constants.as_ref(), + zero_initialize_workgroup_memory: fragment_state + .stage + .zero_initialize_workgroup_memory, }) } None => None, @@ -3482,10 +3554,9 @@ impl Device { .map_err(DeviceError::from)? }; drop(guard); - let closures = self.lock_life().triage_submissions( - submission_index, - self.command_allocator.lock().as_mut().unwrap(), - ); + let closures = self + .lock_life() + .triage_submissions(submission_index, &self.command_allocator); assert!( closures.is_empty(), "wait_for_submit is not expected to work with closures" @@ -3613,10 +3684,7 @@ impl Device { log::error!("failed to wait for the device: {error}"); } let mut life_tracker = self.lock_life(); - let _ = life_tracker.triage_submissions( - current_index, - self.command_allocator.lock().as_mut().unwrap(), - ); + let _ = life_tracker.triage_submissions(current_index, &self.command_allocator); if let Some(device_lost_closure) = life_tracker.device_lost_closure.take() { // It's important to not hold the lock while calling the closure. drop(life_tracker); diff --git a/third_party/rust/wgpu-core/src/global.rs b/third_party/rust/wgpu-core/src/global.rs index 9a8c43bf33..6f6756a88c 100644 --- a/third_party/rust/wgpu-core/src/global.rs +++ b/third_party/rust/wgpu-core/src/global.rs @@ -45,7 +45,7 @@ impl GlobalReport { pub struct Global { pub instance: Instance, - pub surfaces: Registry, + pub(crate) surfaces: Registry, pub(crate) hubs: Hubs, } @@ -155,11 +155,9 @@ impl Drop for Global { // destroy surfaces for element in surfaces_locked.map.drain(..) { if let Element::Occupied(arc_surface, _) = element { - if let Some(surface) = Arc::into_inner(arc_surface) { - self.instance.destroy_surface(surface); - } else { - panic!("Surface cannot be destroyed because is still in use"); - } + let surface = Arc::into_inner(arc_surface) + .expect("Surface cannot be destroyed because is still in use"); + self.instance.destroy_surface(surface); } } } diff --git a/third_party/rust/wgpu-core/src/hal_api.rs b/third_party/rust/wgpu-core/src/hal_api.rs index 179024baed..f1a40b1cff 100644 --- a/third_party/rust/wgpu-core/src/hal_api.rs +++ b/third_party/rust/wgpu-core/src/hal_api.rs @@ -11,7 +11,7 @@ pub trait HalApi: hal::Api + 'static + WasmNotSendSync { fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance>; fn hub(global: &Global) -> &Hub; - fn get_surface(surface: &Surface) -> Option<&Self::Surface>; + fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface>; } impl HalApi for hal::api::Empty { @@ -25,7 +25,7 @@ impl HalApi for hal::api::Empty { fn hub(_: &Global) -> &Hub { unimplemented!("called empty api") } - fn get_surface(_: &Surface) -> Option<&Self::Surface> { + fn surface_as_hal(_: &Surface) -> Option<&Self::Surface> { unimplemented!("called empty api") } } @@ -46,8 +46,8 @@ impl HalApi for hal::api::Vulkan { fn hub(global: &Global) -> &Hub { &global.hubs.vulkan } - fn get_surface(surface: &Surface) -> Option<&Self::Surface> { - surface.raw.downcast_ref::() + fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> { + surface.vulkan.as_ref() } } @@ -67,8 +67,8 @@ impl HalApi for hal::api::Metal { fn hub(global: &Global) -> &Hub { &global.hubs.metal } - fn get_surface(surface: &Surface) -> Option<&Self::Surface> { - surface.raw.downcast_ref::() + fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> { + surface.metal.as_ref() } } @@ -88,8 +88,8 @@ impl HalApi for hal::api::Dx12 { fn hub(global: &Global) -> &Hub { &global.hubs.dx12 } - fn get_surface(surface: &Surface) -> Option<&Self::Surface> { - surface.raw.downcast_ref::() + fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> { + surface.dx12.as_ref() } } @@ -110,7 +110,7 @@ impl HalApi for hal::api::Gles { fn hub(global: &Global) -> &Hub { &global.hubs.gl } - fn get_surface(surface: &Surface) -> Option<&Self::Surface> { - surface.raw.downcast_ref::() + fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> { + surface.gl.as_ref() } } diff --git a/third_party/rust/wgpu-core/src/hub.rs b/third_party/rust/wgpu-core/src/hub.rs index 0f4589c8b3..eb57411d98 100644 --- a/third_party/rust/wgpu-core/src/hub.rs +++ b/third_party/rust/wgpu-core/src/hub.rs @@ -169,23 +169,23 @@ impl HubReport { /// /// [`A::hub(global)`]: HalApi::hub pub struct Hub { - pub adapters: Registry>, - pub devices: Registry>, - pub queues: Registry>, - pub pipeline_layouts: Registry>, - pub shader_modules: Registry>, - pub bind_group_layouts: Registry>, - pub bind_groups: Registry>, - pub command_buffers: Registry>, - pub render_bundles: Registry>, - pub render_pipelines: Registry>, - pub compute_pipelines: Registry>, - pub query_sets: Registry>, - pub buffers: Registry>, - pub staging_buffers: Registry>, - pub textures: Registry>, - pub texture_views: Registry>, - pub samplers: Registry>, + pub(crate) adapters: Registry>, + pub(crate) devices: Registry>, + pub(crate) queues: Registry>, + pub(crate) pipeline_layouts: Registry>, + pub(crate) shader_modules: Registry>, + pub(crate) bind_group_layouts: Registry>, + pub(crate) bind_groups: Registry>, + pub(crate) command_buffers: Registry>, + pub(crate) render_bundles: Registry>, + pub(crate) render_pipelines: Registry>, + pub(crate) compute_pipelines: Registry>, + pub(crate) query_sets: Registry>, + pub(crate) buffers: Registry>, + pub(crate) staging_buffers: Registry>, + pub(crate) textures: Registry>, + pub(crate) texture_views: Registry>, + pub(crate) samplers: Registry>, } impl Hub { @@ -241,7 +241,7 @@ impl Hub { if let Element::Occupied(ref surface, _epoch) = *element { if let Some(ref mut present) = surface.presentation.lock().take() { if let Some(device) = present.device.downcast_ref::() { - let suf = A::get_surface(surface); + let suf = A::surface_as_hal(surface); unsafe { suf.unwrap().unconfigure(device.raw()); //TODO: we could destroy the surface here diff --git a/third_party/rust/wgpu-core/src/id.rs b/third_party/rust/wgpu-core/src/id.rs index 72b74218d0..1fa89f2bf0 100644 --- a/third_party/rust/wgpu-core/src/id.rs +++ b/third_party/rust/wgpu-core/src/id.rs @@ -91,8 +91,7 @@ pub fn as_option_slice(ids: &[Id]) -> &[Option>] { /// An identifier for a wgpu object. /// -/// An `Id` value identifies a value stored in a [`Global`]'s [`Hub`]'s [`Storage`]. -/// `Storage` implements [`Index`] and [`IndexMut`], accepting `Id` values as indices. +/// An `Id` value identifies a value stored in a [`Global`]'s [`Hub`]. /// /// ## Note on `Id` typing /// @@ -112,10 +111,7 @@ pub fn as_option_slice(ids: &[Id]) -> &[Option>] { /// [`Global`]: crate::global::Global /// [`Hub`]: crate::hub::Hub /// [`Hub`]: crate::hub::Hub -/// [`Storage`]: crate::storage::Storage /// [`Texture`]: crate::resource::Texture -/// [`Index`]: std::ops::Index -/// [`IndexMut`]: std::ops::IndexMut /// [`Registry`]: crate::hub::Registry /// [`Empty`]: hal::api::Empty #[repr(transparent)] @@ -182,15 +178,6 @@ where self.0.backend() } - /// Transmute this identifier to one with a different marker trait. - /// - /// Legal use is governed through a sealed trait, however it's correctness - /// depends on the current implementation of `wgpu-core`. - #[inline] - pub const fn transmute>(self) -> Id { - Id(self.0, PhantomData) - } - #[inline] pub fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self { Id(RawId::zip(index, epoch, backend), PhantomData) @@ -202,20 +189,6 @@ where } } -pub(crate) mod transmute { - // This trait is effectively sealed to prevent illegal transmutes. - pub trait Transmute: super::Marker {} - - // Self-transmute is always legal. - impl Transmute for T where T: super::Marker {} - - // TODO: Remove these once queues have their own identifiers. - impl Transmute for super::markers::Device {} - impl Transmute for super::markers::Queue {} - impl Transmute for super::markers::CommandEncoder {} - impl Transmute for super::markers::CommandBuffer {} -} - impl Copy for Id where T: Marker {} impl Clone for Id @@ -349,6 +322,24 @@ ids! { pub type QuerySetId QuerySet; } +impl CommandEncoderId { + pub fn into_command_buffer_id(self) -> CommandBufferId { + Id(self.0, PhantomData) + } +} + +impl CommandBufferId { + pub fn into_command_encoder_id(self) -> CommandEncoderId { + Id(self.0, PhantomData) + } +} + +impl DeviceId { + pub fn into_queue_id(self) -> QueueId { + Id(self.0, PhantomData) + } +} + #[test] fn test_id_backend() { for &b in &[ diff --git a/third_party/rust/wgpu-core/src/identity.rs b/third_party/rust/wgpu-core/src/identity.rs index d76d29341a..c89731f7af 100644 --- a/third_party/rust/wgpu-core/src/identity.rs +++ b/third_party/rust/wgpu-core/src/identity.rs @@ -1,8 +1,8 @@ -use parking_lot::Mutex; use wgt::Backend; use crate::{ id::{Id, Marker}, + lock::{rank, Mutex}, Epoch, Index, }; use std::{fmt::Debug, marker::PhantomData}; @@ -16,31 +16,26 @@ enum IdSource { /// A simple structure to allocate [`Id`] identifiers. /// -/// Calling [`alloc`] returns a fresh, never-before-seen id. Calling [`free`] +/// Calling [`alloc`] returns a fresh, never-before-seen id. Calling [`release`] /// marks an id as dead; it will never be returned again by `alloc`. /// -/// Use `IdentityManager::default` to construct new instances. +/// `IdentityValues` returns `Id`s whose index values are suitable for use as +/// indices into a `Vec` that holds those ids' referents: /// -/// `IdentityManager` returns `Id`s whose index values are suitable for use as -/// indices into a `Storage` that holds those ids' referents: +/// - Every live id has a distinct index value. Every live id's index +/// selects a distinct element in the vector. /// -/// - Every live id has a distinct index value. Each live id's index selects a -/// distinct element in the vector. -/// -/// - `IdentityManager` prefers low index numbers. If you size your vector to +/// - `IdentityValues` prefers low index numbers. If you size your vector to /// accommodate the indices produced here, the vector's length will reflect /// the highwater mark of actual occupancy. /// -/// - `IdentityManager` reuses the index values of freed ids before returning +/// - `IdentityValues` reuses the index values of freed ids before returning /// ids with new index values. Freed vector entries get reused. /// -/// See the module-level documentation for an overview of how this -/// fits together. -/// /// [`Id`]: crate::id::Id /// [`Backend`]: wgt::Backend; -/// [`alloc`]: IdentityManager::alloc -/// [`free`]: IdentityManager::free +/// [`alloc`]: IdentityValues::alloc +/// [`release`]: IdentityValues::release #[derive(Debug)] pub(super) struct IdentityValues { free: Vec<(Index, Epoch)>, @@ -122,12 +117,15 @@ impl IdentityManager { impl IdentityManager { pub fn new() -> Self { Self { - values: Mutex::new(IdentityValues { - free: Vec::new(), - next_index: 0, - count: 0, - id_source: IdSource::None, - }), + values: Mutex::new( + rank::IDENTITY_MANAGER_VALUES, + IdentityValues { + free: Vec::new(), + next_index: 0, + count: 0, + id_source: IdSource::None, + }, + ), _phantom: PhantomData, } } diff --git a/third_party/rust/wgpu-core/src/instance.rs b/third_party/rust/wgpu-core/src/instance.rs index b909245fac..f0a3890c1e 100644 --- a/third_party/rust/wgpu-core/src/instance.rs +++ b/third_party/rust/wgpu-core/src/instance.rs @@ -1,19 +1,19 @@ +use std::collections::HashMap; use std::sync::Arc; use crate::{ - any_surface::AnySurface, api_log, device::{queue::Queue, resource::Device, DeviceDescriptor}, global::Global, hal_api::HalApi, id::markers, id::{AdapterId, DeviceId, Id, Marker, QueueId, SurfaceId}, + lock::{rank, Mutex}, present::Presentation, resource::{Resource, ResourceInfo, ResourceType}, resource_log, LabelHelpers, DOWNLEVEL_WARNING_MESSAGE, }; -use parking_lot::Mutex; use wgt::{Backend, Backends, PowerPreference}; use hal::{Adapter as _, Instance as _, OpenDevice}; @@ -21,6 +21,7 @@ use thiserror::Error; pub type RequestAdapterOptions = wgt::RequestAdapterOptions; type HalInstance = ::Instance; +type HalSurface = ::Surface; #[derive(Clone, Debug, Error)] #[error("Limit '{name}' value {requested} is better than allowed {allowed}")] @@ -113,31 +114,36 @@ impl Instance { } pub(crate) fn destroy_surface(&self, surface: Surface) { - fn destroy(instance: &Option, surface: AnySurface) { - unsafe { - if let Some(suf) = surface.take::() { - instance.as_ref().unwrap().destroy_surface(suf); + fn destroy(instance: &Option, mut surface: Option>) { + if let Some(surface) = surface.take() { + unsafe { + instance.as_ref().unwrap().destroy_surface(surface); } } } - match surface.raw.backend() { - #[cfg(vulkan)] - Backend::Vulkan => destroy::(&self.vulkan, surface.raw), - #[cfg(metal)] - Backend::Metal => destroy::(&self.metal, surface.raw), - #[cfg(dx12)] - Backend::Dx12 => destroy::(&self.dx12, surface.raw), - #[cfg(gles)] - Backend::Gl => destroy::(&self.gl, surface.raw), - _ => unreachable!(), - } + #[cfg(vulkan)] + destroy::(&self.vulkan, surface.vulkan); + #[cfg(metal)] + destroy::(&self.metal, surface.metal); + #[cfg(dx12)] + destroy::(&self.dx12, surface.dx12); + #[cfg(gles)] + destroy::(&self.gl, surface.gl); } } pub struct Surface { pub(crate) presentation: Mutex>, pub(crate) info: ResourceInfo, - pub(crate) raw: AnySurface, + + #[cfg(vulkan)] + pub vulkan: Option>, + #[cfg(metal)] + pub metal: Option>, + #[cfg(dx12)] + pub dx12: Option>, + #[cfg(gles)] + pub gl: Option>, } impl Resource for Surface { @@ -163,7 +169,7 @@ impl Surface { &self, adapter: &Adapter, ) -> Result { - let suf = A::get_surface(self).ok_or(GetSurfaceSupportError::Unsupported)?; + let suf = A::surface_as_hal(self).ok_or(GetSurfaceSupportError::Unsupported)?; profiling::scope!("surface_capabilities"); let caps = unsafe { adapter @@ -203,7 +209,7 @@ impl Adapter { } pub fn is_surface_supported(&self, surface: &Surface) -> bool { - let suf = A::get_surface(surface); + let suf = A::surface_as_hal(surface); // If get_surface returns None, then the API does not advertise support for the surface. // @@ -461,13 +467,25 @@ pub enum RequestAdapterError { #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum CreateSurfaceError { - #[error("No backend is available")] - NoSupportedBackend, - #[error(transparent)] - InstanceError(#[from] hal::InstanceError), + #[error("The backend {0} was not enabled on the instance.")] + BackendNotEnabled(Backend), + #[error("Failed to create surface for any enabled backend: {0:?}")] + FailedToCreateSurfaceForAnyBackend(HashMap), } impl Global { + /// Creates a new surface targeting the given display/window handles. + /// + /// Internally attempts to create hal surfaces for all enabled backends. + /// + /// Fails only if creation for surfaces for all enabled backends fails in which case + /// the error for each enabled backend is listed. + /// Vice versa, if creation for any backend succeeds, success is returned. + /// Surface creation errors are logged to the debug log in any case. + /// + /// id_in: + /// - If `Some`, the id to assign to the surface. A new one will be generated otherwise. + /// /// # Safety /// /// - `display_handle` must be a valid object to create a surface upon. @@ -483,50 +501,86 @@ impl Global { profiling::scope!("Instance::create_surface"); fn init( + errors: &mut HashMap, + any_created: &mut bool, + backend: Backend, inst: &Option, display_handle: raw_window_handle::RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, - ) -> Option> { - inst.as_ref().map(|inst| unsafe { - match inst.create_surface(display_handle, window_handle) { - Ok(raw) => Ok(AnySurface::new::(raw)), - Err(e) => Err(e), + ) -> Option> { + inst.as_ref().and_then(|inst| { + match unsafe { inst.create_surface(display_handle, window_handle) } { + Ok(raw) => { + *any_created = true; + Some(raw) + } + Err(err) => { + log::debug!( + "Instance::create_surface: failed to create surface for {:?}: {:?}", + backend, + err + ); + errors.insert(backend, err); + None + } } }) } - let mut hal_surface: Option> = None; - - #[cfg(vulkan)] - if hal_surface.is_none() { - hal_surface = - init::(&self.instance.vulkan, display_handle, window_handle); - } - #[cfg(metal)] - if hal_surface.is_none() { - hal_surface = - init::(&self.instance.metal, display_handle, window_handle); - } - #[cfg(dx12)] - if hal_surface.is_none() { - hal_surface = - init::(&self.instance.dx12, display_handle, window_handle); - } - #[cfg(gles)] - if hal_surface.is_none() { - hal_surface = init::(&self.instance.gl, display_handle, window_handle); - } - - let hal_surface = hal_surface.ok_or(CreateSurfaceError::NoSupportedBackend)??; + let mut errors = HashMap::default(); + let mut any_created = false; let surface = Surface { - presentation: Mutex::new(None), + presentation: Mutex::new(rank::SURFACE_PRESENTATION, None), info: ResourceInfo::new("", None), - raw: hal_surface, + + #[cfg(vulkan)] + vulkan: init::( + &mut errors, + &mut any_created, + Backend::Vulkan, + &self.instance.vulkan, + display_handle, + window_handle, + ), + #[cfg(metal)] + metal: init::( + &mut errors, + &mut any_created, + Backend::Metal, + &self.instance.metal, + display_handle, + window_handle, + ), + #[cfg(dx12)] + dx12: init::( + &mut errors, + &mut any_created, + Backend::Dx12, + &self.instance.dx12, + display_handle, + window_handle, + ), + #[cfg(gles)] + gl: init::( + &mut errors, + &mut any_created, + Backend::Gl, + &self.instance.gl, + display_handle, + window_handle, + ), }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); - Ok(id) + if any_created { + #[allow(clippy::arc_with_non_send_sync)] + let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface)); + Ok(id) + } else { + Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend( + errors, + )) + } } /// # Safety @@ -537,29 +591,57 @@ impl Global { &self, layer: *mut std::ffi::c_void, id_in: Option, - ) -> SurfaceId { + ) -> Result { profiling::scope!("Instance::create_surface_metal"); let surface = Surface { - presentation: Mutex::new(None), + presentation: Mutex::new(rank::SURFACE_PRESENTATION, None), info: ResourceInfo::new("", None), - raw: { - let hal_surface = self - .instance - .metal + metal: Some(self.instance.metal.as_ref().map_or( + Err(CreateSurfaceError::BackendNotEnabled(Backend::Metal)), + |inst| { + // we don't want to link to metal-rs for this + #[allow(clippy::transmute_ptr_to_ref)] + Ok(inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) })) + }, + )?), + #[cfg(dx12)] + dx12: None, + #[cfg(vulkan)] + vulkan: None, + #[cfg(gles)] + gl: None, + }; + + let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface)); + Ok(id) + } + + #[cfg(dx12)] + fn instance_create_surface_dx12( + &self, + id_in: Option, + create_surface_func: impl FnOnce(&HalInstance) -> HalSurface, + ) -> Result { + let surface = Surface { + presentation: Mutex::new(rank::SURFACE_PRESENTATION, None), + info: ResourceInfo::new("", None), + dx12: Some(create_surface_func( + self.instance + .dx12 .as_ref() - .map(|inst| { - // we don't want to link to metal-rs for this - #[allow(clippy::transmute_ptr_to_ref)] - inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }) - }) - .unwrap(); - AnySurface::new::(hal_surface) - }, + .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?, + )), + #[cfg(metal)] + metal: None, + #[cfg(vulkan)] + vulkan: None, + #[cfg(gles)] + gl: None, }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); - id + let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface)); + Ok(id) } #[cfg(dx12)] @@ -570,25 +652,11 @@ impl Global { &self, visual: *mut std::ffi::c_void, id_in: Option, - ) -> SurfaceId { + ) -> Result { profiling::scope!("Instance::instance_create_surface_from_visual"); - - let surface = Surface { - presentation: Mutex::new(None), - info: ResourceInfo::new("", None), - raw: { - let hal_surface = self - .instance - .dx12 - .as_ref() - .map(|inst| unsafe { inst.create_surface_from_visual(visual as _) }) - .unwrap(); - AnySurface::new::(hal_surface) - }, - }; - - let (id, _) = self.surfaces.prepare(id_in).assign(surface); - id + self.instance_create_surface_dx12(id_in, |inst| unsafe { + inst.create_surface_from_visual(visual as _) + }) } #[cfg(dx12)] @@ -599,25 +667,11 @@ impl Global { &self, surface_handle: *mut std::ffi::c_void, id_in: Option, - ) -> SurfaceId { + ) -> Result { profiling::scope!("Instance::instance_create_surface_from_surface_handle"); - - let surface = Surface { - presentation: Mutex::new(None), - info: ResourceInfo::new("", None), - raw: { - let hal_surface = self - .instance - .dx12 - .as_ref() - .map(|inst| unsafe { inst.create_surface_from_surface_handle(surface_handle) }) - .unwrap(); - AnySurface::new::(hal_surface) - }, - }; - - let (id, _) = self.surfaces.prepare(id_in).assign(surface); - id + self.instance_create_surface_dx12(id_in, |inst| unsafe { + inst.create_surface_from_surface_handle(surface_handle) + }) } #[cfg(dx12)] @@ -628,27 +682,11 @@ impl Global { &self, swap_chain_panel: *mut std::ffi::c_void, id_in: Option, - ) -> SurfaceId { + ) -> Result { profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel"); - - let surface = Surface { - presentation: Mutex::new(None), - info: ResourceInfo::new("", None), - raw: { - let hal_surface = self - .instance - .dx12 - .as_ref() - .map(|inst| unsafe { - inst.create_surface_from_swap_chain_panel(swap_chain_panel as _) - }) - .unwrap(); - AnySurface::new::(hal_surface) - }, - }; - - let (id, _) = self.surfaces.prepare(id_in).assign(surface); - id + self.instance_create_surface_dx12(id_in, |inst| unsafe { + inst.create_surface_from_swap_chain_panel(swap_chain_panel as _) + }) } pub fn surface_drop(&self, id: SurfaceId) { @@ -656,32 +694,34 @@ impl Global { api_log!("Surface::drop {id:?}"); - fn unconfigure(global: &Global, surface: &AnySurface, present: &Presentation) { - let hub = HalApi::hub(global); - if let Some(hal_surface) = surface.downcast_ref::() { + fn unconfigure( + global: &Global, + surface: &Option>, + present: &Presentation, + ) { + if let Some(surface) = surface { + let hub = HalApi::hub(global); if let Some(device) = present.device.downcast_ref::() { - hub.surface_unconfigure(device, hal_surface); + hub.surface_unconfigure(device, surface); } } } let surface = self.surfaces.unregister(id); - if let Some(surface) = Arc::into_inner(surface.unwrap()) { - if let Some(present) = surface.presentation.lock().take() { - #[cfg(vulkan)] - unconfigure::(self, &surface.raw, &present); - #[cfg(metal)] - unconfigure::(self, &surface.raw, &present); - #[cfg(dx12)] - unconfigure::(self, &surface.raw, &present); - #[cfg(gles)] - unconfigure::(self, &surface.raw, &present); - } + let surface = Arc::into_inner(surface.unwrap()) + .expect("Surface cannot be destroyed because is still in use"); - self.instance.destroy_surface(surface); - } else { - panic!("Surface cannot be destroyed because is still in use"); + if let Some(present) = surface.presentation.lock().take() { + #[cfg(vulkan)] + unconfigure::(self, &surface.vulkan, &present); + #[cfg(metal)] + unconfigure::(self, &surface.metal, &present); + #[cfg(dx12)] + unconfigure::(self, &surface.dx12, &present); + #[cfg(gles)] + unconfigure::(self, &surface.gl, &present); } + self.instance.destroy_surface(surface); } fn enumerate( @@ -707,7 +747,7 @@ impl Global { for raw in hal_adapters { let adapter = Adapter::new(raw); log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); - let (id, _) = hub.adapters.prepare(id_backend).assign(adapter); + let (id, _) = hub.adapters.prepare(id_backend).assign(Arc::new(adapter)); list.push(id); } } @@ -754,7 +794,10 @@ impl Global { None => { let adapter = Adapter::new(list.swap_remove(*selected)); log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); - let (id, _) = HalApi::hub(self).adapters.prepare(new_id).assign(adapter); + let (id, _) = HalApi::hub(self) + .adapters + .prepare(new_id) + .assign(Arc::new(adapter)); Some(id) } } @@ -784,7 +827,7 @@ impl Global { adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu); } if let Some(surface) = compatible_surface { - let surface = &A::get_surface(surface); + let surface = &A::surface_as_hal(surface); adapters.retain(|exposed| unsafe { // If the surface does not exist for this backend, // then the surface is not supported. @@ -937,13 +980,13 @@ impl Global { let (id, _adapter): (_, Arc>) = match A::VARIANT { #[cfg(vulkan)] - Backend::Vulkan => fid.assign(Adapter::new(hal_adapter)), + Backend::Vulkan => fid.assign(Arc::new(Adapter::new(hal_adapter))), #[cfg(metal)] - Backend::Metal => fid.assign(Adapter::new(hal_adapter)), + Backend::Metal => fid.assign(Arc::new(Adapter::new(hal_adapter))), #[cfg(dx12)] - Backend::Dx12 => fid.assign(Adapter::new(hal_adapter)), + Backend::Dx12 => fid.assign(Arc::new(Adapter::new(hal_adapter))), #[cfg(gles)] - Backend::Gl => fid.assign(Adapter::new(hal_adapter)), + Backend::Gl => fid.assign(Arc::new(Adapter::new(hal_adapter))), _ => unreachable!(), }; resource_log!("Created Adapter {:?}", id); @@ -1066,13 +1109,13 @@ impl Global { Ok((device, queue)) => (device, queue), Err(e) => break e, }; - let (device_id, _) = device_fid.assign(device); + let (device_id, _) = device_fid.assign(Arc::new(device)); resource_log!("Created Device {:?}", device_id); let device = hub.devices.get(device_id).unwrap(); queue.device = Some(device.clone()); - let (queue_id, queue) = queue_fid.assign(queue); + let (queue_id, queue) = queue_fid.assign(Arc::new(queue)); resource_log!("Created Queue {:?}", queue_id); device.set_queue(queue); @@ -1118,13 +1161,13 @@ impl Global { Ok(device) => device, Err(e) => break e, }; - let (device_id, _) = devices_fid.assign(device); + let (device_id, _) = devices_fid.assign(Arc::new(device)); resource_log!("Created Device {:?}", device_id); let device = hub.devices.get(device_id).unwrap(); queue.device = Some(device.clone()); - let (queue_id, queue) = queues_fid.assign(queue); + let (queue_id, queue) = queues_fid.assign(Arc::new(queue)); resource_log!("Created Queue {:?}", queue_id); device.set_queue(queue); diff --git a/third_party/rust/wgpu-core/src/lib.rs b/third_party/rust/wgpu-core/src/lib.rs index 5454f0d682..032d85a4bc 100644 --- a/third_party/rust/wgpu-core/src/lib.rs +++ b/third_party/rust/wgpu-core/src/lib.rs @@ -39,6 +39,8 @@ unused_braces, // It gets in the way a lot and does not prevent bugs in practice. clippy::pattern_type_mismatch, + // `wgpu-core` isn't entirely user-facing, so it's useful to document internal items. + rustdoc::private_intra_doc_links )] #![warn( trivial_casts, @@ -48,7 +50,6 @@ unused_qualifications )] -pub mod any_surface; pub mod binding_model; pub mod command; mod conv; @@ -62,6 +63,7 @@ pub mod id; pub mod identity; mod init_tracker; pub mod instance; +mod lock; pub mod pipeline; mod pool; pub mod present; diff --git a/third_party/rust/wgpu-core/src/lock/mod.rs b/third_party/rust/wgpu-core/src/lock/mod.rs new file mode 100644 index 0000000000..a6593a062d --- /dev/null +++ b/third_party/rust/wgpu-core/src/lock/mod.rs @@ -0,0 +1,41 @@ +//! Instrumented lock types. +//! +//! This module defines a set of instrumented wrappers for the lock +//! types used in `wgpu-core` ([`Mutex`], [`RwLock`], and +//! [`SnatchLock`]) that help us understand and validate `wgpu-core` +//! synchronization. +//! +//! - The [`ranked`] module defines lock types that perform run-time +//! checks to ensure that each thread acquires locks only in a +//! specific order, to prevent deadlocks. +//! +//! - The [`vanilla`] module defines lock types that are +//! uninstrumented, no-overhead wrappers around the standard lock +//! types. +//! +//! (We plan to add more wrappers in the future.) +//! +//! If the `wgpu_validate_locks` config is set (for example, with +//! `RUSTFLAGS='--cfg wgpu_validate_locks'`), `wgpu-core` uses the +//! [`ranked`] module's locks. We hope to make this the default for +//! debug builds soon. +//! +//! Otherwise, `wgpu-core` uses the [`vanilla`] module's locks. +//! +//! [`Mutex`]: parking_lot::Mutex +//! [`RwLock`]: parking_lot::RwLock +//! [`SnatchLock`]: crate::snatch::SnatchLock + +pub mod rank; + +#[cfg_attr(not(wgpu_validate_locks), allow(dead_code))] +mod ranked; + +#[cfg_attr(wgpu_validate_locks, allow(dead_code))] +mod vanilla; + +#[cfg(wgpu_validate_locks)] +pub use ranked::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; + +#[cfg(not(wgpu_validate_locks))] +pub use vanilla::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; diff --git a/third_party/rust/wgpu-core/src/lock/rank.rs b/third_party/rust/wgpu-core/src/lock/rank.rs new file mode 100644 index 0000000000..4387b8d138 --- /dev/null +++ b/third_party/rust/wgpu-core/src/lock/rank.rs @@ -0,0 +1,170 @@ +//! Ranks for `wgpu-core` locks, restricting acquisition order. +//! +//! See [`LockRank`]. + +/// The rank of a lock. +/// +/// Each [`Mutex`], [`RwLock`], and [`SnatchLock`] in `wgpu-core` has been +/// assigned a *rank*: a node in the DAG defined at the bottom of +/// `wgpu-core/src/lock/rank.rs`. The rank of the most recently +/// acquired lock you are still holding determines which locks you may +/// attempt to acquire next. +/// +/// When you create a lock in `wgpu-core`, you must specify its rank +/// by passing in a [`LockRank`] value. This module declares a +/// pre-defined set of ranks to cover everything in `wgpu-core`, named +/// after the type in which they occur, and the name of the type's +/// field that is a lock. For example, [`CommandBuffer::data`] is a +/// `Mutex`, and its rank here is the constant +/// [`COMMAND_BUFFER_DATA`]. +/// +/// [`Mutex`]: parking_lot::Mutex +/// [`RwLock`]: parking_lot::RwLock +/// [`SnatchLock`]: crate::snatch::SnatchLock +/// [`CommandBuffer::data`]: crate::command::CommandBuffer::data +#[derive(Debug, Copy, Clone)] +pub struct LockRank { + /// The bit representing this lock. + /// + /// There should only be a single bit set in this value. + pub(super) bit: LockRankSet, + + /// A bitmask of permitted successor ranks. + /// + /// If `rank` is the rank of the most recently acquired lock we + /// are still holding, then `rank.followers` is the mask of + /// locks we are allowed to acquire next. + /// + /// The `define_lock_ranks!` macro ensures that there are no + /// cycles in the graph of lock ranks and their followers. + pub(super) followers: LockRankSet, +} + +/// Define a set of lock ranks, and each rank's permitted successors. +macro_rules! define_lock_ranks { + { + $( + $( #[ $attr:meta ] )* + rank $name:ident $member:literal followed by { $( $follower:ident ),* $(,)? } + )* + } => { + // An enum that assigns a unique number to each rank. + #[allow(non_camel_case_types, clippy::upper_case_acronyms)] + enum LockRankNumber { $( $name, )* } + + bitflags::bitflags! { + #[derive(Debug, Copy, Clone, Eq, PartialEq)] + /// A bitflags type representing a set of lock ranks. + pub struct LockRankSet: u64 { + $( + const $name = 1 << (LockRankNumber:: $name as u64); + )* + } + } + + impl LockRankSet { + pub fn name(self) -> &'static str { + match self { + $( + LockRankSet:: $name => $member, + )* + _ => "", + } + } + } + + $( + // If there is any cycle in the ranking, the initializers + // for `followers` will be cyclic, and rustc will give us + // an error message explaining the cycle. + $( #[ $attr ] )* + pub const $name: LockRank = LockRank { + bit: LockRankSet:: $name, + followers: LockRankSet::empty() $( .union($follower.bit) )*, + }; + )* + } +} + +define_lock_ranks! { + rank DEVICE_TEMP_SUSPECTED "Device::temp_suspected" followed by { + SHARED_TRACKER_INDEX_ALLOCATOR_INNER, + COMMAND_BUFFER_DATA, + DEVICE_TRACKERS, + } + rank COMMAND_BUFFER_DATA "CommandBuffer::data" followed by { + DEVICE_SNATCHABLE_LOCK, + DEVICE_USAGE_SCOPES, + SHARED_TRACKER_INDEX_ALLOCATOR_INNER, + BUFFER_BIND_GROUP_STATE_BUFFERS, + TEXTURE_BIND_GROUP_STATE_TEXTURES, + BUFFER_MAP_STATE, + STATELESS_BIND_GROUP_STATE_RESOURCES, + } + rank DEVICE_SNATCHABLE_LOCK "Device::snatchable_lock" followed by { + SHARED_TRACKER_INDEX_ALLOCATOR_INNER, + DEVICE_TRACE, + BUFFER_MAP_STATE, + BUFFER_BIND_GROUP_STATE_BUFFERS, + TEXTURE_BIND_GROUP_STATE_TEXTURES, + STATELESS_BIND_GROUP_STATE_RESOURCES, + // Uncomment this to see an interesting cycle. + // COMMAND_BUFFER_DATA, + } + rank BUFFER_MAP_STATE "Buffer::map_state" followed by { + DEVICE_PENDING_WRITES, + SHARED_TRACKER_INDEX_ALLOCATOR_INNER, + DEVICE_TRACE, + } + rank DEVICE_PENDING_WRITES "Device::pending_writes" followed by { + COMMAND_ALLOCATOR_FREE_ENCODERS, + SHARED_TRACKER_INDEX_ALLOCATOR_INNER, + DEVICE_LIFE_TRACKER, + } + rank DEVICE_LIFE_TRACKER "Device::life_tracker" followed by { + COMMAND_ALLOCATOR_FREE_ENCODERS, + // Uncomment this to see an interesting cycle. + // DEVICE_TEMP_SUSPECTED, + DEVICE_TRACE, + } + rank COMMAND_ALLOCATOR_FREE_ENCODERS "CommandAllocator::free_encoders" followed by { + SHARED_TRACKER_INDEX_ALLOCATOR_INNER, + } + + rank BUFFER_BIND_GROUPS "Buffer::bind_groups" followed by { } + rank BUFFER_BIND_GROUP_STATE_BUFFERS "BufferBindGroupState::buffers" followed by { } + rank BUFFER_INITIALIZATION_STATUS "Buffer::initialization_status" followed by { } + rank BUFFER_SYNC_MAPPED_WRITES "Buffer::sync_mapped_writes" followed by { } + rank DEVICE_DEFERRED_DESTROY "Device::deferred_destroy" followed by { } + rank DEVICE_FENCE "Device::fence" followed by { } + #[allow(dead_code)] + rank DEVICE_TRACE "Device::trace" followed by { } + rank DEVICE_TRACKERS "Device::trackers" followed by { } + rank DEVICE_USAGE_SCOPES "Device::usage_scopes" followed by { } + rank IDENTITY_MANAGER_VALUES "IdentityManager::values" followed by { } + rank REGISTRY_STORAGE "Registry::storage" followed by { } + rank RENDER_BUNDLE_SCOPE_BUFFERS "RenderBundleScope::buffers" followed by { } + rank RENDER_BUNDLE_SCOPE_TEXTURES "RenderBundleScope::textures" followed by { } + rank RENDER_BUNDLE_SCOPE_BIND_GROUPS "RenderBundleScope::bind_groups" followed by { } + rank RENDER_BUNDLE_SCOPE_RENDER_PIPELINES "RenderBundleScope::render_pipelines" followed by { } + rank RENDER_BUNDLE_SCOPE_QUERY_SETS "RenderBundleScope::query_sets" followed by { } + rank RESOURCE_POOL_INNER "ResourcePool::inner" followed by { } + rank SHARED_TRACKER_INDEX_ALLOCATOR_INNER "SharedTrackerIndexAllocator::inner" followed by { } + rank STAGING_BUFFER_RAW "StagingBuffer::raw" followed by { } + rank STATELESS_BIND_GROUP_STATE_RESOURCES "StatelessBindGroupState::resources" followed by { } + rank SURFACE_PRESENTATION "Surface::presentation" followed by { } + rank TEXTURE_BIND_GROUPS "Texture::bind_groups" followed by { } + rank TEXTURE_BIND_GROUP_STATE_TEXTURES "TextureBindGroupState::textures" followed by { } + rank TEXTURE_INITIALIZATION_STATUS "Texture::initialization_status" followed by { } + rank TEXTURE_CLEAR_MODE "Texture::clear_mode" followed by { } + rank TEXTURE_VIEWS "Texture::views" followed by { } + + #[cfg(test)] + rank PAWN "pawn" followed by { ROOK, BISHOP } + #[cfg(test)] + rank ROOK "rook" followed by { KNIGHT } + #[cfg(test)] + rank KNIGHT "knight" followed by { } + #[cfg(test)] + rank BISHOP "bishop" followed by { } +} diff --git a/third_party/rust/wgpu-core/src/lock/ranked.rs b/third_party/rust/wgpu-core/src/lock/ranked.rs new file mode 100644 index 0000000000..4237116c2c --- /dev/null +++ b/third_party/rust/wgpu-core/src/lock/ranked.rs @@ -0,0 +1,397 @@ +//! Lock types that enforce well-ranked lock acquisition order. +//! +//! This module's [`Mutex`] and [`RwLock` types are instrumented to check that +//! `wgpu-core` acquires locks according to their rank, to prevent deadlocks. To +//! use it, put `--cfg wgpu_validate_locks` in `RUSTFLAGS`. +//! +//! The [`LockRank`] constants in the [`lock::rank`] module describe edges in a +//! directed graph of lock acquisitions: each lock's rank says, if this is the most +//! recently acquired lock that you are still holding, then these are the locks you +//! are allowed to acquire next. +//! +//! As long as this graph doesn't have cycles, any number of threads can acquire +//! locks along paths through the graph without deadlock: +//! +//! - Assume that if a thread is holding a lock, then it will either release it, +//! or block trying to acquire another one. No thread just sits on its locks +//! forever for unrelated reasons. If it did, then that would be a source of +//! deadlock "outside the system" that we can't do anything about. +//! +//! - This module asserts that threads acquire and release locks in a stack-like +//! order: a lock is dropped only when it is the *most recently acquired* lock +//! *still held* - call this the "youngest" lock. This stack-like ordering +//! isn't a Rust requirement; Rust lets you drop guards in any order you like. +//! This is a restriction we impose. +//! +//! - Consider the directed graph whose nodes are locks, and whose edges go from +//! each lock to its permitted followers, the locks in its [`LockRank::followers`] +//! set. The definition of the [`lock::rank`] module's [`LockRank`] constants +//! ensures that this graph has no cycles, including trivial cycles from a node to +//! itself. +//! +//! - This module then asserts that each thread attempts to acquire a lock only if +//! it is among its youngest lock's permitted followers. Thus, as a thread +//! acquires locks, it must be traversing a path through the graph along its +//! edges. +//! +//! - Because there are no cycles in the graph, whenever one thread is blocked +//! waiting to acquire a lock, that lock must be held by a different thread: if +//! you were allowed to acquire a lock you already hold, that would be a cycle in +//! the graph. +//! +//! - Furthermore, because the graph has no cycles, as we work our way from each +//! thread to the thread it is blocked waiting for, we must eventually reach an +//! end point: there must be some thread that is able to acquire its next lock, or +//! that is about to release a lock. +//! +//! Thus, the system as a whole is always able to make progress: it is free of +//! deadlocks. +//! +//! Note that this validation only monitors each thread's behavior in isolation: +//! there's only thread-local state, nothing communicated between threads. So we +//! don't detect deadlocks, per se, only the potential to cause deadlocks. This +//! means that the validation is conservative, but more reproducible, since it's not +//! dependent on any particular interleaving of execution. +//! +//! [`lock::rank`]: crate::lock::rank + +use super::rank::LockRank; +use std::{cell::Cell, panic::Location}; + +/// A `Mutex` instrumented for deadlock prevention. +/// +/// This is just a wrapper around a [`parking_lot::Mutex`], along with +/// its rank in the `wgpu_core` lock ordering. +/// +/// For details, see [the module documentation][mod]. +/// +/// [mod]: crate::lock::ranked +pub struct Mutex { + inner: parking_lot::Mutex, + rank: LockRank, +} + +/// A guard produced by locking [`Mutex`]. +/// +/// This is just a wrapper around a [`parking_lot::MutexGuard`], along +/// with the state needed to track lock acquisition. +/// +/// For details, see [the module documentation][mod]. +/// +/// [mod]: crate::lock::ranked +pub struct MutexGuard<'a, T> { + inner: parking_lot::MutexGuard<'a, T>, + saved: LockStateGuard, +} + +thread_local! { + static LOCK_STATE: Cell = const { Cell::new(LockState::INITIAL) }; +} + +/// Per-thread state for the deadlock checker. +#[derive(Debug, Copy, Clone)] +struct LockState { + /// The last lock we acquired, and where. + last_acquired: Option<(LockRank, &'static Location<'static>)>, + + /// The number of locks currently held. + /// + /// This is used to enforce stack-like lock acquisition and release. + depth: u32, +} + +impl LockState { + const INITIAL: LockState = LockState { + last_acquired: None, + depth: 0, + }; +} + +/// A container that restores a [`LockState`] when dropped. +/// +/// This type serves two purposes: +/// +/// - Operations like `RwLockWriteGuard::downgrade` would like to be able to +/// destructure lock guards and reassemble their pieces into new guards, but +/// if the guard type itself implements `Drop`, we can't destructure it +/// without unsafe code or pointless `Option`s whose state is almost always +/// statically known. +/// +/// - We can just implement `Drop` for this type once, and then use it in lock +/// guards, rather than implementing `Drop` separately for each guard type. +struct LockStateGuard(LockState); + +impl Drop for LockStateGuard { + fn drop(&mut self) { + release(self.0) + } +} + +/// Check and record the acquisition of a lock with `new_rank`. +/// +/// Check that acquiring a lock with `new_rank` is permitted at this point, and +/// update the per-thread state accordingly. +/// +/// Return the `LockState` that must be restored when this thread is released. +fn acquire(new_rank: LockRank, location: &'static Location<'static>) -> LockState { + let state = LOCK_STATE.get(); + // Initially, it's fine to acquire any lock. So we only + // need to check when `last_acquired` is `Some`. + if let Some((ref last_rank, ref last_location)) = state.last_acquired { + assert!( + last_rank.followers.contains(new_rank.bit), + "Attempt to acquire nested mutexes in wrong order:\n\ + last locked {:<35} at {}\n\ + now locking {:<35} at {}\n\ + Locking {} after locking {} is not permitted.", + last_rank.bit.name(), + last_location, + new_rank.bit.name(), + location, + new_rank.bit.name(), + last_rank.bit.name(), + ); + } + LOCK_STATE.set(LockState { + last_acquired: Some((new_rank, location)), + depth: state.depth + 1, + }); + state +} + +/// Record the release of a lock whose saved state was `saved`. +/// +/// Check that locks are being acquired in stacking order, and update the +/// per-thread state accordingly. +fn release(saved: LockState) { + let prior = LOCK_STATE.replace(saved); + + // Although Rust allows mutex guards to be dropped in any + // order, this analysis requires that locks be acquired and + // released in stack order: the next lock to be released must be + // the most recently acquired lock still held. + assert_eq!( + prior.depth, + saved.depth + 1, + "Lock not released in stacking order" + ); +} + +impl Mutex { + pub fn new(rank: LockRank, value: T) -> Mutex { + Mutex { + inner: parking_lot::Mutex::new(value), + rank, + } + } + + #[track_caller] + pub fn lock(&self) -> MutexGuard { + let saved = acquire(self.rank, Location::caller()); + MutexGuard { + inner: self.inner.lock(), + saved: LockStateGuard(saved), + } + } +} + +impl<'a, T> std::ops::Deref for MutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl<'a, T> std::ops::DerefMut for MutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner.deref_mut() + } +} + +impl std::fmt::Debug for Mutex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner.fmt(f) + } +} + +/// An `RwLock` instrumented for deadlock prevention. +/// +/// This is just a wrapper around a [`parking_lot::RwLock`], along with +/// its rank in the `wgpu_core` lock ordering. +/// +/// For details, see [the module documentation][mod]. +/// +/// [mod]: crate::lock::ranked +pub struct RwLock { + inner: parking_lot::RwLock, + rank: LockRank, +} + +/// A read guard produced by locking [`RwLock`] for reading. +/// +/// This is just a wrapper around a [`parking_lot::RwLockReadGuard`], along with +/// the state needed to track lock acquisition. +/// +/// For details, see [the module documentation][mod]. +/// +/// [mod]: crate::lock::ranked +pub struct RwLockReadGuard<'a, T> { + inner: parking_lot::RwLockReadGuard<'a, T>, + saved: LockStateGuard, +} + +/// A write guard produced by locking [`RwLock`] for writing. +/// +/// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`], along +/// with the state needed to track lock acquisition. +/// +/// For details, see [the module documentation][mod]. +/// +/// [mod]: crate::lock::ranked +pub struct RwLockWriteGuard<'a, T> { + inner: parking_lot::RwLockWriteGuard<'a, T>, + saved: LockStateGuard, +} + +impl RwLock { + pub fn new(rank: LockRank, value: T) -> RwLock { + RwLock { + inner: parking_lot::RwLock::new(value), + rank, + } + } + + #[track_caller] + pub fn read(&self) -> RwLockReadGuard { + let saved = acquire(self.rank, Location::caller()); + RwLockReadGuard { + inner: self.inner.read(), + saved: LockStateGuard(saved), + } + } + + #[track_caller] + pub fn write(&self) -> RwLockWriteGuard { + let saved = acquire(self.rank, Location::caller()); + RwLockWriteGuard { + inner: self.inner.write(), + saved: LockStateGuard(saved), + } + } +} + +impl<'a, T> RwLockWriteGuard<'a, T> { + pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> { + RwLockReadGuard { + inner: parking_lot::RwLockWriteGuard::downgrade(this.inner), + saved: this.saved, + } + } +} + +impl std::fmt::Debug for RwLock { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner.fmt(f) + } +} + +impl<'a, T> std::ops::Deref for RwLockReadGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl<'a, T> std::ops::Deref for RwLockWriteGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl<'a, T> std::ops::DerefMut for RwLockWriteGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner.deref_mut() + } +} + +/// Locks can be acquired in the order indicated by their ranks. +#[test] +fn permitted() { + use super::rank; + + let lock1 = Mutex::new(rank::PAWN, ()); + let lock2 = Mutex::new(rank::ROOK, ()); + + let _guard1 = lock1.lock(); + let _guard2 = lock2.lock(); +} + +/// Locks can only be acquired in the order indicated by their ranks. +#[test] +#[should_panic(expected = "Locking pawn after locking rook")] +fn forbidden_unrelated() { + use super::rank; + + let lock1 = Mutex::new(rank::ROOK, ()); + let lock2 = Mutex::new(rank::PAWN, ()); + + let _guard1 = lock1.lock(); + let _guard2 = lock2.lock(); +} + +/// Lock acquisitions can't skip ranks. +/// +/// These two locks *could* be acquired in this order, but only if other locks +/// are acquired in between them. Skipping ranks isn't allowed. +#[test] +#[should_panic(expected = "Locking knight after locking pawn")] +fn forbidden_skip() { + use super::rank; + + let lock1 = Mutex::new(rank::PAWN, ()); + let lock2 = Mutex::new(rank::KNIGHT, ()); + + let _guard1 = lock1.lock(); + let _guard2 = lock2.lock(); +} + +/// Locks can be acquired and released in a stack-like order. +#[test] +fn stack_like() { + use super::rank; + + let lock1 = Mutex::new(rank::PAWN, ()); + let lock2 = Mutex::new(rank::ROOK, ()); + let lock3 = Mutex::new(rank::BISHOP, ()); + + let guard1 = lock1.lock(); + let guard2 = lock2.lock(); + drop(guard2); + + let guard3 = lock3.lock(); + drop(guard3); + drop(guard1); +} + +/// Locks can only be acquired and released in a stack-like order. +#[test] +#[should_panic(expected = "Lock not released in stacking order")] +fn non_stack_like() { + use super::rank; + + let lock1 = Mutex::new(rank::PAWN, ()); + let lock2 = Mutex::new(rank::ROOK, ()); + + let guard1 = lock1.lock(); + let guard2 = lock2.lock(); + + // Avoid a double panic from dropping this while unwinding due to the panic + // we're testing for. + std::mem::forget(guard2); + + drop(guard1); +} diff --git a/third_party/rust/wgpu-core/src/lock/vanilla.rs b/third_party/rust/wgpu-core/src/lock/vanilla.rs new file mode 100644 index 0000000000..9a35b6d9d8 --- /dev/null +++ b/third_party/rust/wgpu-core/src/lock/vanilla.rs @@ -0,0 +1,121 @@ +//! Plain, uninstrumented wrappers around [`parking_lot`] lock types. +//! +//! These definitions are used when no particular lock instrumentation +//! Cargo feature is selected. + +/// A plain wrapper around [`parking_lot::Mutex`]. +/// +/// This is just like [`parking_lot::Mutex`], except that our [`new`] +/// method takes a rank, indicating where the new mutex should sit in +/// `wgpu-core`'s lock ordering. The rank is ignored. +/// +/// See the [`lock`] module documentation for other wrappers. +/// +/// [`new`]: Mutex::new +/// [`lock`]: crate::lock +pub struct Mutex(parking_lot::Mutex); + +/// A guard produced by locking [`Mutex`]. +/// +/// This is just a wrapper around a [`parking_lot::MutexGuard`]. +pub struct MutexGuard<'a, T>(parking_lot::MutexGuard<'a, T>); + +impl Mutex { + pub fn new(_rank: super::rank::LockRank, value: T) -> Mutex { + Mutex(parking_lot::Mutex::new(value)) + } + + pub fn lock(&self) -> MutexGuard { + MutexGuard(self.0.lock()) + } +} + +impl<'a, T> std::ops::Deref for MutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl<'a, T> std::ops::DerefMut for MutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0.deref_mut() + } +} + +impl std::fmt::Debug for Mutex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +/// A plain wrapper around [`parking_lot::RwLock`]. +/// +/// This is just like [`parking_lot::RwLock`], except that our [`new`] +/// method takes a rank, indicating where the new mutex should sit in +/// `wgpu-core`'s lock ordering. The rank is ignored. +/// +/// See the [`lock`] module documentation for other wrappers. +/// +/// [`new`]: RwLock::new +/// [`lock`]: crate::lock +pub struct RwLock(parking_lot::RwLock); + +/// A read guard produced by locking [`RwLock`] as a reader. +/// +/// This is just a wrapper around a [`parking_lot::RwLockReadGuard`]. +pub struct RwLockReadGuard<'a, T>(parking_lot::RwLockReadGuard<'a, T>); + +/// A write guard produced by locking [`RwLock`] as a writer. +/// +/// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`]. +pub struct RwLockWriteGuard<'a, T>(parking_lot::RwLockWriteGuard<'a, T>); + +impl RwLock { + pub fn new(_rank: super::rank::LockRank, value: T) -> RwLock { + RwLock(parking_lot::RwLock::new(value)) + } + + pub fn read(&self) -> RwLockReadGuard { + RwLockReadGuard(self.0.read()) + } + + pub fn write(&self) -> RwLockWriteGuard { + RwLockWriteGuard(self.0.write()) + } +} + +impl<'a, T> RwLockWriteGuard<'a, T> { + pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> { + RwLockReadGuard(parking_lot::RwLockWriteGuard::downgrade(this.0)) + } +} + +impl std::fmt::Debug for RwLock { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl<'a, T> std::ops::Deref for RwLockReadGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl<'a, T> std::ops::Deref for RwLockWriteGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl<'a, T> std::ops::DerefMut for RwLockWriteGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0.deref_mut() + } +} diff --git a/third_party/rust/wgpu-core/src/pipeline.rs b/third_party/rust/wgpu-core/src/pipeline.rs index 4a7651b327..d70b118d7e 100644 --- a/third_party/rust/wgpu-core/src/pipeline.rs +++ b/third_party/rust/wgpu-core/src/pipeline.rs @@ -10,7 +10,8 @@ use crate::{ resource_log, validation, Label, }; use arrayvec::ArrayVec; -use std::{borrow::Cow, error::Error, fmt, marker::PhantomData, num::NonZeroU32, sync::Arc}; +use naga::error::ShaderError; +use std::{borrow::Cow, marker::PhantomData, num::NonZeroU32, sync::Arc}; use thiserror::Error; /// Information about buffer bindings, which @@ -107,79 +108,8 @@ impl ShaderModule { } } -#[derive(Clone, Debug)] -pub struct ShaderError { - pub source: String, - pub label: Option, - pub inner: Box, -} -#[cfg(feature = "wgsl")] -impl fmt::Display for ShaderError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let label = self.label.as_deref().unwrap_or_default(); - let string = self.inner.emit_to_string(&self.source); - write!(f, "\nShader '{label}' parsing {string}") - } -} -#[cfg(feature = "glsl")] -impl fmt::Display for ShaderError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let label = self.label.as_deref().unwrap_or_default(); - let string = self.inner.emit_to_string(&self.source); - write!(f, "\nShader '{label}' parsing {string}") - } -} -#[cfg(feature = "spirv")] -impl fmt::Display for ShaderError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let label = self.label.as_deref().unwrap_or_default(); - let string = self.inner.emit_to_string(&self.source); - write!(f, "\nShader '{label}' parsing {string}") - } -} -impl fmt::Display for ShaderError> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use codespan_reporting::{ - diagnostic::{Diagnostic, Label}, - files::SimpleFile, - term, - }; - - let label = self.label.as_deref().unwrap_or_default(); - let files = SimpleFile::new(label, &self.source); - let config = term::Config::default(); - let mut writer = term::termcolor::NoColor::new(Vec::new()); - - let diagnostic = Diagnostic::error().with_labels( - self.inner - .spans() - .map(|&(span, ref desc)| { - Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned()) - }) - .collect(), - ); - - term::emit(&mut writer, &config, &files, &diagnostic).expect("cannot write error"); - - write!( - f, - "\nShader validation {}", - String::from_utf8_lossy(&writer.into_inner()) - ) - } -} -impl Error for ShaderError -where - ShaderError: fmt::Display, - E: Error + 'static, -{ - fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(&self.inner) - } -} - //Note: `Clone` would require `WithSpan: Clone`. -#[derive(Debug, Error)] +#[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum CreateShaderModuleError { #[cfg(feature = "wgsl")] @@ -187,7 +117,7 @@ pub enum CreateShaderModuleError { Parsing(#[from] ShaderError), #[cfg(feature = "glsl")] #[error(transparent)] - ParsingGlsl(#[from] ShaderError), + ParsingGlsl(#[from] ShaderError), #[cfg(feature = "spirv")] #[error(transparent)] ParsingSpirV(#[from] ShaderError), @@ -209,17 +139,6 @@ pub enum CreateShaderModuleError { }, } -impl CreateShaderModuleError { - pub fn location(&self, source: &str) -> Option { - match *self { - #[cfg(feature = "wgsl")] - CreateShaderModuleError::Parsing(ref err) => err.inner.location(source), - CreateShaderModuleError::Validation(ref err) => err.inner.location(source), - _ => None, - } - } -} - /// Describes a programmable pipeline stage. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -233,6 +152,19 @@ pub struct ProgrammableStageDescriptor<'a> { /// * If a single entry point associated with this stage must be in the shader, then proceed as /// if `Some(…)` was specified with that entry point's name. pub entry_point: Option>, + /// Specifies the values of pipeline-overridable constants in the shader module. + /// + /// If an `@id` attribute was specified on the declaration, + /// the key must be the pipeline constant ID as a decimal ASCII number; if not, + /// the key must be the constant's identifier name. + /// + /// The value may represent any of WGSL's concrete scalar types. + pub constants: Cow<'a, naga::back::PipelineConstants>, + /// Whether workgroup scoped memory will be initialized with zero values for this stage. + /// + /// This is required by the WebGPU spec, but may have overhead which can be avoided + /// for cross-platform applications + pub zero_initialize_workgroup_memory: bool, } /// Number of implicit bind groups derived at pipeline creation. diff --git a/third_party/rust/wgpu-core/src/pool.rs b/third_party/rust/wgpu-core/src/pool.rs index 47de6d5feb..7d17f3a7a3 100644 --- a/third_party/rust/wgpu-core/src/pool.rs +++ b/third_party/rust/wgpu-core/src/pool.rs @@ -5,8 +5,8 @@ use std::{ }; use once_cell::sync::OnceCell; -use parking_lot::Mutex; +use crate::lock::{rank, Mutex}; use crate::{PreHashedKey, PreHashedMap}; type SlotInner = Weak; @@ -22,13 +22,15 @@ pub struct ResourcePool { impl ResourcePool { pub fn new() -> Self { Self { - inner: Mutex::new(HashMap::default()), + inner: Mutex::new(rank::RESOURCE_POOL_INNER, HashMap::default()), } } - /// Get a resource from the pool with the given entry map, or create a new one if it doesn't exist using the given constructor. + /// Get a resource from the pool with the given entry map, or create a new + /// one if it doesn't exist using the given constructor. /// - /// Behaves such that only one resource will be created for each unique entry map at any one time. + /// Behaves such that only one resource will be created for each unique + /// entry map at any one time. pub fn get_or_init(&self, key: K, constructor: F) -> Result, E> where F: FnOnce(K) -> Result, E>, @@ -96,6 +98,8 @@ impl ResourcePool { /// Remove the given entry map from the pool. /// /// Must *only* be called in the Drop impl of [`BindGroupLayout`]. + /// + /// [`BindGroupLayout`]: crate::binding_model::BindGroupLayout pub fn remove(&self, key: &K) { let hashed_key = PreHashedKey::from_key(key); diff --git a/third_party/rust/wgpu-core/src/present.rs b/third_party/rust/wgpu-core/src/present.rs index cb4e17798f..053f7fdb24 100644 --- a/third_party/rust/wgpu-core/src/present.rs +++ b/third_party/rust/wgpu-core/src/present.rs @@ -9,7 +9,7 @@ When this texture is presented, we remove it from the device tracker as well as extract it from the hub. !*/ -use std::borrow::Borrow; +use std::{borrow::Borrow, sync::Arc}; #[cfg(feature = "trace")] use crate::device::trace::Action; @@ -21,13 +21,13 @@ use crate::{ hal_api::HalApi, hal_label, id, init_tracker::TextureInitTracker, + lock::{rank, Mutex, RwLock}, resource::{self, ResourceInfo}, snatch::Snatchable, track, }; use hal::{Queue as _, Surface as _}; -use parking_lot::{Mutex, RwLock}; use thiserror::Error; use wgt::SurfaceStatus as Status; @@ -157,7 +157,7 @@ impl Global { #[cfg(not(feature = "trace"))] let _ = device; - let suf = A::get_surface(surface.as_ref()); + let suf = A::surface_as_hal(surface.as_ref()); let (texture_id, status) = match unsafe { suf.unwrap() .acquire_texture(Some(std::time::Duration::from_millis( @@ -215,7 +215,10 @@ impl Global { desc: texture_desc, hal_usage, format_features, - initialization_status: RwLock::new(TextureInitTracker::new(1, 1)), + initialization_status: RwLock::new( + rank::TEXTURE_INITIALIZATION_STATUS, + TextureInitTracker::new(1, 1), + ), full_range: track::TextureSelector { layers: 0..1, mips: 0..1, @@ -224,14 +227,17 @@ impl Global { "", Some(device.tracker_indices.textures.clone()), ), - clear_mode: RwLock::new(resource::TextureClearMode::Surface { - clear_view: Some(clear_view), - }), - views: Mutex::new(Vec::new()), - bind_groups: Mutex::new(Vec::new()), + clear_mode: RwLock::new( + rank::TEXTURE_CLEAR_MODE, + resource::TextureClearMode::Surface { + clear_view: Some(clear_view), + }, + ), + views: Mutex::new(rank::TEXTURE_VIEWS, Vec::new()), + bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, Vec::new()), }; - let (id, resource) = fid.assign(texture); + let (id, resource) = fid.assign(Arc::new(texture)); log::debug!("Created CURRENT Surface Texture {:?}", id); { @@ -324,7 +330,7 @@ impl Global { .textures .remove(texture.info.tracker_index()); let mut exclusive_snatch_guard = device.snatchable_lock.write(); - let suf = A::get_surface(&surface); + let suf = A::surface_as_hal(&surface); let mut inner = texture.inner_mut(&mut exclusive_snatch_guard); let inner = inner.as_mut().unwrap(); @@ -418,7 +424,7 @@ impl Global { .lock() .textures .remove(texture.info.tracker_index()); - let suf = A::get_surface(&surface); + let suf = A::surface_as_hal(&surface); let exclusive_snatch_guard = device.snatchable_lock.write(); match texture.inner.snatch(exclusive_snatch_guard).unwrap() { resource::TextureInner::Surface { mut raw, parent_id } => { diff --git a/third_party/rust/wgpu-core/src/registry.rs b/third_party/rust/wgpu-core/src/registry.rs index 80394351af..f0f5674dae 100644 --- a/third_party/rust/wgpu-core/src/registry.rs +++ b/third_party/rust/wgpu-core/src/registry.rs @@ -1,11 +1,11 @@ use std::sync::Arc; -use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use wgt::Backend; use crate::{ id::Id, identity::IdentityManager, + lock::{rank, RwLock, RwLockReadGuard, RwLockWriteGuard}, resource::Resource, storage::{Element, InvalidId, Storage}, }; @@ -37,7 +37,8 @@ impl RegistryReport { /// any other dependent resource /// #[derive(Debug)] -pub struct Registry { +pub(crate) struct Registry { + // Must only contain an id which has either never been used or has been released from `storage` identity: Arc>, storage: RwLock>, backend: Backend, @@ -47,7 +48,7 @@ impl Registry { pub(crate) fn new(backend: Backend) -> Self { Self { identity: Arc::new(IdentityManager::new()), - storage: RwLock::new(Storage::new()), + storage: RwLock::new(rank::REGISTRY_STORAGE, Storage::new()), backend, } } @@ -78,21 +79,26 @@ impl FutureId<'_, T> { Arc::new(value) } + pub fn init_in_place(&self, mut value: Arc) -> Arc { + Arc::get_mut(&mut value) + .unwrap() + .as_info_mut() + .set_id(self.id); + value + } + /// Assign a new resource to this ID. /// /// Registers it with the registry, and fills out the resource info. - pub fn assign(self, value: T) -> (Id, Arc) { + pub fn assign(self, value: Arc) -> (Id, Arc) { let mut data = self.data.write(); - data.insert(self.id, self.init(value)); + data.insert(self.id, self.init_in_place(value)); (self.id, data.get(self.id).unwrap().clone()) } /// Assign an existing resource to a new ID. /// /// Registers it with the registry. - /// - /// This _will_ leak the ID, and it will not be recycled again. - /// See https://github.com/gfx-rs/wgpu/issues/4912. pub fn assign_existing(self, value: &Arc) -> Id { let mut data = self.data.write(); debug_assert!(!data.contains(self.id)); @@ -138,28 +144,35 @@ impl Registry { pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage> { self.storage.write() } - pub fn unregister_locked(&self, id: Id, storage: &mut Storage) -> Option> { + pub(crate) fn unregister_locked( + &self, + id: Id, + storage: &mut Storage, + ) -> Option> { self.identity.free(id); storage.remove(id) } - pub fn force_replace(&self, id: Id, mut value: T) { + pub(crate) fn force_replace(&self, id: Id, mut value: T) { let mut storage = self.storage.write(); value.as_info_mut().set_id(id); storage.force_replace(id, value) } - pub fn force_replace_with_error(&self, id: Id, label: &str) { + pub(crate) fn force_replace_with_error(&self, id: Id, label: &str) { let mut storage = self.storage.write(); storage.remove(id); storage.insert_error(id, label); } pub(crate) fn unregister(&self, id: Id) -> Option> { - self.identity.free(id); let value = self.storage.write().remove(id); + // This needs to happen *after* removing it from the storage, to maintain the + // invariant that `self.identity` only contains ids which are actually available + // See https://github.com/gfx-rs/wgpu/issues/5372 + self.identity.free(id); //Returning None is legal if it's an error ID value } - pub fn label_for_resource(&self, id: Id) -> String { + pub(crate) fn label_for_resource(&self, id: Id) -> String { let guard = self.storage.read(); let type_name = guard.kind(); @@ -197,3 +210,53 @@ impl Registry { report } } + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use crate::{ + id::Marker, + resource::{Resource, ResourceInfo, ResourceType}, + }; + + use super::Registry; + struct TestData { + info: ResourceInfo, + } + struct TestDataId; + impl Marker for TestDataId {} + + impl Resource for TestData { + type Marker = TestDataId; + + const TYPE: ResourceType = "Test data"; + + fn as_info(&self) -> &ResourceInfo { + &self.info + } + + fn as_info_mut(&mut self) -> &mut ResourceInfo { + &mut self.info + } + } + + #[test] + fn simultaneous_registration() { + let registry = Registry::without_backend(); + std::thread::scope(|s| { + for _ in 0..5 { + s.spawn(|| { + for _ in 0..1000 { + let value = Arc::new(TestData { + info: ResourceInfo::new("Test data", None), + }); + let new_id = registry.prepare(None); + let (id, _) = new_id.assign(value); + registry.unregister(id); + } + }); + } + }) + } +} diff --git a/third_party/rust/wgpu-core/src/resource.rs b/third_party/rust/wgpu-core/src/resource.rs index aca077caab..d3cd2968bf 100644 --- a/third_party/rust/wgpu-core/src/resource.rs +++ b/third_party/rust/wgpu-core/src/resource.rs @@ -8,8 +8,12 @@ use crate::{ }, global::Global, hal_api::HalApi, - id::{AdapterId, BufferId, DeviceId, Id, Marker, SurfaceId, TextureId}, + id::{ + AdapterId, BufferId, CommandEncoderId, DeviceId, Id, Marker, SurfaceId, TextureId, + TextureViewId, + }, init_tracker::{BufferInitTracker, TextureInitTracker}, + lock::{Mutex, RwLock}, resource, resource_log, snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable}, track::{SharedTrackerIndexAllocator, TextureSelector, TrackerIndex}, @@ -18,7 +22,6 @@ use crate::{ }; use hal::CommandEncoder; -use parking_lot::{Mutex, RwLock}; use smallvec::SmallVec; use thiserror::Error; use wgt::WasmNotSendSync; @@ -55,7 +58,7 @@ use std::{ /// [`Device`]: crate::device::resource::Device /// [`Buffer`]: crate::resource::Buffer #[derive(Debug)] -pub struct ResourceInfo { +pub(crate) struct ResourceInfo { id: Option>, tracker_index: TrackerIndex, tracker_indices: Option>, @@ -141,7 +144,7 @@ impl ResourceInfo { pub(crate) type ResourceType = &'static str; -pub trait Resource: 'static + Sized + WasmNotSendSync { +pub(crate) trait Resource: 'static + Sized + WasmNotSendSync { type Marker: Marker; const TYPE: ResourceType; fn as_info(&self) -> &ResourceInfo; @@ -370,10 +373,10 @@ pub type BufferAccessResult = Result<(), BufferAccessError>; #[derive(Debug)] pub(crate) struct BufferPendingMapping { - pub range: Range, - pub op: BufferMapOperation, + pub(crate) range: Range, + pub(crate) op: BufferMapOperation, // hold the parent alive while the mapping is active - pub _parent_buffer: Arc>, + pub(crate) _parent_buffer: Arc>, } pub type BufferDescriptor<'a> = wgt::BufferDescriptor>; @@ -734,7 +737,7 @@ pub(crate) enum TextureInner { } impl TextureInner { - pub fn raw(&self) -> Option<&A::Texture> { + pub(crate) fn raw(&self) -> Option<&A::Texture> { match self { Self::Native { raw } => Some(raw), Self::Surface { raw: Some(tex), .. } => Some(tex.borrow()), @@ -924,11 +927,11 @@ impl Global { /// # Safety /// /// - The raw texture handle must not be manually destroyed - pub unsafe fn texture_as_hal)>( + pub unsafe fn texture_as_hal) -> R, R>( &self, id: TextureId, hal_texture_callback: F, - ) { + ) -> R { profiling::scope!("Texture::as_hal"); let hub = A::hub(self); @@ -937,7 +940,26 @@ impl Global { let snatch_guard = texture.device.snatchable_lock.read(); let hal_texture = texture.raw(&snatch_guard); - hal_texture_callback(hal_texture); + hal_texture_callback(hal_texture) + } + + /// # Safety + /// + /// - The raw texture view handle must not be manually destroyed + pub unsafe fn texture_view_as_hal) -> R, R>( + &self, + id: TextureViewId, + hal_texture_view_callback: F, + ) -> R { + profiling::scope!("TextureView::as_hal"); + + let hub = A::hub(self); + let texture_view_opt = { hub.texture_views.try_get(id).ok().flatten() }; + let texture_view = texture_view_opt.as_ref().unwrap(); + let snatch_guard = texture_view.device.snatchable_lock.read(); + let hal_texture_view = texture_view.raw(&snatch_guard); + + hal_texture_view_callback(hal_texture_view) } /// # Safety @@ -1001,10 +1023,38 @@ impl Global { profiling::scope!("Surface::as_hal"); let surface = self.surfaces.get(id).ok(); - let hal_surface = surface.as_ref().and_then(|surface| A::get_surface(surface)); + let hal_surface = surface + .as_ref() + .and_then(|surface| A::surface_as_hal(surface)); hal_surface_callback(hal_surface) } + + /// # Safety + /// + /// - The raw command encoder handle must not be manually destroyed + pub unsafe fn command_encoder_as_hal_mut< + A: HalApi, + F: FnOnce(Option<&mut A::CommandEncoder>) -> R, + R, + >( + &self, + id: CommandEncoderId, + hal_command_encoder_callback: F, + ) -> R { + profiling::scope!("CommandEncoder::as_hal"); + + let hub = A::hub(self); + let cmd_buf = hub + .command_buffers + .get(id.into_command_buffer_id()) + .unwrap(); + let mut cmd_buf_data = cmd_buf.data.lock(); + let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let cmd_buf_raw = cmd_buf_data.encoder.open().ok(); + + hal_command_encoder_callback(cmd_buf_raw) + } } /// A texture that has been marked as destroyed and is staged for actual deletion soon. diff --git a/third_party/rust/wgpu-core/src/snatch.rs b/third_party/rust/wgpu-core/src/snatch.rs index d5cd1a3d37..08a1eba11d 100644 --- a/third_party/rust/wgpu-core/src/snatch.rs +++ b/third_party/rust/wgpu-core/src/snatch.rs @@ -1,6 +1,6 @@ #![allow(unused)] -use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use crate::lock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::{ backtrace::Backtrace, cell::{Cell, RefCell, UnsafeCell}, @@ -8,6 +8,8 @@ use std::{ thread, }; +use crate::lock::rank; + /// A guard that provides read access to snatchable data. pub struct SnatchGuard<'a>(RwLockReadGuard<'a, ()>); /// A guard that allows snatching the snatchable data. @@ -64,8 +66,58 @@ impl std::fmt::Debug for Snatchable { unsafe impl Sync for Snatchable {} +struct LockTrace { + purpose: &'static str, + caller: &'static Location<'static>, + backtrace: Backtrace, +} + +impl std::fmt::Display for LockTrace { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "a {} lock at {}\n{}", + self.purpose, self.caller, self.backtrace + ) + } +} + +#[cfg(debug_assertions)] +impl LockTrace { + #[track_caller] + fn enter(purpose: &'static str) { + let new = LockTrace { + purpose, + caller: Location::caller(), + backtrace: Backtrace::capture(), + }; + + if let Some(prev) = SNATCH_LOCK_TRACE.take() { + let current = thread::current(); + let name = current.name().unwrap_or(""); + panic!( + "thread '{name}' attempted to acquire a snatch lock recursively.\n\ + - Currently trying to acquire {new}\n\ + - Previously acquired {prev}", + ); + } else { + SNATCH_LOCK_TRACE.set(Some(new)); + } + } + + fn exit() { + SNATCH_LOCK_TRACE.take(); + } +} + +#[cfg(not(debug_assertions))] +impl LockTrace { + fn enter(purpose: &'static str) {} + fn exit() {} +} + thread_local! { - static READ_LOCK_LOCATION: Cell, Backtrace)>> = const { Cell::new(None) }; + static SNATCH_LOCK_TRACE: Cell> = const { Cell::new(None) }; } /// A Device-global lock for all snatchable data. @@ -78,31 +130,16 @@ impl SnatchLock { /// right SnatchLock (the one associated to the same device). This method is unsafe /// to force force sers to think twice about creating a SnatchLock. The only place this /// method should be called is when creating the device. - pub unsafe fn new() -> Self { + pub unsafe fn new(rank: rank::LockRank) -> Self { SnatchLock { - lock: RwLock::new(()), + lock: RwLock::new(rank, ()), } } /// Request read access to snatchable resources. #[track_caller] pub fn read(&self) -> SnatchGuard { - if cfg!(debug_assertions) { - let caller = Location::caller(); - let backtrace = Backtrace::capture(); - if let Some((prev, bt)) = READ_LOCK_LOCATION.take() { - let current = thread::current(); - let name = current.name().unwrap_or(""); - panic!( - "thread '{name}' attempted to acquire a snatch read lock recursively.\n - - {prev}\n{bt}\n - - {caller}\n{backtrace}" - ); - } else { - READ_LOCK_LOCATION.set(Some((caller, backtrace))); - } - } - + LockTrace::enter("read"); SnatchGuard(self.lock.read()) } @@ -111,14 +148,21 @@ impl SnatchLock { /// This should only be called when a resource needs to be snatched. This has /// a high risk of causing lock contention if called concurrently with other /// wgpu work. + #[track_caller] pub fn write(&self) -> ExclusiveSnatchGuard { + LockTrace::enter("write"); ExclusiveSnatchGuard(self.lock.write()) } } impl Drop for SnatchGuard<'_> { fn drop(&mut self) { - #[cfg(debug_assertions)] - READ_LOCK_LOCATION.take(); + LockTrace::exit(); + } +} + +impl Drop for ExclusiveSnatchGuard<'_> { + fn drop(&mut self) { + LockTrace::exit(); } } diff --git a/third_party/rust/wgpu-core/src/storage.rs b/third_party/rust/wgpu-core/src/storage.rs index 554ced8b7d..03874b8104 100644 --- a/third_party/rust/wgpu-core/src/storage.rs +++ b/third_party/rust/wgpu-core/src/storage.rs @@ -29,11 +29,14 @@ pub(crate) struct InvalidId; /// A table of `T` values indexed by the id type `I`. /// +/// `Storage` implements [`std::ops::Index`], accepting `Id` values as +/// indices. +/// /// The table is represented as a vector indexed by the ids' index /// values, so you should use an id allocator like `IdentityManager` /// that keeps the index values dense and close to zero. #[derive(Debug)] -pub struct Storage +pub(crate) struct Storage where T: Resource, { diff --git a/third_party/rust/wgpu-core/src/track/buffer.rs b/third_party/rust/wgpu-core/src/track/buffer.rs index 6cf1fdda6f..9a52a53253 100644 --- a/third_party/rust/wgpu-core/src/track/buffer.rs +++ b/third_party/rust/wgpu-core/src/track/buffer.rs @@ -11,6 +11,7 @@ use super::{PendingTransition, ResourceTracker, TrackerIndex}; use crate::{ hal_api::HalApi, id::BufferId, + lock::{rank, Mutex}, resource::{Buffer, Resource}, snatch::SnatchGuard, storage::Storage, @@ -20,7 +21,6 @@ use crate::{ }, }; use hal::{BufferBarrier, BufferUses}; -use parking_lot::Mutex; use wgt::{strict_assert, strict_assert_eq}; impl ResourceUses for BufferUses { @@ -51,7 +51,7 @@ pub(crate) struct BufferBindGroupState { impl BufferBindGroupState { pub fn new() -> Self { Self { - buffers: Mutex::new(Vec::new()), + buffers: Mutex::new(rank::BUFFER_BIND_GROUP_STATE_BUFFERS, Vec::new()), _phantom: PhantomData, } @@ -245,6 +245,22 @@ impl BufferUsageScope { .get(id) .map_err(|_| UsageConflict::BufferInvalid { id })?; + self.insert_merge_single(buffer.clone(), new_state) + .map(|_| buffer) + } + + /// Merge a single state into the UsageScope, using an already resolved buffer. + /// + /// If the resulting state is invalid, returns a usage + /// conflict with the details of the invalid state. + /// + /// If the ID is higher than the length of internal vectors, + /// the vectors will be extended. A call to set_size is not needed. + pub fn insert_merge_single( + &mut self, + buffer: Arc>, + new_state: BufferUses, + ) -> Result<(), UsageConflict> { let index = buffer.info.tracker_index().as_usize(); self.allow_index(index); @@ -260,12 +276,12 @@ impl BufferUsageScope { index, BufferStateProvider::Direct { state: new_state }, ResourceMetadataProvider::Direct { - resource: Cow::Owned(buffer.clone()), + resource: Cow::Owned(buffer), }, )?; } - Ok(buffer) + Ok(()) } } diff --git a/third_party/rust/wgpu-core/src/track/metadata.rs b/third_party/rust/wgpu-core/src/track/metadata.rs index 3e71e0e084..d6e8d6f906 100644 --- a/third_party/rust/wgpu-core/src/track/metadata.rs +++ b/third_party/rust/wgpu-core/src/track/metadata.rs @@ -87,16 +87,18 @@ impl ResourceMetadata { /// Add the resource with the given index, epoch, and reference count to the /// set. /// + /// Returns a reference to the newly inserted resource. + /// (This allows avoiding a clone/reference count increase in many cases.) + /// /// # Safety /// /// The given `index` must be in bounds for this `ResourceMetadata`'s /// existing tables. See `tracker_assert_in_bounds`. #[inline(always)] - pub(super) unsafe fn insert(&mut self, index: usize, resource: Arc) { + pub(super) unsafe fn insert(&mut self, index: usize, resource: Arc) -> &Arc { self.owned.set(index, true); - unsafe { - *self.resources.get_unchecked_mut(index) = Some(resource); - } + let resource_dst = unsafe { self.resources.get_unchecked_mut(index) }; + resource_dst.insert(resource) } /// Get the resource with the given index. diff --git a/third_party/rust/wgpu-core/src/track/mod.rs b/third_party/rust/wgpu-core/src/track/mod.rs index 374dfe7493..cc20b2a01c 100644 --- a/third_party/rust/wgpu-core/src/track/mod.rs +++ b/third_party/rust/wgpu-core/src/track/mod.rs @@ -102,10 +102,14 @@ mod stateless; mod texture; use crate::{ - binding_model, command, conv, hal_api::HalApi, id, pipeline, resource, snatch::SnatchGuard, + binding_model, command, conv, + hal_api::HalApi, + id, + lock::{rank, Mutex, RwLock}, + pipeline, resource, + snatch::SnatchGuard, }; -use parking_lot::{Mutex, RwLock}; use std::{fmt, ops, sync::Arc}; use thiserror::Error; @@ -136,7 +140,8 @@ impl TrackerIndex { /// of a certain type. This index is separate from the resource ID for various reasons: /// - There can be multiple resource IDs pointing the the same resource. /// - IDs of dead handles can be recycled while resources are internally held alive (and tracked). -/// - The plan is to remove IDs in the long run (https://github.com/gfx-rs/wgpu/issues/5121). +/// - The plan is to remove IDs in the long run +/// ([#5121](https://github.com/gfx-rs/wgpu/issues/5121)). /// In order to produce these tracker indices, there is a shared TrackerIndexAllocator /// per resource type. Indices have the same lifetime as the internal resource they /// are associated to (alloc happens when creating the resource and free is called when @@ -190,7 +195,10 @@ pub(crate) struct SharedTrackerIndexAllocator { impl SharedTrackerIndexAllocator { pub fn new() -> Self { SharedTrackerIndexAllocator { - inner: Mutex::new(TrackerIndexAllocator::new()), + inner: Mutex::new( + rank::SHARED_TRACKER_INDEX_ALLOCATOR_INNER, + TrackerIndexAllocator::new(), + ), } } @@ -480,11 +488,26 @@ impl RenderBundleScope { /// Create the render bundle scope and pull the maximum IDs from the hubs. pub fn new() -> Self { Self { - buffers: RwLock::new(BufferUsageScope::default()), - textures: RwLock::new(TextureUsageScope::default()), - bind_groups: RwLock::new(StatelessTracker::new()), - render_pipelines: RwLock::new(StatelessTracker::new()), - query_sets: RwLock::new(StatelessTracker::new()), + buffers: RwLock::new( + rank::RENDER_BUNDLE_SCOPE_BUFFERS, + BufferUsageScope::default(), + ), + textures: RwLock::new( + rank::RENDER_BUNDLE_SCOPE_TEXTURES, + TextureUsageScope::default(), + ), + bind_groups: RwLock::new( + rank::RENDER_BUNDLE_SCOPE_BIND_GROUPS, + StatelessTracker::new(), + ), + render_pipelines: RwLock::new( + rank::RENDER_BUNDLE_SCOPE_RENDER_PIPELINES, + StatelessTracker::new(), + ), + query_sets: RwLock::new( + rank::RENDER_BUNDLE_SCOPE_QUERY_SETS, + StatelessTracker::new(), + ), } } @@ -639,8 +662,8 @@ impl Tracker { /// /// If a transition is needed to get the resources into the needed /// state, those transitions are stored within the tracker. A - /// subsequent call to [`BufferTracker::drain`] or - /// [`TextureTracker::drain`] is needed to get those transitions. + /// subsequent call to [`BufferTracker::drain_transitions`] or + /// [`TextureTracker::drain_transitions`] is needed to get those transitions. /// /// This is a really funky method used by Compute Passes to generate /// barriers after a call to dispatch without needing to iterate diff --git a/third_party/rust/wgpu-core/src/track/stateless.rs b/third_party/rust/wgpu-core/src/track/stateless.rs index 00225f2305..25ffc027ee 100644 --- a/third_party/rust/wgpu-core/src/track/stateless.rs +++ b/third_party/rust/wgpu-core/src/track/stateless.rs @@ -6,9 +6,14 @@ use std::sync::Arc; -use parking_lot::Mutex; - -use crate::{id::Id, resource::Resource, resource_log, storage::Storage, track::ResourceMetadata}; +use crate::{ + id::Id, + lock::{rank, Mutex}, + resource::Resource, + resource_log, + storage::Storage, + track::ResourceMetadata, +}; use super::{ResourceTracker, TrackerIndex}; @@ -24,7 +29,7 @@ pub(crate) struct StatelessBindGroupSate { impl StatelessBindGroupSate { pub fn new() -> Self { Self { - resources: Mutex::new(Vec::new()), + resources: Mutex::new(rank::STATELESS_BIND_GROUP_STATE_RESOURCES, Vec::new()), } } @@ -153,16 +158,17 @@ impl StatelessTracker { /// /// If the ID is higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. - pub fn insert_single(&mut self, resource: Arc) { + /// + /// Returns a reference to the newly inserted resource. + /// (This allows avoiding a clone/reference count increase in many cases.) + pub fn insert_single(&mut self, resource: Arc) -> &Arc { let index = resource.as_info().tracker_index().as_usize(); self.allow_index(index); self.tracker_assert_in_bounds(index); - unsafe { - self.metadata.insert(index, resource); - } + unsafe { self.metadata.insert(index, resource) } } /// Adds the given resource to the tracker. diff --git a/third_party/rust/wgpu-core/src/track/texture.rs b/third_party/rust/wgpu-core/src/track/texture.rs index 3cf95ff38a..51ed72a18d 100644 --- a/third_party/rust/wgpu-core/src/track/texture.rs +++ b/third_party/rust/wgpu-core/src/track/texture.rs @@ -24,6 +24,7 @@ use super::{ }; use crate::{ hal_api::HalApi, + lock::{rank, Mutex}, resource::{Resource, Texture, TextureInner}, snatch::SnatchGuard, track::{ @@ -36,7 +37,6 @@ use hal::TextureUses; use arrayvec::ArrayVec; use naga::FastHashMap; -use parking_lot::Mutex; use wgt::{strict_assert, strict_assert_eq}; use std::{borrow::Cow, iter, marker::PhantomData, ops::Range, sync::Arc, vec::Drain}; @@ -164,7 +164,7 @@ pub(crate) struct TextureBindGroupState { impl TextureBindGroupState { pub fn new() -> Self { Self { - textures: Mutex::new(Vec::new()), + textures: Mutex::new(rank::TEXTURE_BIND_GROUP_STATE_TEXTURES, Vec::new()), } } diff --git a/third_party/rust/wgpu-core/src/validation.rs b/third_party/rust/wgpu-core/src/validation.rs index e4846c4000..d360ee9621 100644 --- a/third_party/rust/wgpu-core/src/validation.rs +++ b/third_party/rust/wgpu-core/src/validation.rs @@ -655,7 +655,8 @@ impl NumericType { | Vf::Unorm16x4 | Vf::Snorm16x4 | Vf::Float16x4 - | Vf::Float32x4 => (NumericDimension::Vector(Vs::Quad), Scalar::F32), + | Vf::Float32x4 + | Vf::Unorm10_10_10_2 => (NumericDimension::Vector(Vs::Quad), Scalar::F32), Vf::Float64 => (NumericDimension::Scalar, Scalar::F64), Vf::Float64x2 => (NumericDimension::Vector(Vs::Bi), Scalar::F64), Vf::Float64x3 => (NumericDimension::Vector(Vs::Tri), Scalar::F64), diff --git a/third_party/rust/wgpu-hal/.cargo-checksum.json b/third_party/rust/wgpu-hal/.cargo-checksum.json index 2cba88cfdf..265725f165 100644 --- a/third_party/rust/wgpu-hal/.cargo-checksum.json +++ b/third_party/rust/wgpu-hal/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"332863a1b354637fc62ff5729e7c2f5089fa65db05d330ec268a7aab04bb3d42","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","README.md":"099ee611a911dc19330a61bffcde13663929a51b25ac528ee33ea796d695491e","build.rs":"c80bdc0152a00471eec6ed0dd0f7d55d0b975498a00ba05e94100c84ad639a49","examples/halmark/main.rs":"4604737f714943383c57feac2b8468ecf15e9e60c54a5303455e9953ec5c79fb","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"095113a1ba0851652a77aabfc8fa6ea7edcc2d09e91fd1e5009ead87d5998ea9","examples/ray-traced-triangle/main.rs":"955c2b8700c3b2daf14e9ef963ff499ed185b6f349dbc63caa422b2cf4942a1f","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"760cd4eaa79b530368a30140b96bf73ac4fbdb4025eb95f0bed581638c8bb1cb","src/auxil/dxgi/exception.rs":"f0cfb5a0adcdc3b6db909601fee51ad51368f5da269bcd46e4dbea45a3bec4b1","src/auxil/dxgi/factory.rs":"5f861fbfe2f4cce08722a95283549b8f62b96f24a306d080d9f1730ae53501d8","src/auxil/dxgi/mod.rs":"a202564d9ac97530b16a234b87d180cd345aae705e082a9b1177dcde813645f9","src/auxil/dxgi/result.rs":"79fe5aa17a2b21a7f06b1b604200c3c3e73fca31e8193aab80b5b15e7e9818a0","src/auxil/dxgi/time.rs":"b6f966b250e9424d5d7e4065f2108cba87197c1e30baae6d87083055d1bc5a4b","src/auxil/mod.rs":"720ef2aae258733322a3274fd858f91effb8951dabaf7bbfd8a9a0be2d2dba97","src/auxil/renderdoc.rs":"c2f849f70f576b0c9b0d32dd155b6a6353f74dff59cbeeaa994a12789d047c0f","src/dx12/adapter.rs":"2a90a4222702e50fabfc64339ac2aa667e1ee2d2bf801c3e2e59a91e261c7a04","src/dx12/command.rs":"e0675560784214a18e078062cbd0965c21a35c99eecf0e697d1badb9c692db35","src/dx12/conv.rs":"94d35f117ae003b07049f3a0bc6c45a0ffda9fb8053233d39c173cfb1b644403","src/dx12/descriptor.rs":"e06eb08bee4c805fa76b6ab791893b5b563ee60de9c8f8d8e0e21ab97ade5664","src/dx12/device.rs":"6a38dabd4db9d7ca79bfcfbeb3483320ad88f2db6e93a7210051bbf81acb1bbd","src/dx12/instance.rs":"030a86ac810d5ebf151328bbc06b9b5a89788721aa963cb4e0f3ff943b2c8633","src/dx12/mod.rs":"87e7012a113554c976abdbecd10b2fe6aab3ba695c88dc77d6beb3880d96ba54","src/dx12/shader_compilation.rs":"5087adb8576e2d7751619dfdf8b37c573bb4e494290c594077ca3208cce1e746","src/dx12/suballocation.rs":"6939fc36223a15cc070c744d0418f9ac6fa2829d794af17cdea7c61eb5f8d2c0","src/dx12/types.rs":"9573736baaa0ef607367c3b72144556d24faf677a26bb8df49a4372a1348e06b","src/dx12/view.rs":"792772e9c87840dcd045b7381a03162eb4a501492a95ca586e77e81aed621c67","src/empty.rs":"0849e0b7210d33145b3fb1368ed08b13fbc2144b1ccc0a1af913896e916bbe46","src/gles/adapter.rs":"22fe404177d4abb077f35a5be54295f81eacb021d448ad01aa96450ade8b089a","src/gles/command.rs":"788505168ae1af312781c86d31d5bc289fcc4e2b3cb047fb41deb62542db1a95","src/gles/conv.rs":"5d15d3a33032d32ff99bc338fba0689fa54c76d0714e335fe48523d841df386f","src/gles/device.rs":"e126042653b0651a12684504e19c05db3fe333bde3ac408063675eef6c27754a","src/gles/egl.rs":"72feefbcd399e686b5c210a67151ef040e45e123ad371539274d1d52b3dd162d","src/gles/emscripten.rs":"19bb73a9d140645f3f32cd48b002151711a9b8456e213eab5f3a2be79239e147","src/gles/mod.rs":"b8999f76ad45e07312b291457100f12699ba6a2635c1f1913b0648e9a9394015","src/gles/queue.rs":"7f62e9c1cb670f66ac8bb0d62cd531b9c11b2a29f8ed28736c40e21071fbe25d","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"000ed39eae4a6442ca16bdca68e1e61459e6815a5db8eeec53e0ee0f5f14ae66","src/gles/wgl.rs":"78bfe5bcdacfde8d8df0d6f3987048f8ad8a2c2c93df6d607cf5a16795d3bb8e","src/lib.rs":"b80b7d14f524f25875b1d7e7ee67cd6057bbe9944ea92b59d5d4d08d7b17580d","src/metal/adapter.rs":"e473a1857817030ee5c5358e8387daff66d1aca1f5133224cc844ea4b17d3e49","src/metal/command.rs":"61640f2cb7269f44487df2d911771fbe1f78484d44a5363a6ddfce7d77143b02","src/metal/conv.rs":"0bce6a8d0ccef16783475803d70d35e03ab7938c19374e22c9d253abe1f8b111","src/metal/device.rs":"1343ad60a423b81649a6eaad69de743a2247234a75ec48c0698973af67592e48","src/metal/mod.rs":"3e3f69ac864cb6a96c5b9df551a934bbc4bf08503430b9507561eef973daf57f","src/metal/surface.rs":"397dab6726eead96f0be9ecb6686874e691079da94c072921a6422e9b1284fb5","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/vulkan/adapter.rs":"ac4525114d37d6ffa31f2c240b2bb9e1d97d19cd6d400598c2a1153d9144bd0f","src/vulkan/command.rs":"82060e8040eea27b717ec676525139a9c7238074ad5ce6902f5174ac5c7aa048","src/vulkan/conv.rs":"7e6266e3a0b7d0b8d5d51362a0386a84bc047350eeac663b6352a94d5e5c0a87","src/vulkan/device.rs":"24abe83a2cbe8fa3377d0fb8d64fcaac3a3e6b0521ec28143fa8b7dee0c1afee","src/vulkan/instance.rs":"60742c3c1feee63eca0953165dae57c86b0d58e496ad374743ff83ae50a4e8f1","src/vulkan/mod.rs":"dfd8e079b7b783de3dfdfbf2349d7283c1b9108242d1ffbb4e072376901c7bd1"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"8c0a58e1b89cd82b644379eaaa71825499293fe0667192812e1cf41ecec6fd42","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","README.md":"b432248c4d5c85925ea2d741dc53069111619631a009994dbeaef980993d23a2","build.rs":"c80bdc0152a00471eec6ed0dd0f7d55d0b975498a00ba05e94100c84ad639a49","examples/halmark/main.rs":"c5debf7ff46b76fcdd4663c4cbd365d0015ac96c200488f6de34f914ba47d6e3","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"095113a1ba0851652a77aabfc8fa6ea7edcc2d09e91fd1e5009ead87d5998ea9","examples/ray-traced-triangle/main.rs":"5679fb4794966d9132b8d15471526f6adce58378bd319ae3f345494d2a216ddc","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"134a1459339537a462448d5e1eb117931f450c6724bd9cb8388f39870c466eb3","src/auxil/dxgi/exception.rs":"f0cfb5a0adcdc3b6db909601fee51ad51368f5da269bcd46e4dbea45a3bec4b1","src/auxil/dxgi/factory.rs":"5f861fbfe2f4cce08722a95283549b8f62b96f24a306d080d9f1730ae53501d8","src/auxil/dxgi/mod.rs":"a202564d9ac97530b16a234b87d180cd345aae705e082a9b1177dcde813645f9","src/auxil/dxgi/result.rs":"79fe5aa17a2b21a7f06b1b604200c3c3e73fca31e8193aab80b5b15e7e9818a0","src/auxil/dxgi/time.rs":"b6f966b250e9424d5d7e4065f2108cba87197c1e30baae6d87083055d1bc5a4b","src/auxil/mod.rs":"720ef2aae258733322a3274fd858f91effb8951dabaf7bbfd8a9a0be2d2dba97","src/auxil/renderdoc.rs":"c2f849f70f576b0c9b0d32dd155b6a6353f74dff59cbeeaa994a12789d047c0f","src/dx12/adapter.rs":"757fe846d1114bcd2343b8de405869377e1b3930e7e70a4908f07dc5284e0fca","src/dx12/command.rs":"e0675560784214a18e078062cbd0965c21a35c99eecf0e697d1badb9c692db35","src/dx12/conv.rs":"8efa0ecfaaef2d0aaca4a17a4ed293d4921b82383cbce90bec1b2fef41cb3462","src/dx12/descriptor.rs":"e06eb08bee4c805fa76b6ab791893b5b563ee60de9c8f8d8e0e21ab97ade5664","src/dx12/device.rs":"30e1d9ad16a077fdcb8091eed7fe90ba8c51edb905b2908dcdb3c85113cb88a3","src/dx12/instance.rs":"030a86ac810d5ebf151328bbc06b9b5a89788721aa963cb4e0f3ff943b2c8633","src/dx12/mod.rs":"edaf24893edbd5390460a618e8db9e5f767d319efaa834b11f0c2cd1373b41f4","src/dx12/shader_compilation.rs":"5087adb8576e2d7751619dfdf8b37c573bb4e494290c594077ca3208cce1e746","src/dx12/suballocation.rs":"6939fc36223a15cc070c744d0418f9ac6fa2829d794af17cdea7c61eb5f8d2c0","src/dx12/types.rs":"b5140522eea491b6943ee9da235cdbfbd611f830d2719fd8812dfdd494ed16e2","src/dx12/view.rs":"792772e9c87840dcd045b7381a03162eb4a501492a95ca586e77e81aed621c67","src/empty.rs":"0849e0b7210d33145b3fb1368ed08b13fbc2144b1ccc0a1af913896e916bbe46","src/gles/adapter.rs":"90f0402e2b62b9311d247f3eba2ff956ef38e3799ca08355721730fb9a25e6d3","src/gles/command.rs":"788505168ae1af312781c86d31d5bc289fcc4e2b3cb047fb41deb62542db1a95","src/gles/conv.rs":"2e99a39fbef7a5bb8f2a24779bf5387601ba336de4cac9ff2bdac5b93f48a1d7","src/gles/device.rs":"64a8f202f123a4f2238e295023803724cd3095f2932462cc087a2d2212f0df3d","src/gles/egl.rs":"fed5b9c74ada548f90afcf138985514eadf7cc87859b013a3fa33cc7f72fb201","src/gles/emscripten.rs":"19bb73a9d140645f3f32cd48b002151711a9b8456e213eab5f3a2be79239e147","src/gles/mod.rs":"a54401494e4279bd56867fc621bfe3a8252fe82409cdc1594e7b22ee09f68fc0","src/gles/queue.rs":"1d4ea44a8e2ce47f9266260f1f384f02f870473c0411b77c5bab6794ee8484f5","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"000ed39eae4a6442ca16bdca68e1e61459e6815a5db8eeec53e0ee0f5f14ae66","src/gles/wgl.rs":"59cd28ba85c6c3cbcbd82fd0e4225303a5f98e6a41b839400f9cce3a1b267af8","src/lib.rs":"88c8e93b1bea9eb31d2632f519c82e1c15b479e29b3700914a033efb59295634","src/metal/adapter.rs":"87636eaedbb18108c592aebf553ba3d84d052be567aa9306457b8cd9a2c6b0e7","src/metal/command.rs":"61640f2cb7269f44487df2d911771fbe1f78484d44a5363a6ddfce7d77143b02","src/metal/conv.rs":"a34a44e6affb594f3285f8d585b0fb33132aa7dc6a612f7c1aecaa400fe43265","src/metal/device.rs":"81ad3f5e4e5967cdb31a5e0f5e9404324b121408409b1422263bd9b0b793dd26","src/metal/mod.rs":"295223d5a06d9752d6911ec25ceb79c17dd93ced84c2c8a052957e6568e2e749","src/metal/surface.rs":"397dab6726eead96f0be9ecb6686874e691079da94c072921a6422e9b1284fb5","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/vulkan/adapter.rs":"3c82f3294c330c9b3b3b554ea7ef8601459c4f4d28a34700690230e3572c1d44","src/vulkan/command.rs":"a79df7f455c4061ab404c319e6602e6c1a3567443b50c20ddba6150fbdcc8826","src/vulkan/conv.rs":"47b8d7822703a5bd2b8c80118ee6ac1cd0b985758e2f929317fe4c42ce9a9bd9","src/vulkan/device.rs":"fefa6ebebb2d578323f01420fecd85f36e584efdc8a88a0c89ffc66c9d5524f9","src/vulkan/instance.rs":"60742c3c1feee63eca0953165dae57c86b0d58e496ad374743ff83ae50a4e8f1","src/vulkan/mod.rs":"d1aefbd87a166bd2103b418f096ba777d9bc7d19eb2d1363dd2f351639fc732a"},"package":null} \ No newline at end of file diff --git a/third_party/rust/wgpu-hal/Cargo.toml b/third_party/rust/wgpu-hal/Cargo.toml index f601949231..dc9fc7e827 100644 --- a/third_party/rust/wgpu-hal/Cargo.toml +++ b/third_party/rust/wgpu-hal/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.74" name = "wgpu-hal" -version = "0.19.0" +version = "0.20.0" authors = ["gfx-rs developers"] description = "WebGPU hardware abstraction layer" homepage = "https://wgpu.rs/" @@ -63,26 +63,25 @@ version = "0.13.1" optional = true [dependencies.naga] -version = "0.19.0" +version = "0.20.0" path = "../naga" -features = ["clone"] [dependencies.profiling] version = "1" default-features = false [dependencies.wgt] -version = "0.19.0" +version = "0.20.0" path = "../wgpu-types" package = "wgpu-types" [dev-dependencies] cfg-if = "1" env_logger = "0.11" -glam = "0.25.0" +glam = "0.27.0" [dev-dependencies.naga] -version = "0.19.0" +version = "0.20.0" path = "../naga" features = ["wgsl-in"] @@ -156,13 +155,15 @@ features = [ [target."cfg(any(target_os=\"macos\", target_os=\"ios\"))".dependencies] core-graphics-types = "0.1" -metal = "0.27.0" objc = "0.2.5" [target."cfg(any(target_os=\"macos\", target_os=\"ios\"))".dependencies.block] version = "0.1" optional = true +[target."cfg(any(target_os=\"macos\", target_os=\"ios\"))".dependencies.metal] +version = "0.28.0" + [target."cfg(not(target_arch = \"wasm32\"))".dependencies.ash] version = "0.37.3" optional = true @@ -172,7 +173,7 @@ version = "0.6" optional = true [target."cfg(not(target_arch = \"wasm32\"))".dependencies.gpu-descriptor] -version = "0.2" +version = "0.3" optional = true [target."cfg(not(target_arch = \"wasm32\"))".dependencies.khronos-egl] @@ -223,7 +224,7 @@ version = "0.5" optional = true [target."cfg(windows)".dependencies.d3d12] -version = "0.19.0" +version = "0.20.0" path = "../d3d12/" features = ["libloading"] optional = true diff --git a/third_party/rust/wgpu-hal/README.md b/third_party/rust/wgpu-hal/README.md index 588baa3cf5..bb5556b3d2 100644 --- a/third_party/rust/wgpu-hal/README.md +++ b/third_party/rust/wgpu-hal/README.md @@ -1,23 +1,120 @@ -*wgpu-hal* is an explicit low-level GPU abstraction powering *wgpu-core*. -It's a spiritual successor to [gfx-hal](https://github.com/gfx-rs/gfx), -but with reduced scope, and oriented towards WebGPU implementation goals. +# `wgpu_hal`: a cross-platform unsafe graphics abstraction -It has no overhead for validation or tracking, and the API translation overhead is kept to the bare minimum by the design of WebGPU. -This API can be used for resource-demanding applications and engines. +This crate defines a set of traits abstracting over modern graphics APIs, +with implementations ("backends") for Vulkan, Metal, Direct3D, and GL. -# Usage notes +`wgpu_hal` is a spiritual successor to +[gfx-hal](https://github.com/gfx-rs/gfx), but with reduced scope, and +oriented towards WebGPU implementation goals. It has no overhead for +validation or tracking, and the API translation overhead is kept to the bare +minimum by the design of WebGPU. This API can be used for resource-demanding +applications and engines. -All of the API is `unsafe`. Documenting the exact safety requirements for the -state and function arguments is desired, but will likely be incomplete while the library is in early development. +The `wgpu_hal` crate's main design choices: -The returned errors are only for cases that the user can't anticipate, -such as running out-of-memory, or losing the device. -For the counter-example, there is no error for mapping a buffer that's not mappable. -As the buffer creator, the user should already know if they can map it. +- Our traits are meant to be *portable*: proper use + should get equivalent results regardless of the backend. -The API accepts iterators in order to avoid forcing the user to store data in particular containers. The implementation doesn't guarantee that any of the iterators are drained, unless stated otherwise by the function documentation. -For this reason, we recommend that iterators don't do any mutating work. +- Our traits' contracts are *unsafe*: implementations perform minimal + validation, if any, and incorrect use will often cause undefined behavior. + This allows us to minimize the overhead we impose over the underlying + graphics system. If you need safety, the [`wgpu-core`] crate provides a + safe API for driving `wgpu_hal`, implementing all necessary validation, + resource state tracking, and so on. (Note that `wgpu-core` is designed for + use via FFI; the [`wgpu`] crate provides more idiomatic Rust bindings for + `wgpu-core`.) Or, you can do your own validation. -# Debugging +- In the same vein, returned errors *only cover cases the user can't + anticipate*, like running out of memory or losing the device. Any errors + that the user could reasonably anticipate are their responsibility to + avoid. For example, `wgpu_hal` returns no error for mapping a buffer that's + not mappable: as the buffer creator, the user should already know if they + can map it. + +- We use *static dispatch*. The traits are not + generally object-safe. You must select a specific backend type + like [`vulkan::Api`] or [`metal::Api`], and then use that + according to the main traits, or call backend-specific methods. + +- We use *idiomatic Rust parameter passing*, + taking objects by reference, returning them by value, and so on, + unlike `wgpu-core`, which refers to objects by ID. + +- We map buffer contents *persistently*. This means that the buffer + can remain mapped on the CPU while the GPU reads or writes to it. + You must explicitly indicate when data might need to be + transferred between CPU and GPU, if `wgpu_hal` indicates that the + mapping is not coherent (that is, automatically synchronized + between the two devices). + +- You must record *explicit barriers* between different usages of a + resource. For example, if a buffer is written to by a compute + shader, and then used as and index buffer to a draw call, you + must use [`CommandEncoder::transition_buffers`] between those two + operations. + +- Pipeline layouts are *explicitly specified* when setting bind + group. Incompatible layouts disturb groups bound at higher indices. + +- The API *accepts collections as iterators*, to avoid forcing the user to + store data in particular containers. The implementation doesn't guarantee + that any of the iterators are drained, unless stated otherwise by the + function documentation. For this reason, we recommend that iterators don't + do any mutating work. + +Unfortunately, `wgpu_hal`'s safety requirements are not fully documented. +Ideally, all trait methods would have doc comments setting out the +requirements users must meet to ensure correct and portable behavior. If you +are aware of a specific requirement that a backend imposes that is not +ensured by the traits' documented rules, please file an issue. Or, if you are +a capable technical writer, please file a pull request! + +[`wgpu-core`]: https://crates.io/crates/wgpu-core +[`wgpu`]: https://crates.io/crates/wgpu +[`vulkan::Api`]: vulkan/struct.Api.html +[`metal::Api`]: metal/struct.Api.html + +## Primary backends + +The `wgpu_hal` crate has full-featured backends implemented on the following +platform graphics APIs: + +- Vulkan, available on Linux, Android, and Windows, using the [`ash`] crate's + Vulkan bindings. It's also available on macOS, if you install [MoltenVK]. + +- Metal on macOS, using the [`metal`] crate's bindings. + +- Direct3D 12 on Windows, using the [`d3d12`] crate's bindings. + +[`ash`]: https://crates.io/crates/ash +[MoltenVK]: https://github.com/KhronosGroup/MoltenVK +[`metal`]: https://crates.io/crates/metal +[`d3d12`]: ahttps://crates.io/crates/d3d12 + +## Secondary backends + +The `wgpu_hal` crate has a partial implementation based on the following +platform graphics API: + +- The GL backend is available anywhere OpenGL, OpenGL ES, or WebGL are + available. See the [`gles`] module documentation for details. + +[`gles`]: gles/index.html + +You can see what capabilities an adapter is missing by checking the +[`DownlevelCapabilities`][tdc] in [`ExposedAdapter::capabilities`], available +from [`Instance::enumerate_adapters`]. + +The API is generally designed to fit the primary backends better than the +secondary backends, so the latter may impose more overhead. + +[tdc]: wgt::DownlevelCapabilities + +## Debugging + +Most of the information on the wiki [Debugging wgpu Applications][wiki-debug] +page still applies to this API, with the exception of API tracing/replay +functionality, which is only available in `wgpu-core`. + +[wiki-debug]: https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications -Most of the information in https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications still applies to this API, with an exception of API tracing/replay functionality, which is only available in *wgpu-core*. diff --git a/third_party/rust/wgpu-hal/examples/halmark/main.rs b/third_party/rust/wgpu-hal/examples/halmark/main.rs index c238f299e7..aef6919c8f 100644 --- a/third_party/rust/wgpu-hal/examples/halmark/main.rs +++ b/third_party/rust/wgpu-hal/examples/halmark/main.rs @@ -245,17 +245,22 @@ impl Example { .unwrap() }; + let constants = naga::back::PipelineConstants::default(); let pipeline_desc = hal::RenderPipelineDescriptor { label: None, layout: &pipeline_layout, vertex_stage: hal::ProgrammableStage { module: &shader, entry_point: "vs_main", + constants: &constants, + zero_initialize_workgroup_memory: true, }, vertex_buffers: &[], fragment_stage: Some(hal::ProgrammableStage { module: &shader, entry_point: "fs_main", + constants: &constants, + zero_initialize_workgroup_memory: true, }), primitive: wgt::PrimitiveState { topology: wgt::PrimitiveTopology::TriangleStrip, @@ -840,6 +845,7 @@ fn main() { } } ex.render(); + window.request_redraw(); } _ => { example.as_mut().unwrap().update(event); diff --git a/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs b/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs index c05feae820..3985cd60af 100644 --- a/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -371,6 +371,8 @@ impl Example { stage: hal::ProgrammableStage { module: &shader_module, entry_point: "main", + constants: &Default::default(), + zero_initialize_workgroup_memory: true, }, }) } diff --git a/third_party/rust/wgpu-hal/src/auxil/dxgi/conv.rs b/third_party/rust/wgpu-hal/src/auxil/dxgi/conv.rs index 6af4b77bb3..e5162362f7 100644 --- a/third_party/rust/wgpu-hal/src/auxil/dxgi/conv.rs +++ b/third_party/rust/wgpu-hal/src/auxil/dxgi/conv.rs @@ -261,6 +261,7 @@ pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT { Vf::Uint32x4 => DXGI_FORMAT_R32G32B32A32_UINT, Vf::Sint32x4 => DXGI_FORMAT_R32G32B32A32_SINT, Vf::Float32x4 => DXGI_FORMAT_R32G32B32A32_FLOAT, + Vf::Unorm10_10_10_2 => DXGI_FORMAT_R10G10B10A2_UNORM, Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(), } } diff --git a/third_party/rust/wgpu-hal/src/dx12/adapter.rs b/third_party/rust/wgpu-hal/src/dx12/adapter.rs index b417a88a6f..faf25cc852 100644 --- a/third_party/rust/wgpu-hal/src/dx12/adapter.rs +++ b/third_party/rust/wgpu-hal/src/dx12/adapter.rs @@ -115,18 +115,6 @@ impl super::Adapter { ) }); - let mut shader_model_support: d3d12_ty::D3D12_FEATURE_DATA_SHADER_MODEL = - d3d12_ty::D3D12_FEATURE_DATA_SHADER_MODEL { - HighestShaderModel: d3d12_ty::D3D_SHADER_MODEL_6_0, - }; - assert_eq!(0, unsafe { - device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_SHADER_MODEL, - &mut shader_model_support as *mut _ as *mut _, - mem::size_of::() as _, - ) - }); - let mut workarounds = super::Workarounds::default(); let info = wgt::AdapterInfo { @@ -181,6 +169,53 @@ impl super::Adapter { hr == 0 && features3.CastingFullyTypedFormatSupported != 0 }; + let shader_model = if dxc_container.is_none() { + naga::back::hlsl::ShaderModel::V5_1 + } else { + let mut versions = [ + crate::dx12::types::D3D_SHADER_MODEL_6_7, + crate::dx12::types::D3D_SHADER_MODEL_6_6, + crate::dx12::types::D3D_SHADER_MODEL_6_5, + crate::dx12::types::D3D_SHADER_MODEL_6_4, + crate::dx12::types::D3D_SHADER_MODEL_6_3, + crate::dx12::types::D3D_SHADER_MODEL_6_2, + crate::dx12::types::D3D_SHADER_MODEL_6_1, + crate::dx12::types::D3D_SHADER_MODEL_6_0, + crate::dx12::types::D3D_SHADER_MODEL_5_1, + ] + .iter(); + match loop { + if let Some(&sm) = versions.next() { + let mut sm = crate::dx12::types::D3D12_FEATURE_DATA_SHADER_MODEL { + HighestShaderModel: sm, + }; + if 0 == unsafe { + device.CheckFeatureSupport( + 7, // D3D12_FEATURE_SHADER_MODEL + &mut sm as *mut _ as *mut _, + mem::size_of::() + as _, + ) + } { + break sm.HighestShaderModel; + } + } else { + break crate::dx12::types::D3D_SHADER_MODEL_5_1; + } + } { + crate::dx12::types::D3D_SHADER_MODEL_5_1 => naga::back::hlsl::ShaderModel::V5_1, + crate::dx12::types::D3D_SHADER_MODEL_6_0 => naga::back::hlsl::ShaderModel::V6_0, + crate::dx12::types::D3D_SHADER_MODEL_6_1 => naga::back::hlsl::ShaderModel::V6_1, + crate::dx12::types::D3D_SHADER_MODEL_6_2 => naga::back::hlsl::ShaderModel::V6_2, + crate::dx12::types::D3D_SHADER_MODEL_6_3 => naga::back::hlsl::ShaderModel::V6_3, + crate::dx12::types::D3D_SHADER_MODEL_6_4 => naga::back::hlsl::ShaderModel::V6_4, + crate::dx12::types::D3D_SHADER_MODEL_6_5 => naga::back::hlsl::ShaderModel::V6_5, + crate::dx12::types::D3D_SHADER_MODEL_6_6 => naga::back::hlsl::ShaderModel::V6_6, + crate::dx12::types::D3D_SHADER_MODEL_6_7 => naga::back::hlsl::ShaderModel::V6_7, + _ => unreachable!(), + } + }; + let private_caps = super::PrivateCapabilities { instance_flags, heterogeneous_resource_heaps: options.ResourceHeapTier @@ -196,6 +231,7 @@ impl super::Adapter { casting_fully_typed_format_supported, // See https://github.com/gfx-rs/wgpu/issues/3552 suballocation_supported: !info.name.contains("Iris(R) Xe"), + shader_model, }; // Theoretically vram limited, but in practice 2^20 is the limit @@ -273,7 +309,7 @@ impl super::Adapter { wgt::Features::TEXTURE_BINDING_ARRAY | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING | wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, - shader_model_support.HighestShaderModel >= d3d12_ty::D3D_SHADER_MODEL_5_1, + shader_model >= naga::back::hlsl::ShaderModel::V5_1, ); let bgra8unorm_storage_supported = { @@ -295,21 +331,28 @@ impl super::Adapter { bgra8unorm_storage_supported, ); - // we must be using DXC because uint64_t was added with Shader Model 6 - // and FXC only supports up to 5.1 - let int64_shader_ops_supported = dxc_container.is_some() && { - let mut features1: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS1 = - unsafe { mem::zeroed() }; - let hr = unsafe { - device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS1, - &mut features1 as *mut _ as *mut _, - mem::size_of::() as _, - ) - }; - hr == 0 && features1.Int64ShaderOps != 0 + let mut features1: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS1 = unsafe { mem::zeroed() }; + let hr = unsafe { + device.CheckFeatureSupport( + d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS1, + &mut features1 as *mut _ as *mut _, + mem::size_of::() as _, + ) }; - features.set(wgt::Features::SHADER_INT64, int64_shader_ops_supported); + + features.set( + wgt::Features::SHADER_INT64, + shader_model >= naga::back::hlsl::ShaderModel::V6_0 + && hr == 0 + && features1.Int64ShaderOps != 0, + ); + + features.set( + wgt::Features::SUBGROUP, + shader_model >= naga::back::hlsl::ShaderModel::V6_0 + && hr == 0 + && features1.WaveOps != 0, + ); // float32-filterable should always be available on d3d12 features.set(wgt::Features::FLOAT32_FILTERABLE, true); @@ -377,6 +420,8 @@ impl super::Adapter { .min(crate::MAX_VERTEX_BUFFERS as u32), max_vertex_attributes: d3d12_ty::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT, max_vertex_buffer_array_stride: d3d12_ty::D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES, + min_subgroup_size: 4, // Not using `features1.WaveLaneCountMin` as it is unreliable + max_subgroup_size: 128, // The push constants are part of the root signature which // has a limit of 64 DWORDS (256 bytes), but other resources // also share the root signature: diff --git a/third_party/rust/wgpu-hal/src/dx12/conv.rs b/third_party/rust/wgpu-hal/src/dx12/conv.rs index 2b6c1d959e..b09ea76080 100644 --- a/third_party/rust/wgpu-hal/src/dx12/conv.rs +++ b/third_party/rust/wgpu-hal/src/dx12/conv.rs @@ -224,7 +224,7 @@ pub fn map_polygon_mode(mode: wgt::PolygonMode) -> d3d12_ty::D3D12_FILL_MODE { } /// D3D12 doesn't support passing factors ending in `_COLOR` for alpha blending -/// (see https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_render_target_blend_desc). +/// (see ). /// Therefore this function takes an additional `is_alpha` argument /// which if set will return an equivalent `_ALPHA` factor. fn map_blend_factor(factor: wgt::BlendFactor, is_alpha: bool) -> d3d12_ty::D3D12_BLEND { diff --git a/third_party/rust/wgpu-hal/src/dx12/device.rs b/third_party/rust/wgpu-hal/src/dx12/device.rs index 23bd409dc4..82075294ee 100644 --- a/third_party/rust/wgpu-hal/src/dx12/device.rs +++ b/third_party/rust/wgpu-hal/src/dx12/device.rs @@ -218,21 +218,39 @@ impl super::Device { use naga::back::hlsl; let stage_bit = crate::auxil::map_naga_stage(naga_stage); - let module = &stage.module.naga.module; + + let (module, info) = naga::back::pipeline_constants::process_overrides( + &stage.module.naga.module, + &stage.module.naga.info, + stage.constants, + ) + .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("HLSL: {e:?}")))?; + + let needs_temp_options = stage.zero_initialize_workgroup_memory + != layout.naga_options.zero_initialize_workgroup_memory; + let mut temp_options; + let naga_options = if needs_temp_options { + temp_options = layout.naga_options.clone(); + temp_options.zero_initialize_workgroup_memory = stage.zero_initialize_workgroup_memory; + &temp_options + } else { + &layout.naga_options + }; + //TODO: reuse the writer let mut source = String::new(); - let mut writer = hlsl::Writer::new(&mut source, &layout.naga_options); + let mut writer = hlsl::Writer::new(&mut source, naga_options); let reflection_info = { profiling::scope!("naga::back::hlsl::write"); writer - .write(module, &stage.module.naga.info) + .write(&module, &info) .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("HLSL: {e:?}")))? }; let full_stage = format!( "{}_{}\0", naga_stage.to_hlsl_str(), - layout.naga_options.shader_model.to_str() + naga_options.shader_model.to_str() ); let ep_index = module @@ -1062,12 +1080,7 @@ impl crate::Device for super::Device { }, bind_group_infos, naga_options: hlsl::Options { - shader_model: match self.dxc_container { - // DXC - Some(_) => hlsl::ShaderModel::V6_0, - // FXC doesn't support SM 6.0 - None => hlsl::ShaderModel::V5_1, - }, + shader_model: self.private_caps.shader_model, binding_map, fake_missing_bindings: false, special_constants_binding, diff --git a/third_party/rust/wgpu-hal/src/dx12/mod.rs b/third_party/rust/wgpu-hal/src/dx12/mod.rs index 4f958943ca..9f021bc241 100644 --- a/third_party/rust/wgpu-hal/src/dx12/mod.rs +++ b/third_party/rust/wgpu-hal/src/dx12/mod.rs @@ -195,6 +195,7 @@ struct PrivateCapabilities { heap_create_not_zeroed: bool, casting_fully_typed_format_supported: bool, suballocation_supported: bool, + shader_model: naga::back::hlsl::ShaderModel, } #[derive(Default)] @@ -439,7 +440,7 @@ impl Texture { } } - /// see https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources#plane-slice + /// see fn calc_subresource(&self, mip_level: u32, array_layer: u32, plane: u32) -> u32 { mip_level + (array_layer + plane * self.array_layer_count()) * self.mip_level_count } diff --git a/third_party/rust/wgpu-hal/src/dx12/types.rs b/third_party/rust/wgpu-hal/src/dx12/types.rs index b4ad38324a..17b608b840 100644 --- a/third_party/rust/wgpu-hal/src/dx12/types.rs +++ b/third_party/rust/wgpu-hal/src/dx12/types.rs @@ -41,3 +41,25 @@ winapi::STRUCT! { BarycentricsSupported: winapi::shared::minwindef::BOOL, } } + +winapi::ENUM! { + enum D3D_SHADER_MODEL { + D3D_SHADER_MODEL_NONE = 0, + D3D_SHADER_MODEL_5_1 = 0x51, + D3D_SHADER_MODEL_6_0 = 0x60, + D3D_SHADER_MODEL_6_1 = 0x61, + D3D_SHADER_MODEL_6_2 = 0x62, + D3D_SHADER_MODEL_6_3 = 0x63, + D3D_SHADER_MODEL_6_4 = 0x64, + D3D_SHADER_MODEL_6_5 = 0x65, + D3D_SHADER_MODEL_6_6 = 0x66, + D3D_SHADER_MODEL_6_7 = 0x67, + D3D_HIGHEST_SHADER_MODEL = 0x67, + } +} + +winapi::STRUCT! { + struct D3D12_FEATURE_DATA_SHADER_MODEL { + HighestShaderModel: D3D_SHADER_MODEL, + } +} diff --git a/third_party/rust/wgpu-hal/src/gles/adapter.rs b/third_party/rust/wgpu-hal/src/gles/adapter.rs index b9d044337c..052c77006b 100644 --- a/third_party/rust/wgpu-hal/src/gles/adapter.rs +++ b/third_party/rust/wgpu-hal/src/gles/adapter.rs @@ -104,7 +104,7 @@ impl super::Adapter { } } - fn make_info(vendor_orig: String, renderer_orig: String) -> wgt::AdapterInfo { + fn make_info(vendor_orig: String, renderer_orig: String, version: String) -> wgt::AdapterInfo { let vendor = vendor_orig.to_lowercase(); let renderer = renderer_orig.to_lowercase(); @@ -179,13 +179,33 @@ impl super::Adapter { 0 }; + let driver; + let driver_info; + if version.starts_with("WebGL ") || version.starts_with("OpenGL ") { + let es_sig = " ES"; + match version.find(es_sig) { + Some(pos) => { + driver = version[..pos + es_sig.len()].to_owned(); + driver_info = version[pos + es_sig.len() + 1..].to_owned(); + } + None => { + let pos = version.find(' ').unwrap(); + driver = version[..pos].to_owned(); + driver_info = version[pos + 1..].to_owned(); + } + } + } else { + driver = "OpenGL".to_owned(); + driver_info = version; + } + wgt::AdapterInfo { name: renderer_orig, vendor: vendor_id, device: 0, device_type: inferred_device_type, - driver: String::new(), - driver_info: String::new(), + driver, + driver_info, backend: wgt::Backend::Gl, } } @@ -507,8 +527,7 @@ impl super::Adapter { let has_etc = if cfg!(any(webgl, Emscripten)) { extensions.contains("WEBGL_compressed_texture_etc") } else { - // This is a required part of GLES3, but not part of Desktop GL at all. - es_ver.is_some() + es_ver.is_some() || extensions.contains("GL_ARB_ES3_compatibility") }; features.set(wgt::Features::TEXTURE_COMPRESSION_ETC2, has_etc); @@ -728,6 +747,8 @@ impl super::Adapter { } else { !0 }, + min_subgroup_size: 0, + max_subgroup_size: 0, max_push_constant_size: super::MAX_PUSH_CONSTANTS as u32 * 4, min_uniform_buffer_offset_alignment, min_storage_buffer_offset_alignment, @@ -825,7 +846,7 @@ impl super::Adapter { max_msaa_samples: max_samples, }), }, - info: Self::make_info(vendor, renderer), + info: Self::make_info(vendor, renderer, version), features, capabilities: crate::Capabilities { limits, diff --git a/third_party/rust/wgpu-hal/src/gles/conv.rs b/third_party/rust/wgpu-hal/src/gles/conv.rs index bde69b8629..a6c924f162 100644 --- a/third_party/rust/wgpu-hal/src/gles/conv.rs +++ b/third_party/rust/wgpu-hal/src/gles/conv.rs @@ -212,6 +212,7 @@ pub(super) fn describe_vertex_format(vertex_format: wgt::VertexFormat) -> super: Vf::Uint32x4 => (4, glow::UNSIGNED_INT, Vak::Integer), Vf::Sint32x4 => (4, glow::INT, Vak::Integer), Vf::Float32x4 => (4, glow::FLOAT, Vak::Float), + Vf::Unorm10_10_10_2 => (4, glow::UNSIGNED_INT_10_10_10_2, Vak::Float), Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(), }; diff --git a/third_party/rust/wgpu-hal/src/gles/device.rs b/third_party/rust/wgpu-hal/src/gles/device.rs index 50c07f3ff0..a1e2736aa6 100644 --- a/third_party/rust/wgpu-hal/src/gles/device.rs +++ b/third_party/rust/wgpu-hal/src/gles/device.rs @@ -220,9 +220,17 @@ impl super::Device { multiview: context.multiview, }; - let shader = &stage.module.naga; - let entry_point_index = shader - .module + let (module, info) = naga::back::pipeline_constants::process_overrides( + &stage.module.naga.module, + &stage.module.naga.info, + stage.constants, + ) + .map_err(|e| { + let msg = format!("{e}"); + crate::PipelineError::Linkage(map_naga_stage(naga_stage), msg) + })?; + + let entry_point_index = module .entry_points .iter() .position(|ep| ep.name.as_str() == stage.entry_point) @@ -247,11 +255,23 @@ impl super::Device { }; let mut output = String::new(); + let needs_temp_options = stage.zero_initialize_workgroup_memory + != context.layout.naga_options.zero_initialize_workgroup_memory; + let mut temp_options; + let naga_options = if needs_temp_options { + // We use a conditional here, as cloning the naga_options could be expensive + // That is, we want to avoid doing that unless we cannot avoid it + temp_options = context.layout.naga_options.clone(); + temp_options.zero_initialize_workgroup_memory = stage.zero_initialize_workgroup_memory; + &temp_options + } else { + &context.layout.naga_options + }; let mut writer = glsl::Writer::new( &mut output, - &shader.module, - &shader.info, - &context.layout.naga_options, + &module, + &info, + naga_options, &pipeline_options, policies, ) @@ -269,8 +289,8 @@ impl super::Device { context.consume_reflection( gl, - &shader.module, - shader.info.get_entry_point(entry_point_index), + &module, + info.get_entry_point(entry_point_index), reflection_info, naga_stage, program, @@ -297,6 +317,7 @@ impl super::Device { naga_stage: naga_stage.to_owned(), shader_id: stage.module.id, entry_point: stage.entry_point.to_owned(), + zero_initialize_workgroup_memory: stage.zero_initialize_workgroup_memory, }); } let mut guard = self diff --git a/third_party/rust/wgpu-hal/src/gles/egl.rs b/third_party/rust/wgpu-hal/src/gles/egl.rs index b166f4f102..00ef70ba88 100644 --- a/third_party/rust/wgpu-hal/src/gles/egl.rs +++ b/third_party/rust/wgpu-hal/src/gles/egl.rs @@ -526,28 +526,51 @@ impl Inner { } let (config, supports_native_window) = choose_config(&egl, display, srgb_kind)?; - egl.bind_api(khronos_egl::OPENGL_ES_API).unwrap(); + + let supports_opengl = if version >= (1, 4) { + let client_apis = egl + .query_string(Some(display), khronos_egl::CLIENT_APIS) + .unwrap() + .to_string_lossy(); + client_apis + .split(' ') + .any(|client_api| client_api == "OpenGL") + } else { + false + }; + egl.bind_api(if supports_opengl { + khronos_egl::OPENGL_API + } else { + khronos_egl::OPENGL_ES_API + }) + .unwrap(); let needs_robustness = true; let mut khr_context_flags = 0; let supports_khr_context = display_extensions.contains("EGL_KHR_create_context"); - //TODO: make it so `Device` == EGL Context - let mut context_attributes = vec![ - khronos_egl::CONTEXT_MAJOR_VERSION, - 3, // Request GLES 3.0 or higher - ]; - - if force_gles_minor_version != wgt::Gles3MinorVersion::Automatic { + let mut context_attributes = vec![]; + if supports_opengl { + context_attributes.push(khronos_egl::CONTEXT_MAJOR_VERSION); + context_attributes.push(3); context_attributes.push(khronos_egl::CONTEXT_MINOR_VERSION); - context_attributes.push(match force_gles_minor_version { - wgt::Gles3MinorVersion::Version0 => 0, - wgt::Gles3MinorVersion::Version1 => 1, - wgt::Gles3MinorVersion::Version2 => 2, - _ => unreachable!(), - }); + context_attributes.push(3); + if force_gles_minor_version != wgt::Gles3MinorVersion::Automatic { + log::warn!("Ignoring specified GLES minor version as OpenGL is used"); + } + } else { + context_attributes.push(khronos_egl::CONTEXT_MAJOR_VERSION); + context_attributes.push(3); // Request GLES 3.0 or higher + if force_gles_minor_version != wgt::Gles3MinorVersion::Automatic { + context_attributes.push(khronos_egl::CONTEXT_MINOR_VERSION); + context_attributes.push(match force_gles_minor_version { + wgt::Gles3MinorVersion::Automatic => unreachable!(), + wgt::Gles3MinorVersion::Version0 => 0, + wgt::Gles3MinorVersion::Version1 => 1, + wgt::Gles3MinorVersion::Version2 => 2, + }); + } } - if flags.contains(wgt::InstanceFlags::DEBUG) { if version >= (1, 5) { log::debug!("\tEGL context: +debug"); @@ -577,8 +600,6 @@ impl Inner { // because it's for desktop GL only, not GLES. log::warn!("\tEGL context: -robust access"); } - - //TODO do we need `khronos_egl::CONTEXT_OPENGL_NOTIFICATION_STRATEGY_EXT`? } if khr_context_flags != 0 { context_attributes.push(EGL_CONTEXT_FLAGS_KHR); @@ -977,6 +998,7 @@ impl crate::Instance for Instance { srgb_kind: inner.srgb_kind, }) } + unsafe fn destroy_surface(&self, _surface: Surface) {} unsafe fn enumerate_adapters(&self) -> Vec> { @@ -993,6 +1015,12 @@ impl crate::Instance for Instance { }) }; + // In contrast to OpenGL ES, OpenGL requires explicitly enabling sRGB conversions, + // as otherwise the user has to do the sRGB conversion. + if !matches!(inner.srgb_kind, SrgbFrameBufferKind::None) { + unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) }; + } + if self.flags.contains(wgt::InstanceFlags::DEBUG) && gl.supports_debug() { log::debug!("Max label length: {}", unsafe { gl.get_parameter_i32(glow::MAX_LABEL_LENGTH) @@ -1106,6 +1134,13 @@ impl Surface { unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) }; unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)) }; + + if !matches!(self.srgb_kind, SrgbFrameBufferKind::None) { + // Disable sRGB conversions for `glBlitFramebuffer` as behavior does diverge between + // drivers and formats otherwise and we want to ensure no sRGB conversions happen. + unsafe { gl.disable(glow::FRAMEBUFFER_SRGB) }; + } + // Note the Y-flipping here. GL's presentation is not flipped, // but main rendering is. Therefore, we Y-flip the output positions // in the shader, and also this blit. @@ -1123,6 +1158,11 @@ impl Surface { glow::NEAREST, ) }; + + if !matches!(self.srgb_kind, SrgbFrameBufferKind::None) { + unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) }; + } + unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) }; self.egl diff --git a/third_party/rust/wgpu-hal/src/gles/mod.rs b/third_party/rust/wgpu-hal/src/gles/mod.rs index 6f41f7c000..0fcb09be46 100644 --- a/third_party/rust/wgpu-hal/src/gles/mod.rs +++ b/third_party/rust/wgpu-hal/src/gles/mod.rs @@ -602,6 +602,7 @@ struct ProgramStage { naga_stage: naga::ShaderStage, shader_id: ShaderId, entry_point: String, + zero_initialize_workgroup_memory: bool, } #[derive(PartialEq, Eq, Hash)] diff --git a/third_party/rust/wgpu-hal/src/gles/queue.rs b/third_party/rust/wgpu-hal/src/gles/queue.rs index 29dfb79d04..7c728d3978 100644 --- a/third_party/rust/wgpu-hal/src/gles/queue.rs +++ b/third_party/rust/wgpu-hal/src/gles/queue.rs @@ -213,12 +213,27 @@ impl super::Queue { instance_count, ref first_instance_location, } => { - match base_vertex { - 0 => { - unsafe { - gl.uniform_1_u32(first_instance_location.as_ref(), first_instance) - }; + let supports_full_instancing = self + .shared + .private_caps + .contains(PrivateCapabilities::FULLY_FEATURED_INSTANCING); + if supports_full_instancing { + unsafe { + gl.draw_elements_instanced_base_vertex_base_instance( + topology, + index_count as i32, + index_type, + index_offset as i32, + instance_count as i32, + base_vertex, + first_instance, + ) + } + } else { + unsafe { gl.uniform_1_u32(first_instance_location.as_ref(), first_instance) }; + + if base_vertex == 0 { unsafe { // Don't use `gl.draw_elements`/`gl.draw_elements_base_vertex` for `instance_count == 1`. // Angle has a bug where it doesn't consider the instance divisor when `DYNAMIC_DRAW` is used in `gl.draw_elements`/`gl.draw_elements_base_vertex`. @@ -231,41 +246,17 @@ impl super::Queue { instance_count as i32, ) } - } - _ => { - let supports_full_instancing = self - .shared - .private_caps - .contains(PrivateCapabilities::FULLY_FEATURED_INSTANCING); - - if supports_full_instancing { - unsafe { - gl.draw_elements_instanced_base_vertex_base_instance( - topology, - index_count as i32, - index_type, - index_offset as i32, - instance_count as i32, - base_vertex, - first_instance, - ) - } - } else { - unsafe { - gl.uniform_1_u32(first_instance_location.as_ref(), first_instance) - }; - - // If we've gotten here, wgpu-core has already validated that this function exists via the DownlevelFlags::BASE_VERTEX feature. - unsafe { - gl.draw_elements_instanced_base_vertex( - topology, - index_count as _, - index_type, - index_offset as i32, - instance_count as i32, - base_vertex, - ) - } + } else { + // If we've gotten here, wgpu-core has already validated that this function exists via the DownlevelFlags::BASE_VERTEX feature. + unsafe { + gl.draw_elements_instanced_base_vertex( + topology, + index_count as _, + index_type, + index_offset as i32, + instance_count as i32, + base_vertex, + ) } } } diff --git a/third_party/rust/wgpu-hal/src/gles/wgl.rs b/third_party/rust/wgpu-hal/src/gles/wgl.rs index 2564892969..aae70478b4 100644 --- a/third_party/rust/wgpu-hal/src/gles/wgl.rs +++ b/third_party/rust/wgpu-hal/src/gles/wgl.rs @@ -507,6 +507,8 @@ impl crate::Instance for Instance { .supported_extensions() .contains("GL_ARB_framebuffer_sRGB"); + // In contrast to OpenGL ES, OpenGL requires explicitly enabling sRGB conversions, + // as otherwise the user has to do the sRGB conversion. if srgb_capable { unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) }; } diff --git a/third_party/rust/wgpu-hal/src/lib.rs b/third_party/rust/wgpu-hal/src/lib.rs index 79bd54e66e..d300ca30cc 100644 --- a/third_party/rust/wgpu-hal/src/lib.rs +++ b/third_party/rust/wgpu-hal/src/lib.rs @@ -1,17 +1,208 @@ -/*! This library describes the internal unsafe graphics abstraction API. - * It follows WebGPU for the most part, re-using wgpu-types, - * with the following deviations: - * - Fully unsafe: zero overhead, zero validation. - * - Compile-time backend selection via traits. - * - Objects are passed by references and returned by value. No IDs. - * - Mapping is persistent, with explicit synchronization. - * - Resource transitions are explicit. - * - All layouts are explicit. Binding model has compatibility. +/*! A cross-platform unsafe graphics abstraction. * - * General design direction is to follow the majority by the following weights: - * - wgpu-core: 1.5 - * - primary backends (Vulkan/Metal/DX12): 1.0 each - * - secondary backend (GLES): 0.5 + * This crate defines a set of traits abstracting over modern graphics APIs, + * with implementations ("backends") for Vulkan, Metal, Direct3D, and GL. + * + * `wgpu-hal` is a spiritual successor to + * [gfx-hal](https://github.com/gfx-rs/gfx), but with reduced scope, and + * oriented towards WebGPU implementation goals. It has no overhead for + * validation or tracking, and the API translation overhead is kept to the bare + * minimum by the design of WebGPU. This API can be used for resource-demanding + * applications and engines. + * + * The `wgpu-hal` crate's main design choices: + * + * - Our traits are meant to be *portable*: proper use + * should get equivalent results regardless of the backend. + * + * - Our traits' contracts are *unsafe*: implementations perform minimal + * validation, if any, and incorrect use will often cause undefined behavior. + * This allows us to minimize the overhead we impose over the underlying + * graphics system. If you need safety, the [`wgpu-core`] crate provides a + * safe API for driving `wgpu-hal`, implementing all necessary validation, + * resource state tracking, and so on. (Note that `wgpu-core` is designed for + * use via FFI; the [`wgpu`] crate provides more idiomatic Rust bindings for + * `wgpu-core`.) Or, you can do your own validation. + * + * - In the same vein, returned errors *only cover cases the user can't + * anticipate*, like running out of memory or losing the device. Any errors + * that the user could reasonably anticipate are their responsibility to + * avoid. For example, `wgpu-hal` returns no error for mapping a buffer that's + * not mappable: as the buffer creator, the user should already know if they + * can map it. + * + * - We use *static dispatch*. The traits are not + * generally object-safe. You must select a specific backend type + * like [`vulkan::Api`] or [`metal::Api`], and then use that + * according to the main traits, or call backend-specific methods. + * + * - We use *idiomatic Rust parameter passing*, + * taking objects by reference, returning them by value, and so on, + * unlike `wgpu-core`, which refers to objects by ID. + * + * - We map buffer contents *persistently*. This means that the buffer + * can remain mapped on the CPU while the GPU reads or writes to it. + * You must explicitly indicate when data might need to be + * transferred between CPU and GPU, if `wgpu-hal` indicates that the + * mapping is not coherent (that is, automatically synchronized + * between the two devices). + * + * - You must record *explicit barriers* between different usages of a + * resource. For example, if a buffer is written to by a compute + * shader, and then used as and index buffer to a draw call, you + * must use [`CommandEncoder::transition_buffers`] between those two + * operations. + * + * - Pipeline layouts are *explicitly specified* when setting bind + * group. Incompatible layouts disturb groups bound at higher indices. + * + * - The API *accepts collections as iterators*, to avoid forcing the user to + * store data in particular containers. The implementation doesn't guarantee + * that any of the iterators are drained, unless stated otherwise by the + * function documentation. For this reason, we recommend that iterators don't + * do any mutating work. + * + * Unfortunately, `wgpu-hal`'s safety requirements are not fully documented. + * Ideally, all trait methods would have doc comments setting out the + * requirements users must meet to ensure correct and portable behavior. If you + * are aware of a specific requirement that a backend imposes that is not + * ensured by the traits' documented rules, please file an issue. Or, if you are + * a capable technical writer, please file a pull request! + * + * [`wgpu-core`]: https://crates.io/crates/wgpu-core + * [`wgpu`]: https://crates.io/crates/wgpu + * [`vulkan::Api`]: vulkan/struct.Api.html + * [`metal::Api`]: metal/struct.Api.html + * + * ## Primary backends + * + * The `wgpu-hal` crate has full-featured backends implemented on the following + * platform graphics APIs: + * + * - Vulkan, available on Linux, Android, and Windows, using the [`ash`] crate's + * Vulkan bindings. It's also available on macOS, if you install [MoltenVK]. + * + * - Metal on macOS, using the [`metal`] crate's bindings. + * + * - Direct3D 12 on Windows, using the [`d3d12`] crate's bindings. + * + * [`ash`]: https://crates.io/crates/ash + * [MoltenVK]: https://github.com/KhronosGroup/MoltenVK + * [`metal`]: https://crates.io/crates/metal + * [`d3d12`]: ahttps://crates.io/crates/d3d12 + * + * ## Secondary backends + * + * The `wgpu-hal` crate has a partial implementation based on the following + * platform graphics API: + * + * - The GL backend is available anywhere OpenGL, OpenGL ES, or WebGL are + * available. See the [`gles`] module documentation for details. + * + * [`gles`]: gles/index.html + * + * You can see what capabilities an adapter is missing by checking the + * [`DownlevelCapabilities`][tdc] in [`ExposedAdapter::capabilities`], available + * from [`Instance::enumerate_adapters`]. + * + * The API is generally designed to fit the primary backends better than the + * secondary backends, so the latter may impose more overhead. + * + * [tdc]: wgt::DownlevelCapabilities + * + * ## Traits + * + * The `wgpu-hal` crate defines a handful of traits that together + * represent a cross-platform abstraction for modern GPU APIs. + * + * - The [`Api`] trait represents a `wgpu-hal` backend. It has no methods of its + * own, only a collection of associated types. + * + * - [`Api::Instance`] implements the [`Instance`] trait. [`Instance::init`] + * creates an instance value, which you can use to enumerate the adapters + * available on the system. For example, [`vulkan::Api::Instance::init`][Ii] + * returns an instance that can enumerate the Vulkan physical devices on your + * system. + * + * - [`Api::Adapter`] implements the [`Adapter`] trait, representing a + * particular device from a particular backend. For example, a Vulkan instance + * might have a Lavapipe software adapter and a GPU-based adapter. + * + * - [`Api::Device`] implements the [`Device`] trait, representing an active + * link to a device. You get a device value by calling [`Adapter::open`], and + * then use it to create buffers, textures, shader modules, and so on. + * + * - [`Api::Queue`] implements the [`Queue`] trait, which you use to submit + * command buffers to a given device. + * + * - [`Api::CommandEncoder`] implements the [`CommandEncoder`] trait, which you + * use to build buffers of commands to submit to a queue. This has all the + * methods for drawing and running compute shaders, which is presumably what + * you're here for. + * + * - [`Api::Surface`] implements the [`Surface`] trait, which represents a + * swapchain for presenting images on the screen, via interaction with the + * system's window manager. + * + * The [`Api`] trait has various other associated types like [`Api::Buffer`] and + * [`Api::Texture`] that represent resources the rest of the interface can + * operate on, but these generally do not have their own traits. + * + * [Ii]: Instance::init + * + * ## Validation is the calling code's responsibility, not `wgpu-hal`'s + * + * As much as possible, `wgpu-hal` traits place the burden of validation, + * resource tracking, and state tracking on the caller, not on the trait + * implementations themselves. Anything which can reasonably be handled in + * backend-independent code should be. A `wgpu_hal` backend's sole obligation is + * to provide portable behavior, and report conditions that the calling code + * can't reasonably anticipate, like device loss or running out of memory. + * + * The `wgpu` crate collection is intended for use in security-sensitive + * applications, like web browsers, where the API is available to untrusted + * code. This means that `wgpu-core`'s validation is not simply a service to + * developers, to be provided opportunistically when the performance costs are + * acceptable and the necessary data is ready at hand. Rather, `wgpu-core`'s + * validation must be exhaustive, to ensure that even malicious content cannot + * provoke and exploit undefined behavior in the platform's graphics API. + * + * Because graphics APIs' requirements are complex, the only practical way for + * `wgpu` to provide exhaustive validation is to comprehensively track the + * lifetime and state of all the resources in the system. Implementing this + * separately for each backend is infeasible; effort would be better spent + * making the cross-platform validation in `wgpu-core` legible and trustworthy. + * Fortunately, the requirements are largely similar across the various + * platforms, so cross-platform validation is practical. + * + * Some backends have specific requirements that aren't practical to foist off + * on the `wgpu-hal` user. For example, properly managing macOS Objective-C or + * Microsoft COM reference counts is best handled by using appropriate pointer + * types within the backend. + * + * A desire for "defense in depth" may suggest performing additional validation + * in `wgpu-hal` when the opportunity arises, but this must be done with + * caution. Even experienced contributors infer the expectations their changes + * must meet by considering not just requirements made explicit in types, tests, + * assertions, and comments, but also those implicit in the surrounding code. + * When one sees validation or state-tracking code in `wgpu-hal`, it is tempting + * to conclude, "Oh, `wgpu-hal` checks for this, so `wgpu-core` needn't worry + * about it - that would be redundant!" The responsibility for exhaustive + * validation always rests with `wgpu-core`, regardless of what may or may not + * be checked in `wgpu-hal`. + * + * To this end, any "defense in depth" validation that does appear in `wgpu-hal` + * for requirements that `wgpu-core` should have enforced should report failure + * via the `unreachable!` macro, because problems detected at this stage always + * indicate a bug in `wgpu-core`. + * + * ## Debugging + * + * Most of the information on the wiki [Debugging wgpu Applications][wiki-debug] + * page still applies to this API, with the exception of API tracing/replay + * functionality, which is only available in `wgpu-core`. + * + * [wiki-debug]: https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications */ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] @@ -198,6 +389,15 @@ pub trait Api: Clone + fmt::Debug + Sized { type Queue: Queue; type CommandEncoder: CommandEncoder; + + /// This API's command buffer type. + /// + /// The only thing you can do with `CommandBuffer`s is build them + /// with a [`CommandEncoder`] and then pass them to + /// [`Queue::submit`] for execution, or destroy them by passing + /// them to [`CommandEncoder::reset_all`]. + /// + /// [`CommandEncoder`]: Api::CommandEncoder type CommandBuffer: WasmNotSendSync + fmt::Debug; type Buffer: fmt::Debug + WasmNotSendSync + 'static; @@ -206,6 +406,24 @@ pub trait Api: Clone + fmt::Debug + Sized { type TextureView: fmt::Debug + WasmNotSendSync; type Sampler: fmt::Debug + WasmNotSendSync; type QuerySet: fmt::Debug + WasmNotSendSync; + + /// A value you can block on to wait for something to finish. + /// + /// A `Fence` holds a monotonically increasing [`FenceValue`]. You can call + /// [`Device::wait`] to block until a fence reaches or passes a value you + /// choose. [`Queue::submit`] can take a `Fence` and a [`FenceValue`] to + /// store in it when the submitted work is complete. + /// + /// Attempting to set a fence to a value less than its current value has no + /// effect. + /// + /// Waiting on a fence returns as soon as the fence reaches *or passes* the + /// requested value. This implies that, in order to reliably determine when + /// an operation has completed, operations must finish in order of + /// increasing fence values: if a higher-valued operation were to finish + /// before a lower-valued operation, then waiting for the fence to reach the + /// lower value could return before the lower-valued operation has actually + /// finished. type Fence: fmt::Debug + WasmNotSendSync; type BindGroupLayout: fmt::Debug + WasmNotSendSync; @@ -405,7 +623,25 @@ pub trait Device: WasmNotSendSync { &self, fence: &::Fence, ) -> Result; - /// Calling wait with a lower value than the current fence value will immediately return. + + /// Wait for `fence` to reach `value`. + /// + /// Operations like [`Queue::submit`] can accept a [`Fence`] and a + /// [`FenceValue`] to store in it, so you can use this `wait` function + /// to wait for a given queue submission to finish execution. + /// + /// The `value` argument must be a value that some actual operation you have + /// already presented to the device is going to store in `fence`. You cannot + /// wait for values yet to be submitted. (This restriction accommodates + /// implementations like the `vulkan` backend's [`FencePool`] that must + /// allocate a distinct synchronization object for each fence value one is + /// able to wait for.) + /// + /// Calling `wait` with a lower [`FenceValue`] than `fence`'s current value + /// returns immediately. + /// + /// [`Fence`]: Api::Fence + /// [`FencePool`]: vulkan/enum.Fence.html#variant.FencePool unsafe fn wait( &self, fence: &::Fence, @@ -437,14 +673,48 @@ pub trait Device: WasmNotSendSync { pub trait Queue: WasmNotSendSync { type A: Api; - /// Submits the command buffers for execution on GPU. + /// Submit `command_buffers` for execution on GPU. + /// + /// If `signal_fence` is `Some(fence, value)`, update `fence` to `value` + /// when the operation is complete. See [`Fence`] for details. + /// + /// If two calls to `submit` on a single `Queue` occur in a particular order + /// (that is, they happen on the same thread, or on two threads that have + /// synchronized to establish an ordering), then the first submission's + /// commands all complete execution before any of the second submission's + /// commands begin. All results produced by one submission are visible to + /// the next. + /// + /// Within a submission, command buffers execute in the order in which they + /// appear in `command_buffers`. All results produced by one buffer are + /// visible to the next. + /// + /// If two calls to `submit` on a single `Queue` from different threads are + /// not synchronized to occur in a particular order, they must pass distinct + /// [`Fence`]s. As explained in the [`Fence`] documentation, waiting for + /// operations to complete is only trustworthy when operations finish in + /// order of increasing fence value, but submissions from different threads + /// cannot determine how to order the fence values if the submissions + /// themselves are unordered. If each thread uses a separate [`Fence`], this + /// problem does not arise. /// /// Valid usage: - /// - all of the command buffers were created from command pools - /// that are associated with this queue. - /// - all of the command buffers had `CommandBuffer::finish()` called. - /// - all surface textures that the command buffers write to must be - /// passed to the surface_textures argument. + /// + /// - All of the [`CommandBuffer`][cb]s were created from + /// [`CommandEncoder`][ce]s that are associated with this queue. + /// + /// - All of those [`CommandBuffer`][cb]s must remain alive until + /// the submitted commands have finished execution. (Since + /// command buffers must not outlive their encoders, this + /// implies that the encoders must remain alive as well.) + /// + /// - All of the [`SurfaceTexture`][st]s that the command buffers + /// write to appear in the `surface_textures` argument. + /// + /// [`Fence`]: Api::Fence + /// [cb]: Api::CommandBuffer + /// [ce]: Api::CommandEncoder + /// [st]: Api::SurfaceTexture unsafe fn submit( &self, command_buffers: &[&::CommandBuffer], @@ -459,7 +729,12 @@ pub trait Queue: WasmNotSendSync { unsafe fn get_timestamp_period(&self) -> f32; } -/// Encoder and allocation pool for `CommandBuffer`. +/// Encoder and allocation pool for `CommandBuffer`s. +/// +/// A `CommandEncoder` not only constructs `CommandBuffer`s but also +/// acts as the allocation pool that owns the buffers' underlying +/// storage. Thus, `CommandBuffer`s must not outlive the +/// `CommandEncoder` that created them. /// /// The life cycle of a `CommandBuffer` is as follows: /// @@ -472,14 +747,17 @@ pub trait Queue: WasmNotSendSync { /// /// - Call methods like `copy_buffer_to_buffer`, `begin_render_pass`, /// etc. on a "recording" `CommandEncoder` to add commands to the -/// list. +/// list. (If an error occurs, you must call `discard_encoding`; see +/// below.) /// /// - Call `end_encoding` on a recording `CommandEncoder` to close the /// encoder and construct a fresh `CommandBuffer` consisting of the /// list of commands recorded up to that point. /// /// - Call `discard_encoding` on a recording `CommandEncoder` to drop -/// the commands recorded thus far and close the encoder. +/// the commands recorded thus far and close the encoder. This is +/// the only safe thing to do on a `CommandEncoder` if an error has +/// occurred while recording commands. /// /// - Call `reset_all` on a closed `CommandEncoder`, passing all the /// live `CommandBuffers` built from it. All the `CommandBuffer`s @@ -497,6 +775,10 @@ pub trait Queue: WasmNotSendSync { /// built it. /// /// - A `CommandEncoder` must not outlive its `Device`. +/// +/// It is the user's responsibility to meet this requirements. This +/// allows `CommandEncoder` implementations to keep their state +/// tracking to a minimum. pub trait CommandEncoder: WasmNotSendSync + fmt::Debug { type A: Api; @@ -509,13 +791,20 @@ pub trait CommandEncoder: WasmNotSendSync + fmt::Debug { /// This `CommandEncoder` must be in the "closed" state. unsafe fn begin_encoding(&mut self, label: Label) -> Result<(), DeviceError>; - /// Discard the command list under construction, if any. + /// Discard the command list under construction. + /// + /// If an error has occurred while recording commands, this + /// is the only safe thing to do with the encoder. /// /// This puts this `CommandEncoder` in the "closed" state. /// /// # Safety /// /// This `CommandEncoder` must be in the "recording" state. + /// + /// Callers must not assume that implementations of this + /// function are idempotent, and thus should not call it + /// multiple times in a row. unsafe fn discard_encoding(&mut self); /// Return a fresh [`CommandBuffer`] holding the recorded commands. @@ -1318,6 +1607,13 @@ pub struct ProgrammableStage<'a, A: Api> { /// The name of the entry point in the compiled shader. There must be a function with this name /// in the shader. pub entry_point: &'a str, + /// Pipeline constants + pub constants: &'a naga::back::PipelineConstants, + /// Whether workgroup scoped memory will be initialized with zero values for this stage. + /// + /// This is required by the WebGPU spec, but may have overhead which can be avoided + /// for cross-platform applications + pub zero_initialize_workgroup_memory: bool, } // Rust gets confused about the impl requirements for `A` @@ -1326,6 +1622,8 @@ impl Clone for ProgrammableStage<'_, A> { Self { module: self.module, entry_point: self.entry_point, + constants: self.constants, + zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory, } } } diff --git a/third_party/rust/wgpu-hal/src/metal/adapter.rs b/third_party/rust/wgpu-hal/src/metal/adapter.rs index 6211896838..cddba472bd 100644 --- a/third_party/rust/wgpu-hal/src/metal/adapter.rs +++ b/third_party/rust/wgpu-hal/src/metal/adapter.rs @@ -562,7 +562,11 @@ impl super::PrivateCapabilities { Self { family_check, - msl_version: if os_is_xr || version.at_least((12, 0), (15, 0), os_is_mac) { + msl_version: if os_is_xr || version.at_least((14, 0), (17, 0), os_is_mac) { + MTLLanguageVersion::V3_1 + } else if version.at_least((13, 0), (16, 0), os_is_mac) { + MTLLanguageVersion::V3_0 + } else if version.at_least((12, 0), (15, 0), os_is_mac) { MTLLanguageVersion::V2_4 } else if version.at_least((11, 0), (14, 0), os_is_mac) { MTLLanguageVersion::V2_3 @@ -809,6 +813,14 @@ impl super::PrivateCapabilities { None }, timestamp_query_support, + supports_simd_scoped_operations: family_check + && (device.supports_family(MTLGPUFamily::Metal3) + || device.supports_family(MTLGPUFamily::Mac2) + || device.supports_family(MTLGPUFamily::Apple7)), + // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=5 + int64: family_check + && (device.supports_family(MTLGPUFamily::Apple3) + || device.supports_family(MTLGPUFamily::Metal3)), } } @@ -882,7 +894,7 @@ impl super::PrivateCapabilities { } features.set( F::SHADER_INT64, - self.msl_version >= MTLLanguageVersion::V2_3, + self.int64 && self.msl_version >= MTLLanguageVersion::V2_3, ); features.set( @@ -894,6 +906,10 @@ impl super::PrivateCapabilities { features.set(F::RG11B10UFLOAT_RENDERABLE, self.format_rg11b10_all); features.set(F::SHADER_UNUSED_VERTEX_OUTPUT, true); + if self.supports_simd_scoped_operations { + features.insert(F::SUBGROUP | F::SUBGROUP_BARRIER); + } + features } @@ -948,6 +964,8 @@ impl super::PrivateCapabilities { max_vertex_buffers: self.max_vertex_buffers, max_vertex_attributes: 31, max_vertex_buffer_array_stride: base.max_vertex_buffer_array_stride, + min_subgroup_size: 4, + max_subgroup_size: 64, max_push_constant_size: 0x1000, min_uniform_buffer_offset_alignment: self.buffer_alignment as u32, min_storage_buffer_offset_alignment: self.buffer_alignment as u32, diff --git a/third_party/rust/wgpu-hal/src/metal/conv.rs b/third_party/rust/wgpu-hal/src/metal/conv.rs index 8f6439b50b..6ebabee1a6 100644 --- a/third_party/rust/wgpu-hal/src/metal/conv.rs +++ b/third_party/rust/wgpu-hal/src/metal/conv.rs @@ -222,6 +222,7 @@ pub fn map_vertex_format(format: wgt::VertexFormat) -> metal::MTLVertexFormat { Vf::Uint32x4 => UInt4, Vf::Sint32x4 => Int4, Vf::Float32x4 => Float4, + Vf::Unorm10_10_10_2 => UInt1010102Normalized, Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(), } } diff --git a/third_party/rust/wgpu-hal/src/metal/device.rs b/third_party/rust/wgpu-hal/src/metal/device.rs index 179429f5d7..2c8f5a2bfb 100644 --- a/third_party/rust/wgpu-hal/src/metal/device.rs +++ b/third_party/rust/wgpu-hal/src/metal/device.rs @@ -69,7 +69,13 @@ impl super::Device { ) -> Result { let stage_bit = map_naga_stage(naga_stage); - let module = &stage.module.naga.module; + let (module, module_info) = naga::back::pipeline_constants::process_overrides( + &stage.module.naga.module, + &stage.module.naga.info, + stage.constants, + ) + .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("MSL: {:?}", e)))?; + let ep_resources = &layout.per_stage_map[naga_stage]; let bounds_check_policy = if stage.module.runtime_checks { @@ -88,6 +94,8 @@ impl super::Device { metal::MTLLanguageVersion::V2_2 => (2, 2), metal::MTLLanguageVersion::V2_3 => (2, 3), metal::MTLLanguageVersion::V2_4 => (2, 4), + metal::MTLLanguageVersion::V3_0 => (3, 0), + metal::MTLLanguageVersion::V3_1 => (3, 1), }, inline_samplers: Default::default(), spirv_cross_compatibility: false, @@ -104,7 +112,7 @@ impl super::Device { // TODO: support bounds checks on binding arrays binding_array: naga::proc::BoundsCheckPolicy::Unchecked, }, - zero_initialize_workgroup_memory: true, + zero_initialize_workgroup_memory: stage.zero_initialize_workgroup_memory, }; let pipeline_options = naga::back::msl::PipelineOptions { @@ -114,13 +122,9 @@ impl super::Device { }, }; - let (source, info) = naga::back::msl::write_string( - module, - &stage.module.naga.info, - &options, - &pipeline_options, - ) - .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("MSL: {:?}", e)))?; + let (source, info) = + naga::back::msl::write_string(&module, &module_info, &options, &pipeline_options) + .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("MSL: {:?}", e)))?; log::debug!( "Naga generated shader for entry point '{}' and stage {:?}\n{}", @@ -168,7 +172,7 @@ impl super::Device { })?; // collect sizes indices, immutable buffers, and work group memory sizes - let ep_info = &stage.module.naga.info.get_entry_point(ep_index); + let ep_info = &module_info.get_entry_point(ep_index); let mut wg_memory_sizes = Vec::new(); let mut sized_bindings = Vec::new(); let mut immutable_buffer_mask = 0; diff --git a/third_party/rust/wgpu-hal/src/metal/mod.rs b/third_party/rust/wgpu-hal/src/metal/mod.rs index 6aeafb0f86..7d547cfe3c 100644 --- a/third_party/rust/wgpu-hal/src/metal/mod.rs +++ b/third_party/rust/wgpu-hal/src/metal/mod.rs @@ -269,6 +269,8 @@ struct PrivateCapabilities { supports_shader_primitive_index: bool, has_unified_memory: Option, timestamp_query_support: TimestampQuerySupport, + supports_simd_scoped_operations: bool, + int64: bool, } #[derive(Clone, Debug)] @@ -649,7 +651,7 @@ struct BufferResource { /// Buffers with the [`wgt::BufferBindingType::Storage`] binding type can /// hold WGSL runtime-sized arrays. When one does, we must pass its size to /// shader entry points to implement bounds checks and WGSL's `arrayLength` - /// function. See [`device::CompiledShader::sized_bindings`] for details. + /// function. See `device::CompiledShader::sized_bindings` for details. /// /// [`Storage`]: wgt::BufferBindingType::Storage binding_size: Option, @@ -680,12 +682,12 @@ struct PipelineStageInfo { /// The buffer argument table index at which we pass runtime-sized arrays' buffer sizes. /// - /// See [`device::CompiledShader::sized_bindings`] for more details. + /// See `device::CompiledShader::sized_bindings` for more details. sizes_slot: Option, /// Bindings of all WGSL `storage` globals that contain runtime-sized arrays. /// - /// See [`device::CompiledShader::sized_bindings`] for more details. + /// See `device::CompiledShader::sized_bindings` for more details. sized_bindings: Vec, } @@ -801,7 +803,7 @@ struct CommandState { /// /// Specifically: /// - /// - The keys are ['ResourceBinding`] values (that is, the WGSL `@group` + /// - The keys are [`ResourceBinding`] values (that is, the WGSL `@group` /// and `@binding` attributes) for `var` global variables in the /// current module that contain runtime-sized arrays. /// @@ -813,7 +815,7 @@ struct CommandState { /// of the buffers listed in [`stage_infos.S.sized_bindings`], which we must /// pass to the entry point. /// - /// See [`device::CompiledShader::sized_bindings`] for more details. + /// See `device::CompiledShader::sized_bindings` for more details. /// /// [`ResourceBinding`]: naga::ResourceBinding storage_buffer_length_map: rustc_hash::FxHashMap, diff --git a/third_party/rust/wgpu-hal/src/vulkan/adapter.rs b/third_party/rust/wgpu-hal/src/vulkan/adapter.rs index 2665463792..21219361f4 100644 --- a/third_party/rust/wgpu-hal/src/vulkan/adapter.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/adapter.rs @@ -35,6 +35,8 @@ fn indexing_features() -> wgt::Features { /// [`PhysicalDeviceFeatures::from_extensions_and_requested_features`] /// constructs an value of this type indicating which Vulkan features to /// enable, based on the `wgpu_types::Features` requested. +/// +/// [`Instance::expose_adapter`]: super::Instance::expose_adapter #[derive(Debug, Default)] pub struct PhysicalDeviceFeatures { /// Basic Vulkan 1.0 features. @@ -86,6 +88,9 @@ pub struct PhysicalDeviceFeatures { /// /// However, we do populate this when creating a device if /// [`Features::RAY_TRACING_ACCELERATION_STRUCTURE`] is requested. + /// + /// [`Instance::expose_adapter`]: super::Instance::expose_adapter + /// [`Features::RAY_TRACING_ACCELERATION_STRUCTURE`]: wgt::Features::RAY_TRACING_ACCELERATION_STRUCTURE buffer_device_address: Option, /// Features provided by `VK_KHR_ray_query`, @@ -95,12 +100,17 @@ pub struct PhysicalDeviceFeatures { /// this from `vkGetPhysicalDeviceFeatures2`. /// /// However, we do populate this when creating a device if ray tracing is requested. + /// + /// [`Instance::expose_adapter`]: super::Instance::expose_adapter ray_query: Option, /// Features provided by `VK_KHR_zero_initialize_workgroup_memory`, promoted /// to Vulkan 1.3. zero_initialize_workgroup_memory: Option, + + /// Features provided by `VK_EXT_subgroup_size_control`, promoted to Vulkan 1.3. + subgroup_size_control: Option, } // This is safe because the structs have `p_next: *mut c_void`, which we null out/never read. @@ -148,6 +158,9 @@ impl PhysicalDeviceFeatures { if let Some(ref mut feature) = self.ray_query { info = info.push_next(feature); } + if let Some(ref mut feature) = self.subgroup_size_control { + info = info.push_next(feature); + } info } @@ -175,6 +188,7 @@ impl PhysicalDeviceFeatures { /// [`Features`]: wgt::Features /// [`DownlevelFlags`]: wgt::DownlevelFlags /// [`PrivateCapabilities`]: super::PrivateCapabilities + /// [`add_to_device_create_builder`]: PhysicalDeviceFeatures::add_to_device_create_builder /// [`DeviceCreateInfoBuilder`]: vk::DeviceCreateInfoBuilder /// [`Adapter::required_device_extensions`]: super::Adapter::required_device_extensions fn from_extensions_and_requested_features( @@ -434,6 +448,17 @@ impl PhysicalDeviceFeatures { } else { None }, + subgroup_size_control: if device_api_version >= vk::API_VERSION_1_3 + || enabled_extensions.contains(&vk::ExtSubgroupSizeControlFn::name()) + { + Some( + vk::PhysicalDeviceSubgroupSizeControlFeatures::builder() + .subgroup_size_control(true) + .build(), + ) + } else { + None + }, } } @@ -442,6 +467,9 @@ impl PhysicalDeviceFeatures { /// Given `self`, together with the instance and physical device it was /// built from, and a `caps` also built from those, determine which wgpu /// features and downlevel flags the device can support. + /// + /// [`Features`]: wgt::Features + /// [`DownlevelFlags`]: wgt::DownlevelFlags fn to_wgpu( &self, instance: &ash::Instance, @@ -638,6 +666,34 @@ impl PhysicalDeviceFeatures { ); } + if let Some(ref subgroup) = caps.subgroup { + if (caps.device_api_version >= vk::API_VERSION_1_3 + || caps.supports_extension(vk::ExtSubgroupSizeControlFn::name())) + && subgroup.supported_operations.contains( + vk::SubgroupFeatureFlags::BASIC + | vk::SubgroupFeatureFlags::VOTE + | vk::SubgroupFeatureFlags::ARITHMETIC + | vk::SubgroupFeatureFlags::BALLOT + | vk::SubgroupFeatureFlags::SHUFFLE + | vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE, + ) + { + features.set( + F::SUBGROUP, + subgroup + .supported_stages + .contains(vk::ShaderStageFlags::COMPUTE | vk::ShaderStageFlags::FRAGMENT), + ); + features.set( + F::SUBGROUP_VERTEX, + subgroup + .supported_stages + .contains(vk::ShaderStageFlags::VERTEX), + ); + features.insert(F::SUBGROUP_BARRIER); + } + } + let supports_depth_format = |format| { supports_format( instance, @@ -773,6 +829,13 @@ pub struct PhysicalDeviceProperties { /// `VK_KHR_driver_properties` extension, promoted to Vulkan 1.2. driver: Option, + /// Additional `vk::PhysicalDevice` properties from Vulkan 1.1. + subgroup: Option, + + /// Additional `vk::PhysicalDevice` properties from the + /// `VK_EXT_subgroup_size_control` extension, promoted to Vulkan 1.3. + subgroup_size_control: Option, + /// The device API version. /// /// Which is the version of Vulkan supported for device-level functionality. @@ -888,6 +951,11 @@ impl PhysicalDeviceProperties { if self.supports_extension(vk::ExtImageRobustnessFn::name()) { extensions.push(vk::ExtImageRobustnessFn::name()); } + + // Require `VK_EXT_subgroup_size_control` if the associated feature was requested + if requested_features.contains(wgt::Features::SUBGROUP) { + extensions.push(vk::ExtSubgroupSizeControlFn::name()); + } } // Optional `VK_KHR_swapchain_mutable_format` @@ -987,6 +1055,14 @@ impl PhysicalDeviceProperties { .min(crate::MAX_VERTEX_BUFFERS as u32), max_vertex_attributes: limits.max_vertex_input_attributes, max_vertex_buffer_array_stride: limits.max_vertex_input_binding_stride, + min_subgroup_size: self + .subgroup_size_control + .map(|subgroup_size| subgroup_size.min_subgroup_size) + .unwrap_or(0), + max_subgroup_size: self + .subgroup_size_control + .map(|subgroup_size| subgroup_size.max_subgroup_size) + .unwrap_or(0), max_push_constant_size: limits.max_push_constants_size, min_uniform_buffer_offset_alignment: limits.min_uniform_buffer_offset_alignment as u32, min_storage_buffer_offset_alignment: limits.min_storage_buffer_offset_alignment as u32, @@ -1042,6 +1118,9 @@ impl super::InstanceShared { let supports_driver_properties = capabilities.device_api_version >= vk::API_VERSION_1_2 || capabilities.supports_extension(vk::KhrDriverPropertiesFn::name()); + let supports_subgroup_size_control = capabilities.device_api_version + >= vk::API_VERSION_1_3 + || capabilities.supports_extension(vk::ExtSubgroupSizeControlFn::name()); let supports_acceleration_structure = capabilities.supports_extension(vk::KhrAccelerationStructureFn::name()); @@ -1075,6 +1154,20 @@ impl super::InstanceShared { builder = builder.push_next(next); } + if capabilities.device_api_version >= vk::API_VERSION_1_1 { + let next = capabilities + .subgroup + .insert(vk::PhysicalDeviceSubgroupProperties::default()); + builder = builder.push_next(next); + } + + if supports_subgroup_size_control { + let next = capabilities + .subgroup_size_control + .insert(vk::PhysicalDeviceSubgroupSizeControlProperties::default()); + builder = builder.push_next(next); + } + let mut properties2 = builder.build(); unsafe { get_device_properties.get_physical_device_properties2(phd, &mut properties2); @@ -1190,6 +1283,16 @@ impl super::InstanceShared { builder = builder.push_next(next); } + // `VK_EXT_subgroup_size_control` is promoted to 1.3 + if capabilities.device_api_version >= vk::API_VERSION_1_3 + || capabilities.supports_extension(vk::ExtSubgroupSizeControlFn::name()) + { + let next = features + .subgroup_size_control + .insert(vk::PhysicalDeviceSubgroupSizeControlFeatures::default()); + builder = builder.push_next(next); + } + let mut features2 = builder.build(); unsafe { get_device_properties.get_physical_device_features2(phd, &mut features2); @@ -1382,6 +1485,9 @@ impl super::Instance { }), image_format_list: phd_capabilities.device_api_version >= vk::API_VERSION_1_2 || phd_capabilities.supports_extension(vk::KhrImageFormatListFn::name()), + subgroup_size_control: phd_features + .subgroup_size_control + .map_or(false, |ext| ext.subgroup_size_control == vk::TRUE), }; let capabilities = crate::Capabilities { limits: phd_capabilities.to_wgpu_limits(), @@ -1581,6 +1687,15 @@ impl super::Adapter { capabilities.push(spv::Capability::Geometry); } + if features.intersects(wgt::Features::SUBGROUP | wgt::Features::SUBGROUP_VERTEX) { + capabilities.push(spv::Capability::GroupNonUniform); + capabilities.push(spv::Capability::GroupNonUniformVote); + capabilities.push(spv::Capability::GroupNonUniformArithmetic); + capabilities.push(spv::Capability::GroupNonUniformBallot); + capabilities.push(spv::Capability::GroupNonUniformShuffle); + capabilities.push(spv::Capability::GroupNonUniformShuffleRelative); + } + if features.intersects( wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, @@ -1616,7 +1731,13 @@ impl super::Adapter { true, // could check `super::Workarounds::SEPARATE_ENTRY_POINTS` ); spv::Options { - lang_version: (1, 0), + lang_version: if features + .intersects(wgt::Features::SUBGROUP | wgt::Features::SUBGROUP_VERTEX) + { + (1, 3) + } else { + (1, 0) + }, flags, capabilities: Some(capabilities.iter().cloned().collect()), bounds_check_policies: naga::proc::BoundsCheckPolicies { diff --git a/third_party/rust/wgpu-hal/src/vulkan/command.rs b/third_party/rust/wgpu-hal/src/vulkan/command.rs index 43a2471954..ceb44dfbe6 100644 --- a/third_party/rust/wgpu-hal/src/vulkan/command.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/command.rs @@ -104,6 +104,11 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn discard_encoding(&mut self) { + // Safe use requires this is not called in the "closed" state, so the buffer + // shouldn't be null. Assert this to make sure we're not pushing null + // buffers to the discard pile. + assert_ne!(self.active, vk::CommandBuffer::null()); + self.discarded.push(self.active); self.active = vk::CommandBuffer::null(); } diff --git a/third_party/rust/wgpu-hal/src/vulkan/conv.rs b/third_party/rust/wgpu-hal/src/vulkan/conv.rs index 8202c93aa3..fe284f32a9 100644 --- a/third_party/rust/wgpu-hal/src/vulkan/conv.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/conv.rs @@ -399,6 +399,7 @@ pub fn map_vertex_format(vertex_format: wgt::VertexFormat) -> vk::Format { Vf::Float64x2 => vk::Format::R64G64_SFLOAT, Vf::Float64x3 => vk::Format::R64G64B64_SFLOAT, Vf::Float64x4 => vk::Format::R64G64B64A64_SFLOAT, + Vf::Unorm10_10_10_2 => vk::Format::A2B10G10R10_UNORM_PACK32, } } diff --git a/third_party/rust/wgpu-hal/src/vulkan/device.rs b/third_party/rust/wgpu-hal/src/vulkan/device.rs index 70028cc700..ec392533a0 100644 --- a/third_party/rust/wgpu-hal/src/vulkan/device.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/device.rs @@ -2,6 +2,7 @@ use super::conv; use arrayvec::ArrayVec; use ash::{extensions::khr, vk}; +use naga::back::spv::ZeroInitializeWorkgroupMemoryMode; use parking_lot::Mutex; use std::{ @@ -737,7 +738,8 @@ impl super::Device { }; let needs_temp_options = !runtime_checks || !binding_map.is_empty() - || naga_shader.debug_source.is_some(); + || naga_shader.debug_source.is_some() + || !stage.zero_initialize_workgroup_memory; let mut temp_options; let options = if needs_temp_options { temp_options = self.naga_options.clone(); @@ -760,27 +762,40 @@ impl super::Device { file_name: debug.file_name.as_ref().as_ref(), }) } + if !stage.zero_initialize_workgroup_memory { + temp_options.zero_initialize_workgroup_memory = + ZeroInitializeWorkgroupMemoryMode::None; + } &temp_options } else { &self.naga_options }; + + let (module, info) = naga::back::pipeline_constants::process_overrides( + &naga_shader.module, + &naga_shader.info, + stage.constants, + ) + .map_err(|e| crate::PipelineError::Linkage(stage_flags, format!("{e}")))?; + let spv = { profiling::scope!("naga::spv::write_vec"); - naga::back::spv::write_vec( - &naga_shader.module, - &naga_shader.info, - options, - Some(&pipeline_options), - ) + naga::back::spv::write_vec(&module, &info, options, Some(&pipeline_options)) } .map_err(|e| crate::PipelineError::Linkage(stage_flags, format!("{e}")))?; self.create_shader_module_impl(&spv)? } }; + let mut flags = vk::PipelineShaderStageCreateFlags::empty(); + if self.shared.private_caps.subgroup_size_control { + flags |= vk::PipelineShaderStageCreateFlags::ALLOW_VARYING_SUBGROUP_SIZE + } + let entry_point = CString::new(stage.entry_point).unwrap(); let create_info = vk::PipelineShaderStageCreateInfo::builder() + .flags(flags) .stage(conv::map_shader_stage(stage_flags)) .module(vk_module) .name(&entry_point) @@ -1587,6 +1602,7 @@ impl crate::Device for super::Device { .shared .workarounds .contains(super::Workarounds::SEPARATE_ENTRY_POINTS) + || !naga_shader.module.overrides.is_empty() { return Ok(super::ShaderModule::Intermediate { naga_shader, diff --git a/third_party/rust/wgpu-hal/src/vulkan/mod.rs b/third_party/rust/wgpu-hal/src/vulkan/mod.rs index 0cd385045c..d1ea82772e 100644 --- a/third_party/rust/wgpu-hal/src/vulkan/mod.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/mod.rs @@ -238,6 +238,7 @@ struct PrivateCapabilities { robust_image_access2: bool, zero_initialize_workgroup_memory: bool, image_format_list: bool, + subgroup_size_control: bool, } bitflags::bitflags!( @@ -413,6 +414,15 @@ pub struct TextureView { attachment: FramebufferAttachment, } +impl TextureView { + /// # Safety + /// + /// - The image view handle must not be manually destroyed + pub unsafe fn raw_handle(&self) -> vk::ImageView { + self.raw + } +} + #[derive(Debug)] pub struct Sampler { raw: vk::Sampler, @@ -438,6 +448,7 @@ pub struct BindGroup { set: gpu_descriptor::DescriptorSet, } +/// Miscellaneous allocation recycling pool for `CommandAllocator`. #[derive(Default)] struct Temp { marker: Vec, @@ -467,11 +478,31 @@ impl Temp { pub struct CommandEncoder { raw: vk::CommandPool, device: Arc, + + /// The current command buffer, if `self` is in the ["recording"] + /// state. + /// + /// ["recording"]: crate::CommandEncoder + /// + /// If non-`null`, the buffer is in the Vulkan "recording" state. active: vk::CommandBuffer, + + /// What kind of pass we are currently within: compute or render. bind_point: vk::PipelineBindPoint, + + /// Allocation recycling pool for this encoder. temp: Temp, + + /// A pool of available command buffers. + /// + /// These are all in the Vulkan "initial" state. free: Vec, + + /// A pool of discarded command buffers. + /// + /// These could be in any Vulkan state except "pending". discarded: Vec, + /// If this is true, the active renderpass enabled a debug span, /// and needs to be disabled on renderpass close. rpass_debug_marker_active: bool, @@ -481,6 +512,15 @@ pub struct CommandEncoder { end_of_pass_timer_query: Option<(vk::QueryPool, u32)>, } +impl CommandEncoder { + /// # Safety + /// + /// - The command buffer handle must not be manually destroyed + pub unsafe fn raw_handle(&self) -> vk::CommandBuffer { + self.active + } +} + impl fmt::Debug for CommandEncoder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CommandEncoder") @@ -519,9 +559,47 @@ pub struct QuerySet { raw: vk::QueryPool, } +/// The [`Api::Fence`] type for [`vulkan::Api`]. +/// +/// This is an `enum` because there are two possible implementations of +/// `wgpu-hal` fences on Vulkan: Vulkan fences, which work on any version of +/// Vulkan, and Vulkan timeline semaphores, which are easier and cheaper but +/// require non-1.0 features. +/// +/// [`Device::create_fence`] returns a [`TimelineSemaphore`] if +/// [`VK_KHR_timeline_semaphore`] is available and enabled, and a [`FencePool`] +/// otherwise. +/// +/// [`Api::Fence`]: crate::Api::Fence +/// [`vulkan::Api`]: Api +/// [`Device::create_fence`]: crate::Device::create_fence +/// [`TimelineSemaphore`]: Fence::TimelineSemaphore +/// [`VK_KHR_timeline_semaphore`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VK_KHR_timeline_semaphore +/// [`FencePool`]: Fence::FencePool #[derive(Debug)] pub enum Fence { + /// A Vulkan [timeline semaphore]. + /// + /// These are simpler to use than Vulkan fences, since timeline semaphores + /// work exactly the way [`wpgu_hal::Api::Fence`] is specified to work. + /// + /// [timeline semaphore]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-semaphores + /// [`wpgu_hal::Api::Fence`]: crate::Api::Fence TimelineSemaphore(vk::Semaphore), + + /// A collection of Vulkan [fence]s, each associated with a [`FenceValue`]. + /// + /// The effective [`FenceValue`] of this variant is the greater of + /// `last_completed` and the maximum value associated with a signalled fence + /// in `active`. + /// + /// Fences are available in all versions of Vulkan, but since they only have + /// two states, "signaled" and "unsignaled", we need to use a separate fence + /// for each queue submission we might want to wait for, and remember which + /// [`FenceValue`] each one represents. + /// + /// [fence]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-fences + /// [`FenceValue`]: crate::FenceValue FencePool { last_completed: crate::FenceValue, /// The pending fence values have to be ascending. @@ -531,21 +609,32 @@ pub enum Fence { } impl Fence { + /// Return the highest [`FenceValue`] among the signalled fences in `active`. + /// + /// As an optimization, assume that we already know that the fence has + /// reached `last_completed`, and don't bother checking fences whose values + /// are less than that: those fences remain in the `active` array only + /// because we haven't called `maintain` yet to clean them up. + /// + /// [`FenceValue`]: crate::FenceValue fn check_active( device: &ash::Device, - mut max_value: crate::FenceValue, + mut last_completed: crate::FenceValue, active: &[(crate::FenceValue, vk::Fence)], ) -> Result { for &(value, raw) in active.iter() { unsafe { - if value > max_value && device.get_fence_status(raw)? { - max_value = value; + if value > last_completed && device.get_fence_status(raw)? { + last_completed = value; } } } - Ok(max_value) + Ok(last_completed) } + /// Return the highest signalled [`FenceValue`] for `self`. + /// + /// [`FenceValue`]: crate::FenceValue fn get_latest( &self, device: &ash::Device, @@ -566,6 +655,18 @@ impl Fence { } } + /// Trim the internal state of this [`Fence`]. + /// + /// This function has no externally visible effect, but you should call it + /// periodically to keep this fence's resource consumption under control. + /// + /// For fences using the [`FencePool`] implementation, this function + /// recycles fences that have been signaled. If you don't call this, + /// [`Queue::submit`] will just keep allocating a new Vulkan fence every + /// time it's called. + /// + /// [`FencePool`]: Fence::FencePool + /// [`Queue::submit`]: crate::Queue::submit fn maintain(&mut self, device: &ash::Device) -> Result<(), crate::DeviceError> { match *self { Self::TimelineSemaphore(_) => {} diff --git a/third_party/rust/wgpu-types/.cargo-checksum.json b/third_party/rust/wgpu-types/.cargo-checksum.json index 928cdbab21..0f14282158 100644 --- a/third_party/rust/wgpu-types/.cargo-checksum.json +++ b/third_party/rust/wgpu-types/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"0bcb9c2d557d01677740fea4690c79544898fe749880a72512dca33db171e590","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"b9fda00d1b61364cdd7e544aee731ce075ea8403349ed286711d39aa8d414c28","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"d8f88446d6c1740116442320eca91e06ce9a2f4713179195c1be44e8ab1fc42d","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"0e844b150863abdecee2a2cb44245330f22ab48d8ab14f15f06c13f96213bdf3","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null} \ No newline at end of file diff --git a/third_party/rust/wgpu-types/Cargo.toml b/third_party/rust/wgpu-types/Cargo.toml index c6f8b3002d..44bfa08b33 100644 --- a/third_party/rust/wgpu-types/Cargo.toml +++ b/third_party/rust/wgpu-types/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.74" name = "wgpu-types" -version = "0.19.0" +version = "0.20.0" authors = ["gfx-rs developers"] description = "WebGPU types" homepage = "https://wgpu.rs/" @@ -45,7 +45,7 @@ features = ["serde_derive"] optional = true [dev-dependencies] -serde_json = "1.0.113" +serde_json = "1.0.116" [dev-dependencies.serde] version = "1" diff --git a/third_party/rust/wgpu-types/src/lib.rs b/third_party/rust/wgpu-types/src/lib.rs index b36801e941..7049cd3a8d 100644 --- a/third_party/rust/wgpu-types/src/lib.rs +++ b/third_party/rust/wgpu-types/src/lib.rs @@ -890,6 +890,30 @@ bitflags::bitflags! { /// /// This is a native only feature. const SHADER_INT64 = 1 << 55; + /// Allows compute and fragment shaders to use the subgroup operation built-ins + /// + /// Supported Platforms: + /// - Vulkan + /// - DX12 + /// - Metal + /// + /// This is a native only feature. + const SUBGROUP = 1 << 56; + /// Allows vertex shaders to use the subgroup operation built-ins + /// + /// Supported Platforms: + /// - Vulkan + /// + /// This is a native only feature. + const SUBGROUP_VERTEX = 1 << 57; + /// Allows shaders to use the subgroup barrier + /// + /// Supported Platforms: + /// - Vulkan + /// - Metal + /// + /// This is a native only feature. + const SUBGROUP_BARRIER = 1 << 58; } } @@ -1119,7 +1143,7 @@ pub struct Limits { /// pipeline output data, across all color attachments. pub max_color_attachment_bytes_per_sample: u32, /// Maximum number of bytes used for workgroup memory in a compute entry point. Defaults to - /// 16352. Higher is "better". + /// 16384. Higher is "better". pub max_compute_workgroup_storage_size: u32, /// Maximum value of the product of the `workgroup_size` dimensions for a compute entry-point. /// Defaults to 256. Higher is "better". @@ -1136,6 +1160,11 @@ pub struct Limits { /// The maximum value for each dimension of a `ComputePass::dispatch(x, y, z)` operation. /// Defaults to 65535. Higher is "better". pub max_compute_workgroups_per_dimension: u32, + + /// Minimal number of invocations in a subgroup. Higher is "better". + pub min_subgroup_size: u32, + /// Maximal number of invocations in a subgroup. Lower is "better". + pub max_subgroup_size: u32, /// Amount of storage available for push constants in bytes. Defaults to 0. Higher is "better". /// Requesting more than 0 during device creation requires [`Features::PUSH_CONSTANTS`] to be enabled. /// @@ -1146,7 +1175,6 @@ pub struct Limits { /// - OpenGL doesn't natively support push constants, and are emulated with uniforms, /// so this number is less useful but likely 256. pub max_push_constant_size: u32, - /// Maximum number of live non-sampler bindings. /// /// This limit only affects the d3d12 backend. Using a large number will allow the device @@ -1156,6 +1184,14 @@ pub struct Limits { impl Default for Limits { fn default() -> Self { + Self::defaults() + } +} + +impl Limits { + // Rust doesn't allow const in trait implementations, so we break this out + // to allow reusing these defaults in const contexts like `downlevel_defaults` + const fn defaults() -> Self { Self { max_texture_dimension_1d: 8192, max_texture_dimension_2d: 8192, @@ -1170,10 +1206,10 @@ impl Default for Limits { max_storage_buffers_per_shader_stage: 8, max_storage_textures_per_shader_stage: 4, max_uniform_buffers_per_shader_stage: 12, - max_uniform_buffer_binding_size: 64 << 10, - max_storage_buffer_binding_size: 128 << 20, + max_uniform_buffer_binding_size: 64 << 10, // (64 KiB) + max_storage_buffer_binding_size: 128 << 20, // (128 MiB) max_vertex_buffers: 8, - max_buffer_size: 256 << 20, + max_buffer_size: 256 << 20, // (256 MiB) max_vertex_attributes: 16, max_vertex_buffer_array_stride: 2048, min_uniform_buffer_offset_alignment: 256, @@ -1187,13 +1223,13 @@ impl Default for Limits { max_compute_workgroup_size_y: 256, max_compute_workgroup_size_z: 64, max_compute_workgroups_per_dimension: 65535, + min_subgroup_size: 0, + max_subgroup_size: 0, max_push_constant_size: 0, max_non_sampler_bindings: 1_000_000, } } -} -impl Limits { /// These default limits are guaranteed to be compatible with GLES-3.1, and D3D11 /// /// Those limits are as follows (different from default are marked with *): @@ -1218,13 +1254,15 @@ impl Limits { /// max_vertex_buffers: 8, /// max_vertex_attributes: 16, /// max_vertex_buffer_array_stride: 2048, + /// min_subgroup_size: 0, + /// max_subgroup_size: 0, /// max_push_constant_size: 0, /// min_uniform_buffer_offset_alignment: 256, /// min_storage_buffer_offset_alignment: 256, /// max_inter_stage_shader_components: 60, /// max_color_attachments: 8, /// max_color_attachment_bytes_per_sample: 32, - /// max_compute_workgroup_storage_size: 16352, + /// max_compute_workgroup_storage_size: 16352, // * /// max_compute_invocations_per_workgroup: 256, /// max_compute_workgroup_size_x: 256, /// max_compute_workgroup_size_y: 256, @@ -1239,35 +1277,11 @@ impl Limits { max_texture_dimension_1d: 2048, max_texture_dimension_2d: 2048, max_texture_dimension_3d: 256, - max_texture_array_layers: 256, - max_bind_groups: 4, - max_bindings_per_bind_group: 1000, - max_dynamic_uniform_buffers_per_pipeline_layout: 8, - max_dynamic_storage_buffers_per_pipeline_layout: 4, - max_sampled_textures_per_shader_stage: 16, - max_samplers_per_shader_stage: 16, max_storage_buffers_per_shader_stage: 4, - max_storage_textures_per_shader_stage: 4, - max_uniform_buffers_per_shader_stage: 12, - max_uniform_buffer_binding_size: 16 << 10, - max_storage_buffer_binding_size: 128 << 20, - max_vertex_buffers: 8, - max_vertex_attributes: 16, - max_vertex_buffer_array_stride: 2048, - max_push_constant_size: 0, - min_uniform_buffer_offset_alignment: 256, - min_storage_buffer_offset_alignment: 256, - max_inter_stage_shader_components: 60, - max_color_attachments: 8, - max_color_attachment_bytes_per_sample: 32, + max_uniform_buffer_binding_size: 16 << 10, // (16 KiB) + // see: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=7 max_compute_workgroup_storage_size: 16352, - max_compute_invocations_per_workgroup: 256, - max_compute_workgroup_size_x: 256, - max_compute_workgroup_size_y: 256, - max_compute_workgroup_size_z: 64, - max_compute_workgroups_per_dimension: 65535, - max_buffer_size: 256 << 20, - max_non_sampler_bindings: 1_000_000, + ..Self::defaults() } } @@ -1296,6 +1310,8 @@ impl Limits { /// max_vertex_buffers: 8, /// max_vertex_attributes: 16, /// max_vertex_buffer_array_stride: 255, // + + /// min_subgroup_size: 0, + /// max_subgroup_size: 0, /// max_push_constant_size: 0, /// min_uniform_buffer_offset_alignment: 256, /// min_storage_buffer_offset_alignment: 256, @@ -1326,6 +1342,8 @@ impl Limits { max_compute_workgroup_size_y: 0, max_compute_workgroup_size_z: 0, max_compute_workgroups_per_dimension: 0, + min_subgroup_size: 0, + max_subgroup_size: 0, // Value supported by Intel Celeron B830 on Windows (OpenGL 3.1) max_inter_stage_shader_components: 31, @@ -1418,6 +1436,10 @@ impl Limits { compare!(max_vertex_buffers, Less); compare!(max_vertex_attributes, Less); compare!(max_vertex_buffer_array_stride, Less); + if self.min_subgroup_size > 0 && self.max_subgroup_size > 0 { + compare!(min_subgroup_size, Greater); + compare!(max_subgroup_size, Less); + } compare!(max_push_constant_size, Less); compare!(min_uniform_buffer_offset_alignment, Greater); compare!(min_storage_buffer_offset_alignment, Greater); @@ -4942,6 +4964,9 @@ pub enum VertexFormat { Float64x3 = 32, /// Four double-precision floats (f64). `vec4` in shaders. Requires [`Features::VERTEX_ATTRIBUTE_64BIT`]. Float64x4 = 33, + /// Three unsigned 10-bit integers and one 2-bit integer, packed into a 32-bit integer (u32). [0, 1024] converted to float [0, 1] `vec4` in shaders. + #[cfg_attr(feature = "serde", serde(rename = "unorm10-10-10-2"))] + Unorm10_10_10_2 = 34, } impl VertexFormat { @@ -4960,7 +4985,8 @@ impl VertexFormat { | Self::Float16x2 | Self::Float32 | Self::Uint32 - | Self::Sint32 => 4, + | Self::Sint32 + | Self::Unorm10_10_10_2 => 4, Self::Uint16x4 | Self::Sint16x4 | Self::Unorm16x4 @@ -7068,7 +7094,7 @@ pub struct InstanceDescriptor { pub flags: InstanceFlags, /// Which DX12 shader compiler to use. pub dx12_shader_compiler: Dx12Compiler, - /// Which OpenGL ES 3 minor version to request. + /// Which OpenGL ES 3 minor version to request. Will be ignored if OpenGL is available. pub gles_minor_version: Gles3MinorVersion, } diff --git a/third_party/rust/zerocopy-derive/.cargo-checksum.json b/third_party/rust/zerocopy-derive/.cargo-checksum.json new file mode 100644 index 0000000000..805ee6472f --- /dev/null +++ b/third_party/rust/zerocopy-derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b92b9f131058b37c8287d8cd35731a933f05bcd2b82d4ff4771bb8b9e7726d0d","LICENSE-APACHE":"9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3","LICENSE-BSD":"83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32","LICENSE-MIT":"1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df","src/ext.rs":"d741f6132fca552676b132a38b6431362054aec0c86dcf1c281bca51d5decad2","src/lib.rs":"cb237ff473b4216c7b6e6beeb4789532eac31e776c9b6d39a06d408e2003bfd5","src/repr.rs":"780f547b9d51794ec35ea9359a2c55cd40cf1d84f6e1f4080034ff337df953c1","tests/enum_as_bytes.rs":"2e11daa46c6b922d748321e9a47c3b355e2a9e3b48af95a699c39186b7783711","tests/enum_from_zeroes.rs":"32ca3d0dc9085ef8eb9597b5e057ff0b3a0e92b6da44fac3326b2a124010ba4b","tests/enum_known_layout.rs":"7bc4979b3f9cadc4784afd821ea1c0670fe987a842627f9bb4406b248c5c6ce4","tests/enum_unaligned.rs":"0c42281098047c6a106c2eae2ee792b893b4f295e8147cf56eaf826888be5fbf","tests/hygiene.rs":"24f6fb3e4f1aa313753d3f16d9285105b836392f9d68de77ea436a9b24443102","tests/paths_and_modules.rs":"4218b6ac5d1aeb2d3b199af5f64eea45ab1117fc135e9d30588ff761e98b0f10","tests/priv_in_pub.rs":"57ff0106151dc34f2e14be90ca73c1c7e6791215683b28fc68abd2deed90fedb","tests/struct_as_bytes.rs":"334053105b4341376e11a895ceb534b1f0961100f7d04ece17745fbf7d58e0ca","tests/struct_from_bytes.rs":"90e4d0d7cd9b72f3338edff937f195614fca52b6d937cfbba5c2bc763ebc1e60","tests/struct_from_zeroes.rs":"52d6965cd7571926683e85b5b13e09a25144ad0615c7c73ac3a0abf99fa33cb8","tests/struct_known_layout.rs":"1d54c62a9f4682a1ae4174cee9c73c5f0986623f7bbb069c1bed78b82be36989","tests/struct_unaligned.rs":"a5d3377dda1ba884ec4b70ca043f599eccba3b2258de16c58a72c43633507e2e","tests/trybuild.rs":"0954299d2c50d06259a628fa828131e9f0e8953dfcc2cf0d52d6d9ff40c969d5","tests/ui-msrv/derive_transparent.rs":"9f15bf0bf22c8e47c3d645f99239462eae6a875bd469510ad41838d9ae4ed1f8","tests/ui-msrv/derive_transparent.stderr":"b8a66f15647fa8ef3ab5ab371710f36943b42af8f3d2d088509c05f029ad7b8d","tests/ui-msrv/enum.rs":"7eb4f7f912f91c9a040536882b398ac4f07153fd8dbcc49a30603c6eb8107899","tests/ui-msrv/enum.stderr":"321e41c161804d3918fd15214845862c5ca346581e88cf0260073e3c6203cc21","tests/ui-msrv/enum_from_bytes_u8_too_few.rs":"afbec6f24a4bfca472f2929abc5125d8f5b305a0a1b472a1215ad7739ed63100","tests/ui-msrv/enum_from_bytes_u8_too_few.stderr":"a5ab2757166ef9dfa51a09d3dbddd5e9e2b1a46bd3d4b8d175b33a90747878d7","tests/ui-msrv/late_compile_pass.rs":"244f7dcc9a821a400fe3c24323cf8ffe89aa28454527a85b492fc5afd5cae205","tests/ui-msrv/late_compile_pass.stderr":"a8598656086bfc855c7c69131e08b3ac0eac22c5a731346ab4fb5d06dc0dd8e6","tests/ui-msrv/mid_compile_pass.rs":"b80b01bfd383c537173f7d630ec2789a2af3e01bc6d53c807fdcf271b235d0c9","tests/ui-msrv/mid_compile_pass.stderr":"d2d8d441c7642ca266a4250e8b6a4a9aa693cfc2ec48f679600e392e7b6c6273","tests/ui-msrv/struct.rs":"882b8f0a84ac772aaec5a4f786a5216ad37a269a6d9f1f836f1b27cbe861743c","tests/ui-msrv/struct.stderr":"eb245197d856850ea4e9c6ec58fae60058dee5f7fb7ca68b113e4c9cd7826b34","tests/ui-msrv/union.rs":"0661431d493e5690653ba0ed076fba14ab03fff81471d572369269aa58bde5a0","tests/ui-msrv/union.stderr":"a75b425e50af3759dfe4d2bf832b4cb650ddbaf6b5c8853aa904be98685f1e53","tests/ui-nightly/derive_transparent.rs":"9f15bf0bf22c8e47c3d645f99239462eae6a875bd469510ad41838d9ae4ed1f8","tests/ui-nightly/derive_transparent.stderr":"8feb1939943dfa984b301d806844fe0d95ea4830690dd636643c80c81d827d46","tests/ui-nightly/enum.rs":"7eb4f7f912f91c9a040536882b398ac4f07153fd8dbcc49a30603c6eb8107899","tests/ui-nightly/enum.stderr":"9b4d965632beb995022209f0f4ca5d875725f33149916a963402b1901e1dbf14","tests/ui-nightly/enum_from_bytes_u8_too_few.rs":"afbec6f24a4bfca472f2929abc5125d8f5b305a0a1b472a1215ad7739ed63100","tests/ui-nightly/enum_from_bytes_u8_too_few.stderr":"28a493e1057279ea8e20df49ff0c02dfa132027a86bb6f5fe50e250c14e62572","tests/ui-nightly/late_compile_pass.rs":"244f7dcc9a821a400fe3c24323cf8ffe89aa28454527a85b492fc5afd5cae205","tests/ui-nightly/late_compile_pass.stderr":"f9615dc6b05b9b16a67fac482996a4eb147ff4c40e57083c74bdadd00545e3cf","tests/ui-nightly/mid_compile_pass.rs":"b80b01bfd383c537173f7d630ec2789a2af3e01bc6d53c807fdcf271b235d0c9","tests/ui-nightly/mid_compile_pass.stderr":"632c2bcbd13cef40d33acff4e03a92ba1ead5183f9b0876ab761d6c6e9da4276","tests/ui-nightly/struct.rs":"882b8f0a84ac772aaec5a4f786a5216ad37a269a6d9f1f836f1b27cbe861743c","tests/ui-nightly/struct.stderr":"34d084ac848de2880725d41e217c68d1c4cfc31f430195b65508f04dc547e9e5","tests/ui-nightly/union.rs":"0661431d493e5690653ba0ed076fba14ab03fff81471d572369269aa58bde5a0","tests/ui-nightly/union.stderr":"98209cdba5ae46d190d66ba9a6c882aff43b5c584cefc156c5fd24db177f377f","tests/ui-stable/derive_transparent.rs":"9f15bf0bf22c8e47c3d645f99239462eae6a875bd469510ad41838d9ae4ed1f8","tests/ui-stable/derive_transparent.stderr":"7563c87d050d46b7b02f175da358ff03415e729af09bfcef048744569068d7fb","tests/ui-stable/enum.rs":"7eb4f7f912f91c9a040536882b398ac4f07153fd8dbcc49a30603c6eb8107899","tests/ui-stable/enum.stderr":"3d2f2fa112f70f7c18e6aa3400ed5f28ff39b9241de4fdecf7e786bfe85ceadc","tests/ui-stable/enum_from_bytes_u8_too_few.rs":"afbec6f24a4bfca472f2929abc5125d8f5b305a0a1b472a1215ad7739ed63100","tests/ui-stable/enum_from_bytes_u8_too_few.stderr":"b3edb381f968f6f2ad9ab4810132df5962b0650460e07f77af818ababf124fe7","tests/ui-stable/late_compile_pass.rs":"244f7dcc9a821a400fe3c24323cf8ffe89aa28454527a85b492fc5afd5cae205","tests/ui-stable/late_compile_pass.stderr":"a22045df3f18250281809d487dc5782fc951431bd9728215bc9805e2e3e26407","tests/ui-stable/mid_compile_pass.rs":"b80b01bfd383c537173f7d630ec2789a2af3e01bc6d53c807fdcf271b235d0c9","tests/ui-stable/mid_compile_pass.stderr":"673d12c5c7105700a071f995f5644448694efe5733b54ac95dfa02ebe18b67f4","tests/ui-stable/struct.rs":"882b8f0a84ac772aaec5a4f786a5216ad37a269a6d9f1f836f1b27cbe861743c","tests/ui-stable/struct.stderr":"36360e6559d22de902331c48e9398955f4186195e2c1c4bfb587afb287538388","tests/ui-stable/union.rs":"0661431d493e5690653ba0ed076fba14ab03fff81471d572369269aa58bde5a0","tests/ui-stable/union.stderr":"0a2012e5f32634fc3beb033f07b66fc043737623f630f5f957864e72e9dd3ef6","tests/union_as_bytes.rs":"57e69981ed7bb8eebbb2ea2be160532074e32aa4cec6543e9e3af0f5e3767fd8","tests/union_from_bytes.rs":"7da559bbb70fb2dbbb7422ad3099d8c2504d5815bc1e87173ffa758b929382b2","tests/union_from_zeroes.rs":"448d21026955403e1f09c69e19c3542a454456aab1c13d32dad8c612b8cbc7f8","tests/union_known_layout.rs":"a94be098de0a2565d1cf3e9631b36c250ddae1c3490f18e9d8a7b6f70274ec00","tests/union_unaligned.rs":"c8a0458226645063805b9653c2148048e7b93b273b93e7959a969f15e167fa57","tests/util.rs":"8d0cfb435e4b154a3702511f3d10331d6b01bcd90f0d70d4a094778813e9e387"},"package":"9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"} \ No newline at end of file diff --git a/third_party/rust/zerocopy-derive/Cargo.toml b/third_party/rust/zerocopy-derive/Cargo.toml new file mode 100644 index 0000000000..827fe9f223 --- /dev/null +++ b/third_party/rust/zerocopy-derive/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.60.0" +name = "zerocopy-derive" +version = "0.7.32" +authors = ["Joshua Liebow-Feeser "] +exclude = [ + ".*", + "tests/enum_from_bytes.rs", + "tests/ui-nightly/enum_from_bytes_u16_too_few.rs.disabled", +] +description = "Custom derive for traits from the zerocopy crate" +license = "BSD-2-Clause OR Apache-2.0 OR MIT" +repository = "https://github.com/google/zerocopy" + +[lib] +proc-macro = true + +[dependencies.proc-macro2] +version = "1.0.1" + +[dependencies.quote] +version = "1.0.10" + +[dependencies.syn] +version = "2.0.31" + +[dev-dependencies.static_assertions] +version = "1.1" + +[dev-dependencies.trybuild] +version = "=1.0.85" +features = ["diff"] diff --git a/third_party/rust/zerocopy-derive/LICENSE-APACHE b/third_party/rust/zerocopy-derive/LICENSE-APACHE new file mode 100644 index 0000000000..2dc22c12fa --- /dev/null +++ b/third_party/rust/zerocopy-derive/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 The Fuchsia Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/third_party/rust/zerocopy-derive/LICENSE-BSD b/third_party/rust/zerocopy-derive/LICENSE-BSD new file mode 100644 index 0000000000..7ed244f42d --- /dev/null +++ b/third_party/rust/zerocopy-derive/LICENSE-BSD @@ -0,0 +1,24 @@ +Copyright 2019 The Fuchsia Authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/rust/zerocopy-derive/LICENSE-MIT b/third_party/rust/zerocopy-derive/LICENSE-MIT new file mode 100644 index 0000000000..26e15216cd --- /dev/null +++ b/third_party/rust/zerocopy-derive/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2023 The Fuchsia Authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/third_party/rust/zerocopy-derive/src/ext.rs b/third_party/rust/zerocopy-derive/src/ext.rs new file mode 100644 index 0000000000..87cf838f88 --- /dev/null +++ b/third_party/rust/zerocopy-derive/src/ext.rs @@ -0,0 +1,53 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use syn::{Data, DataEnum, DataStruct, DataUnion, Type}; + +pub trait DataExt { + /// Extract the types of all fields. For enums, extract the types of fields + /// from each variant. + fn field_types(&self) -> Vec<&Type>; +} + +impl DataExt for Data { + fn field_types(&self) -> Vec<&Type> { + match self { + Data::Struct(strc) => strc.field_types(), + Data::Enum(enm) => enm.field_types(), + Data::Union(un) => un.field_types(), + } + } +} + +impl DataExt for DataStruct { + fn field_types(&self) -> Vec<&Type> { + self.fields.iter().map(|f| &f.ty).collect() + } +} + +impl DataExt for DataEnum { + fn field_types(&self) -> Vec<&Type> { + self.variants.iter().flat_map(|var| &var.fields).map(|f| &f.ty).collect() + } +} + +impl DataExt for DataUnion { + fn field_types(&self) -> Vec<&Type> { + self.fields.named.iter().map(|f| &f.ty).collect() + } +} + +pub trait EnumExt { + fn is_c_like(&self) -> bool; +} + +impl EnumExt for DataEnum { + fn is_c_like(&self) -> bool { + self.field_types().is_empty() + } +} diff --git a/third_party/rust/zerocopy-derive/src/lib.rs b/third_party/rust/zerocopy-derive/src/lib.rs new file mode 100644 index 0000000000..9af8a28a06 --- /dev/null +++ b/third_party/rust/zerocopy-derive/src/lib.rs @@ -0,0 +1,882 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//! Derive macros for [zerocopy]'s traits. +//! +//! [zerocopy]: https://docs.rs/zerocopy + +// Sometimes we want to use lints which were added after our MSRV. +// `unknown_lints` is `warn` by default and we deny warnings in CI, so without +// this attribute, any unknown lint would cause a CI failure when testing with +// our MSRV. +#![allow(unknown_lints)] +#![deny(renamed_and_removed_lints)] +#![deny(clippy::all, clippy::missing_safety_doc, clippy::undocumented_unsafe_blocks)] +#![deny( + rustdoc::bare_urls, + rustdoc::broken_intra_doc_links, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_html_tags, + rustdoc::invalid_rust_codeblocks, + rustdoc::missing_crate_level_docs, + rustdoc::private_intra_doc_links +)] +#![recursion_limit = "128"] + +mod ext; +mod repr; + +use { + proc_macro2::Span, + quote::quote, + syn::{ + parse_quote, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error, Expr, ExprLit, + GenericParam, Ident, Lit, + }, +}; + +use {crate::ext::*, crate::repr::*}; + +// Unwraps a `Result<_, Vec>`, converting any `Err` value into a +// `TokenStream` and returning it. +macro_rules! try_or_print { + ($e:expr) => { + match $e { + Ok(x) => x, + Err(errors) => return print_all_errors(errors).into(), + } + }; +} + +// TODO(https://github.com/rust-lang/rust/issues/54140): Some errors could be +// made better if we could add multiple lines of error output like this: +// +// error: unsupported representation +// --> enum.rs:28:8 +// | +// 28 | #[repr(transparent)] +// | +// help: required by the derive of FromBytes +// +// Instead, we have more verbose error messages like "unsupported representation +// for deriving FromZeroes, FromBytes, AsBytes, or Unaligned on an enum" +// +// This will probably require Span::error +// (https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.error), +// which is currently unstable. Revisit this once it's stable. + +#[proc_macro_derive(KnownLayout)] +pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + + let is_repr_c_struct = match &ast.data { + Data::Struct(..) => { + let reprs = try_or_print!(repr::reprs::(&ast.attrs)); + if reprs.iter().any(|(_meta, repr)| repr == &Repr::C) { + Some(reprs) + } else { + None + } + } + Data::Enum(..) | Data::Union(..) => None, + }; + + let fields = ast.data.field_types(); + + let (require_self_sized, extras) = if let ( + Some(reprs), + Some((trailing_field, leading_fields)), + ) = (is_repr_c_struct, fields.split_last()) + { + let repr_align = reprs + .iter() + .find_map( + |(_meta, repr)| { + if let Repr::Align(repr_align) = repr { + Some(repr_align) + } else { + None + } + }, + ) + .map(|repr_align| quote!(NonZeroUsize::new(#repr_align as usize))) + .unwrap_or(quote!(None)); + + let repr_packed = reprs + .iter() + .find_map(|(_meta, repr)| match repr { + Repr::Packed => Some(1), + Repr::PackedN(repr_packed) => Some(*repr_packed), + _ => None, + }) + .map(|repr_packed| quote!(NonZeroUsize::new(#repr_packed as usize))) + .unwrap_or(quote!(None)); + + ( + false, + quote!( + // SAFETY: `LAYOUT` accurately describes the layout of `Self`. + // The layout of `Self` is reflected using a sequence of + // invocations of `DstLayout::{new_zst,extend,pad_to_align}`. + // The documentation of these items vows that invocations in + // this manner will acurately describe a type, so long as: + // + // - that type is `repr(C)`, + // - its fields are enumerated in the order they appear, + // - the presence of `repr_align` and `repr_packed` are correctly accounted for. + // + // We respect all three of these preconditions here. This + // expansion is only used if `is_repr_c_struct`, we enumerate + // the fields in order, and we extract the values of `align(N)` + // and `packed(N)`. + const LAYOUT: ::zerocopy::DstLayout = { + use ::zerocopy::macro_util::core_reexport::num::NonZeroUsize; + use ::zerocopy::{DstLayout, KnownLayout}; + + let repr_align = #repr_align; + let repr_packed = #repr_packed; + + DstLayout::new_zst(repr_align) + #(.extend(DstLayout::for_type::<#leading_fields>(), repr_packed))* + .extend(<#trailing_field as KnownLayout>::LAYOUT, repr_packed) + .pad_to_align() + }; + + // SAFETY: + // - The recursive call to `raw_from_ptr_len` preserves both address and provenance. + // - The `as` cast preserves both address and provenance. + // - `NonNull::new_unchecked` preserves both address and provenance. + #[inline(always)] + fn raw_from_ptr_len( + bytes: ::zerocopy::macro_util::core_reexport::ptr::NonNull, + elems: usize, + ) -> ::zerocopy::macro_util::core_reexport::ptr::NonNull { + use ::zerocopy::{KnownLayout}; + let trailing = <#trailing_field as KnownLayout>::raw_from_ptr_len(bytes, elems); + let slf = trailing.as_ptr() as *mut Self; + // SAFETY: Constructed from `trailing`, which is non-null. + unsafe { ::zerocopy::macro_util::core_reexport::ptr::NonNull::new_unchecked(slf) } + } + ), + ) + } else { + // For enums, unions, and non-`repr(C)` structs, we require that + // `Self` is sized, and as a result don't need to reason about the + // internals of the type. + ( + true, + quote!( + // SAFETY: `LAYOUT` is guaranteed to accurately describe the + // layout of `Self`, because that is the documented safety + // contract of `DstLayout::for_type`. + const LAYOUT: ::zerocopy::DstLayout = ::zerocopy::DstLayout::for_type::(); + + // SAFETY: `.cast` preserves address and provenance. + // + // TODO(#429): Add documentation to `.cast` that promises that + // it preserves provenance. + #[inline(always)] + fn raw_from_ptr_len( + bytes: ::zerocopy::macro_util::core_reexport::ptr::NonNull, + _elems: usize, + ) -> ::zerocopy::macro_util::core_reexport::ptr::NonNull { + bytes.cast::() + } + ), + ) + }; + + match &ast.data { + Data::Struct(strct) => { + let require_trait_bound_on_field_types = if require_self_sized { + RequireBoundedFields::No + } else { + RequireBoundedFields::Trailing + }; + + // A bound on the trailing field is required, since structs are + // unsized if their trailing field is unsized. Reflecting the layout + // of an usized trailing field requires that the field is + // `KnownLayout`. + impl_block( + &ast, + strct, + Trait::KnownLayout, + require_trait_bound_on_field_types, + require_self_sized, + None, + Some(extras), + ) + } + Data::Enum(enm) => { + // A bound on the trailing field is not required, since enums cannot + // currently be unsized. + impl_block( + &ast, + enm, + Trait::KnownLayout, + RequireBoundedFields::No, + true, + None, + Some(extras), + ) + } + Data::Union(unn) => { + // A bound on the trailing field is not required, since unions + // cannot currently be unsized. + impl_block( + &ast, + unn, + Trait::KnownLayout, + RequireBoundedFields::No, + true, + None, + Some(extras), + ) + } + } + .into() +} + +#[proc_macro_derive(FromZeroes)] +pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + match &ast.data { + Data::Struct(strct) => derive_from_zeroes_struct(&ast, strct), + Data::Enum(enm) => derive_from_zeroes_enum(&ast, enm), + Data::Union(unn) => derive_from_zeroes_union(&ast, unn), + } + .into() +} + +#[proc_macro_derive(FromBytes)] +pub fn derive_from_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + match &ast.data { + Data::Struct(strct) => derive_from_bytes_struct(&ast, strct), + Data::Enum(enm) => derive_from_bytes_enum(&ast, enm), + Data::Union(unn) => derive_from_bytes_union(&ast, unn), + } + .into() +} + +#[proc_macro_derive(AsBytes)] +pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + match &ast.data { + Data::Struct(strct) => derive_as_bytes_struct(&ast, strct), + Data::Enum(enm) => derive_as_bytes_enum(&ast, enm), + Data::Union(unn) => derive_as_bytes_union(&ast, unn), + } + .into() +} + +#[proc_macro_derive(Unaligned)] +pub fn derive_unaligned(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + match &ast.data { + Data::Struct(strct) => derive_unaligned_struct(&ast, strct), + Data::Enum(enm) => derive_unaligned_enum(&ast, enm), + Data::Union(unn) => derive_unaligned_union(&ast, unn), + } + .into() +} + +const STRUCT_UNION_ALLOWED_REPR_COMBINATIONS: &[&[StructRepr]] = &[ + &[StructRepr::C], + &[StructRepr::Transparent], + &[StructRepr::Packed], + &[StructRepr::C, StructRepr::Packed], +]; + +// A struct is `FromZeroes` if: +// - all fields are `FromZeroes` + +fn derive_from_zeroes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream { + impl_block(ast, strct, Trait::FromZeroes, RequireBoundedFields::Yes, false, None, None) +} + +// An enum is `FromZeroes` if: +// - all of its variants are fieldless +// - one of the variants has a discriminant of `0` + +fn derive_from_zeroes_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream { + if !enm.is_c_like() { + return Error::new_spanned(ast, "only C-like enums can implement FromZeroes") + .to_compile_error(); + } + + let has_explicit_zero_discriminant = + enm.variants.iter().filter_map(|v| v.discriminant.as_ref()).any(|(_, e)| { + if let Expr::Lit(ExprLit { lit: Lit::Int(i), .. }) = e { + i.base10_parse::().ok() == Some(0) + } else { + false + } + }); + // If the first variant of an enum does not specify its discriminant, it is set to zero: + // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations + let has_implicit_zero_discriminant = + enm.variants.iter().next().map(|v| v.discriminant.is_none()) == Some(true); + + if !has_explicit_zero_discriminant && !has_implicit_zero_discriminant { + return Error::new_spanned( + ast, + "FromZeroes only supported on enums with a variant that has a discriminant of `0`", + ) + .to_compile_error(); + } + + impl_block(ast, enm, Trait::FromZeroes, RequireBoundedFields::Yes, false, None, None) +} + +// Like structs, unions are `FromZeroes` if +// - all fields are `FromZeroes` + +fn derive_from_zeroes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream { + impl_block(ast, unn, Trait::FromZeroes, RequireBoundedFields::Yes, false, None, None) +} + +// A struct is `FromBytes` if: +// - all fields are `FromBytes` + +fn derive_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream { + impl_block(ast, strct, Trait::FromBytes, RequireBoundedFields::Yes, false, None, None) +} + +// An enum is `FromBytes` if: +// - Every possible bit pattern must be valid, which means that every bit +// pattern must correspond to a different enum variant. Thus, for an enum +// whose layout takes up N bytes, there must be 2^N variants. +// - Since we must know N, only representations which guarantee the layout's +// size are allowed. These are `repr(uN)` and `repr(iN)` (`repr(C)` implies an +// implementation-defined size). `usize` and `isize` technically guarantee the +// layout's size, but would require us to know how large those are on the +// target platform. This isn't terribly difficult - we could emit a const +// expression that could call `core::mem::size_of` in order to determine the +// size and check against the number of enum variants, but a) this would be +// platform-specific and, b) even on Rust's smallest bit width platform (32), +// this would require ~4 billion enum variants, which obviously isn't a thing. + +fn derive_from_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream { + if !enm.is_c_like() { + return Error::new_spanned(ast, "only C-like enums can implement FromBytes") + .to_compile_error(); + } + + let reprs = try_or_print!(ENUM_FROM_BYTES_CFG.validate_reprs(ast)); + + let variants_required = match reprs.as_slice() { + [EnumRepr::U8] | [EnumRepr::I8] => 1usize << 8, + [EnumRepr::U16] | [EnumRepr::I16] => 1usize << 16, + // `validate_reprs` has already validated that it's one of the preceding + // patterns. + _ => unreachable!(), + }; + if enm.variants.len() != variants_required { + return Error::new_spanned( + ast, + format!( + "FromBytes only supported on {} enum with {} variants", + reprs[0], variants_required + ), + ) + .to_compile_error(); + } + + impl_block(ast, enm, Trait::FromBytes, RequireBoundedFields::Yes, false, None, None) +} + +#[rustfmt::skip] +const ENUM_FROM_BYTES_CFG: Config = { + use EnumRepr::*; + Config { + allowed_combinations_message: r#"FromBytes requires repr of "u8", "u16", "i8", or "i16""#, + derive_unaligned: false, + allowed_combinations: &[ + &[U8], + &[U16], + &[I8], + &[I16], + ], + disallowed_but_legal_combinations: &[ + &[C], + &[U32], + &[I32], + &[U64], + &[I64], + &[Usize], + &[Isize], + ], + } +}; + +// Like structs, unions are `FromBytes` if +// - all fields are `FromBytes` + +fn derive_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream { + impl_block(ast, unn, Trait::FromBytes, RequireBoundedFields::Yes, false, None, None) +} + +// A struct is `AsBytes` if: +// - all fields are `AsBytes` +// - `repr(C)` or `repr(transparent)` and +// - no padding (size of struct equals sum of size of field types) +// - `repr(packed)` + +fn derive_as_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream { + let reprs = try_or_print!(STRUCT_UNION_AS_BYTES_CFG.validate_reprs(ast)); + let is_transparent = reprs.contains(&StructRepr::Transparent); + let is_packed = reprs.contains(&StructRepr::Packed); + + // TODO(#10): Support type parameters for non-transparent, non-packed + // structs. + if !ast.generics.params.is_empty() && !is_transparent && !is_packed { + return Error::new( + Span::call_site(), + "unsupported on generic structs that are not repr(transparent) or repr(packed)", + ) + .to_compile_error(); + } + + // We don't need a padding check if the struct is repr(transparent) or + // repr(packed). + // - repr(transparent): The layout and ABI of the whole struct is the same + // as its only non-ZST field (meaning there's no padding outside of that + // field) and we require that field to be `AsBytes` (meaning there's no + // padding in that field). + // - repr(packed): Any inter-field padding bytes are removed, meaning that + // any padding bytes would need to come from the fields, all of which + // we require to be `AsBytes` (meaning they don't have any padding). + let padding_check = if is_transparent || is_packed { None } else { Some(PaddingCheck::Struct) }; + impl_block(ast, strct, Trait::AsBytes, RequireBoundedFields::Yes, false, padding_check, None) +} + +const STRUCT_UNION_AS_BYTES_CFG: Config = Config { + // Since `disallowed_but_legal_combinations` is empty, this message will + // never actually be emitted. + allowed_combinations_message: r#"AsBytes requires either a) repr "C" or "transparent" with all fields implementing AsBytes or, b) repr "packed""#, + derive_unaligned: false, + allowed_combinations: STRUCT_UNION_ALLOWED_REPR_COMBINATIONS, + disallowed_but_legal_combinations: &[], +}; + +// An enum is `AsBytes` if it is C-like and has a defined repr. + +fn derive_as_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream { + if !enm.is_c_like() { + return Error::new_spanned(ast, "only C-like enums can implement AsBytes") + .to_compile_error(); + } + + // We don't care what the repr is; we only care that it is one of the + // allowed ones. + let _: Vec = try_or_print!(ENUM_AS_BYTES_CFG.validate_reprs(ast)); + impl_block(ast, enm, Trait::AsBytes, RequireBoundedFields::No, false, None, None) +} + +#[rustfmt::skip] +const ENUM_AS_BYTES_CFG: Config = { + use EnumRepr::*; + Config { + // Since `disallowed_but_legal_combinations` is empty, this message will + // never actually be emitted. + allowed_combinations_message: r#"AsBytes requires repr of "C", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", or "isize""#, + derive_unaligned: false, + allowed_combinations: &[ + &[C], + &[U8], + &[U16], + &[I8], + &[I16], + &[U32], + &[I32], + &[U64], + &[I64], + &[Usize], + &[Isize], + ], + disallowed_but_legal_combinations: &[], + } +}; + +// A union is `AsBytes` if: +// - all fields are `AsBytes` +// - `repr(C)`, `repr(transparent)`, or `repr(packed)` +// - no padding (size of union equals size of each field type) + +fn derive_as_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream { + // TODO(#10): Support type parameters. + if !ast.generics.params.is_empty() { + return Error::new(Span::call_site(), "unsupported on types with type parameters") + .to_compile_error(); + } + + try_or_print!(STRUCT_UNION_AS_BYTES_CFG.validate_reprs(ast)); + + impl_block( + ast, + unn, + Trait::AsBytes, + RequireBoundedFields::Yes, + false, + Some(PaddingCheck::Union), + None, + ) +} + +// A struct is `Unaligned` if: +// - `repr(align)` is no more than 1 and either +// - `repr(C)` or `repr(transparent)` and +// - all fields `Unaligned` +// - `repr(packed)` + +fn derive_unaligned_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream { + let reprs = try_or_print!(STRUCT_UNION_UNALIGNED_CFG.validate_reprs(ast)); + let require_trait_bounds_on_field_types = (!reprs.contains(&StructRepr::Packed)).into(); + + impl_block(ast, strct, Trait::Unaligned, require_trait_bounds_on_field_types, false, None, None) +} + +const STRUCT_UNION_UNALIGNED_CFG: Config = Config { + // Since `disallowed_but_legal_combinations` is empty, this message will + // never actually be emitted. + allowed_combinations_message: r#"Unaligned requires either a) repr "C" or "transparent" with all fields implementing Unaligned or, b) repr "packed""#, + derive_unaligned: true, + allowed_combinations: STRUCT_UNION_ALLOWED_REPR_COMBINATIONS, + disallowed_but_legal_combinations: &[], +}; + +// An enum is `Unaligned` if: +// - No `repr(align(N > 1))` +// - `repr(u8)` or `repr(i8)` + +fn derive_unaligned_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream { + if !enm.is_c_like() { + return Error::new_spanned(ast, "only C-like enums can implement Unaligned") + .to_compile_error(); + } + + // The only valid reprs are `u8` and `i8`, and optionally `align(1)`. We + // don't actually care what the reprs are so long as they satisfy that + // requirement. + let _: Vec = try_or_print!(ENUM_UNALIGNED_CFG.validate_reprs(ast)); + + // C-like enums cannot currently have type parameters, so this value of true + // for `require_trait_bound_on_field_types` doesn't really do anything. But + // it's marginally more future-proof in case that restriction is lifted in + // the future. + impl_block(ast, enm, Trait::Unaligned, RequireBoundedFields::Yes, false, None, None) +} + +#[rustfmt::skip] +const ENUM_UNALIGNED_CFG: Config = { + use EnumRepr::*; + Config { + allowed_combinations_message: + r#"Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))"#, + derive_unaligned: true, + allowed_combinations: &[ + &[U8], + &[I8], + ], + disallowed_but_legal_combinations: &[ + &[C], + &[U16], + &[U32], + &[U64], + &[Usize], + &[I16], + &[I32], + &[I64], + &[Isize], + ], + } +}; + +// Like structs, a union is `Unaligned` if: +// - `repr(align)` is no more than 1 and either +// - `repr(C)` or `repr(transparent)` and +// - all fields `Unaligned` +// - `repr(packed)` + +fn derive_unaligned_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream { + let reprs = try_or_print!(STRUCT_UNION_UNALIGNED_CFG.validate_reprs(ast)); + let require_trait_bound_on_field_types = (!reprs.contains(&StructRepr::Packed)).into(); + + impl_block(ast, unn, Trait::Unaligned, require_trait_bound_on_field_types, false, None, None) +} + +// This enum describes what kind of padding check needs to be generated for the +// associated impl. +enum PaddingCheck { + // Check that the sum of the fields' sizes exactly equals the struct's size. + Struct, + // Check that the size of each field exactly equals the union's size. + Union, +} + +impl PaddingCheck { + /// Returns the ident of the macro to call in order to validate that a type + /// passes the padding check encoded by `PaddingCheck`. + fn validator_macro_ident(&self) -> Ident { + let s = match self { + PaddingCheck::Struct => "struct_has_padding", + PaddingCheck::Union => "union_has_padding", + }; + + Ident::new(s, Span::call_site()) + } +} + +#[derive(Debug, Eq, PartialEq)] +enum Trait { + KnownLayout, + FromZeroes, + FromBytes, + AsBytes, + Unaligned, +} + +impl Trait { + fn ident(&self) -> Ident { + Ident::new(format!("{:?}", self).as_str(), Span::call_site()) + } +} + +#[derive(Debug, Eq, PartialEq)] +enum RequireBoundedFields { + No, + Yes, + Trailing, +} + +impl From for RequireBoundedFields { + fn from(do_require: bool) -> Self { + match do_require { + true => Self::Yes, + false => Self::No, + } + } +} + +fn impl_block( + input: &DeriveInput, + data: &D, + trt: Trait, + require_trait_bound_on_field_types: RequireBoundedFields, + require_self_sized: bool, + padding_check: Option, + extras: Option, +) -> proc_macro2::TokenStream { + // In this documentation, we will refer to this hypothetical struct: + // + // #[derive(FromBytes)] + // struct Foo + // where + // T: Copy, + // I: Clone, + // I::Item: Clone, + // { + // a: u8, + // b: T, + // c: I::Item, + // } + // + // We extract the field types, which in this case are `u8`, `T`, and + // `I::Item`. We re-use the existing parameters and where clauses. If + // `require_trait_bound == true` (as it is for `FromBytes), we add where + // bounds for each field's type: + // + // impl FromBytes for Foo + // where + // T: Copy, + // I: Clone, + // I::Item: Clone, + // T: FromBytes, + // I::Item: FromBytes, + // { + // } + // + // NOTE: It is standard practice to only emit bounds for the type parameters + // themselves, not for field types based on those parameters (e.g., `T` vs + // `T::Foo`). For a discussion of why this is standard practice, see + // https://github.com/rust-lang/rust/issues/26925. + // + // The reason we diverge from this standard is that doing it that way for us + // would be unsound. E.g., consider a type, `T` where `T: FromBytes` but + // `T::Foo: !FromBytes`. It would not be sound for us to accept a type with + // a `T::Foo` field as `FromBytes` simply because `T: FromBytes`. + // + // While there's no getting around this requirement for us, it does have the + // pretty serious downside that, when lifetimes are involved, the trait + // solver ties itself in knots: + // + // #[derive(Unaligned)] + // #[repr(C)] + // struct Dup<'a, 'b> { + // a: PhantomData<&'a u8>, + // b: PhantomData<&'b u8>, + // } + // + // error[E0283]: type annotations required: cannot resolve `core::marker::PhantomData<&'a u8>: zerocopy::Unaligned` + // --> src/main.rs:6:10 + // | + // 6 | #[derive(Unaligned)] + // | ^^^^^^^^^ + // | + // = note: required by `zerocopy::Unaligned` + + let type_ident = &input.ident; + let trait_ident = trt.ident(); + let field_types = data.field_types(); + + let bound_tt = |ty| parse_quote!(#ty: ::zerocopy::#trait_ident); + let field_type_bounds: Vec<_> = match (require_trait_bound_on_field_types, &field_types[..]) { + (RequireBoundedFields::Yes, _) => field_types.iter().map(bound_tt).collect(), + (RequireBoundedFields::No, _) | (RequireBoundedFields::Trailing, []) => vec![], + (RequireBoundedFields::Trailing, [.., last]) => vec![bound_tt(last)], + }; + + // Don't bother emitting a padding check if there are no fields. + #[allow(unstable_name_collisions)] // See `BoolExt` below + let padding_check_bound = padding_check.and_then(|check| (!field_types.is_empty()).then_some(check)).map(|check| { + let fields = field_types.iter(); + let validator_macro = check.validator_macro_ident(); + parse_quote!( + ::zerocopy::macro_util::HasPadding<#type_ident, {::zerocopy::#validator_macro!(#type_ident, #(#fields),*)}>: + ::zerocopy::macro_util::ShouldBe + ) + }); + + let self_sized_bound = if require_self_sized { Some(parse_quote!(Self: Sized)) } else { None }; + + let bounds = input + .generics + .where_clause + .as_ref() + .map(|where_clause| where_clause.predicates.iter()) + .into_iter() + .flatten() + .chain(field_type_bounds.iter()) + .chain(padding_check_bound.iter()) + .chain(self_sized_bound.iter()); + + // The parameters with trait bounds, but without type defaults. + let params = input.generics.params.clone().into_iter().map(|mut param| { + match &mut param { + GenericParam::Type(ty) => ty.default = None, + GenericParam::Const(cnst) => cnst.default = None, + GenericParam::Lifetime(_) => {} + } + quote!(#param) + }); + + // The identifiers of the parameters without trait bounds or type defaults. + let param_idents = input.generics.params.iter().map(|param| match param { + GenericParam::Type(ty) => { + let ident = &ty.ident; + quote!(#ident) + } + GenericParam::Lifetime(l) => { + let ident = &l.lifetime; + quote!(#ident) + } + GenericParam::Const(cnst) => { + let ident = &cnst.ident; + quote!({#ident}) + } + }); + + quote! { + // TODO(#553): Add a test that generates a warning when + // `#[allow(deprecated)]` isn't present. + #[allow(deprecated)] + unsafe impl < #(#params),* > ::zerocopy::#trait_ident for #type_ident < #(#param_idents),* > + where + #(#bounds,)* + { + fn only_derive_is_allowed_to_implement_this_trait() {} + + #extras + } + } +} + +fn print_all_errors(errors: Vec) -> proc_macro2::TokenStream { + errors.iter().map(Error::to_compile_error).collect() +} + +// A polyfill for `Option::then_some`, which was added after our MSRV. +// +// TODO(#67): Remove this once our MSRV is >= 1.62. +trait BoolExt { + fn then_some(self, t: T) -> Option; +} + +impl BoolExt for bool { + fn then_some(self, t: T) -> Option { + if self { + Some(t) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_config_repr_orderings() { + // Validate that the repr lists in the various configs are in the + // canonical order. If they aren't, then our algorithm to look up in + // those lists won't work. + + // TODO(https://github.com/rust-lang/rust/issues/53485): Remove once + // `Vec::is_sorted` is stabilized. + fn is_sorted_and_deduped(ts: &[T]) -> bool { + let mut sorted = ts.to_vec(); + sorted.sort(); + sorted.dedup(); + ts == sorted.as_slice() + } + + fn elements_are_sorted_and_deduped(lists: &[&[T]]) -> bool { + lists.iter().all(|list| is_sorted_and_deduped(list)) + } + + fn config_is_sorted(config: &Config) -> bool { + elements_are_sorted_and_deduped(config.allowed_combinations) + && elements_are_sorted_and_deduped(config.disallowed_but_legal_combinations) + } + + assert!(config_is_sorted(&STRUCT_UNION_UNALIGNED_CFG)); + assert!(config_is_sorted(&ENUM_FROM_BYTES_CFG)); + assert!(config_is_sorted(&ENUM_UNALIGNED_CFG)); + } + + #[test] + fn test_config_repr_no_overlap() { + // Validate that no set of reprs appears in both the + // `allowed_combinations` and `disallowed_but_legal_combinations` lists. + + fn overlap(a: &[T], b: &[T]) -> bool { + a.iter().any(|elem| b.contains(elem)) + } + + fn config_overlaps(config: &Config) -> bool { + overlap(config.allowed_combinations, config.disallowed_but_legal_combinations) + } + + assert!(!config_overlaps(&STRUCT_UNION_UNALIGNED_CFG)); + assert!(!config_overlaps(&ENUM_FROM_BYTES_CFG)); + assert!(!config_overlaps(&ENUM_UNALIGNED_CFG)); + } +} diff --git a/third_party/rust/zerocopy-derive/src/repr.rs b/third_party/rust/zerocopy-derive/src/repr.rs new file mode 100644 index 0000000000..f4f2788685 --- /dev/null +++ b/third_party/rust/zerocopy-derive/src/repr.rs @@ -0,0 +1,311 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use core::fmt::{self, Display, Formatter}; + +use { + proc_macro2::Span, + syn::punctuated::Punctuated, + syn::spanned::Spanned, + syn::token::Comma, + syn::{Attribute, DeriveInput, Error, LitInt, Meta}, +}; + +pub struct Config { + // A human-readable message describing what combinations of representations + // are allowed. This will be printed to the user if they use an invalid + // combination. + pub allowed_combinations_message: &'static str, + // Whether we're checking as part of `derive(Unaligned)`. If not, we can + // ignore `repr(align)`, which makes the code (and the list of valid repr + // combinations we have to enumerate) somewhat simpler. If we're checking + // for `Unaligned`, then in addition to checking against illegal + // combinations, we also check to see if there exists a `repr(align(N > 1))` + // attribute. + pub derive_unaligned: bool, + // Combinations which are valid for the trait. + pub allowed_combinations: &'static [&'static [Repr]], + // Combinations which are not valid for the trait, but are legal according + // to Rust. Any combination not in this or `allowed_combinations` is either + // illegal according to Rust or the behavior is unspecified. If the behavior + // is unspecified, it might become specified in the future, and that + // specification might not play nicely with our requirements. Thus, we + // reject combinations with unspecified behavior in addition to illegal + // combinations. + pub disallowed_but_legal_combinations: &'static [&'static [Repr]], +} + +impl Config { + /// Validate that `input`'s representation attributes conform to the + /// requirements specified by this `Config`. + /// + /// `validate_reprs` extracts the `repr` attributes, validates that they + /// conform to the requirements of `self`, and returns them. Regardless of + /// whether `align` attributes are considered during validation, they are + /// stripped out of the returned value since no callers care about them. + pub fn validate_reprs(&self, input: &DeriveInput) -> Result, Vec> { + let mut metas_reprs = reprs(&input.attrs)?; + metas_reprs.sort_by(|a: &(_, R), b| a.1.partial_cmp(&b.1).unwrap()); + + if self.derive_unaligned { + if let Some((meta, _)) = + metas_reprs.iter().find(|&repr: &&(_, R)| repr.1.is_align_gt_one()) + { + return Err(vec![Error::new_spanned( + meta, + "cannot derive Unaligned with repr(align(N > 1))", + )]); + } + } + + let mut metas = Vec::new(); + let mut reprs = Vec::new(); + metas_reprs.into_iter().filter(|(_, repr)| !repr.is_align()).for_each(|(meta, repr)| { + metas.push(meta); + reprs.push(repr) + }); + + if reprs.is_empty() { + // Use `Span::call_site` to report this error on the + // `#[derive(...)]` itself. + return Err(vec![Error::new(Span::call_site(), "must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout")]); + } + + let initial_sp = metas[0].span(); + let err_span = metas.iter().skip(1).try_fold(initial_sp, |sp, meta| sp.join(meta.span())); + + if self.allowed_combinations.contains(&reprs.as_slice()) { + Ok(reprs) + } else if self.disallowed_but_legal_combinations.contains(&reprs.as_slice()) { + Err(vec![Error::new( + err_span.unwrap_or_else(|| input.span()), + self.allowed_combinations_message, + )]) + } else { + Err(vec![Error::new( + err_span.unwrap_or_else(|| input.span()), + "conflicting representation hints", + )]) + } + } +} + +// The type of valid reprs for a particular kind (enum, struct, union). +pub trait KindRepr: 'static + Sized + Ord { + fn is_align(&self) -> bool; + fn is_align_gt_one(&self) -> bool; + fn parse(meta: &Meta) -> syn::Result; +} + +// Defines an enum for reprs which are valid for a given kind (structs, enums, +// etc), and provide implementations of `KindRepr`, `Ord`, and `Display`, and +// those traits' super-traits. +macro_rules! define_kind_specific_repr { + ($type_name:expr, $repr_name:ident, [ $($repr_variant:ident),* ] , [ $($repr_variant_aligned:ident),* ]) => { + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum $repr_name { + $($repr_variant,)* + $($repr_variant_aligned(u64),)* + } + + impl KindRepr for $repr_name { + fn is_align(&self) -> bool { + match self { + $($repr_name::$repr_variant_aligned(_) => true,)* + _ => false, + } + } + + fn is_align_gt_one(&self) -> bool { + match self { + // `packed(n)` only lowers alignment + $repr_name::Align(n) => n > &1, + _ => false, + } + } + + fn parse(meta: &Meta) -> syn::Result<$repr_name> { + match Repr::from_meta(meta)? { + $(Repr::$repr_variant => Ok($repr_name::$repr_variant),)* + $(Repr::$repr_variant_aligned(u) => Ok($repr_name::$repr_variant_aligned(u)),)* + _ => Err(Error::new_spanned(meta, concat!("unsupported representation for deriving FromBytes, AsBytes, or Unaligned on ", $type_name))) + } + } + } + + // Define a stable ordering so we can canonicalize lists of reprs. The + // ordering itself doesn't matter so long as it's stable. + impl PartialOrd for $repr_name { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl Ord for $repr_name { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + format!("{:?}", self).cmp(&format!("{:?}", other)) + } + } + + impl core::fmt::Display for $repr_name { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + $($repr_name::$repr_variant => Repr::$repr_variant,)* + $($repr_name::$repr_variant_aligned(u) => Repr::$repr_variant_aligned(*u),)* + }.fmt(f) + } + } + } +} + +define_kind_specific_repr!("a struct", StructRepr, [C, Transparent, Packed], [Align, PackedN]); +define_kind_specific_repr!( + "an enum", + EnumRepr, + [C, U8, U16, U32, U64, Usize, I8, I16, I32, I64, Isize], + [Align] +); + +// All representations known to Rust. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum Repr { + U8, + U16, + U32, + U64, + Usize, + I8, + I16, + I32, + I64, + Isize, + C, + Transparent, + Packed, + PackedN(u64), + Align(u64), +} + +impl Repr { + fn from_meta(meta: &Meta) -> Result { + let (path, list) = match meta { + Meta::Path(path) => (path, None), + Meta::List(list) => (&list.path, Some(list)), + _ => return Err(Error::new_spanned(meta, "unrecognized representation hint")), + }; + + let ident = path + .get_ident() + .ok_or_else(|| Error::new_spanned(meta, "unrecognized representation hint"))?; + + Ok(match (ident.to_string().as_str(), list) { + ("u8", None) => Repr::U8, + ("u16", None) => Repr::U16, + ("u32", None) => Repr::U32, + ("u64", None) => Repr::U64, + ("usize", None) => Repr::Usize, + ("i8", None) => Repr::I8, + ("i16", None) => Repr::I16, + ("i32", None) => Repr::I32, + ("i64", None) => Repr::I64, + ("isize", None) => Repr::Isize, + ("C", None) => Repr::C, + ("transparent", None) => Repr::Transparent, + ("packed", None) => Repr::Packed, + ("packed", Some(list)) => { + Repr::PackedN(list.parse_args::()?.base10_parse::()?) + } + ("align", Some(list)) => { + Repr::Align(list.parse_args::()?.base10_parse::()?) + } + _ => return Err(Error::new_spanned(meta, "unrecognized representation hint")), + }) + } +} + +impl KindRepr for Repr { + fn is_align(&self) -> bool { + false + } + + fn is_align_gt_one(&self) -> bool { + false + } + + fn parse(meta: &Meta) -> syn::Result { + Self::from_meta(meta) + } +} + +impl Display for Repr { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { + if let Repr::Align(n) = self { + return write!(f, "repr(align({}))", n); + } + if let Repr::PackedN(n) = self { + return write!(f, "repr(packed({}))", n); + } + write!( + f, + "repr({})", + match self { + Repr::U8 => "u8", + Repr::U16 => "u16", + Repr::U32 => "u32", + Repr::U64 => "u64", + Repr::Usize => "usize", + Repr::I8 => "i8", + Repr::I16 => "i16", + Repr::I32 => "i32", + Repr::I64 => "i64", + Repr::Isize => "isize", + Repr::C => "C", + Repr::Transparent => "transparent", + Repr::Packed => "packed", + _ => unreachable!(), + } + ) + } +} + +pub(crate) fn reprs(attrs: &[Attribute]) -> Result, Vec> { + let mut reprs = Vec::new(); + let mut errors = Vec::new(); + for attr in attrs { + // Ignore documentation attributes. + if attr.path().is_ident("doc") { + continue; + } + if let Meta::List(ref meta_list) = attr.meta { + if meta_list.path.is_ident("repr") { + let parsed: Punctuated = + match meta_list.parse_args_with(Punctuated::parse_terminated) { + Ok(parsed) => parsed, + Err(_) => { + errors.push(Error::new_spanned( + &meta_list.tokens, + "unrecognized representation hint", + )); + continue; + } + }; + for meta in parsed { + match R::parse(&meta) { + Ok(repr) => reprs.push((meta, repr)), + Err(err) => errors.push(err), + } + } + } + } + } + + if !errors.is_empty() { + return Err(errors); + } + Ok(reprs) +} diff --git a/third_party/rust/zerocopy-derive/tests/enum_as_bytes.rs b/third_party/rust/zerocopy-derive/tests/enum_as_bytes.rs new file mode 100644 index 0000000000..e305bc4cea --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/enum_as_bytes.rs @@ -0,0 +1,101 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +use {static_assertions::assert_impl_all, zerocopy::AsBytes}; + +// An enum is `AsBytes` if if has a defined repr. + +#[derive(AsBytes)] +#[repr(C)] +enum C { + A, +} + +assert_impl_all!(C: AsBytes); + +#[derive(AsBytes)] +#[repr(u8)] +enum U8 { + A, +} + +assert_impl_all!(U8: AsBytes); + +#[derive(AsBytes)] +#[repr(u16)] +enum U16 { + A, +} + +assert_impl_all!(U16: AsBytes); + +#[derive(AsBytes)] +#[repr(u32)] +enum U32 { + A, +} + +assert_impl_all!(U32: AsBytes); + +#[derive(AsBytes)] +#[repr(u64)] +enum U64 { + A, +} + +assert_impl_all!(U64: AsBytes); + +#[derive(AsBytes)] +#[repr(usize)] +enum Usize { + A, +} + +assert_impl_all!(Usize: AsBytes); + +#[derive(AsBytes)] +#[repr(i8)] +enum I8 { + A, +} + +assert_impl_all!(I8: AsBytes); + +#[derive(AsBytes)] +#[repr(i16)] +enum I16 { + A, +} + +assert_impl_all!(I16: AsBytes); + +#[derive(AsBytes)] +#[repr(i32)] +enum I32 { + A, +} + +assert_impl_all!(I32: AsBytes); + +#[derive(AsBytes)] +#[repr(i64)] +enum I64 { + A, +} + +assert_impl_all!(I64: AsBytes); + +#[derive(AsBytes)] +#[repr(isize)] +enum Isize { + A, +} + +assert_impl_all!(Isize: AsBytes); diff --git a/third_party/rust/zerocopy-derive/tests/enum_from_zeroes.rs b/third_party/rust/zerocopy-derive/tests/enum_from_zeroes.rs new file mode 100644 index 0000000000..c6bb675f52 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/enum_from_zeroes.rs @@ -0,0 +1,35 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +mod util; + +use {static_assertions::assert_impl_all, zerocopy::FromZeroes}; + +#[derive(FromZeroes)] +enum Foo { + A, +} + +assert_impl_all!(Foo: FromZeroes); + +#[derive(FromZeroes)] +enum Bar { + A = 0, +} + +assert_impl_all!(Bar: FromZeroes); + +#[derive(FromZeroes)] +enum Baz { + A = 1, + B = 0, +} + +assert_impl_all!(Baz: FromZeroes); diff --git a/third_party/rust/zerocopy-derive/tests/enum_known_layout.rs b/third_party/rust/zerocopy-derive/tests/enum_known_layout.rs new file mode 100644 index 0000000000..49a6765e53 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/enum_known_layout.rs @@ -0,0 +1,46 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#![allow(warnings)] + +mod util; + +use {core::marker::PhantomData, static_assertions::assert_impl_all, zerocopy::KnownLayout}; + +#[derive(KnownLayout)] +enum Foo { + A, +} + +assert_impl_all!(Foo: KnownLayout); + +#[derive(KnownLayout)] +enum Bar { + A = 0, +} + +assert_impl_all!(Bar: KnownLayout); + +#[derive(KnownLayout)] +enum Baz { + A = 1, + B = 0, +} + +assert_impl_all!(Baz: KnownLayout); + +// Deriving `KnownLayout` should work if the enum has bounded parameters. + +#[derive(KnownLayout)] +#[repr(C)] +enum WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + KnownLayout> +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + KnownLayout, +{ + Variant([T; N], PhantomData<&'a &'b ()>), +} + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: KnownLayout); diff --git a/third_party/rust/zerocopy-derive/tests/enum_unaligned.rs b/third_party/rust/zerocopy-derive/tests/enum_unaligned.rs new file mode 100644 index 0000000000..152ce276b8 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/enum_unaligned.rs @@ -0,0 +1,47 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +use {static_assertions::assert_impl_all, zerocopy::Unaligned}; + +// An enum is `Unaligned` if: +// - No `repr(align(N > 1))` +// - `repr(u8)` or `repr(i8)` + +#[derive(Unaligned)] +#[repr(u8)] +enum Foo { + A, +} + +assert_impl_all!(Foo: Unaligned); + +#[derive(Unaligned)] +#[repr(i8)] +enum Bar { + A, +} + +assert_impl_all!(Bar: Unaligned); + +#[derive(Unaligned)] +#[repr(u8, align(1))] +enum Baz { + A, +} + +assert_impl_all!(Baz: Unaligned); + +#[derive(Unaligned)] +#[repr(i8, align(1))] +enum Blah { + B, +} + +assert_impl_all!(Blah: Unaligned); diff --git a/third_party/rust/zerocopy-derive/tests/hygiene.rs b/third_party/rust/zerocopy-derive/tests/hygiene.rs new file mode 100644 index 0000000000..b7b838d6c3 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/hygiene.rs @@ -0,0 +1,43 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// Make sure that macro hygiene will ensure that when we reference "zerocopy", +// that will work properly even if they've renamed the crate and have not +// imported its traits. + +#![allow(warnings)] + +extern crate zerocopy as _zerocopy; + +#[macro_use] +mod util; + +use std::{marker::PhantomData, option::IntoIter}; + +use static_assertions::assert_impl_all; + +#[derive( + _zerocopy::KnownLayout, _zerocopy::FromZeroes, _zerocopy::FromBytes, _zerocopy::Unaligned, +)] +#[repr(C)] +struct TypeParams<'a, T, I: Iterator> { + a: T, + c: I::Item, + d: u8, + e: PhantomData<&'a [u8]>, + f: PhantomData<&'static str>, + g: PhantomData, +} + +assert_impl_all!( + TypeParams<'static, (), IntoIter<()>>: + _zerocopy::KnownLayout, + _zerocopy::FromZeroes, + _zerocopy::FromBytes, + _zerocopy::Unaligned +); diff --git a/third_party/rust/zerocopy-derive/tests/paths_and_modules.rs b/third_party/rust/zerocopy-derive/tests/paths_and_modules.rs new file mode 100644 index 0000000000..a01983b097 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/paths_and_modules.rs @@ -0,0 +1,38 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned}; + +// Ensure that types that are use'd and types that are referenced by path work. + +mod foo { + use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned}; + + #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + #[repr(C)] + pub struct Foo { + foo: u8, + } + + #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + #[repr(C)] + pub struct Bar { + bar: u8, + } +} + +use foo::Foo; + +#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] +#[repr(C)] +struct Baz { + foo: Foo, + bar: foo::Bar, +} diff --git a/third_party/rust/zerocopy-derive/tests/priv_in_pub.rs b/third_party/rust/zerocopy-derive/tests/priv_in_pub.rs new file mode 100644 index 0000000000..5f7d8749d3 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/priv_in_pub.rs @@ -0,0 +1,24 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use zerocopy::{AsBytes, FromBytes, FromZeroes, KnownLayout, Unaligned}; + +// These derives do not result in E0446 as of Rust 1.59.0, because of +// https://github.com/rust-lang/rust/pull/90586. +// +// This change eliminates one of the major downsides of emitting `where` +// bounds for field types (i.e., the emission of E0446 for private field +// types). + +#[derive(KnownLayout, AsBytes, FromZeroes, FromBytes, Unaligned)] +#[repr(C)] +pub struct Public(Private); + +#[derive(KnownLayout, AsBytes, FromZeroes, FromBytes, Unaligned)] +#[repr(C)] +struct Private(()); diff --git a/third_party/rust/zerocopy-derive/tests/struct_as_bytes.rs b/third_party/rust/zerocopy-derive/tests/struct_as_bytes.rs new file mode 100644 index 0000000000..3c71bf07b5 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/struct_as_bytes.rs @@ -0,0 +1,161 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +mod util; + +use std::{marker::PhantomData, mem::ManuallyDrop, option::IntoIter}; + +use {static_assertions::assert_impl_all, zerocopy::AsBytes}; + +use self::util::AU16; + +// A struct is `AsBytes` if: +// - all fields are `AsBytes` +// - `repr(C)` or `repr(transparent)` and +// - no padding (size of struct equals sum of size of field types) +// - `repr(packed)` + +#[derive(AsBytes)] +#[repr(C)] +struct CZst; + +assert_impl_all!(CZst: AsBytes); + +#[derive(AsBytes)] +#[repr(C)] +struct C { + a: u8, + b: u8, + c: AU16, +} + +assert_impl_all!(C: AsBytes); + +#[derive(AsBytes)] +#[repr(transparent)] +struct Transparent { + a: u8, + b: CZst, +} + +assert_impl_all!(Transparent: AsBytes); + +#[derive(AsBytes)] +#[repr(transparent)] +struct TransparentGeneric { + a: CZst, + b: T, +} + +assert_impl_all!(TransparentGeneric: AsBytes); +assert_impl_all!(TransparentGeneric<[u64]>: AsBytes); + +#[derive(AsBytes)] +#[repr(C, packed)] +struct CZstPacked; + +assert_impl_all!(CZstPacked: AsBytes); + +#[derive(AsBytes)] +#[repr(C, packed)] +struct CPacked { + a: u8, + // NOTE: The `u16` type is not guaranteed to have alignment 2, although it + // does on many platforms. However, to fix this would require a custom type + // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not + // allowed to transitively contain `#[repr(align(...))]` types. Thus, we + // have no choice but to use `u16` here. Luckily, these tests run in CI on + // platforms on which `u16` has alignment 2, so this isn't that big of a + // deal. + b: u16, +} + +assert_impl_all!(CPacked: AsBytes); + +#[derive(AsBytes)] +#[repr(C, packed(2))] +// The same caveats as for CPacked apply - we're assuming u64 is at least +// 4-byte aligned by default. Without packed(2), this should fail, as there +// would be padding between a/b assuming u64 is 4+ byte aligned. +struct CPacked2 { + a: u16, + b: u64, +} + +assert_impl_all!(CPacked2: AsBytes); + +#[derive(AsBytes)] +#[repr(C, packed)] +struct CPackedGeneric { + t: T, + // Unsized types stored in `repr(packed)` structs must not be dropped + // because dropping them in-place might be unsound depending on the + // alignment of the outer struct. Sized types can be dropped by first being + // moved to an aligned stack variable, but this isn't possible with unsized + // types. + u: ManuallyDrop, +} + +assert_impl_all!(CPackedGeneric: AsBytes); +assert_impl_all!(CPackedGeneric: AsBytes); + +#[derive(AsBytes)] +#[repr(packed)] +struct Packed { + a: u8, + // NOTE: The `u16` type is not guaranteed to have alignment 2, although it + // does on many platforms. However, to fix this would require a custom type + // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not + // allowed to transitively contain `#[repr(align(...))]` types. Thus, we + // have no choice but to use `u16` here. Luckily, these tests run in CI on + // platforms on which `u16` has alignment 2, so this isn't that big of a + // deal. + b: u16, +} + +assert_impl_all!(Packed: AsBytes); + +#[derive(AsBytes)] +#[repr(packed)] +struct PackedGeneric { + t: T, + // Unsized types stored in `repr(packed)` structs must not be dropped + // because dropping them in-place might be unsound depending on the + // alignment of the outer struct. Sized types can be dropped by first being + // moved to an aligned stack variable, but this isn't possible with unsized + // types. + u: ManuallyDrop, +} + +assert_impl_all!(PackedGeneric: AsBytes); +assert_impl_all!(PackedGeneric: AsBytes); + +#[derive(AsBytes)] +#[repr(transparent)] +struct Unsized { + a: [u8], +} + +assert_impl_all!(Unsized: AsBytes); + +// Deriving `AsBytes` should work if the struct has bounded parameters. + +#[derive(AsBytes)] +#[repr(transparent)] +struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + AsBytes>( + [T; N], + PhantomData<&'a &'b ()>, +) +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + AsBytes; + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: AsBytes); diff --git a/third_party/rust/zerocopy-derive/tests/struct_from_bytes.rs b/third_party/rust/zerocopy-derive/tests/struct_from_bytes.rs new file mode 100644 index 0000000000..98f03d1640 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/struct_from_bytes.rs @@ -0,0 +1,79 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +mod util; + +use std::{marker::PhantomData, option::IntoIter}; + +use { + static_assertions::assert_impl_all, + zerocopy::{FromBytes, FromZeroes}, +}; + +use crate::util::AU16; + +// A struct is `FromBytes` if: +// - all fields are `FromBytes` + +#[derive(FromZeroes, FromBytes)] +struct Zst; + +assert_impl_all!(Zst: FromBytes); + +#[derive(FromZeroes, FromBytes)] +struct One { + a: u8, +} + +assert_impl_all!(One: FromBytes); + +#[derive(FromZeroes, FromBytes)] +struct Two { + a: u8, + b: Zst, +} + +assert_impl_all!(Two: FromBytes); + +#[derive(FromZeroes, FromBytes)] +struct Unsized { + a: [u8], +} + +assert_impl_all!(Unsized: FromBytes); + +#[derive(FromZeroes, FromBytes)] +struct TypeParams<'a, T: ?Sized, I: Iterator> { + a: I::Item, + b: u8, + c: PhantomData<&'a [u8]>, + d: PhantomData<&'static str>, + e: PhantomData, + f: T, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromBytes); +assert_impl_all!(TypeParams<'static, AU16, IntoIter<()>>: FromBytes); +assert_impl_all!(TypeParams<'static, [AU16], IntoIter<()>>: FromBytes); + +// Deriving `FromBytes` should work if the struct has bounded parameters. + +#[derive(FromZeroes, FromBytes)] +#[repr(transparent)] +struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromBytes>( + [T; N], + PhantomData<&'a &'b ()>, +) +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + FromBytes; + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromBytes); diff --git a/third_party/rust/zerocopy-derive/tests/struct_from_zeroes.rs b/third_party/rust/zerocopy-derive/tests/struct_from_zeroes.rs new file mode 100644 index 0000000000..75d824594b --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/struct_from_zeroes.rs @@ -0,0 +1,77 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +#[macro_use] +mod util; + +use std::{marker::PhantomData, option::IntoIter}; + +use {static_assertions::assert_impl_all, zerocopy::FromZeroes}; + +use crate::util::AU16; + +// A struct is `FromZeroes` if: +// - all fields are `FromZeroes` + +#[derive(FromZeroes)] +struct Zst; + +assert_impl_all!(Zst: FromZeroes); + +#[derive(FromZeroes)] +struct One { + a: bool, +} + +assert_impl_all!(One: FromZeroes); + +#[derive(FromZeroes)] +struct Two { + a: bool, + b: Zst, +} + +assert_impl_all!(Two: FromZeroes); + +#[derive(FromZeroes)] +struct Unsized { + a: [u8], +} + +assert_impl_all!(Unsized: FromZeroes); + +#[derive(FromZeroes)] +struct TypeParams<'a, T: ?Sized, I: Iterator> { + a: I::Item, + b: u8, + c: PhantomData<&'a [u8]>, + d: PhantomData<&'static str>, + e: PhantomData, + f: T, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromZeroes); +assert_impl_all!(TypeParams<'static, AU16, IntoIter<()>>: FromZeroes); +assert_impl_all!(TypeParams<'static, [AU16], IntoIter<()>>: FromZeroes); + +// Deriving `FromZeroes` should work if the struct has bounded parameters. + +#[derive(FromZeroes)] +#[repr(transparent)] +struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromZeroes>( + [T; N], + PhantomData<&'a &'b ()>, +) +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + FromZeroes; + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromZeroes); diff --git a/third_party/rust/zerocopy-derive/tests/struct_known_layout.rs b/third_party/rust/zerocopy-derive/tests/struct_known_layout.rs new file mode 100644 index 0000000000..68d1284de9 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/struct_known_layout.rs @@ -0,0 +1,65 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#![allow(warnings)] + +#[macro_use] +mod util; + +use std::{marker::PhantomData, option::IntoIter}; + +use { + static_assertions::assert_impl_all, + zerocopy::{DstLayout, KnownLayout}, +}; + +use crate::util::AU16; + +#[derive(KnownLayout)] +struct Zst; + +assert_impl_all!(Zst: KnownLayout); + +#[derive(KnownLayout)] +struct One { + a: bool, +} + +assert_impl_all!(One: KnownLayout); + +#[derive(KnownLayout)] +struct Two { + a: bool, + b: Zst, +} + +assert_impl_all!(Two: KnownLayout); + +#[derive(KnownLayout)] +struct TypeParams<'a, T, I: Iterator> { + a: I::Item, + b: u8, + c: PhantomData<&'a [u8]>, + d: PhantomData<&'static str>, + e: PhantomData, + f: T, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: KnownLayout); +assert_impl_all!(TypeParams<'static, AU16, IntoIter<()>>: KnownLayout); + +// Deriving `KnownLayout` should work if the struct has bounded parameters. + +#[derive(KnownLayout)] +#[repr(C)] +struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + KnownLayout>( + [T; N], + PhantomData<&'a &'b ()>, +) +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + KnownLayout; + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: KnownLayout); diff --git a/third_party/rust/zerocopy-derive/tests/struct_unaligned.rs b/third_party/rust/zerocopy-derive/tests/struct_unaligned.rs new file mode 100644 index 0000000000..a7db4322a6 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/struct_unaligned.rs @@ -0,0 +1,100 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +mod util; + +use std::{marker::PhantomData, option::IntoIter}; + +use {static_assertions::assert_impl_all, zerocopy::Unaligned}; + +use crate::util::AU16; + +// A struct is `Unaligned` if: +// - `repr(align)` is no more than 1 and either +// - `repr(C)` or `repr(transparent)` and +// - all fields Unaligned +// - `repr(packed)` + +#[derive(Unaligned)] +#[repr(C)] +struct Foo { + a: u8, +} + +assert_impl_all!(Foo: Unaligned); + +#[derive(Unaligned)] +#[repr(transparent)] +struct Bar { + a: u8, +} + +assert_impl_all!(Bar: Unaligned); + +#[derive(Unaligned)] +#[repr(packed)] +struct Baz { + // NOTE: The `u16` type is not guaranteed to have alignment 2, although it + // does on many platforms. However, to fix this would require a custom type + // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not + // allowed to transitively contain `#[repr(align(...))]` types. Thus, we + // have no choice but to use `u16` here. Luckily, these tests run in CI on + // platforms on which `u16` has alignment 2, so this isn't that big of a + // deal. + a: u16, +} + +assert_impl_all!(Baz: Unaligned); + +#[derive(Unaligned)] +#[repr(C, align(1))] +struct FooAlign { + a: u8, +} + +assert_impl_all!(FooAlign: Unaligned); + +#[derive(Unaligned)] +#[repr(transparent)] +struct Unsized { + a: [u8], +} + +assert_impl_all!(Unsized: Unaligned); + +#[derive(Unaligned)] +#[repr(C)] +struct TypeParams<'a, T: ?Sized, I: Iterator> { + a: I::Item, + b: u8, + c: PhantomData<&'a [u8]>, + d: PhantomData<&'static str>, + e: PhantomData, + f: T, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: Unaligned); +assert_impl_all!(TypeParams<'static, u8, IntoIter<()>>: Unaligned); +assert_impl_all!(TypeParams<'static, [u8], IntoIter<()>>: Unaligned); + +// Deriving `Unaligned` should work if the struct has bounded parameters. + +#[derive(Unaligned)] +#[repr(transparent)] +struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + Unaligned>( + [T; N], + PhantomData<&'a &'b ()>, +) +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + Unaligned; + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: Unaligned); diff --git a/third_party/rust/zerocopy-derive/tests/trybuild.rs b/third_party/rust/zerocopy-derive/tests/trybuild.rs new file mode 100644 index 0000000000..3ea1c3bfb8 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/trybuild.rs @@ -0,0 +1,19 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[test] +#[cfg_attr(miri, ignore)] +fn ui() { + let version = testutil::ToolchainVersion::extract_from_pwd().unwrap(); + // See the doc comment on this method for an explanation of what this does + // and why we store source files in different directories. + let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning(); + + let t = trybuild::TestCases::new(); + t.compile_fail(format!("tests/{source_files_dirname}/*.rs")); +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.rs b/third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.rs new file mode 100644 index 0000000000..2084d921bf --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.rs @@ -0,0 +1,40 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use core::marker::PhantomData; + +use { + static_assertions::assert_impl_all, + zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned}, +}; + +use self::util::NotZerocopy; + +fn main() {} + +// Test generic transparent structs + +#[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] +#[repr(transparent)] +struct TransparentStruct { + inner: T, + _phantom: PhantomData<()>, +} + +// It should be legal to derive these traits on a transparent struct, but it +// must also ensure the traits are only implemented when the inner type +// implements them. +assert_impl_all!(TransparentStruct: FromZeroes); +assert_impl_all!(TransparentStruct: FromBytes); +assert_impl_all!(TransparentStruct: AsBytes); +assert_impl_all!(TransparentStruct: Unaligned); diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr b/third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr new file mode 100644 index 0000000000..3b228b1551 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr @@ -0,0 +1,71 @@ +error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied + --> tests/ui-msrv/derive_transparent.rs:37:1 + | +37 | assert_impl_all!(TransparentStruct: FromZeroes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy` + | +note: required because of the requirements on the impl of `FromZeroes` for `TransparentStruct` + --> tests/ui-msrv/derive_transparent.rs:27:19 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^^ +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-msrv/derive_transparent.rs:37:1 + | +37 | assert_impl_all!(TransparentStruct: FromZeroes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all` + = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-msrv/derive_transparent.rs:38:1 + | +38 | assert_impl_all!(TransparentStruct: FromBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | +note: required because of the requirements on the impl of `FromBytes` for `TransparentStruct` + --> tests/ui-msrv/derive_transparent.rs:27:31 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-msrv/derive_transparent.rs:38:1 + | +38 | assert_impl_all!(TransparentStruct: FromBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all` + = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-msrv/derive_transparent.rs:39:1 + | +39 | assert_impl_all!(TransparentStruct: AsBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | +note: required because of the requirements on the impl of `AsBytes` for `TransparentStruct` + --> tests/ui-msrv/derive_transparent.rs:27:10 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^ +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-msrv/derive_transparent.rs:39:1 + | +39 | assert_impl_all!(TransparentStruct: AsBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all` + = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied + --> tests/ui-msrv/derive_transparent.rs:40:1 + | +40 | assert_impl_all!(TransparentStruct: Unaligned); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` + | +note: required because of the requirements on the impl of `Unaligned` for `TransparentStruct` + --> tests/ui-msrv/derive_transparent.rs:27:42 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-msrv/derive_transparent.rs:40:1 + | +40 | assert_impl_all!(TransparentStruct: Unaligned); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all` + = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/enum.rs b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum.rs new file mode 100644 index 0000000000..31d5679d19 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum.rs @@ -0,0 +1,194 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// +// Generic errors +// + +#[derive(FromZeroes, FromBytes)] +#[repr("foo")] +enum Generic1 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(foo)] +enum Generic2 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(transparent)] +enum Generic3 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u8, u16)] +enum Generic4 { + A, +} + +#[derive(FromZeroes, FromBytes)] +enum Generic5 { + A, +} + +// +// FromZeroes errors +// + +#[derive(FromZeroes)] +enum FromZeroes1 { + A(u8), +} + +#[derive(FromZeroes)] +enum FromZeroes2 { + A, + B(u8), +} + +#[derive(FromZeroes)] +enum FromZeroes3 { + A = 1, + B, +} + +// +// FromBytes errors +// + +#[derive(FromZeroes, FromBytes)] +#[repr(C)] +enum FromBytes1 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(usize)] +enum FromBytes2 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(isize)] +enum FromBytes3 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u32)] +enum FromBytes4 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(i32)] +enum FromBytes5 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u64)] +enum FromBytes6 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(i64)] +enum FromBytes7 { + A, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C)] +enum Unaligned1 { + A, +} + +#[derive(Unaligned)] +#[repr(u16)] +enum Unaligned2 { + A, +} + +#[derive(Unaligned)] +#[repr(i16)] +enum Unaligned3 { + A, +} + +#[derive(Unaligned)] +#[repr(u32)] +enum Unaligned4 { + A, +} + +#[derive(Unaligned)] +#[repr(i32)] +enum Unaligned5 { + A, +} + +#[derive(Unaligned)] +#[repr(u64)] +enum Unaligned6 { + A, +} + +#[derive(Unaligned)] +#[repr(i64)] +enum Unaligned7 { + A, +} + +#[derive(Unaligned)] +#[repr(usize)] +enum Unaligned8 { + A, +} + +#[derive(Unaligned)] +#[repr(isize)] +enum Unaligned9 { + A, +} + +#[derive(Unaligned)] +#[repr(u8, align(2))] +enum Unaligned10 { + A, +} + +#[derive(Unaligned)] +#[repr(i8, align(2))] +enum Unaligned11 { + A, +} + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +enum Unaligned12 { + A, +} + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +enum Unaligned13 { + A, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/enum.stderr b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum.stderr new file mode 100644 index 0000000000..39bde3f9e3 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum.stderr @@ -0,0 +1,199 @@ +error: unrecognized representation hint + --> tests/ui-msrv/enum.rs:19:8 + | +19 | #[repr("foo")] + | ^^^^^ + +error: unrecognized representation hint + --> tests/ui-msrv/enum.rs:25:8 + | +25 | #[repr(foo)] + | ^^^ + +error: unsupported representation for deriving FromBytes, AsBytes, or Unaligned on an enum + --> tests/ui-msrv/enum.rs:31:8 + | +31 | #[repr(transparent)] + | ^^^^^^^^^^^ + +error: conflicting representation hints + --> tests/ui-msrv/enum.rs:37:1 + | +37 | #[repr(u8, u16)] + | ^ + +error: must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout + --> tests/ui-msrv/enum.rs:42:22 + | +42 | #[derive(FromZeroes, FromBytes)] + | ^^^^^^^^^ + | + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: only C-like enums can implement FromZeroes + --> tests/ui-msrv/enum.rs:52:1 + | +52 | / enum FromZeroes1 { +53 | | A(u8), +54 | | } + | |_^ + +error: only C-like enums can implement FromZeroes + --> tests/ui-msrv/enum.rs:57:1 + | +57 | / enum FromZeroes2 { +58 | | A, +59 | | B(u8), +60 | | } + | |_^ + +error: FromZeroes only supported on enums with a variant that has a discriminant of `0` + --> tests/ui-msrv/enum.rs:63:1 + | +63 | / enum FromZeroes3 { +64 | | A = 1, +65 | | B, +66 | | } + | |_^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-msrv/enum.rs:73:8 + | +73 | #[repr(C)] + | ^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-msrv/enum.rs:79:8 + | +79 | #[repr(usize)] + | ^^^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-msrv/enum.rs:85:8 + | +85 | #[repr(isize)] + | ^^^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-msrv/enum.rs:91:8 + | +91 | #[repr(u32)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-msrv/enum.rs:97:8 + | +97 | #[repr(i32)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-msrv/enum.rs:103:8 + | +103 | #[repr(u64)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-msrv/enum.rs:109:8 + | +109 | #[repr(i64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:119:8 + | +119 | #[repr(C)] + | ^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:125:8 + | +125 | #[repr(u16)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:131:8 + | +131 | #[repr(i16)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:137:8 + | +137 | #[repr(u32)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:143:8 + | +143 | #[repr(i32)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:149:8 + | +149 | #[repr(u64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:155:8 + | +155 | #[repr(i64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:161:8 + | +161 | #[repr(usize)] + | ^^^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-msrv/enum.rs:167:8 + | +167 | #[repr(isize)] + | ^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/enum.rs:173:12 + | +173 | #[repr(u8, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/enum.rs:179:12 + | +179 | #[repr(i8, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/enum.rs:185:18 + | +185 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/enum.rs:191:8 + | +191 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0565]: meta item in `repr` must be an identifier + --> tests/ui-msrv/enum.rs:19:8 + | +19 | #[repr("foo")] + | ^^^^^ + +error[E0552]: unrecognized representation hint + --> tests/ui-msrv/enum.rs:25:8 + | +25 | #[repr(foo)] + | ^^^ + +error[E0566]: conflicting representation hints + --> tests/ui-msrv/enum.rs:37:8 + | +37 | #[repr(u8, u16)] + | ^^ ^^^ + | + = note: `#[deny(conflicting_repr_hints)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.rs b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.rs new file mode 100644 index 0000000000..1b1bed31f3 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.rs @@ -0,0 +1,272 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +#[derive(FromBytes)] +#[repr(u8)] +enum Foo { + Variant0, + Variant1, + Variant2, + Variant3, + Variant4, + Variant5, + Variant6, + Variant7, + Variant8, + Variant9, + Variant10, + Variant11, + Variant12, + Variant13, + Variant14, + Variant15, + Variant16, + Variant17, + Variant18, + Variant19, + Variant20, + Variant21, + Variant22, + Variant23, + Variant24, + Variant25, + Variant26, + Variant27, + Variant28, + Variant29, + Variant30, + Variant31, + Variant32, + Variant33, + Variant34, + Variant35, + Variant36, + Variant37, + Variant38, + Variant39, + Variant40, + Variant41, + Variant42, + Variant43, + Variant44, + Variant45, + Variant46, + Variant47, + Variant48, + Variant49, + Variant50, + Variant51, + Variant52, + Variant53, + Variant54, + Variant55, + Variant56, + Variant57, + Variant58, + Variant59, + Variant60, + Variant61, + Variant62, + Variant63, + Variant64, + Variant65, + Variant66, + Variant67, + Variant68, + Variant69, + Variant70, + Variant71, + Variant72, + Variant73, + Variant74, + Variant75, + Variant76, + Variant77, + Variant78, + Variant79, + Variant80, + Variant81, + Variant82, + Variant83, + Variant84, + Variant85, + Variant86, + Variant87, + Variant88, + Variant89, + Variant90, + Variant91, + Variant92, + Variant93, + Variant94, + Variant95, + Variant96, + Variant97, + Variant98, + Variant99, + Variant100, + Variant101, + Variant102, + Variant103, + Variant104, + Variant105, + Variant106, + Variant107, + Variant108, + Variant109, + Variant110, + Variant111, + Variant112, + Variant113, + Variant114, + Variant115, + Variant116, + Variant117, + Variant118, + Variant119, + Variant120, + Variant121, + Variant122, + Variant123, + Variant124, + Variant125, + Variant126, + Variant127, + Variant128, + Variant129, + Variant130, + Variant131, + Variant132, + Variant133, + Variant134, + Variant135, + Variant136, + Variant137, + Variant138, + Variant139, + Variant140, + Variant141, + Variant142, + Variant143, + Variant144, + Variant145, + Variant146, + Variant147, + Variant148, + Variant149, + Variant150, + Variant151, + Variant152, + Variant153, + Variant154, + Variant155, + Variant156, + Variant157, + Variant158, + Variant159, + Variant160, + Variant161, + Variant162, + Variant163, + Variant164, + Variant165, + Variant166, + Variant167, + Variant168, + Variant169, + Variant170, + Variant171, + Variant172, + Variant173, + Variant174, + Variant175, + Variant176, + Variant177, + Variant178, + Variant179, + Variant180, + Variant181, + Variant182, + Variant183, + Variant184, + Variant185, + Variant186, + Variant187, + Variant188, + Variant189, + Variant190, + Variant191, + Variant192, + Variant193, + Variant194, + Variant195, + Variant196, + Variant197, + Variant198, + Variant199, + Variant200, + Variant201, + Variant202, + Variant203, + Variant204, + Variant205, + Variant206, + Variant207, + Variant208, + Variant209, + Variant210, + Variant211, + Variant212, + Variant213, + Variant214, + Variant215, + Variant216, + Variant217, + Variant218, + Variant219, + Variant220, + Variant221, + Variant222, + Variant223, + Variant224, + Variant225, + Variant226, + Variant227, + Variant228, + Variant229, + Variant230, + Variant231, + Variant232, + Variant233, + Variant234, + Variant235, + Variant236, + Variant237, + Variant238, + Variant239, + Variant240, + Variant241, + Variant242, + Variant243, + Variant244, + Variant245, + Variant246, + Variant247, + Variant248, + Variant249, + Variant250, + Variant251, + Variant252, + Variant253, + Variant254, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.stderr b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.stderr new file mode 100644 index 0000000000..ff828dccba --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.stderr @@ -0,0 +1,11 @@ +error: FromBytes only supported on repr(u8) enum with 256 variants + --> tests/ui-msrv/enum_from_bytes_u8_too_few.rs:15:1 + | +15 | / #[repr(u8)] +16 | | enum Foo { +17 | | Variant0, +18 | | Variant1, +... | +271 | | Variant254, +272 | | } + | |_^ diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.rs b/third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.rs new file mode 100644 index 0000000000..cd65a6ed2c --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.rs @@ -0,0 +1,75 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use self::util::{NotZerocopy, AU16}; +use zerocopy::KnownLayout; + +fn main() {} + +// These tests cause errors which are generated by a later compilation pass than +// the other errors we generate, and so if they're compiled in the same file, +// the compiler will never get to that pass, and so we won't get the errors. + +// +// FromZeroes errors +// + +#[derive(FromZeroes)] +struct FromZeroes1 { + value: NotZerocopy, +} + +// +// FromBytes errors +// + +#[derive(FromBytes)] +struct FromBytes1 { + value: NotZerocopy, +} + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes1 { + value: NotZerocopy, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C)] +struct Unaligned1 { + aligned: AU16, +} + +// This specifically tests a bug we had in an old version of the code in which +// the trait bound would only be enforced for the first field's type. +#[derive(Unaligned)] +#[repr(C)] +struct Unaligned2 { + unaligned: u8, + aligned: AU16, +} + +#[derive(Unaligned)] +#[repr(transparent)] +struct Unaligned3 { + aligned: AU16, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr b/third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr new file mode 100644 index 0000000000..39dbcd1866 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr @@ -0,0 +1,74 @@ +warning: unused import: `zerocopy::KnownLayout` + --> tests/ui-msrv/late_compile_pass.rs:16:5 + | +16 | use zerocopy::KnownLayout; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied + --> tests/ui-msrv/late_compile_pass.rs:28:10 + | +28 | #[derive(FromZeroes)] + | ^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy` + | + = help: see issue #48214 + = note: this error originates in the derive macro `FromZeroes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-msrv/late_compile_pass.rs:37:10 + | +37 | #[derive(FromBytes)] + | ^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | + = help: see issue #48214 + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `FromBytes1: FromZeroes` is not satisfied + --> tests/ui-msrv/late_compile_pass.rs:37:10 + | +37 | #[derive(FromBytes)] + | ^^^^^^^^^ the trait `FromZeroes` is not implemented for `FromBytes1` + | +note: required by a bound in `FromBytes` + --> $WORKSPACE/src/lib.rs + | + | pub unsafe trait FromBytes: FromZeroes { + | ^^^^^^^^^^ required by this bound in `FromBytes` + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-msrv/late_compile_pass.rs:46:10 + | +46 | #[derive(AsBytes)] + | ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-msrv/late_compile_pass.rs:56:10 + | +56 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: see issue #48214 + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-msrv/late_compile_pass.rs:64:10 + | +64 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: see issue #48214 + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-msrv/late_compile_pass.rs:71:10 + | +71 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: see issue #48214 + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs b/third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs new file mode 100644 index 0000000000..e0c4bc578d --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs @@ -0,0 +1,61 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::KnownLayout; + +fn main() {} + +// These tests cause errors which are generated by a later compilation pass than +// the other errors we generate, and so if they're compiled in the same file, +// the compiler will never get to that pass, and so we won't get the errors. + +// +// KnownLayout errors +// + +fn assert_kl(_: &T) {} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | Y | N | N | KL04 | +#[derive(KnownLayout)] +struct KL04(u8, T); + +fn test_kl04(kl: &KL04) { + assert_kl(kl); +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | Y | Y | N | KL06 | +#[derive(KnownLayout)] +struct KL06(u8, T); + +fn test_kl06(kl: &KL06) { + assert_kl(kl); +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | Y | N | N | KL12 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL12(u8, T); + +fn test_kl12(kl: &KL12) { + assert_kl(kl) +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | Y | N | Y | KL13 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL13(u8, T); + +fn test_kl13(t: T) -> impl KnownLayout { + KL13(0u8, t) +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr b/third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr new file mode 100644 index 0000000000..5aa2cde0aa --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr @@ -0,0 +1,104 @@ +error[E0277]: the trait bound `T: KnownLayout` is not satisfied + --> tests/ui-msrv/mid_compile_pass.rs:59:26 + | +59 | fn test_kl13(t: T) -> impl KnownLayout { + | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` + | +note: required because of the requirements on the impl of `KnownLayout` for `KL13` + --> tests/ui-msrv/mid_compile_pass.rs:55:10 + | +55 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +59 | fn test_kl13(t: T) -> impl KnownLayout { + | +++++++++++++++++++++++ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> tests/ui-msrv/mid_compile_pass.rs:31:15 + | +30 | fn test_kl04(kl: &KL04) { + | - this type parameter needs to be `std::marker::Sized` +31 | assert_kl(kl); + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `KL04` + --> tests/ui-msrv/mid_compile_pass.rs:28:8 + | +28 | struct KL04(u8, T); + | ^^^^ +note: required because of the requirements on the impl of `KnownLayout` for `KL04` + --> tests/ui-msrv/mid_compile_pass.rs:27:10 + | +27 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ +note: required by a bound in `assert_kl` + --> tests/ui-msrv/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +30 - fn test_kl04(kl: &KL04) { +30 + fn test_kl04(kl: &KL04) { + | + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> tests/ui-msrv/mid_compile_pass.rs:40:15 + | +39 | fn test_kl06(kl: &KL06) { + | - this type parameter needs to be `std::marker::Sized` +40 | assert_kl(kl); + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `KL06` + --> tests/ui-msrv/mid_compile_pass.rs:37:8 + | +37 | struct KL06(u8, T); + | ^^^^ +note: required because of the requirements on the impl of `KnownLayout` for `KL06` + --> tests/ui-msrv/mid_compile_pass.rs:36:10 + | +36 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ +note: required by a bound in `assert_kl` + --> tests/ui-msrv/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +39 - fn test_kl06(kl: &KL06) { +39 + fn test_kl06(kl: &KL06) { + | + +error[E0277]: the trait bound `T: KnownLayout` is not satisfied + --> tests/ui-msrv/mid_compile_pass.rs:50:15 + | +50 | assert_kl(kl) + | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | | + | required by a bound introduced by this call + | +note: required because of the requirements on the impl of `KnownLayout` for `KL12` + --> tests/ui-msrv/mid_compile_pass.rs:45:10 + | +45 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ +note: required by a bound in `assert_kl` + --> tests/ui-msrv/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting this bound + | +49 | fn test_kl12(kl: &KL12) { + | +++++++++++++++++++++++ diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/struct.rs b/third_party/rust/zerocopy-derive/tests/ui-msrv/struct.rs new file mode 100644 index 0000000000..c76dc7f952 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/struct.rs @@ -0,0 +1,99 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use zerocopy::KnownLayout; + +use self::util::AU16; + +fn main() {} + +// +// KnownLayout errors +// + +struct NotKnownLayout; + +struct NotKnownLayoutDst([u8]); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | N | N | N | KL00 | +#[derive(KnownLayout)] +struct KL00(u8, NotKnownLayoutDst); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | N | Y | N | KL02 | +#[derive(KnownLayout)] +struct KL02(u8, [u8]); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | N | N | N | KL08 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL08(u8, NotKnownLayoutDst); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | N | N | Y | KL09 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL09(NotKnownLayout, NotKnownLayout); + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes1(T); + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes2 { + foo: u8, + bar: AU16, +} + +#[derive(AsBytes)] +#[repr(C, packed(2))] +struct AsBytes3 { + foo: u8, + // We'd prefer to use AU64 here, but you can't use aligned types in + // packed structs. + bar: u64, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C, align(2))] +struct Unaligned1; + +#[derive(Unaligned)] +#[repr(transparent, align(2))] +struct Unaligned2 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(packed, align(2))] +struct Unaligned3; + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +struct Unaligned4; + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +struct Unaligned5; diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/struct.stderr b/third_party/rust/zerocopy-derive/tests/ui-msrv/struct.stderr new file mode 100644 index 0000000000..f4a435d5f5 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/struct.stderr @@ -0,0 +1,113 @@ +error: unsupported on generic structs that are not repr(transparent) or repr(packed) + --> tests/ui-msrv/struct.rs:55:10 + | +55 | #[derive(AsBytes)] + | ^^^^^^^ + | + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/struct.rs:80:11 + | +80 | #[repr(C, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/struct.rs:84:21 + | +84 | #[repr(transparent, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/struct.rs:90:16 + | +90 | #[repr(packed, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/struct.rs:94:18 + | +94 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/struct.rs:98:8 + | +98 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0692]: transparent struct cannot have other repr hints + --> tests/ui-msrv/struct.rs:84:8 + | +84 | #[repr(transparent, align(2))] + | ^^^^^^^^^^^ ^^^^^^^^ + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/struct.rs:31:10 + | +31 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `KL00`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `KL00` + --> tests/ui-msrv/struct.rs:32:8 + | +32 | struct KL00(u8, NotKnownLayoutDst); + | ^^^^ + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/struct.rs:36:10 + | +36 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `KL02`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `KL02` + --> tests/ui-msrv/struct.rs:37:8 + | +37 | struct KL02(u8, [u8]); + | ^^^^ + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotKnownLayoutDst: KnownLayout` is not satisfied + --> tests/ui-msrv/struct.rs:41:10 + | +41 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayoutDst` + | + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotKnownLayout: KnownLayout` is not satisfied + --> tests/ui-msrv/struct.rs:47:10 + | +47 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayout` + | + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-msrv/struct.rs:59:10 + | +59 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the following implementations were found: + as ShouldBe> + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-msrv/struct.rs:66:10 + | +66 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the following implementations were found: + as ShouldBe> + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/union.rs b/third_party/rust/zerocopy-derive/tests/ui-msrv/union.rs new file mode 100644 index 0000000000..8938e78478 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/union.rs @@ -0,0 +1,73 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use self::util::AU16; +use std::mem::ManuallyDrop; + +fn main() {} + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +union AsBytes1 { + foo: ManuallyDrop, +} + +#[derive(AsBytes)] +#[repr(C)] +union AsBytes2 { + foo: u8, + bar: [u8; 2], +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C, align(2))] +union Unaligned1 { + foo: i16, + bar: AU16, +} + +// Transparent unions are unstable; see issue #60405 +// for more information. + +// #[derive(Unaligned)] +// #[repr(transparent, align(2))] +// union Unaligned2 { +// foo: u8, +// } + +#[derive(Unaligned)] +#[repr(packed, align(2))] +union Unaligned3 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +struct Unaligned4 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +struct Unaligned5 { + foo: u8, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-msrv/union.stderr b/third_party/rust/zerocopy-derive/tests/ui-msrv/union.stderr new file mode 100644 index 0000000000..3e13059211 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-msrv/union.stderr @@ -0,0 +1,42 @@ +error: unsupported on types with type parameters + --> tests/ui-msrv/union.rs:24:10 + | +24 | #[derive(AsBytes)] + | ^^^^^^^ + | + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/union.rs:42:11 + | +42 | #[repr(C, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/union.rs:58:16 + | +58 | #[repr(packed, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/union.rs:64:18 + | +64 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-msrv/union.rs:70:8 + | +70 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-msrv/union.rs:30:10 + | +30 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the following implementations were found: + as ShouldBe> + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.rs b/third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.rs new file mode 100644 index 0000000000..2084d921bf --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.rs @@ -0,0 +1,40 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use core::marker::PhantomData; + +use { + static_assertions::assert_impl_all, + zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned}, +}; + +use self::util::NotZerocopy; + +fn main() {} + +// Test generic transparent structs + +#[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] +#[repr(transparent)] +struct TransparentStruct { + inner: T, + _phantom: PhantomData<()>, +} + +// It should be legal to derive these traits on a transparent struct, but it +// must also ensure the traits are only implemented when the inner type +// implements them. +assert_impl_all!(TransparentStruct: FromZeroes); +assert_impl_all!(TransparentStruct: FromBytes); +assert_impl_all!(TransparentStruct: AsBytes); +assert_impl_all!(TransparentStruct: Unaligned); diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr b/third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr new file mode 100644 index 0000000000..f214877dfb --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr @@ -0,0 +1,111 @@ +error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied + --> tests/ui-nightly/derive_transparent.rs:37:18 + | +37 | assert_impl_all!(TransparentStruct: FromZeroes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromZeroes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required for `TransparentStruct` to implement `FromZeroes` + --> tests/ui-nightly/derive_transparent.rs:27:19 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-nightly/derive_transparent.rs:37:1 + | +37 | assert_impl_all!(TransparentStruct: FromZeroes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-nightly/derive_transparent.rs:38:18 + | +38 | assert_impl_all!(TransparentStruct: FromBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required for `TransparentStruct` to implement `FromBytes` + --> tests/ui-nightly/derive_transparent.rs:27:31 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-nightly/derive_transparent.rs:38:1 + | +38 | assert_impl_all!(TransparentStruct: FromBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-nightly/derive_transparent.rs:39:18 + | +39 | assert_impl_all!(TransparentStruct: AsBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required for `TransparentStruct` to implement `AsBytes` + --> tests/ui-nightly/derive_transparent.rs:27:10 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-nightly/derive_transparent.rs:39:1 + | +39 | assert_impl_all!(TransparentStruct: AsBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied + --> tests/ui-nightly/derive_transparent.rs:40:18 + | +40 | assert_impl_all!(TransparentStruct: Unaligned); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + TransparentStruct + U16 + U32 + U64 + U128 + and $N others +note: required for `TransparentStruct` to implement `Unaligned` + --> tests/ui-nightly/derive_transparent.rs:27:42 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-nightly/derive_transparent.rs:40:1 + | +40 | assert_impl_all!(TransparentStruct: Unaligned); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/enum.rs b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum.rs new file mode 100644 index 0000000000..31d5679d19 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum.rs @@ -0,0 +1,194 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// +// Generic errors +// + +#[derive(FromZeroes, FromBytes)] +#[repr("foo")] +enum Generic1 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(foo)] +enum Generic2 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(transparent)] +enum Generic3 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u8, u16)] +enum Generic4 { + A, +} + +#[derive(FromZeroes, FromBytes)] +enum Generic5 { + A, +} + +// +// FromZeroes errors +// + +#[derive(FromZeroes)] +enum FromZeroes1 { + A(u8), +} + +#[derive(FromZeroes)] +enum FromZeroes2 { + A, + B(u8), +} + +#[derive(FromZeroes)] +enum FromZeroes3 { + A = 1, + B, +} + +// +// FromBytes errors +// + +#[derive(FromZeroes, FromBytes)] +#[repr(C)] +enum FromBytes1 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(usize)] +enum FromBytes2 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(isize)] +enum FromBytes3 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u32)] +enum FromBytes4 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(i32)] +enum FromBytes5 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u64)] +enum FromBytes6 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(i64)] +enum FromBytes7 { + A, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C)] +enum Unaligned1 { + A, +} + +#[derive(Unaligned)] +#[repr(u16)] +enum Unaligned2 { + A, +} + +#[derive(Unaligned)] +#[repr(i16)] +enum Unaligned3 { + A, +} + +#[derive(Unaligned)] +#[repr(u32)] +enum Unaligned4 { + A, +} + +#[derive(Unaligned)] +#[repr(i32)] +enum Unaligned5 { + A, +} + +#[derive(Unaligned)] +#[repr(u64)] +enum Unaligned6 { + A, +} + +#[derive(Unaligned)] +#[repr(i64)] +enum Unaligned7 { + A, +} + +#[derive(Unaligned)] +#[repr(usize)] +enum Unaligned8 { + A, +} + +#[derive(Unaligned)] +#[repr(isize)] +enum Unaligned9 { + A, +} + +#[derive(Unaligned)] +#[repr(u8, align(2))] +enum Unaligned10 { + A, +} + +#[derive(Unaligned)] +#[repr(i8, align(2))] +enum Unaligned11 { + A, +} + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +enum Unaligned12 { + A, +} + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +enum Unaligned13 { + A, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/enum.stderr b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum.stderr new file mode 100644 index 0000000000..a4d5edf35f --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum.stderr @@ -0,0 +1,201 @@ +error: unrecognized representation hint + --> tests/ui-nightly/enum.rs:19:8 + | +19 | #[repr("foo")] + | ^^^^^ + +error: unrecognized representation hint + --> tests/ui-nightly/enum.rs:25:8 + | +25 | #[repr(foo)] + | ^^^ + +error: unsupported representation for deriving FromBytes, AsBytes, or Unaligned on an enum + --> tests/ui-nightly/enum.rs:31:8 + | +31 | #[repr(transparent)] + | ^^^^^^^^^^^ + +error: conflicting representation hints + --> tests/ui-nightly/enum.rs:37:8 + | +37 | #[repr(u8, u16)] + | ^^^^^^^ + +error: must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout + --> tests/ui-nightly/enum.rs:42:22 + | +42 | #[derive(FromZeroes, FromBytes)] + | ^^^^^^^^^ + | + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: only C-like enums can implement FromZeroes + --> tests/ui-nightly/enum.rs:52:1 + | +52 | / enum FromZeroes1 { +53 | | A(u8), +54 | | } + | |_^ + +error: only C-like enums can implement FromZeroes + --> tests/ui-nightly/enum.rs:57:1 + | +57 | / enum FromZeroes2 { +58 | | A, +59 | | B(u8), +60 | | } + | |_^ + +error: FromZeroes only supported on enums with a variant that has a discriminant of `0` + --> tests/ui-nightly/enum.rs:63:1 + | +63 | / enum FromZeroes3 { +64 | | A = 1, +65 | | B, +66 | | } + | |_^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-nightly/enum.rs:73:8 + | +73 | #[repr(C)] + | ^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-nightly/enum.rs:79:8 + | +79 | #[repr(usize)] + | ^^^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-nightly/enum.rs:85:8 + | +85 | #[repr(isize)] + | ^^^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-nightly/enum.rs:91:8 + | +91 | #[repr(u32)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-nightly/enum.rs:97:8 + | +97 | #[repr(i32)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-nightly/enum.rs:103:8 + | +103 | #[repr(u64)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-nightly/enum.rs:109:8 + | +109 | #[repr(i64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:119:8 + | +119 | #[repr(C)] + | ^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:125:8 + | +125 | #[repr(u16)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:131:8 + | +131 | #[repr(i16)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:137:8 + | +137 | #[repr(u32)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:143:8 + | +143 | #[repr(i32)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:149:8 + | +149 | #[repr(u64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:155:8 + | +155 | #[repr(i64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:161:8 + | +161 | #[repr(usize)] + | ^^^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-nightly/enum.rs:167:8 + | +167 | #[repr(isize)] + | ^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/enum.rs:173:12 + | +173 | #[repr(u8, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/enum.rs:179:12 + | +179 | #[repr(i8, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/enum.rs:185:18 + | +185 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/enum.rs:191:8 + | +191 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0565]: meta item in `repr` must be an identifier + --> tests/ui-nightly/enum.rs:19:8 + | +19 | #[repr("foo")] + | ^^^^^ + +error[E0552]: unrecognized representation hint + --> tests/ui-nightly/enum.rs:25:8 + | +25 | #[repr(foo)] + | ^^^ + | + = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0566]: conflicting representation hints + --> tests/ui-nightly/enum.rs:37:8 + | +37 | #[repr(u8, u16)] + | ^^ ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` on by default diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.rs b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.rs new file mode 100644 index 0000000000..1b1bed31f3 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.rs @@ -0,0 +1,272 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +#[derive(FromBytes)] +#[repr(u8)] +enum Foo { + Variant0, + Variant1, + Variant2, + Variant3, + Variant4, + Variant5, + Variant6, + Variant7, + Variant8, + Variant9, + Variant10, + Variant11, + Variant12, + Variant13, + Variant14, + Variant15, + Variant16, + Variant17, + Variant18, + Variant19, + Variant20, + Variant21, + Variant22, + Variant23, + Variant24, + Variant25, + Variant26, + Variant27, + Variant28, + Variant29, + Variant30, + Variant31, + Variant32, + Variant33, + Variant34, + Variant35, + Variant36, + Variant37, + Variant38, + Variant39, + Variant40, + Variant41, + Variant42, + Variant43, + Variant44, + Variant45, + Variant46, + Variant47, + Variant48, + Variant49, + Variant50, + Variant51, + Variant52, + Variant53, + Variant54, + Variant55, + Variant56, + Variant57, + Variant58, + Variant59, + Variant60, + Variant61, + Variant62, + Variant63, + Variant64, + Variant65, + Variant66, + Variant67, + Variant68, + Variant69, + Variant70, + Variant71, + Variant72, + Variant73, + Variant74, + Variant75, + Variant76, + Variant77, + Variant78, + Variant79, + Variant80, + Variant81, + Variant82, + Variant83, + Variant84, + Variant85, + Variant86, + Variant87, + Variant88, + Variant89, + Variant90, + Variant91, + Variant92, + Variant93, + Variant94, + Variant95, + Variant96, + Variant97, + Variant98, + Variant99, + Variant100, + Variant101, + Variant102, + Variant103, + Variant104, + Variant105, + Variant106, + Variant107, + Variant108, + Variant109, + Variant110, + Variant111, + Variant112, + Variant113, + Variant114, + Variant115, + Variant116, + Variant117, + Variant118, + Variant119, + Variant120, + Variant121, + Variant122, + Variant123, + Variant124, + Variant125, + Variant126, + Variant127, + Variant128, + Variant129, + Variant130, + Variant131, + Variant132, + Variant133, + Variant134, + Variant135, + Variant136, + Variant137, + Variant138, + Variant139, + Variant140, + Variant141, + Variant142, + Variant143, + Variant144, + Variant145, + Variant146, + Variant147, + Variant148, + Variant149, + Variant150, + Variant151, + Variant152, + Variant153, + Variant154, + Variant155, + Variant156, + Variant157, + Variant158, + Variant159, + Variant160, + Variant161, + Variant162, + Variant163, + Variant164, + Variant165, + Variant166, + Variant167, + Variant168, + Variant169, + Variant170, + Variant171, + Variant172, + Variant173, + Variant174, + Variant175, + Variant176, + Variant177, + Variant178, + Variant179, + Variant180, + Variant181, + Variant182, + Variant183, + Variant184, + Variant185, + Variant186, + Variant187, + Variant188, + Variant189, + Variant190, + Variant191, + Variant192, + Variant193, + Variant194, + Variant195, + Variant196, + Variant197, + Variant198, + Variant199, + Variant200, + Variant201, + Variant202, + Variant203, + Variant204, + Variant205, + Variant206, + Variant207, + Variant208, + Variant209, + Variant210, + Variant211, + Variant212, + Variant213, + Variant214, + Variant215, + Variant216, + Variant217, + Variant218, + Variant219, + Variant220, + Variant221, + Variant222, + Variant223, + Variant224, + Variant225, + Variant226, + Variant227, + Variant228, + Variant229, + Variant230, + Variant231, + Variant232, + Variant233, + Variant234, + Variant235, + Variant236, + Variant237, + Variant238, + Variant239, + Variant240, + Variant241, + Variant242, + Variant243, + Variant244, + Variant245, + Variant246, + Variant247, + Variant248, + Variant249, + Variant250, + Variant251, + Variant252, + Variant253, + Variant254, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.stderr b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.stderr new file mode 100644 index 0000000000..50cf0e7cb8 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.stderr @@ -0,0 +1,11 @@ +error: FromBytes only supported on repr(u8) enum with 256 variants + --> tests/ui-nightly/enum_from_bytes_u8_too_few.rs:15:1 + | +15 | / #[repr(u8)] +16 | | enum Foo { +17 | | Variant0, +18 | | Variant1, +... | +271 | | Variant254, +272 | | } + | |_^ diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.rs b/third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.rs new file mode 100644 index 0000000000..cd65a6ed2c --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.rs @@ -0,0 +1,75 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use self::util::{NotZerocopy, AU16}; +use zerocopy::KnownLayout; + +fn main() {} + +// These tests cause errors which are generated by a later compilation pass than +// the other errors we generate, and so if they're compiled in the same file, +// the compiler will never get to that pass, and so we won't get the errors. + +// +// FromZeroes errors +// + +#[derive(FromZeroes)] +struct FromZeroes1 { + value: NotZerocopy, +} + +// +// FromBytes errors +// + +#[derive(FromBytes)] +struct FromBytes1 { + value: NotZerocopy, +} + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes1 { + value: NotZerocopy, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C)] +struct Unaligned1 { + aligned: AU16, +} + +// This specifically tests a bug we had in an old version of the code in which +// the trait bound would only be enforced for the first field's type. +#[derive(Unaligned)] +#[repr(C)] +struct Unaligned2 { + unaligned: u8, + aligned: AU16, +} + +#[derive(Unaligned)] +#[repr(transparent)] +struct Unaligned3 { + aligned: AU16, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr b/third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr new file mode 100644 index 0000000000..3c45dc4e84 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr @@ -0,0 +1,150 @@ +warning: unused import: `zerocopy::KnownLayout` + --> tests/ui-nightly/late_compile_pass.rs:16:5 + | +16 | use zerocopy::KnownLayout; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied + --> tests/ui-nightly/late_compile_pass.rs:28:10 + | +28 | #[derive(FromZeroes)] + | ^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromZeroes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `FromZeroes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-nightly/late_compile_pass.rs:37:10 + | +37 | #[derive(FromBytes)] + | ^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `FromBytes1: FromZeroes` is not satisfied + --> tests/ui-nightly/late_compile_pass.rs:37:10 + | +37 | #[derive(FromBytes)] + | ^^^^^^^^^ the trait `FromZeroes` is not implemented for `FromBytes1` + | + = help: the following other types implement trait `FromZeroes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `FromBytes` + --> $WORKSPACE/src/lib.rs + | + | pub unsafe trait FromBytes: FromZeroes { + | ^^^^^^^^^^ required by this bound in `FromBytes` + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-nightly/late_compile_pass.rs:46:10 + | +46 | #[derive(AsBytes)] + | ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-nightly/late_compile_pass.rs:56:10 + | +56 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + Unaligned1 + Unaligned2 + Unaligned3 + U16 + U32 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-nightly/late_compile_pass.rs:64:10 + | +64 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + Unaligned1 + Unaligned2 + Unaligned3 + U16 + U32 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-nightly/late_compile_pass.rs:71:10 + | +71 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + Unaligned1 + Unaligned2 + Unaligned3 + U16 + U32 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.rs b/third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.rs new file mode 100644 index 0000000000..e0c4bc578d --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.rs @@ -0,0 +1,61 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::KnownLayout; + +fn main() {} + +// These tests cause errors which are generated by a later compilation pass than +// the other errors we generate, and so if they're compiled in the same file, +// the compiler will never get to that pass, and so we won't get the errors. + +// +// KnownLayout errors +// + +fn assert_kl(_: &T) {} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | Y | N | N | KL04 | +#[derive(KnownLayout)] +struct KL04(u8, T); + +fn test_kl04(kl: &KL04) { + assert_kl(kl); +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | Y | Y | N | KL06 | +#[derive(KnownLayout)] +struct KL06(u8, T); + +fn test_kl06(kl: &KL06) { + assert_kl(kl); +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | Y | N | N | KL12 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL12(u8, T); + +fn test_kl12(kl: &KL12) { + assert_kl(kl) +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | Y | N | Y | KL13 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL13(u8, T); + +fn test_kl13(t: T) -> impl KnownLayout { + KL13(0u8, t) +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr b/third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr new file mode 100644 index 0000000000..7fd758c8fe --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr @@ -0,0 +1,104 @@ +error[E0277]: the trait bound `T: KnownLayout` is not satisfied + --> tests/ui-nightly/mid_compile_pass.rs:59:26 + | +59 | fn test_kl13(t: T) -> impl KnownLayout { + | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` + | +note: required for `KL13` to implement `KnownLayout` + --> tests/ui-nightly/mid_compile_pass.rs:55:10 + | +55 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +59 | fn test_kl13(t: T) -> impl KnownLayout { + | +++++++++++++++++++++++ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> tests/ui-nightly/mid_compile_pass.rs:31:15 + | +30 | fn test_kl04(kl: &KL04) { + | - this type parameter needs to be `Sized` +31 | assert_kl(kl); + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `KL04` + --> tests/ui-nightly/mid_compile_pass.rs:28:8 + | +28 | struct KL04(u8, T); + | ^^^^ +note: required for `KL04` to implement `KnownLayout` + --> tests/ui-nightly/mid_compile_pass.rs:27:10 + | +27 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `assert_kl` + --> tests/ui-nightly/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +30 - fn test_kl04(kl: &KL04) { +30 + fn test_kl04(kl: &KL04) { + | + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> tests/ui-nightly/mid_compile_pass.rs:40:15 + | +39 | fn test_kl06(kl: &KL06) { + | - this type parameter needs to be `Sized` +40 | assert_kl(kl); + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `KL06` + --> tests/ui-nightly/mid_compile_pass.rs:37:8 + | +37 | struct KL06(u8, T); + | ^^^^ +note: required for `KL06` to implement `KnownLayout` + --> tests/ui-nightly/mid_compile_pass.rs:36:10 + | +36 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `assert_kl` + --> tests/ui-nightly/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +39 - fn test_kl06(kl: &KL06) { +39 + fn test_kl06(kl: &KL06) { + | + +error[E0277]: the trait bound `T: KnownLayout` is not satisfied + --> tests/ui-nightly/mid_compile_pass.rs:50:15 + | +50 | assert_kl(kl) + | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | | + | required by a bound introduced by this call + | +note: required for `KL12` to implement `KnownLayout` + --> tests/ui-nightly/mid_compile_pass.rs:45:10 + | +45 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `assert_kl` + --> tests/ui-nightly/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting this bound + | +49 | fn test_kl12(kl: &KL12) { + | +++++++++++++++++++++++ diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/struct.rs b/third_party/rust/zerocopy-derive/tests/ui-nightly/struct.rs new file mode 100644 index 0000000000..c76dc7f952 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/struct.rs @@ -0,0 +1,99 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use zerocopy::KnownLayout; + +use self::util::AU16; + +fn main() {} + +// +// KnownLayout errors +// + +struct NotKnownLayout; + +struct NotKnownLayoutDst([u8]); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | N | N | N | KL00 | +#[derive(KnownLayout)] +struct KL00(u8, NotKnownLayoutDst); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | N | Y | N | KL02 | +#[derive(KnownLayout)] +struct KL02(u8, [u8]); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | N | N | N | KL08 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL08(u8, NotKnownLayoutDst); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | N | N | Y | KL09 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL09(NotKnownLayout, NotKnownLayout); + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes1(T); + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes2 { + foo: u8, + bar: AU16, +} + +#[derive(AsBytes)] +#[repr(C, packed(2))] +struct AsBytes3 { + foo: u8, + // We'd prefer to use AU64 here, but you can't use aligned types in + // packed structs. + bar: u64, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C, align(2))] +struct Unaligned1; + +#[derive(Unaligned)] +#[repr(transparent, align(2))] +struct Unaligned2 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(packed, align(2))] +struct Unaligned3; + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +struct Unaligned4; + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +struct Unaligned5; diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/struct.stderr b/third_party/rust/zerocopy-derive/tests/ui-nightly/struct.stderr new file mode 100644 index 0000000000..c3abcbd182 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -0,0 +1,143 @@ +error: unsupported on generic structs that are not repr(transparent) or repr(packed) + --> tests/ui-nightly/struct.rs:55:10 + | +55 | #[derive(AsBytes)] + | ^^^^^^^ + | + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/struct.rs:80:11 + | +80 | #[repr(C, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/struct.rs:84:21 + | +84 | #[repr(transparent, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/struct.rs:90:16 + | +90 | #[repr(packed, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/struct.rs:94:18 + | +94 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/struct.rs:98:8 + | +98 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0692]: transparent struct cannot have other repr hints + --> tests/ui-nightly/struct.rs:84:8 + | +84 | #[repr(transparent, align(2))] + | ^^^^^^^^^^^ ^^^^^^^^ + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/struct.rs:31:10 + | +31 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `KL00`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `KL00` + --> tests/ui-nightly/struct.rs:32:8 + | +32 | struct KL00(u8, NotKnownLayoutDst); + | ^^^^ + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/struct.rs:36:10 + | +36 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `KL02`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `KL02` + --> tests/ui-nightly/struct.rs:37:8 + | +37 | struct KL02(u8, [u8]); + | ^^^^ + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotKnownLayoutDst: KnownLayout` is not satisfied + --> tests/ui-nightly/struct.rs:41:10 + | +41 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayoutDst` + | + = help: the following other types implement trait `KnownLayout`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotKnownLayout: KnownLayout` is not satisfied + --> tests/ui-nightly/struct.rs:47:10 + | +47 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayout` + | + = help: the following other types implement trait `KnownLayout`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-nightly/struct.rs:59:10 + | +59 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the trait `ShouldBe` is implemented for `HasPadding` + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-nightly/struct.rs:66:10 + | +66 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the trait `ShouldBe` is implemented for `HasPadding` + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0587]: type has conflicting packed and align representation hints + --> tests/ui-nightly/struct.rs:91:1 + | +91 | struct Unaligned3; + | ^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/union.rs b/third_party/rust/zerocopy-derive/tests/ui-nightly/union.rs new file mode 100644 index 0000000000..8938e78478 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/union.rs @@ -0,0 +1,73 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use self::util::AU16; +use std::mem::ManuallyDrop; + +fn main() {} + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +union AsBytes1 { + foo: ManuallyDrop, +} + +#[derive(AsBytes)] +#[repr(C)] +union AsBytes2 { + foo: u8, + bar: [u8; 2], +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C, align(2))] +union Unaligned1 { + foo: i16, + bar: AU16, +} + +// Transparent unions are unstable; see issue #60405 +// for more information. + +// #[derive(Unaligned)] +// #[repr(transparent, align(2))] +// union Unaligned2 { +// foo: u8, +// } + +#[derive(Unaligned)] +#[repr(packed, align(2))] +union Unaligned3 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +struct Unaligned4 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +struct Unaligned5 { + foo: u8, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-nightly/union.stderr b/third_party/rust/zerocopy-derive/tests/ui-nightly/union.stderr new file mode 100644 index 0000000000..afc4e8c18d --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-nightly/union.stderr @@ -0,0 +1,48 @@ +error: unsupported on types with type parameters + --> tests/ui-nightly/union.rs:24:10 + | +24 | #[derive(AsBytes)] + | ^^^^^^^ + | + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/union.rs:42:11 + | +42 | #[repr(C, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/union.rs:58:16 + | +58 | #[repr(packed, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/union.rs:64:18 + | +64 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-nightly/union.rs:70:8 + | +70 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-nightly/union.rs:30:10 + | +30 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the trait `ShouldBe` is implemented for `HasPadding` + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0587]: type has conflicting packed and align representation hints + --> tests/ui-nightly/union.rs:59:1 + | +59 | union Unaligned3 { + | ^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.rs b/third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.rs new file mode 100644 index 0000000000..2084d921bf --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.rs @@ -0,0 +1,40 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use core::marker::PhantomData; + +use { + static_assertions::assert_impl_all, + zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned}, +}; + +use self::util::NotZerocopy; + +fn main() {} + +// Test generic transparent structs + +#[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] +#[repr(transparent)] +struct TransparentStruct { + inner: T, + _phantom: PhantomData<()>, +} + +// It should be legal to derive these traits on a transparent struct, but it +// must also ensure the traits are only implemented when the inner type +// implements them. +assert_impl_all!(TransparentStruct: FromZeroes); +assert_impl_all!(TransparentStruct: FromBytes); +assert_impl_all!(TransparentStruct: AsBytes); +assert_impl_all!(TransparentStruct: Unaligned); diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.stderr b/third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.stderr new file mode 100644 index 0000000000..f24dd4866d --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/derive_transparent.stderr @@ -0,0 +1,111 @@ +error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied + --> tests/ui-stable/derive_transparent.rs:37:18 + | +37 | assert_impl_all!(TransparentStruct: FromZeroes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromZeroes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required for `TransparentStruct` to implement `FromZeroes` + --> tests/ui-stable/derive_transparent.rs:27:19 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-stable/derive_transparent.rs:37:1 + | +37 | assert_impl_all!(TransparentStruct: FromZeroes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-stable/derive_transparent.rs:38:18 + | +38 | assert_impl_all!(TransparentStruct: FromBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required for `TransparentStruct` to implement `FromBytes` + --> tests/ui-stable/derive_transparent.rs:27:31 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-stable/derive_transparent.rs:38:1 + | +38 | assert_impl_all!(TransparentStruct: FromBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-stable/derive_transparent.rs:39:18 + | +39 | assert_impl_all!(TransparentStruct: AsBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required for `TransparentStruct` to implement `AsBytes` + --> tests/ui-stable/derive_transparent.rs:27:10 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-stable/derive_transparent.rs:39:1 + | +39 | assert_impl_all!(TransparentStruct: AsBytes); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied + --> tests/ui-stable/derive_transparent.rs:40:18 + | +40 | assert_impl_all!(TransparentStruct: Unaligned); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + TransparentStruct + U16 + U32 + U64 + U128 + and $N others +note: required for `TransparentStruct` to implement `Unaligned` + --> tests/ui-stable/derive_transparent.rs:27:42 + | +27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::{closure#0}::assert_impl_all` + --> tests/ui-stable/derive_transparent.rs:40:1 + | +40 | assert_impl_all!(TransparentStruct: Unaligned); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/enum.rs b/third_party/rust/zerocopy-derive/tests/ui-stable/enum.rs new file mode 100644 index 0000000000..31d5679d19 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/enum.rs @@ -0,0 +1,194 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// +// Generic errors +// + +#[derive(FromZeroes, FromBytes)] +#[repr("foo")] +enum Generic1 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(foo)] +enum Generic2 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(transparent)] +enum Generic3 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u8, u16)] +enum Generic4 { + A, +} + +#[derive(FromZeroes, FromBytes)] +enum Generic5 { + A, +} + +// +// FromZeroes errors +// + +#[derive(FromZeroes)] +enum FromZeroes1 { + A(u8), +} + +#[derive(FromZeroes)] +enum FromZeroes2 { + A, + B(u8), +} + +#[derive(FromZeroes)] +enum FromZeroes3 { + A = 1, + B, +} + +// +// FromBytes errors +// + +#[derive(FromZeroes, FromBytes)] +#[repr(C)] +enum FromBytes1 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(usize)] +enum FromBytes2 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(isize)] +enum FromBytes3 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u32)] +enum FromBytes4 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(i32)] +enum FromBytes5 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(u64)] +enum FromBytes6 { + A, +} + +#[derive(FromZeroes, FromBytes)] +#[repr(i64)] +enum FromBytes7 { + A, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C)] +enum Unaligned1 { + A, +} + +#[derive(Unaligned)] +#[repr(u16)] +enum Unaligned2 { + A, +} + +#[derive(Unaligned)] +#[repr(i16)] +enum Unaligned3 { + A, +} + +#[derive(Unaligned)] +#[repr(u32)] +enum Unaligned4 { + A, +} + +#[derive(Unaligned)] +#[repr(i32)] +enum Unaligned5 { + A, +} + +#[derive(Unaligned)] +#[repr(u64)] +enum Unaligned6 { + A, +} + +#[derive(Unaligned)] +#[repr(i64)] +enum Unaligned7 { + A, +} + +#[derive(Unaligned)] +#[repr(usize)] +enum Unaligned8 { + A, +} + +#[derive(Unaligned)] +#[repr(isize)] +enum Unaligned9 { + A, +} + +#[derive(Unaligned)] +#[repr(u8, align(2))] +enum Unaligned10 { + A, +} + +#[derive(Unaligned)] +#[repr(i8, align(2))] +enum Unaligned11 { + A, +} + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +enum Unaligned12 { + A, +} + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +enum Unaligned13 { + A, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/enum.stderr b/third_party/rust/zerocopy-derive/tests/ui-stable/enum.stderr new file mode 100644 index 0000000000..a47ce9c4ba --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/enum.stderr @@ -0,0 +1,201 @@ +error: unrecognized representation hint + --> tests/ui-stable/enum.rs:19:8 + | +19 | #[repr("foo")] + | ^^^^^ + +error: unrecognized representation hint + --> tests/ui-stable/enum.rs:25:8 + | +25 | #[repr(foo)] + | ^^^ + +error: unsupported representation for deriving FromBytes, AsBytes, or Unaligned on an enum + --> tests/ui-stable/enum.rs:31:8 + | +31 | #[repr(transparent)] + | ^^^^^^^^^^^ + +error: conflicting representation hints + --> tests/ui-stable/enum.rs:37:1 + | +37 | #[repr(u8, u16)] + | ^ + +error: must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout + --> tests/ui-stable/enum.rs:42:22 + | +42 | #[derive(FromZeroes, FromBytes)] + | ^^^^^^^^^ + | + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: only C-like enums can implement FromZeroes + --> tests/ui-stable/enum.rs:52:1 + | +52 | / enum FromZeroes1 { +53 | | A(u8), +54 | | } + | |_^ + +error: only C-like enums can implement FromZeroes + --> tests/ui-stable/enum.rs:57:1 + | +57 | / enum FromZeroes2 { +58 | | A, +59 | | B(u8), +60 | | } + | |_^ + +error: FromZeroes only supported on enums with a variant that has a discriminant of `0` + --> tests/ui-stable/enum.rs:63:1 + | +63 | / enum FromZeroes3 { +64 | | A = 1, +65 | | B, +66 | | } + | |_^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-stable/enum.rs:73:8 + | +73 | #[repr(C)] + | ^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-stable/enum.rs:79:8 + | +79 | #[repr(usize)] + | ^^^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-stable/enum.rs:85:8 + | +85 | #[repr(isize)] + | ^^^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-stable/enum.rs:91:8 + | +91 | #[repr(u32)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-stable/enum.rs:97:8 + | +97 | #[repr(i32)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-stable/enum.rs:103:8 + | +103 | #[repr(u64)] + | ^^^ + +error: FromBytes requires repr of "u8", "u16", "i8", or "i16" + --> tests/ui-stable/enum.rs:109:8 + | +109 | #[repr(i64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:119:8 + | +119 | #[repr(C)] + | ^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:125:8 + | +125 | #[repr(u16)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:131:8 + | +131 | #[repr(i16)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:137:8 + | +137 | #[repr(u32)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:143:8 + | +143 | #[repr(i32)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:149:8 + | +149 | #[repr(u64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:155:8 + | +155 | #[repr(i64)] + | ^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:161:8 + | +161 | #[repr(usize)] + | ^^^^^ + +error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1))) + --> tests/ui-stable/enum.rs:167:8 + | +167 | #[repr(isize)] + | ^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/enum.rs:173:12 + | +173 | #[repr(u8, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/enum.rs:179:12 + | +179 | #[repr(i8, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/enum.rs:185:18 + | +185 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/enum.rs:191:8 + | +191 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0565]: meta item in `repr` must be an identifier + --> tests/ui-stable/enum.rs:19:8 + | +19 | #[repr("foo")] + | ^^^^^ + +error[E0552]: unrecognized representation hint + --> tests/ui-stable/enum.rs:25:8 + | +25 | #[repr(foo)] + | ^^^ + | + = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0566]: conflicting representation hints + --> tests/ui-stable/enum.rs:37:8 + | +37 | #[repr(u8, u16)] + | ^^ ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` on by default diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.rs b/third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.rs new file mode 100644 index 0000000000..1b1bed31f3 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.rs @@ -0,0 +1,272 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +#[derive(FromBytes)] +#[repr(u8)] +enum Foo { + Variant0, + Variant1, + Variant2, + Variant3, + Variant4, + Variant5, + Variant6, + Variant7, + Variant8, + Variant9, + Variant10, + Variant11, + Variant12, + Variant13, + Variant14, + Variant15, + Variant16, + Variant17, + Variant18, + Variant19, + Variant20, + Variant21, + Variant22, + Variant23, + Variant24, + Variant25, + Variant26, + Variant27, + Variant28, + Variant29, + Variant30, + Variant31, + Variant32, + Variant33, + Variant34, + Variant35, + Variant36, + Variant37, + Variant38, + Variant39, + Variant40, + Variant41, + Variant42, + Variant43, + Variant44, + Variant45, + Variant46, + Variant47, + Variant48, + Variant49, + Variant50, + Variant51, + Variant52, + Variant53, + Variant54, + Variant55, + Variant56, + Variant57, + Variant58, + Variant59, + Variant60, + Variant61, + Variant62, + Variant63, + Variant64, + Variant65, + Variant66, + Variant67, + Variant68, + Variant69, + Variant70, + Variant71, + Variant72, + Variant73, + Variant74, + Variant75, + Variant76, + Variant77, + Variant78, + Variant79, + Variant80, + Variant81, + Variant82, + Variant83, + Variant84, + Variant85, + Variant86, + Variant87, + Variant88, + Variant89, + Variant90, + Variant91, + Variant92, + Variant93, + Variant94, + Variant95, + Variant96, + Variant97, + Variant98, + Variant99, + Variant100, + Variant101, + Variant102, + Variant103, + Variant104, + Variant105, + Variant106, + Variant107, + Variant108, + Variant109, + Variant110, + Variant111, + Variant112, + Variant113, + Variant114, + Variant115, + Variant116, + Variant117, + Variant118, + Variant119, + Variant120, + Variant121, + Variant122, + Variant123, + Variant124, + Variant125, + Variant126, + Variant127, + Variant128, + Variant129, + Variant130, + Variant131, + Variant132, + Variant133, + Variant134, + Variant135, + Variant136, + Variant137, + Variant138, + Variant139, + Variant140, + Variant141, + Variant142, + Variant143, + Variant144, + Variant145, + Variant146, + Variant147, + Variant148, + Variant149, + Variant150, + Variant151, + Variant152, + Variant153, + Variant154, + Variant155, + Variant156, + Variant157, + Variant158, + Variant159, + Variant160, + Variant161, + Variant162, + Variant163, + Variant164, + Variant165, + Variant166, + Variant167, + Variant168, + Variant169, + Variant170, + Variant171, + Variant172, + Variant173, + Variant174, + Variant175, + Variant176, + Variant177, + Variant178, + Variant179, + Variant180, + Variant181, + Variant182, + Variant183, + Variant184, + Variant185, + Variant186, + Variant187, + Variant188, + Variant189, + Variant190, + Variant191, + Variant192, + Variant193, + Variant194, + Variant195, + Variant196, + Variant197, + Variant198, + Variant199, + Variant200, + Variant201, + Variant202, + Variant203, + Variant204, + Variant205, + Variant206, + Variant207, + Variant208, + Variant209, + Variant210, + Variant211, + Variant212, + Variant213, + Variant214, + Variant215, + Variant216, + Variant217, + Variant218, + Variant219, + Variant220, + Variant221, + Variant222, + Variant223, + Variant224, + Variant225, + Variant226, + Variant227, + Variant228, + Variant229, + Variant230, + Variant231, + Variant232, + Variant233, + Variant234, + Variant235, + Variant236, + Variant237, + Variant238, + Variant239, + Variant240, + Variant241, + Variant242, + Variant243, + Variant244, + Variant245, + Variant246, + Variant247, + Variant248, + Variant249, + Variant250, + Variant251, + Variant252, + Variant253, + Variant254, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.stderr b/third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.stderr new file mode 100644 index 0000000000..5edbabc47d --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.stderr @@ -0,0 +1,11 @@ +error: FromBytes only supported on repr(u8) enum with 256 variants + --> tests/ui-stable/enum_from_bytes_u8_too_few.rs:15:1 + | +15 | / #[repr(u8)] +16 | | enum Foo { +17 | | Variant0, +18 | | Variant1, +... | +271 | | Variant254, +272 | | } + | |_^ diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.rs b/third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.rs new file mode 100644 index 0000000000..cd65a6ed2c --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.rs @@ -0,0 +1,75 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use self::util::{NotZerocopy, AU16}; +use zerocopy::KnownLayout; + +fn main() {} + +// These tests cause errors which are generated by a later compilation pass than +// the other errors we generate, and so if they're compiled in the same file, +// the compiler will never get to that pass, and so we won't get the errors. + +// +// FromZeroes errors +// + +#[derive(FromZeroes)] +struct FromZeroes1 { + value: NotZerocopy, +} + +// +// FromBytes errors +// + +#[derive(FromBytes)] +struct FromBytes1 { + value: NotZerocopy, +} + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes1 { + value: NotZerocopy, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C)] +struct Unaligned1 { + aligned: AU16, +} + +// This specifically tests a bug we had in an old version of the code in which +// the trait bound would only be enforced for the first field's type. +#[derive(Unaligned)] +#[repr(C)] +struct Unaligned2 { + unaligned: u8, + aligned: AU16, +} + +#[derive(Unaligned)] +#[repr(transparent)] +struct Unaligned3 { + aligned: AU16, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr b/third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr new file mode 100644 index 0000000000..808054ab4d --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr @@ -0,0 +1,144 @@ +warning: unused import: `zerocopy::KnownLayout` + --> tests/ui-stable/late_compile_pass.rs:16:5 + | +16 | use zerocopy::KnownLayout; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied + --> tests/ui-stable/late_compile_pass.rs:28:10 + | +28 | #[derive(FromZeroes)] + | ^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromZeroes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `FromZeroes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-stable/late_compile_pass.rs:37:10 + | +37 | #[derive(FromBytes)] + | ^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `FromBytes1: FromZeroes` is not satisfied + --> tests/ui-stable/late_compile_pass.rs:37:10 + | +37 | #[derive(FromBytes)] + | ^^^^^^^^^ the trait `FromZeroes` is not implemented for `FromBytes1` + | + = help: the following other types implement trait `FromZeroes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `FromBytes` + --> $WORKSPACE/src/lib.rs + | + | pub unsafe trait FromBytes: FromZeroes { + | ^^^^^^^^^^ required by this bound in `FromBytes` + = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-stable/late_compile_pass.rs:46:10 + | +46 | #[derive(AsBytes)] + | ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-stable/late_compile_pass.rs:56:10 + | +56 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + Unaligned1 + Unaligned2 + Unaligned3 + U16 + U32 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-stable/late_compile_pass.rs:64:10 + | +64 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + Unaligned1 + Unaligned2 + Unaligned3 + U16 + U32 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-stable/late_compile_pass.rs:71:10 + | +71 | #[derive(Unaligned)] + | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + = help: the following other types implement trait `Unaligned`: + bool + i8 + u8 + Unaligned1 + Unaligned2 + Unaligned3 + U16 + U32 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.rs b/third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.rs new file mode 100644 index 0000000000..e0c4bc578d --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.rs @@ -0,0 +1,61 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::KnownLayout; + +fn main() {} + +// These tests cause errors which are generated by a later compilation pass than +// the other errors we generate, and so if they're compiled in the same file, +// the compiler will never get to that pass, and so we won't get the errors. + +// +// KnownLayout errors +// + +fn assert_kl(_: &T) {} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | Y | N | N | KL04 | +#[derive(KnownLayout)] +struct KL04(u8, T); + +fn test_kl04(kl: &KL04) { + assert_kl(kl); +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | Y | Y | N | KL06 | +#[derive(KnownLayout)] +struct KL06(u8, T); + +fn test_kl06(kl: &KL06) { + assert_kl(kl); +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | Y | N | N | KL12 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL12(u8, T); + +fn test_kl12(kl: &KL12) { + assert_kl(kl) +} + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | Y | N | Y | KL13 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL13(u8, T); + +fn test_kl13(t: T) -> impl KnownLayout { + KL13(0u8, t) +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr b/third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr new file mode 100644 index 0000000000..f39bcdb170 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr @@ -0,0 +1,104 @@ +error[E0277]: the trait bound `T: KnownLayout` is not satisfied + --> tests/ui-stable/mid_compile_pass.rs:59:26 + | +59 | fn test_kl13(t: T) -> impl KnownLayout { + | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` + | +note: required for `KL13` to implement `KnownLayout` + --> tests/ui-stable/mid_compile_pass.rs:55:10 + | +55 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +59 | fn test_kl13(t: T) -> impl KnownLayout { + | +++++++++++++++++++++++ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> tests/ui-stable/mid_compile_pass.rs:31:15 + | +30 | fn test_kl04(kl: &KL04) { + | - this type parameter needs to be `Sized` +31 | assert_kl(kl); + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `KL04` + --> tests/ui-stable/mid_compile_pass.rs:28:8 + | +28 | struct KL04(u8, T); + | ^^^^ +note: required for `KL04` to implement `KnownLayout` + --> tests/ui-stable/mid_compile_pass.rs:27:10 + | +27 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `assert_kl` + --> tests/ui-stable/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +30 - fn test_kl04(kl: &KL04) { +30 + fn test_kl04(kl: &KL04) { + | + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> tests/ui-stable/mid_compile_pass.rs:40:15 + | +39 | fn test_kl06(kl: &KL06) { + | - this type parameter needs to be `Sized` +40 | assert_kl(kl); + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `KL06` + --> tests/ui-stable/mid_compile_pass.rs:37:8 + | +37 | struct KL06(u8, T); + | ^^^^ +note: required for `KL06` to implement `KnownLayout` + --> tests/ui-stable/mid_compile_pass.rs:36:10 + | +36 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `assert_kl` + --> tests/ui-stable/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +39 - fn test_kl06(kl: &KL06) { +39 + fn test_kl06(kl: &KL06) { + | + +error[E0277]: the trait bound `T: KnownLayout` is not satisfied + --> tests/ui-stable/mid_compile_pass.rs:50:15 + | +50 | assert_kl(kl) + | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | | + | required by a bound introduced by this call + | +note: required for `KL12` to implement `KnownLayout` + --> tests/ui-stable/mid_compile_pass.rs:45:10 + | +45 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `assert_kl` + --> tests/ui-stable/mid_compile_pass.rs:23:26 + | +23 | fn assert_kl(_: &T) {} + | ^^^^^^^^^^^ required by this bound in `assert_kl` + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting this bound + | +49 | fn test_kl12(kl: &KL12) { + | +++++++++++++++++++++++ diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/struct.rs b/third_party/rust/zerocopy-derive/tests/ui-stable/struct.rs new file mode 100644 index 0000000000..c76dc7f952 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/struct.rs @@ -0,0 +1,99 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use zerocopy::KnownLayout; + +use self::util::AU16; + +fn main() {} + +// +// KnownLayout errors +// + +struct NotKnownLayout; + +struct NotKnownLayoutDst([u8]); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | N | N | N | KL00 | +#[derive(KnownLayout)] +struct KL00(u8, NotKnownLayoutDst); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | N | N | Y | N | KL02 | +#[derive(KnownLayout)] +struct KL02(u8, [u8]); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | N | N | N | KL08 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL08(u8, NotKnownLayoutDst); + +// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | +// | Y | N | N | Y | KL09 | +#[derive(KnownLayout)] +#[repr(C)] +struct KL09(NotKnownLayout, NotKnownLayout); + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes1(T); + +#[derive(AsBytes)] +#[repr(C)] +struct AsBytes2 { + foo: u8, + bar: AU16, +} + +#[derive(AsBytes)] +#[repr(C, packed(2))] +struct AsBytes3 { + foo: u8, + // We'd prefer to use AU64 here, but you can't use aligned types in + // packed structs. + bar: u64, +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C, align(2))] +struct Unaligned1; + +#[derive(Unaligned)] +#[repr(transparent, align(2))] +struct Unaligned2 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(packed, align(2))] +struct Unaligned3; + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +struct Unaligned4; + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +struct Unaligned5; diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/struct.stderr b/third_party/rust/zerocopy-derive/tests/ui-stable/struct.stderr new file mode 100644 index 0000000000..a93d7c45b0 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/struct.stderr @@ -0,0 +1,131 @@ +error: unsupported on generic structs that are not repr(transparent) or repr(packed) + --> tests/ui-stable/struct.rs:55:10 + | +55 | #[derive(AsBytes)] + | ^^^^^^^ + | + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/struct.rs:80:11 + | +80 | #[repr(C, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/struct.rs:84:21 + | +84 | #[repr(transparent, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/struct.rs:90:16 + | +90 | #[repr(packed, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/struct.rs:94:18 + | +94 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/struct.rs:98:8 + | +98 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0692]: transparent struct cannot have other repr hints + --> tests/ui-stable/struct.rs:84:8 + | +84 | #[repr(transparent, align(2))] + | ^^^^^^^^^^^ ^^^^^^^^ + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/struct.rs:31:10 + | +31 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `KL00`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `KL00` + --> tests/ui-stable/struct.rs:32:8 + | +32 | struct KL00(u8, NotKnownLayoutDst); + | ^^^^ + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/struct.rs:36:10 + | +36 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `KL02`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `KL02` + --> tests/ui-stable/struct.rs:37:8 + | +37 | struct KL02(u8, [u8]); + | ^^^^ + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotKnownLayoutDst: KnownLayout` is not satisfied + --> tests/ui-stable/struct.rs:41:10 + | +41 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayoutDst` + | + = help: the following other types implement trait `KnownLayout`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotKnownLayout: KnownLayout` is not satisfied + --> tests/ui-stable/struct.rs:47:10 + | +47 | #[derive(KnownLayout)] + | ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayout` + | + = help: the following other types implement trait `KnownLayout`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + = help: see issue #48214 + = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-stable/struct.rs:59:10 + | +59 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the trait `ShouldBe` is implemented for `HasPadding` + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-stable/struct.rs:66:10 + | +66 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the trait `ShouldBe` is implemented for `HasPadding` + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/union.rs b/third_party/rust/zerocopy-derive/tests/ui-stable/union.rs new file mode 100644 index 0000000000..8938e78478 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/union.rs @@ -0,0 +1,73 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[macro_use] +extern crate zerocopy; + +#[path = "../util.rs"] +mod util; + +use self::util::AU16; +use std::mem::ManuallyDrop; + +fn main() {} + +// +// AsBytes errors +// + +#[derive(AsBytes)] +#[repr(C)] +union AsBytes1 { + foo: ManuallyDrop, +} + +#[derive(AsBytes)] +#[repr(C)] +union AsBytes2 { + foo: u8, + bar: [u8; 2], +} + +// +// Unaligned errors +// + +#[derive(Unaligned)] +#[repr(C, align(2))] +union Unaligned1 { + foo: i16, + bar: AU16, +} + +// Transparent unions are unstable; see issue #60405 +// for more information. + +// #[derive(Unaligned)] +// #[repr(transparent, align(2))] +// union Unaligned2 { +// foo: u8, +// } + +#[derive(Unaligned)] +#[repr(packed, align(2))] +union Unaligned3 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(align(1), align(2))] +struct Unaligned4 { + foo: u8, +} + +#[derive(Unaligned)] +#[repr(align(2), align(4))] +struct Unaligned5 { + foo: u8, +} diff --git a/third_party/rust/zerocopy-derive/tests/ui-stable/union.stderr b/third_party/rust/zerocopy-derive/tests/ui-stable/union.stderr new file mode 100644 index 0000000000..8d5cbbbd66 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/ui-stable/union.stderr @@ -0,0 +1,41 @@ +error: unsupported on types with type parameters + --> tests/ui-stable/union.rs:24:10 + | +24 | #[derive(AsBytes)] + | ^^^^^^^ + | + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/union.rs:42:11 + | +42 | #[repr(C, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/union.rs:58:16 + | +58 | #[repr(packed, align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/union.rs:64:18 + | +64 | #[repr(align(1), align(2))] + | ^^^^^^^^ + +error: cannot derive Unaligned with repr(align(N > 1)) + --> tests/ui-stable/union.rs:70:8 + | +70 | #[repr(align(2), align(4))] + | ^^^^^^^^ + +error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied + --> tests/ui-stable/union.rs:30:10 + | +30 | #[derive(AsBytes)] + | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` + | + = help: the trait `ShouldBe` is implemented for `HasPadding` + = help: see issue #48214 + = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy-derive/tests/union_as_bytes.rs b/third_party/rust/zerocopy-derive/tests/union_as_bytes.rs new file mode 100644 index 0000000000..84f51817f2 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/union_as_bytes.rs @@ -0,0 +1,75 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +use std::{marker::PhantomData, option::IntoIter}; + +use {static_assertions::assert_impl_all, zerocopy::AsBytes}; + +// A union is `AsBytes` if: +// - all fields are `AsBytes` +// - `repr(C)` or `repr(transparent)` and +// - no padding (size of union equals size of each field type) +// - `repr(packed)` + +#[derive(AsBytes, Clone, Copy)] +#[repr(C)] +union CZst { + a: (), +} + +assert_impl_all!(CZst: AsBytes); + +#[derive(AsBytes)] +#[repr(C)] +union C { + a: u8, + b: u8, +} + +assert_impl_all!(C: AsBytes); + +// Transparent unions are unstable; see issue #60405 +// for more information. + +// #[derive(AsBytes)] +// #[repr(transparent)] +// union Transparent { +// a: u8, +// b: CZst, +// } + +// is_as_bytes!(Transparent); + +#[derive(AsBytes)] +#[repr(C, packed)] +union CZstPacked { + a: (), +} + +assert_impl_all!(CZstPacked: AsBytes); + +#[derive(AsBytes)] +#[repr(C, packed)] +union CPacked { + a: u8, + b: i8, +} + +assert_impl_all!(CPacked: AsBytes); + +#[derive(AsBytes)] +#[repr(C, packed)] +union CMultibytePacked { + a: i32, + b: u32, + c: f32, +} + +assert_impl_all!(CMultibytePacked: AsBytes); diff --git a/third_party/rust/zerocopy-derive/tests/union_from_bytes.rs b/third_party/rust/zerocopy-derive/tests/union_from_bytes.rs new file mode 100644 index 0000000000..4635735ef1 --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/union_from_bytes.rs @@ -0,0 +1,72 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +use std::{marker::PhantomData, option::IntoIter}; + +use { + static_assertions::assert_impl_all, + zerocopy::{FromBytes, FromZeroes}, +}; + +// A union is `FromBytes` if: +// - all fields are `FromBytes` + +#[derive(Clone, Copy, FromZeroes, FromBytes)] +union Zst { + a: (), +} + +assert_impl_all!(Zst: FromBytes); + +#[derive(FromZeroes, FromBytes)] +union One { + a: u8, +} + +assert_impl_all!(One: FromBytes); + +#[derive(FromZeroes, FromBytes)] +union Two { + a: u8, + b: Zst, +} + +assert_impl_all!(Two: FromBytes); + +#[derive(FromZeroes, FromBytes)] +union TypeParams<'a, T: Copy, I: Iterator> +where + I::Item: Copy, +{ + a: T, + c: I::Item, + d: u8, + e: PhantomData<&'a [u8]>, + f: PhantomData<&'static str>, + g: PhantomData, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromBytes); + +// Deriving `FromBytes` should work if the union has bounded parameters. + +#[derive(FromZeroes, FromBytes)] +#[repr(C)] +union WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromBytes> +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + Copy + FromBytes, +{ + a: [T; N], + b: PhantomData<&'a &'b ()>, +} + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromBytes); diff --git a/third_party/rust/zerocopy-derive/tests/union_from_zeroes.rs b/third_party/rust/zerocopy-derive/tests/union_from_zeroes.rs new file mode 100644 index 0000000000..935fc1563b --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/union_from_zeroes.rs @@ -0,0 +1,72 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +#[macro_use] +mod util; + +use std::{marker::PhantomData, option::IntoIter}; + +use {static_assertions::assert_impl_all, zerocopy::FromZeroes}; + +// A union is `FromZeroes` if: +// - all fields are `FromZeroes` + +#[derive(Clone, Copy, FromZeroes)] +union Zst { + a: (), +} + +assert_impl_all!(Zst: FromZeroes); + +#[derive(FromZeroes)] +union One { + a: bool, +} + +assert_impl_all!(One: FromZeroes); + +#[derive(FromZeroes)] +union Two { + a: bool, + b: Zst, +} + +assert_impl_all!(Two: FromZeroes); + +#[derive(FromZeroes)] +union TypeParams<'a, T: Copy, I: Iterator> +where + I::Item: Copy, +{ + a: T, + c: I::Item, + d: u8, + e: PhantomData<&'a [u8]>, + f: PhantomData<&'static str>, + g: PhantomData, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromZeroes); + +// Deriving `FromZeroes` should work if the union has bounded parameters. + +#[derive(FromZeroes)] +#[repr(C)] +union WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromZeroes> +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + Copy + FromZeroes, +{ + a: [T; N], + b: PhantomData<&'a &'b ()>, +} + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromZeroes); diff --git a/third_party/rust/zerocopy-derive/tests/union_known_layout.rs b/third_party/rust/zerocopy-derive/tests/union_known_layout.rs new file mode 100644 index 0000000000..337ab4afef --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/union_known_layout.rs @@ -0,0 +1,65 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#![allow(warnings)] + +#[macro_use] +mod util; + +use std::{marker::PhantomData, option::IntoIter}; + +use {static_assertions::assert_impl_all, zerocopy::KnownLayout}; + +#[derive(Clone, Copy, KnownLayout)] +union Zst { + a: (), +} + +assert_impl_all!(Zst: KnownLayout); + +#[derive(KnownLayout)] +union One { + a: bool, +} + +assert_impl_all!(One: KnownLayout); + +#[derive(KnownLayout)] +union Two { + a: bool, + b: Zst, +} + +assert_impl_all!(Two: KnownLayout); + +#[derive(KnownLayout)] +union TypeParams<'a, T: Copy, I: Iterator> +where + I::Item: Copy, +{ + a: T, + c: I::Item, + d: u8, + e: PhantomData<&'a [u8]>, + f: PhantomData<&'static str>, + g: PhantomData, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: KnownLayout); + +// Deriving `KnownLayout` should work if the union has bounded parameters. + +#[derive(KnownLayout)] +#[repr(C)] +union WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + KnownLayout> +where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + Copy + KnownLayout, +{ + a: [T; N], + b: PhantomData<&'a &'b ()>, +} + +assert_impl_all!(WithParams<'static, 'static, 42, u8>: KnownLayout); diff --git a/third_party/rust/zerocopy-derive/tests/union_unaligned.rs b/third_party/rust/zerocopy-derive/tests/union_unaligned.rs new file mode 100644 index 0000000000..5ba3ac76ac --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/union_unaligned.rs @@ -0,0 +1,77 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(warnings)] + +use std::{marker::PhantomData, option::IntoIter}; + +use {static_assertions::assert_impl_all, zerocopy::Unaligned}; + +// A union is `Unaligned` if: +// - `repr(align)` is no more than 1 and either +// - `repr(C)` or `repr(transparent)` and +// - all fields `Unaligned` +// - `repr(packed)` + +#[derive(Unaligned)] +#[repr(C)] +union Foo { + a: u8, +} + +assert_impl_all!(Foo: Unaligned); + +// Transparent unions are unstable; see issue #60405 +// for more information. + +// #[derive(Unaligned)] +// #[repr(transparent)] +// union Bar { +// a: u8, +// } + +// is_unaligned!(Bar); + +#[derive(Unaligned)] +#[repr(packed)] +union Baz { + // NOTE: The `u16` type is not guaranteed to have alignment 2, although it + // does on many platforms. However, to fix this would require a custom type + // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not + // allowed to transitively contain `#[repr(align(...))]` types. Thus, we + // have no choice but to use `u16` here. Luckily, these tests run in CI on + // platforms on which `u16` has alignment 2, so this isn't that big of a + // deal. + a: u16, +} + +assert_impl_all!(Baz: Unaligned); + +#[derive(Unaligned)] +#[repr(C, align(1))] +union FooAlign { + a: u8, +} + +assert_impl_all!(FooAlign: Unaligned); + +#[derive(Unaligned)] +#[repr(C)] +union TypeParams<'a, T: Copy, I: Iterator> +where + I::Item: Copy, +{ + a: T, + c: I::Item, + d: u8, + e: PhantomData<&'a [u8]>, + f: PhantomData<&'static str>, + g: PhantomData, +} + +assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: Unaligned); diff --git a/third_party/rust/zerocopy-derive/tests/util.rs b/third_party/rust/zerocopy-derive/tests/util.rs new file mode 100644 index 0000000000..a8656fb20f --- /dev/null +++ b/third_party/rust/zerocopy-derive/tests/util.rs @@ -0,0 +1,20 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use zerocopy::{AsBytes, FromBytes, FromZeroes, KnownLayout}; + +/// A type that doesn't implement any zerocopy traits. +pub struct NotZerocopy(T); + +/// A `u16` with alignment 2. +/// +/// Though `u16` has alignment 2 on some platforms, it's not guaranteed. By +/// contrast, `AU16` is guaranteed to have alignment 2. +#[derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Copy, Clone)] +#[repr(C, align(2))] +pub struct AU16(u16); diff --git a/third_party/rust/zerocopy/.cargo-checksum.json b/third_party/rust/zerocopy/.cargo-checksum.json new file mode 100644 index 0000000000..9025e8f525 --- /dev/null +++ b/third_party/rust/zerocopy/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CONTRIBUTING.md":"47968395d4bee21ffd1f4e665625ba6c89b841a71dc92d0cac432aafbcbfe027","Cargo.toml":"61ae2f6dcb97a4acc33f221b8110de9c171437ccf69902f172c6ef71934e1458","INTERNAL.md":"d6f3929776cd6b195d926dda36b7db287f92fa17ed8dabb0c9c12eb6f945bd61","LICENSE-APACHE":"9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3","LICENSE-BSD":"83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32","LICENSE-MIT":"1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df","POLICIES.md":"c889920550fcd6aa0477ae1f9a1c6aa6f48bc0c5923b035d5ae8af4d3ce06b91","README.md":"a2a01b58f7344a1a03b314d545d221e1a22642071d2067ebefbeb0d1c63a27d0","cargo.sh":"ea53cc247d35243fbe161024890f7c2f855688b8fd26b7244df5ae999ba99bd2","clippy.toml":"df67a6131fff2fe52309e797d2dfad080fc8cbdfcb1baa7f14415b3e397c291c","generate-readme.sh":"0b86377c6ca87971154b8f461e71d72727ecb65e550d2f96729d8949e5264155","rustfmt.toml":"33a21d11175200d203fcdb803c61a24fc461661bf8a2de7c9189af7ecee123c2","src/byteorder.rs":"1fe45a93aefe6ecaa08217c7203ee94d93ae3fcd57113025cf789d26953f12e8","src/lib.rs":"2f21f18a4ca1d4be2d997f037158cb21a7421b2ba2cc52f3e4c5f9410197ed27","src/macro_util.rs":"23ac66f9e011a21c63c65bd2e8a4aadc90706f4d375239a5a0bbe309c588c8de","src/macros.rs":"6c6d794ad398131892c6541bb1a172b10144241057c0d79d1807cc97298beb42","src/post_monomorphization_compile_fail_tests.rs":"6f20b9ddb9d8c2573f2f0c18f58998b9207e588190586891f48b00570f7d4623","src/third_party/rust/LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","src/third_party/rust/LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","src/third_party/rust/README.fuchsia":"5dc26ec369c273eb99679b43c5de4c41c82797e8800c3926c4c76912e9596ecf","src/third_party/rust/layout.rs":"bf602961483f1ed0266602c00bc31345da38f4601954ed4a673f26d7ae8199b9","src/util.rs":"8bf8c2c12bba9596d38018f90da90a9aa310d9c1c677f318ecec40b1811885aa","src/wrappers.rs":"598520c9f56a1c6dff65f615cb386b95a02b131de72afd8b70dcdb2eabe993f1","testdata/include_value/data":"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589","tests/trybuild.rs":"8b77ed684725d2e99fd7806d8f361cd2495b388cc463be3ff2fae25bcbe34c56","tests/ui-msrv/include_value_not_from_bytes.rs":"ea2a419e0c7ce12b4febe6139523184cba2b2c54c879177e0c58a5f78f0ec340","tests/ui-msrv/include_value_not_from_bytes.stderr":"57d634cea8f0906b08e7eea056d09b02364f2a656623116c29fdc706b5393926","tests/ui-msrv/include_value_wrong_size.rs":"418e8c86ebf5a28ee50bd6ae00550f62a7a0ef3a7e7fda965b3d2337b64f2c66","tests/ui-msrv/include_value_wrong_size.stderr":"40bcc6c0172b530cda18bf60d35550e219254a71c0a1e4b16417b17db6d18829","tests/ui-msrv/invalid-impls/invalid-impls.rs":"474d843ad40f3936adcd3ff592d815d8169813962ab9d99a68348b4b91aef10e","tests/ui-msrv/invalid-impls/invalid-impls.stderr":"ddc7a15d675f91b8b838c5c1b8e0d3973d981b11ce956e0f50d4880f0ff0e408","tests/ui-msrv/max-align.rs":"ffcb6687c98e5629d01b17cbd0845ec195007cc39aa244b26a77d17688c8f13d","tests/ui-msrv/max-align.stderr":"38775aa2a8bc035eedbc57ab0081c865b804d9a7fc5200ec425210fdea6a69d1","tests/ui-msrv/transmute-dst-not-frombytes.rs":"e00251eae67cdf8267a4963f212857a2a51de640a6f856c4b8df2a953caad25a","tests/ui-msrv/transmute-dst-not-frombytes.stderr":"537111d0377c9a255bb9cd43fa12646a901f0b8cf6b1fb5842fb5f0d41ea86e8","tests/ui-msrv/transmute-mut-alignment-increase.rs":"ba83c9cf01acf11352f7ee5b54cd73a451394fd78b8ddeb0637931c87adfd6ae","tests/ui-msrv/transmute-mut-alignment-increase.stderr":"9e879881032ab5ba28f8cc6a240bf96150c4a7fb3e55b1de0c808dc5e0b1179d","tests/ui-msrv/transmute-mut-const.rs":"4227f4c0dda6d6128f41b209ecc2bf941c7659c8de84cc0e418862d279baa78f","tests/ui-msrv/transmute-mut-const.stderr":"3c8dcb20b8cffd73f3b330b0199c5912ff015b51fce6d3acf684e388abb70a9c","tests/ui-msrv/transmute-mut-dst-generic.rs":"aa015679b75dac0c37d5c43782b5e9522257f6ba34a10a89d0c1eba524a7af5c","tests/ui-msrv/transmute-mut-dst-generic.stderr":"d19ae09a138d21aa64da708da85fd09b9b98a70c76cf397f5cbe7866ccbddbed","tests/ui-msrv/transmute-mut-dst-not-a-reference.rs":"5d784ab588f081bfc304501f811a85ea2662f88fff8274ccbd53172ec255212c","tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr":"1cca08728f4b93b78757224420090f4ec0a2014043e9b1d86ffafe9fcc8f1faa","tests/ui-msrv/transmute-mut-dst-not-asbytes.rs":"b1f986b3433980d7572a80511ca5a758c91e0c761d01c50bc73ed025d45698a6","tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr":"fd4a28b880eebd3d4f4b1f0388a26b372b07fd8186979970e2ea881379bf007b","tests/ui-msrv/transmute-mut-dst-not-frombytes.rs":"a4353eeb67b4701908e694738c5c4ce965afe4432f14e00e740684352f5ddd30","tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr":"fd9e4c396c995be82b4bda2a28565f5d427d9733ae85f56cfb3922b1130fa06a","tests/ui-msrv/transmute-mut-dst-unsized.rs":"58c3423c07dd06ca98e61439f318ba5f3f7fc68ca9cb59371ebc482ad54709db","tests/ui-msrv/transmute-mut-dst-unsized.stderr":"b0c443b692859195ade80fb3650d51b4a01c2dd8b523322db84acfc3845b154d","tests/ui-msrv/transmute-mut-illegal-lifetime.rs":"ec18bf7b3d9bd2674b43d0e04fc0545227473d43b07e2bbccc19c2068df33673","tests/ui-msrv/transmute-mut-illegal-lifetime.stderr":"ff5965b190242ce05735d7c072c11565c5bd8609261c83dd06396ae8416dfbaa","tests/ui-msrv/transmute-mut-size-decrease.rs":"51aa423ec51a3c5579bbd7bac33adac8040629adc94eec3fb84825ef4f84f7bb","tests/ui-msrv/transmute-mut-size-decrease.stderr":"ae0c86cfbd85107ea908218c5389218a64a46ccf53a0bc553b9c17b48f475e0f","tests/ui-msrv/transmute-mut-size-increase.rs":"ecc34f87b2ec668338672be6bac82b4056ebe35d98fd5d9a210f43f7e866b8e1","tests/ui-msrv/transmute-mut-size-increase.stderr":"d8f4c9f85c59cf24f88e08b3e67796d1218a512e0082100bb63fe38a69186484","tests/ui-msrv/transmute-mut-src-dst-generic.rs":"613e00a353d1b359b57450bb408da585528f84b7eaf039a0c8d86bde1803395f","tests/ui-msrv/transmute-mut-src-dst-generic.stderr":"ec064415b76e341316de3886f3222ab826c2621ea641eb62285b1814369f48c2","tests/ui-msrv/transmute-mut-src-dst-not-references.rs":"0b73d42fbcecba3483e24d4e9296d24d551de18822b45120e225356c5ccefad8","tests/ui-msrv/transmute-mut-src-dst-not-references.stderr":"fc2740d55afdb07bdde457ac259f48ef5b3e13503968299e51791576328b207d","tests/ui-msrv/transmute-mut-src-dst-unsized.rs":"8ccf11a1990dbfd7ed7180c5e73e3a278f072f0a86eb2810f1b2c737ece76c57","tests/ui-msrv/transmute-mut-src-dst-unsized.stderr":"a47a39be560a9a80a31ebd6ee30178f2e375e9450c61a86effb3611f654e302c","tests/ui-msrv/transmute-mut-src-generic.rs":"2cfe526643436df07247cc2583e1d097b247411185952132433127a159527669","tests/ui-msrv/transmute-mut-src-generic.stderr":"a7588c104a34936839fdef78029fdc3929f08f6befac2a94ef5fce5364cd89ca","tests/ui-msrv/transmute-mut-src-immutable.rs":"606aba0c01726255c9be7e67a032ce854209c62dffec16d5dd2c8f484e19979a","tests/ui-msrv/transmute-mut-src-immutable.stderr":"6854b18881116cecf0c716eac01aac312bfe43a295a797c4ad01ac8b7ea7d81c","tests/ui-msrv/transmute-mut-src-not-a-reference.rs":"e627a60c6f6d1b398bdcfc9307dbc57b268cc784b4967d1afaceed7eebd5db47","tests/ui-msrv/transmute-mut-src-not-a-reference.stderr":"538af460b18f588b6075307de50ba1307f98189d2f2aea74346a77ad8b64710c","tests/ui-msrv/transmute-mut-src-not-asbytes.rs":"d0a6ddcfe31ac34ccc550090b80a67a010202bee12a39c230dd4374ef81a520c","tests/ui-msrv/transmute-mut-src-not-asbytes.stderr":"446ab2326cedeae89bd951561206dddcb546684629b12e46e3de1025caa7c894","tests/ui-msrv/transmute-mut-src-not-frombytes.rs":"5866e7d74baf3efb500338ba91a76f221e4a2479376e6921ec831fa284c9b3db","tests/ui-msrv/transmute-mut-src-not-frombytes.stderr":"659915278b39092444f82347fbd62d4bd0c12cecb1d5976159b3fd90c8b995f2","tests/ui-msrv/transmute-mut-src-unsized.rs":"6676d8f29f0a32418f86d4423c464f4e0fdb8fe9ee8aa87f86c5fcdf8bd5e197","tests/ui-msrv/transmute-mut-src-unsized.stderr":"7f9a60f0bafa5d59403e49f2a6b68a56fa2be6c2a62d785fe4cb51bc056159cc","tests/ui-msrv/transmute-ptr-to-usize.rs":"ea33dc39115509988d9abd6ac6536d88d82082417b21da9f9bc8cf8369c69618","tests/ui-msrv/transmute-ptr-to-usize.stderr":"e8713417a977f07158a58aec6690c3a79b49cf5edb9e66f6c1d218a1a55f47eb","tests/ui-msrv/transmute-ref-alignment-increase.rs":"a5028469f90ca572ec1c73131f9a8a0a1cbca47de0dcb9003ba98de378def783","tests/ui-msrv/transmute-ref-alignment-increase.stderr":"2c56277ab280ac4477ccd3ca4c48ac60e096a95579bfea58da81d9082d8ab499","tests/ui-msrv/transmute-ref-dst-generic.rs":"4a6b56491fd59646d1d1d8edbcc9d7de0dc69a9e6e4779f3cfd90e287f11557c","tests/ui-msrv/transmute-ref-dst-generic.stderr":"8f47f9eabb44e8d5c561359237e79d42a998b615b526666e16db325b9cea8a09","tests/ui-msrv/transmute-ref-dst-mutable.rs":"1c48caae9912f70dec5f5a99a0c880fe6a3022f11fd412438b8a1576803e5f73","tests/ui-msrv/transmute-ref-dst-mutable.stderr":"289e040b3e725546081dfd07640e499a5622915954f12c871708d3f46ff43d7a","tests/ui-msrv/transmute-ref-dst-not-a-reference.rs":"c4b8a6c1970e30390d0a301e2dbe718b9eeef743299f7e91cd12c582ec203af7","tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr":"b6c1f2aede85cce47f5ca379b9ae5a77c777e7c60de6590578c47432ebacae88","tests/ui-msrv/transmute-ref-dst-not-frombytes.rs":"42aab9630fbab93f400713a1730d6dd6a89f821b0fa4dd5347aabe5e78b13aff","tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr":"00b6c3472c0f84f4e32217c1c839c0eab1bf449abbc8bb8f60878ce62c360c8b","tests/ui-msrv/transmute-ref-dst-unsized.rs":"c374df8d00541fd34fff37e231e341501a427961f60d88ad3e3c375085cc060d","tests/ui-msrv/transmute-ref-dst-unsized.stderr":"73636b1d142730f1330753c3fa14c88a32a23bf1c0741503b99610a506a8f66b","tests/ui-msrv/transmute-ref-illegal-lifetime.rs":"6812bbf7ec851a8591464f10864dbd1f225e65ed5793b6f6375cbe8a9db50b14","tests/ui-msrv/transmute-ref-illegal-lifetime.stderr":"4f2a3e71cda94564f2343ca9ff23de3eca0d2ff465cedacab187151183813092","tests/ui-msrv/transmute-ref-size-decrease.rs":"939fb562e4678368e59fdafb3a597fd54a661fd09d9ecb23c6e626ff59b45384","tests/ui-msrv/transmute-ref-size-decrease.stderr":"686597597e9f87e717b702bf6b8b6a52d14c5612ec267d48a01b442ab14648e1","tests/ui-msrv/transmute-ref-size-increase.rs":"f66ab294f7618abfac5c503570137759afceb0dd26c8802bb1786b8873fe5670","tests/ui-msrv/transmute-ref-size-increase.stderr":"f1ad62609362a24b5cf47761e30e2cf0a35db82682e041faf251b2a1f822da7c","tests/ui-msrv/transmute-ref-src-dst-generic.rs":"96a6f6580307e6a397af8ca688a8a65144dff5240372203bd9f02bad6a41fd1e","tests/ui-msrv/transmute-ref-src-dst-generic.stderr":"ca3c1493cbab64b5af7c3c4ea88ca16f6bb2478865b0dbe9d4a28d3b11d5fad1","tests/ui-msrv/transmute-ref-src-dst-not-references.rs":"7311602a0153b260d819e9608e8e66ef5904919a2349a95187919d8211e48e23","tests/ui-msrv/transmute-ref-src-dst-not-references.stderr":"003bb1ccb5cf8322416e00e0fa5645f94d76aad875e60d281daae9625eb583a4","tests/ui-msrv/transmute-ref-src-dst-unsized.rs":"f83e0225e824b7526d7732ef5d759b32358e5db50c3c6a318d2b5dcc2eb3c707","tests/ui-msrv/transmute-ref-src-dst-unsized.stderr":"558be2a5b90f3b3a304d5ae94ed3f7cd369e1e0ad03991ff57500913232ea8de","tests/ui-msrv/transmute-ref-src-generic.rs":"ac1699aeca61c82aff5dac51d387a4ef7522faf2b2dfc56af398a2dc9d53745b","tests/ui-msrv/transmute-ref-src-generic.stderr":"2ba4f5f66b2a2eae90f2cb4b28bb92b066fcaf17412ca777e7d9823697d64736","tests/ui-msrv/transmute-ref-src-not-a-reference.rs":"a921f168fa6cb3c6a19894cecdb118bc3164275746672a916aa5194b92f2fb57","tests/ui-msrv/transmute-ref-src-not-a-reference.stderr":"5a8d829089820ec79d9cd8d9ffac7dbde430914fdad691d46edcd96414d5cad0","tests/ui-msrv/transmute-ref-src-not-asbytes.rs":"09aabae9e4634a5432bf7225240954d7b0592994c97a927e0469e27854588232","tests/ui-msrv/transmute-ref-src-not-asbytes.stderr":"bbd65ef7225a7a39f8c53362a1f137a6b294227b0d2b658fa8082742cda4a8bf","tests/ui-msrv/transmute-ref-src-unsized.rs":"d7797488f0ab5db89944ac7db25625c63aef72e6e4ed481d00a083449050b813","tests/ui-msrv/transmute-ref-src-unsized.stderr":"68537a0c14f72addd12d9e2a75f1a965e730a7ee8da04303402ecd69fe6de95e","tests/ui-msrv/transmute-size-decrease.rs":"c63dd10ddab58e282b033132d79fd21e80edb0c654f856679237977f62ced1ed","tests/ui-msrv/transmute-size-decrease.stderr":"978a9600a42a75fb33e46d10ac1485ef7c0a26054d15e52ec7e13023780d919e","tests/ui-msrv/transmute-size-increase.rs":"9413442e6e3c574bd7e36e8d4242000c1513624a4edc97567695a81b5851c491","tests/ui-msrv/transmute-size-increase.stderr":"168c9bb1045d125b069859d88132b7855a161e1353e1ff3d3f0bfcb70a831128","tests/ui-msrv/transmute-src-not-asbytes.rs":"8e2a76d99734c0502ba9daa8c7c2e34ca830ffd6024d3f7f29363d4263e89f74","tests/ui-msrv/transmute-src-not-asbytes.stderr":"e5913ff39e19e7f38b7aebe19f1930810c898d34fb7e7815c1404eff715f0414","tests/ui-nightly/include_value_not_from_bytes.rs":"ea2a419e0c7ce12b4febe6139523184cba2b2c54c879177e0c58a5f78f0ec340","tests/ui-nightly/include_value_not_from_bytes.stderr":"ca8e43f83feaf9210369fe37b2d31cacac7839e9bdd073aa6bcdc4bf11a88354","tests/ui-nightly/include_value_wrong_size.rs":"418e8c86ebf5a28ee50bd6ae00550f62a7a0ef3a7e7fda965b3d2337b64f2c66","tests/ui-nightly/include_value_wrong_size.stderr":"2b340b79ab4de286609aa5bf561c550ac3f30818df34bc659b54a58f4565501b","tests/ui-nightly/invalid-impls/invalid-impls.rs":"474d843ad40f3936adcd3ff592d815d8169813962ab9d99a68348b4b91aef10e","tests/ui-nightly/invalid-impls/invalid-impls.stderr":"0666e32657fa5f7292c62f34c0178c8dc442c53cf6f4d795894684b3e7b3e570","tests/ui-nightly/max-align.rs":"ffcb6687c98e5629d01b17cbd0845ec195007cc39aa244b26a77d17688c8f13d","tests/ui-nightly/max-align.stderr":"c346c1cbc54039a3fc7d8b69bce45d7306d16ca3b0092fcea478306171cf1318","tests/ui-nightly/transmute-dst-not-frombytes.rs":"e00251eae67cdf8267a4963f212857a2a51de640a6f856c4b8df2a953caad25a","tests/ui-nightly/transmute-dst-not-frombytes.stderr":"046d7e096f089ede594d360a36a9c1ab9f6e456576218fee3c9781169bf3adc4","tests/ui-nightly/transmute-mut-alignment-increase.rs":"ba83c9cf01acf11352f7ee5b54cd73a451394fd78b8ddeb0637931c87adfd6ae","tests/ui-nightly/transmute-mut-alignment-increase.stderr":"db521ff9c180434136b0e8421823435be8ed23c7ac85d9a83c479ad1b8153281","tests/ui-nightly/transmute-mut-const.rs":"4227f4c0dda6d6128f41b209ecc2bf941c7659c8de84cc0e418862d279baa78f","tests/ui-nightly/transmute-mut-const.stderr":"3d84712235a0e819e0286ddfccbf771cf3d4b03c944eb2794b75555499b3295f","tests/ui-nightly/transmute-mut-dst-generic.rs":"aa015679b75dac0c37d5c43782b5e9522257f6ba34a10a89d0c1eba524a7af5c","tests/ui-nightly/transmute-mut-dst-generic.stderr":"d012039fa54f3d7cc8ee7275637964e7d83f8067545260676326b571bca46617","tests/ui-nightly/transmute-mut-dst-not-a-reference.rs":"5d784ab588f081bfc304501f811a85ea2662f88fff8274ccbd53172ec255212c","tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr":"9d21ae45aff909bf6e6feca6c60fae8db1e4318935aede558bee1e243ede59f8","tests/ui-nightly/transmute-mut-dst-not-asbytes.rs":"b1f986b3433980d7572a80511ca5a758c91e0c761d01c50bc73ed025d45698a6","tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr":"5d77d9085413d8cea2572b574e882b7894898c2ec771059ff2b0e5f6acd11ca7","tests/ui-nightly/transmute-mut-dst-not-frombytes.rs":"a4353eeb67b4701908e694738c5c4ce965afe4432f14e00e740684352f5ddd30","tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr":"6d4f31f9698099bf52e45debdbaafd4ae85fb74c353d3d76c20fdb6414ea7a9b","tests/ui-nightly/transmute-mut-dst-unsized.rs":"58c3423c07dd06ca98e61439f318ba5f3f7fc68ca9cb59371ebc482ad54709db","tests/ui-nightly/transmute-mut-dst-unsized.stderr":"0df79b2009b5f8d237d81957b5fbaa04181de59306ba2fe77027081592f4c6d9","tests/ui-nightly/transmute-mut-illegal-lifetime.rs":"ec18bf7b3d9bd2674b43d0e04fc0545227473d43b07e2bbccc19c2068df33673","tests/ui-nightly/transmute-mut-illegal-lifetime.stderr":"b0379252732ca51314077fa20d3fb4bfcbee61f486229547c807ed0d7dede9c8","tests/ui-nightly/transmute-mut-size-decrease.rs":"51aa423ec51a3c5579bbd7bac33adac8040629adc94eec3fb84825ef4f84f7bb","tests/ui-nightly/transmute-mut-size-decrease.stderr":"9294c2562503924704673967f93afbfd4b1d84abbf76318636105acdc3f37a63","tests/ui-nightly/transmute-mut-size-increase.rs":"ecc34f87b2ec668338672be6bac82b4056ebe35d98fd5d9a210f43f7e866b8e1","tests/ui-nightly/transmute-mut-size-increase.stderr":"6858e39d6238843faa0ec4bf199f88d5013f1b50a811f5e882837f01eea00f93","tests/ui-nightly/transmute-mut-src-dst-generic.rs":"613e00a353d1b359b57450bb408da585528f84b7eaf039a0c8d86bde1803395f","tests/ui-nightly/transmute-mut-src-dst-generic.stderr":"f6a7bb45e58bf80a25a4e694e881f9c38f2a5d33817d9337d41a6d2c2aef93e8","tests/ui-nightly/transmute-mut-src-dst-not-references.rs":"0b73d42fbcecba3483e24d4e9296d24d551de18822b45120e225356c5ccefad8","tests/ui-nightly/transmute-mut-src-dst-not-references.stderr":"0e1e17242ec0b1e9052087b18ccdde9fa117e430a3675b624c49d36eb933ee88","tests/ui-nightly/transmute-mut-src-dst-unsized.rs":"8ccf11a1990dbfd7ed7180c5e73e3a278f072f0a86eb2810f1b2c737ece76c57","tests/ui-nightly/transmute-mut-src-dst-unsized.stderr":"608ed4e9d52c8c52773afea6565c42e30d8c6791c8a8d929235eb0bdcd9db1a6","tests/ui-nightly/transmute-mut-src-generic.rs":"2cfe526643436df07247cc2583e1d097b247411185952132433127a159527669","tests/ui-nightly/transmute-mut-src-generic.stderr":"3c54bad3b3ab88b5c046bfb6ef79e0162ec7228447a1ba8321d9da754d536f20","tests/ui-nightly/transmute-mut-src-immutable.rs":"606aba0c01726255c9be7e67a032ce854209c62dffec16d5dd2c8f484e19979a","tests/ui-nightly/transmute-mut-src-immutable.stderr":"d99fc596f5732e5a4b193028812e047ba0c748017a94fd55d4f7802849159359","tests/ui-nightly/transmute-mut-src-not-a-reference.rs":"e627a60c6f6d1b398bdcfc9307dbc57b268cc784b4967d1afaceed7eebd5db47","tests/ui-nightly/transmute-mut-src-not-a-reference.stderr":"3085a0120d3dcbc1d01d226e0b4235fe39da9a956444aabdedac9ec938aca609","tests/ui-nightly/transmute-mut-src-not-asbytes.rs":"d0a6ddcfe31ac34ccc550090b80a67a010202bee12a39c230dd4374ef81a520c","tests/ui-nightly/transmute-mut-src-not-asbytes.stderr":"7cd91c207adb2b3bc9d2f3f5eaa2409f6290c429eb393533676f9f7628420623","tests/ui-nightly/transmute-mut-src-not-frombytes.rs":"5866e7d74baf3efb500338ba91a76f221e4a2479376e6921ec831fa284c9b3db","tests/ui-nightly/transmute-mut-src-not-frombytes.stderr":"95f362f717bbed7501d9e328b6369a76a4b10c167e062272e64a1b8887669114","tests/ui-nightly/transmute-mut-src-unsized.rs":"6676d8f29f0a32418f86d4423c464f4e0fdb8fe9ee8aa87f86c5fcdf8bd5e197","tests/ui-nightly/transmute-mut-src-unsized.stderr":"9ac64e0b1c4afe6fe4bc20e63f7c22e89d596377212ac3c3ebf87ea12096818a","tests/ui-nightly/transmute-ptr-to-usize.rs":"ea33dc39115509988d9abd6ac6536d88d82082417b21da9f9bc8cf8369c69618","tests/ui-nightly/transmute-ptr-to-usize.stderr":"f05ba5ad01e235eed456686a1ee5b7a668495c38054155965846d2bd613bd7d8","tests/ui-nightly/transmute-ref-alignment-increase.rs":"a5028469f90ca572ec1c73131f9a8a0a1cbca47de0dcb9003ba98de378def783","tests/ui-nightly/transmute-ref-alignment-increase.stderr":"aef92964ba843b890ce6c6b0924726dd89e1b9d6513f2148c269fe8fa203adac","tests/ui-nightly/transmute-ref-dst-generic.rs":"4a6b56491fd59646d1d1d8edbcc9d7de0dc69a9e6e4779f3cfd90e287f11557c","tests/ui-nightly/transmute-ref-dst-generic.stderr":"06b9fcf8e0443f997c0ef5f8e2659afcb65f095b11162ea69488f89788b337a7","tests/ui-nightly/transmute-ref-dst-mutable.rs":"1c48caae9912f70dec5f5a99a0c880fe6a3022f11fd412438b8a1576803e5f73","tests/ui-nightly/transmute-ref-dst-mutable.stderr":"96d38ce9a807ad7b60a846a8f5558c447da0d6cbe9225a077df4997712424d9a","tests/ui-nightly/transmute-ref-dst-not-a-reference.rs":"c4b8a6c1970e30390d0a301e2dbe718b9eeef743299f7e91cd12c582ec203af7","tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr":"8ed2540877865fcdfca6e150465996a8f2872eb122ed5d647825e9181ae64754","tests/ui-nightly/transmute-ref-dst-not-frombytes.rs":"42aab9630fbab93f400713a1730d6dd6a89f821b0fa4dd5347aabe5e78b13aff","tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr":"ab474a92c39a0810796d51228db2340a4d52915ddbae72a77ac4962e8bf9604e","tests/ui-nightly/transmute-ref-dst-unsized.rs":"c374df8d00541fd34fff37e231e341501a427961f60d88ad3e3c375085cc060d","tests/ui-nightly/transmute-ref-dst-unsized.stderr":"fc2579bc6b9f6fff8b2092fff88d617c98e218ae1399b39dea80d9d71c6112f7","tests/ui-nightly/transmute-ref-illegal-lifetime.rs":"6812bbf7ec851a8591464f10864dbd1f225e65ed5793b6f6375cbe8a9db50b14","tests/ui-nightly/transmute-ref-illegal-lifetime.stderr":"cb98c1b304334e58fc61be1c4b7782e68ab92d90a44c9627326d94d14a44cc38","tests/ui-nightly/transmute-ref-size-decrease.rs":"939fb562e4678368e59fdafb3a597fd54a661fd09d9ecb23c6e626ff59b45384","tests/ui-nightly/transmute-ref-size-decrease.stderr":"14f6ea48e66c484e94f47c3af0983de06869a884cda19b2201548aadc2378758","tests/ui-nightly/transmute-ref-size-increase.rs":"f66ab294f7618abfac5c503570137759afceb0dd26c8802bb1786b8873fe5670","tests/ui-nightly/transmute-ref-size-increase.stderr":"d5777c69b0ee36b6dcaf7699abb3ea03e1a8bac17bb5a1d4059ae28ff5f4357f","tests/ui-nightly/transmute-ref-src-dst-generic.rs":"96a6f6580307e6a397af8ca688a8a65144dff5240372203bd9f02bad6a41fd1e","tests/ui-nightly/transmute-ref-src-dst-generic.stderr":"ebffb5c5318798ff84f1da69c3ba732b9af2ad3688ebd7b4b2770e2b201afccb","tests/ui-nightly/transmute-ref-src-dst-not-references.rs":"7311602a0153b260d819e9608e8e66ef5904919a2349a95187919d8211e48e23","tests/ui-nightly/transmute-ref-src-dst-not-references.stderr":"ca5b956d99998df493f7c72df6bd315b8cd6f1f9b113a45416b0088f1e368900","tests/ui-nightly/transmute-ref-src-dst-unsized.rs":"f83e0225e824b7526d7732ef5d759b32358e5db50c3c6a318d2b5dcc2eb3c707","tests/ui-nightly/transmute-ref-src-dst-unsized.stderr":"35f3ce0a3c11aa4ac6eb65a48089e0025e85fc016ae81566be57e4a1152dac2f","tests/ui-nightly/transmute-ref-src-generic.rs":"ac1699aeca61c82aff5dac51d387a4ef7522faf2b2dfc56af398a2dc9d53745b","tests/ui-nightly/transmute-ref-src-generic.stderr":"b53a09eca6226647cf53ee9bd0388e558def3bd1f8009b6ec74cc26e4db13d1c","tests/ui-nightly/transmute-ref-src-not-a-reference.rs":"a921f168fa6cb3c6a19894cecdb118bc3164275746672a916aa5194b92f2fb57","tests/ui-nightly/transmute-ref-src-not-a-reference.stderr":"f7b51be513a0603070e218bdd1ca2c47a94c58151ab5649f68877ea3d83268f4","tests/ui-nightly/transmute-ref-src-not-asbytes.rs":"09aabae9e4634a5432bf7225240954d7b0592994c97a927e0469e27854588232","tests/ui-nightly/transmute-ref-src-not-asbytes.stderr":"fdc888ef7f049c957bd000c321979f9b61008a1b1ba8dabf323e33676f7de030","tests/ui-nightly/transmute-ref-src-unsized.rs":"d7797488f0ab5db89944ac7db25625c63aef72e6e4ed481d00a083449050b813","tests/ui-nightly/transmute-ref-src-unsized.stderr":"7e874cb32d41946e2e49627fd64b6e0103d65c955a44ccf18edf184312edb68b","tests/ui-nightly/transmute-size-decrease.rs":"c63dd10ddab58e282b033132d79fd21e80edb0c654f856679237977f62ced1ed","tests/ui-nightly/transmute-size-decrease.stderr":"4e014a129866804cf91cc3ff7a8ad1044ae1e3a6aad3b6ff8839605ab1b1df77","tests/ui-nightly/transmute-size-increase.rs":"9413442e6e3c574bd7e36e8d4242000c1513624a4edc97567695a81b5851c491","tests/ui-nightly/transmute-size-increase.stderr":"c307d7a2ae3d18e016be5d77e720bcf7023d03b10bb3ff3190e4d934eb9fc6a7","tests/ui-nightly/transmute-src-not-asbytes.rs":"8e2a76d99734c0502ba9daa8c7c2e34ca830ffd6024d3f7f29363d4263e89f74","tests/ui-nightly/transmute-src-not-asbytes.stderr":"71938c61511f4746a919b7656dc6181e7f0367e9a97b3693563dc9b53302cb8c","tests/ui-stable/include_value_not_from_bytes.rs":"ea2a419e0c7ce12b4febe6139523184cba2b2c54c879177e0c58a5f78f0ec340","tests/ui-stable/include_value_not_from_bytes.stderr":"5aa78f38cdbd69c99a77cc68331fd0bd4bb0a07fd35e807b2aa35dd4c56e56ee","tests/ui-stable/include_value_wrong_size.rs":"418e8c86ebf5a28ee50bd6ae00550f62a7a0ef3a7e7fda965b3d2337b64f2c66","tests/ui-stable/include_value_wrong_size.stderr":"b4fdeefd36bb2343f4e6cfae39c821fcfefd0671ea59205ffeea48318ce4fac7","tests/ui-stable/invalid-impls/invalid-impls.rs":"474d843ad40f3936adcd3ff592d815d8169813962ab9d99a68348b4b91aef10e","tests/ui-stable/invalid-impls/invalid-impls.stderr":"8310e42b17407faecee6c53a357037485f496783d80d40f5faebbb4b6f8483e8","tests/ui-stable/max-align.rs":"ffcb6687c98e5629d01b17cbd0845ec195007cc39aa244b26a77d17688c8f13d","tests/ui-stable/max-align.stderr":"e33783407e633f7b45980d47192402dde119dd31feeda4bc68822926fcf29c07","tests/ui-stable/transmute-dst-not-frombytes.rs":"e00251eae67cdf8267a4963f212857a2a51de640a6f856c4b8df2a953caad25a","tests/ui-stable/transmute-dst-not-frombytes.stderr":"95f850609dfc88c2e47c6667601da35099a6588a939c8f9ea7f5bd3e2d03d20f","tests/ui-stable/transmute-mut-alignment-increase.rs":"ba83c9cf01acf11352f7ee5b54cd73a451394fd78b8ddeb0637931c87adfd6ae","tests/ui-stable/transmute-mut-alignment-increase.stderr":"92f1cda35d0c41a93f93152ad5c77fcd2c9ae17a7f2b4d54a311d434aa586400","tests/ui-stable/transmute-mut-const.rs":"4227f4c0dda6d6128f41b209ecc2bf941c7659c8de84cc0e418862d279baa78f","tests/ui-stable/transmute-mut-const.stderr":"d27b218da464aee431665618ffb4902e4d1a65e4153d25f05591538bf22cd623","tests/ui-stable/transmute-mut-dst-generic.rs":"aa015679b75dac0c37d5c43782b5e9522257f6ba34a10a89d0c1eba524a7af5c","tests/ui-stable/transmute-mut-dst-generic.stderr":"f2c60a1aae05ad780802b0290989c546abe35adcbcacf83a2264446a40ceb5dd","tests/ui-stable/transmute-mut-dst-not-a-reference.rs":"5d784ab588f081bfc304501f811a85ea2662f88fff8274ccbd53172ec255212c","tests/ui-stable/transmute-mut-dst-not-a-reference.stderr":"16a9cf4e0f90772d19c132f50dd0a85e60ecd929a6aa0820fbf568c7f6183d74","tests/ui-stable/transmute-mut-dst-not-asbytes.rs":"b1f986b3433980d7572a80511ca5a758c91e0c761d01c50bc73ed025d45698a6","tests/ui-stable/transmute-mut-dst-not-asbytes.stderr":"aa3615c19ef50b855a4c2feafa09d7af6e7603649df0337e29ca12d352306452","tests/ui-stable/transmute-mut-dst-not-frombytes.rs":"a4353eeb67b4701908e694738c5c4ce965afe4432f14e00e740684352f5ddd30","tests/ui-stable/transmute-mut-dst-not-frombytes.stderr":"5625f642d278fd6617472ba06aa8dda9a78899223ff3b04734060996d5dd67f2","tests/ui-stable/transmute-mut-dst-unsized.rs":"58c3423c07dd06ca98e61439f318ba5f3f7fc68ca9cb59371ebc482ad54709db","tests/ui-stable/transmute-mut-dst-unsized.stderr":"8cad3c8812e78b21667b6b885c3e4c5da025a154ea519f5539e9688802bb2ec4","tests/ui-stable/transmute-mut-illegal-lifetime.rs":"ec18bf7b3d9bd2674b43d0e04fc0545227473d43b07e2bbccc19c2068df33673","tests/ui-stable/transmute-mut-illegal-lifetime.stderr":"3a43e0be32ef3589fe3fa713d387bd3976bd8c75813f9641bbf7c539e10bed41","tests/ui-stable/transmute-mut-size-decrease.rs":"51aa423ec51a3c5579bbd7bac33adac8040629adc94eec3fb84825ef4f84f7bb","tests/ui-stable/transmute-mut-size-decrease.stderr":"b63870c4361917d4cd19fbaba433a9389b806135c9576ae8997c86f3b763fe3c","tests/ui-stable/transmute-mut-size-increase.rs":"ecc34f87b2ec668338672be6bac82b4056ebe35d98fd5d9a210f43f7e866b8e1","tests/ui-stable/transmute-mut-size-increase.stderr":"cb086ebcc60c4e17f8897c62c5b36b110b259c6e970825953798daf37144af47","tests/ui-stable/transmute-mut-src-dst-generic.rs":"613e00a353d1b359b57450bb408da585528f84b7eaf039a0c8d86bde1803395f","tests/ui-stable/transmute-mut-src-dst-generic.stderr":"ff7758361ba41d2bc3a49e9942e9f1f1b76d245f19a5391e45b9a066b8d0f6f4","tests/ui-stable/transmute-mut-src-dst-not-references.rs":"0b73d42fbcecba3483e24d4e9296d24d551de18822b45120e225356c5ccefad8","tests/ui-stable/transmute-mut-src-dst-not-references.stderr":"830581700736527e224bd923da3cd9c215e68556d2379c678174c08eff1501d6","tests/ui-stable/transmute-mut-src-dst-unsized.rs":"8ccf11a1990dbfd7ed7180c5e73e3a278f072f0a86eb2810f1b2c737ece76c57","tests/ui-stable/transmute-mut-src-dst-unsized.stderr":"b8a4632d0ba4229231cd30e8af07bb25dfc3cf1235ebbeb7a62e2ec71ebbef3a","tests/ui-stable/transmute-mut-src-generic.rs":"2cfe526643436df07247cc2583e1d097b247411185952132433127a159527669","tests/ui-stable/transmute-mut-src-generic.stderr":"de709f4435bf09ce98a6a9b19ac69560f85c43b665277ef60c9e62169e4a001f","tests/ui-stable/transmute-mut-src-immutable.rs":"606aba0c01726255c9be7e67a032ce854209c62dffec16d5dd2c8f484e19979a","tests/ui-stable/transmute-mut-src-immutable.stderr":"7c24d82d943695955b3ec1f0a53a349645fd3de1d549f3be989532e3774279bf","tests/ui-stable/transmute-mut-src-not-a-reference.rs":"e627a60c6f6d1b398bdcfc9307dbc57b268cc784b4967d1afaceed7eebd5db47","tests/ui-stable/transmute-mut-src-not-a-reference.stderr":"29b09aea59cfdb4b6535c5d33ec803539f28e53cce81938767ea0c22a1b1ce7d","tests/ui-stable/transmute-mut-src-not-asbytes.rs":"d0a6ddcfe31ac34ccc550090b80a67a010202bee12a39c230dd4374ef81a520c","tests/ui-stable/transmute-mut-src-not-asbytes.stderr":"51daf0724583595017b758d5881e10af3a07f07ce4b03754a909849561125509","tests/ui-stable/transmute-mut-src-not-frombytes.rs":"5866e7d74baf3efb500338ba91a76f221e4a2479376e6921ec831fa284c9b3db","tests/ui-stable/transmute-mut-src-not-frombytes.stderr":"83d60a22c5df81aef9a02033c5a4f097acc0338bde8b380dc053cc422333f8ba","tests/ui-stable/transmute-mut-src-unsized.rs":"6676d8f29f0a32418f86d4423c464f4e0fdb8fe9ee8aa87f86c5fcdf8bd5e197","tests/ui-stable/transmute-mut-src-unsized.stderr":"af53ab7b9b5edd17c9857459cbaf9636a2363196820fc998c4de81ede75ec441","tests/ui-stable/transmute-ptr-to-usize.rs":"ea33dc39115509988d9abd6ac6536d88d82082417b21da9f9bc8cf8369c69618","tests/ui-stable/transmute-ptr-to-usize.stderr":"cba0e2d85a961b56d8fc2566bc555082b52f762ac36b9745e319bb5d1e726514","tests/ui-stable/transmute-ref-alignment-increase.rs":"a5028469f90ca572ec1c73131f9a8a0a1cbca47de0dcb9003ba98de378def783","tests/ui-stable/transmute-ref-alignment-increase.stderr":"514c5254a0e84051cb34bd700c08163a98195730b87e67acda8907d401311b6c","tests/ui-stable/transmute-ref-dst-generic.rs":"4a6b56491fd59646d1d1d8edbcc9d7de0dc69a9e6e4779f3cfd90e287f11557c","tests/ui-stable/transmute-ref-dst-generic.stderr":"0fa2e50dd2f259260511ae3534334420e4384d542daa8532c7d3a625652c2ada","tests/ui-stable/transmute-ref-dst-mutable.rs":"1c48caae9912f70dec5f5a99a0c880fe6a3022f11fd412438b8a1576803e5f73","tests/ui-stable/transmute-ref-dst-mutable.stderr":"fc83b5283cb5319fd7a2b79f94ed0a49f16bce5b222f7e1cc5ce5a879f3de650","tests/ui-stable/transmute-ref-dst-not-a-reference.rs":"c4b8a6c1970e30390d0a301e2dbe718b9eeef743299f7e91cd12c582ec203af7","tests/ui-stable/transmute-ref-dst-not-a-reference.stderr":"e8a126f4832344b8a69591fcc25e22bbbb29f2078b809a47f8afa40ac1087a1f","tests/ui-stable/transmute-ref-dst-not-frombytes.rs":"42aab9630fbab93f400713a1730d6dd6a89f821b0fa4dd5347aabe5e78b13aff","tests/ui-stable/transmute-ref-dst-not-frombytes.stderr":"fb34ebeba63588a4f81763ea0363d4c5501b2dc1452bd5e8334c8fe009b420ae","tests/ui-stable/transmute-ref-dst-unsized.rs":"c374df8d00541fd34fff37e231e341501a427961f60d88ad3e3c375085cc060d","tests/ui-stable/transmute-ref-dst-unsized.stderr":"6024b682bfe79f7d972094f4f77bda7f8ed40f8949e14594a1d20f1fb8389c42","tests/ui-stable/transmute-ref-illegal-lifetime.rs":"6812bbf7ec851a8591464f10864dbd1f225e65ed5793b6f6375cbe8a9db50b14","tests/ui-stable/transmute-ref-illegal-lifetime.stderr":"45ab741d710dc5a01a21ab64f99927e7da5593328b2037b9bc82a87bc0969136","tests/ui-stable/transmute-ref-size-decrease.rs":"939fb562e4678368e59fdafb3a597fd54a661fd09d9ecb23c6e626ff59b45384","tests/ui-stable/transmute-ref-size-decrease.stderr":"fec5ab0e3d885bbb8e7ab82d6d58b9b4ee35a1802502fbc494bafa086d4132cf","tests/ui-stable/transmute-ref-size-increase.rs":"f66ab294f7618abfac5c503570137759afceb0dd26c8802bb1786b8873fe5670","tests/ui-stable/transmute-ref-size-increase.stderr":"720e2150c9ed538cf00d7525124ab0cee6ac53e91582470e09c140db783fc2be","tests/ui-stable/transmute-ref-src-dst-generic.rs":"96a6f6580307e6a397af8ca688a8a65144dff5240372203bd9f02bad6a41fd1e","tests/ui-stable/transmute-ref-src-dst-generic.stderr":"25f15e5316df34cd4a438548090c287228f86062f7e2ef59ea17fb727b868a19","tests/ui-stable/transmute-ref-src-dst-not-references.rs":"7311602a0153b260d819e9608e8e66ef5904919a2349a95187919d8211e48e23","tests/ui-stable/transmute-ref-src-dst-not-references.stderr":"2bff9f290ec40458939a1633f850853b3486220cfd40bc24c4e52635b7455742","tests/ui-stable/transmute-ref-src-dst-unsized.rs":"f83e0225e824b7526d7732ef5d759b32358e5db50c3c6a318d2b5dcc2eb3c707","tests/ui-stable/transmute-ref-src-dst-unsized.stderr":"80f9b39173dee338d3d7997d1283772b963e211dd6f14cfe37affc23520f7263","tests/ui-stable/transmute-ref-src-generic.rs":"ac1699aeca61c82aff5dac51d387a4ef7522faf2b2dfc56af398a2dc9d53745b","tests/ui-stable/transmute-ref-src-generic.stderr":"f3f8a7ee67ebec21169e1284c9eeaedcfa7b93c05f4e42c504cbd06508f34f9f","tests/ui-stable/transmute-ref-src-not-a-reference.rs":"a921f168fa6cb3c6a19894cecdb118bc3164275746672a916aa5194b92f2fb57","tests/ui-stable/transmute-ref-src-not-a-reference.stderr":"52efb101d85126138395fbed84c7cb911f86ea4457b991d91b2b6ec66521bcff","tests/ui-stable/transmute-ref-src-not-asbytes.rs":"09aabae9e4634a5432bf7225240954d7b0592994c97a927e0469e27854588232","tests/ui-stable/transmute-ref-src-not-asbytes.stderr":"543d5e4cced8f4d9f702a95d039579e121137ae2abfe2dad3da4692b8a43c1f0","tests/ui-stable/transmute-ref-src-unsized.rs":"d7797488f0ab5db89944ac7db25625c63aef72e6e4ed481d00a083449050b813","tests/ui-stable/transmute-ref-src-unsized.stderr":"228c5e4531cb5b8e33602dc58e9e0356a04de2946e17fbb206624f187ec86730","tests/ui-stable/transmute-size-decrease.rs":"c63dd10ddab58e282b033132d79fd21e80edb0c654f856679237977f62ced1ed","tests/ui-stable/transmute-size-decrease.stderr":"685acfb1b758f9854a5b36565f0b26cc1ef35322ee25387f05733187de1864d1","tests/ui-stable/transmute-size-increase.rs":"9413442e6e3c574bd7e36e8d4242000c1513624a4edc97567695a81b5851c491","tests/ui-stable/transmute-size-increase.stderr":"54cf03066a5d10ab7caa4741fe9d40df491a9a3fb81b6425a40bf04e21a6910e","tests/ui-stable/transmute-src-not-asbytes.rs":"8e2a76d99734c0502ba9daa8c7c2e34ca830ffd6024d3f7f29363d4263e89f74","tests/ui-stable/transmute-src-not-asbytes.stderr":"022dbcfa9950fe0576a26aecb6b8047740dd580f15491a754e9b95e16e1938da"},"package":"74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"} \ No newline at end of file diff --git a/third_party/rust/zerocopy/CONTRIBUTING.md b/third_party/rust/zerocopy/CONTRIBUTING.md new file mode 100644 index 0000000000..929e80996b --- /dev/null +++ b/third_party/rust/zerocopy/CONTRIBUTING.md @@ -0,0 +1,215 @@ + + +# How to Contribute + +We'd love to accept your patches and contributions to zerocopy. There are just a +few small guidelines you need to follow. + +Once you've read the rest of this doc, check out our [good-first-issue +label][good-first-issue] for some good issues you can use to get your toes wet! + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement. You (or your employer) retain the copyright to your contribution; +this simply gives us permission to use and redistribute your contributions as +part of the project. Head over to to see +your current agreements on file or to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code Reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult [GitHub +Help][about_pull_requests] for more information on using pull requests. + +## Code Guidelines + +### Philosophy + +This section is inspired by [Flutter's style guide][flutter_philosophy], which +contains many general principles that you should apply to all your programming +work. Read it. The below calls out specific aspects that we feel are +particularly important. + +#### Dogfood Your Features + +In non-library code, it's often advised to only implement features you need. +After all, it's hard to correctly design code without a concrete use case to +guide its design. Since zerocopy is a library, this advice is not as applicable; +we want our API surface to be featureful and complete even if not every feature +or method has a known use case. However, the observation that unused code is +hard to design still holds. + +Thus, when designing external-facing features, try to make use of them somehow. +This could be by using them to implement other features, or it could be by +writing prototype code which won't actually be checked in anywhere. If you're +feeling ambitious, you could even add (and check in) a [Cargo +example][cargo_example] that exercises the new feature. + +#### Go Down the Rabbit Hole + +You will occasionally encounter behavior that surprises you or seems wrong. It +probably is! Invest the time to find the root cause - you will either learn +something, or fix something, and both are worth your time. Do not work around +behavior you don't understand. + +### Avoid Duplication + +Avoid duplicating code whenever possible. In cases where existing code is not +exposed in a manner suitable to your needs, prefer to extract the necessary +parts into a common dependency. + +### Comments + +When writing comments, take a moment to consider the future reader of your +comment. Ensure that your comments are complete sentences with proper grammar +and punctuation. Note that adding more comments or more verbose comments is not +always better; for example, avoid comments that repeat the code they're anchored +on. + +Documentation comments should be self-contained; in other words, do not assume +that the reader is aware of documentation in adjacent files or on adjacent +structures. Avoid documentation comments on types which describe _instances_ of +the type; for example, `AddressSet is a set of client addresses.` is a comment +that describes a field of type `AddressSet`, but the type may be used to hold +any kind of `Address`, not just a client's. + +Phrase your comments to avoid references that might become stale; for example: +do not mention a variable or type by name when possible (certain doc comments +are necessary exceptions). Also avoid references to past or future versions of +or past or future work surrounding the item being documented; explain things +from first principles rather than making external references (including past +revisions). + +When writing TODOs: + +1. Include an issue reference using the format `TODO(#123):` +1. Phrase the text as an action that is to be taken; it should be possible for + another contributor to pick up the TODO without consulting any external + sources, including the referenced issue. + +### Tests + +Much of the code in zerocopy has the property that, if it is buggy, those bugs +may not cause user code to fail. This makes it extra important to write thorough +tests, but it also makes it harder to write those tests correctly. Here are some +guidelines on how to test code in zerocopy: +1. All code added to zerocopy must include tests that exercise it completely. +1. Tests must be deterministic. Threaded or time-dependent code, random number + generators (RNGs), and communication with external processes are common + sources of nondeterminism. See [Write reproducible, deterministic + tests][determinism] for tips. +1. Avoid [change detector tests][change_detector_tests]; tests that are + unnecessarily sensitive to changes, especially ones external to the code + under test, can hamper feature development and refactoring. +1. Since we run tests in [Miri][miri], make sure that tests exist which exercise + any potential [undefined behavior][undefined_behavior] so that Miri can catch + it. +1. If there's some user code that should be impossible to compile, add a + [trybuild test][trybuild] to ensure that it's properly rejected. + +### Source Control Best Practices + +Commits should be arranged for ease of reading; that is, incidental changes +such as code movement or formatting changes should be committed separately from +actual code changes. + +Commits should always be focused. For example, a commit could add a feature, +fix a bug, or refactor code, but not a mixture. + +Commits should be thoughtfully sized; avoid overly large or complex commits +which can be logically separated, but also avoid overly separated commits that +require code reviews to load multiple commits into their mental working memory +in order to properly understand how the various pieces fit together. + +#### Commit Messages + +Commit messages should be _concise_ but self-contained (avoid relying on issue +references as explanations for changes) and written such that they are helpful +to people reading in the future (include rationale and any necessary context). + +Avoid superfluous details or narrative. + +Commit messages should consist of a brief subject line and a separate +explanatory paragraph in accordance with the following: + +1. [Separate subject from body with a blank line](https://chris.beams.io/posts/git-commit/#separate) +1. [Limit the subject line to 50 characters](https://chris.beams.io/posts/git-commit/#limit-50) +1. [Capitalize the subject line](https://chris.beams.io/posts/git-commit/#capitalize) +1. [Do not end the subject line with a period](https://chris.beams.io/posts/git-commit/#end) +1. [Use the imperative mood in the subject line](https://chris.beams.io/posts/git-commit/#imperative) +1. [Wrap the body at 72 characters](https://chris.beams.io/posts/git-commit/#wrap-72) +1. [Use the body to explain what and why vs. how](https://chris.beams.io/posts/git-commit/#why-not-how) + +If the code affects a particular subsystem, prefix the subject line with the +name of that subsystem in square brackets, omitting any "zerocopy" prefix +(that's implicit). For example, for a commit adding a feature to the +zerocopy-derive crate: + +```text +[derive] Support AsBytes on types with parameters +``` + +The body may be omitted if the subject is self-explanatory; e.g. when fixing a +typo. The git book contains a [Commit Guidelines][commit_guidelines] section +with much of the same advice, and the list above is part of a [blog +post][beams_git_commit] by [Chris Beams][chris_beams]. + +Commit messages should make use of issue integration. Including an issue +reference like `#123` will cause the GitHub UI to link the text of that +reference to the referenced issue, and will also make it so that the referenced +issue back-links to the commit. Use "Closes", "Fixes", or "Resolves" on its own +line to automatically close an issue when your commit is merged: + +```text +Closes #123 +Fixes #123 +Resolves #123 +``` + +When using issue integration, don't omit necessary context that may also be +included in the relevant issue (see "Commit messages should be _concise_ but +self-contained" above). Git history is more likely to be retained indefinitely +than issue history (for example, if this repository is migrated away from GitHub +at some point in the future). + +Commit messages should never contain references to any of: + +1. Relative moments in time +1. Non-public URLs +1. Individuals +1. Hosted code reviews (such as on https://github.com/google/zerocopy/pulls) + + Refer to commits in this repository by their SHA-1 hash + + Refer to commits in other repositories by public web address (such as + https://github.com/google/zerocopy/commit/789b3deb) +1. Other entities which may not make sense to arbitrary future readers + +## Community Guidelines + +This project follows [Google's Open Source Community +Guidelines][google_open_source_guidelines]. + +[about_pull_requests]: https://help.github.com/articles/about-pull-requests/ +[beams_git_commit]: https://chris.beams.io/posts/git-commit/ +[cargo_example]: http://xion.io/post/code/rust-examples.html +[change_detector_tests]: https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html +[chris_beams]: https://chris.beams.io/ +[commit_guidelines]: https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines +[determinism]: https://fuchsia.dev/fuchsia-src/contribute/testing/best-practices#write_reproducible_deterministic_tests +[flutter_philosophy]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#philosophy +[good-first-issue]: https://github.com/google/zerocopy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22 +[google_open_source_guidelines]: https://opensource.google/conduct/ +[magic_number]: https://en.wikipedia.org/wiki/Magic_number_(programming) +[miri]: https://github.com/rust-lang/miri +[trybuild]: https://crates.io/crates/trybuild +[undefined_behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html diff --git a/third_party/rust/zerocopy/Cargo.toml b/third_party/rust/zerocopy/Cargo.toml new file mode 100644 index 0000000000..36c00b78e4 --- /dev/null +++ b/third_party/rust/zerocopy/Cargo.toml @@ -0,0 +1,87 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.60.0" +name = "zerocopy" +version = "0.7.32" +authors = ["Joshua Liebow-Feeser "] +exclude = [".*"] +description = "Utilities for zero-copy parsing and serialization" +readme = "README.md" +license = "BSD-2-Clause OR Apache-2.0 OR MIT" +repository = "https://github.com/google/zerocopy" + +[package.metadata.ci] +pinned-nightly = "nightly-2023-12-05" +pinned-stable = "1.74.0" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "doc_cfg", + "--generate-link-to-definition", +] + +[package.metadata.playground] +features = ["__internal_use_only_features_that_work_on_stable"] + +[dependencies.byteorder] +version = "1.3" +optional = true +default-features = false + +[dependencies.zerocopy-derive] +version = "=0.7.32" +optional = true + +[dev-dependencies.assert_matches] +version = "1.5" + +[dev-dependencies.elain] +version = "0.3.0" + +[dev-dependencies.itertools] +version = "0.11" + +[dev-dependencies.rand] +version = "0.8.5" +features = ["small_rng"] + +[dev-dependencies.rustversion] +version = "1.0" + +[dev-dependencies.static_assertions] +version = "1.1" + +[dev-dependencies.trybuild] +version = "=1.0.85" +features = ["diff"] + +[dev-dependencies.zerocopy-derive] +version = "=0.7.32" + +[features] +__internal_use_only_features_that_work_on_stable = [ + "alloc", + "derive", + "simd", +] +alloc = [] +default = ["byteorder"] +derive = ["zerocopy-derive"] +simd = [] +simd-nightly = ["simd"] + +[target."cfg(any())".dependencies.zerocopy-derive] +version = "=0.7.32" diff --git a/third_party/rust/zerocopy/INTERNAL.md b/third_party/rust/zerocopy/INTERNAL.md new file mode 100644 index 0000000000..4e7f440732 --- /dev/null +++ b/third_party/rust/zerocopy/INTERNAL.md @@ -0,0 +1,44 @@ + + +# Internal details + +This file documents various internal details of zerocopy and its infrastructure +that consumers don't need to be concerned about. It focuses on details that +affect multiple files, and allows each affected code location to reference this +document rather than requiring us to repeat the same explanation in multiple +locations. + +## CI and toolchain versions + +In CI (`.github/workflows/ci.yml`), we pin to specific versions or dates of the +stable and nightly toolchains. The reason is twofold: First, our UI tests (see +`tests/trybuild.rs` and `zerocopy-derive/tests/trybuild.rs`) depend on the +format of rustc's error messages, and that format can change between toolchain +versions (we also maintain multiple copies of our UI tests - one for each +toolchain version pinned in CI - for this reason). Second, not all nightlies +have a working Miri, so we need to pin to one that does (see +https://rust-lang.github.io/rustup-components-history/). + +Updating the versions pinned in CI may cause the UI tests to break. In order to +fix UI tests after a version update, run: + +``` +$ TRYBUILD=overwrite ./cargo.sh +all test +``` + +## Crate versions + +We ensure that the crate versions of zerocopy and zerocopy-derive are always the +same in-tree, and that zerocopy depends upon zerocopy-derive using an exact +version match to the current version in-tree. This has the result that, even +when published on crates.io, both crates effectively constitute a single atomic +version. So long as the code in zerocopy is compatible with the code in +zerocopy-derive in the same Git commit, then publishing them both is fine. This +frees us from the normal task of reasoning about compatibility with a range of +semver-compatible versions of different crates. diff --git a/third_party/rust/zerocopy/LICENSE-APACHE b/third_party/rust/zerocopy/LICENSE-APACHE new file mode 100644 index 0000000000..2dc22c12fa --- /dev/null +++ b/third_party/rust/zerocopy/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 The Fuchsia Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/third_party/rust/zerocopy/LICENSE-BSD b/third_party/rust/zerocopy/LICENSE-BSD new file mode 100644 index 0000000000..7ed244f42d --- /dev/null +++ b/third_party/rust/zerocopy/LICENSE-BSD @@ -0,0 +1,24 @@ +Copyright 2019 The Fuchsia Authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/rust/zerocopy/LICENSE-MIT b/third_party/rust/zerocopy/LICENSE-MIT new file mode 100644 index 0000000000..26e15216cd --- /dev/null +++ b/third_party/rust/zerocopy/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2023 The Fuchsia Authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/third_party/rust/zerocopy/POLICIES.md b/third_party/rust/zerocopy/POLICIES.md new file mode 100644 index 0000000000..a9d9cc5ab2 --- /dev/null +++ b/third_party/rust/zerocopy/POLICIES.md @@ -0,0 +1,103 @@ + + +# Zerocopy's Policies + +## Soundness + +Zerocopy is expressly designed for use in security-critical contexts. It is used +in hardware security firmware, cryptographic implementations, hypervisors, and +more. We understand that software in these contexts has a very high bar for +correctness, and we take our responsibility to meet that bar very seriously. + +This section describes policies which are designed to ensure the correctness and +soundness of our code and prevent regressions. + +### Forwards-compatibility + +Rust does not currently have a formal memory model. As such, while Rust provides +guarantees about the semantics of some operations, the semantics of many +operations is up in the air and subject to change. + +Zerocopy strives to ensure that our code - and code emitted by our custom +derives - is sound under any version of Rust as early as our MSRV, and will +continue to be sound under any future version of Rust. The policies in this +section are designed to help ensure that we live up to this goal. + +### Safety comments + +Each non-test `unsafe` block must be annotated with a "safety comment" which +provides a rationale for its soundness. In order to ensure that our soundness is +forwards-compatible, safety comments must satisfy the following criteria: +- Safety comments must constitute a (possibly informal) proof that all of Rust's + soundness rules are upheld. +- Safety comments must only rely for their correctness on statements which + appear in the stable versions of the [Rust Reference] or standard library + documentation (ie, the docs for [core], [alloc], and [std]); arguments which + rely on text from the beta or nightly versions of these documents are not + considered complete. +- All statements from the Reference or standard library documentation which are + relied upon for soundness must be quoted in the safety comment. This ensures + that there is no ambiguity as to what aspect of the text is being cited. This + is especially important in cases where the text of these documents changes in + the future. Such changes are of course required to be backwards-compatible, + but may change the manner in which a particular guarantee is explained. + +We use the [`clippy::undocumented_unsafe_blocks`] lint to ensure that `unsafe` +blocks cannot be added without a safety comment. Note that there are a few +outstanding uncommented `unsafe` blocks which are tracked in [#429]. Our goal is +to reach 100% safety comment coverage and not regress once we've reached it. + +[Rust Reference]: https://doc.rust-lang.org/reference/ +[core]: https://doc.rust-lang.org/stable/core/ +[alloc]: https://doc.rust-lang.org/stable/alloc/ +[std]: https://doc.rust-lang.org/stable/std/ +[`clippy::undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#/undocumented_unsafe_blocks +[#429]: https://github.com/google/zerocopy/issues/429 + +#### Exceptions to our safety comment policy + +In rare circumstances, the soundness of an `unsafe` block may depend upon +semantics which are widely agreed upon but not formally guaranteed. In order to +avoid slowing down zerocopy's development to an unreasonable degree, a safety +comment may violate our safety comment policy so long as all of the following +hold: +- The safety comment's correctness may rely on semantics which are not + guaranteed in official Rust documentation *so long as* a member of the Rust + team has articulated in an official communication (e.g. a comment on a Rust + GitHub repo) that Rust intends to guarantee particular semantics. +- There exists an active effort to formalize the guarantee in Rust's official + documentation. + +### Target architecture support + +Zerocopy bases its soundness on guarantees made about the semantics of Rust +which appear in the Rust Reference or standard library documentation; zerocopy +is sound so long as these guarantees hold. There are known cases in which these +guarantees do not hold on certain target architectures (see +[rust-lang/unsafe-code-guidelines#461]); on such target architectures, zerocopy +may be unsound. We consider it outside of zerocopy's scope to reason about these +cases. Zerocopy makes no effort maintain soundness in cases where Rust's +documented guarantees do not hold. + +[rust-lang/unsafe-code-guidelines#461]: https://github.com/rust-lang/unsafe-code-guidelines/issues/461 + +## MSRV + +Our minimum supported Rust version (MSRV) is encoded in our `Cargo.toml` file. +We consider an increase in MSRV to be a semver-breaking change, and will only +increase our MSRV during semver-breaking version changes (e.g., 0.1 -> 0.2, 1.0 +-> 2.0, etc). + +## Yanking + +Whenever a bug or regression is identified, we will yank any affected versions +which are part of the current version train. For example, if the most recent +version is 0.10.20 and a bug is uncovered, we will release a fix in 0.10.21 and +yank all 0.10.X versions which are affected. We *may* also yank versions in previous +version trains on a case-by-case basis, but we don't guarantee it. diff --git a/third_party/rust/zerocopy/README.md b/third_party/rust/zerocopy/README.md new file mode 100644 index 0000000000..ec09c4569a --- /dev/null +++ b/third_party/rust/zerocopy/README.md @@ -0,0 +1,154 @@ + + +# zerocopy + +*Want to help improve zerocopy? +Fill out our [user survey][user-survey]!* + +***Fast, safe, compile error. Pick two.*** + +Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe` +so you don't have to. + +## Overview + +Zerocopy provides four core marker traits, each of which can be derived +(e.g., `#[derive(FromZeroes)]`): +- `FromZeroes` indicates that a sequence of zero bytes represents a valid + instance of a type +- `FromBytes` indicates that a type may safely be converted from an + arbitrary byte sequence +- `AsBytes` indicates that a type may safely be converted *to* a byte + sequence +- `Unaligned` indicates that a type's alignment requirement is 1 + +Types which implement a subset of these traits can then be converted to/from +byte sequences with little to no runtime overhead. + +Zerocopy also provides byte-order aware integer types that support these +conversions; see the `byteorder` module. These types are especially useful +for network parsing. + +[user-survey]: https://docs.google.com/forms/d/e/1FAIpQLSdzBNTN9tzwsmtyZxRFNL02K36IWCdHWW2ZBckyQS2xiO3i8Q/viewform?usp=published_options + +## Cargo Features + +- **`alloc`** + By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled, + the `alloc` crate is added as a dependency, and some allocation-related + functionality is added. + +- **`byteorder`** (enabled by default) + Adds the `byteorder` module and a dependency on the `byteorder` crate. + The `byteorder` module provides byte order-aware equivalents of the + multi-byte primitive numerical types. Unlike their primitive equivalents, + the types in this module have no alignment requirement and support byte + order conversions. This can be useful in handling file formats, network + packet layouts, etc which don't provide alignment guarantees and which may + use a byte order different from that of the execution platform. + +- **`derive`** + Provides derives for the core marker traits via the `zerocopy-derive` + crate. These derives are re-exported from `zerocopy`, so it is not + necessary to depend on `zerocopy-derive` directly. + + However, you may experience better compile times if you instead directly + depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`, + since doing so will allow Rust to compile these crates in parallel. To do + so, do *not* enable the `derive` feature, and list both dependencies in + your `Cargo.toml` with the same leading non-zero version number; e.g: + + ```toml + [dependencies] + zerocopy = "0.X" + zerocopy-derive = "0.X" + ``` + +- **`simd`** + When the `simd` feature is enabled, `FromZeroes`, `FromBytes`, and + `AsBytes` impls are emitted for all stable SIMD types which exist on the + target platform. Note that the layout of SIMD types is not yet stabilized, + so these impls may be removed in the future if layout changes make them + invalid. For more information, see the Unsafe Code Guidelines Reference + page on the [layout of packed SIMD vectors][simd-layout]. + +- **`simd-nightly`** + Enables the `simd` feature and adds support for SIMD types which are only + available on nightly. Since these types are unstable, support for any type + may be removed at any point in the future. + +[simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html + +## Security Ethos + +Zerocopy is expressly designed for use in security-critical contexts. We +strive to ensure that that zerocopy code is sound under Rust's current +memory model, and *any future memory model*. We ensure this by: +- **...not 'guessing' about Rust's semantics.** + We annotate `unsafe` code with a precise rationale for its soundness that + cites a relevant section of Rust's official documentation. When Rust's + documented semantics are unclear, we work with the Rust Operational + Semantics Team to clarify Rust's documentation. +- **...rigorously testing our implementation.** + We run tests using [Miri], ensuring that zerocopy is sound across a wide + array of supported target platforms of varying endianness and pointer + width, and across both current and experimental memory models of Rust. +- **...formally proving the correctness of our implementation.** + We apply formal verification tools like [Kani][kani] to prove zerocopy's + correctness. + +For more information, see our full [soundness policy]. + +[Miri]: https://github.com/rust-lang/miri +[Kani]: https://github.com/model-checking/kani +[soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness + +## Relationship to Project Safe Transmute + +[Project Safe Transmute] is an official initiative of the Rust Project to +develop language-level support for safer transmutation. The Project consults +with crates like zerocopy to identify aspects of safer transmutation that +would benefit from compiler support, and has developed an [experimental, +compiler-supported analysis][mcp-transmutability] which determines whether, +for a given type, any value of that type may be soundly transmuted into +another type. Once this functionality is sufficiently mature, zerocopy +intends to replace its internal transmutability analysis (implemented by our +custom derives) with the compiler-supported one. This change will likely be +an implementation detail that is invisible to zerocopy's users. + +Project Safe Transmute will not replace the need for most of zerocopy's +higher-level abstractions. The experimental compiler analysis is a tool for +checking the soundness of `unsafe` code, not a tool to avoid writing +`unsafe` code altogether. For the foreseeable future, crates like zerocopy +will still be required in order to provide higher-level abstractions on top +of the building block provided by Project Safe Transmute. + +[Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html +[mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411 + +## MSRV + +See our [MSRV policy]. + +[MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv + +## Changelog + +Zerocopy uses [GitHub Releases]. + +[GitHub Releases]: https://github.com/google/zerocopy/releases + +## Disclaimer + +Disclaimer: Zerocopy is not an officially supported Google product. diff --git a/third_party/rust/zerocopy/cargo.sh b/third_party/rust/zerocopy/cargo.sh new file mode 100755 index 0000000000..f72e898db6 --- /dev/null +++ b/third_party/rust/zerocopy/cargo.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# +# Copyright 2023 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +# This script is a thin wrapper around Cargo that provides human-friendly +# toolchain names which are automatically translated to the toolchain versions +# we have pinned in CI. +# +# cargo.sh --version # looks up the version for the named toolchain +# cargo.sh + [...] # runs cargo commands with the named toolchain +# cargo.sh +all [...] # runs cargo commands with each toolchain +# +# The meta-toolchain "all" instructs this script to run the provided command +# once for each toolchain (msrv, stable, nightly). +# +# A common task that is especially annoying to perform by hand is to update +# trybuild's stderr files. Using this script: +# +# TRYBUILD=overwrite ./cargo.sh +all test --workspace + +set -eo pipefail + +function print-usage-and-exit { + echo "Usage:" >&2 + echo " $0 --version " >&2 + echo " $0 + [...]" >&2 + echo " $0 +all [...]" >&2 + exit 1 +} + +[[ $# -gt 0 ]] || print-usage-and-exit + +function pkg-meta { + # NOTE(#547): We set `CARGO_TARGET_DIR` here because `cargo metadata` + # sometimes causes the `cargo-metadata` crate to be rebuilt from source using + # the default toolchain. This has the effect of clobbering any existing build + # artifacts from whatever toolchain the user has specified (e.g., `+nightly`), + # causing the subsequent `cargo` invocation to rebuild unnecessarily. By + # specifying a separate build directory here, we ensure that this never + # clobbers the build artifacts used by the later `cargo` invocation. + CARGO_TARGET_DIR=target/cargo-sh cargo metadata --format-version 1 | jq -r ".packages[] | select(.name == \"zerocopy\").$1" +} + +function lookup-version { + VERSION="$1" + case "$VERSION" in + msrv) + pkg-meta rust_version + ;; + stable) + pkg-meta 'metadata.ci."pinned-stable"' + ;; + nightly) + pkg-meta 'metadata.ci."pinned-nightly"' + ;; + *) + echo "Unrecognized toolchain name: '$VERSION' (options are 'msrv', 'stable', 'nightly')" >&2 + return 1 + ;; + esac +} + +function get-rustflags { + [ "$1" == nightly ] && echo "--cfg __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS" +} + +function prompt { + PROMPT="$1" + YES="$2" + while true; do + read -p "$PROMPT " yn + case "$yn" in + [Yy]) $YES; return $?; ;; + [Nn]) return 1; ;; + *) break; ;; + esac + done +} + +case "$1" in + # cargo.sh --version + --version) + [[ $# -eq 2 ]] || print-usage-and-exit + lookup-version "$2" + ;; + # cargo.sh +all [...] + +all) + echo "[cargo.sh] warning: running the same command for each toolchain (msrv, stable, nightly)" >&2 + for toolchain in msrv stable nightly; do + echo "[cargo.sh] running with toolchain: $toolchain" >&2 + $0 "+$toolchain" ${@:2} + done + exit 0 + ;; + # cargo.sh + [...] + +*) + TOOLCHAIN="$(lookup-version ${1:1})" + + cargo "+$TOOLCHAIN" version &>/dev/null && \ + rustup "+$TOOLCHAIN" component list | grep '^rust-src (installed)$' >/dev/null || { + echo "[cargo.sh] missing either toolchain '$TOOLCHAIN' or component 'rust-src'" >&2 + # If we're running in a GitHub action, then it's better to bail than to + # hang waiting for input we're never going to get. + [ -z ${GITHUB_RUN_ID+x} ] || exit 1 + prompt "[cargo.sh] would you like to install toolchain '$TOOLCHAIN' and component 'rust-src' via 'rustup'?" \ + "rustup toolchain install $TOOLCHAIN -c rust-src" + } || exit 1 + + RUSTFLAGS="$(get-rustflags ${1:1}) $RUSTFLAGS" cargo "+$TOOLCHAIN" ${@:2} + ;; + *) + print-usage-and-exit + ;; +esac diff --git a/third_party/rust/zerocopy/clippy.toml b/third_party/rust/zerocopy/clippy.toml new file mode 100644 index 0000000000..9c1140643c --- /dev/null +++ b/third_party/rust/zerocopy/clippy.toml @@ -0,0 +1,10 @@ +# Copyright 2023 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +accept-comment-above-statement = true +accept-comment-above-attributes = true diff --git a/third_party/rust/zerocopy/generate-readme.sh b/third_party/rust/zerocopy/generate-readme.sh new file mode 100755 index 0000000000..be0dc929af --- /dev/null +++ b/third_party/rust/zerocopy/generate-readme.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# +# Copyright 2022 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +set -eo pipefail + +COPYRIGHT_HEADER=$(mktemp) +BODY=$(mktemp) +DISCLAIMER_FOOTER=$(mktemp) + +cat > $COPYRIGHT_HEADER <<'EOF' + + +EOF + +# This uses the `cargo readme` tool, which you can install via `cargo install +# cargo-readme --version 3.2.0`. +# +# The `sed` command is used to strip code links like: +# +# /// Here is a link to [`Vec`]. +# +# These links don't work in a Markdown file, and so we remove the `[` and `]` +# characters to convert them to non-link code snippets. +cargo readme --no-license | sed 's/\[\(`[^`]*`\)]/\1/g' > $BODY + +cat > $DISCLAIMER_FOOTER <<'EOF' + +## Disclaimer + +Disclaimer: Zerocopy is not an officially supported Google product. +EOF + +cat $COPYRIGHT_HEADER $BODY $DISCLAIMER_FOOTER diff --git a/third_party/rust/zerocopy/rustfmt.toml b/third_party/rust/zerocopy/rustfmt.toml new file mode 100644 index 0000000000..c967afe9c5 --- /dev/null +++ b/third_party/rust/zerocopy/rustfmt.toml @@ -0,0 +1,19 @@ +# Copyright 2022 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +edition = "2021" + +# The "Default" setting has a heuristic which splits lines too aggresively. +# We are willing to revisit this setting in future versions of rustfmt. +# Bugs: +# * https://github.com/rust-lang/rustfmt/issues/3119 +# * https://github.com/rust-lang/rustfmt/issues/3120 +use_small_heuristics = "Max" + +# Prevent carriage returns +newline_style = "Unix" diff --git a/third_party/rust/zerocopy/src/byteorder.rs b/third_party/rust/zerocopy/src/byteorder.rs new file mode 100644 index 0000000000..2769410451 --- /dev/null +++ b/third_party/rust/zerocopy/src/byteorder.rs @@ -0,0 +1,1075 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//! Byte order-aware numeric primitives. +//! +//! This module contains equivalents of the native multi-byte integer types with +//! no alignment requirement and supporting byte order conversions. +//! +//! For each native multi-byte integer type - `u16`, `i16`, `u32`, etc - and +//! floating point type - `f32` and `f64` - an equivalent type is defined by +//! this module - [`U16`], [`I16`], [`U32`], [`F64`], etc. Unlike their native +//! counterparts, these types have alignment 1, and take a type parameter +//! specifying the byte order in which the bytes are stored in memory. Each type +//! implements the [`FromBytes`], [`AsBytes`], and [`Unaligned`] traits. +//! +//! These two properties, taken together, make these types useful for defining +//! data structures whose memory layout matches a wire format such as that of a +//! network protocol or a file format. Such formats often have multi-byte values +//! at offsets that do not respect the alignment requirements of the equivalent +//! native types, and stored in a byte order not necessarily the same as that of +//! the target platform. +//! +//! Type aliases are provided for common byte orders in the [`big_endian`], +//! [`little_endian`], [`network_endian`], and [`native_endian`] submodules. +//! +//! # Example +//! +//! One use of these types is for representing network packet formats, such as +//! UDP: +//! +//! ```rust,edition2021 +//! # #[cfg(feature = "derive")] { // This example uses derives, and won't compile without them +//! use zerocopy::{AsBytes, ByteSlice, FromBytes, FromZeroes, Ref, Unaligned}; +//! use zerocopy::byteorder::network_endian::U16; +//! +//! #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] +//! #[repr(C)] +//! struct UdpHeader { +//! src_port: U16, +//! dst_port: U16, +//! length: U16, +//! checksum: U16, +//! } +//! +//! struct UdpPacket { +//! header: Ref, +//! body: B, +//! } +//! +//! impl UdpPacket { +//! fn parse(bytes: B) -> Option> { +//! let (header, body) = Ref::new_from_prefix(bytes)?; +//! Some(UdpPacket { header, body }) +//! } +//! +//! fn src_port(&self) -> u16 { +//! self.header.src_port.get() +//! } +//! +//! // more getters... +//! } +//! # } +//! ``` + +use core::{ + convert::{TryFrom, TryInto}, + fmt::{self, Binary, Debug, Display, Formatter, LowerHex, Octal, UpperHex}, + marker::PhantomData, + num::TryFromIntError, +}; + +// We don't reexport `WriteBytesExt` or `ReadBytesExt` because those are only +// available with the `std` feature enabled, and zerocopy is `no_std` by +// default. +pub use ::byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian, NetworkEndian, BE, LE}; + +use super::*; + +macro_rules! impl_fmt_trait { + ($name:ident, $native:ident, $trait:ident) => { + impl $trait for $name { + #[inline(always)] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + $trait::fmt(&self.get(), f) + } + } + }; +} + +macro_rules! impl_fmt_traits { + ($name:ident, $native:ident, "floating point number") => { + impl_fmt_trait!($name, $native, Display); + }; + ($name:ident, $native:ident, "unsigned integer") => { + impl_fmt_traits!($name, $native, @all_types); + }; + ($name:ident, $native:ident, "signed integer") => { + impl_fmt_traits!($name, $native, @all_types); + }; + ($name:ident, $native:ident, @all_types) => { + impl_fmt_trait!($name, $native, Display); + impl_fmt_trait!($name, $native, Octal); + impl_fmt_trait!($name, $native, LowerHex); + impl_fmt_trait!($name, $native, UpperHex); + impl_fmt_trait!($name, $native, Binary); + }; +} + +macro_rules! impl_ops_traits { + ($name:ident, $native:ident, "floating point number") => { + impl_ops_traits!($name, $native, @all_types); + impl_ops_traits!($name, $native, @signed_integer_floating_point); + }; + ($name:ident, $native:ident, "unsigned integer") => { + impl_ops_traits!($name, $native, @signed_unsigned_integer); + impl_ops_traits!($name, $native, @all_types); + }; + ($name:ident, $native:ident, "signed integer") => { + impl_ops_traits!($name, $native, @signed_unsigned_integer); + impl_ops_traits!($name, $native, @signed_integer_floating_point); + impl_ops_traits!($name, $native, @all_types); + }; + ($name:ident, $native:ident, @signed_unsigned_integer) => { + impl_ops_traits!(@without_byteorder_swap $name, $native, BitAnd, bitand, BitAndAssign, bitand_assign); + impl_ops_traits!(@without_byteorder_swap $name, $native, BitOr, bitor, BitOrAssign, bitor_assign); + impl_ops_traits!(@without_byteorder_swap $name, $native, BitXor, bitxor, BitXorAssign, bitxor_assign); + impl_ops_traits!(@with_byteorder_swap $name, $native, Shl, shl, ShlAssign, shl_assign); + impl_ops_traits!(@with_byteorder_swap $name, $native, Shr, shr, ShrAssign, shr_assign); + + impl core::ops::Not for $name { + type Output = $name; + + #[inline(always)] + fn not(self) -> $name { + let self_native = $native::from_ne_bytes(self.0); + $name((!self_native).to_ne_bytes(), PhantomData) + } + } + }; + ($name:ident, $native:ident, @signed_integer_floating_point) => { + impl core::ops::Neg for $name { + type Output = $name; + + #[inline(always)] + fn neg(self) -> $name { + let self_native: $native = self.get(); + #[allow(clippy::arithmetic_side_effects)] + $name::::new(-self_native) + } + } + }; + ($name:ident, $native:ident, @all_types) => { + impl_ops_traits!(@with_byteorder_swap $name, $native, Add, add, AddAssign, add_assign); + impl_ops_traits!(@with_byteorder_swap $name, $native, Div, div, DivAssign, div_assign); + impl_ops_traits!(@with_byteorder_swap $name, $native, Mul, mul, MulAssign, mul_assign); + impl_ops_traits!(@with_byteorder_swap $name, $native, Rem, rem, RemAssign, rem_assign); + impl_ops_traits!(@with_byteorder_swap $name, $native, Sub, sub, SubAssign, sub_assign); + }; + (@with_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => { + impl core::ops::$trait for $name { + type Output = $name; + + #[inline(always)] + fn $method(self, rhs: $name) -> $name { + let self_native: $native = self.get(); + let rhs_native: $native = rhs.get(); + let result_native = core::ops::$trait::$method(self_native, rhs_native); + $name::::new(result_native) + } + } + + impl core::ops::$trait_assign for $name { + #[inline(always)] + fn $method_assign(&mut self, rhs: $name) { + *self = core::ops::$trait::$method(*self, rhs); + } + } + }; + // Implement traits in terms of the same trait on the native type, but + // without performing a byte order swap. This only works for bitwise + // operations like `&`, `|`, etc. + (@without_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => { + impl core::ops::$trait for $name { + type Output = $name; + + #[inline(always)] + fn $method(self, rhs: $name) -> $name { + let self_native = $native::from_ne_bytes(self.0); + let rhs_native = $native::from_ne_bytes(rhs.0); + let result_native = core::ops::$trait::$method(self_native, rhs_native); + $name(result_native.to_ne_bytes(), PhantomData) + } + } + + impl core::ops::$trait_assign for $name { + #[inline(always)] + fn $method_assign(&mut self, rhs: $name) { + *self = core::ops::$trait::$method(*self, rhs); + } + } + }; +} + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + +macro_rules! define_max_value_constant { + ($name:ident, $bytes:expr, "unsigned integer") => { + /// The maximum value. + /// + /// This constant should be preferred to constructing a new value using + /// `new`, as `new` may perform an endianness swap depending on the + /// endianness `O` and the endianness of the platform. + pub const MAX_VALUE: $name = $name([0xFFu8; $bytes], PhantomData); + }; + // We don't provide maximum and minimum value constants for signed values + // and floats because there's no way to do it generically - it would require + // a different value depending on the value of the `ByteOrder` type + // parameter. Currently, one workaround would be to provide implementations + // for concrete implementations of that trait. In the long term, if we are + // ever able to make the `new` constructor a const fn, we could use that + // instead. + ($name:ident, $bytes:expr, "signed integer") => {}; + ($name:ident, $bytes:expr, "floating point number") => {}; +} + +macro_rules! define_type { + ($article:ident, + $name:ident, + $native:ident, + $bits:expr, + $bytes:expr, + $read_method:ident, + $write_method:ident, + $number_kind:tt, + [$($larger_native:ty),*], + [$($larger_native_try:ty),*], + [$($larger_byteorder:ident),*], + [$($larger_byteorder_try:ident),*]) => { + doc_comment! { + concat!("A ", stringify!($bits), "-bit ", $number_kind, + " stored in a given byte order. + +`", stringify!($name), "` is like the native `", stringify!($native), "` type with +two major differences: First, it has no alignment requirement (its alignment is 1). +Second, the endianness of its memory layout is given by the type parameter `O`, +which can be any type which implements [`ByteOrder`]. In particular, this refers +to [`BigEndian`], [`LittleEndian`], [`NativeEndian`], and [`NetworkEndian`]. + +", stringify!($article), " `", stringify!($name), "` can be constructed using +the [`new`] method, and its contained value can be obtained as a native +`",stringify!($native), "` using the [`get`] method, or updated in place with +the [`set`] method. In all cases, if the endianness `O` is not the same as the +endianness of the current platform, an endianness swap will be performed in +order to uphold the invariants that a) the layout of `", stringify!($name), "` +has endianness `O` and that, b) the layout of `", stringify!($native), "` has +the platform's native endianness. + +`", stringify!($name), "` implements [`FromBytes`], [`AsBytes`], and [`Unaligned`], +making it useful for parsing and serialization. See the module documentation for an +example of how it can be used for parsing UDP packets. + +[`new`]: crate::byteorder::", stringify!($name), "::new +[`get`]: crate::byteorder::", stringify!($name), "::get +[`set`]: crate::byteorder::", stringify!($name), "::set +[`FromBytes`]: crate::FromBytes +[`AsBytes`]: crate::AsBytes +[`Unaligned`]: crate::Unaligned"), + #[derive(Copy, Clone, Eq, PartialEq, Hash)] + #[cfg_attr(any(feature = "derive", test), derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned))] + #[repr(transparent)] + pub struct $name([u8; $bytes], PhantomData); + } + + #[cfg(not(any(feature = "derive", test)))] + impl_known_layout!(O => $name); + + safety_comment! { + /// SAFETY: + /// `$name` is `repr(transparent)`, and so it has the same layout + /// as its only non-zero field, which is a `u8` array. `u8` arrays + /// are `FromZeroes`, `FromBytes`, `AsBytes`, and `Unaligned`. + impl_or_verify!(O => FromZeroes for $name); + impl_or_verify!(O => FromBytes for $name); + impl_or_verify!(O => AsBytes for $name); + impl_or_verify!(O => Unaligned for $name); + } + + impl Default for $name { + #[inline(always)] + fn default() -> $name { + $name::ZERO + } + } + + impl $name { + /// The value zero. + /// + /// This constant should be preferred to constructing a new value + /// using `new`, as `new` may perform an endianness swap depending + /// on the endianness and platform. + pub const ZERO: $name = $name([0u8; $bytes], PhantomData); + + define_max_value_constant!($name, $bytes, $number_kind); + + /// Constructs a new value from bytes which are already in the + /// endianness `O`. + #[inline(always)] + pub const fn from_bytes(bytes: [u8; $bytes]) -> $name { + $name(bytes, PhantomData) + } + } + + impl $name { + // TODO(joshlf): Make these const fns if the `ByteOrder` methods + // ever become const fns. + + /// Constructs a new value, possibly performing an endianness swap + /// to guarantee that the returned value has endianness `O`. + #[inline(always)] + pub fn new(n: $native) -> $name { + let mut out = $name::default(); + O::$write_method(&mut out.0[..], n); + out + } + + /// Returns the value as a primitive type, possibly performing an + /// endianness swap to guarantee that the return value has the + /// endianness of the native platform. + #[inline(always)] + pub fn get(self) -> $native { + O::$read_method(&self.0[..]) + } + + /// Updates the value in place as a primitive type, possibly + /// performing an endianness swap to guarantee that the stored value + /// has the endianness `O`. + #[inline(always)] + pub fn set(&mut self, n: $native) { + O::$write_method(&mut self.0[..], n); + } + } + + // The reasoning behind which traits to implement here is to only + // implement traits which won't cause inference issues. Notably, + // comparison traits like PartialEq and PartialOrd tend to cause + // inference issues. + + impl From<$name> for [u8; $bytes] { + #[inline(always)] + fn from(x: $name) -> [u8; $bytes] { + x.0 + } + } + + impl From<[u8; $bytes]> for $name { + #[inline(always)] + fn from(bytes: [u8; $bytes]) -> $name { + $name(bytes, PhantomData) + } + } + + impl From<$name> for $native { + #[inline(always)] + fn from(x: $name) -> $native { + x.get() + } + } + + impl From<$native> for $name { + #[inline(always)] + fn from(x: $native) -> $name { + $name::new(x) + } + } + + $( + impl From<$name> for $larger_native { + #[inline(always)] + fn from(x: $name) -> $larger_native { + x.get().into() + } + } + )* + + $( + impl TryFrom<$larger_native_try> for $name { + type Error = TryFromIntError; + #[inline(always)] + fn try_from(x: $larger_native_try) -> Result<$name, TryFromIntError> { + $native::try_from(x).map($name::new) + } + } + )* + + $( + impl From<$name> for $larger_byteorder

    { + #[inline(always)] + fn from(x: $name) -> $larger_byteorder

    { + $larger_byteorder::new(x.get().into()) + } + } + )* + + $( + impl TryFrom<$larger_byteorder_try

    > for $name { + type Error = TryFromIntError; + #[inline(always)] + fn try_from(x: $larger_byteorder_try

    ) -> Result<$name, TryFromIntError> { + x.get().try_into().map($name::new) + } + } + )* + + impl AsRef<[u8; $bytes]> for $name { + #[inline(always)] + fn as_ref(&self) -> &[u8; $bytes] { + &self.0 + } + } + + impl AsMut<[u8; $bytes]> for $name { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u8; $bytes] { + &mut self.0 + } + } + + impl PartialEq<$name> for [u8; $bytes] { + #[inline(always)] + fn eq(&self, other: &$name) -> bool { + self.eq(&other.0) + } + } + + impl PartialEq<[u8; $bytes]> for $name { + #[inline(always)] + fn eq(&self, other: &[u8; $bytes]) -> bool { + self.0.eq(other) + } + } + + impl_fmt_traits!($name, $native, $number_kind); + impl_ops_traits!($name, $native, $number_kind); + + impl Debug for $name { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + // This results in a format like "U16(42)". + f.debug_tuple(stringify!($name)).field(&self.get()).finish() + } + } + }; +} + +define_type!( + A, + U16, + u16, + 16, + 2, + read_u16, + write_u16, + "unsigned integer", + [u32, u64, u128, usize], + [u32, u64, u128, usize], + [U32, U64, U128], + [U32, U64, U128] +); +define_type!( + A, + U32, + u32, + 32, + 4, + read_u32, + write_u32, + "unsigned integer", + [u64, u128], + [u64, u128], + [U64, U128], + [U64, U128] +); +define_type!( + A, + U64, + u64, + 64, + 8, + read_u64, + write_u64, + "unsigned integer", + [u128], + [u128], + [U128], + [U128] +); +define_type!(A, U128, u128, 128, 16, read_u128, write_u128, "unsigned integer", [], [], [], []); +define_type!( + An, + I16, + i16, + 16, + 2, + read_i16, + write_i16, + "signed integer", + [i32, i64, i128, isize], + [i32, i64, i128, isize], + [I32, I64, I128], + [I32, I64, I128] +); +define_type!( + An, + I32, + i32, + 32, + 4, + read_i32, + write_i32, + "signed integer", + [i64, i128], + [i64, i128], + [I64, I128], + [I64, I128] +); +define_type!( + An, + I64, + i64, + 64, + 8, + read_i64, + write_i64, + "signed integer", + [i128], + [i128], + [I128], + [I128] +); +define_type!(An, I128, i128, 128, 16, read_i128, write_i128, "signed integer", [], [], [], []); +define_type!( + An, + F32, + f32, + 32, + 4, + read_f32, + write_f32, + "floating point number", + [f64], + [], + [F64], + [] +); +define_type!(An, F64, f64, 64, 8, read_f64, write_f64, "floating point number", [], [], [], []); + +macro_rules! module { + ($name:ident, $trait:ident, $endianness_str:expr) => { + /// Numeric primitives stored in + #[doc = $endianness_str] + /// byte order. + pub mod $name { + use byteorder::$trait; + + module!(@ty U16, $trait, "16-bit unsigned integer", $endianness_str); + module!(@ty U32, $trait, "32-bit unsigned integer", $endianness_str); + module!(@ty U64, $trait, "64-bit unsigned integer", $endianness_str); + module!(@ty U128, $trait, "128-bit unsigned integer", $endianness_str); + module!(@ty I16, $trait, "16-bit signed integer", $endianness_str); + module!(@ty I32, $trait, "32-bit signed integer", $endianness_str); + module!(@ty I64, $trait, "64-bit signed integer", $endianness_str); + module!(@ty I128, $trait, "128-bit signed integer", $endianness_str); + module!(@ty F32, $trait, "32-bit floating point number", $endianness_str); + module!(@ty F64, $trait, "64-bit floating point number", $endianness_str); + } + }; + (@ty $ty:ident, $trait:ident, $desc_str:expr, $endianness_str:expr) => { + /// A + #[doc = $desc_str] + /// stored in + #[doc = $endianness_str] + /// byte order. + pub type $ty = crate::byteorder::$ty<$trait>; + }; +} + +module!(big_endian, BigEndian, "big-endian"); +module!(little_endian, LittleEndian, "little-endian"); +module!(network_endian, NetworkEndian, "network-endian"); +module!(native_endian, NativeEndian, "native-endian"); + +#[cfg(any(test, kani))] +mod tests { + use ::byteorder::NativeEndian; + + use { + super::*, + crate::{AsBytes, FromBytes, Unaligned}, + }; + + #[cfg(not(kani))] + mod compatibility { + pub(super) use rand::{ + distributions::{Distribution, Standard}, + rngs::SmallRng, + Rng, SeedableRng, + }; + + pub(crate) trait Arbitrary {} + + impl Arbitrary for T {} + } + + #[cfg(kani)] + mod compatibility { + pub(crate) use kani::Arbitrary; + + pub(crate) struct SmallRng; + + impl SmallRng { + pub(crate) fn seed_from_u64(_state: u64) -> Self { + Self + } + } + + pub(crate) trait Rng { + fn sample>(&mut self, _distr: D) -> T + where + T: Arbitrary, + { + kani::any() + } + } + + impl Rng for SmallRng {} + + pub(crate) trait Distribution {} + impl Distribution for U {} + + pub(crate) struct Standard; + } + + use compatibility::*; + + // A native integer type (u16, i32, etc). + trait Native: Arbitrary + FromBytes + AsBytes + Copy + PartialEq + Debug { + const ZERO: Self; + const MAX_VALUE: Self; + + type Distribution: Distribution; + const DIST: Self::Distribution; + + fn rand(rng: &mut R) -> Self { + rng.sample(Self::DIST) + } + + #[cfg(kani)] + fn any() -> Self { + kani::any() + } + + fn checked_add(self, rhs: Self) -> Option; + fn checked_div(self, rhs: Self) -> Option; + fn checked_mul(self, rhs: Self) -> Option; + fn checked_rem(self, rhs: Self) -> Option; + fn checked_sub(self, rhs: Self) -> Option; + fn checked_shl(self, rhs: Self) -> Option; + fn checked_shr(self, rhs: Self) -> Option; + + fn is_nan(self) -> bool; + + /// For `f32` and `f64`, NaN values are not considered equal to + /// themselves. This method is like `assert_eq!`, but it treats NaN + /// values as equal. + fn assert_eq_or_nan(self, other: Self) { + let slf = (!self.is_nan()).then(|| self); + let other = (!other.is_nan()).then(|| other); + assert_eq!(slf, other); + } + } + + trait ByteArray: + FromBytes + AsBytes + Copy + AsRef<[u8]> + AsMut<[u8]> + Debug + Default + Eq + { + /// Invert the order of the bytes in the array. + fn invert(self) -> Self; + } + + trait ByteOrderType: FromBytes + AsBytes + Unaligned + Copy + Eq + Debug { + type Native: Native; + type ByteArray: ByteArray; + + const ZERO: Self; + + fn new(native: Self::Native) -> Self; + fn get(self) -> Self::Native; + fn set(&mut self, native: Self::Native); + fn from_bytes(bytes: Self::ByteArray) -> Self; + fn into_bytes(self) -> Self::ByteArray; + + /// For `f32` and `f64`, NaN values are not considered equal to + /// themselves. This method is like `assert_eq!`, but it treats NaN + /// values as equal. + fn assert_eq_or_nan(self, other: Self) { + let slf = (!self.get().is_nan()).then(|| self); + let other = (!other.get().is_nan()).then(|| other); + assert_eq!(slf, other); + } + } + + trait ByteOrderTypeUnsigned: ByteOrderType { + const MAX_VALUE: Self; + } + + macro_rules! impl_byte_array { + ($bytes:expr) => { + impl ByteArray for [u8; $bytes] { + fn invert(mut self) -> [u8; $bytes] { + self.reverse(); + self + } + } + }; + } + + impl_byte_array!(2); + impl_byte_array!(4); + impl_byte_array!(8); + impl_byte_array!(16); + + macro_rules! impl_byte_order_type_unsigned { + ($name:ident, unsigned) => { + impl ByteOrderTypeUnsigned for $name { + const MAX_VALUE: $name = $name::MAX_VALUE; + } + }; + ($name:ident, signed) => {}; + } + + macro_rules! impl_traits { + ($name:ident, $native:ident, $bytes:expr, $sign:ident $(, @$float:ident)?) => { + impl Native for $native { + // For some types, `0 as $native` is required (for example, when + // `$native` is a floating-point type; `0` is an integer), but + // for other types, it's a trivial cast. In all cases, Clippy + // thinks it's dangerous. + #[allow(trivial_numeric_casts, clippy::as_conversions)] + const ZERO: $native = 0 as $native; + const MAX_VALUE: $native = $native::MAX; + + type Distribution = Standard; + const DIST: Standard = Standard; + + impl_traits!(@float_dependent_methods $(@$float)?); + } + + impl ByteOrderType for $name { + type Native = $native; + type ByteArray = [u8; $bytes]; + + const ZERO: $name = $name::ZERO; + + fn new(native: $native) -> $name { + $name::new(native) + } + + fn get(self) -> $native { + $name::get(self) + } + + fn set(&mut self, native: $native) { + $name::set(self, native) + } + + fn from_bytes(bytes: [u8; $bytes]) -> $name { + $name::from(bytes) + } + + fn into_bytes(self) -> [u8; $bytes] { + <[u8; $bytes]>::from(self) + } + } + + impl_byte_order_type_unsigned!($name, $sign); + }; + (@float_dependent_methods) => { + fn checked_add(self, rhs: Self) -> Option { self.checked_add(rhs) } + fn checked_div(self, rhs: Self) -> Option { self.checked_div(rhs) } + fn checked_mul(self, rhs: Self) -> Option { self.checked_mul(rhs) } + fn checked_rem(self, rhs: Self) -> Option { self.checked_rem(rhs) } + fn checked_sub(self, rhs: Self) -> Option { self.checked_sub(rhs) } + fn checked_shl(self, rhs: Self) -> Option { self.checked_shl(rhs.try_into().unwrap_or(u32::MAX)) } + fn checked_shr(self, rhs: Self) -> Option { self.checked_shr(rhs.try_into().unwrap_or(u32::MAX)) } + fn is_nan(self) -> bool { false } + }; + (@float_dependent_methods @float) => { + fn checked_add(self, rhs: Self) -> Option { Some(self + rhs) } + fn checked_div(self, rhs: Self) -> Option { Some(self / rhs) } + fn checked_mul(self, rhs: Self) -> Option { Some(self * rhs) } + fn checked_rem(self, rhs: Self) -> Option { Some(self % rhs) } + fn checked_sub(self, rhs: Self) -> Option { Some(self - rhs) } + fn checked_shl(self, _rhs: Self) -> Option { unimplemented!() } + fn checked_shr(self, _rhs: Self) -> Option { unimplemented!() } + fn is_nan(self) -> bool { self.is_nan() } + }; + } + + impl_traits!(U16, u16, 2, unsigned); + impl_traits!(U32, u32, 4, unsigned); + impl_traits!(U64, u64, 8, unsigned); + impl_traits!(U128, u128, 16, unsigned); + impl_traits!(I16, i16, 2, signed); + impl_traits!(I32, i32, 4, signed); + impl_traits!(I64, i64, 8, signed); + impl_traits!(I128, i128, 16, signed); + impl_traits!(F32, f32, 4, signed, @float); + impl_traits!(F64, f64, 8, signed, @float); + + macro_rules! call_for_unsigned_types { + ($fn:ident, $byteorder:ident) => { + $fn::>(); + $fn::>(); + $fn::>(); + $fn::>(); + }; + } + + macro_rules! call_for_signed_types { + ($fn:ident, $byteorder:ident) => { + $fn::>(); + $fn::>(); + $fn::>(); + $fn::>(); + }; + } + + macro_rules! call_for_float_types { + ($fn:ident, $byteorder:ident) => { + $fn::>(); + $fn::>(); + }; + } + + macro_rules! call_for_all_types { + ($fn:ident, $byteorder:ident) => { + call_for_unsigned_types!($fn, $byteorder); + call_for_signed_types!($fn, $byteorder); + call_for_float_types!($fn, $byteorder); + }; + } + + #[cfg(target_endian = "big")] + type NonNativeEndian = LittleEndian; + #[cfg(target_endian = "little")] + type NonNativeEndian = BigEndian; + + // We use a `u64` seed so that we can use `SeedableRng::seed_from_u64`. + // `SmallRng`'s `SeedableRng::Seed` differs by platform, so if we wanted to + // call `SeedableRng::from_seed`, which takes a `Seed`, we would need + // conditional compilation by `target_pointer_width`. + const RNG_SEED: u64 = 0x7A03CAE2F32B5B8F; + + const RAND_ITERS: usize = if cfg!(any(miri, kani)) { + // The tests below which use this constant used to take a very long time + // on Miri, which slows down local development and CI jobs. We're not + // using Miri to check for the correctness of our code, but rather its + // soundness, and at least in the context of these particular tests, a + // single loop iteration is just as good for surfacing UB as multiple + // iterations are. + // + // As of the writing of this comment, here's one set of measurements: + // + // $ # RAND_ITERS == 1 + // $ cargo miri test -- -Z unstable-options --report-time endian + // test byteorder::tests::test_native_endian ... ok <0.049s> + // test byteorder::tests::test_non_native_endian ... ok <0.061s> + // + // $ # RAND_ITERS == 1024 + // $ cargo miri test -- -Z unstable-options --report-time endian + // test byteorder::tests::test_native_endian ... ok <25.716s> + // test byteorder::tests::test_non_native_endian ... ok <38.127s> + 1 + } else { + 1024 + }; + + #[cfg_attr(test, test)] + #[cfg_attr(kani, kani::proof)] + fn test_zero() { + fn test_zero() { + assert_eq!(T::ZERO.get(), T::Native::ZERO); + } + + call_for_all_types!(test_zero, NativeEndian); + call_for_all_types!(test_zero, NonNativeEndian); + } + + #[cfg_attr(test, test)] + #[cfg_attr(kani, kani::proof)] + fn test_max_value() { + fn test_max_value() { + assert_eq!(T::MAX_VALUE.get(), T::Native::MAX_VALUE); + } + + call_for_unsigned_types!(test_max_value, NativeEndian); + call_for_unsigned_types!(test_max_value, NonNativeEndian); + } + + #[cfg_attr(test, test)] + #[cfg_attr(kani, kani::proof)] + fn test_endian() { + fn test(invert: bool) { + let mut r = SmallRng::seed_from_u64(RNG_SEED); + for _ in 0..RAND_ITERS { + let native = T::Native::rand(&mut r); + let mut bytes = T::ByteArray::default(); + bytes.as_bytes_mut().copy_from_slice(native.as_bytes()); + if invert { + bytes = bytes.invert(); + } + let mut from_native = T::new(native); + let from_bytes = T::from_bytes(bytes); + + from_native.assert_eq_or_nan(from_bytes); + from_native.get().assert_eq_or_nan(native); + from_bytes.get().assert_eq_or_nan(native); + + assert_eq!(from_native.into_bytes(), bytes); + assert_eq!(from_bytes.into_bytes(), bytes); + + let updated = T::Native::rand(&mut r); + from_native.set(updated); + from_native.get().assert_eq_or_nan(updated); + } + } + + fn test_native() { + test::(false); + } + + fn test_non_native() { + test::(true); + } + + call_for_all_types!(test_native, NativeEndian); + call_for_all_types!(test_non_native, NonNativeEndian); + } + + #[test] + fn test_ops_impls() { + // Test implementations of traits in `core::ops`. Some of these are + // fairly banal, but some are optimized to perform the operation without + // swapping byte order (namely, bit-wise operations which are identical + // regardless of byte order). These are important to test, and while + // we're testing those anyway, it's trivial to test all of the impls. + + fn test(op: F, op_native: G, op_native_checked: Option) + where + T: ByteOrderType, + F: Fn(T, T) -> T, + G: Fn(T::Native, T::Native) -> T::Native, + H: Fn(T::Native, T::Native) -> Option, + { + let mut r = SmallRng::seed_from_u64(RNG_SEED); + for _ in 0..RAND_ITERS { + let n0 = T::Native::rand(&mut r); + let n1 = T::Native::rand(&mut r); + let t0 = T::new(n0); + let t1 = T::new(n1); + + // If this operation would overflow/underflow, skip it rather + // than attempt to catch and recover from panics. + if matches!(&op_native_checked, Some(checked) if checked(n0, n1).is_none()) { + continue; + } + + let n_res = op_native(n0, n1); + let t_res = op(t0, t1); + + // For `f32` and `f64`, NaN values are not considered equal to + // themselves. We store `Option`/`Option` and store + // NaN as `None` so they can still be compared. + let n_res = (!T::Native::is_nan(n_res)).then(|| n_res); + let t_res = (!T::Native::is_nan(t_res.get())).then(|| t_res.get()); + assert_eq!(n_res, t_res); + } + } + + macro_rules! test { + (@binary $trait:ident, $method:ident $([$checked_method:ident])?, $($call_for_macros:ident),*) => {{ + test!( + @inner $trait, + core::ops::$trait::$method, + core::ops::$trait::$method, + { + #[allow(unused_mut, unused_assignments)] + let mut op_native_checked = None:: Option>; + $( + op_native_checked = Some(T::Native::$checked_method); + )? + op_native_checked + }, + $($call_for_macros),* + ); + }}; + (@unary $trait:ident, $method:ident $([$checked_method:ident])?, $($call_for_macros:ident),*) => {{ + test!( + @inner $trait, + |slf, _rhs| core::ops::$trait::$method(slf), + |slf, _rhs| core::ops::$trait::$method(slf), + { + #[allow(unused_mut, unused_assignments)] + let mut op_native_checked = None:: Option>; + $( + op_native_checked = Some(|slf, _rhs| T::Native::$checked_method(slf)); + )? + op_native_checked + }, + $($call_for_macros),* + ); + }}; + (@inner $trait:ident, $op:expr, $op_native:expr, $op_native_checked:expr, $($call_for_macros:ident),*) => {{ + fn t>() + where + T::Native: core::ops::$trait, + { + test::( + $op, + $op_native, + $op_native_checked, + ); + } + + $( + $call_for_macros!(t, NativeEndian); + $call_for_macros!(t, NonNativeEndian); + )* + }}; + } + + test!(@binary Add, add[checked_add], call_for_all_types); + test!(@binary Div, div[checked_div], call_for_all_types); + test!(@binary Mul, mul[checked_mul], call_for_all_types); + test!(@binary Rem, rem[checked_rem], call_for_all_types); + test!(@binary Sub, sub[checked_sub], call_for_all_types); + + test!(@binary BitAnd, bitand, call_for_unsigned_types, call_for_signed_types); + test!(@binary BitOr, bitor, call_for_unsigned_types, call_for_signed_types); + test!(@binary BitXor, bitxor, call_for_unsigned_types, call_for_signed_types); + test!(@binary Shl, shl[checked_shl], call_for_unsigned_types, call_for_signed_types); + test!(@binary Shr, shr[checked_shr], call_for_unsigned_types, call_for_signed_types); + + test!(@unary Not, not, call_for_signed_types, call_for_unsigned_types); + test!(@unary Neg, neg, call_for_signed_types, call_for_float_types); + } + + #[test] + fn test_debug_impl() { + // Ensure that Debug applies format options to the inner value. + let val = U16::::new(10); + assert_eq!(format!("{:?}", val), "U16(10)"); + assert_eq!(format!("{:03?}", val), "U16(010)"); + assert_eq!(format!("{:x?}", val), "U16(a)"); + } +} diff --git a/third_party/rust/zerocopy/src/lib.rs b/third_party/rust/zerocopy/src/lib.rs new file mode 100644 index 0000000000..1e826439ff --- /dev/null +++ b/third_party/rust/zerocopy/src/lib.rs @@ -0,0 +1,8256 @@ +// Copyright 2018 The Fuchsia Authors +// +// Licensed under the 2-Clause BSD License , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// After updating the following doc comment, make sure to run the following +// command to update `README.md` based on its contents: +// +// ./generate-readme.sh > README.md + +//! *Want to help improve zerocopy? +//! Fill out our [user survey][user-survey]!* +//! +//! ***Fast, safe, compile error. Pick two.*** +//! +//! Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe` +//! so you don't have to. +//! +//! # Overview +//! +//! Zerocopy provides four core marker traits, each of which can be derived +//! (e.g., `#[derive(FromZeroes)]`): +//! - [`FromZeroes`] indicates that a sequence of zero bytes represents a valid +//! instance of a type +//! - [`FromBytes`] indicates that a type may safely be converted from an +//! arbitrary byte sequence +//! - [`AsBytes`] indicates that a type may safely be converted *to* a byte +//! sequence +//! - [`Unaligned`] indicates that a type's alignment requirement is 1 +//! +//! Types which implement a subset of these traits can then be converted to/from +//! byte sequences with little to no runtime overhead. +//! +//! Zerocopy also provides byte-order aware integer types that support these +//! conversions; see the [`byteorder`] module. These types are especially useful +//! for network parsing. +//! +//! [user-survey]: https://docs.google.com/forms/d/e/1FAIpQLSdzBNTN9tzwsmtyZxRFNL02K36IWCdHWW2ZBckyQS2xiO3i8Q/viewform?usp=published_options +//! +//! # Cargo Features +//! +//! - **`alloc`** +//! By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled, +//! the `alloc` crate is added as a dependency, and some allocation-related +//! functionality is added. +//! +//! - **`byteorder`** (enabled by default) +//! Adds the [`byteorder`] module and a dependency on the `byteorder` crate. +//! The `byteorder` module provides byte order-aware equivalents of the +//! multi-byte primitive numerical types. Unlike their primitive equivalents, +//! the types in this module have no alignment requirement and support byte +//! order conversions. This can be useful in handling file formats, network +//! packet layouts, etc which don't provide alignment guarantees and which may +//! use a byte order different from that of the execution platform. +//! +//! - **`derive`** +//! Provides derives for the core marker traits via the `zerocopy-derive` +//! crate. These derives are re-exported from `zerocopy`, so it is not +//! necessary to depend on `zerocopy-derive` directly. +//! +//! However, you may experience better compile times if you instead directly +//! depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`, +//! since doing so will allow Rust to compile these crates in parallel. To do +//! so, do *not* enable the `derive` feature, and list both dependencies in +//! your `Cargo.toml` with the same leading non-zero version number; e.g: +//! +//! ```toml +//! [dependencies] +//! zerocopy = "0.X" +//! zerocopy-derive = "0.X" +//! ``` +//! +//! - **`simd`** +//! When the `simd` feature is enabled, `FromZeroes`, `FromBytes`, and +//! `AsBytes` impls are emitted for all stable SIMD types which exist on the +//! target platform. Note that the layout of SIMD types is not yet stabilized, +//! so these impls may be removed in the future if layout changes make them +//! invalid. For more information, see the Unsafe Code Guidelines Reference +//! page on the [layout of packed SIMD vectors][simd-layout]. +//! +//! - **`simd-nightly`** +//! Enables the `simd` feature and adds support for SIMD types which are only +//! available on nightly. Since these types are unstable, support for any type +//! may be removed at any point in the future. +//! +//! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html +//! +//! # Security Ethos +//! +//! Zerocopy is expressly designed for use in security-critical contexts. We +//! strive to ensure that that zerocopy code is sound under Rust's current +//! memory model, and *any future memory model*. We ensure this by: +//! - **...not 'guessing' about Rust's semantics.** +//! We annotate `unsafe` code with a precise rationale for its soundness that +//! cites a relevant section of Rust's official documentation. When Rust's +//! documented semantics are unclear, we work with the Rust Operational +//! Semantics Team to clarify Rust's documentation. +//! - **...rigorously testing our implementation.** +//! We run tests using [Miri], ensuring that zerocopy is sound across a wide +//! array of supported target platforms of varying endianness and pointer +//! width, and across both current and experimental memory models of Rust. +//! - **...formally proving the correctness of our implementation.** +//! We apply formal verification tools like [Kani][kani] to prove zerocopy's +//! correctness. +//! +//! For more information, see our full [soundness policy]. +//! +//! [Miri]: https://github.com/rust-lang/miri +//! [Kani]: https://github.com/model-checking/kani +//! [soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness +//! +//! # Relationship to Project Safe Transmute +//! +//! [Project Safe Transmute] is an official initiative of the Rust Project to +//! develop language-level support for safer transmutation. The Project consults +//! with crates like zerocopy to identify aspects of safer transmutation that +//! would benefit from compiler support, and has developed an [experimental, +//! compiler-supported analysis][mcp-transmutability] which determines whether, +//! for a given type, any value of that type may be soundly transmuted into +//! another type. Once this functionality is sufficiently mature, zerocopy +//! intends to replace its internal transmutability analysis (implemented by our +//! custom derives) with the compiler-supported one. This change will likely be +//! an implementation detail that is invisible to zerocopy's users. +//! +//! Project Safe Transmute will not replace the need for most of zerocopy's +//! higher-level abstractions. The experimental compiler analysis is a tool for +//! checking the soundness of `unsafe` code, not a tool to avoid writing +//! `unsafe` code altogether. For the foreseeable future, crates like zerocopy +//! will still be required in order to provide higher-level abstractions on top +//! of the building block provided by Project Safe Transmute. +//! +//! [Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html +//! [mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411 +//! +//! # MSRV +//! +//! See our [MSRV policy]. +//! +//! [MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv +//! +//! # Changelog +//! +//! Zerocopy uses [GitHub Releases]. +//! +//! [GitHub Releases]: https://github.com/google/zerocopy/releases + +// Sometimes we want to use lints which were added after our MSRV. +// `unknown_lints` is `warn` by default and we deny warnings in CI, so without +// this attribute, any unknown lint would cause a CI failure when testing with +// our MSRV. +#![allow(unknown_lints)] +#![deny(renamed_and_removed_lints)] +#![deny( + anonymous_parameters, + deprecated_in_future, + illegal_floating_point_literal_pattern, + late_bound_lifetime_arguments, + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + path_statements, + patterns_in_fns_without_body, + rust_2018_idioms, + trivial_numeric_casts, + unreachable_pub, + unsafe_op_in_unsafe_fn, + unused_extern_crates, + unused_qualifications, + variant_size_differences +)] +#![cfg_attr( + __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, + deny(fuzzy_provenance_casts, lossy_provenance_casts) +)] +#![deny( + clippy::all, + clippy::alloc_instead_of_core, + clippy::arithmetic_side_effects, + clippy::as_underscore, + clippy::assertions_on_result_states, + clippy::as_conversions, + clippy::correctness, + clippy::dbg_macro, + clippy::decimal_literal_representation, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::missing_inline_in_public_items, + clippy::missing_safety_doc, + clippy::obfuscated_if_else, + clippy::perf, + clippy::print_stdout, + clippy::std_instead_of_core, + clippy::style, + clippy::suspicious, + clippy::todo, + clippy::undocumented_unsafe_blocks, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unwrap_used, + clippy::use_debug +)] +#![deny( + rustdoc::bare_urls, + rustdoc::broken_intra_doc_links, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_html_tags, + rustdoc::invalid_rust_codeblocks, + rustdoc::missing_crate_level_docs, + rustdoc::private_intra_doc_links +)] +// In test code, it makes sense to weight more heavily towards concise, readable +// code over correct or debuggable code. +#![cfg_attr(any(test, kani), allow( + // In tests, you get line numbers and have access to source code, so panic + // messages are less important. You also often unwrap a lot, which would + // make expect'ing instead very verbose. + clippy::unwrap_used, + // In tests, there's no harm to "panic risks" - the worst that can happen is + // that your test will fail, and you'll fix it. By contrast, panic risks in + // production code introduce the possibly of code panicking unexpectedly "in + // the field". + clippy::arithmetic_side_effects, + clippy::indexing_slicing, +))] +#![cfg_attr(not(test), no_std)] +#![cfg_attr(feature = "simd-nightly", feature(stdsimd))] +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![cfg_attr( + __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, + feature(layout_for_ptr, strict_provenance) +)] + +// This is a hack to allow zerocopy-derive derives to work in this crate. They +// assume that zerocopy is linked as an extern crate, so they access items from +// it as `zerocopy::Xxx`. This makes that still work. +#[cfg(any(feature = "derive", test))] +extern crate self as zerocopy; + +#[macro_use] +mod macros; + +#[cfg(feature = "byteorder")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))] +pub mod byteorder; +#[doc(hidden)] +pub mod macro_util; +mod post_monomorphization_compile_fail_tests; +mod util; +// TODO(#252): If we make this pub, come up with a better name. +mod wrappers; + +#[cfg(feature = "byteorder")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))] +pub use crate::byteorder::*; +pub use crate::wrappers::*; + +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::Unaligned; + +// `pub use` separately here so that we can mark it `#[doc(hidden)]`. +// +// TODO(#29): Remove this or add a doc comment. +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +#[doc(hidden)] +pub use zerocopy_derive::KnownLayout; + +use core::{ + cell::{self, RefMut}, + cmp::Ordering, + fmt::{self, Debug, Display, Formatter}, + hash::Hasher, + marker::PhantomData, + mem::{self, ManuallyDrop, MaybeUninit}, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, + }, + ops::{Deref, DerefMut}, + ptr::{self, NonNull}, + slice, +}; + +#[cfg(feature = "alloc")] +extern crate alloc; +#[cfg(feature = "alloc")] +use alloc::{boxed::Box, vec::Vec}; + +#[cfg(any(feature = "alloc", kani))] +use core::alloc::Layout; + +// Used by `TryFromBytes::is_bit_valid`. +#[doc(hidden)] +pub use crate::util::ptr::Ptr; + +// For each polyfill, as soon as the corresponding feature is stable, the +// polyfill import will be unused because method/function resolution will prefer +// the inherent method/function over a trait method/function. Thus, we suppress +// the `unused_imports` warning. +// +// See the documentation on `util::polyfills` for more information. +#[allow(unused_imports)] +use crate::util::polyfills::NonNullExt as _; + +#[rustversion::nightly] +#[cfg(all(test, not(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)))] +const _: () = { + #[deprecated = "some tests may be skipped due to missing RUSTFLAGS=\"--cfg __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS\""] + const _WARNING: () = (); + #[warn(deprecated)] + _WARNING +}; + +/// The target pointer width, counted in bits. +const POINTER_WIDTH_BITS: usize = mem::size_of::() * 8; + +/// The layout of a type which might be dynamically-sized. +/// +/// `DstLayout` describes the layout of sized types, slice types, and "slice +/// DSTs" - ie, those that are known by the type system to have a trailing slice +/// (as distinguished from `dyn Trait` types - such types *might* have a +/// trailing slice type, but the type system isn't aware of it). +/// +/// # Safety +/// +/// Unlike [`core::alloc::Layout`], `DstLayout` is only used to describe full +/// Rust types - ie, those that satisfy the layout requirements outlined by +/// [the reference]. Callers may assume that an instance of `DstLayout` +/// satisfies any conditions imposed on Rust types by the reference. +/// +/// If `layout: DstLayout` describes a type, `T`, then it is guaranteed that: +/// - `layout.align` is equal to `T`'s alignment +/// - If `layout.size_info` is `SizeInfo::Sized { size }`, then `T: Sized` and +/// `size_of::() == size` +/// - If `layout.size_info` is `SizeInfo::SliceDst(slice_layout)`, then +/// - `T` is a slice DST +/// - The `size` of an instance of `T` with `elems` trailing slice elements is +/// equal to `slice_layout.offset + slice_layout.elem_size * elems` rounded up +/// to the nearest multiple of `layout.align`. Any bytes in the range +/// `[slice_layout.offset + slice_layout.elem_size * elems, size)` are padding +/// and must not be assumed to be initialized. +/// +/// [the reference]: https://doc.rust-lang.org/reference/type-layout.html +#[doc(hidden)] +#[allow(missing_debug_implementations, missing_copy_implementations)] +#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))] +pub struct DstLayout { + align: NonZeroUsize, + size_info: SizeInfo, +} + +#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))] +enum SizeInfo { + Sized { _size: usize }, + SliceDst(TrailingSliceLayout), +} + +#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))] +struct TrailingSliceLayout { + // The offset of the first byte of the trailing slice field. Note that this + // is NOT the same as the minimum size of the type. For example, consider + // the following type: + // + // struct Foo { + // a: u16, + // b: u8, + // c: [u8], + // } + // + // In `Foo`, `c` is at byte offset 3. When `c.len() == 0`, `c` is followed + // by a padding byte. + _offset: usize, + // The size of the element type of the trailing slice field. + _elem_size: E, +} + +impl SizeInfo { + /// Attempts to create a `SizeInfo` from `Self` in which `elem_size` is a + /// `NonZeroUsize`. If `elem_size` is 0, returns `None`. + #[allow(unused)] + const fn try_to_nonzero_elem_size(&self) -> Option> { + Some(match *self { + SizeInfo::Sized { _size } => SizeInfo::Sized { _size }, + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => { + if let Some(_elem_size) = NonZeroUsize::new(_elem_size) { + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) + } else { + return None; + } + } + }) + } +} + +#[doc(hidden)] +#[derive(Copy, Clone)] +#[cfg_attr(test, derive(Debug))] +#[allow(missing_debug_implementations)] +pub enum _CastType { + _Prefix, + _Suffix, +} + +impl DstLayout { + /// The minimum possible alignment of a type. + const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) { + Some(min_align) => min_align, + None => unreachable!(), + }; + + /// The maximum theoretic possible alignment of a type. + /// + /// For compatibility with future Rust versions, this is defined as the + /// maximum power-of-two that fits into a `usize`. See also + /// [`DstLayout::CURRENT_MAX_ALIGN`]. + const THEORETICAL_MAX_ALIGN: NonZeroUsize = + match NonZeroUsize::new(1 << (POINTER_WIDTH_BITS - 1)) { + Some(max_align) => max_align, + None => unreachable!(), + }; + + /// The current, documented max alignment of a type \[1\]. + /// + /// \[1\] Per : + /// + /// The alignment value must be a power of two from 1 up to + /// 229. + #[cfg(not(kani))] + const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 28) { + Some(max_align) => max_align, + None => unreachable!(), + }; + + /// Constructs a `DstLayout` for a zero-sized type with `repr_align` + /// alignment (or 1). If `repr_align` is provided, then it must be a power + /// of two. + /// + /// # Panics + /// + /// This function panics if the supplied `repr_align` is not a power of two. + /// + /// # Safety + /// + /// Unsafe code may assume that the contract of this function is satisfied. + #[doc(hidden)] + #[inline] + pub const fn new_zst(repr_align: Option) -> DstLayout { + let align = match repr_align { + Some(align) => align, + None => Self::MIN_ALIGN, + }; + + assert!(align.is_power_of_two()); + + DstLayout { align, size_info: SizeInfo::Sized { _size: 0 } } + } + + /// Constructs a `DstLayout` which describes `T`. + /// + /// # Safety + /// + /// Unsafe code may assume that `DstLayout` is the correct layout for `T`. + #[doc(hidden)] + #[inline] + pub const fn for_type() -> DstLayout { + // SAFETY: `align` is correct by construction. `T: Sized`, and so it is + // sound to initialize `size_info` to `SizeInfo::Sized { size }`; the + // `size` field is also correct by construction. + DstLayout { + align: match NonZeroUsize::new(mem::align_of::()) { + Some(align) => align, + None => unreachable!(), + }, + size_info: SizeInfo::Sized { _size: mem::size_of::() }, + } + } + + /// Constructs a `DstLayout` which describes `[T]`. + /// + /// # Safety + /// + /// Unsafe code may assume that `DstLayout` is the correct layout for `[T]`. + const fn for_slice() -> DstLayout { + // SAFETY: The alignment of a slice is equal to the alignment of its + // element type, and so `align` is initialized correctly. + // + // Since this is just a slice type, there is no offset between the + // beginning of the type and the beginning of the slice, so it is + // correct to set `offset: 0`. The `elem_size` is correct by + // construction. Since `[T]` is a (degenerate case of a) slice DST, it + // is correct to initialize `size_info` to `SizeInfo::SliceDst`. + DstLayout { + align: match NonZeroUsize::new(mem::align_of::()) { + Some(align) => align, + None => unreachable!(), + }, + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _offset: 0, + _elem_size: mem::size_of::(), + }), + } + } + + /// Like `Layout::extend`, this creates a layout that describes a record + /// whose layout consists of `self` followed by `next` that includes the + /// necessary inter-field padding, but not any trailing padding. + /// + /// In order to match the layout of a `#[repr(C)]` struct, this method + /// should be invoked for each field in declaration order. To add trailing + /// padding, call `DstLayout::pad_to_align` after extending the layout for + /// all fields. If `self` corresponds to a type marked with + /// `repr(packed(N))`, then `repr_packed` should be set to `Some(N)`, + /// otherwise `None`. + /// + /// This method cannot be used to match the layout of a record with the + /// default representation, as that representation is mostly unspecified. + /// + /// # Safety + /// + /// If a (potentially hypothetical) valid `repr(C)` Rust type begins with + /// fields whose layout are `self`, and those fields are immediately + /// followed by a field whose layout is `field`, then unsafe code may rely + /// on `self.extend(field, repr_packed)` producing a layout that correctly + /// encompasses those two components. + /// + /// We make no guarantees to the behavior of this method if these fragments + /// cannot appear in a valid Rust type (e.g., the concatenation of the + /// layouts would lead to a size larger than `isize::MAX`). + #[doc(hidden)] + #[inline] + pub const fn extend(self, field: DstLayout, repr_packed: Option) -> Self { + use util::{core_layout::padding_needed_for, max, min}; + + // If `repr_packed` is `None`, there are no alignment constraints, and + // the value can be defaulted to `THEORETICAL_MAX_ALIGN`. + let max_align = match repr_packed { + Some(max_align) => max_align, + None => Self::THEORETICAL_MAX_ALIGN, + }; + + assert!(max_align.is_power_of_two()); + + // We use Kani to prove that this method is robust to future increases + // in Rust's maximum allowed alignment. However, if such a change ever + // actually occurs, we'd like to be notified via assertion failures. + #[cfg(not(kani))] + { + debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + if let Some(repr_packed) = repr_packed { + debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + } + } + + // The field's alignment is clamped by `repr_packed` (i.e., the + // `repr(packed(N))` attribute, if any) [1]. + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // The alignments of each field, for the purpose of positioning + // fields, is the smaller of the specified alignment and the alignment + // of the field's type. + let field_align = min(field.align, max_align); + + // The struct's alignment is the maximum of its previous alignment and + // `field_align`. + let align = max(self.align, field_align); + + let size_info = match self.size_info { + // If the layout is already a DST, we panic; DSTs cannot be extended + // with additional fields. + SizeInfo::SliceDst(..) => panic!("Cannot extend a DST with additional fields."), + + SizeInfo::Sized { _size: preceding_size } => { + // Compute the minimum amount of inter-field padding needed to + // satisfy the field's alignment, and offset of the trailing + // field. [1] + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // Inter-field padding is guaranteed to be the minimum + // required in order to satisfy each field's (possibly + // altered) alignment. + let padding = padding_needed_for(preceding_size, field_align); + + // This will not panic (and is proven to not panic, with Kani) + // if the layout components can correspond to a leading layout + // fragment of a valid Rust type, but may panic otherwise (e.g., + // combining or aligning the components would create a size + // exceeding `isize::MAX`). + let offset = match preceding_size.checked_add(padding) { + Some(offset) => offset, + None => panic!("Adding padding to `self`'s size overflows `usize`."), + }; + + match field.size_info { + SizeInfo::Sized { _size: field_size } => { + // If the trailing field is sized, the resulting layout + // will be sized. Its size will be the sum of the + // preceeding layout, the size of the new field, and the + // size of inter-field padding between the two. + // + // This will not panic (and is proven with Kani to not + // panic) if the layout components can correspond to a + // leading layout fragment of a valid Rust type, but may + // panic otherwise (e.g., combining or aligning the + // components would create a size exceeding + // `usize::MAX`). + let size = match offset.checked_add(field_size) { + Some(size) => size, + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), + }; + SizeInfo::Sized { _size: size } + } + SizeInfo::SliceDst(TrailingSliceLayout { + _offset: trailing_offset, + _elem_size, + }) => { + // If the trailing field is dynamically sized, so too + // will the resulting layout. The offset of the trailing + // slice component is the sum of the offset of the + // trailing field and the trailing slice offset within + // that field. + // + // This will not panic (and is proven with Kani to not + // panic) if the layout components can correspond to a + // leading layout fragment of a valid Rust type, but may + // panic otherwise (e.g., combining or aligning the + // components would create a size exceeding + // `usize::MAX`). + let offset = match offset.checked_add(trailing_offset) { + Some(offset) => offset, + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), + }; + SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size }) + } + } + } + }; + + DstLayout { align, size_info } + } + + /// Like `Layout::pad_to_align`, this routine rounds the size of this layout + /// up to the nearest multiple of this type's alignment or `repr_packed` + /// (whichever is less). This method leaves DST layouts unchanged, since the + /// trailing padding of DSTs is computed at runtime. + /// + /// In order to match the layout of a `#[repr(C)]` struct, this method + /// should be invoked after the invocations of [`DstLayout::extend`]. If + /// `self` corresponds to a type marked with `repr(packed(N))`, then + /// `repr_packed` should be set to `Some(N)`, otherwise `None`. + /// + /// This method cannot be used to match the layout of a record with the + /// default representation, as that representation is mostly unspecified. + /// + /// # Safety + /// + /// If a (potentially hypothetical) valid `repr(C)` type begins with fields + /// whose layout are `self` followed only by zero or more bytes of trailing + /// padding (not included in `self`), then unsafe code may rely on + /// `self.pad_to_align(repr_packed)` producing a layout that correctly + /// encapsulates the layout of that type. + /// + /// We make no guarantees to the behavior of this method if `self` cannot + /// appear in a valid Rust type (e.g., because the addition of trailing + /// padding would lead to a size larger than `isize::MAX`). + #[doc(hidden)] + #[inline] + pub const fn pad_to_align(self) -> Self { + use util::core_layout::padding_needed_for; + + let size_info = match self.size_info { + // For sized layouts, we add the minimum amount of trailing padding + // needed to satisfy alignment. + SizeInfo::Sized { _size: unpadded_size } => { + let padding = padding_needed_for(unpadded_size, self.align); + let size = match unpadded_size.checked_add(padding) { + Some(size) => size, + None => panic!("Adding padding caused size to overflow `usize`."), + }; + SizeInfo::Sized { _size: size } + } + // For DST layouts, trailing padding depends on the length of the + // trailing DST and is computed at runtime. This does not alter the + // offset or element size of the layout, so we leave `size_info` + // unchanged. + size_info @ SizeInfo::SliceDst(_) => size_info, + }; + + DstLayout { align: self.align, size_info } + } + + /// Validates that a cast is sound from a layout perspective. + /// + /// Validates that the size and alignment requirements of a type with the + /// layout described in `self` would not be violated by performing a + /// `cast_type` cast from a pointer with address `addr` which refers to a + /// memory region of size `bytes_len`. + /// + /// If the cast is valid, `validate_cast_and_convert_metadata` returns + /// `(elems, split_at)`. If `self` describes a dynamically-sized type, then + /// `elems` is the maximum number of trailing slice elements for which a + /// cast would be valid (for sized types, `elem` is meaningless and should + /// be ignored). `split_at` is the index at which to split the memory region + /// in order for the prefix (suffix) to contain the result of the cast, and + /// in order for the remaining suffix (prefix) to contain the leftover + /// bytes. + /// + /// There are three conditions under which a cast can fail: + /// - The smallest possible value for the type is larger than the provided + /// memory region + /// - A prefix cast is requested, and `addr` does not satisfy `self`'s + /// alignment requirement + /// - A suffix cast is requested, and `addr + bytes_len` does not satisfy + /// `self`'s alignment requirement (as a consequence, since all instances + /// of the type are a multiple of its alignment, no size for the type will + /// result in a starting address which is properly aligned) + /// + /// # Safety + /// + /// The caller may assume that this implementation is correct, and may rely + /// on that assumption for the soundness of their code. In particular, the + /// caller may assume that, if `validate_cast_and_convert_metadata` returns + /// `Some((elems, split_at))`, then: + /// - A pointer to the type (for dynamically sized types, this includes + /// `elems` as its pointer metadata) describes an object of size `size <= + /// bytes_len` + /// - If this is a prefix cast: + /// - `addr` satisfies `self`'s alignment + /// - `size == split_at` + /// - If this is a suffix cast: + /// - `split_at == bytes_len - size` + /// - `addr + split_at` satisfies `self`'s alignment + /// + /// Note that this method does *not* ensure that a pointer constructed from + /// its return values will be a valid pointer. In particular, this method + /// does not reason about `isize` overflow, which is a requirement of many + /// Rust pointer APIs, and may at some point be determined to be a validity + /// invariant of pointer types themselves. This should never be a problem so + /// long as the arguments to this method are derived from a known-valid + /// pointer (e.g., one derived from a safe Rust reference), but it is + /// nonetheless the caller's responsibility to justify that pointer + /// arithmetic will not overflow based on a safety argument *other than* the + /// mere fact that this method returned successfully. + /// + /// # Panics + /// + /// `validate_cast_and_convert_metadata` will panic if `self` describes a + /// DST whose trailing slice element is zero-sized. + /// + /// If `addr + bytes_len` overflows `usize`, + /// `validate_cast_and_convert_metadata` may panic, or it may return + /// incorrect results. No guarantees are made about when + /// `validate_cast_and_convert_metadata` will panic. The caller should not + /// rely on `validate_cast_and_convert_metadata` panicking in any particular + /// condition, even if `debug_assertions` are enabled. + #[allow(unused)] + const fn validate_cast_and_convert_metadata( + &self, + addr: usize, + bytes_len: usize, + cast_type: _CastType, + ) -> Option<(usize, usize)> { + // `debug_assert!`, but with `#[allow(clippy::arithmetic_side_effects)]`. + macro_rules! __debug_assert { + ($e:expr $(, $msg:expr)?) => { + debug_assert!({ + #[allow(clippy::arithmetic_side_effects)] + let e = $e; + e + } $(, $msg)?); + }; + } + + // Note that, in practice, `self` is always a compile-time constant. We + // do this check earlier than needed to ensure that we always panic as a + // result of bugs in the program (such as calling this function on an + // invalid type) instead of allowing this panic to be hidden if the cast + // would have failed anyway for runtime reasons (such as a too-small + // memory region). + // + // TODO(#67): Once our MSRV is 1.65, use let-else: + // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements + let size_info = match self.size_info.try_to_nonzero_elem_size() { + Some(size_info) => size_info, + None => panic!("attempted to cast to slice type with zero-sized element"), + }; + + // Precondition + __debug_assert!(addr.checked_add(bytes_len).is_some(), "`addr` + `bytes_len` > usize::MAX"); + + // Alignment checks go in their own block to avoid introducing variables + // into the top-level scope. + { + // We check alignment for `addr` (for prefix casts) or `addr + + // bytes_len` (for suffix casts). For a prefix cast, the correctness + // of this check is trivial - `addr` is the address the object will + // live at. + // + // For a suffix cast, we know that all valid sizes for the type are + // a multiple of the alignment (and by safety precondition, we know + // `DstLayout` may only describe valid Rust types). Thus, a + // validly-sized instance which lives at a validly-aligned address + // must also end at a validly-aligned address. Thus, if the end + // address for a suffix cast (`addr + bytes_len`) is not aligned, + // then no valid start address will be aligned either. + let offset = match cast_type { + _CastType::_Prefix => 0, + _CastType::_Suffix => bytes_len, + }; + + // Addition is guaranteed not to overflow because `offset <= + // bytes_len`, and `addr + bytes_len <= usize::MAX` is a + // precondition of this method. Modulus is guaranteed not to divide + // by 0 because `align` is non-zero. + #[allow(clippy::arithmetic_side_effects)] + if (addr + offset) % self.align.get() != 0 { + return None; + } + } + + let (elems, self_bytes) = match size_info { + SizeInfo::Sized { _size: size } => { + if size > bytes_len { + return None; + } + (0, size) + } + SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size: elem_size }) => { + // Calculate the maximum number of bytes that could be consumed + // - any number of bytes larger than this will either not be a + // multiple of the alignment, or will be larger than + // `bytes_len`. + let max_total_bytes = + util::round_down_to_next_multiple_of_alignment(bytes_len, self.align); + // Calculate the maximum number of bytes that could be consumed + // by the trailing slice. + // + // TODO(#67): Once our MSRV is 1.65, use let-else: + // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements + let max_slice_and_padding_bytes = match max_total_bytes.checked_sub(offset) { + Some(max) => max, + // `bytes_len` too small even for 0 trailing slice elements. + None => return None, + }; + + // Calculate the number of elements that fit in + // `max_slice_and_padding_bytes`; any remaining bytes will be + // considered padding. + // + // Guaranteed not to divide by zero: `elem_size` is non-zero. + #[allow(clippy::arithmetic_side_effects)] + let elems = max_slice_and_padding_bytes / elem_size.get(); + // Guaranteed not to overflow on multiplication: `usize::MAX >= + // max_slice_and_padding_bytes >= (max_slice_and_padding_bytes / + // elem_size) * elem_size`. + // + // Guaranteed not to overflow on addition: + // - max_slice_and_padding_bytes == max_total_bytes - offset + // - elems * elem_size <= max_slice_and_padding_bytes == max_total_bytes - offset + // - elems * elem_size + offset <= max_total_bytes <= usize::MAX + #[allow(clippy::arithmetic_side_effects)] + let without_padding = offset + elems * elem_size.get(); + // `self_bytes` is equal to the offset bytes plus the bytes + // consumed by the trailing slice plus any padding bytes + // required to satisfy the alignment. Note that we have computed + // the maximum number of trailing slice elements that could fit + // in `self_bytes`, so any padding is guaranteed to be less than + // the size of an extra element. + // + // Guaranteed not to overflow: + // - By previous comment: without_padding == elems * elem_size + + // offset <= max_total_bytes + // - By construction, `max_total_bytes` is a multiple of + // `self.align`. + // - At most, adding padding needed to round `without_padding` + // up to the next multiple of the alignment will bring + // `self_bytes` up to `max_total_bytes`. + #[allow(clippy::arithmetic_side_effects)] + let self_bytes = without_padding + + util::core_layout::padding_needed_for(without_padding, self.align); + (elems, self_bytes) + } + }; + + __debug_assert!(self_bytes <= bytes_len); + + let split_at = match cast_type { + _CastType::_Prefix => self_bytes, + // Guaranteed not to underflow: + // - In the `Sized` branch, only returns `size` if `size <= + // bytes_len`. + // - In the `SliceDst` branch, calculates `self_bytes <= + // max_toatl_bytes`, which is upper-bounded by `bytes_len`. + #[allow(clippy::arithmetic_side_effects)] + _CastType::_Suffix => bytes_len - self_bytes, + }; + + Some((elems, split_at)) + } +} + +/// A trait which carries information about a type's layout that is used by the +/// internals of this crate. +/// +/// This trait is not meant for consumption by code outside of this crate. While +/// the normal semver stability guarantees apply with respect to which types +/// implement this trait and which trait implementations are implied by this +/// trait, no semver stability guarantees are made regarding its internals; they +/// may change at any time, and code which makes use of them may break. +/// +/// # Safety +/// +/// This trait does not convey any safety guarantees to code outside this crate. +#[doc(hidden)] // TODO: Remove this once KnownLayout is used by other APIs +pub unsafe trait KnownLayout { + // The `Self: Sized` bound makes it so that `KnownLayout` can still be + // object safe. It's not currently object safe thanks to `const LAYOUT`, and + // it likely won't be in the future, but there's no reason not to be + // forwards-compatible with object safety. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + #[doc(hidden)] + const LAYOUT: DstLayout; + + /// SAFETY: The returned pointer has the same address and provenance as + /// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems` + /// elements in its trailing slice. If `Self` is sized, `elems` is ignored. + #[doc(hidden)] + fn raw_from_ptr_len(bytes: NonNull, elems: usize) -> NonNull; +} + +// SAFETY: Delegates safety to `DstLayout::for_slice`. +unsafe impl KnownLayout for [T] { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized, + { + } + const LAYOUT: DstLayout = DstLayout::for_slice::(); + + // SAFETY: `.cast` preserves address and provenance. The returned pointer + // refers to an object with `elems` elements by construction. + #[inline(always)] + fn raw_from_ptr_len(data: NonNull, elems: usize) -> NonNull { + // TODO(#67): Remove this allow. See NonNullExt for more details. + #[allow(unstable_name_collisions)] + NonNull::slice_from_raw_parts(data.cast::(), elems) + } +} + +#[rustfmt::skip] +impl_known_layout!( + (), + u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64, + bool, char, + NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, + NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize +); +#[rustfmt::skip] +impl_known_layout!( + T => Option, + T: ?Sized => PhantomData, + T => Wrapping, + T => MaybeUninit, + T: ?Sized => *const T, + T: ?Sized => *mut T, +); +impl_known_layout!(const N: usize, T => [T; N]); + +safety_comment! { + /// SAFETY: + /// `str` and `ManuallyDrop<[T]>` [1] have the same representations as + /// `[u8]` and `[T]` repsectively. `str` has different bit validity than + /// `[u8]`, but that doesn't affect the soundness of this impl. + /// + /// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + /// + /// `ManuallyDrop` is guaranteed to have the same layout and bit + /// validity as `T` + /// + /// TODO(#429): + /// - Add quotes from docs. + /// - Once [1] (added in + /// https://github.com/rust-lang/rust/pull/115522) is available on stable, + /// quote the stable docs instead of the nightly docs. + unsafe_impl_known_layout!(#[repr([u8])] str); + unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop); +} + +/// Analyzes whether a type is [`FromZeroes`]. +/// +/// This derive analyzes, at compile time, whether the annotated type satisfies +/// the [safety conditions] of `FromZeroes` and implements `FromZeroes` if it is +/// sound to do so. This derive can be applied to structs, enums, and unions; +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::FromZeroes; +/// #[derive(FromZeroes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant0, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// [safety conditions]: trait@FromZeroes#safety +/// +/// # Analysis +/// +/// *This section describes, roughly, the analysis performed by this derive to +/// determine whether it is sound to implement `FromZeroes` for a given type. +/// Unless you are modifying the implementation of this derive, or attempting to +/// manually implement `FromZeroes` for a type yourself, you don't need to read +/// this section.* +/// +/// If a type has the following properties, then this derive can implement +/// `FromZeroes` for that type: +/// +/// - If the type is a struct, all of its fields must be `FromZeroes`. +/// - If the type is an enum, it must be C-like (meaning that all variants have +/// no fields) and it must have a variant with a discriminant of `0`. See [the +/// reference] for a description of how discriminant values are chosen. +/// - The type must not contain any [`UnsafeCell`]s (this is required in order +/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of +/// memory). The type may contain references or pointers to `UnsafeCell`s so +/// long as those values can themselves be initialized from zeroes +/// (`FromZeroes` is not currently implemented for, e.g., +/// `Option<&UnsafeCell<_>>`, but it could be one day). +/// +/// This analysis is subject to change. Unsafe code may *only* rely on the +/// documented [safety conditions] of `FromZeroes`, and must *not* rely on the +/// implementation details of this derive. +/// +/// [the reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations +/// [`UnsafeCell`]: core::cell::UnsafeCell +/// +/// ## Why isn't an explicit representation required for structs? +/// +/// Neither this derive, nor the [safety conditions] of `FromZeroes`, requires +/// that structs are marked with `#[repr(C)]`. +/// +/// Per the [Rust reference](reference), +/// +/// > The representation of a type can change the padding between fields, but +/// does not change the layout of the fields themselves. +/// +/// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations +/// +/// Since the layout of structs only consists of padding bytes and field bytes, +/// a struct is soundly `FromZeroes` if: +/// 1. its padding is soundly `FromZeroes`, and +/// 2. its fields are soundly `FromZeroes`. +/// +/// The answer to the first question is always yes: padding bytes do not have +/// any validity constraints. A [discussion] of this question in the Unsafe Code +/// Guidelines Working Group concluded that it would be virtually unimaginable +/// for future versions of rustc to add validity constraints to padding bytes. +/// +/// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 +/// +/// Whether a struct is soundly `FromZeroes` therefore solely depends on whether +/// its fields are `FromZeroes`. +// TODO(#146): Document why we don't require an enum to have an explicit `repr` +// attribute. +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::FromZeroes; + +/// Types whose validity can be checked at runtime, allowing them to be +/// conditionally converted from byte slices. +/// +/// WARNING: Do not implement this trait yourself! Instead, use +/// `#[derive(TryFromBytes)]`. +/// +/// `TryFromBytes` types can safely be deserialized from an untrusted sequence +/// of bytes by performing a runtime check that the byte sequence contains a +/// valid instance of `Self`. +/// +/// `TryFromBytes` is ignorant of byte order. For byte order-aware types, see +/// the [`byteorder`] module. +/// +/// # What is a "valid instance"? +/// +/// In Rust, each type has *bit validity*, which refers to the set of bit +/// patterns which may appear in an instance of that type. It is impossible for +/// safe Rust code to produce values which violate bit validity (ie, values +/// outside of the "valid" set of bit patterns). If `unsafe` code produces an +/// invalid value, this is considered [undefined behavior]. +/// +/// Rust's bit validity rules are currently being decided, which means that some +/// types have three classes of bit patterns: those which are definitely valid, +/// and whose validity is documented in the language; those which may or may not +/// be considered valid at some point in the future; and those which are +/// definitely invalid. +/// +/// Zerocopy takes a conservative approach, and only considers a bit pattern to +/// be valid if its validity is a documenteed guarantee provided by the +/// language. +/// +/// For most use cases, Rust's current guarantees align with programmers' +/// intuitions about what ought to be valid. As a result, zerocopy's +/// conservatism should not affect most users. One notable exception is unions, +/// whose bit validity is very up in the air; zerocopy does not permit +/// implementing `TryFromBytes` for any union type. +/// +/// If you are negatively affected by lack of support for a particular type, +/// we encourage you to let us know by [filing an issue][github-repo]. +/// +/// # Safety +/// +/// On its own, `T: TryFromBytes` does not make any guarantees about the layout +/// or representation of `T`. It merely provides the ability to perform a +/// validity check at runtime via methods like [`try_from_ref`]. +/// +/// Currently, it is not possible to stably implement `TryFromBytes` other than +/// by using `#[derive(TryFromBytes)]`. While there are `#[doc(hidden)]` items +/// on this trait that provide well-defined safety invariants, no stability +/// guarantees are made with respect to these items. In particular, future +/// releases of zerocopy may make backwards-breaking changes to these items, +/// including changes that only affect soundness, which may cause code which +/// uses those items to silently become unsound. +/// +/// [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html +/// [github-repo]: https://github.com/google/zerocopy +/// [`try_from_ref`]: TryFromBytes::try_from_ref +// TODO(#5): Update `try_from_ref` doc link once it exists +#[doc(hidden)] +pub unsafe trait TryFromBytes { + /// Does a given memory range contain a valid instance of `Self`? + /// + /// # Safety + /// + /// ## Preconditions + /// + /// The memory referenced by `candidate` may only be accessed via reads for + /// the duration of this method call. This prohibits writes through mutable + /// references and through [`UnsafeCell`]s. There may exist immutable + /// references to the same memory which contain `UnsafeCell`s so long as: + /// - Those `UnsafeCell`s exist at the same byte ranges as `UnsafeCell`s in + /// `Self`. This is a bidirectional property: `Self` may not contain + /// `UnsafeCell`s where other references to the same memory do not, and + /// vice-versa. + /// - Those `UnsafeCell`s are never used to perform mutation for the + /// duration of this method call. + /// + /// The memory referenced by `candidate` may not be referenced by any + /// mutable references even if these references are not used to perform + /// mutation. + /// + /// `candidate` is not required to refer to a valid `Self`. However, it must + /// satisfy the requirement that uninitialized bytes may only be present + /// where it is possible for them to be present in `Self`. This is a dynamic + /// property: if, at a particular byte offset, a valid enum discriminant is + /// set, the subsequent bytes may only have uninitialized bytes as + /// specificed by the corresponding enum. + /// + /// Formally, given `len = size_of_val_raw(candidate)`, at every byte + /// offset, `b`, in the range `[0, len)`: + /// - If, in all instances `s: Self` of length `len`, the byte at offset `b` + /// in `s` is initialized, then the byte at offset `b` within `*candidate` + /// must be initialized. + /// - Let `c` be the contents of the byte range `[0, b)` in `*candidate`. + /// Let `S` be the subset of valid instances of `Self` of length `len` + /// which contain `c` in the offset range `[0, b)`. If, for all instances + /// of `s: Self` in `S`, the byte at offset `b` in `s` is initialized, + /// then the byte at offset `b` in `*candidate` must be initialized. + /// + /// Pragmatically, this means that if `*candidate` is guaranteed to + /// contain an enum type at a particular offset, and the enum discriminant + /// stored in `*candidate` corresponds to a valid variant of that enum + /// type, then it is guaranteed that the appropriate bytes of `*candidate` + /// are initialized as defined by that variant's bit validity (although + /// note that the variant may contain another enum type, in which case the + /// same rules apply depending on the state of its discriminant, and so on + /// recursively). + /// + /// ## Postconditions + /// + /// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true, + /// `*candidate` contains a valid `Self`. + /// + /// # Panics + /// + /// `is_bit_valid` may panic. Callers are responsible for ensuring that any + /// `unsafe` code remains sound even in the face of `is_bit_valid` + /// panicking. (We support user-defined validation routines; so long as + /// these routines are not required to be `unsafe`, there is no way to + /// ensure that these do not generate panics.) + /// + /// [`UnsafeCell`]: core::cell::UnsafeCell + #[doc(hidden)] + unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool; + + /// Attempts to interpret a byte slice as a `Self`. + /// + /// `try_from_ref` validates that `bytes` contains a valid `Self`, and that + /// it satisfies `Self`'s alignment requirement. If it does, then `bytes` is + /// reinterpreted as a `Self`. + /// + /// Note that Rust's bit validity rules are still being decided. As such, + /// there exist types whose bit validity is ambiguous. See the + /// `TryFromBytes` docs for a discussion of how these cases are handled. + // TODO(#251): In a future in which we distinguish between `FromBytes` and + // `RefFromBytes`, this requires `where Self: RefFromBytes` to disallow + // interior mutability. + #[inline] + #[doc(hidden)] // TODO(#5): Finalize name before remove this attribute. + fn try_from_ref(bytes: &[u8]) -> Option<&Self> + where + Self: KnownLayout, + { + let maybe_self = Ptr::from(bytes).try_cast_into_no_leftover::()?; + + // SAFETY: + // - Since `bytes` is an immutable reference, we know that no mutable + // references exist to this memory region. + // - Since `[u8]` contains no `UnsafeCell`s, we know there are no + // `&UnsafeCell` references to this memory region. + // - Since we don't permit implementing `TryFromBytes` for types which + // contain `UnsafeCell`s, there are no `UnsafeCell`s in `Self`, and so + // the requirement that all references contain `UnsafeCell`s at the + // same offsets is trivially satisfied. + // - All bytes of `bytes` are initialized. + // + // This call may panic. If that happens, it doesn't cause any soundness + // issues, as we have not generated any invalid state which we need to + // fix before returning. + if unsafe { !Self::is_bit_valid(maybe_self) } { + return None; + } + + // SAFETY: + // - Preconditions for `as_ref`: + // - `is_bit_valid` guarantees that `*maybe_self` contains a valid + // `Self`. Since `&[u8]` does not permit interior mutation, this + // cannot be invalidated after this method returns. + // - Since the argument and return types are immutable references, + // Rust will prevent the caller from producing any mutable + // references to the same memory region. + // - Since `Self` is not allowed to contain any `UnsafeCell`s and the + // same is true of `[u8]`, interior mutation is not possible. Thus, + // no mutation is possible. For the same reason, there is no + // mismatch between the two types in terms of which byte ranges are + // referenced as `UnsafeCell`s. + // - Since interior mutation isn't possible within `Self`, there's no + // way for the returned reference to be used to modify the byte range, + // and thus there's no way for the returned reference to be used to + // write an invalid `[u8]` which would be observable via the original + // `&[u8]`. + Some(unsafe { maybe_self.as_ref() }) + } +} + +/// Types for which a sequence of bytes all set to zero represents a valid +/// instance of the type. +/// +/// Any memory region of the appropriate length which is guaranteed to contain +/// only zero bytes can be viewed as any `FromZeroes` type with no runtime +/// overhead. This is useful whenever memory is known to be in a zeroed state, +/// such memory returned from some allocation routines. +/// +/// # Implementation +/// +/// **Do not implement this trait yourself!** Instead, use +/// [`#[derive(FromZeroes)]`][derive] (requires the `derive` Cargo feature); +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::FromZeroes; +/// #[derive(FromZeroes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant0, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// This derive performs a sophisticated, compile-time safety analysis to +/// determine whether a type is `FromZeroes`. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: FromZeroes`, and +/// what unsafe code may assume of such types. If you don't plan on implementing +/// `FromZeroes` manually, and you don't plan on writing unsafe code that +/// operates on `FromZeroes` types, then you don't need to read this section.* +/// +/// If `T: FromZeroes`, then unsafe code may assume that: +/// - It is sound to treat any initialized sequence of zero bytes of length +/// `size_of::()` as a `T`. +/// - Given `b: &[u8]` where `b.len() == size_of::()`, `b` is aligned to +/// `align_of::()`, and `b` contains only zero bytes, it is sound to +/// construct a `t: &T` at the same address as `b`, and it is sound for both +/// `b` and `t` to be live at the same time. +/// +/// If a type is marked as `FromZeroes` which violates this contract, it may +/// cause undefined behavior. +/// +/// `#[derive(FromZeroes)]` only permits [types which satisfy these +/// requirements][derive-analysis]. +/// +#[cfg_attr( + feature = "derive", + doc = "[derive]: zerocopy_derive::FromZeroes", + doc = "[derive-analysis]: zerocopy_derive::FromZeroes#analysis" +)] +#[cfg_attr( + not(feature = "derive"), + doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html"), + doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html#analysis"), +)] +pub unsafe trait FromZeroes { + // The `Self: Sized` bound makes it so that `FromZeroes` is still object + // safe. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + /// Overwrites `self` with zeroes. + /// + /// Sets every byte in `self` to 0. While this is similar to doing `*self = + /// Self::new_zeroed()`, it differs in that `zero` does not semantically + /// drop the current value and replace it with a new one - it simply + /// modifies the bytes of the existing value. + /// + /// # Examples + /// + /// ``` + /// # use zerocopy::FromZeroes; + /// # use zerocopy_derive::*; + /// # + /// #[derive(FromZeroes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let mut header = PacketHeader { + /// src_port: 100u16.to_be_bytes(), + /// dst_port: 200u16.to_be_bytes(), + /// length: 300u16.to_be_bytes(), + /// checksum: 400u16.to_be_bytes(), + /// }; + /// + /// header.zero(); + /// + /// assert_eq!(header.src_port, [0, 0]); + /// assert_eq!(header.dst_port, [0, 0]); + /// assert_eq!(header.length, [0, 0]); + /// assert_eq!(header.checksum, [0, 0]); + /// ``` + #[inline(always)] + fn zero(&mut self) { + let slf: *mut Self = self; + let len = mem::size_of_val(self); + // SAFETY: + // - `self` is guaranteed by the type system to be valid for writes of + // size `size_of_val(self)`. + // - `u8`'s alignment is 1, and thus `self` is guaranteed to be aligned + // as required by `u8`. + // - Since `Self: FromZeroes`, the all-zeroes instance is a valid + // instance of `Self.` + // + // TODO(#429): Add references to docs and quotes. + unsafe { ptr::write_bytes(slf.cast::(), 0, len) }; + } + + /// Creates an instance of `Self` from zeroed bytes. + /// + /// # Examples + /// + /// ``` + /// # use zerocopy::FromZeroes; + /// # use zerocopy_derive::*; + /// # + /// #[derive(FromZeroes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header: PacketHeader = FromZeroes::new_zeroed(); + /// + /// assert_eq!(header.src_port, [0, 0]); + /// assert_eq!(header.dst_port, [0, 0]); + /// assert_eq!(header.length, [0, 0]); + /// assert_eq!(header.checksum, [0, 0]); + /// ``` + #[inline(always)] + fn new_zeroed() -> Self + where + Self: Sized, + { + // SAFETY: `FromZeroes` says that the all-zeroes bit pattern is legal. + unsafe { mem::zeroed() } + } + + /// Creates a `Box` from zeroed bytes. + /// + /// This function is useful for allocating large values on the heap and + /// zero-initializing them, without ever creating a temporary instance of + /// `Self` on the stack. For example, `<[u8; 1048576]>::new_box_zeroed()` + /// will allocate `[u8; 1048576]` directly on the heap; it does not require + /// storing `[u8; 1048576]` in a temporary variable on the stack. + /// + /// On systems that use a heap implementation that supports allocating from + /// pre-zeroed memory, using `new_box_zeroed` (or related functions) may + /// have performance benefits. + /// + /// Note that `Box` can be converted to `Arc` and other + /// container types without reallocation. + /// + /// # Panics + /// + /// Panics if allocation of `size_of::()` bytes fails. + #[cfg(feature = "alloc")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] + #[inline] + fn new_box_zeroed() -> Box + where + Self: Sized, + { + // If `T` is a ZST, then return a proper boxed instance of it. There is + // no allocation, but `Box` does require a correct dangling pointer. + let layout = Layout::new::(); + if layout.size() == 0 { + return Box::new(Self::new_zeroed()); + } + + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::() }; + if ptr.is_null() { + alloc::alloc::handle_alloc_error(layout); + } + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + Box::from_raw(ptr) + } + } + + /// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes. + /// + /// This function is useful for allocating large values of `[Self]` on the + /// heap and zero-initializing them, without ever creating a temporary + /// instance of `[Self; _]` on the stack. For example, + /// `u8::new_box_slice_zeroed(1048576)` will allocate the slice directly on + /// the heap; it does not require storing the slice on the stack. + /// + /// On systems that use a heap implementation that supports allocating from + /// pre-zeroed memory, using `new_box_slice_zeroed` may have performance + /// benefits. + /// + /// If `Self` is a zero-sized type, then this function will return a + /// `Box<[Self]>` that has the correct `len`. Such a box cannot contain any + /// actual information, but its `len()` property will report the correct + /// value. + /// + /// # Panics + /// + /// * Panics if `size_of::() * len` overflows. + /// * Panics if allocation of `size_of::() * len` bytes fails. + #[cfg(feature = "alloc")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] + #[inline] + fn new_box_slice_zeroed(len: usize) -> Box<[Self]> + where + Self: Sized, + { + let size = mem::size_of::() + .checked_mul(len) + .expect("mem::size_of::() * len overflows `usize`"); + let align = mem::align_of::(); + // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a + // bug in which sufficiently-large allocations (those which, when + // rounded up to the alignment, overflow `isize`) are not rejected, + // which can cause undefined behavior. See #64 for details. + // + // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion. + #[allow(clippy::as_conversions)] + let max_alloc = (isize::MAX as usize).saturating_sub(align); + assert!(size <= max_alloc); + // TODO(https://github.com/rust-lang/rust/issues/55724): Use + // `Layout::repeat` once it's stabilized. + let layout = + Layout::from_size_align(size, align).expect("total allocation size overflows `isize`"); + + let ptr = if layout.size() != 0 { + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::() }; + if ptr.is_null() { + alloc::alloc::handle_alloc_error(layout); + } + ptr + } else { + // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` + // is zero, but it does require a non-null dangling pointer for its + // allocation. + NonNull::::dangling().as_ptr() + }; + + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + Box::from_raw(slice::from_raw_parts_mut(ptr, len)) + } + } + + /// Creates a `Vec` from zeroed bytes. + /// + /// This function is useful for allocating large values of `Vec`s and + /// zero-initializing them, without ever creating a temporary instance of + /// `[Self; _]` (or many temporary instances of `Self`) on the stack. For + /// example, `u8::new_vec_zeroed(1048576)` will allocate directly on the + /// heap; it does not require storing intermediate values on the stack. + /// + /// On systems that use a heap implementation that supports allocating from + /// pre-zeroed memory, using `new_vec_zeroed` may have performance benefits. + /// + /// If `Self` is a zero-sized type, then this function will return a + /// `Vec` that has the correct `len`. Such a `Vec` cannot contain any + /// actual information, but its `len()` property will report the correct + /// value. + /// + /// # Panics + /// + /// * Panics if `size_of::() * len` overflows. + /// * Panics if allocation of `size_of::() * len` bytes fails. + #[cfg(feature = "alloc")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "new_vec_zeroed")))] + #[inline(always)] + fn new_vec_zeroed(len: usize) -> Vec + where + Self: Sized, + { + Self::new_box_slice_zeroed(len).into() + } +} + +/// Analyzes whether a type is [`FromBytes`]. +/// +/// This derive analyzes, at compile time, whether the annotated type satisfies +/// the [safety conditions] of `FromBytes` and implements `FromBytes` if it is +/// sound to do so. This derive can be applied to structs, enums, and unions; +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::{FromBytes, FromZeroes}; +/// #[derive(FromZeroes, FromBytes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, +/// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, +/// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, +/// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, +/// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, +/// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, +/// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, +/// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, +/// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, +/// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, +/// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, +/// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, +/// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, +/// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, +/// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, +/// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, +/// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, +/// # VFF, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// [safety conditions]: trait@FromBytes#safety +/// +/// # Analysis +/// +/// *This section describes, roughly, the analysis performed by this derive to +/// determine whether it is sound to implement `FromBytes` for a given type. +/// Unless you are modifying the implementation of this derive, or attempting to +/// manually implement `FromBytes` for a type yourself, you don't need to read +/// this section.* +/// +/// If a type has the following properties, then this derive can implement +/// `FromBytes` for that type: +/// +/// - If the type is a struct, all of its fields must be `FromBytes`. +/// - If the type is an enum: +/// - It must be a C-like enum (meaning that all variants have no fields). +/// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, +/// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). +/// - The maximum number of discriminants must be used (so that every possible +/// bit pattern is a valid one). Be very careful when using the `C`, +/// `usize`, or `isize` representations, as their size is +/// platform-dependent. +/// - The type must not contain any [`UnsafeCell`]s (this is required in order +/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of +/// memory). The type may contain references or pointers to `UnsafeCell`s so +/// long as those values can themselves be initialized from zeroes +/// (`FromBytes` is not currently implemented for, e.g., `Option<*const +/// UnsafeCell<_>>`, but it could be one day). +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell +/// +/// This analysis is subject to change. Unsafe code may *only* rely on the +/// documented [safety conditions] of `FromBytes`, and must *not* rely on the +/// implementation details of this derive. +/// +/// ## Why isn't an explicit representation required for structs? +/// +/// Neither this derive, nor the [safety conditions] of `FromBytes`, requires +/// that structs are marked with `#[repr(C)]`. +/// +/// Per the [Rust reference](reference), +/// +/// > The representation of a type can change the padding between fields, but +/// does not change the layout of the fields themselves. +/// +/// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations +/// +/// Since the layout of structs only consists of padding bytes and field bytes, +/// a struct is soundly `FromBytes` if: +/// 1. its padding is soundly `FromBytes`, and +/// 2. its fields are soundly `FromBytes`. +/// +/// The answer to the first question is always yes: padding bytes do not have +/// any validity constraints. A [discussion] of this question in the Unsafe Code +/// Guidelines Working Group concluded that it would be virtually unimaginable +/// for future versions of rustc to add validity constraints to padding bytes. +/// +/// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 +/// +/// Whether a struct is soundly `FromBytes` therefore solely depends on whether +/// its fields are `FromBytes`. +// TODO(#146): Document why we don't require an enum to have an explicit `repr` +// attribute. +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::FromBytes; + +/// Types for which any bit pattern is valid. +/// +/// Any memory region of the appropriate length which contains initialized bytes +/// can be viewed as any `FromBytes` type with no runtime overhead. This is +/// useful for efficiently parsing bytes as structured data. +/// +/// # Implementation +/// +/// **Do not implement this trait yourself!** Instead, use +/// [`#[derive(FromBytes)]`][derive] (requires the `derive` Cargo feature); +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::{FromBytes, FromZeroes}; +/// #[derive(FromZeroes, FromBytes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, +/// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, +/// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, +/// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, +/// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, +/// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, +/// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, +/// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, +/// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, +/// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, +/// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, +/// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, +/// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, +/// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, +/// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, +/// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, +/// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, +/// # VFF, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// This derive performs a sophisticated, compile-time safety analysis to +/// determine whether a type is `FromBytes`. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: FromBytes`, and +/// what unsafe code may assume of such types. If you don't plan on implementing +/// `FromBytes` manually, and you don't plan on writing unsafe code that +/// operates on `FromBytes` types, then you don't need to read this section.* +/// +/// If `T: FromBytes`, then unsafe code may assume that: +/// - It is sound to treat any initialized sequence of bytes of length +/// `size_of::()` as a `T`. +/// - Given `b: &[u8]` where `b.len() == size_of::()`, `b` is aligned to +/// `align_of::()` it is sound to construct a `t: &T` at the same address +/// as `b`, and it is sound for both `b` and `t` to be live at the same time. +/// +/// If a type is marked as `FromBytes` which violates this contract, it may +/// cause undefined behavior. +/// +/// `#[derive(FromBytes)]` only permits [types which satisfy these +/// requirements][derive-analysis]. +/// +#[cfg_attr( + feature = "derive", + doc = "[derive]: zerocopy_derive::FromBytes", + doc = "[derive-analysis]: zerocopy_derive::FromBytes#analysis" +)] +#[cfg_attr( + not(feature = "derive"), + doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html"), + doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html#analysis"), +)] +pub unsafe trait FromBytes: FromZeroes { + // The `Self: Sized` bound makes it so that `FromBytes` is still object + // safe. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + /// Interprets the given `bytes` as a `&Self` without copying. + /// + /// If `bytes.len() != size_of::()` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These bytes encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice(); + /// + /// let header = PacketHeader::ref_from(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn ref_from(bytes: &[u8]) -> Option<&Self> + where + Self: Sized, + { + Ref::<&[u8], Self>::new(bytes).map(Ref::into_ref) + } + + /// Interprets the prefix of the given `bytes` as a `&Self` without copying. + /// + /// `ref_from_prefix` returns a reference to the first `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or `bytes` is not + /// aligned to `align_of::()`, this returns `None`. + /// + /// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use + /// [`Ref::into_ref`] to get a `&Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let header = PacketHeader::ref_from_prefix(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn ref_from_prefix(bytes: &[u8]) -> Option<&Self> + where + Self: Sized, + { + Ref::<&[u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_ref()) + } + + /// Interprets the suffix of the given `bytes` as a `&Self` without copying. + /// + /// `ref_from_suffix` returns a reference to the last `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or the suffix of + /// `bytes` is not aligned to `align_of::()`, this returns `None`. + /// + /// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then, use + /// [`Ref::into_ref`] to get a `&Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketTrailer { + /// frame_check_sequence: [u8; 4], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketTrailer`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let trailer = PacketTrailer::ref_from_suffix(bytes).unwrap(); + /// + /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); + /// ``` + #[inline] + fn ref_from_suffix(bytes: &[u8]) -> Option<&Self> + where + Self: Sized, + { + Ref::<&[u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_ref()) + } + + /// Interprets the given `bytes` as a `&mut Self` without copying. + /// + /// If `bytes.len() != size_of::()` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These bytes encode a `PacketHeader`. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; + /// + /// let header = PacketHeader::mut_from(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// + /// header.checksum = [0, 0]; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0]); + /// ``` + #[inline] + fn mut_from(bytes: &mut [u8]) -> Option<&mut Self> + where + Self: Sized + AsBytes, + { + Ref::<&mut [u8], Self>::new(bytes).map(Ref::into_mut) + } + + /// Interprets the prefix of the given `bytes` as a `&mut Self` without + /// copying. + /// + /// `mut_from_prefix` returns a reference to the first `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or `bytes` is not + /// aligned to `align_of::()`, this returns `None`. + /// + /// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use + /// [`Ref::into_mut`] to get a `&mut Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketHeader`. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let header = PacketHeader::mut_from_prefix(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// + /// header.checksum = [0, 0]; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 8, 9]); + /// ``` + #[inline] + fn mut_from_prefix(bytes: &mut [u8]) -> Option<&mut Self> + where + Self: Sized + AsBytes, + { + Ref::<&mut [u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_mut()) + } + + /// Interprets the suffix of the given `bytes` as a `&mut Self` without copying. + /// + /// `mut_from_suffix` returns a reference to the last `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or the suffix of + /// `bytes` is not aligned to `align_of::()`, this returns `None`. + /// + /// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then, + /// use [`Ref::into_mut`] to get a `&mut Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketTrailer { + /// frame_check_sequence: [u8; 4], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketTrailer`. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let trailer = PacketTrailer::mut_from_suffix(bytes).unwrap(); + /// + /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); + /// + /// trailer.frame_check_sequence = [0, 0, 0, 0]; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]); + /// ``` + #[inline] + fn mut_from_suffix(bytes: &mut [u8]) -> Option<&mut Self> + where + Self: Sized + AsBytes, + { + Ref::<&mut [u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_mut()) + } + + /// Interprets the given `bytes` as a `&[Self]` without copying. + /// + /// If `bytes.len() % size_of::() != 0` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// If you need to convert a specific number of slice elements, see + /// [`slice_from_prefix`](FromBytes::slice_from_prefix) or + /// [`slice_from_suffix`](FromBytes::slice_from_suffix). + /// + /// # Panics + /// + /// If `Self` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These bytes encode two `Pixel`s. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice(); + /// + /// let pixels = Pixel::slice_from(bytes).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// ``` + #[inline] + fn slice_from(bytes: &[u8]) -> Option<&[Self]> + where + Self: Sized, + { + Ref::<_, [Self]>::new_slice(bytes).map(|r| r.into_slice()) + } + + /// Interprets the prefix of the given `bytes` as a `&[Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the remaining bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let (pixels, rest) = Pixel::slice_from_prefix(bytes, 2).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// + /// assert_eq!(rest, &[8, 9]); + /// ``` + #[inline] + fn slice_from_prefix(bytes: &[u8], count: usize) -> Option<(&[Self], &[u8])> + where + Self: Sized, + { + Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_slice(), b)) + } + + /// Interprets the suffix of the given `bytes` as a `&[Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the preceding bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let (rest, pixels) = Pixel::slice_from_suffix(bytes, 2).unwrap(); + /// + /// assert_eq!(rest, &[0, 1]); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 2, g: 3, b: 4, a: 5 }, + /// Pixel { r: 6, g: 7, b: 8, a: 9 }, + /// ]); + /// ``` + #[inline] + fn slice_from_suffix(bytes: &[u8], count: usize) -> Option<(&[u8], &[Self])> + where + Self: Sized, + { + Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_slice())) + } + + /// Interprets the given `bytes` as a `&mut [Self]` without copying. + /// + /// If `bytes.len() % size_of::() != 0` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// If you need to convert a specific number of slice elements, see + /// [`mut_slice_from_prefix`](FromBytes::mut_slice_from_prefix) or + /// [`mut_slice_from_suffix`](FromBytes::mut_slice_from_suffix). + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These bytes encode two `Pixel`s. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; + /// + /// let pixels = Pixel::mut_slice_from(bytes).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// + /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0]); + /// ``` + #[inline] + fn mut_slice_from(bytes: &mut [u8]) -> Option<&mut [Self]> + where + Self: Sized + AsBytes, + { + Ref::<_, [Self]>::new_slice(bytes).map(|r| r.into_mut_slice()) + } + + /// Interprets the prefix of the given `bytes` as a `&mut [Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the remaining bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let (pixels, rest) = Pixel::mut_slice_from_prefix(bytes, 2).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// + /// assert_eq!(rest, &[8, 9]); + /// + /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 8, 9]); + /// ``` + #[inline] + fn mut_slice_from_prefix(bytes: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])> + where + Self: Sized + AsBytes, + { + Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_mut_slice(), b)) + } + + /// Interprets the suffix of the given `bytes` as a `&mut [Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the preceding bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let (rest, pixels) = Pixel::mut_slice_from_suffix(bytes, 2).unwrap(); + /// + /// assert_eq!(rest, &[0, 1]); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 2, g: 3, b: 4, a: 5 }, + /// Pixel { r: 6, g: 7, b: 8, a: 9 }, + /// ]); + /// + /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]); + /// ``` + #[inline] + fn mut_slice_from_suffix(bytes: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])> + where + Self: Sized + AsBytes, + { + Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_mut_slice())) + } + + /// Reads a copy of `Self` from `bytes`. + /// + /// If `bytes.len() != size_of::()`, `read_from` returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These bytes encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice(); + /// + /// let header = PacketHeader::read_from(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn read_from(bytes: &[u8]) -> Option + where + Self: Sized, + { + Ref::<_, Unalign>::new_unaligned(bytes).map(|r| r.read().into_inner()) + } + + /// Reads a copy of `Self` from the prefix of `bytes`. + /// + /// `read_from_prefix` reads a `Self` from the first `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()`, it returns + /// `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let header = PacketHeader::read_from_prefix(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn read_from_prefix(bytes: &[u8]) -> Option + where + Self: Sized, + { + Ref::<_, Unalign>::new_unaligned_from_prefix(bytes) + .map(|(r, _)| r.read().into_inner()) + } + + /// Reads a copy of `Self` from the suffix of `bytes`. + /// + /// `read_from_suffix` reads a `Self` from the last `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()`, it returns + /// `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketTrailer { + /// frame_check_sequence: [u8; 4], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketTrailer`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let trailer = PacketTrailer::read_from_suffix(bytes).unwrap(); + /// + /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); + /// ``` + #[inline] + fn read_from_suffix(bytes: &[u8]) -> Option + where + Self: Sized, + { + Ref::<_, Unalign>::new_unaligned_from_suffix(bytes) + .map(|(_, r)| r.read().into_inner()) + } +} + +/// Analyzes whether a type is [`AsBytes`]. +/// +/// This derive analyzes, at compile time, whether the annotated type satisfies +/// the [safety conditions] of `AsBytes` and implements `AsBytes` if it is +/// sound to do so. This derive can be applied to structs, enums, and unions; +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::{AsBytes}; +/// #[derive(AsBytes)] +/// #[repr(C)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(C)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// [safety conditions]: trait@AsBytes#safety +/// +/// # Error Messages +/// +/// Due to the way that the custom derive for `AsBytes` is implemented, you may +/// get an error like this: +/// +/// ```text +/// error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied +/// --> lib.rs:23:10 +/// | +/// 1 | #[derive(AsBytes)] +/// | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` +/// | +/// = help: the trait `ShouldBe` is implemented for `HasPadding` +/// ``` +/// +/// This error indicates that the type being annotated has padding bytes, which +/// is illegal for `AsBytes` types. Consider reducing the alignment of some +/// fields by using types in the [`byteorder`] module, adding explicit struct +/// fields where those padding bytes would be, or using `#[repr(packed)]`. See +/// the Rust Reference's page on [type layout] for more information +/// about type layout and padding. +/// +/// [type layout]: https://doc.rust-lang.org/reference/type-layout.html +/// +/// # Analysis +/// +/// *This section describes, roughly, the analysis performed by this derive to +/// determine whether it is sound to implement `AsBytes` for a given type. +/// Unless you are modifying the implementation of this derive, or attempting to +/// manually implement `AsBytes` for a type yourself, you don't need to read +/// this section.* +/// +/// If a type has the following properties, then this derive can implement +/// `AsBytes` for that type: +/// +/// - If the type is a struct: +/// - It must have a defined representation (`repr(C)`, `repr(transparent)`, +/// or `repr(packed)`). +/// - All of its fields must be `AsBytes`. +/// - Its layout must have no padding. This is always true for +/// `repr(transparent)` and `repr(packed)`. For `repr(C)`, see the layout +/// algorithm described in the [Rust Reference]. +/// - If the type is an enum: +/// - It must be a C-like enum (meaning that all variants have no fields). +/// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, +/// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). +/// - The type must not contain any [`UnsafeCell`]s (this is required in order +/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of +/// memory). The type may contain references or pointers to `UnsafeCell`s so +/// long as those values can themselves be initialized from zeroes (`AsBytes` +/// is not currently implemented for, e.g., `Option<&UnsafeCell<_>>`, but it +/// could be one day). +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell +/// +/// This analysis is subject to change. Unsafe code may *only* rely on the +/// documented [safety conditions] of `FromBytes`, and must *not* rely on the +/// implementation details of this derive. +/// +/// [Rust Reference]: https://doc.rust-lang.org/reference/type-layout.html +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::AsBytes; + +/// Types that can be viewed as an immutable slice of initialized bytes. +/// +/// Any `AsBytes` type can be viewed as a slice of initialized bytes of the same +/// size. This is useful for efficiently serializing structured data as raw +/// bytes. +/// +/// # Implementation +/// +/// **Do not implement this trait yourself!** Instead, use +/// [`#[derive(AsBytes)]`][derive] (requires the `derive` Cargo feature); e.g.: +/// +/// ``` +/// # use zerocopy_derive::AsBytes; +/// #[derive(AsBytes)] +/// #[repr(C)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant0, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(C)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// This derive performs a sophisticated, compile-time safety analysis to +/// determine whether a type is `AsBytes`. See the [derive +/// documentation][derive] for guidance on how to interpret error messages +/// produced by the derive's analysis. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: AsBytes`, and +/// what unsafe code may assume of such types. If you don't plan on implementing +/// `AsBytes` manually, and you don't plan on writing unsafe code that +/// operates on `AsBytes` types, then you don't need to read this section.* +/// +/// If `T: AsBytes`, then unsafe code may assume that: +/// - It is sound to treat any `t: T` as an immutable `[u8]` of length +/// `size_of_val(t)`. +/// - Given `t: &T`, it is sound to construct a `b: &[u8]` where `b.len() == +/// size_of_val(t)` at the same address as `t`, and it is sound for both `b` +/// and `t` to be live at the same time. +/// +/// If a type is marked as `AsBytes` which violates this contract, it may cause +/// undefined behavior. +/// +/// `#[derive(AsBytes)]` only permits [types which satisfy these +/// requirements][derive-analysis]. +/// +#[cfg_attr( + feature = "derive", + doc = "[derive]: zerocopy_derive::AsBytes", + doc = "[derive-analysis]: zerocopy_derive::AsBytes#analysis" +)] +#[cfg_attr( + not(feature = "derive"), + doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.AsBytes.html"), + doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.AsBytes.html#analysis"), +)] +pub unsafe trait AsBytes { + // The `Self: Sized` bound makes it so that this function doesn't prevent + // `AsBytes` from being object safe. Note that other `AsBytes` methods + // prevent object safety, but those provide a benefit in exchange for object + // safety. If at some point we remove those methods, change their type + // signatures, or move them out of this trait so that `AsBytes` is object + // safe again, it's important that this function not prevent object safety. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + /// Gets the bytes of this value. + /// + /// `as_bytes` provides access to the bytes of this value as an immutable + /// byte slice. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let bytes = header.as_bytes(); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); + /// ``` + #[inline(always)] + fn as_bytes(&self) -> &[u8] { + // Note that this method does not have a `Self: Sized` bound; + // `size_of_val` works for unsized values too. + let len = mem::size_of_val(self); + let slf: *const Self = self; + + // SAFETY: + // - `slf.cast::()` is valid for reads for `len * + // mem::size_of::()` many bytes because... + // - `slf` is the same pointer as `self`, and `self` is a reference + // which points to an object whose size is `len`. Thus... + // - The entire region of `len` bytes starting at `slf` is contained + // within a single allocation. + // - `slf` is non-null. + // - `slf` is trivially aligned to `align_of::() == 1`. + // - `Self: AsBytes` ensures that all of the bytes of `slf` are + // initialized. + // - Since `slf` is derived from `self`, and `self` is an immutable + // reference, the only other references to this memory region that + // could exist are other immutable references, and those don't allow + // mutation. `AsBytes` prohibits types which contain `UnsafeCell`s, + // which are the only types for which this rule wouldn't be sufficient. + // - The total size of the resulting slice is no larger than + // `isize::MAX` because no allocation produced by safe code can be + // larger than `isize::MAX`. + // + // TODO(#429): Add references to docs and quotes. + unsafe { slice::from_raw_parts(slf.cast::(), len) } + } + + /// Gets the bytes of this value mutably. + /// + /// `as_bytes_mut` provides access to the bytes of this value as a mutable + /// byte slice. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Eq, PartialEq, Debug)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let mut header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let bytes = header.as_bytes_mut(); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); + /// + /// bytes.reverse(); + /// + /// assert_eq!(header, PacketHeader { + /// src_port: [7, 6], + /// dst_port: [5, 4], + /// length: [3, 2], + /// checksum: [1, 0], + /// }); + /// ``` + #[inline(always)] + fn as_bytes_mut(&mut self) -> &mut [u8] + where + Self: FromBytes, + { + // Note that this method does not have a `Self: Sized` bound; + // `size_of_val` works for unsized values too. + let len = mem::size_of_val(self); + let slf: *mut Self = self; + + // SAFETY: + // - `slf.cast::()` is valid for reads and writes for `len * + // mem::size_of::()` many bytes because... + // - `slf` is the same pointer as `self`, and `self` is a reference + // which points to an object whose size is `len`. Thus... + // - The entire region of `len` bytes starting at `slf` is contained + // within a single allocation. + // - `slf` is non-null. + // - `slf` is trivially aligned to `align_of::() == 1`. + // - `Self: AsBytes` ensures that all of the bytes of `slf` are + // initialized. + // - `Self: FromBytes` ensures that no write to this memory region + // could result in it containing an invalid `Self`. + // - Since `slf` is derived from `self`, and `self` is a mutable + // reference, no other references to this memory region can exist. + // - The total size of the resulting slice is no larger than + // `isize::MAX` because no allocation produced by safe code can be + // larger than `isize::MAX`. + // + // TODO(#429): Add references to docs and quotes. + unsafe { slice::from_raw_parts_mut(slf.cast::(), len) } + } + + /// Writes a copy of `self` to `bytes`. + /// + /// If `bytes.len() != size_of_val(self)`, `write_to` returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0]; + /// + /// header.write_to(&mut bytes[..]); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); + /// ``` + /// + /// If too many or too few target bytes are provided, `write_to` returns + /// `None` and leaves the target bytes unmodified: + /// + /// ``` + /// # use zerocopy::AsBytes; + /// # let header = u128::MAX; + /// let mut excessive_bytes = &mut [0u8; 128][..]; + /// + /// let write_result = header.write_to(excessive_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(excessive_bytes, [0u8; 128]); + /// ``` + #[inline] + fn write_to(&self, bytes: &mut [u8]) -> Option<()> { + if bytes.len() != mem::size_of_val(self) { + return None; + } + + bytes.copy_from_slice(self.as_bytes()); + Some(()) + } + + /// Writes a copy of `self` to the prefix of `bytes`. + /// + /// `write_to_prefix` writes `self` to the first `size_of_val(self)` bytes + /// of `bytes`. If `bytes.len() < size_of_val(self)`, it returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + /// + /// header.write_to_prefix(&mut bytes[..]); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7, 0, 0]); + /// ``` + /// + /// If insufficient target bytes are provided, `write_to_prefix` returns + /// `None` and leaves the target bytes unmodified: + /// + /// ``` + /// # use zerocopy::AsBytes; + /// # let header = u128::MAX; + /// let mut insufficent_bytes = &mut [0, 0][..]; + /// + /// let write_result = header.write_to_suffix(insufficent_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(insufficent_bytes, [0, 0]); + /// ``` + #[inline] + fn write_to_prefix(&self, bytes: &mut [u8]) -> Option<()> { + let size = mem::size_of_val(self); + bytes.get_mut(..size)?.copy_from_slice(self.as_bytes()); + Some(()) + } + + /// Writes a copy of `self` to the suffix of `bytes`. + /// + /// `write_to_suffix` writes `self` to the last `size_of_val(self)` bytes of + /// `bytes`. If `bytes.len() < size_of_val(self)`, it returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + /// + /// header.write_to_suffix(&mut bytes[..]); + /// + /// assert_eq!(bytes, [0, 0, 0, 1, 2, 3, 4, 5, 6, 7]); + /// + /// let mut insufficent_bytes = &mut [0, 0][..]; + /// + /// let write_result = header.write_to_suffix(insufficent_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(insufficent_bytes, [0, 0]); + /// ``` + /// + /// If insufficient target bytes are provided, `write_to_suffix` returns + /// `None` and leaves the target bytes unmodified: + /// + /// ``` + /// # use zerocopy::AsBytes; + /// # let header = u128::MAX; + /// let mut insufficent_bytes = &mut [0, 0][..]; + /// + /// let write_result = header.write_to_suffix(insufficent_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(insufficent_bytes, [0, 0]); + /// ``` + #[inline] + fn write_to_suffix(&self, bytes: &mut [u8]) -> Option<()> { + let start = bytes.len().checked_sub(mem::size_of_val(self))?; + bytes + .get_mut(start..) + .expect("`start` should be in-bounds of `bytes`") + .copy_from_slice(self.as_bytes()); + Some(()) + } +} + +/// Types with no alignment requirement. +/// +/// WARNING: Do not implement this trait yourself! Instead, use +/// `#[derive(Unaligned)]` (requires the `derive` Cargo feature). +/// +/// If `T: Unaligned`, then `align_of::() == 1`. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: Unaligned`, and +/// what unsafe code may assume of such types. `#[derive(Unaligned)]` only +/// permits types which satisfy these requirements. If you don't plan on +/// implementing `Unaligned` manually, and you don't plan on writing unsafe code +/// that operates on `Unaligned` types, then you don't need to read this +/// section.* +/// +/// If `T: Unaligned`, then unsafe code may assume that it is sound to produce a +/// reference to `T` at any memory location regardless of alignment. If a type +/// is marked as `Unaligned` which violates this contract, it may cause +/// undefined behavior. +pub unsafe trait Unaligned { + // The `Self: Sized` bound makes it so that `Unaligned` is still object + // safe. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; +} + +safety_comment! { + /// SAFETY: + /// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a + /// zero-sized type to have a size of 0 and an alignment of 1." + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: There + /// is only one possible sequence of 0 bytes, and `()` is inhabited. + /// - `AsBytes`: Since `()` has size 0, it contains no padding bytes. + /// - `Unaligned`: `()` has alignment 1. + /// + /// [1] https://doc.rust-lang.org/reference/type-layout.html#tuple-layout + unsafe_impl!((): TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_unaligned!(()); +} + +safety_comment! { + /// SAFETY: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: all bit + /// patterns are valid for numeric types [1] + /// - `AsBytes`: numeric types have no padding bytes [1] + /// - `Unaligned` (`u8` and `i8` only): The reference [2] specifies the size + /// of `u8` and `i8` as 1 byte. We also know that: + /// - Alignment is >= 1 [3] + /// - Size is an integer multiple of alignment [4] + /// - The only value >= 1 for which 1 is an integer multiple is 1 + /// Therefore, the only possible alignment for `u8` and `i8` is 1. + /// + /// [1] Per https://doc.rust-lang.org/beta/reference/types/numeric.html#bit-validity: + /// + /// For every numeric type, `T`, the bit validity of `T` is equivalent to + /// the bit validity of `[u8; size_of::()]`. An uninitialized byte is + /// not a valid `u8`. + /// + /// TODO(https://github.com/rust-lang/reference/pull/1392): Once this text + /// is available on the Stable docs, cite those instead. + /// + /// [2] https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout + /// + /// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment: + /// + /// Alignment is measured in bytes, and must be at least 1. + /// + /// [4] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment: + /// + /// The size of a value is always a multiple of its alignment. + /// + /// TODO(#278): Once we've updated the trait docs to refer to `u8`s rather + /// than bits or bytes, update this comment, especially the reference to + /// [1]. + unsafe_impl!(u8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + unsafe_impl!(i8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_unaligned!(u8, i8); + unsafe_impl!(u16: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i16: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(u32: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i32: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(u64: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i64: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(u128: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i128: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(usize: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(isize: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(f32: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(f64: TryFromBytes, FromZeroes, FromBytes, AsBytes); +} + +safety_comment! { + /// SAFETY: + /// - `FromZeroes`: Valid since "[t]he value false has the bit pattern + /// 0x00" [1]. + /// - `AsBytes`: Since "the boolean type has a size and alignment of 1 each" + /// and "The value false has the bit pattern 0x00 and the value true has + /// the bit pattern 0x01" [1]. Thus, the only byte of the bool is always + /// initialized. + /// - `Unaligned`: Per the reference [1], "[a]n object with the boolean type + /// has a size and alignment of 1 each." + /// + /// [1] https://doc.rust-lang.org/reference/types/boolean.html + unsafe_impl!(bool: FromZeroes, AsBytes, Unaligned); + assert_unaligned!(bool); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut bool` and `let r = *mut u8`, `r` refers to an object + /// of the same size as that referred to by `t`. This is true because + /// `bool` and `u8` have the same size (1 byte) [1]. + /// - Since the closure takes a `&u8` argument, given a `Ptr<'a, bool>` + /// which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed that the + /// memory referenced by that `Ptr` always contains a valid `u8`. Since + /// `bool`'s single byte is always initialized, `is_bit_valid`'s + /// precondition requires that the same is true of its argument. Since + /// `u8`'s only bit validity invariant is that its single byte must be + /// initialized, this memory is guaranteed to contain a valid `u8`. + /// - The alignment of `bool` is equal to the alignment of `u8`. [1] [2] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `bool`. We only return true if the + /// `u8` value is 0 or 1, and both of these are valid values for `bool`. + /// [3] + /// + /// [1] Per https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout: + /// + /// The size of most primitives is given in this table. + /// + /// | Type | `size_of::() ` | + /// |-----------|----------------------| + /// | `bool` | 1 | + /// | `u8`/`i8` | 1 | + /// + /// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment: + /// + /// The size of a value is always a multiple of its alignment. + /// + /// [3] Per https://doc.rust-lang.org/reference/types/boolean.html: + /// + /// The value false has the bit pattern 0x00 and the value true has the + /// bit pattern 0x01. + unsafe_impl!(bool: TryFromBytes; |byte: &u8| *byte < 2); +} +safety_comment! { + /// SAFETY: + /// - `FromZeroes`: Per reference [1], "[a] value of type char is a Unicode + /// scalar value (i.e. a code point that is not a surrogate), represented + /// as a 32-bit unsigned word in the 0x0000 to 0xD7FF or 0xE000 to + /// 0x10FFFF range" which contains 0x0000. + /// - `AsBytes`: `char` is per reference [1] "represented as a 32-bit + /// unsigned word" (`u32`) which is `AsBytes`. Note that unlike `u32`, not + /// all bit patterns are valid for `char`. + /// + /// [1] https://doc.rust-lang.org/reference/types/textual.html + unsafe_impl!(char: FromZeroes, AsBytes); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut char` and `let r = *mut u32`, `r` refers to an object + /// of the same size as that referred to by `t`. This is true because + /// `char` and `u32` have the same size [1]. + /// - Since the closure takes a `&u32` argument, given a `Ptr<'a, char>` + /// which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed that the + /// memory referenced by that `Ptr` always contains a valid `u32`. Since + /// `char`'s bytes are always initialized [2], `is_bit_valid`'s + /// precondition requires that the same is true of its argument. Since + /// `u32`'s only bit validity invariant is that its bytes must be + /// initialized, this memory is guaranteed to contain a valid `u32`. + /// - The alignment of `char` is equal to the alignment of `u32`. [1] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `char`. `char::from_u32` guarantees + /// that it returns `None` if its input is not a valid `char`. [3] + /// + /// [1] Per https://doc.rust-lang.org/nightly/reference/types/textual.html#layout-and-bit-validity: + /// + /// `char` is guaranteed to have the same size and alignment as `u32` on + /// all platforms. + /// + /// [2] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32: + /// + /// Every byte of a `char` is guaranteed to be initialized. + /// + /// [3] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32: + /// + /// `from_u32()` will return `None` if the input is not a valid value for + /// a `char`. + unsafe_impl!(char: TryFromBytes; |candidate: &u32| char::from_u32(*candidate).is_some()); +} +safety_comment! { + /// SAFETY: + /// - `FromZeroes`, `AsBytes`, `Unaligned`: Per the reference [1], `str` + /// has the same layout as `[u8]`, and `[u8]` is `FromZeroes`, `AsBytes`, + /// and `Unaligned`. + /// + /// Note that we don't `assert_unaligned!(str)` because `assert_unaligned!` + /// uses `align_of`, which only works for `Sized` types. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] https://doc.rust-lang.org/reference/type-layout.html#str-layout + unsafe_impl!(str: FromZeroes, AsBytes, Unaligned); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut str` and `let r = *mut [u8]`, `r` refers to an object + /// of the same size as that referred to by `t`. This is true because + /// `str` and `[u8]` have the same representation. [1] + /// - Since the closure takes a `&[u8]` argument, given a `Ptr<'a, str>` + /// which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed that the + /// memory referenced by that `Ptr` always contains a valid `[u8]`. + /// Since `str`'s bytes are always initialized [1], `is_bit_valid`'s + /// precondition requires that the same is true of its argument. Since + /// `[u8]`'s only bit validity invariant is that its bytes must be + /// initialized, this memory is guaranteed to contain a valid `[u8]`. + /// - The alignment of `str` is equal to the alignment of `[u8]`. [1] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `str`. `str::from_utf8` guarantees that + /// it returns `Err` if its input is not a valid `str`. [2] + /// + /// [1] Per https://doc.rust-lang.org/reference/types/textual.html: + /// + /// A value of type `str` is represented the same was as `[u8]`. + /// + /// [2] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors: + /// + /// Returns `Err` if the slice is not UTF-8. + unsafe_impl!(str: TryFromBytes; |candidate: &[u8]| core::str::from_utf8(candidate).is_ok()); +} + +safety_comment! { + // `NonZeroXxx` is `AsBytes`, but not `FromZeroes` or `FromBytes`. + // + /// SAFETY: + /// - `AsBytes`: `NonZeroXxx` has the same layout as its associated + /// primitive. Since it is the same size, this guarantees it has no + /// padding - integers have no padding, and there's no room for padding + /// if it can represent all of the same values except 0. + /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that + /// `Option` and `Option` both have size 1. [1] [2] + /// This is worded in a way that makes it unclear whether it's meant as a + /// guarantee, but given the purpose of those types, it's virtually + /// unthinkable that that would ever change. `Option` cannot be smaller + /// than its contained type, which implies that, and `NonZeroX8` are of + /// size 1 or 0. `NonZeroX8` can represent multiple states, so they cannot + /// be 0 bytes, which means that they must be 1 byte. The only valid + /// alignment for a 1-byte type is 1. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html + /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html + /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation + /// that layout is the same as primitive layout. + unsafe_impl!(NonZeroU8: AsBytes, Unaligned); + unsafe_impl!(NonZeroI8: AsBytes, Unaligned); + assert_unaligned!(NonZeroU8, NonZeroI8); + unsafe_impl!(NonZeroU16: AsBytes); + unsafe_impl!(NonZeroI16: AsBytes); + unsafe_impl!(NonZeroU32: AsBytes); + unsafe_impl!(NonZeroI32: AsBytes); + unsafe_impl!(NonZeroU64: AsBytes); + unsafe_impl!(NonZeroI64: AsBytes); + unsafe_impl!(NonZeroU128: AsBytes); + unsafe_impl!(NonZeroI128: AsBytes); + unsafe_impl!(NonZeroUsize: AsBytes); + unsafe_impl!(NonZeroIsize: AsBytes); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut NonZeroXxx` and `let r = *mut xxx`, `r` refers to an + /// object of the same size as that referred to by `t`. This is true + /// because `NonZeroXxx` and `xxx` have the same size. [1] + /// - Since the closure takes a `&xxx` argument, given a `Ptr<'a, + /// NonZeroXxx>` which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed + /// that the memory referenced by that `Ptr` always contains a valid + /// `xxx`. Since `NonZeroXxx`'s bytes are always initialized [1], + /// `is_bit_valid`'s precondition requires that the same is true of its + /// argument. Since `xxx`'s only bit validity invariant is that its + /// bytes must be initialized, this memory is guaranteed to contain a + /// valid `xxx`. + /// - The alignment of `NonZeroXxx` is equal to the alignment of `xxx`. + /// [1] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `NonZeroXxx`. The only `xxx` + /// which is not also a valid `NonZeroXxx` is 0. [1] + /// + /// [1] Per https://doc.rust-lang.org/core/num/struct.NonZeroU16.html: + /// + /// `NonZeroU16` is guaranteed to have the same layout and bit validity as + /// `u16` with the exception that `0` is not a valid instance. + unsafe_impl!(NonZeroU8: TryFromBytes; |n: &u8| *n != 0); + unsafe_impl!(NonZeroI8: TryFromBytes; |n: &i8| *n != 0); + unsafe_impl!(NonZeroU16: TryFromBytes; |n: &u16| *n != 0); + unsafe_impl!(NonZeroI16: TryFromBytes; |n: &i16| *n != 0); + unsafe_impl!(NonZeroU32: TryFromBytes; |n: &u32| *n != 0); + unsafe_impl!(NonZeroI32: TryFromBytes; |n: &i32| *n != 0); + unsafe_impl!(NonZeroU64: TryFromBytes; |n: &u64| *n != 0); + unsafe_impl!(NonZeroI64: TryFromBytes; |n: &i64| *n != 0); + unsafe_impl!(NonZeroU128: TryFromBytes; |n: &u128| *n != 0); + unsafe_impl!(NonZeroI128: TryFromBytes; |n: &i128| *n != 0); + unsafe_impl!(NonZeroUsize: TryFromBytes; |n: &usize| *n != 0); + unsafe_impl!(NonZeroIsize: TryFromBytes; |n: &isize| *n != 0); +} +safety_comment! { + /// SAFETY: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`, + /// `AsBytes`: The Rust compiler reuses `0` value to represent `None`, so + /// `size_of::>() == size_of::()`; see + /// `NonZeroXxx` documentation. + /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that + /// `Option` and `Option` both have size 1. [1] [2] + /// This is worded in a way that makes it unclear whether it's meant as a + /// guarantee, but given the purpose of those types, it's virtually + /// unthinkable that that would ever change. The only valid alignment for + /// a 1-byte type is 1. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html + /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html + /// + /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation + /// for layout guarantees. + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_unaligned!(Option, Option); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); +} + +safety_comment! { + /// SAFETY: + /// The following types can be transmuted from `[0u8; size_of::()]`. [1] + /// None of them contain `UnsafeCell`s, and so they all soundly implement + /// `FromZeroes`. + /// + /// [1] Per + /// https://doc.rust-lang.org/nightly/core/option/index.html#representation: + /// + /// Rust guarantees to optimize the following types `T` such that + /// [`Option`] has the same size and alignment as `T`. In some of these + /// cases, Rust further guarantees that `transmute::<_, Option>([0u8; + /// size_of::()])` is sound and produces `Option::::None`. These + /// cases are identified by the second column: + /// + /// | `T` | `transmute::<_, Option>([0u8; size_of::()])` sound? | + /// |-----------------------|-----------------------------------------------------------| + /// | [`Box`] | when `U: Sized` | + /// | `&U` | when `U: Sized` | + /// | `&mut U` | when `U: Sized` | + /// | [`ptr::NonNull`] | when `U: Sized` | + /// | `fn`, `extern "C" fn` | always | + /// + /// TODO(#429), TODO(https://github.com/rust-lang/rust/pull/115333): Cite + /// the Stable docs once they're available. + #[cfg(feature = "alloc")] + unsafe_impl!( + #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] + T => FromZeroes for Option> + ); + unsafe_impl!(T => FromZeroes for Option<&'_ T>); + unsafe_impl!(T => FromZeroes for Option<&'_ mut T>); + unsafe_impl!(T => FromZeroes for Option>); + unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_fn!(...)); + unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_extern_c_fn!(...)); +} + +safety_comment! { + /// SAFETY: + /// Per reference [1]: + /// "For all T, the following are guaranteed: + /// size_of::>() == 0 + /// align_of::>() == 1". + /// This gives: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: There + /// is only one possible sequence of 0 bytes, and `PhantomData` is + /// inhabited. + /// - `AsBytes`: Since `PhantomData` has size 0, it contains no padding + /// bytes. + /// - `Unaligned`: Per the preceding reference, `PhantomData` has alignment + /// 1. + /// + /// [1] https://doc.rust-lang.org/std/marker/struct.PhantomData.html#layout-1 + unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData); + unsafe_impl!(T: ?Sized => FromZeroes for PhantomData); + unsafe_impl!(T: ?Sized => FromBytes for PhantomData); + unsafe_impl!(T: ?Sized => AsBytes for PhantomData); + unsafe_impl!(T: ?Sized => Unaligned for PhantomData); + assert_unaligned!(PhantomData<()>, PhantomData, PhantomData); +} +safety_comment! { + /// SAFETY: + /// `Wrapping` is guaranteed by its docs [1] to have the same layout and + /// bit validity as `T`. Also, `Wrapping` is `#[repr(transparent)]`, and + /// has a single field, which is `pub`. Per the reference [2], this means + /// that the `#[repr(transparent)]` attribute is "considered part of the + /// public ABI". + /// + /// - `TryFromBytes`: The safety requirements for `unsafe_impl!` with an + /// `is_bit_valid` closure: + /// - Given `t: *mut Wrapping` and `let r = *mut T`, `r` refers to an + /// object of the same size as that referred to by `t`. This is true + /// because `Wrapping` and `T` have the same layout + /// - The alignment of `Wrapping` is equal to the alignment of `T`. + /// - The impl must only return `true` for its argument if the original + /// `Ptr>` refers to a valid `Wrapping`. Since + /// `Wrapping` has the same bit validity as `T`, and since our impl + /// just calls `T::is_bit_valid`, our impl returns `true` exactly when + /// its argument contains a valid `Wrapping`. + /// - `FromBytes`: Since `Wrapping` has the same bit validity as `T`, if + /// `T: FromBytes`, then all initialized byte sequences are valid + /// instances of `Wrapping`. Similarly, if `T: FromBytes`, then + /// `Wrapping` doesn't contain any `UnsafeCell`s. Thus, `impl FromBytes + /// for Wrapping where T: FromBytes` is a sound impl. + /// - `AsBytes`: Since `Wrapping` has the same bit validity as `T`, if + /// `T: AsBytes`, then all valid instances of `Wrapping` have all of + /// their bytes initialized. Similarly, if `T: AsBytes`, then + /// `Wrapping` doesn't contain any `UnsafeCell`s. Thus, `impl AsBytes + /// for Wrapping where T: AsBytes` is a valid impl. + /// - `Unaligned`: Since `Wrapping` has the same layout as `T`, + /// `Wrapping` has alignment 1 exactly when `T` does. + /// + /// [1] Per https://doc.rust-lang.org/core/num/struct.NonZeroU16.html: + /// + /// `NonZeroU16` is guaranteed to have the same layout and bit validity as + /// `u16` with the exception that `0` is not a valid instance. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] TODO(https://doc.rust-lang.org/nightly/core/num/struct.Wrapping.html#layout-1): + /// Reference this documentation once it's available on stable. + /// + /// [2] https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent + unsafe_impl!(T: TryFromBytes => TryFromBytes for Wrapping; |candidate: Ptr| { + // SAFETY: + // - Since `T` and `Wrapping` have the same layout and bit validity + // and contain the same fields, `T` contains `UnsafeCell`s exactly + // where `Wrapping` does. Thus, all memory and `UnsafeCell` + // preconditions of `T::is_bit_valid` hold exactly when the same + // preconditions for `Wrapping::is_bit_valid` hold. + // - By the same token, since `candidate` is guaranteed to have its + // bytes initialized where there are always initialized bytes in + // `Wrapping`, the same is true for `T`. + unsafe { T::is_bit_valid(candidate) } + }); + unsafe_impl!(T: FromZeroes => FromZeroes for Wrapping); + unsafe_impl!(T: FromBytes => FromBytes for Wrapping); + unsafe_impl!(T: AsBytes => AsBytes for Wrapping); + unsafe_impl!(T: Unaligned => Unaligned for Wrapping); + assert_unaligned!(Wrapping<()>, Wrapping); +} +safety_comment! { + // `MaybeUninit` is `FromZeroes` and `FromBytes`, but never `AsBytes` + // since it may contain uninitialized bytes. + // + /// SAFETY: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: + /// `MaybeUninit` has no restrictions on its contents. Unfortunately, + /// in addition to bit validity, `TryFromBytes`, `FromZeroes` and + /// `FromBytes` also require that implementers contain no `UnsafeCell`s. + /// Thus, we require `T: Trait` in order to ensure that `T` - and thus + /// `MaybeUninit` - contains to `UnsafeCell`s. Thus, requiring that `T` + /// implement each of these traits is sufficient. + /// - `Unaligned`: "MaybeUninit is guaranteed to have the same size, + /// alignment, and ABI as T" [1] + /// + /// [1] https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#layout-1 + /// + /// TODO(https://github.com/google/zerocopy/issues/251): If we split + /// `FromBytes` and `RefFromBytes`, or if we introduce a separate + /// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes` + /// and `FromBytes`. + unsafe_impl!(T: TryFromBytes => TryFromBytes for MaybeUninit); + unsafe_impl!(T: FromZeroes => FromZeroes for MaybeUninit); + unsafe_impl!(T: FromBytes => FromBytes for MaybeUninit); + unsafe_impl!(T: Unaligned => Unaligned for MaybeUninit); + assert_unaligned!(MaybeUninit<()>, MaybeUninit); +} +safety_comment! { + /// SAFETY: + /// `ManuallyDrop` has the same layout and bit validity as `T` [1], and + /// accessing the inner value is safe (meaning that it's unsound to leave + /// the inner value uninitialized while exposing the `ManuallyDrop` to safe + /// code). + /// - `FromZeroes`, `FromBytes`: Since it has the same layout as `T`, any + /// valid `T` is a valid `ManuallyDrop`. If `T: FromZeroes`, a sequence + /// of zero bytes is a valid `T`, and thus a valid `ManuallyDrop`. If + /// `T: FromBytes`, any sequence of bytes is a valid `T`, and thus a valid + /// `ManuallyDrop`. + /// - `AsBytes`: Since it has the same layout as `T`, and since it's unsound + /// to let safe code access a `ManuallyDrop` whose inner value is + /// uninitialized, safe code can only ever access a `ManuallyDrop` whose + /// contents are a valid `T`. Since `T: AsBytes`, this means that safe + /// code can only ever access a `ManuallyDrop` with all initialized bytes. + /// - `Unaligned`: `ManuallyDrop` has the same layout (and thus alignment) + /// as `T`, and `T: Unaligned` guarantees that that alignment is 1. + /// + /// `ManuallyDrop` is guaranteed to have the same layout and bit + /// validity as `T` + /// + /// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + /// + /// TODO(#429): + /// - Add quotes from docs. + /// - Once [1] (added in + /// https://github.com/rust-lang/rust/pull/115522) is available on stable, + /// quote the stable docs instead of the nightly docs. + unsafe_impl!(T: ?Sized + FromZeroes => FromZeroes for ManuallyDrop); + unsafe_impl!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop); + unsafe_impl!(T: ?Sized + AsBytes => AsBytes for ManuallyDrop); + unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop); + assert_unaligned!(ManuallyDrop<()>, ManuallyDrop); +} +safety_comment! { + /// SAFETY: + /// Per the reference [1]: + /// + /// An array of `[T; N]` has a size of `size_of::() * N` and the same + /// alignment of `T`. Arrays are laid out so that the zero-based `nth` + /// element of the array is offset from the start of the array by `n * + /// size_of::()` bytes. + /// + /// ... + /// + /// Slices have the same layout as the section of the array they slice. + /// + /// In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s + /// laid out back-to-back with no bytes in between. Therefore, `[T]` or `[T; + /// N]` are `TryFromBytes`, `FromZeroes`, `FromBytes`, and `AsBytes` if `T` + /// is (respectively). Furthermore, since an array/slice has "the same + /// alignment of `T`", `[T]` and `[T; N]` are `Unaligned` if `T` is. + /// + /// Note that we don't `assert_unaligned!` for slice types because + /// `assert_unaligned!` uses `align_of`, which only works for `Sized` types. + /// + /// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout + unsafe_impl!(const N: usize, T: FromZeroes => FromZeroes for [T; N]); + unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]); + unsafe_impl!(const N: usize, T: AsBytes => AsBytes for [T; N]); + unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]); + assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]); + unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c: Ptr<[T]>| { + // SAFETY: Assuming the preconditions of `is_bit_valid` are satisfied, + // so too will the postcondition: that, if `is_bit_valid(candidate)` + // returns true, `*candidate` contains a valid `Self`. Per the reference + // [1]: + // + // An array of `[T; N]` has a size of `size_of::() * N` and the + // same alignment of `T`. Arrays are laid out so that the zero-based + // `nth` element of the array is offset from the start of the array by + // `n * size_of::()` bytes. + // + // ... + // + // Slices have the same layout as the section of the array they slice. + // + // In other words, the layout of a `[T] is a sequence of `T`s laid out + // back-to-back with no bytes in between. If all elements in `candidate` + // are `is_bit_valid`, so too is `candidate`. + // + // Note that any of the below calls may panic, but it would still be + // sound even if it did. `is_bit_valid` does not promise that it will + // not panic (in fact, it explicitly warns that it's a possibility), and + // we have not violated any safety invariants that we must fix before + // returning. + c.iter().all(|elem| + // SAFETY: We uphold the safety contract of `is_bit_valid(elem)`, by + // precondition on the surrounding call to `is_bit_valid`. The + // memory referenced by `elem` is contained entirely within `c`, and + // satisfies the preconditions satisfied by `c`. By axiom, we assume + // that `Iterator:all` does not invalidate these preconditions + // (e.g., by writing to `elem`.) Since `elem` is derived from `c`, + // it is only possible for uninitialized bytes to occur in `elem` at + // the same bytes they occur within `c`. + unsafe { ::is_bit_valid(elem) } + ) + }); + unsafe_impl!(T: FromZeroes => FromZeroes for [T]); + unsafe_impl!(T: FromBytes => FromBytes for [T]); + unsafe_impl!(T: AsBytes => AsBytes for [T]); + unsafe_impl!(T: Unaligned => Unaligned for [T]); +} +safety_comment! { + /// SAFETY: + /// - `FromZeroes`: For thin pointers (note that `T: Sized`), the zero + /// pointer is considered "null". [1] No operations which require + /// provenance are legal on null pointers, so this is not a footgun. + /// + /// NOTE(#170): Implementing `FromBytes` and `AsBytes` for raw pointers + /// would be sound, but carries provenance footguns. We want to support + /// `FromBytes` and `AsBytes` for raw pointers eventually, but we are + /// holding off until we can figure out how to address those footguns. + /// + /// [1] TODO(https://github.com/rust-lang/rust/pull/116988): Cite the + /// documentation once this PR lands. + unsafe_impl!(T => FromZeroes for *const T); + unsafe_impl!(T => FromZeroes for *mut T); +} + +// SIMD support +// +// Per the Unsafe Code Guidelines Reference [1]: +// +// Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs +// containing `N` elements of type `T` where `N` is a power-of-two and the +// size and alignment requirements of `T` are equal: +// +// ```rust +// #[repr(simd)] +// struct Vector(T_0, ..., T_(N - 1)); +// ``` +// +// ... +// +// The size of `Vector` is `N * size_of::()` and its alignment is an +// implementation-defined function of `T` and `N` greater than or equal to +// `align_of::()`. +// +// ... +// +// Vector elements are laid out in source field order, enabling random access +// to vector elements by reinterpreting the vector as an array: +// +// ```rust +// union U { +// vec: Vector, +// arr: [T; N] +// } +// +// assert_eq!(size_of::>(), size_of::<[T; N]>()); +// assert!(align_of::>() >= align_of::<[T; N]>()); +// +// unsafe { +// let u = U { vec: Vector(t_0, ..., t_(N - 1)) }; +// +// assert_eq!(u.vec.0, u.arr[0]); +// // ... +// assert_eq!(u.vec.(N - 1), u.arr[N - 1]); +// } +// ``` +// +// Given this background, we can observe that: +// - The size and bit pattern requirements of a SIMD type are equivalent to the +// equivalent array type. Thus, for any SIMD type whose primitive `T` is +// `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes`, that SIMD type is +// also `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` respectively. +// - Since no upper bound is placed on the alignment, no SIMD type can be +// guaranteed to be `Unaligned`. +// +// Also per [1]: +// +// This chapter represents the consensus from issue #38. The statements in +// here are not (yet) "guaranteed" not to change until an RFC ratifies them. +// +// See issue #38 [2]. While this behavior is not technically guaranteed, the +// likelihood that the behavior will change such that SIMD types are no longer +// `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` is next to zero, as +// that would defeat the entire purpose of SIMD types. Nonetheless, we put this +// behavior behind the `simd` Cargo feature, which requires consumers to opt +// into this stability hazard. +// +// [1] https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html +// [2] https://github.com/rust-lang/unsafe-code-guidelines/issues/38 +#[cfg(feature = "simd")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "simd")))] +mod simd { + /// Defines a module which implements `TryFromBytes`, `FromZeroes`, + /// `FromBytes`, and `AsBytes` for a set of types from a module in + /// `core::arch`. + /// + /// `$arch` is both the name of the defined module and the name of the + /// module in `core::arch`, and `$typ` is the list of items from that module + /// to implement `FromZeroes`, `FromBytes`, and `AsBytes` for. + #[allow(unused_macros)] // `allow(unused_macros)` is needed because some + // target/feature combinations don't emit any impls + // and thus don't use this macro. + macro_rules! simd_arch_mod { + (#[cfg $cfg:tt] $arch:ident, $mod:ident, $($typ:ident),*) => { + #[cfg $cfg] + #[cfg_attr(doc_cfg, doc(cfg $cfg))] + mod $mod { + use core::arch::$arch::{$($typ),*}; + + use crate::*; + impl_known_layout!($($typ),*); + safety_comment! { + /// SAFETY: + /// See comment on module definition for justification. + $( unsafe_impl!($typ: TryFromBytes, FromZeroes, FromBytes, AsBytes); )* + } + } + }; + } + + #[rustfmt::skip] + const _: () = { + simd_arch_mod!( + #[cfg(target_arch = "x86")] + x86, x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "x86"))] + x86, x86_nightly, __m512bh, __m512, __m512d, __m512i + ); + simd_arch_mod!( + #[cfg(target_arch = "x86_64")] + x86_64, x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))] + x86_64, x86_64_nightly, __m512bh, __m512, __m512d, __m512i + ); + simd_arch_mod!( + #[cfg(target_arch = "wasm32")] + wasm32, wasm32, v128 + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))] + powerpc, powerpc, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] + powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long + ); + simd_arch_mod!( + #[cfg(target_arch = "aarch64")] + aarch64, aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, + int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t, + int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t, + poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t, + poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t, + uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t, + uint64x1_t, uint64x2_t + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "arm"))] + arm, arm, int8x4_t, uint8x4_t + ); + }; +} + +/// Safely transmutes a value of one type to a value of another type of the same +/// size. +/// +/// The expression `$e` must have a concrete type, `T`, which implements +/// `AsBytes`. The `transmute!` expression must also have a concrete type, `U` +/// (`U` is inferred from the calling context), and `U` must implement +/// `FromBytes`. +/// +/// Note that the `T` produced by the expression `$e` will *not* be dropped. +/// Semantically, its bits will be copied into a new value of type `U`, the +/// original `T` will be forgotten, and the value of type `U` will be returned. +/// +/// # Examples +/// +/// ``` +/// # use zerocopy::transmute; +/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; +/// +/// let two_dimensional: [[u8; 4]; 2] = transmute!(one_dimensional); +/// +/// assert_eq!(two_dimensional, [[0, 1, 2, 3], [4, 5, 6, 7]]); +/// ``` +#[macro_export] +macro_rules! transmute { + ($e:expr) => {{ + // NOTE: This must be a macro (rather than a function with trait bounds) + // because there's no way, in a generic context, to enforce that two + // types have the same size. `core::mem::transmute` uses compiler magic + // to enforce this so long as the types are concrete. + + let e = $e; + if false { + // This branch, though never taken, ensures that the type of `e` is + // `AsBytes` and that the type of this macro invocation expression + // is `FromBytes`. + + struct AssertIsAsBytes(T); + let _ = AssertIsAsBytes(e); + + struct AssertIsFromBytes(U); + #[allow(unused, unreachable_code)] + let u = AssertIsFromBytes(loop {}); + u.0 + } else { + // SAFETY: `core::mem::transmute` ensures that the type of `e` and + // the type of this macro invocation expression have the same size. + // We know this transmute is safe thanks to the `AsBytes` and + // `FromBytes` bounds enforced by the `false` branch. + // + // We use this reexport of `core::mem::transmute` because we know it + // will always be available for crates which are using the 2015 + // edition of Rust. By contrast, if we were to use + // `std::mem::transmute`, this macro would not work for such crates + // in `no_std` contexts, and if we were to use + // `core::mem::transmute`, this macro would not work in `std` + // contexts in which `core` was not manually imported. This is not a + // problem for 2018 edition crates. + unsafe { + // Clippy: It's okay to transmute a type to itself. + #[allow(clippy::useless_transmute)] + $crate::macro_util::core_reexport::mem::transmute(e) + } + } + }} +} + +/// Safely transmutes a mutable or immutable reference of one type to an +/// immutable reference of another type of the same size. +/// +/// The expression `$e` must have a concrete type, `&T` or `&mut T`, where `T: +/// Sized + AsBytes`. The `transmute_ref!` expression must also have a concrete +/// type, `&U` (`U` is inferred from the calling context), where `U: Sized + +/// FromBytes`. It must be the case that `align_of::() >= align_of::()`. +/// +/// The lifetime of the input type, `&T` or `&mut T`, must be the same as or +/// outlive the lifetime of the output type, `&U`. +/// +/// # Examples +/// +/// ``` +/// # use zerocopy::transmute_ref; +/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; +/// +/// let two_dimensional: &[[u8; 4]; 2] = transmute_ref!(&one_dimensional); +/// +/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); +/// ``` +/// +/// # Alignment increase error message +/// +/// Because of limitations on macros, the error message generated when +/// `transmute_ref!` is used to transmute from a type of lower alignment to a +/// type of higher alignment is somewhat confusing. For example, the following +/// code: +/// +/// ```compile_fail +/// const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]); +/// ``` +/// +/// ...generates the following error: +/// +/// ```text +/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types +/// --> src/lib.rs:1524:34 +/// | +/// 5 | const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]); +/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/// | +/// = note: source type: `AlignOf<[u8; 2]>` (8 bits) +/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) +/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +/// ``` +/// +/// This is saying that `max(align_of::(), align_of::()) != +/// align_of::()`, which is equivalent to `align_of::() < +/// align_of::()`. +#[macro_export] +macro_rules! transmute_ref { + ($e:expr) => {{ + // NOTE: This must be a macro (rather than a function with trait bounds) + // because there's no way, in a generic context, to enforce that two + // types have the same size or alignment. + + // Ensure that the source type is a reference or a mutable reference + // (note that mutable references are implicitly reborrowed here). + let e: &_ = $e; + + #[allow(unused, clippy::diverging_sub_expression)] + if false { + // This branch, though never taken, ensures that the type of `e` is + // `&T` where `T: 't + Sized + AsBytes`, that the type of this macro + // expression is `&U` where `U: 'u + Sized + FromBytes`, and that + // `'t` outlives `'u`. + + struct AssertIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T); + let _ = AssertIsAsBytes(e); + + struct AssertIsFromBytes<'a, U: ::core::marker::Sized + $crate::FromBytes>(&'a U); + #[allow(unused, unreachable_code)] + let u = AssertIsFromBytes(loop {}); + u.0 + } else if false { + // This branch, though never taken, ensures that `size_of::() == + // size_of::()` and that that `align_of::() >= + // align_of::()`. + + // `t` is inferred to have type `T` because it's assigned to `e` (of + // type `&T`) as `&t`. + let mut t = unreachable!(); + e = &t; + + // `u` is inferred to have type `U` because it's used as `&u` as the + // value returned from this branch. + let u; + + $crate::assert_size_eq!(t, u); + $crate::assert_align_gt_eq!(t, u); + + &u + } else { + // SAFETY: For source type `Src` and destination type `Dst`: + // - We know that `Src: AsBytes` and `Dst: FromBytes` thanks to the + // uses of `AssertIsAsBytes` and `AssertIsFromBytes` above. + // - We know that `size_of::() == size_of::()` thanks to + // the use of `assert_size_eq!` above. + // - We know that `align_of::() >= align_of::()` thanks to + // the use of `assert_align_gt_eq!` above. + unsafe { $crate::macro_util::transmute_ref(e) } + } + }} +} + +/// Safely transmutes a mutable reference of one type to an mutable reference of +/// another type of the same size. +/// +/// The expression `$e` must have a concrete type, `&mut T`, where `T: Sized + +/// AsBytes`. The `transmute_mut!` expression must also have a concrete type, +/// `&mut U` (`U` is inferred from the calling context), where `U: Sized + +/// FromBytes`. It must be the case that `align_of::() >= align_of::()`. +/// +/// The lifetime of the input type, `&mut T`, must be the same as or outlive the +/// lifetime of the output type, `&mut U`. +/// +/// # Examples +/// +/// ``` +/// # use zerocopy::transmute_mut; +/// let mut one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; +/// +/// let two_dimensional: &mut [[u8; 4]; 2] = transmute_mut!(&mut one_dimensional); +/// +/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); +/// +/// two_dimensional.reverse(); +/// +/// assert_eq!(one_dimensional, [4, 5, 6, 7, 0, 1, 2, 3]); +/// ``` +/// +/// # Alignment increase error message +/// +/// Because of limitations on macros, the error message generated when +/// `transmute_mut!` is used to transmute from a type of lower alignment to a +/// type of higher alignment is somewhat confusing. For example, the following +/// code: +/// +/// ```compile_fail +/// const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]); +/// ``` +/// +/// ...generates the following error: +/// +/// ```text +/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types +/// --> src/lib.rs:1524:34 +/// | +/// 5 | const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]); +/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/// | +/// = note: source type: `AlignOf<[u8; 2]>` (8 bits) +/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) +/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +/// ``` +/// +/// This is saying that `max(align_of::(), align_of::()) != +/// align_of::()`, which is equivalent to `align_of::() < +/// align_of::()`. +#[macro_export] +macro_rules! transmute_mut { + ($e:expr) => {{ + // NOTE: This must be a macro (rather than a function with trait bounds) + // because there's no way, in a generic context, to enforce that two + // types have the same size or alignment. + + // Ensure that the source type is a mutable reference. + let e: &mut _ = $e; + + #[allow(unused, clippy::diverging_sub_expression)] + if false { + // This branch, though never taken, ensures that the type of `e` is + // `&mut T` where `T: 't + Sized + FromBytes + AsBytes`, that the + // type of this macro expression is `&mut U` where `U: 'u + Sized + + // FromBytes + AsBytes`. + + // We use immutable references here rather than mutable so that, if + // this macro is used in a const context (in which, as of this + // writing, mutable references are banned), the error message + // appears to originate in the user's code rather than in the + // internals of this macro. + struct AssertSrcIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T); + struct AssertSrcIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T); + struct AssertDstIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T); + struct AssertDstIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T); + + if true { + let _ = AssertSrcIsFromBytes(&*e); + } else { + let _ = AssertSrcIsAsBytes(&*e); + } + + if true { + #[allow(unused, unreachable_code)] + let u = AssertDstIsFromBytes(loop {}); + &mut *u.0 + } else { + #[allow(unused, unreachable_code)] + let u = AssertDstIsAsBytes(loop {}); + &mut *u.0 + } + } else if false { + // This branch, though never taken, ensures that `size_of::() == + // size_of::()` and that that `align_of::() >= + // align_of::()`. + + // `t` is inferred to have type `T` because it's assigned to `e` (of + // type `&mut T`) as `&mut t`. + let mut t = unreachable!(); + e = &mut t; + + // `u` is inferred to have type `U` because it's used as `&mut u` as + // the value returned from this branch. + let u; + + $crate::assert_size_eq!(t, u); + $crate::assert_align_gt_eq!(t, u); + + &mut u + } else { + // SAFETY: For source type `Src` and destination type `Dst`: + // - We know that `Src: FromBytes + AsBytes` and `Dst: FromBytes + + // AsBytes` thanks to the uses of `AssertSrcIsFromBytes`, + // `AssertSrcIsAsBytes`, `AssertDstIsFromBytes`, and + // `AssertDstIsAsBytes` above. + // - We know that `size_of::() == size_of::()` thanks to + // the use of `assert_size_eq!` above. + // - We know that `align_of::() >= align_of::()` thanks to + // the use of `assert_align_gt_eq!` above. + unsafe { $crate::macro_util::transmute_mut(e) } + } + }} +} + +/// Includes a file and safely transmutes it to a value of an arbitrary type. +/// +/// The file will be included as a byte array, `[u8; N]`, which will be +/// transmuted to another type, `T`. `T` is inferred from the calling context, +/// and must implement [`FromBytes`]. +/// +/// The file is located relative to the current file (similarly to how modules +/// are found). The provided path is interpreted in a platform-specific way at +/// compile time. So, for instance, an invocation with a Windows path containing +/// backslashes `\` would not compile correctly on Unix. +/// +/// `include_value!` is ignorant of byte order. For byte order-aware types, see +/// the [`byteorder`] module. +/// +/// # Examples +/// +/// Assume there are two files in the same directory with the following +/// contents: +/// +/// File `data` (no trailing newline): +/// +/// ```text +/// abcd +/// ``` +/// +/// File `main.rs`: +/// +/// ```rust +/// use zerocopy::include_value; +/// # macro_rules! include_value { +/// # ($file:expr) => { zerocopy::include_value!(concat!("../testdata/include_value/", $file)) }; +/// # } +/// +/// fn main() { +/// let as_u32: u32 = include_value!("data"); +/// assert_eq!(as_u32, u32::from_ne_bytes([b'a', b'b', b'c', b'd'])); +/// let as_i32: i32 = include_value!("data"); +/// assert_eq!(as_i32, i32::from_ne_bytes([b'a', b'b', b'c', b'd'])); +/// } +/// ``` +#[doc(alias("include_bytes", "include_data", "include_type"))] +#[macro_export] +macro_rules! include_value { + ($file:expr $(,)?) => { + $crate::transmute!(*::core::include_bytes!($file)) + }; +} + +/// A typed reference derived from a byte slice. +/// +/// A `Ref` is a reference to a `T` which is stored in a byte slice, `B`. +/// Unlike a native reference (`&T` or `&mut T`), `Ref` has the same +/// mutability as the byte slice it was constructed from (`B`). +/// +/// # Examples +/// +/// `Ref` can be used to treat a sequence of bytes as a structured type, and to +/// read and write the fields of that type as if the byte slice reference were +/// simply a reference to that type. +/// +/// ```rust +/// # #[cfg(feature = "derive")] { // This example uses derives, and won't compile without them +/// use zerocopy::{AsBytes, ByteSlice, ByteSliceMut, FromBytes, FromZeroes, Ref, Unaligned}; +/// +/// #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] +/// #[repr(C)] +/// struct UdpHeader { +/// src_port: [u8; 2], +/// dst_port: [u8; 2], +/// length: [u8; 2], +/// checksum: [u8; 2], +/// } +/// +/// struct UdpPacket { +/// header: Ref, +/// body: B, +/// } +/// +/// impl UdpPacket { +/// pub fn parse(bytes: B) -> Option> { +/// let (header, body) = Ref::new_unaligned_from_prefix(bytes)?; +/// Some(UdpPacket { header, body }) +/// } +/// +/// pub fn get_src_port(&self) -> [u8; 2] { +/// self.header.src_port +/// } +/// } +/// +/// impl UdpPacket { +/// pub fn set_src_port(&mut self, src_port: [u8; 2]) { +/// self.header.src_port = src_port; +/// } +/// } +/// # } +/// ``` +pub struct Ref(B, PhantomData); + +/// Deprecated: prefer [`Ref`] instead. +#[deprecated(since = "0.7.0", note = "LayoutVerified has been renamed to Ref")] +#[doc(hidden)] +pub type LayoutVerified = Ref; + +impl Ref +where + B: ByteSlice, +{ + /// Constructs a new `Ref`. + /// + /// `new` verifies that `bytes.len() == size_of::()` and that `bytes` is + /// aligned to `align_of::()`, and constructs a new `Ref`. If either of + /// these checks fail, it returns `None`. + #[inline] + pub fn new(bytes: B) -> Option> { + if bytes.len() != mem::size_of::() || !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + Some(Ref(bytes, PhantomData)) + } + + /// Constructs a new `Ref` from the prefix of a byte slice. + /// + /// `new_from_prefix` verifies that `bytes.len() >= size_of::()` and that + /// `bytes` is aligned to `align_of::()`. It consumes the first + /// `size_of::()` bytes from `bytes` to construct a `Ref`, and returns + /// the remaining bytes to the caller. If either the length or alignment + /// checks fail, it returns `None`. + #[inline] + pub fn new_from_prefix(bytes: B) -> Option<(Ref, B)> { + if bytes.len() < mem::size_of::() || !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + let (bytes, suffix) = bytes.split_at(mem::size_of::()); + Some((Ref(bytes, PhantomData), suffix)) + } + + /// Constructs a new `Ref` from the suffix of a byte slice. + /// + /// `new_from_suffix` verifies that `bytes.len() >= size_of::()` and that + /// the last `size_of::()` bytes of `bytes` are aligned to + /// `align_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If either the length or alignment checks fail, it returns + /// `None`. + #[inline] + pub fn new_from_suffix(bytes: B) -> Option<(B, Ref)> { + let bytes_len = bytes.len(); + let split_at = bytes_len.checked_sub(mem::size_of::())?; + let (prefix, bytes) = bytes.split_at(split_at); + if !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + Some((prefix, Ref(bytes, PhantomData))) + } +} + +impl Ref +where + B: ByteSlice, +{ + /// Constructs a new `Ref` of a slice type. + /// + /// `new_slice` verifies that `bytes.len()` is a multiple of + /// `size_of::()` and that `bytes` is aligned to `align_of::()`, and + /// constructs a new `Ref`. If either of these checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline] + pub fn new_slice(bytes: B) -> Option> { + let remainder = bytes + .len() + .checked_rem(mem::size_of::()) + .expect("Ref::new_slice called on a zero-sized type"); + if remainder != 0 || !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + Some(Ref(bytes, PhantomData)) + } + + /// Constructs a new `Ref` of a slice type from the prefix of a byte slice. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the remaining bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// # Panics + /// + /// `new_slice_from_prefix` panics if `T` is a zero-sized type. + #[inline] + pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { + let expected_len = match mem::size_of::().checked_mul(count) { + Some(len) => len, + None => return None, + }; + if bytes.len() < expected_len { + return None; + } + let (prefix, bytes) = bytes.split_at(expected_len); + Self::new_slice(prefix).map(move |l| (l, bytes)) + } + + /// Constructs a new `Ref` of a slice type from the suffix of a byte slice. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the preceding bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// # Panics + /// + /// `new_slice_from_suffix` panics if `T` is a zero-sized type. + #[inline] + pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { + let expected_len = match mem::size_of::().checked_mul(count) { + Some(len) => len, + None => return None, + }; + let split_at = bytes.len().checked_sub(expected_len)?; + let (bytes, suffix) = bytes.split_at(split_at); + Self::new_slice(suffix).map(move |l| (bytes, l)) + } +} + +fn map_zeroed(opt: Option>) -> Option> { + match opt { + Some(mut r) => { + r.0.fill(0); + Some(r) + } + None => None, + } +} + +fn map_prefix_tuple_zeroed( + opt: Option<(Ref, B)>, +) -> Option<(Ref, B)> { + match opt { + Some((mut r, rest)) => { + r.0.fill(0); + Some((r, rest)) + } + None => None, + } +} + +fn map_suffix_tuple_zeroed( + opt: Option<(B, Ref)>, +) -> Option<(B, Ref)> { + map_prefix_tuple_zeroed(opt.map(|(a, b)| (b, a))).map(|(a, b)| (b, a)) +} + +impl Ref +where + B: ByteSliceMut, +{ + /// Constructs a new `Ref` after zeroing the bytes. + /// + /// `new_zeroed` verifies that `bytes.len() == size_of::()` and that + /// `bytes` is aligned to `align_of::()`, and constructs a new `Ref`. If + /// either of these checks fail, it returns `None`. + /// + /// If the checks succeed, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new(bytes)) + } + + /// Constructs a new `Ref` from the prefix of a byte slice, zeroing the + /// prefix. + /// + /// `new_from_prefix_zeroed` verifies that `bytes.len() >= size_of::()` + /// and that `bytes` is aligned to `align_of::()`. It consumes the first + /// `size_of::()` bytes from `bytes` to construct a `Ref`, and returns + /// the remaining bytes to the caller. If either the length or alignment + /// checks fail, it returns `None`. + /// + /// If the checks succeed, then the prefix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_from_prefix_zeroed(bytes: B) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_from_prefix(bytes)) + } + + /// Constructs a new `Ref` from the suffix of a byte slice, zeroing the + /// suffix. + /// + /// `new_from_suffix_zeroed` verifies that `bytes.len() >= size_of::()` + /// and that the last `size_of::()` bytes of `bytes` are aligned to + /// `align_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If either the length or alignment checks fail, it returns + /// `None`. + /// + /// If the checks succeed, then the suffix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_from_suffix_zeroed(bytes: B) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_from_suffix(bytes)) + } +} + +impl Ref +where + B: ByteSliceMut, +{ + /// Constructs a new `Ref` of a slice type after zeroing the bytes. + /// + /// `new_slice_zeroed` verifies that `bytes.len()` is a multiple of + /// `size_of::()` and that `bytes` is aligned to `align_of::()`, and + /// constructs a new `Ref`. If either of these checks fail, it returns + /// `None`. + /// + /// If the checks succeed, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new_slice(bytes)) + } + + /// Constructs a new `Ref` of a slice type from the prefix of a byte slice, + /// after zeroing the bytes. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the remaining bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// If the checks succeed, then the suffix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_from_prefix_zeroed` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_from_prefix_zeroed(bytes: B, count: usize) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_slice_from_prefix(bytes, count)) + } + + /// Constructs a new `Ref` of a slice type from the prefix of a byte slice, + /// after zeroing the bytes. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the preceding bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// If the checks succeed, then the consumed suffix will be initialized to + /// zero. This can be useful when re-using buffers to ensure that sensitive + /// data previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_from_suffix_zeroed` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_from_suffix_zeroed(bytes: B, count: usize) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_slice_from_suffix(bytes, count)) + } +} + +impl Ref +where + B: ByteSlice, + T: Unaligned, +{ + /// Constructs a new `Ref` for a type with no alignment requirement. + /// + /// `new_unaligned` verifies that `bytes.len() == size_of::()` and + /// constructs a new `Ref`. If the check fails, it returns `None`. + #[inline(always)] + pub fn new_unaligned(bytes: B) -> Option> { + Ref::new(bytes) + } + + /// Constructs a new `Ref` from the prefix of a byte slice for a type with + /// no alignment requirement. + /// + /// `new_unaligned_from_prefix` verifies that `bytes.len() >= + /// size_of::()`. It consumes the first `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. If the length check fails, it returns `None`. + #[inline(always)] + pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref, B)> { + Ref::new_from_prefix(bytes) + } + + /// Constructs a new `Ref` from the suffix of a byte slice for a type with + /// no alignment requirement. + /// + /// `new_unaligned_from_suffix` verifies that `bytes.len() >= + /// size_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If the length check fails, it returns `None`. + #[inline(always)] + pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref)> { + Ref::new_from_suffix(bytes) + } +} + +impl Ref +where + B: ByteSlice, + T: Unaligned, +{ + /// Constructs a new `Ref` of a slice type with no alignment requirement. + /// + /// `new_slice_unaligned` verifies that `bytes.len()` is a multiple of + /// `size_of::()` and constructs a new `Ref`. If the check fails, it + /// returns `None`. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned(bytes: B) -> Option> { + Ref::new_slice(bytes) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the prefix of a byte slice. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the first `size_of::() * count` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. It also ensures that `sizeof::() * count` does not overflow a + /// `usize`. If either the length, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_prefix` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { + Ref::new_slice_from_prefix(bytes, count) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the suffix of a byte slice. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the last `size_of::() * count` bytes from `bytes` + /// to construct a `Ref`, and returns the remaining bytes to the caller. It + /// also ensures that `sizeof::() * count` does not overflow a `usize`. + /// If either the length, or overflow checks fail, it returns `None`. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_suffix` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { + Ref::new_slice_from_suffix(bytes, count) + } +} + +impl Ref +where + B: ByteSliceMut, + T: Unaligned, +{ + /// Constructs a new `Ref` for a type with no alignment requirement, zeroing + /// the bytes. + /// + /// `new_unaligned_zeroed` verifies that `bytes.len() == size_of::()` and + /// constructs a new `Ref`. If the check fails, it returns `None`. + /// + /// If the check succeeds, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_unaligned_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new_unaligned(bytes)) + } + + /// Constructs a new `Ref` from the prefix of a byte slice for a type with + /// no alignment requirement, zeroing the prefix. + /// + /// `new_unaligned_from_prefix_zeroed` verifies that `bytes.len() >= + /// size_of::()`. It consumes the first `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. If the length check fails, it returns `None`. + /// + /// If the check succeeds, then the prefix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_unaligned_from_prefix_zeroed(bytes: B) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_unaligned_from_prefix(bytes)) + } + + /// Constructs a new `Ref` from the suffix of a byte slice for a type with + /// no alignment requirement, zeroing the suffix. + /// + /// `new_unaligned_from_suffix_zeroed` verifies that `bytes.len() >= + /// size_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If the length check fails, it returns `None`. + /// + /// If the check succeeds, then the suffix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_unaligned_from_suffix_zeroed(bytes: B) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_unaligned_from_suffix(bytes)) + } +} + +impl Ref +where + B: ByteSliceMut, + T: Unaligned, +{ + /// Constructs a new `Ref` for a slice type with no alignment requirement, + /// zeroing the bytes. + /// + /// `new_slice_unaligned_zeroed` verifies that `bytes.len()` is a multiple + /// of `size_of::()` and constructs a new `Ref`. If the check fails, it + /// returns `None`. + /// + /// If the check succeeds, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new_slice_unaligned(bytes)) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the prefix of a byte slice, after zeroing the bytes. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the first `size_of::() * count` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. It also ensures that `sizeof::() * count` does not overflow a + /// `usize`. If either the length, or overflow checks fail, it returns + /// `None`. + /// + /// If the checks succeed, then the prefix will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_prefix_zeroed` panics if `T` is a zero-sized + /// type. + #[inline(always)] + pub fn new_slice_unaligned_from_prefix_zeroed( + bytes: B, + count: usize, + ) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_slice_unaligned_from_prefix(bytes, count)) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the suffix of a byte slice, after zeroing the bytes. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the last `size_of::() * count` bytes from `bytes` + /// to construct a `Ref`, and returns the remaining bytes to the caller. It + /// also ensures that `sizeof::() * count` does not overflow a `usize`. + /// If either the length, or overflow checks fail, it returns `None`. + /// + /// If the checks succeed, then the suffix will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_suffix_zeroed` panics if `T` is a zero-sized + /// type. + #[inline(always)] + pub fn new_slice_unaligned_from_suffix_zeroed( + bytes: B, + count: usize, + ) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_slice_unaligned_from_suffix(bytes, count)) + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSlice, + T: FromBytes, +{ + /// Converts this `Ref` into a reference. + /// + /// `into_ref` consumes the `Ref`, and returns a reference to `T`. + #[inline(always)] + pub fn into_ref(self) -> &'a T { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a`, it is sound to drop `self` and still + // access the underlying memory using reads for `'a`. + unsafe { self.deref_helper() } + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Converts this `Ref` into a mutable reference. + /// + /// `into_mut` consumes the `Ref`, and returns a mutable reference to `T`. + #[inline(always)] + pub fn into_mut(mut self) -> &'a mut T { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a + ByteSliceMut`, it is sound to drop + // `self` and still access the underlying memory using both reads and + // writes for `'a`. + unsafe { self.deref_mut_helper() } + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSlice, + T: FromBytes, +{ + /// Converts this `Ref` into a slice reference. + /// + /// `into_slice` consumes the `Ref`, and returns a reference to `[T]`. + #[inline(always)] + pub fn into_slice(self) -> &'a [T] { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a`, it is sound to drop `self` and still + // access the underlying memory using reads for `'a`. + unsafe { self.deref_slice_helper() } + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Converts this `Ref` into a mutable slice reference. + /// + /// `into_mut_slice` consumes the `Ref`, and returns a mutable reference to + /// `[T]`. + #[inline(always)] + pub fn into_mut_slice(mut self) -> &'a mut [T] { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a + ByteSliceMut`, it is sound to drop + // `self` and still access the underlying memory using both reads and + // writes for `'a`. + unsafe { self.deref_mut_slice_helper() } + } +} + +impl Ref +where + B: ByteSlice, + T: FromBytes, +{ + /// Creates an immutable reference to `T` with a specific lifetime. + /// + /// # Safety + /// + /// The type bounds on this method guarantee that it is safe to create an + /// immutable reference to `T` from `self`. However, since the lifetime `'a` + /// is not required to be shorter than the lifetime of the reference to + /// `self`, the caller must guarantee that the lifetime `'a` is valid for + /// this reference. In particular, the referent must exist for all of `'a`, + /// and no mutable references to the same memory may be constructed during + /// `'a`. + unsafe fn deref_helper<'a>(&self) -> &'a T { + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + &*self.0.as_ptr().cast::() + } + } +} + +impl Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Creates a mutable reference to `T` with a specific lifetime. + /// + /// # Safety + /// + /// The type bounds on this method guarantee that it is safe to create a + /// mutable reference to `T` from `self`. However, since the lifetime `'a` + /// is not required to be shorter than the lifetime of the reference to + /// `self`, the caller must guarantee that the lifetime `'a` is valid for + /// this reference. In particular, the referent must exist for all of `'a`, + /// and no other references - mutable or immutable - to the same memory may + /// be constructed during `'a`. + unsafe fn deref_mut_helper<'a>(&mut self) -> &'a mut T { + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + &mut *self.0.as_mut_ptr().cast::() + } + } +} + +impl Ref +where + B: ByteSlice, + T: FromBytes, +{ + /// Creates an immutable reference to `[T]` with a specific lifetime. + /// + /// # Safety + /// + /// `deref_slice_helper` has the same safety requirements as `deref_helper`. + unsafe fn deref_slice_helper<'a>(&self) -> &'a [T] { + let len = self.0.len(); + let elem_size = mem::size_of::(); + debug_assert_ne!(elem_size, 0); + // `Ref<_, [T]>` maintains the invariant that `size_of::() > 0`. + // Thus, neither the mod nor division operations here can panic. + #[allow(clippy::arithmetic_side_effects)] + let elems = { + debug_assert_eq!(len % elem_size, 0); + len / elem_size + }; + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + slice::from_raw_parts(self.0.as_ptr().cast::(), elems) + } + } +} + +impl Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Creates a mutable reference to `[T]` with a specific lifetime. + /// + /// # Safety + /// + /// `deref_mut_slice_helper` has the same safety requirements as + /// `deref_mut_helper`. + unsafe fn deref_mut_slice_helper<'a>(&mut self) -> &'a mut [T] { + let len = self.0.len(); + let elem_size = mem::size_of::(); + debug_assert_ne!(elem_size, 0); + // `Ref<_, [T]>` maintains the invariant that `size_of::() > 0`. + // Thus, neither the mod nor division operations here can panic. + #[allow(clippy::arithmetic_side_effects)] + let elems = { + debug_assert_eq!(len % elem_size, 0); + len / elem_size + }; + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + slice::from_raw_parts_mut(self.0.as_mut_ptr().cast::(), elems) + } + } +} + +impl Ref +where + B: ByteSlice, + T: ?Sized, +{ + /// Gets the underlying bytes. + #[inline] + pub fn bytes(&self) -> &[u8] { + &self.0 + } +} + +impl Ref +where + B: ByteSliceMut, + T: ?Sized, +{ + /// Gets the underlying bytes mutably. + #[inline] + pub fn bytes_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +impl Ref +where + B: ByteSlice, + T: FromBytes, +{ + /// Reads a copy of `T`. + #[inline] + pub fn read(&self) -> T { + // SAFETY: Because of the invariants on `Ref`, we know that `self.0` is + // at least `size_of::()` bytes long, and that it is at least as + // aligned as `align_of::()`. Because `T: FromBytes`, it is sound to + // interpret these bytes as a `T`. + unsafe { ptr::read(self.0.as_ptr().cast::()) } + } +} + +impl Ref +where + B: ByteSliceMut, + T: AsBytes, +{ + /// Writes the bytes of `t` and then forgets `t`. + #[inline] + pub fn write(&mut self, t: T) { + // SAFETY: Because of the invariants on `Ref`, we know that `self.0` is + // at least `size_of::()` bytes long, and that it is at least as + // aligned as `align_of::()`. Writing `t` to the buffer will allow + // all of the bytes of `t` to be accessed as a `[u8]`, but because `T: + // AsBytes`, we know this is sound. + unsafe { ptr::write(self.0.as_mut_ptr().cast::(), t) } + } +} + +impl Deref for Ref +where + B: ByteSlice, + T: FromBytes, +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no mutable methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_helper` for what invariants we are required + // to uphold. + unsafe { self.deref_helper() } + } +} + +impl DerefMut for Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no other methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_mut_helper` for what invariants we are + // required to uphold. + unsafe { self.deref_mut_helper() } + } +} + +impl Deref for Ref +where + B: ByteSlice, + T: FromBytes, +{ + type Target = [T]; + #[inline] + fn deref(&self) -> &[T] { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no mutable methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_slice_helper` for what invariants we are + // required to uphold. + unsafe { self.deref_slice_helper() } + } +} + +impl DerefMut for Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + #[inline] + fn deref_mut(&mut self) -> &mut [T] { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no other methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_mut_slice_helper` for what invariants we are + // required to uphold. + unsafe { self.deref_mut_slice_helper() } + } +} + +impl Display for Ref +where + B: ByteSlice, + T: FromBytes + Display, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &T = self; + inner.fmt(fmt) + } +} + +impl Display for Ref +where + B: ByteSlice, + T: FromBytes, + [T]: Display, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &[T] = self; + inner.fmt(fmt) + } +} + +impl Debug for Ref +where + B: ByteSlice, + T: FromBytes + Debug, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &T = self; + fmt.debug_tuple("Ref").field(&inner).finish() + } +} + +impl Debug for Ref +where + B: ByteSlice, + T: FromBytes + Debug, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &[T] = self; + fmt.debug_tuple("Ref").field(&inner).finish() + } +} + +impl Eq for Ref +where + B: ByteSlice, + T: FromBytes + Eq, +{ +} + +impl Eq for Ref +where + B: ByteSlice, + T: FromBytes + Eq, +{ +} + +impl PartialEq for Ref +where + B: ByteSlice, + T: FromBytes + PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other.deref()) + } +} + +impl PartialEq for Ref +where + B: ByteSlice, + T: FromBytes + PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other.deref()) + } +} + +impl Ord for Ref +where + B: ByteSlice, + T: FromBytes + Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + let inner: &T = self; + let other_inner: &T = other; + inner.cmp(other_inner) + } +} + +impl Ord for Ref +where + B: ByteSlice, + T: FromBytes + Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + let inner: &[T] = self; + let other_inner: &[T] = other; + inner.cmp(other_inner) + } +} + +impl PartialOrd for Ref +where + B: ByteSlice, + T: FromBytes + PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + let inner: &T = self; + let other_inner: &T = other; + inner.partial_cmp(other_inner) + } +} + +impl PartialOrd for Ref +where + B: ByteSlice, + T: FromBytes + PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + let inner: &[T] = self; + let other_inner: &[T] = other; + inner.partial_cmp(other_inner) + } +} + +mod sealed { + pub trait ByteSliceSealed {} +} + +// ByteSlice and ByteSliceMut abstract over [u8] references (&[u8], &mut [u8], +// Ref<[u8]>, RefMut<[u8]>, etc). We rely on various behaviors of these +// references such as that a given reference will never changes its length +// between calls to deref() or deref_mut(), and that split_at() works as +// expected. If ByteSlice or ByteSliceMut were not sealed, consumers could +// implement them in a way that violated these behaviors, and would break our +// unsafe code. Thus, we seal them and implement it only for known-good +// reference types. For the same reason, they're unsafe traits. + +#[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99068) +/// A mutable or immutable reference to a byte slice. +/// +/// `ByteSlice` abstracts over the mutability of a byte slice reference, and is +/// implemented for various special reference types such as `Ref<[u8]>` and +/// `RefMut<[u8]>`. +/// +/// Note that, while it would be technically possible, `ByteSlice` is not +/// implemented for [`Vec`], as the only way to implement the [`split_at`] +/// method would involve reallocation, and `split_at` must be a very cheap +/// operation in order for the utilities in this crate to perform as designed. +/// +/// [`split_at`]: crate::ByteSlice::split_at +// It may seem overkill to go to this length to ensure that this doc link never +// breaks. We do this because it simplifies CI - it means that generating docs +// always succeeds, so we don't need special logic to only generate docs under +// certain features. +#[cfg_attr(feature = "alloc", doc = "[`Vec`]: alloc::vec::Vec")] +#[cfg_attr( + not(feature = "alloc"), + doc = "[`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html" +)] +pub unsafe trait ByteSlice: + Deref + Sized + self::sealed::ByteSliceSealed +{ + /// Are the [`Ref::into_ref`] and [`Ref::into_mut`] methods sound when used + /// with `Self`? If not, evaluating this constant must panic at compile + /// time. + /// + /// This exists to work around #716 on versions of zerocopy prior to 0.8. + /// + /// # Safety + /// + /// This may only be set to true if the following holds: Given the + /// following: + /// - `Self: 'a` + /// - `bytes: Self` + /// - `let ptr = bytes.as_ptr()` + /// + /// ...then: + /// - Using `ptr` to read the memory previously addressed by `bytes` is + /// sound for `'a` even after `bytes` has been dropped. + /// - If `Self: ByteSliceMut`, using `ptr` to write the memory previously + /// addressed by `bytes` is sound for `'a` even after `bytes` has been + /// dropped. + #[doc(hidden)] + const INTO_REF_INTO_MUT_ARE_SOUND: bool; + + /// Gets a raw pointer to the first byte in the slice. + #[inline] + fn as_ptr(&self) -> *const u8 { + <[u8]>::as_ptr(self) + } + + /// Splits the slice at the midpoint. + /// + /// `x.split_at(mid)` returns `x[..mid]` and `x[mid..]`. + /// + /// # Panics + /// + /// `x.split_at(mid)` panics if `mid > x.len()`. + fn split_at(self, mid: usize) -> (Self, Self); +} + +#[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99068) +/// A mutable reference to a byte slice. +/// +/// `ByteSliceMut` abstracts over various ways of storing a mutable reference to +/// a byte slice, and is implemented for various special reference types such as +/// `RefMut<[u8]>`. +pub unsafe trait ByteSliceMut: ByteSlice + DerefMut { + /// Gets a mutable raw pointer to the first byte in the slice. + #[inline] + fn as_mut_ptr(&mut self) -> *mut u8 { + <[u8]>::as_mut_ptr(self) + } +} + +impl<'a> sealed::ByteSliceSealed for &'a [u8] {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for &'a [u8] { + // SAFETY: If `&'b [u8]: 'a`, then the underlying memory is treated as + // borrowed immutably for `'a` even if the slice itself is dropped. + const INTO_REF_INTO_MUT_ARE_SOUND: bool = true; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + <[u8]>::split_at(self, mid) + } +} + +impl<'a> sealed::ByteSliceSealed for &'a mut [u8] {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for &'a mut [u8] { + // SAFETY: If `&'b mut [u8]: 'a`, then the underlying memory is treated as + // borrowed mutably for `'a` even if the slice itself is dropped. + const INTO_REF_INTO_MUT_ARE_SOUND: bool = true; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + <[u8]>::split_at_mut(self, mid) + } +} + +impl<'a> sealed::ByteSliceSealed for cell::Ref<'a, [u8]> {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for cell::Ref<'a, [u8]> { + const INTO_REF_INTO_MUT_ARE_SOUND: bool = if !cfg!(doc) { + panic!("Ref::into_ref and Ref::into_mut are unsound when used with core::cell::Ref; see https://github.com/google/zerocopy/issues/716") + } else { + // When compiling documentation, allow the evaluation of this constant + // to succeed. This doesn't represent a soundness hole - it just delays + // any error to runtime. The reason we need this is that, otherwise, + // `rustdoc` will fail when trying to document this item. + false + }; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + cell::Ref::map_split(self, |slice| <[u8]>::split_at(slice, mid)) + } +} + +impl<'a> sealed::ByteSliceSealed for RefMut<'a, [u8]> {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for RefMut<'a, [u8]> { + const INTO_REF_INTO_MUT_ARE_SOUND: bool = if !cfg!(doc) { + panic!("Ref::into_ref and Ref::into_mut are unsound when used with core::cell::RefMut; see https://github.com/google/zerocopy/issues/716") + } else { + // When compiling documentation, allow the evaluation of this constant + // to succeed. This doesn't represent a soundness hole - it just delays + // any error to runtime. The reason we need this is that, otherwise, + // `rustdoc` will fail when trying to document this item. + false + }; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + RefMut::map_split(self, |slice| <[u8]>::split_at_mut(slice, mid)) + } +} + +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSliceMut for &'a mut [u8] {} + +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSliceMut for RefMut<'a, [u8]> {} + +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] +mod alloc_support { + use alloc::vec::Vec; + + use super::*; + + /// Extends a `Vec` by pushing `additional` new items onto the end of the + /// vector. The new items are initialized with zeroes. + /// + /// # Panics + /// + /// Panics if `Vec::reserve(additional)` fails to reserve enough memory. + #[inline(always)] + pub fn extend_vec_zeroed(v: &mut Vec, additional: usize) { + insert_vec_zeroed(v, v.len(), additional); + } + + /// Inserts `additional` new items into `Vec` at `position`. + /// The new items are initialized with zeroes. + /// + /// # Panics + /// + /// * Panics if `position > v.len()`. + /// * Panics if `Vec::reserve(additional)` fails to reserve enough memory. + #[inline] + pub fn insert_vec_zeroed(v: &mut Vec, position: usize, additional: usize) { + assert!(position <= v.len()); + v.reserve(additional); + // SAFETY: The `reserve` call guarantees that these cannot overflow: + // * `ptr.add(position)` + // * `position + additional` + // * `v.len() + additional` + // + // `v.len() - position` cannot overflow because we asserted that + // `position <= v.len()`. + unsafe { + // This is a potentially overlapping copy. + let ptr = v.as_mut_ptr(); + #[allow(clippy::arithmetic_side_effects)] + ptr.add(position).copy_to(ptr.add(position + additional), v.len() - position); + ptr.add(position).write_bytes(0, additional); + #[allow(clippy::arithmetic_side_effects)] + v.set_len(v.len() + additional); + } + } + + #[cfg(test)] + mod tests { + use core::convert::TryFrom as _; + + use super::*; + + #[test] + fn test_extend_vec_zeroed() { + // Test extending when there is an existing allocation. + let mut v = vec![100u64, 200, 300]; + extend_vec_zeroed(&mut v, 3); + assert_eq!(v.len(), 6); + assert_eq!(&*v, &[100, 200, 300, 0, 0, 0]); + drop(v); + + // Test extending when there is no existing allocation. + let mut v: Vec = Vec::new(); + extend_vec_zeroed(&mut v, 3); + assert_eq!(v.len(), 3); + assert_eq!(&*v, &[0, 0, 0]); + drop(v); + } + + #[test] + fn test_extend_vec_zeroed_zst() { + // Test extending when there is an existing (fake) allocation. + let mut v = vec![(), (), ()]; + extend_vec_zeroed(&mut v, 3); + assert_eq!(v.len(), 6); + assert_eq!(&*v, &[(), (), (), (), (), ()]); + drop(v); + + // Test extending when there is no existing (fake) allocation. + let mut v: Vec<()> = Vec::new(); + extend_vec_zeroed(&mut v, 3); + assert_eq!(&*v, &[(), (), ()]); + drop(v); + } + + #[test] + fn test_insert_vec_zeroed() { + // Insert at start (no existing allocation). + let mut v: Vec = Vec::new(); + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 2); + assert_eq!(&*v, &[0, 0]); + drop(v); + + // Insert at start. + let mut v = vec![100u64, 200, 300]; + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 5); + assert_eq!(&*v, &[0, 0, 100, 200, 300]); + drop(v); + + // Insert at middle. + let mut v = vec![100u64, 200, 300]; + insert_vec_zeroed(&mut v, 1, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[100, 0, 200, 300]); + drop(v); + + // Insert at end. + let mut v = vec![100u64, 200, 300]; + insert_vec_zeroed(&mut v, 3, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[100, 200, 300, 0]); + drop(v); + } + + #[test] + fn test_insert_vec_zeroed_zst() { + // Insert at start (no existing fake allocation). + let mut v: Vec<()> = Vec::new(); + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 2); + assert_eq!(&*v, &[(), ()]); + drop(v); + + // Insert at start. + let mut v = vec![(), (), ()]; + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 5); + assert_eq!(&*v, &[(), (), (), (), ()]); + drop(v); + + // Insert at middle. + let mut v = vec![(), (), ()]; + insert_vec_zeroed(&mut v, 1, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[(), (), (), ()]); + drop(v); + + // Insert at end. + let mut v = vec![(), (), ()]; + insert_vec_zeroed(&mut v, 3, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[(), (), (), ()]); + drop(v); + } + + #[test] + fn test_new_box_zeroed() { + assert_eq!(*u64::new_box_zeroed(), 0); + } + + #[test] + fn test_new_box_zeroed_array() { + drop(<[u32; 0x1000]>::new_box_zeroed()); + } + + #[test] + fn test_new_box_zeroed_zst() { + // This test exists in order to exercise unsafe code, especially + // when running under Miri. + #[allow(clippy::unit_cmp)] + { + assert_eq!(*<()>::new_box_zeroed(), ()); + } + } + + #[test] + fn test_new_box_slice_zeroed() { + let mut s: Box<[u64]> = u64::new_box_slice_zeroed(3); + assert_eq!(s.len(), 3); + assert_eq!(&*s, &[0, 0, 0]); + s[1] = 3; + assert_eq!(&*s, &[0, 3, 0]); + } + + #[test] + fn test_new_box_slice_zeroed_empty() { + let s: Box<[u64]> = u64::new_box_slice_zeroed(0); + assert_eq!(s.len(), 0); + } + + #[test] + fn test_new_box_slice_zeroed_zst() { + let mut s: Box<[()]> = <()>::new_box_slice_zeroed(3); + assert_eq!(s.len(), 3); + assert!(s.get(10).is_none()); + // This test exists in order to exercise unsafe code, especially + // when running under Miri. + #[allow(clippy::unit_cmp)] + { + assert_eq!(s[1], ()); + } + s[2] = (); + } + + #[test] + fn test_new_box_slice_zeroed_zst_empty() { + let s: Box<[()]> = <()>::new_box_slice_zeroed(0); + assert_eq!(s.len(), 0); + } + + #[test] + #[should_panic(expected = "mem::size_of::() * len overflows `usize`")] + fn test_new_box_slice_zeroed_panics_mul_overflow() { + let _ = u16::new_box_slice_zeroed(usize::MAX); + } + + #[test] + #[should_panic(expected = "assertion failed: size <= max_alloc")] + fn test_new_box_slice_zeroed_panics_isize_overflow() { + let max = usize::try_from(isize::MAX).unwrap(); + let _ = u16::new_box_slice_zeroed((max / mem::size_of::()) + 1); + } + } +} + +#[cfg(feature = "alloc")] +#[doc(inline)] +pub use alloc_support::*; + +#[cfg(test)] +mod tests { + #![allow(clippy::unreadable_literal)] + + use core::{cell::UnsafeCell, convert::TryInto as _, ops::Deref}; + + use static_assertions::assert_impl_all; + + use super::*; + use crate::util::testutil::*; + + // An unsized type. + // + // This is used to test the custom derives of our traits. The `[u8]` type + // gets a hand-rolled impl, so it doesn't exercise our custom derives. + #[derive(Debug, Eq, PartialEq, FromZeroes, FromBytes, AsBytes, Unaligned)] + #[repr(transparent)] + struct Unsized([u8]); + + impl Unsized { + fn from_mut_slice(slc: &mut [u8]) -> &mut Unsized { + // SAFETY: This *probably* sound - since the layouts of `[u8]` and + // `Unsized` are the same, so are the layouts of `&mut [u8]` and + // `&mut Unsized`. [1] Even if it turns out that this isn't actually + // guaranteed by the language spec, we can just change this since + // it's in test code. + // + // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/375 + unsafe { mem::transmute(slc) } + } + } + + /// Tests of when a sized `DstLayout` is extended with a sized field. + #[allow(clippy::decimal_literal_representation)] + #[test] + fn test_dst_layout_extend_sized_with_sized() { + // This macro constructs a layout corresponding to a `u8` and extends it + // with a zero-sized trailing field of given alignment `n`. The macro + // tests that the resulting layout has both size and alignment `min(n, + // P)` for all valid values of `repr(packed(P))`. + macro_rules! test_align_is_size { + ($n:expr) => { + let base = DstLayout::for_type::(); + let trailing_field = DstLayout::for_type::>(); + + let packs = + core::iter::once(None).chain((0..29).map(|p| NonZeroUsize::new(2usize.pow(p)))); + + for pack in packs { + let composite = base.extend(trailing_field, pack); + let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN); + let align = $n.min(max_align.get()); + assert_eq!( + composite, + DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::Sized { _size: align } + } + ) + } + }; + } + + test_align_is_size!(1); + test_align_is_size!(2); + test_align_is_size!(4); + test_align_is_size!(8); + test_align_is_size!(16); + test_align_is_size!(32); + test_align_is_size!(64); + test_align_is_size!(128); + test_align_is_size!(256); + test_align_is_size!(512); + test_align_is_size!(1024); + test_align_is_size!(2048); + test_align_is_size!(4096); + test_align_is_size!(8192); + test_align_is_size!(16384); + test_align_is_size!(32768); + test_align_is_size!(65536); + test_align_is_size!(131072); + test_align_is_size!(262144); + test_align_is_size!(524288); + test_align_is_size!(1048576); + test_align_is_size!(2097152); + test_align_is_size!(4194304); + test_align_is_size!(8388608); + test_align_is_size!(16777216); + test_align_is_size!(33554432); + test_align_is_size!(67108864); + test_align_is_size!(33554432); + test_align_is_size!(134217728); + test_align_is_size!(268435456); + } + + /// Tests of when a sized `DstLayout` is extended with a DST field. + #[test] + fn test_dst_layout_extend_sized_with_dst() { + // Test that for all combinations of real-world alignments and + // `repr_packed` values, that the extension of a sized `DstLayout`` with + // a DST field correctly computes the trailing offset in the composite + // layout. + + let aligns = (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()); + let packs = core::iter::once(None).chain(aligns.clone().map(Some)); + + for align in aligns { + for pack in packs.clone() { + let base = DstLayout::for_type::(); + let elem_size = 42; + let trailing_field_offset = 11; + + let trailing_field = DstLayout { + align, + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _elem_size: elem_size, + _offset: 11, + }), + }; + + let composite = base.extend(trailing_field, pack); + + let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN).get(); + + let align = align.get().min(max_align); + + assert_eq!( + composite, + DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _elem_size: elem_size, + _offset: align + trailing_field_offset, + }), + } + ) + } + } + } + + /// Tests that calling `pad_to_align` on a sized `DstLayout` adds the + /// expected amount of trailing padding. + #[test] + fn test_dst_layout_pad_to_align_with_sized() { + // For all valid alignments `align`, construct a one-byte layout aligned + // to `align`, call `pad_to_align`, and assert that the size of the + // resulting layout is equal to `align`. + for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) { + let layout = DstLayout { align, size_info: SizeInfo::Sized { _size: 1 } }; + + assert_eq!( + layout.pad_to_align(), + DstLayout { align, size_info: SizeInfo::Sized { _size: align.get() } } + ); + } + + // Test explicitly-provided combinations of unpadded and padded + // counterparts. + + macro_rules! test { + (unpadded { size: $unpadded_size:expr, align: $unpadded_align:expr } + => padded { size: $padded_size:expr, align: $padded_align:expr }) => { + let unpadded = DstLayout { + align: NonZeroUsize::new($unpadded_align).unwrap(), + size_info: SizeInfo::Sized { _size: $unpadded_size }, + }; + let padded = unpadded.pad_to_align(); + + assert_eq!( + padded, + DstLayout { + align: NonZeroUsize::new($padded_align).unwrap(), + size_info: SizeInfo::Sized { _size: $padded_size }, + } + ); + }; + } + + test!(unpadded { size: 0, align: 4 } => padded { size: 0, align: 4 }); + test!(unpadded { size: 1, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 2, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 3, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 4, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 5, align: 4 } => padded { size: 8, align: 4 }); + test!(unpadded { size: 6, align: 4 } => padded { size: 8, align: 4 }); + test!(unpadded { size: 7, align: 4 } => padded { size: 8, align: 4 }); + test!(unpadded { size: 8, align: 4 } => padded { size: 8, align: 4 }); + + let current_max_align = DstLayout::CURRENT_MAX_ALIGN.get(); + + test!(unpadded { size: 1, align: current_max_align } + => padded { size: current_max_align, align: current_max_align }); + + test!(unpadded { size: current_max_align + 1, align: current_max_align } + => padded { size: current_max_align * 2, align: current_max_align }); + } + + /// Tests that calling `pad_to_align` on a DST `DstLayout` is a no-op. + #[test] + fn test_dst_layout_pad_to_align_with_dst() { + for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) { + for offset in 0..10 { + for elem_size in 0..10 { + let layout = DstLayout { + align, + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }), + }; + assert_eq!(layout.pad_to_align(), layout); + } + } + } + } + + // This test takes a long time when running under Miri, so we skip it in + // that case. This is acceptable because this is a logic test that doesn't + // attempt to expose UB. + #[test] + #[cfg_attr(miri, ignore)] + fn testvalidate_cast_and_convert_metadata() { + impl From for SizeInfo { + fn from(_size: usize) -> SizeInfo { + SizeInfo::Sized { _size } + } + } + + impl From<(usize, usize)> for SizeInfo { + fn from((_offset, _elem_size): (usize, usize)) -> SizeInfo { + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) + } + } + + fn layout>(s: S, align: usize) -> DstLayout { + DstLayout { size_info: s.into(), align: NonZeroUsize::new(align).unwrap() } + } + + /// This macro accepts arguments in the form of: + /// + /// layout(_, _, _).validate(_, _, _), Ok(Some((_, _))) + /// | | | | | | | | + /// base_size ----+ | | | | | | | + /// align -----------+ | | | | | | + /// trailing_size ------+ | | | | | + /// addr ---------------------------+ | | | | + /// bytes_len -------------------------+ | | | + /// cast_type ----------------------------+ | | + /// elems ---------------------------------------------+ | + /// split_at ---------------------------------------------+ + /// + /// `.validate` is shorthand for `.validate_cast_and_convert_metadata` + /// for brevity. + /// + /// Each argument can either be an iterator or a wildcard. Each + /// wildcarded variable is implicitly replaced by an iterator over a + /// representative sample of values for that variable. Each `test!` + /// invocation iterates over every combination of values provided by + /// each variable's iterator (ie, the cartesian product) and validates + /// that the results are expected. + /// + /// The final argument uses the same syntax, but it has a different + /// meaning: + /// - If it is `Ok(pat)`, then the pattern `pat` is supplied to + /// `assert_matches!` to validate the computed result for each + /// combination of input values. + /// - If it is `Err(msg)`, then `test!` validates that the call to + /// `validate_cast_and_convert_metadata` panics with the given panic + /// message. + /// + /// Note that the meta-variables that match these variables have the + /// `tt` type, and some valid expressions are not valid `tt`s (such as + /// `a..b`). In this case, wrap the expression in parentheses, and it + /// will become valid `tt`. + macro_rules! test { + ($(:$sizes:expr =>)? + layout($size:tt, $align:tt) + .validate($addr:tt, $bytes_len:tt, $cast_type:tt), $expect:pat $(,)? + ) => { + itertools::iproduct!( + test!(@generate_size $size), + test!(@generate_align $align), + test!(@generate_usize $addr), + test!(@generate_usize $bytes_len), + test!(@generate_cast_type $cast_type) + ).for_each(|(size_info, align, addr, bytes_len, cast_type)| { + // Temporarily disable the panic hook installed by the test + // harness. If we don't do this, all panic messages will be + // kept in an internal log. On its own, this isn't a + // problem, but if a non-caught panic ever happens (ie, in + // code later in this test not in this macro), all of the + // previously-buffered messages will be dumped, hiding the + // real culprit. + let previous_hook = std::panic::take_hook(); + // I don't understand why, but this seems to be required in + // addition to the previous line. + std::panic::set_hook(Box::new(|_| {})); + let actual = std::panic::catch_unwind(|| { + layout(size_info, align).validate_cast_and_convert_metadata(addr, bytes_len, cast_type) + }).map_err(|d| { + *d.downcast::<&'static str>().expect("expected string panic message").as_ref() + }); + std::panic::set_hook(previous_hook); + + assert_matches::assert_matches!( + actual, $expect, + "layout({size_info:?}, {align}).validate_cast_and_convert_metadata({addr}, {bytes_len}, {cast_type:?})", + ); + }); + }; + (@generate_usize _) => { 0..8 }; + // Generate sizes for both Sized and !Sized types. + (@generate_size _) => { + test!(@generate_size (_)).chain(test!(@generate_size (_, _))) + }; + // Generate sizes for both Sized and !Sized types by chaining + // specified iterators for each. + (@generate_size ($sized_sizes:tt | $unsized_sizes:tt)) => { + test!(@generate_size ($sized_sizes)).chain(test!(@generate_size $unsized_sizes)) + }; + // Generate sizes for Sized types. + (@generate_size (_)) => { test!(@generate_size (0..8)) }; + (@generate_size ($sizes:expr)) => { $sizes.into_iter().map(Into::::into) }; + // Generate sizes for !Sized types. + (@generate_size ($min_sizes:tt, $elem_sizes:tt)) => { + itertools::iproduct!( + test!(@generate_min_size $min_sizes), + test!(@generate_elem_size $elem_sizes) + ).map(Into::::into) + }; + (@generate_fixed_size _) => { (0..8).into_iter().map(Into::::into) }; + (@generate_min_size _) => { 0..8 }; + (@generate_elem_size _) => { 1..8 }; + (@generate_align _) => { [1, 2, 4, 8, 16] }; + (@generate_opt_usize _) => { [None].into_iter().chain((0..8).map(Some).into_iter()) }; + (@generate_cast_type _) => { [_CastType::_Prefix, _CastType::_Suffix] }; + (@generate_cast_type $variant:ident) => { [_CastType::$variant] }; + // Some expressions need to be wrapped in parentheses in order to be + // valid `tt`s (required by the top match pattern). See the comment + // below for more details. This arm removes these parentheses to + // avoid generating an `unused_parens` warning. + (@$_:ident ($vals:expr)) => { $vals }; + (@$_:ident $vals:expr) => { $vals }; + } + + const EVENS: [usize; 8] = [0, 2, 4, 6, 8, 10, 12, 14]; + const ODDS: [usize; 8] = [1, 3, 5, 7, 9, 11, 13, 15]; + + // base_size is too big for the memory region. + test!(layout(((1..8) | ((1..8), (1..8))), _).validate(_, [0], _), Ok(None)); + test!(layout(((2..8) | ((2..8), (2..8))), _).validate(_, [1], _), Ok(None)); + + // addr is unaligned for prefix cast + test!(layout(_, [2]).validate(ODDS, _, _Prefix), Ok(None)); + test!(layout(_, [2]).validate(ODDS, _, _Prefix), Ok(None)); + + // addr is aligned, but end of buffer is unaligned for suffix cast + test!(layout(_, [2]).validate(EVENS, ODDS, _Suffix), Ok(None)); + test!(layout(_, [2]).validate(EVENS, ODDS, _Suffix), Ok(None)); + + // Unfortunately, these constants cannot easily be used in the + // implementation of `validate_cast_and_convert_metadata`, since + // `panic!` consumes a string literal, not an expression. + // + // It's important that these messages be in a separate module. If they + // were at the function's top level, we'd pass them to `test!` as, e.g., + // `Err(TRAILING)`, which would run into a subtle Rust footgun - the + // `TRAILING` identifier would be treated as a pattern to match rather + // than a value to check for equality. + mod msgs { + pub(super) const TRAILING: &str = + "attempted to cast to slice type with zero-sized element"; + pub(super) const OVERFLOW: &str = "`addr` + `bytes_len` > usize::MAX"; + } + + // casts with ZST trailing element types are unsupported + test!(layout((_, [0]), _).validate(_, _, _), Err(msgs::TRAILING),); + + // addr + bytes_len must not overflow usize + test!(layout(_, _).validate([usize::MAX], (1..100), _), Err(msgs::OVERFLOW)); + test!(layout(_, _).validate((1..100), [usize::MAX], _), Err(msgs::OVERFLOW)); + test!( + layout(_, _).validate( + [usize::MAX / 2 + 1, usize::MAX], + [usize::MAX / 2 + 1, usize::MAX], + _ + ), + Err(msgs::OVERFLOW) + ); + + // Validates that `validate_cast_and_convert_metadata` satisfies its own + // documented safety postconditions, and also a few other properties + // that aren't documented but we want to guarantee anyway. + fn validate_behavior( + (layout, addr, bytes_len, cast_type): (DstLayout, usize, usize, _CastType), + ) { + if let Some((elems, split_at)) = + layout.validate_cast_and_convert_metadata(addr, bytes_len, cast_type) + { + let (size_info, align) = (layout.size_info, layout.align); + let debug_str = format!( + "layout({size_info:?}, {align}).validate_cast_and_convert_metadata({addr}, {bytes_len}, {cast_type:?}) => ({elems}, {split_at})", + ); + + // If this is a sized type (no trailing slice), then `elems` is + // meaningless, but in practice we set it to 0. Callers are not + // allowed to rely on this, but a lot of math is nicer if + // they're able to, and some callers might accidentally do that. + let sized = matches!(layout.size_info, SizeInfo::Sized { .. }); + assert!(!(sized && elems != 0), "{}", debug_str); + + let resulting_size = match layout.size_info { + SizeInfo::Sized { _size } => _size, + SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }) => { + let padded_size = |elems| { + let without_padding = offset + elems * elem_size; + without_padding + + util::core_layout::padding_needed_for(without_padding, align) + }; + + let resulting_size = padded_size(elems); + // Test that `validate_cast_and_convert_metadata` + // computed the largest possible value that fits in the + // given range. + assert!(padded_size(elems + 1) > bytes_len, "{}", debug_str); + resulting_size + } + }; + + // Test safety postconditions guaranteed by + // `validate_cast_and_convert_metadata`. + assert!(resulting_size <= bytes_len, "{}", debug_str); + match cast_type { + _CastType::_Prefix => { + assert_eq!(addr % align, 0, "{}", debug_str); + assert_eq!(resulting_size, split_at, "{}", debug_str); + } + _CastType::_Suffix => { + assert_eq!(split_at, bytes_len - resulting_size, "{}", debug_str); + assert_eq!((addr + split_at) % align, 0, "{}", debug_str); + } + } + } else { + let min_size = match layout.size_info { + SizeInfo::Sized { _size } => _size, + SizeInfo::SliceDst(TrailingSliceLayout { _offset, .. }) => { + _offset + util::core_layout::padding_needed_for(_offset, layout.align) + } + }; + + // If a cast is invalid, it is either because... + // 1. there are insufficent bytes at the given region for type: + let insufficient_bytes = bytes_len < min_size; + // 2. performing the cast would misalign type: + let base = match cast_type { + _CastType::_Prefix => 0, + _CastType::_Suffix => bytes_len, + }; + let misaligned = (base + addr) % layout.align != 0; + + assert!(insufficient_bytes || misaligned); + } + } + + let sizes = 0..8; + let elem_sizes = 1..8; + let size_infos = sizes + .clone() + .map(Into::::into) + .chain(itertools::iproduct!(sizes, elem_sizes).map(Into::::into)); + let layouts = itertools::iproduct!(size_infos, [1, 2, 4, 8, 16, 32]) + .filter(|(size_info, align)| !matches!(size_info, SizeInfo::Sized { _size } if _size % align != 0)) + .map(|(size_info, align)| layout(size_info, align)); + itertools::iproduct!(layouts, 0..8, 0..8, [_CastType::_Prefix, _CastType::_Suffix]) + .for_each(validate_behavior); + } + + #[test] + #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] + fn test_validate_rust_layout() { + use core::ptr::NonNull; + + // This test synthesizes pointers with various metadata and uses Rust's + // built-in APIs to confirm that Rust makes decisions about type layout + // which are consistent with what we believe is guaranteed by the + // language. If this test fails, it doesn't just mean our code is wrong + // - it means we're misunderstanding the language's guarantees. + + #[derive(Debug)] + struct MacroArgs { + offset: usize, + align: NonZeroUsize, + elem_size: Option, + } + + /// # Safety + /// + /// `test` promises to only call `addr_of_slice_field` on a `NonNull` + /// which points to a valid `T`. + /// + /// `with_elems` must produce a pointer which points to a valid `T`. + fn test NonNull>( + args: MacroArgs, + with_elems: W, + addr_of_slice_field: Option) -> NonNull>, + ) { + let dst = args.elem_size.is_some(); + let layout = { + let size_info = match args.elem_size { + Some(elem_size) => SizeInfo::SliceDst(TrailingSliceLayout { + _offset: args.offset, + _elem_size: elem_size, + }), + None => SizeInfo::Sized { + // Rust only supports types whose sizes are a multiple + // of their alignment. If the macro created a type like + // this: + // + // #[repr(C, align(2))] + // struct Foo([u8; 1]); + // + // ...then Rust will automatically round the type's size + // up to 2. + _size: args.offset + + util::core_layout::padding_needed_for(args.offset, args.align), + }, + }; + DstLayout { size_info, align: args.align } + }; + + for elems in 0..128 { + let ptr = with_elems(elems); + + if let Some(addr_of_slice_field) = addr_of_slice_field { + let slc_field_ptr = addr_of_slice_field(ptr).as_ptr(); + // SAFETY: Both `slc_field_ptr` and `ptr` are pointers to + // the same valid Rust object. + let offset: usize = + unsafe { slc_field_ptr.byte_offset_from(ptr.as_ptr()).try_into().unwrap() }; + assert_eq!(offset, args.offset); + } + + // SAFETY: `ptr` points to a valid `T`. + let (size, align) = unsafe { + (mem::size_of_val_raw(ptr.as_ptr()), mem::align_of_val_raw(ptr.as_ptr())) + }; + + // Avoid expensive allocation when running under Miri. + let assert_msg = if !cfg!(miri) { + format!("\n{args:?}\nsize:{size}, align:{align}") + } else { + String::new() + }; + + let without_padding = + args.offset + args.elem_size.map(|elem_size| elems * elem_size).unwrap_or(0); + assert!(size >= without_padding, "{}", assert_msg); + assert_eq!(align, args.align.get(), "{}", assert_msg); + + // This encodes the most important part of the test: our + // understanding of how Rust determines the layout of repr(C) + // types. Sized repr(C) types are trivial, but DST types have + // some subtlety. Note that: + // - For sized types, `without_padding` is just the size of the + // type that we constructed for `Foo`. Since we may have + // requested a larger alignment, `Foo` may actually be larger + // than this, hence `padding_needed_for`. + // - For unsized types, `without_padding` is dynamically + // computed from the offset, the element size, and element + // count. We expect that the size of the object should be + // `offset + elem_size * elems` rounded up to the next + // alignment. + let expected_size = without_padding + + util::core_layout::padding_needed_for(without_padding, args.align); + assert_eq!(expected_size, size, "{}", assert_msg); + + // For zero-sized element types, + // `validate_cast_and_convert_metadata` just panics, so we skip + // testing those types. + if args.elem_size.map(|elem_size| elem_size > 0).unwrap_or(true) { + let addr = ptr.addr().get(); + let (got_elems, got_split_at) = layout + .validate_cast_and_convert_metadata(addr, size, _CastType::_Prefix) + .unwrap(); + // Avoid expensive allocation when running under Miri. + let assert_msg = if !cfg!(miri) { + format!( + "{}\nvalidate_cast_and_convert_metadata({addr}, {size})", + assert_msg + ) + } else { + String::new() + }; + assert_eq!(got_split_at, size, "{}", assert_msg); + if dst { + assert!(got_elems >= elems, "{}", assert_msg); + if got_elems != elems { + // If `validate_cast_and_convert_metadata` + // returned more elements than `elems`, that + // means that `elems` is not the maximum number + // of elements that can fit in `size` - in other + // words, there is enough padding at the end of + // the value to fit at least one more element. + // If we use this metadata to synthesize a + // pointer, despite having a different element + // count, we still expect it to have the same + // size. + let got_ptr = with_elems(got_elems); + // SAFETY: `got_ptr` is a pointer to a valid `T`. + let size_of_got_ptr = unsafe { mem::size_of_val_raw(got_ptr.as_ptr()) }; + assert_eq!(size_of_got_ptr, size, "{}", assert_msg); + } + } else { + // For sized casts, the returned element value is + // technically meaningless, and we don't guarantee any + // particular value. In practice, it's always zero. + assert_eq!(got_elems, 0, "{}", assert_msg) + } + } + } + } + + macro_rules! validate_against_rust { + ($offset:literal, $align:literal $(, $elem_size:literal)?) => {{ + #[repr(C, align($align))] + struct Foo([u8; $offset]$(, [[u8; $elem_size]])?); + + let args = MacroArgs { + offset: $offset, + align: $align.try_into().unwrap(), + elem_size: { + #[allow(unused)] + let ret = None::; + $(let ret = Some($elem_size);)? + ret + } + }; + + #[repr(C, align($align))] + struct FooAlign; + // Create an aligned buffer to use in order to synthesize + // pointers to `Foo`. We don't ever load values from these + // pointers - we just do arithmetic on them - so having a "real" + // block of memory as opposed to a validly-aligned-but-dangling + // pointer is only necessary to make Miri happy since we run it + // with "strict provenance" checking enabled. + let aligned_buf = Align::<_, FooAlign>::new([0u8; 1024]); + let with_elems = |elems| { + let slc = NonNull::slice_from_raw_parts(NonNull::from(&aligned_buf.t), elems); + #[allow(clippy::as_conversions)] + NonNull::new(slc.as_ptr() as *mut Foo).unwrap() + }; + let addr_of_slice_field = { + #[allow(unused)] + let f = None::) -> NonNull>; + $( + // SAFETY: `test` promises to only call `f` with a `ptr` + // to a valid `Foo`. + let f: Option) -> NonNull> = Some(|ptr: NonNull| unsafe { + NonNull::new(ptr::addr_of_mut!((*ptr.as_ptr()).1)).unwrap().cast::() + }); + let _ = $elem_size; + )? + f + }; + + test::(args, with_elems, addr_of_slice_field); + }}; + } + + // Every permutation of: + // - offset in [0, 4] + // - align in [1, 16] + // - elem_size in [0, 4] (plus no elem_size) + validate_against_rust!(0, 1); + validate_against_rust!(0, 1, 0); + validate_against_rust!(0, 1, 1); + validate_against_rust!(0, 1, 2); + validate_against_rust!(0, 1, 3); + validate_against_rust!(0, 1, 4); + validate_against_rust!(0, 2); + validate_against_rust!(0, 2, 0); + validate_against_rust!(0, 2, 1); + validate_against_rust!(0, 2, 2); + validate_against_rust!(0, 2, 3); + validate_against_rust!(0, 2, 4); + validate_against_rust!(0, 4); + validate_against_rust!(0, 4, 0); + validate_against_rust!(0, 4, 1); + validate_against_rust!(0, 4, 2); + validate_against_rust!(0, 4, 3); + validate_against_rust!(0, 4, 4); + validate_against_rust!(0, 8); + validate_against_rust!(0, 8, 0); + validate_against_rust!(0, 8, 1); + validate_against_rust!(0, 8, 2); + validate_against_rust!(0, 8, 3); + validate_against_rust!(0, 8, 4); + validate_against_rust!(0, 16); + validate_against_rust!(0, 16, 0); + validate_against_rust!(0, 16, 1); + validate_against_rust!(0, 16, 2); + validate_against_rust!(0, 16, 3); + validate_against_rust!(0, 16, 4); + validate_against_rust!(1, 1); + validate_against_rust!(1, 1, 0); + validate_against_rust!(1, 1, 1); + validate_against_rust!(1, 1, 2); + validate_against_rust!(1, 1, 3); + validate_against_rust!(1, 1, 4); + validate_against_rust!(1, 2); + validate_against_rust!(1, 2, 0); + validate_against_rust!(1, 2, 1); + validate_against_rust!(1, 2, 2); + validate_against_rust!(1, 2, 3); + validate_against_rust!(1, 2, 4); + validate_against_rust!(1, 4); + validate_against_rust!(1, 4, 0); + validate_against_rust!(1, 4, 1); + validate_against_rust!(1, 4, 2); + validate_against_rust!(1, 4, 3); + validate_against_rust!(1, 4, 4); + validate_against_rust!(1, 8); + validate_against_rust!(1, 8, 0); + validate_against_rust!(1, 8, 1); + validate_against_rust!(1, 8, 2); + validate_against_rust!(1, 8, 3); + validate_against_rust!(1, 8, 4); + validate_against_rust!(1, 16); + validate_against_rust!(1, 16, 0); + validate_against_rust!(1, 16, 1); + validate_against_rust!(1, 16, 2); + validate_against_rust!(1, 16, 3); + validate_against_rust!(1, 16, 4); + validate_against_rust!(2, 1); + validate_against_rust!(2, 1, 0); + validate_against_rust!(2, 1, 1); + validate_against_rust!(2, 1, 2); + validate_against_rust!(2, 1, 3); + validate_against_rust!(2, 1, 4); + validate_against_rust!(2, 2); + validate_against_rust!(2, 2, 0); + validate_against_rust!(2, 2, 1); + validate_against_rust!(2, 2, 2); + validate_against_rust!(2, 2, 3); + validate_against_rust!(2, 2, 4); + validate_against_rust!(2, 4); + validate_against_rust!(2, 4, 0); + validate_against_rust!(2, 4, 1); + validate_against_rust!(2, 4, 2); + validate_against_rust!(2, 4, 3); + validate_against_rust!(2, 4, 4); + validate_against_rust!(2, 8); + validate_against_rust!(2, 8, 0); + validate_against_rust!(2, 8, 1); + validate_against_rust!(2, 8, 2); + validate_against_rust!(2, 8, 3); + validate_against_rust!(2, 8, 4); + validate_against_rust!(2, 16); + validate_against_rust!(2, 16, 0); + validate_against_rust!(2, 16, 1); + validate_against_rust!(2, 16, 2); + validate_against_rust!(2, 16, 3); + validate_against_rust!(2, 16, 4); + validate_against_rust!(3, 1); + validate_against_rust!(3, 1, 0); + validate_against_rust!(3, 1, 1); + validate_against_rust!(3, 1, 2); + validate_against_rust!(3, 1, 3); + validate_against_rust!(3, 1, 4); + validate_against_rust!(3, 2); + validate_against_rust!(3, 2, 0); + validate_against_rust!(3, 2, 1); + validate_against_rust!(3, 2, 2); + validate_against_rust!(3, 2, 3); + validate_against_rust!(3, 2, 4); + validate_against_rust!(3, 4); + validate_against_rust!(3, 4, 0); + validate_against_rust!(3, 4, 1); + validate_against_rust!(3, 4, 2); + validate_against_rust!(3, 4, 3); + validate_against_rust!(3, 4, 4); + validate_against_rust!(3, 8); + validate_against_rust!(3, 8, 0); + validate_against_rust!(3, 8, 1); + validate_against_rust!(3, 8, 2); + validate_against_rust!(3, 8, 3); + validate_against_rust!(3, 8, 4); + validate_against_rust!(3, 16); + validate_against_rust!(3, 16, 0); + validate_against_rust!(3, 16, 1); + validate_against_rust!(3, 16, 2); + validate_against_rust!(3, 16, 3); + validate_against_rust!(3, 16, 4); + validate_against_rust!(4, 1); + validate_against_rust!(4, 1, 0); + validate_against_rust!(4, 1, 1); + validate_against_rust!(4, 1, 2); + validate_against_rust!(4, 1, 3); + validate_against_rust!(4, 1, 4); + validate_against_rust!(4, 2); + validate_against_rust!(4, 2, 0); + validate_against_rust!(4, 2, 1); + validate_against_rust!(4, 2, 2); + validate_against_rust!(4, 2, 3); + validate_against_rust!(4, 2, 4); + validate_against_rust!(4, 4); + validate_against_rust!(4, 4, 0); + validate_against_rust!(4, 4, 1); + validate_against_rust!(4, 4, 2); + validate_against_rust!(4, 4, 3); + validate_against_rust!(4, 4, 4); + validate_against_rust!(4, 8); + validate_against_rust!(4, 8, 0); + validate_against_rust!(4, 8, 1); + validate_against_rust!(4, 8, 2); + validate_against_rust!(4, 8, 3); + validate_against_rust!(4, 8, 4); + validate_against_rust!(4, 16); + validate_against_rust!(4, 16, 0); + validate_against_rust!(4, 16, 1); + validate_against_rust!(4, 16, 2); + validate_against_rust!(4, 16, 3); + validate_against_rust!(4, 16, 4); + } + + #[test] + fn test_known_layout() { + // Test that `$ty` and `ManuallyDrop<$ty>` have the expected layout. + // Test that `PhantomData<$ty>` has the same layout as `()` regardless + // of `$ty`. + macro_rules! test { + ($ty:ty, $expect:expr) => { + let expect = $expect; + assert_eq!(<$ty as KnownLayout>::LAYOUT, expect); + assert_eq!( as KnownLayout>::LAYOUT, expect); + assert_eq!( as KnownLayout>::LAYOUT, <() as KnownLayout>::LAYOUT); + }; + } + + let layout = |offset, align, _trailing_slice_elem_size| DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: match _trailing_slice_elem_size { + None => SizeInfo::Sized { _size: offset }, + Some(elem_size) => SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }), + }, + }; + + test!((), layout(0, 1, None)); + test!(u8, layout(1, 1, None)); + // Use `align_of` because `u64` alignment may be smaller than 8 on some + // platforms. + test!(u64, layout(8, mem::align_of::(), None)); + test!(AU64, layout(8, 8, None)); + + test!(Option<&'static ()>, usize::LAYOUT); + + test!([()], layout(0, 1, Some(0))); + test!([u8], layout(0, 1, Some(1))); + test!(str, layout(0, 1, Some(1))); + } + + #[cfg(feature = "derive")] + #[test] + fn test_known_layout_derive() { + // In this and other files (`late_compile_pass.rs`, + // `mid_compile_pass.rs`, and `struct.rs`), we test success and failure + // modes of `derive(KnownLayout)` for the following combination of + // properties: + // + // +------------+--------------------------------------+-----------+ + // | | trailing field properties | | + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // |------------+----------+----------------+----------+-----------| + // | N | N | N | N | KL00 | + // | N | N | N | Y | KL01 | + // | N | N | Y | N | KL02 | + // | N | N | Y | Y | KL03 | + // | N | Y | N | N | KL04 | + // | N | Y | N | Y | KL05 | + // | N | Y | Y | N | KL06 | + // | N | Y | Y | Y | KL07 | + // | Y | N | N | N | KL08 | + // | Y | N | N | Y | KL09 | + // | Y | N | Y | N | KL10 | + // | Y | N | Y | Y | KL11 | + // | Y | Y | N | N | KL12 | + // | Y | Y | N | Y | KL13 | + // | Y | Y | Y | N | KL14 | + // | Y | Y | Y | Y | KL15 | + // +------------+----------+----------------+----------+-----------+ + + struct NotKnownLayout { + _t: T, + } + + #[derive(KnownLayout)] + #[repr(C)] + struct AlignSize + where + elain::Align: elain::Alignment, + { + _align: elain::Align, + _size: [u8; SIZE], + } + + type AU16 = AlignSize<2, 2>; + type AU32 = AlignSize<4, 4>; + + fn _assert_kl(_: &T) {} + + let sized_layout = |align, size| DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::Sized { _size: size }, + }; + + let unsized_layout = |align, elem_size, offset| DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }), + }; + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | N | N | Y | KL01 | + #[derive(KnownLayout)] + struct KL01(NotKnownLayout, NotKnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(4, 8)); + + // ...with `align(N)`: + #[derive(KnownLayout)] + #[repr(align(64))] + struct KL01Align(NotKnownLayout, NotKnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(64, 64)); + + // ...with `packed`: + #[derive(KnownLayout)] + #[repr(packed)] + struct KL01Packed(NotKnownLayout, NotKnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 6)); + + // ...with `packed(N)`: + #[derive(KnownLayout)] + #[repr(packed(2))] + struct KL01PackedN(NotKnownLayout, NotKnownLayout); + + assert_impl_all!(KL01PackedN: KnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(2, 6)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | N | Y | Y | KL03 | + #[derive(KnownLayout)] + struct KL03(NotKnownLayout, u8); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 1)); + + // ... with `align(N)` + #[derive(KnownLayout)] + #[repr(align(64))] + struct KL03Align(NotKnownLayout, u8); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(64, 64)); + + // ... with `packed`: + #[derive(KnownLayout)] + #[repr(packed)] + struct KL03Packed(NotKnownLayout, u8); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 5)); + + // ... with `packed(N)` + #[derive(KnownLayout)] + #[repr(packed(2))] + struct KL03PackedN(NotKnownLayout, u8); + + assert_impl_all!(KL03PackedN: KnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(2, 6)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | Y | N | Y | KL05 | + #[derive(KnownLayout)] + struct KL05(u8, T); + + fn _test_kl05(t: T) -> impl KnownLayout { + KL05(0u8, t) + } + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | Y | Y | Y | KL07 | + #[derive(KnownLayout)] + struct KL07(u8, T); + + fn _test_kl07(t: T) -> impl KnownLayout { + let _ = KL07(0u8, t); + } + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | N | Y | N | KL10 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL10(NotKnownLayout, [u8]); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), None) + .extend(<[u8] as KnownLayout>::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(4, 1, 4)); + + // ...with `align(N)`: + #[derive(KnownLayout)] + #[repr(C, align(64))] + struct KL10Align(NotKnownLayout, [u8]); + + let repr_align = NonZeroUsize::new(64); + + let expected = DstLayout::new_zst(repr_align) + .extend(DstLayout::for_type::>(), None) + .extend(<[u8] as KnownLayout>::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(64, 1, 4)); + + // ...with `packed`: + #[derive(KnownLayout)] + #[repr(C, packed)] + struct KL10Packed(NotKnownLayout, [u8]); + + let repr_packed = NonZeroUsize::new(1); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(1, 1, 4)); + + // ...with `packed(N)`: + #[derive(KnownLayout)] + #[repr(C, packed(2))] + struct KL10PackedN(NotKnownLayout, [u8]); + + let repr_packed = NonZeroUsize::new(2); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(2, 1, 4)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | N | Y | Y | KL11 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL11(NotKnownLayout, u8); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), None) + .extend(::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(8, 16)); + + // ...with `align(N)`: + #[derive(KnownLayout)] + #[repr(C, align(64))] + struct KL11Align(NotKnownLayout, u8); + + let repr_align = NonZeroUsize::new(64); + + let expected = DstLayout::new_zst(repr_align) + .extend(DstLayout::for_type::>(), None) + .extend(::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(64, 64)); + + // ...with `packed`: + #[derive(KnownLayout)] + #[repr(C, packed)] + struct KL11Packed(NotKnownLayout, u8); + + let repr_packed = NonZeroUsize::new(1); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 9)); + + // ...with `packed(N)`: + #[derive(KnownLayout)] + #[repr(C, packed(2))] + struct KL11PackedN(NotKnownLayout, u8); + + let repr_packed = NonZeroUsize::new(2); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(2, 10)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | Y | Y | N | KL14 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL14(u8, T); + + fn _test_kl14(kl: &KL14) { + _assert_kl(kl) + } + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | Y | Y | Y | KL15 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL15(u8, T); + + fn _test_kl15(t: T) -> impl KnownLayout { + let _ = KL15(0u8, t); + } + + // Test a variety of combinations of field types: + // - () + // - u8 + // - AU16 + // - [()] + // - [u8] + // - [AU16] + + #[allow(clippy::upper_case_acronyms)] + #[derive(KnownLayout)] + #[repr(C)] + struct KLTU(T, U); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 0, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 0, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 0, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 1, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2)); + + // Test a variety of field counts. + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF0; + + assert_eq!(::LAYOUT, sized_layout(1, 0)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF1([u8]); + + assert_eq!(::LAYOUT, unsized_layout(1, 1, 0)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF2(NotKnownLayout, [u8]); + + assert_eq!(::LAYOUT, unsized_layout(1, 1, 1)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF3(NotKnownLayout, NotKnownLayout, [u8]); + + assert_eq!(::LAYOUT, unsized_layout(2, 1, 4)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF4(NotKnownLayout, NotKnownLayout, NotKnownLayout, [u8]); + + assert_eq!(::LAYOUT, unsized_layout(4, 1, 8)); + } + + #[test] + fn test_object_safety() { + fn _takes_from_zeroes(_: &dyn FromZeroes) {} + fn _takes_from_bytes(_: &dyn FromBytes) {} + fn _takes_unaligned(_: &dyn Unaligned) {} + } + + #[test] + fn test_from_zeroes_only() { + // Test types that implement `FromZeroes` but not `FromBytes`. + + assert!(!bool::new_zeroed()); + assert_eq!(char::new_zeroed(), '\0'); + + #[cfg(feature = "alloc")] + { + assert_eq!(bool::new_box_zeroed(), Box::new(false)); + assert_eq!(char::new_box_zeroed(), Box::new('\0')); + + assert_eq!(bool::new_box_slice_zeroed(3).as_ref(), [false, false, false]); + assert_eq!(char::new_box_slice_zeroed(3).as_ref(), ['\0', '\0', '\0']); + + assert_eq!(bool::new_vec_zeroed(3).as_ref(), [false, false, false]); + assert_eq!(char::new_vec_zeroed(3).as_ref(), ['\0', '\0', '\0']); + } + + let mut string = "hello".to_string(); + let s: &mut str = string.as_mut(); + assert_eq!(s, "hello"); + s.zero(); + assert_eq!(s, "\0\0\0\0\0"); + } + + #[test] + fn test_read_write() { + const VAL: u64 = 0x12345678; + #[cfg(target_endian = "big")] + const VAL_BYTES: [u8; 8] = VAL.to_be_bytes(); + #[cfg(target_endian = "little")] + const VAL_BYTES: [u8; 8] = VAL.to_le_bytes(); + + // Test `FromBytes::{read_from, read_from_prefix, read_from_suffix}`. + + assert_eq!(u64::read_from(&VAL_BYTES[..]), Some(VAL)); + // The first 8 bytes are from `VAL_BYTES` and the second 8 bytes are all + // zeroes. + let bytes_with_prefix: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); + assert_eq!(u64::read_from_prefix(&bytes_with_prefix[..]), Some(VAL)); + assert_eq!(u64::read_from_suffix(&bytes_with_prefix[..]), Some(0)); + // The first 8 bytes are all zeroes and the second 8 bytes are from + // `VAL_BYTES` + let bytes_with_suffix: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); + assert_eq!(u64::read_from_prefix(&bytes_with_suffix[..]), Some(0)); + assert_eq!(u64::read_from_suffix(&bytes_with_suffix[..]), Some(VAL)); + + // Test `AsBytes::{write_to, write_to_prefix, write_to_suffix}`. + + let mut bytes = [0u8; 8]; + assert_eq!(VAL.write_to(&mut bytes[..]), Some(())); + assert_eq!(bytes, VAL_BYTES); + let mut bytes = [0u8; 16]; + assert_eq!(VAL.write_to_prefix(&mut bytes[..]), Some(())); + let want: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); + assert_eq!(bytes, want); + let mut bytes = [0u8; 16]; + assert_eq!(VAL.write_to_suffix(&mut bytes[..]), Some(())); + let want: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); + assert_eq!(bytes, want); + } + + #[test] + fn test_transmute() { + // Test that memory is transmuted as expected. + let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; + let x: [[u8; 2]; 4] = transmute!(array_of_u8s); + assert_eq!(x, array_of_arrays); + let x: [u8; 8] = transmute!(array_of_arrays); + assert_eq!(x, array_of_u8s); + + // Test that the source expression's value is forgotten rather than + // dropped. + #[derive(AsBytes)] + #[repr(transparent)] + struct PanicOnDrop(()); + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop::drop"); + } + } + #[allow(clippy::let_unit_value)] + let _: () = transmute!(PanicOnDrop(())); + + // Test that `transmute!` is legal in a const context. + const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; + const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; + const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S); + assert_eq!(X, ARRAY_OF_ARRAYS); + } + + #[test] + fn test_transmute_ref() { + // Test that memory is transmuted as expected. + let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; + let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s); + assert_eq!(*x, array_of_arrays); + let x: &[u8; 8] = transmute_ref!(&array_of_arrays); + assert_eq!(*x, array_of_u8s); + + // Test that `transmute_ref!` is legal in a const context. + const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; + const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; + #[allow(clippy::redundant_static_lifetimes)] + const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S); + assert_eq!(*X, ARRAY_OF_ARRAYS); + + // Test that it's legal to transmute a reference while shrinking the + // lifetime (note that `X` has the lifetime `'static`). + let x: &[u8; 8] = transmute_ref!(X); + assert_eq!(*x, ARRAY_OF_U8S); + + // Test that `transmute_ref!` supports decreasing alignment. + let u = AU64(0); + let array = [0, 0, 0, 0, 0, 0, 0, 0]; + let x: &[u8; 8] = transmute_ref!(&u); + assert_eq!(*x, array); + + // Test that a mutable reference can be turned into an immutable one. + let mut x = 0u8; + #[allow(clippy::useless_transmute)] + let y: &u8 = transmute_ref!(&mut x); + assert_eq!(*y, 0); + } + + #[test] + fn test_transmute_mut() { + // Test that memory is transmuted as expected. + let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; + let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s); + assert_eq!(*x, array_of_arrays); + let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); + assert_eq!(*x, array_of_u8s); + + { + // Test that it's legal to transmute a reference while shrinking the + // lifetime. + let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); + assert_eq!(*x, array_of_u8s); + } + // Test that `transmute_mut!` supports decreasing alignment. + let mut u = AU64(0); + let array = [0, 0, 0, 0, 0, 0, 0, 0]; + let x: &[u8; 8] = transmute_mut!(&mut u); + assert_eq!(*x, array); + + // Test that a mutable reference can be turned into an immutable one. + let mut x = 0u8; + #[allow(clippy::useless_transmute)] + let y: &u8 = transmute_mut!(&mut x); + assert_eq!(*y, 0); + } + + #[test] + fn test_macros_evaluate_args_once() { + let mut ctr = 0; + let _: usize = transmute!({ + ctr += 1; + 0usize + }); + assert_eq!(ctr, 1); + + let mut ctr = 0; + let _: &usize = transmute_ref!({ + ctr += 1; + &0usize + }); + assert_eq!(ctr, 1); + } + + #[test] + fn test_include_value() { + const AS_U32: u32 = include_value!("../testdata/include_value/data"); + assert_eq!(AS_U32, u32::from_ne_bytes([b'a', b'b', b'c', b'd'])); + const AS_I32: i32 = include_value!("../testdata/include_value/data"); + assert_eq!(AS_I32, i32::from_ne_bytes([b'a', b'b', b'c', b'd'])); + } + + #[test] + fn test_address() { + // Test that the `Deref` and `DerefMut` implementations return a + // reference which points to the right region of memory. + + let buf = [0]; + let r = Ref::<_, u8>::new(&buf[..]).unwrap(); + let buf_ptr = buf.as_ptr(); + let deref_ptr: *const u8 = r.deref(); + assert_eq!(buf_ptr, deref_ptr); + + let buf = [0]; + let r = Ref::<_, [u8]>::new_slice(&buf[..]).unwrap(); + let buf_ptr = buf.as_ptr(); + let deref_ptr = r.deref().as_ptr(); + assert_eq!(buf_ptr, deref_ptr); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations, that reads via `deref` and `read` + // behave the same, and that writes via `deref_mut` and `write` behave the + // same. + fn test_new_helper(mut r: Ref<&mut [u8], AU64>) { + // assert that the value starts at 0 + assert_eq!(*r, AU64(0)); + assert_eq!(r.read(), AU64(0)); + + // Assert that values written to the typed value are reflected in the + // byte slice. + const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); + *r = VAL1; + assert_eq!(r.bytes(), &VAL1.to_bytes()); + *r = AU64(0); + r.write(VAL1); + assert_eq!(r.bytes(), &VAL1.to_bytes()); + + // Assert that values written to the byte slice are reflected in the + // typed value. + const VAL2: AU64 = AU64(!VAL1.0); // different from `VAL1` + r.bytes_mut().copy_from_slice(&VAL2.to_bytes()[..]); + assert_eq!(*r, VAL2); + assert_eq!(r.read(), VAL2); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations; pass a value with `typed_len` `AU64`s + // backed by an array of `typed_len * 8` bytes. + fn test_new_helper_slice(mut r: Ref<&mut [u8], [AU64]>, typed_len: usize) { + // Assert that the value starts out zeroed. + assert_eq!(&*r, vec![AU64(0); typed_len].as_slice()); + + // Check the backing storage is the exact same slice. + let untyped_len = typed_len * 8; + assert_eq!(r.bytes().len(), untyped_len); + assert_eq!(r.bytes().as_ptr(), r.as_ptr().cast::()); + + // Assert that values written to the typed value are reflected in the + // byte slice. + const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); + for typed in &mut *r { + *typed = VAL1; + } + assert_eq!(r.bytes(), VAL1.0.to_ne_bytes().repeat(typed_len).as_slice()); + + // Assert that values written to the byte slice are reflected in the + // typed value. + const VAL2: AU64 = AU64(!VAL1.0); // different from VAL1 + r.bytes_mut().copy_from_slice(&VAL2.0.to_ne_bytes().repeat(typed_len)); + assert!(r.iter().copied().all(|x| x == VAL2)); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations, that reads via `deref` and `read` + // behave the same, and that writes via `deref_mut` and `write` behave the + // same. + fn test_new_helper_unaligned(mut r: Ref<&mut [u8], [u8; 8]>) { + // assert that the value starts at 0 + assert_eq!(*r, [0; 8]); + assert_eq!(r.read(), [0; 8]); + + // Assert that values written to the typed value are reflected in the + // byte slice. + const VAL1: [u8; 8] = [0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00]; + *r = VAL1; + assert_eq!(r.bytes(), &VAL1); + *r = [0; 8]; + r.write(VAL1); + assert_eq!(r.bytes(), &VAL1); + + // Assert that values written to the byte slice are reflected in the + // typed value. + const VAL2: [u8; 8] = [0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF]; // different from VAL1 + r.bytes_mut().copy_from_slice(&VAL2[..]); + assert_eq!(*r, VAL2); + assert_eq!(r.read(), VAL2); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations; pass a value with `len` `u8`s backed + // by an array of `len` bytes. + fn test_new_helper_slice_unaligned(mut r: Ref<&mut [u8], [u8]>, len: usize) { + // Assert that the value starts out zeroed. + assert_eq!(&*r, vec![0u8; len].as_slice()); + + // Check the backing storage is the exact same slice. + assert_eq!(r.bytes().len(), len); + assert_eq!(r.bytes().as_ptr(), r.as_ptr()); + + // Assert that values written to the typed value are reflected in the + // byte slice. + let mut expected_bytes = [0xFF, 0x00].iter().copied().cycle().take(len).collect::>(); + r.copy_from_slice(&expected_bytes); + assert_eq!(r.bytes(), expected_bytes.as_slice()); + + // Assert that values written to the byte slice are reflected in the + // typed value. + for byte in &mut expected_bytes { + *byte = !*byte; // different from `expected_len` + } + r.bytes_mut().copy_from_slice(&expected_bytes); + assert_eq!(&*r, expected_bytes.as_slice()); + } + + #[test] + fn test_new_aligned_sized() { + // Test that a properly-aligned, properly-sized buffer works for new, + // new_from_prefix, and new_from_suffix, and that new_from_prefix and + // new_from_suffix return empty slices. Test that a properly-aligned + // buffer whose length is a multiple of the element size works for + // new_slice. Test that xxx_zeroed behaves the same, and zeroes the + // memory. + + // A buffer with an alignment of 8. + let mut buf = Align::<[u8; 8], AU64>::default(); + // `buf.t` should be aligned to 8, so this should always succeed. + test_new_helper(Ref::<_, AU64>::new(&mut buf.t[..]).unwrap()); + let ascending: [u8; 8] = (0..8).collect::>().try_into().unwrap(); + buf.t = ascending; + test_new_helper(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).unwrap()); + { + // In a block so that `r` and `suffix` don't live too long. + buf.set_default(); + let (r, suffix) = Ref::<_, AU64>::new_from_prefix(&mut buf.t[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper(r); + } + { + buf.t = ascending; + let (r, suffix) = Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper(r); + } + { + buf.set_default(); + let (prefix, r) = Ref::<_, AU64>::new_from_suffix(&mut buf.t[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper(r); + } + { + buf.t = ascending; + let (prefix, r) = Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper(r); + } + + // A buffer with alignment 8 and length 24. We choose this length very + // intentionally: if we instead used length 16, then the prefix and + // suffix lengths would be identical. In the past, we used length 16, + // which resulted in this test failing to discover the bug uncovered in + // #506. + let mut buf = Align::<[u8; 24], AU64>::default(); + // `buf.t` should be aligned to 8 and have a length which is a multiple + // of `size_of::()`, so this should always succeed. + test_new_helper_slice(Ref::<_, [AU64]>::new_slice(&mut buf.t[..]).unwrap(), 3); + let ascending: [u8; 24] = (0..24).collect::>().try_into().unwrap(); + // 16 ascending bytes followed by 8 zeros. + let mut ascending_prefix = ascending; + ascending_prefix[16..].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); + // 8 zeros followed by 16 ascending bytes. + let mut ascending_suffix = ascending; + ascending_suffix[..8].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); + test_new_helper_slice(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[..]).unwrap(), 3); + + { + buf.t = ascending_suffix; + let (r, suffix) = Ref::<_, [AU64]>::new_slice_from_prefix(&mut buf.t[..], 1).unwrap(); + assert_eq!(suffix, &ascending[8..]); + test_new_helper_slice(r, 1); + } + { + buf.t = ascending_suffix; + let (r, suffix) = + Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], 1).unwrap(); + assert_eq!(suffix, &ascending[8..]); + test_new_helper_slice(r, 1); + } + { + buf.t = ascending_prefix; + let (prefix, r) = Ref::<_, [AU64]>::new_slice_from_suffix(&mut buf.t[..], 1).unwrap(); + assert_eq!(prefix, &ascending[..16]); + test_new_helper_slice(r, 1); + } + { + buf.t = ascending_prefix; + let (prefix, r) = + Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], 1).unwrap(); + assert_eq!(prefix, &ascending[..16]); + test_new_helper_slice(r, 1); + } + } + + #[test] + fn test_new_unaligned_sized() { + // Test that an unaligned, properly-sized buffer works for + // `new_unaligned`, `new_unaligned_from_prefix`, and + // `new_unaligned_from_suffix`, and that `new_unaligned_from_prefix` + // `new_unaligned_from_suffix` return empty slices. Test that an + // unaligned buffer whose length is a multiple of the element size works + // for `new_slice`. Test that `xxx_zeroed` behaves the same, and zeroes + // the memory. + + let mut buf = [0u8; 8]; + test_new_helper_unaligned(Ref::<_, [u8; 8]>::new_unaligned(&mut buf[..]).unwrap()); + buf = [0xFFu8; 8]; + test_new_helper_unaligned(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf[..]).unwrap()); + { + // In a block so that `r` and `suffix` don't live too long. + buf = [0u8; 8]; + let (r, suffix) = Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 8]; + let (r, suffix) = + Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper_unaligned(r); + } + { + buf = [0u8; 8]; + let (prefix, r) = Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 8]; + let (prefix, r) = + Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper_unaligned(r); + } + + let mut buf = [0u8; 16]; + // `buf.t` should be aligned to 8 and have a length which is a multiple + // of `size_of::AU64>()`, so this should always succeed. + test_new_helper_slice_unaligned( + Ref::<_, [u8]>::new_slice_unaligned(&mut buf[..]).unwrap(), + 16, + ); + buf = [0xFFu8; 16]; + test_new_helper_slice_unaligned( + Ref::<_, [u8]>::new_slice_unaligned_zeroed(&mut buf[..]).unwrap(), + 16, + ); + + { + buf = [0u8; 16]; + let (r, suffix) = + Ref::<_, [u8]>::new_slice_unaligned_from_prefix(&mut buf[..], 8).unwrap(); + assert_eq!(suffix, [0; 8]); + test_new_helper_slice_unaligned(r, 8); + } + { + buf = [0xFFu8; 16]; + let (r, suffix) = + Ref::<_, [u8]>::new_slice_unaligned_from_prefix_zeroed(&mut buf[..], 8).unwrap(); + assert_eq!(suffix, [0xFF; 8]); + test_new_helper_slice_unaligned(r, 8); + } + { + buf = [0u8; 16]; + let (prefix, r) = + Ref::<_, [u8]>::new_slice_unaligned_from_suffix(&mut buf[..], 8).unwrap(); + assert_eq!(prefix, [0; 8]); + test_new_helper_slice_unaligned(r, 8); + } + { + buf = [0xFFu8; 16]; + let (prefix, r) = + Ref::<_, [u8]>::new_slice_unaligned_from_suffix_zeroed(&mut buf[..], 8).unwrap(); + assert_eq!(prefix, [0xFF; 8]); + test_new_helper_slice_unaligned(r, 8); + } + } + + #[test] + fn test_new_oversized() { + // Test that a properly-aligned, overly-sized buffer works for + // `new_from_prefix` and `new_from_suffix`, and that they return the + // remainder and prefix of the slice respectively. Test that + // `xxx_zeroed` behaves the same, and zeroes the memory. + + let mut buf = Align::<[u8; 16], AU64>::default(); + { + // In a block so that `r` and `suffix` don't live too long. `buf.t` + // should be aligned to 8, so this should always succeed. + let (r, suffix) = Ref::<_, AU64>::new_from_prefix(&mut buf.t[..]).unwrap(); + assert_eq!(suffix.len(), 8); + test_new_helper(r); + } + { + buf.t = [0xFFu8; 16]; + // `buf.t` should be aligned to 8, so this should always succeed. + let (r, suffix) = Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).unwrap(); + // Assert that the suffix wasn't zeroed. + assert_eq!(suffix, &[0xFFu8; 8]); + test_new_helper(r); + } + { + buf.set_default(); + // `buf.t` should be aligned to 8, so this should always succeed. + let (prefix, r) = Ref::<_, AU64>::new_from_suffix(&mut buf.t[..]).unwrap(); + assert_eq!(prefix.len(), 8); + test_new_helper(r); + } + { + buf.t = [0xFFu8; 16]; + // `buf.t` should be aligned to 8, so this should always succeed. + let (prefix, r) = Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).unwrap(); + // Assert that the prefix wasn't zeroed. + assert_eq!(prefix, &[0xFFu8; 8]); + test_new_helper(r); + } + } + + #[test] + fn test_new_unaligned_oversized() { + // Test than an unaligned, overly-sized buffer works for + // `new_unaligned_from_prefix` and `new_unaligned_from_suffix`, and that + // they return the remainder and prefix of the slice respectively. Test + // that `xxx_zeroed` behaves the same, and zeroes the memory. + + let mut buf = [0u8; 16]; + { + // In a block so that `r` and `suffix` don't live too long. + let (r, suffix) = Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap(); + assert_eq!(suffix.len(), 8); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 16]; + let (r, suffix) = + Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf[..]).unwrap(); + // Assert that the suffix wasn't zeroed. + assert_eq!(suffix, &[0xFF; 8]); + test_new_helper_unaligned(r); + } + { + buf = [0u8; 16]; + let (prefix, r) = Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap(); + assert_eq!(prefix.len(), 8); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 16]; + let (prefix, r) = + Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf[..]).unwrap(); + // Assert that the prefix wasn't zeroed. + assert_eq!(prefix, &[0xFF; 8]); + test_new_helper_unaligned(r); + } + } + + #[test] + fn test_ref_from_mut_from() { + // Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` success cases + // Exhaustive coverage for these methods is covered by the `Ref` tests above, + // which these helper methods defer to. + + let mut buf = + Align::<[u8; 16], AU64>::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + + assert_eq!( + AU64::ref_from(&buf.t[8..]).unwrap().0.to_ne_bytes(), + [8, 9, 10, 11, 12, 13, 14, 15] + ); + let suffix = AU64::mut_from(&mut buf.t[8..]).unwrap(); + suffix.0 = 0x0101010101010101; + // The `[u8:9]` is a non-half size of the full buffer, which would catch + // `from_prefix` having the same implementation as `from_suffix` (issues #506, #511). + assert_eq!(<[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]); + let suffix = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap(); + suffix.0 = 0x0202020202020202; + <[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap()[0] = 42; + assert_eq!(<[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), &[0, 1, 2, 3, 4, 5, 42, 7, 2]); + <[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap()[1] = 30; + assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]); + } + + #[test] + fn test_ref_from_mut_from_error() { + // Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` error cases. + + // Fail because the buffer is too large. + let mut buf = Align::<[u8; 16], AU64>::default(); + // `buf.t` should be aligned to 8, so only the length check should fail. + assert!(AU64::ref_from(&buf.t[..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none()); + + // Fail because the buffer is too small. + let mut buf = Align::<[u8; 4], AU64>::default(); + assert!(AU64::ref_from(&buf.t[..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none()); + assert!(AU64::ref_from_prefix(&buf.t[..]).is_none()); + assert!(AU64::mut_from_prefix(&mut buf.t[..]).is_none()); + assert!(AU64::ref_from_suffix(&buf.t[..]).is_none()); + assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from_prefix(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from_prefix(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from_suffix(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from_suffix(&mut buf.t[..]).is_none()); + + // Fail because the alignment is insufficient. + let mut buf = Align::<[u8; 13], AU64>::default(); + assert!(AU64::ref_from(&buf.t[1..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[1..]).is_none()); + assert!(AU64::ref_from(&buf.t[1..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[1..]).is_none()); + assert!(AU64::ref_from_prefix(&buf.t[1..]).is_none()); + assert!(AU64::mut_from_prefix(&mut buf.t[1..]).is_none()); + assert!(AU64::ref_from_suffix(&buf.t[..]).is_none()); + assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none()); + } + + #[test] + #[allow(clippy::cognitive_complexity)] + fn test_new_error() { + // Fail because the buffer is too large. + + // A buffer with an alignment of 8. + let mut buf = Align::<[u8; 16], AU64>::default(); + // `buf.t` should be aligned to 8, so only the length check should fail. + assert!(Ref::<_, AU64>::new(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.t[..]).is_none()); + + // Fail because the buffer is too small. + + // A buffer with an alignment of 8. + let mut buf = Align::<[u8; 4], AU64>::default(); + // `buf.t` should be aligned to 8, so only the length check should fail. + assert!(Ref::<_, AU64>::new(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_suffix(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf.t[..]).is_none()); + + // Fail because the length is not a multiple of the element size. + + let mut buf = Align::<[u8; 12], AU64>::default(); + // `buf.t` has length 12, but element size is 8. + assert!(Ref::<_, [AU64]>::new_slice(&buf.t[..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned(&buf.t[..]).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_zeroed(&mut buf.t[..]).is_none()); + + // Fail because the buffer is too short. + let mut buf = Align::<[u8; 12], AU64>::default(); + // `buf.t` has length 12, but the element size is 8 (and we're expecting + // two of them). + assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], 2).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], 2).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix_zeroed(&mut buf.t[..], 2) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix_zeroed(&mut buf.t[..], 2) + .is_none()); + + // Fail because the alignment is insufficient. + + // A buffer with an alignment of 8. An odd buffer size is chosen so that + // the last byte of the buffer has odd alignment. + let mut buf = Align::<[u8; 13], AU64>::default(); + // Slicing from 1, we get a buffer with size 12 (so the length check + // should succeed) but an alignment of only 1, which is insufficient. + assert!(Ref::<_, AU64>::new(&buf.t[1..]).is_none()); + assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[1..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix(&buf.t[1..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[1..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice(&buf.t[1..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[1..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[1..], 1).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[1..], 1).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[1..], 1).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[1..], 1).is_none()); + // Slicing is unnecessary here because `new_from_suffix[_zeroed]` use + // the suffix of the slice, which has odd alignment. + assert!(Ref::<_, AU64>::new_from_suffix(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).is_none()); + + // Fail due to arithmetic overflow. + + let mut buf = Align::<[u8; 16], AU64>::default(); + let unreasonable_len = usize::MAX / mem::size_of::() + 1; + assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[..], unreasonable_len).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[..], unreasonable_len).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix(&buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix_zeroed( + &mut buf.t[..], + unreasonable_len + ) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix(&buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix_zeroed( + &mut buf.t[..], + unreasonable_len + ) + .is_none()); + } + + // Tests for ensuring that, if a ZST is passed into a slice-like function, + // we always panic. Since these tests need to be separate per-function, and + // they tend to take up a lot of space, we generate them using a macro in a + // submodule instead. The submodule ensures that we can just re-use the name + // of the function under test for the name of the test itself. + mod test_zst_panics { + macro_rules! zst_test { + ($name:ident($($tt:tt)*), $constructor_in_panic_msg:tt) => { + #[test] + #[should_panic = concat!("Ref::", $constructor_in_panic_msg, " called on a zero-sized type")] + fn $name() { + let mut buffer = [0u8]; + let r = $crate::Ref::<_, [()]>::$name(&mut buffer[..], $($tt)*); + unreachable!("should have panicked, got {:?}", r); + } + } + } + zst_test!(new_slice(), "new_slice"); + zst_test!(new_slice_zeroed(), "new_slice"); + zst_test!(new_slice_from_prefix(1), "new_slice"); + zst_test!(new_slice_from_prefix_zeroed(1), "new_slice"); + zst_test!(new_slice_from_suffix(1), "new_slice"); + zst_test!(new_slice_from_suffix_zeroed(1), "new_slice"); + zst_test!(new_slice_unaligned(), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_zeroed(), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_prefix(1), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_prefix_zeroed(1), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_suffix(1), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_suffix_zeroed(1), "new_slice_unaligned"); + } + + #[test] + fn test_as_bytes_methods() { + /// Run a series of tests by calling `AsBytes` methods on `t`. + /// + /// `bytes` is the expected byte sequence returned from `t.as_bytes()` + /// before `t` has been modified. `post_mutation` is the expected + /// sequence returned from `t.as_bytes()` after `t.as_bytes_mut()[0]` + /// has had its bits flipped (by applying `^= 0xFF`). + /// + /// `N` is the size of `t` in bytes. + fn test( + t: &mut T, + bytes: &[u8], + post_mutation: &T, + ) { + // Test that we can access the underlying bytes, and that we get the + // right bytes and the right number of bytes. + assert_eq!(t.as_bytes(), bytes); + + // Test that changes to the underlying byte slices are reflected in + // the original object. + t.as_bytes_mut()[0] ^= 0xFF; + assert_eq!(t, post_mutation); + t.as_bytes_mut()[0] ^= 0xFF; + + // `write_to` rejects slices that are too small or too large. + assert_eq!(t.write_to(&mut vec![0; N - 1][..]), None); + assert_eq!(t.write_to(&mut vec![0; N + 1][..]), None); + + // `write_to` works as expected. + let mut bytes = [0; N]; + assert_eq!(t.write_to(&mut bytes[..]), Some(())); + assert_eq!(bytes, t.as_bytes()); + + // `write_to_prefix` rejects slices that are too small. + assert_eq!(t.write_to_prefix(&mut vec![0; N - 1][..]), None); + + // `write_to_prefix` works with exact-sized slices. + let mut bytes = [0; N]; + assert_eq!(t.write_to_prefix(&mut bytes[..]), Some(())); + assert_eq!(bytes, t.as_bytes()); + + // `write_to_prefix` works with too-large slices, and any bytes past + // the prefix aren't modified. + let mut too_many_bytes = vec![0; N + 1]; + too_many_bytes[N] = 123; + assert_eq!(t.write_to_prefix(&mut too_many_bytes[..]), Some(())); + assert_eq!(&too_many_bytes[..N], t.as_bytes()); + assert_eq!(too_many_bytes[N], 123); + + // `write_to_suffix` rejects slices that are too small. + assert_eq!(t.write_to_suffix(&mut vec![0; N - 1][..]), None); + + // `write_to_suffix` works with exact-sized slices. + let mut bytes = [0; N]; + assert_eq!(t.write_to_suffix(&mut bytes[..]), Some(())); + assert_eq!(bytes, t.as_bytes()); + + // `write_to_suffix` works with too-large slices, and any bytes + // before the suffix aren't modified. + let mut too_many_bytes = vec![0; N + 1]; + too_many_bytes[0] = 123; + assert_eq!(t.write_to_suffix(&mut too_many_bytes[..]), Some(())); + assert_eq!(&too_many_bytes[1..], t.as_bytes()); + assert_eq!(too_many_bytes[0], 123); + } + + #[derive(Debug, Eq, PartialEq, FromZeroes, FromBytes, AsBytes)] + #[repr(C)] + struct Foo { + a: u32, + b: Wrapping, + c: Option, + } + + let expected_bytes: Vec = if cfg!(target_endian = "little") { + vec![1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0] + } else { + vec![0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0] + }; + let post_mutation_expected_a = + if cfg!(target_endian = "little") { 0x00_00_00_FE } else { 0xFF_00_00_01 }; + test::<_, 12>( + &mut Foo { a: 1, b: Wrapping(2), c: None }, + expected_bytes.as_bytes(), + &Foo { a: post_mutation_expected_a, b: Wrapping(2), c: None }, + ); + test::<_, 3>( + Unsized::from_mut_slice(&mut [1, 2, 3]), + &[1, 2, 3], + Unsized::from_mut_slice(&mut [0xFE, 2, 3]), + ); + } + + #[test] + fn test_array() { + #[derive(FromZeroes, FromBytes, AsBytes)] + #[repr(C)] + struct Foo { + a: [u16; 33], + } + + let foo = Foo { a: [0xFFFF; 33] }; + let expected = [0xFFu8; 66]; + assert_eq!(foo.as_bytes(), &expected[..]); + } + + #[test] + fn test_display_debug() { + let buf = Align::<[u8; 8], u64>::default(); + let r = Ref::<_, u64>::new(&buf.t[..]).unwrap(); + assert_eq!(format!("{}", r), "0"); + assert_eq!(format!("{:?}", r), "Ref(0)"); + + let buf = Align::<[u8; 8], u64>::default(); + let r = Ref::<_, [u64]>::new_slice(&buf.t[..]).unwrap(); + assert_eq!(format!("{:?}", r), "Ref([0])"); + } + + #[test] + fn test_eq() { + let buf1 = 0_u64; + let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap(); + let buf2 = 0_u64; + let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap(); + assert_eq!(r1, r2); + } + + #[test] + fn test_ne() { + let buf1 = 0_u64; + let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap(); + let buf2 = 1_u64; + let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap(); + assert_ne!(r1, r2); + } + + #[test] + fn test_ord() { + let buf1 = 0_u64; + let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap(); + let buf2 = 1_u64; + let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap(); + assert!(r1 < r2); + } + + #[test] + fn test_new_zeroed() { + assert!(!bool::new_zeroed()); + assert_eq!(u64::new_zeroed(), 0); + // This test exists in order to exercise unsafe code, especially when + // running under Miri. + #[allow(clippy::unit_cmp)] + { + assert_eq!(<()>::new_zeroed(), ()); + } + } + + #[test] + fn test_transparent_packed_generic_struct() { + #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + #[repr(transparent)] + struct Foo { + _t: T, + _phantom: PhantomData<()>, + } + + assert_impl_all!(Foo: FromZeroes, FromBytes, AsBytes); + assert_impl_all!(Foo: Unaligned); + + #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + #[repr(packed)] + struct Bar { + _t: T, + _u: U, + } + + assert_impl_all!(Bar: FromZeroes, FromBytes, AsBytes, Unaligned); + } + + #[test] + fn test_impls() { + use core::borrow::Borrow; + + // A type that can supply test cases for testing + // `TryFromBytes::is_bit_valid`. All types passed to `assert_impls!` + // must implement this trait; that macro uses it to generate runtime + // tests for `TryFromBytes` impls. + // + // All `T: FromBytes` types are provided with a blanket impl. Other + // types must implement `TryFromBytesTestable` directly (ie using + // `impl_try_from_bytes_testable!`). + trait TryFromBytesTestable { + fn with_passing_test_cases(f: F); + fn with_failing_test_cases(f: F); + } + + impl TryFromBytesTestable for T { + fn with_passing_test_cases(f: F) { + // Test with a zeroed value. + f(&Self::new_zeroed()); + + let ffs = { + let mut t = Self::new_zeroed(); + let ptr: *mut T = &mut t; + // SAFETY: `T: FromBytes` + unsafe { ptr::write_bytes(ptr.cast::(), 0xFF, mem::size_of::()) }; + t + }; + + // Test with a value initialized with 0xFF. + f(&ffs); + } + + fn with_failing_test_cases(_f: F) {} + } + + // Implements `TryFromBytesTestable`. + macro_rules! impl_try_from_bytes_testable { + // Base case for recursion (when the list of types has run out). + (=> @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {}; + // Implements for type(s) with no type parameters. + ($ty:ty $(,$tys:ty)* => @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => { + impl TryFromBytesTestable for $ty { + impl_try_from_bytes_testable!( + @methods @success $($success_case),* + $(, @failure $($failure_case),*)? + ); + } + impl_try_from_bytes_testable!($($tys),* => @success $($success_case),* $(, @failure $($failure_case),*)?); + }; + // Implements for multiple types with no type parameters. + ($($($ty:ty),* => @success $($success_case:expr), * $(, @failure $($failure_case:expr),*)?;)*) => { + $( + impl_try_from_bytes_testable!($($ty),* => @success $($success_case),* $(, @failure $($failure_case),*)*); + )* + }; + // Implements only the methods; caller must invoke this from inside + // an impl block. + (@methods @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => { + fn with_passing_test_cases(_f: F) { + $( + _f($success_case.borrow()); + )* + } + + fn with_failing_test_cases(_f: F) { + $($( + // `unused_qualifications` is spuriously triggered on + // `Option::::None`. + #[allow(unused_qualifications)] + let case = $failure_case.as_bytes(); + _f(case.as_bytes()); + )*)? + } + }; + } + + // Note that these impls are only for types which are not `FromBytes`. + // `FromBytes` types are covered by a preceding blanket impl. + impl_try_from_bytes_testable!( + bool => @success true, false, + @failure 2u8, 3u8, 0xFFu8; + char => @success '\u{0}', '\u{D7FF}', '\u{E000}', '\u{10FFFF}', + @failure 0xD800u32, 0xDFFFu32, 0x110000u32; + str => @success "", "hello", "❤️🧡💛💚💙💜", + @failure [0, 159, 146, 150]; + [u8] => @success [], [0, 1, 2]; + NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, + NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, + NonZeroUsize, NonZeroIsize + => @success Self::new(1).unwrap(), + // Doing this instead of `0` ensures that we always satisfy + // the size and alignment requirements of `Self` (whereas + // `0` may be any integer type with a different size or + // alignment than some `NonZeroXxx` types). + @failure Option::::None; + [bool] + => @success [true, false], [false, true], + @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8]; + ); + + // Asserts that `$ty` implements any `$trait` and doesn't implement any + // `!$trait`. Note that all `$trait`s must come before any `!$trait`s. + // + // For `T: TryFromBytes`, uses `TryFromBytesTestable` to test success + // and failure cases for `TryFromBytes::is_bit_valid`. + macro_rules! assert_impls { + ($ty:ty: TryFromBytes) => { + <$ty as TryFromBytesTestable>::with_passing_test_cases(|val| { + let c = Ptr::from(val); + // SAFETY: + // - Since `val` is a normal reference, `c` is guranteed to + // be aligned, to point to a single allocation, and to + // have a size which doesn't overflow `isize`. + // - Since `val` is a valid `$ty`, `c`'s referent satisfies + // the bit validity constraints of `is_bit_valid`, which + // are a superset of the bit validity constraints of + // `$ty`. + let res = unsafe { <$ty as TryFromBytes>::is_bit_valid(c) }; + assert!(res, "{}::is_bit_valid({:?}): got false, expected true", stringify!($ty), val); + + // TODO(#5): In addition to testing `is_bit_valid`, test the + // methods built on top of it. This would both allow us to + // test their implementations and actually convert the bytes + // to `$ty`, giving Miri a chance to catch if this is + // unsound (ie, if our `is_bit_valid` impl is buggy). + // + // The following code was tried, but it doesn't work because + // a) some types are not `AsBytes` and, b) some types are + // not `Sized`. + // + // let r = <$ty as TryFromBytes>::try_from_ref(val.as_bytes()).unwrap(); + // assert_eq!(r, &val); + // let r = <$ty as TryFromBytes>::try_from_mut(val.as_bytes_mut()).unwrap(); + // assert_eq!(r, &mut val); + // let v = <$ty as TryFromBytes>::try_read_from(val.as_bytes()).unwrap(); + // assert_eq!(v, val); + }); + #[allow(clippy::as_conversions)] + <$ty as TryFromBytesTestable>::with_failing_test_cases(|c| { + let res = <$ty as TryFromBytes>::try_from_ref(c); + assert!(res.is_none(), "{}::is_bit_valid({:?}): got true, expected false", stringify!($ty), c); + }); + + #[allow(dead_code)] + const _: () = { static_assertions::assert_impl_all!($ty: TryFromBytes); }; + }; + ($ty:ty: $trait:ident) => { + #[allow(dead_code)] + const _: () = { static_assertions::assert_impl_all!($ty: $trait); }; + }; + ($ty:ty: !$trait:ident) => { + #[allow(dead_code)] + const _: () = { static_assertions::assert_not_impl_any!($ty: $trait); }; + }; + ($ty:ty: $($trait:ident),* $(,)? $(!$negative_trait:ident),*) => { + $( + assert_impls!($ty: $trait); + )* + + $( + assert_impls!($ty: !$negative_trait); + )* + }; + } + + // NOTE: The negative impl assertions here are not necessarily + // prescriptive. They merely serve as change detectors to make sure + // we're aware of what trait impls are getting added with a given + // change. Of course, some impls would be invalid (e.g., `bool: + // FromBytes`), and so this change detection is very important. + + assert_impls!((): KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(u8: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(i8: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(u16: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i16: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(u32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(u64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(u128: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i128: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(usize: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(isize: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(f32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(f64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + + assert_impls!(bool: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes); + assert_impls!(char: KnownLayout, TryFromBytes, FromZeroes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(str: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes); + + assert_impls!(NonZeroU8: KnownLayout, TryFromBytes, AsBytes, Unaligned, !FromZeroes, !FromBytes); + assert_impls!(NonZeroI8: KnownLayout, TryFromBytes, AsBytes, Unaligned, !FromZeroes, !FromBytes); + assert_impls!(NonZeroU16: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI16: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroU32: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI32: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroU64: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI64: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroU128: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI128: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroUsize: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroIsize: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + + // Implements none of the ZC traits. + struct NotZerocopy; + + #[rustfmt::skip] + type FnManyArgs = fn( + NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, + ) -> (NotZerocopy, NotZerocopy); + + // Allowed, because we're not actually using this type for FFI. + #[allow(improper_ctypes_definitions)] + #[rustfmt::skip] + type ECFnManyArgs = extern "C" fn( + NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, + ) -> (NotZerocopy, NotZerocopy); + + #[cfg(feature = "alloc")] + assert_impls!(Option>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option]>>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static UnsafeCell>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static [UnsafeCell]>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static mut UnsafeCell>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static mut [UnsafeCell]>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option]>>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(PhantomData: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(PhantomData<[u8]>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + + assert_impls!(ManuallyDrop: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!(ManuallyDrop<[u8]>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!(ManuallyDrop: !TryFromBytes, !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(ManuallyDrop<[NotZerocopy]>: !TryFromBytes, !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(MaybeUninit: KnownLayout, TryFromBytes, FromZeroes, FromBytes, Unaligned, !AsBytes); + assert_impls!(MaybeUninit: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(Wrapping: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(Wrapping: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(Unalign: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!(Unalign: Unaligned, !KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes); + + assert_impls!([u8]: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!([bool]: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes); + assert_impls!([NotZerocopy]: !KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!([u8; 0]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!([NotZerocopy; 0]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!([u8; 1]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!([NotZerocopy; 1]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(*const NotZerocopy: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*mut NotZerocopy: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*const [NotZerocopy]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*mut [NotZerocopy]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*const dyn Debug: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*mut dyn Debug: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + #[cfg(feature = "simd")] + { + #[allow(unused_macros)] + macro_rules! test_simd_arch_mod { + ($arch:ident, $($typ:ident),*) => { + { + use core::arch::$arch::{$($typ),*}; + use crate::*; + $( assert_impls!($typ: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); )* + } + }; + } + #[cfg(target_arch = "x86")] + test_simd_arch_mod!(x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i); + + #[cfg(all(feature = "simd-nightly", target_arch = "x86"))] + test_simd_arch_mod!(x86, __m512bh, __m512, __m512d, __m512i); + + #[cfg(target_arch = "x86_64")] + test_simd_arch_mod!(x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i); + + #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))] + test_simd_arch_mod!(x86_64, __m512bh, __m512, __m512d, __m512i); + + #[cfg(target_arch = "wasm32")] + test_simd_arch_mod!(wasm32, v128); + + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))] + test_simd_arch_mod!( + powerpc, + vector_bool_long, + vector_double, + vector_signed_long, + vector_unsigned_long + ); + + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] + test_simd_arch_mod!( + powerpc64, + vector_bool_long, + vector_double, + vector_signed_long, + vector_unsigned_long + ); + #[cfg(target_arch = "aarch64")] + #[rustfmt::skip] + test_simd_arch_mod!( + aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, + int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t, + int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t, + poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t, + poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t, + uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t, + uint64x1_t, uint64x2_t + ); + #[cfg(all(feature = "simd-nightly", target_arch = "arm"))] + #[rustfmt::skip] + test_simd_arch_mod!(arm, int8x4_t, uint8x4_t); + } + } +} + +#[cfg(kani)] +mod proofs { + use super::*; + + impl kani::Arbitrary for DstLayout { + fn any() -> Self { + let align: NonZeroUsize = kani::any(); + let size_info: SizeInfo = kani::any(); + + kani::assume(align.is_power_of_two()); + kani::assume(align < DstLayout::THEORETICAL_MAX_ALIGN); + + // For testing purposes, we most care about instantiations of + // `DstLayout` that can correspond to actual Rust types. We use + // `Layout` to verify that our `DstLayout` satisfies the validity + // conditions of Rust layouts. + kani::assume( + match size_info { + SizeInfo::Sized { _size } => Layout::from_size_align(_size, align.get()), + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => { + // `SliceDst`` cannot encode an exact size, but we know + // it is at least `_offset` bytes. + Layout::from_size_align(_offset, align.get()) + } + } + .is_ok(), + ); + + Self { align: align, size_info: size_info } + } + } + + impl kani::Arbitrary for SizeInfo { + fn any() -> Self { + let is_sized: bool = kani::any(); + + match is_sized { + true => { + let size: usize = kani::any(); + + kani::assume(size <= isize::MAX as _); + + SizeInfo::Sized { _size: size } + } + false => SizeInfo::SliceDst(kani::any()), + } + } + } + + impl kani::Arbitrary for TrailingSliceLayout { + fn any() -> Self { + let elem_size: usize = kani::any(); + let offset: usize = kani::any(); + + kani::assume(elem_size < isize::MAX as _); + kani::assume(offset < isize::MAX as _); + + TrailingSliceLayout { _elem_size: elem_size, _offset: offset } + } + } + + #[kani::proof] + fn prove_dst_layout_extend() { + use crate::util::{core_layout::padding_needed_for, max, min}; + + let base: DstLayout = kani::any(); + let field: DstLayout = kani::any(); + let packed: Option = kani::any(); + + if let Some(max_align) = packed { + kani::assume(max_align.is_power_of_two()); + kani::assume(base.align <= max_align); + } + + // The base can only be extended if it's sized. + kani::assume(matches!(base.size_info, SizeInfo::Sized { .. })); + let base_size = if let SizeInfo::Sized { _size: size } = base.size_info { + size + } else { + unreachable!(); + }; + + // Under the above conditions, `DstLayout::extend` will not panic. + let composite = base.extend(field, packed); + + // The field's alignment is clamped by `max_align` (i.e., the + // `packed` attribute, if any) [1]. + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // The alignments of each field, for the purpose of positioning + // fields, is the smaller of the specified alignment and the + // alignment of the field's type. + let field_align = min(field.align, packed.unwrap_or(DstLayout::THEORETICAL_MAX_ALIGN)); + + // The struct's alignment is the maximum of its previous alignment and + // `field_align`. + assert_eq!(composite.align, max(base.align, field_align)); + + // Compute the minimum amount of inter-field padding needed to + // satisfy the field's alignment, and offset of the trailing field. + // [1] + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // Inter-field padding is guaranteed to be the minimum required in + // order to satisfy each field's (possibly altered) alignment. + let padding = padding_needed_for(base_size, field_align); + let offset = base_size + padding; + + // For testing purposes, we'll also construct `alloc::Layout` + // stand-ins for `DstLayout`, and show that `extend` behaves + // comparably on both types. + let base_analog = Layout::from_size_align(base_size, base.align.get()).unwrap(); + + match field.size_info { + SizeInfo::Sized { _size: field_size } => { + if let SizeInfo::Sized { _size: composite_size } = composite.size_info { + // If the trailing field is sized, the resulting layout + // will be sized. Its size will be the sum of the + // preceeding layout, the size of the new field, and the + // size of inter-field padding between the two. + assert_eq!(composite_size, offset + field_size); + + let field_analog = + Layout::from_size_align(field_size, field_align.get()).unwrap(); + + if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog) + { + assert_eq!(actual_offset, offset); + assert_eq!(actual_composite.size(), composite_size); + assert_eq!(actual_composite.align(), composite.align.get()); + } else { + // An error here reflects that composite of `base` + // and `field` cannot correspond to a real Rust type + // fragment, because such a fragment would violate + // the basic invariants of a valid Rust layout. At + // the time of writing, `DstLayout` is a little more + // permissive than `Layout`, so we don't assert + // anything in this branch (e.g., unreachability). + } + } else { + panic!("The composite of two sized layouts must be sized.") + } + } + SizeInfo::SliceDst(TrailingSliceLayout { + _offset: field_offset, + _elem_size: field_elem_size, + }) => { + if let SizeInfo::SliceDst(TrailingSliceLayout { + _offset: composite_offset, + _elem_size: composite_elem_size, + }) = composite.size_info + { + // The offset of the trailing slice component is the sum + // of the offset of the trailing field and the trailing + // slice offset within that field. + assert_eq!(composite_offset, offset + field_offset); + // The elem size is unchanged. + assert_eq!(composite_elem_size, field_elem_size); + + let field_analog = + Layout::from_size_align(field_offset, field_align.get()).unwrap(); + + if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog) + { + assert_eq!(actual_offset, offset); + assert_eq!(actual_composite.size(), composite_offset); + assert_eq!(actual_composite.align(), composite.align.get()); + } else { + // An error here reflects that composite of `base` + // and `field` cannot correspond to a real Rust type + // fragment, because such a fragment would violate + // the basic invariants of a valid Rust layout. At + // the time of writing, `DstLayout` is a little more + // permissive than `Layout`, so we don't assert + // anything in this branch (e.g., unreachability). + } + } else { + panic!("The extension of a layout with a DST must result in a DST.") + } + } + } + } + + #[kani::proof] + #[kani::should_panic] + fn prove_dst_layout_extend_dst_panics() { + let base: DstLayout = kani::any(); + let field: DstLayout = kani::any(); + let packed: Option = kani::any(); + + if let Some(max_align) = packed { + kani::assume(max_align.is_power_of_two()); + kani::assume(base.align <= max_align); + } + + kani::assume(matches!(base.size_info, SizeInfo::SliceDst(..))); + + let _ = base.extend(field, packed); + } + + #[kani::proof] + fn prove_dst_layout_pad_to_align() { + use crate::util::core_layout::padding_needed_for; + + let layout: DstLayout = kani::any(); + + let padded: DstLayout = layout.pad_to_align(); + + // Calling `pad_to_align` does not alter the `DstLayout`'s alignment. + assert_eq!(padded.align, layout.align); + + if let SizeInfo::Sized { _size: unpadded_size } = layout.size_info { + if let SizeInfo::Sized { _size: padded_size } = padded.size_info { + // If the layout is sized, it will remain sized after padding is + // added. Its sum will be its unpadded size and the size of the + // trailing padding needed to satisfy its alignment + // requirements. + let padding = padding_needed_for(unpadded_size, layout.align); + assert_eq!(padded_size, unpadded_size + padding); + + // Prove that calling `DstLayout::pad_to_align` behaves + // identically to `Layout::pad_to_align`. + let layout_analog = + Layout::from_size_align(unpadded_size, layout.align.get()).unwrap(); + let padded_analog = layout_analog.pad_to_align(); + assert_eq!(padded_analog.align(), layout.align.get()); + assert_eq!(padded_analog.size(), padded_size); + } else { + panic!("The padding of a sized layout must result in a sized layout.") + } + } else { + // If the layout is a DST, padding cannot be statically added. + assert_eq!(padded.size_info, layout.size_info); + } + } +} diff --git a/third_party/rust/zerocopy/src/macro_util.rs b/third_party/rust/zerocopy/src/macro_util.rs new file mode 100644 index 0000000000..24fec4f015 --- /dev/null +++ b/third_party/rust/zerocopy/src/macro_util.rs @@ -0,0 +1,670 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//! Utilities used by macros and by `zerocopy-derive`. +//! +//! These are defined here `zerocopy` rather than in code generated by macros or +//! by `zerocopy-derive` so that they can be compiled once rather than +//! recompiled for every invocation (e.g., if they were defined in generated +//! code, then deriving `AsBytes` and `FromBytes` on three different types would +//! result in the code in question being emitted and compiled six different +//! times). + +#![allow(missing_debug_implementations)] + +use core::{marker::PhantomData, mem::ManuallyDrop}; + +// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this +// `cfg` when `size_of_val_raw` is stabilized. +#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] +use core::ptr::{self, NonNull}; + +/// A compile-time check that should be one particular value. +pub trait ShouldBe {} + +/// A struct for checking whether `T` contains padding. +pub struct HasPadding(PhantomData); + +impl ShouldBe for HasPadding {} + +/// A type whose size is equal to `align_of::()`. +#[repr(C)] +pub struct AlignOf { + // This field ensures that: + // - The size is always at least 1 (the minimum possible alignment). + // - If the alignment is greater than 1, Rust has to round up to the next + // multiple of it in order to make sure that `Align`'s size is a multiple + // of that alignment. Without this field, its size could be 0, which is a + // valid multiple of any alignment. + _u: u8, + _a: [T; 0], +} + +impl AlignOf { + #[inline(never)] // Make `missing_inline_in_public_items` happy. + pub fn into_t(self) -> T { + unreachable!() + } +} + +/// A type whose size is equal to `max(align_of::(), align_of::())`. +#[repr(C)] +pub union MaxAlignsOf { + _t: ManuallyDrop>, + _u: ManuallyDrop>, +} + +impl MaxAlignsOf { + #[inline(never)] // Make `missing_inline_in_public_items` happy. + pub fn new(_t: T, _u: U) -> MaxAlignsOf { + unreachable!() + } +} + +const _64K: usize = 1 << 16; + +// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this +// `cfg` when `size_of_val_raw` is stabilized. +#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] +#[repr(C, align(65536))] +struct Aligned64kAllocation([u8; _64K]); + +/// A pointer to an aligned allocation of size 2^16. +/// +/// # Safety +/// +/// `ALIGNED_64K_ALLOCATION` is guaranteed to point to the entirety of an +/// allocation with size and alignment 2^16, and to have valid provenance. +// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this +// `cfg` when `size_of_val_raw` is stabilized. +#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] +pub const ALIGNED_64K_ALLOCATION: NonNull<[u8]> = { + const REF: &Aligned64kAllocation = &Aligned64kAllocation([0; _64K]); + let ptr: *const Aligned64kAllocation = REF; + let ptr: *const [u8] = ptr::slice_from_raw_parts(ptr.cast(), _64K); + // SAFETY: + // - `ptr` is derived from a Rust reference, which is guaranteed to be + // non-null. + // - `ptr` is derived from an `&Aligned64kAllocation`, which has size and + // alignment `_64K` as promised. Its length is initialized to `_64K`, + // which means that it refers to the entire allocation. + // - `ptr` is derived from a Rust reference, which is guaranteed to have + // valid provenance. + // + // TODO(#429): Once `NonNull::new_unchecked` docs document that it preserves + // provenance, cite those docs. + // TODO: Replace this `as` with `ptr.cast_mut()` once our MSRV >= 1.65 + #[allow(clippy::as_conversions)] + unsafe { + NonNull::new_unchecked(ptr as *mut _) + } +}; + +/// Computes the offset of the base of the field `$trailing_field_name` within +/// the type `$ty`. +/// +/// `trailing_field_offset!` produces code which is valid in a `const` context. +// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this +// `cfg` when `size_of_val_raw` is stabilized. +#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] +#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. +#[macro_export] +macro_rules! trailing_field_offset { + ($ty:ty, $trailing_field_name:tt) => {{ + let min_size = { + let zero_elems: *const [()] = + $crate::macro_util::core_reexport::ptr::slice_from_raw_parts( + $crate::macro_util::core_reexport::ptr::NonNull::<()>::dangling() + .as_ptr() + .cast_const(), + 0, + ); + // SAFETY: + // - If `$ty` is `Sized`, `size_of_val_raw` is always safe to call. + // - Otherwise: + // - If `$ty` is not a slice DST, this pointer conversion will + // fail due to "mismatched vtable kinds", and compilation will + // fail. + // - If `$ty` is a slice DST, the safety requirement is that "the + // length of the slice tail must be an initialized integer, and + // the size of the entire value (dynamic tail length + + // statically sized prefix) must fit in isize." The length is + // initialized to 0 above, and Rust guarantees that no type's + // minimum size may overflow `isize`. [1] + // + // [1] TODO(#429), + // TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465#issuecomment-1782206516): + // Citation for this? + unsafe { + #[allow(clippy::as_conversions)] + $crate::macro_util::core_reexport::mem::size_of_val_raw(zero_elems as *const $ty) + } + }; + + assert!(min_size <= _64K); + + #[allow(clippy::as_conversions)] + let ptr = ALIGNED_64K_ALLOCATION.as_ptr() as *const $ty; + + // SAFETY: + // - Thanks to the preceding `assert!`, we know that the value with zero + // elements fits in `_64K` bytes, and thus in the allocation addressed + // by `ALIGNED_64K_ALLOCATION`. The offset of the trailing field is + // guaranteed to be no larger than this size, so this field projection + // is guaranteed to remain in-bounds of its allocation. + // - Because the minimum size is no larger than `_64K` bytes, and + // because an object's size must always be a multiple of its alignment + // [1], we know that `$ty`'s alignment is no larger than `_64K`. The + // allocation addressed by `ALIGNED_64K_ALLOCATION` is guaranteed to + // be aligned to `_64K`, so `ptr` is guaranteed to satisfy `$ty`'s + // alignment. + // + // Note that, as of [2], this requirement is technically unnecessary + // for Rust versions >= 1.75.0, but no harm in guaranteeing it anyway + // until we bump our MSRV. + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html: + // + // The size of a value is always a multiple of its alignment. + // + // [2] https://github.com/rust-lang/reference/pull/1387 + let field = unsafe { + $crate::macro_util::core_reexport::ptr::addr_of!((*ptr).$trailing_field_name) + }; + // SAFETY: + // - Both `ptr` and `field` are derived from the same allocated object. + // - By the preceding safety comment, `field` is in bounds of that + // allocated object. + // - The distance, in bytes, between `ptr` and `field` is required to be + // a multiple of the size of `u8`, which is trivially true because + // `u8`'s size is 1. + // - The distance, in bytes, cannot overflow `isize`. This is guaranteed + // because no allocated object can have a size larger than can fit in + // `isize`. [1] + // - The distance being in-bounds cannot rely on wrapping around the + // address space. This is guaranteed because the same is guaranteed of + // allocated objects. [1] + // + // [1] TODO(#429), TODO(https://github.com/rust-lang/rust/pull/116675): + // Once these are guaranteed in the Reference, cite it. + let offset = unsafe { field.cast::().offset_from(ptr.cast::()) }; + // Guaranteed not to be lossy: `field` comes after `ptr`, so the offset + // from `ptr` to `field` is guaranteed to be positive. + assert!(offset >= 0); + Some( + #[allow(clippy::as_conversions)] + { + offset as usize + }, + ) + }}; +} + +/// Computes alignment of `$ty: ?Sized`. +/// +/// `align_of!` produces code which is valid in a `const` context. +// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this +// `cfg` when `size_of_val_raw` is stabilized. +#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] +#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. +#[macro_export] +macro_rules! align_of { + ($ty:ty) => {{ + // SAFETY: `OffsetOfTrailingIsAlignment` is `repr(C)`, and its layout is + // guaranteed [1] to begin with the single-byte layout for `_byte`, + // followed by the padding needed to align `_trailing`, then the layout + // for `_trailing`, and finally any trailing padding bytes needed to + // correctly-align the entire struct. + // + // This macro computes the alignment of `$ty` by counting the number of + // bytes preceeding `_trailing`. For instance, if the alignment of `$ty` + // is `1`, then no padding is required align `_trailing` and it will be + // located immediately after `_byte` at offset 1. If the alignment of + // `$ty` is 2, then a single padding byte is required before + // `_trailing`, and `_trailing` will be located at offset 2. + + // This correspondence between offset and alignment holds for all valid + // Rust alignments, and we confirm this exhaustively (or, at least up to + // the maximum alignment supported by `trailing_field_offset!`) in + // `test_align_of_dst`. + // + // [1]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprc + + #[repr(C)] + struct OffsetOfTrailingIsAlignment { + _byte: u8, + _trailing: $ty, + } + + trailing_field_offset!(OffsetOfTrailingIsAlignment, _trailing) + }}; +} + +/// Does the struct type `$t` have padding? +/// +/// `$ts` is the list of the type of every field in `$t`. `$t` must be a +/// struct type, or else `struct_has_padding!`'s result may be meaningless. +/// +/// Note that `struct_has_padding!`'s results are independent of `repr` since +/// they only consider the size of the type and the sizes of the fields. +/// Whatever the repr, the size of the type already takes into account any +/// padding that the compiler has decided to add. Structs with well-defined +/// representations (such as `repr(C)`) can use this macro to check for padding. +/// Note that while this may yield some consistent value for some `repr(Rust)` +/// structs, it is not guaranteed across platforms or compilations. +#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. +#[macro_export] +macro_rules! struct_has_padding { + ($t:ty, $($ts:ty),*) => { + core::mem::size_of::<$t>() > 0 $(+ core::mem::size_of::<$ts>())* + }; +} + +/// Does the union type `$t` have padding? +/// +/// `$ts` is the list of the type of every field in `$t`. `$t` must be a +/// union type, or else `union_has_padding!`'s result may be meaningless. +/// +/// Note that `union_has_padding!`'s results are independent of `repr` since +/// they only consider the size of the type and the sizes of the fields. +/// Whatever the repr, the size of the type already takes into account any +/// padding that the compiler has decided to add. Unions with well-defined +/// representations (such as `repr(C)`) can use this macro to check for padding. +/// Note that while this may yield some consistent value for some `repr(Rust)` +/// unions, it is not guaranteed across platforms or compilations. +#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. +#[macro_export] +macro_rules! union_has_padding { + ($t:ty, $($ts:ty),*) => { + false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())* + }; +} + +/// Does `t` have alignment greater than or equal to `u`? If not, this macro +/// produces a compile error. It must be invoked in a dead codepath. This is +/// used in `transmute_ref!` and `transmute_mut!`. +#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. +#[macro_export] +macro_rules! assert_align_gt_eq { + ($t:ident, $u: ident) => {{ + // The comments here should be read in the context of this macro's + // invocations in `transmute_ref!` and `transmute_mut!`. + if false { + // The type wildcard in this bound is inferred to be `T` because + // `align_of.into_t()` is assigned to `t` (which has type `T`). + let align_of: $crate::macro_util::AlignOf<_> = unreachable!(); + $t = align_of.into_t(); + // `max_aligns` is inferred to have type `MaxAlignsOf` because + // of the inferred types of `t` and `u`. + let mut max_aligns = $crate::macro_util::MaxAlignsOf::new($t, $u); + + // This transmute will only compile successfully if + // `align_of::() == max(align_of::(), align_of::())` - in + // other words, if `align_of::() >= align_of::()`. + // + // SAFETY: This code is never run. + max_aligns = unsafe { $crate::macro_util::core_reexport::mem::transmute(align_of) }; + } else { + loop {} + } + }}; +} + +/// Do `t` and `u` have the same size? If not, this macro produces a compile +/// error. It must be invoked in a dead codepath. This is used in +/// `transmute_ref!` and `transmute_mut!`. +#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. +#[macro_export] +macro_rules! assert_size_eq { + ($t:ident, $u: ident) => {{ + // The comments here should be read in the context of this macro's + // invocations in `transmute_ref!` and `transmute_mut!`. + if false { + // SAFETY: This code is never run. + $u = unsafe { + // Clippy: It's okay to transmute a type to itself. + #[allow(clippy::useless_transmute)] + $crate::macro_util::core_reexport::mem::transmute($t) + }; + } else { + loop {} + } + }}; +} + +/// Transmutes a reference of one type to a reference of another type. +/// +/// # Safety +/// +/// The caller must guarantee that: +/// - `Src: AsBytes` +/// - `Dst: FromBytes` +/// - `size_of::() == size_of::()` +/// - `align_of::() >= align_of::()` +#[inline(always)] +pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + src: &'src Src, +) -> &'dst Dst { + let src: *const Src = src; + let dst = src.cast::(); + // SAFETY: + // - We know that it is sound to view the target type of the input reference + // (`Src`) as the target type of the output reference (`Dst`) because the + // caller has guaranteed that `Src: AsBytes`, `Dst: FromBytes`, and + // `size_of::() == size_of::()`. + // - We know that there are no `UnsafeCell`s, and thus we don't have to + // worry about `UnsafeCell` overlap, because `Src: AsBytes` and `Dst: + // FromBytes` both forbid `UnsafeCell`s. + // - The caller has guaranteed that alignment is not increased. + // - We know that the returned lifetime will not outlive the input lifetime + // thanks to the lifetime bounds on this function. + unsafe { &*dst } +} + +/// Transmutes a mutable reference of one type to a mutable reference of another +/// type. +/// +/// # Safety +/// +/// The caller must guarantee that: +/// - `Src: FromBytes + AsBytes` +/// - `Dst: FromBytes + AsBytes` +/// - `size_of::() == size_of::()` +/// - `align_of::() >= align_of::()` +#[inline(always)] +pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + src: &'src mut Src, +) -> &'dst mut Dst { + let src: *mut Src = src; + let dst = src.cast::(); + // SAFETY: + // - We know that it is sound to view the target type of the input reference + // (`Src`) as the target type of the output reference (`Dst`) and + // vice-versa because the caller has guaranteed that `Src: FromBytes + + // AsBytes`, `Dst: FromBytes + AsBytes`, and `size_of::() == + // size_of::()`. + // - We know that there are no `UnsafeCell`s, and thus we don't have to + // worry about `UnsafeCell` overlap, because `Src: FromBytes + AsBytes` + // and `Dst: FromBytes + AsBytes` forbid `UnsafeCell`s. + // - The caller has guaranteed that alignment is not increased. + // - We know that the returned lifetime will not outlive the input lifetime + // thanks to the lifetime bounds on this function. + unsafe { &mut *dst } +} + +// NOTE: We can't change this to a `pub use core as core_reexport` until [1] is +// fixed or we update to a semver-breaking version (as of this writing, 0.8.0) +// on the `main` branch. +// +// [1] https://github.com/obi1kenobi/cargo-semver-checks/issues/573 +pub mod core_reexport { + pub use core::*; + + pub mod mem { + pub use core::mem::*; + } +} + +#[cfg(test)] +mod tests { + use core::mem; + + use super::*; + use crate::util::testutil::*; + + #[test] + fn test_align_of() { + macro_rules! test { + ($ty:ty) => { + assert_eq!(mem::size_of::>(), mem::align_of::<$ty>()); + }; + } + + test!(()); + test!(u8); + test!(AU64); + test!([AU64; 2]); + } + + #[test] + fn test_max_aligns_of() { + macro_rules! test { + ($t:ty, $u:ty) => { + assert_eq!( + mem::size_of::>(), + core::cmp::max(mem::align_of::<$t>(), mem::align_of::<$u>()) + ); + }; + } + + test!(u8, u8); + test!(u8, AU64); + test!(AU64, u8); + } + + #[test] + fn test_typed_align_check() { + // Test that the type-based alignment check used in + // `assert_align_gt_eq!` behaves as expected. + + macro_rules! assert_t_align_gteq_u_align { + ($t:ty, $u:ty, $gteq:expr) => { + assert_eq!( + mem::size_of::>() == mem::size_of::>(), + $gteq + ); + }; + } + + assert_t_align_gteq_u_align!(u8, u8, true); + assert_t_align_gteq_u_align!(AU64, AU64, true); + assert_t_align_gteq_u_align!(AU64, u8, true); + assert_t_align_gteq_u_align!(u8, AU64, false); + } + + // TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove + // this `cfg` when `size_of_val_raw` is stabilized. + #[allow(clippy::decimal_literal_representation)] + #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] + #[test] + fn test_trailing_field_offset() { + assert_eq!(mem::align_of::(), _64K); + + macro_rules! test { + (#[$cfg:meta] ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {{ + #[$cfg] + struct Test($($ts,)* $trailing_field_ty); + assert_eq!(test!(@offset $($ts),* ; $trailing_field_ty), $expect); + }}; + (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => { + test!(#[$cfg] ($($ts),* ; $trailing_field_ty) => $expect); + test!($(#[$cfgs])* ($($ts),* ; $trailing_field_ty) => $expect); + }; + (@offset ; $_trailing:ty) => { trailing_field_offset!(Test, 0) }; + (@offset $_t:ty ; $_trailing:ty) => { trailing_field_offset!(Test, 1) }; + } + + test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; u8) => Some(0)); + test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; [u8]) => Some(0)); + test!(#[repr(C)] #[repr(packed)] (u8; u8) => Some(1)); + test!(#[repr(C)] (; AU64) => Some(0)); + test!(#[repr(C)] (; [AU64]) => Some(0)); + test!(#[repr(C)] (u8; AU64) => Some(8)); + test!(#[repr(C)] (u8; [AU64]) => Some(8)); + test!(#[repr(C)] (; Nested) => Some(0)); + test!(#[repr(C)] (; Nested) => Some(0)); + test!(#[repr(C)] (u8; Nested) => Some(8)); + test!(#[repr(C)] (u8; Nested) => Some(8)); + + // Test that `packed(N)` limits the offset of the trailing field. + test!(#[repr(C, packed( 1))] (u8; elain::Align< 2>) => Some( 1)); + test!(#[repr(C, packed( 2))] (u8; elain::Align< 4>) => Some( 2)); + test!(#[repr(C, packed( 4))] (u8; elain::Align< 8>) => Some( 4)); + test!(#[repr(C, packed( 8))] (u8; elain::Align< 16>) => Some( 8)); + test!(#[repr(C, packed( 16))] (u8; elain::Align< 32>) => Some( 16)); + test!(#[repr(C, packed( 32))] (u8; elain::Align< 64>) => Some( 32)); + test!(#[repr(C, packed( 64))] (u8; elain::Align< 128>) => Some( 64)); + test!(#[repr(C, packed( 128))] (u8; elain::Align< 256>) => Some( 128)); + test!(#[repr(C, packed( 256))] (u8; elain::Align< 512>) => Some( 256)); + test!(#[repr(C, packed( 512))] (u8; elain::Align< 1024>) => Some( 512)); + test!(#[repr(C, packed( 1024))] (u8; elain::Align< 2048>) => Some( 1024)); + test!(#[repr(C, packed( 2048))] (u8; elain::Align< 4096>) => Some( 2048)); + test!(#[repr(C, packed( 4096))] (u8; elain::Align< 8192>) => Some( 4096)); + test!(#[repr(C, packed( 8192))] (u8; elain::Align< 16384>) => Some( 8192)); + test!(#[repr(C, packed( 16384))] (u8; elain::Align< 32768>) => Some( 16384)); + test!(#[repr(C, packed( 32768))] (u8; elain::Align< 65536>) => Some( 32768)); + test!(#[repr(C, packed( 65536))] (u8; elain::Align< 131072>) => Some( 65536)); + /* Alignments above 65536 are not yet supported. + test!(#[repr(C, packed( 131072))] (u8; elain::Align< 262144>) => Some( 131072)); + test!(#[repr(C, packed( 262144))] (u8; elain::Align< 524288>) => Some( 262144)); + test!(#[repr(C, packed( 524288))] (u8; elain::Align< 1048576>) => Some( 524288)); + test!(#[repr(C, packed( 1048576))] (u8; elain::Align< 2097152>) => Some( 1048576)); + test!(#[repr(C, packed( 2097152))] (u8; elain::Align< 4194304>) => Some( 2097152)); + test!(#[repr(C, packed( 4194304))] (u8; elain::Align< 8388608>) => Some( 4194304)); + test!(#[repr(C, packed( 8388608))] (u8; elain::Align< 16777216>) => Some( 8388608)); + test!(#[repr(C, packed( 16777216))] (u8; elain::Align< 33554432>) => Some( 16777216)); + test!(#[repr(C, packed( 33554432))] (u8; elain::Align< 67108864>) => Some( 33554432)); + test!(#[repr(C, packed( 67108864))] (u8; elain::Align< 33554432>) => Some( 67108864)); + test!(#[repr(C, packed( 33554432))] (u8; elain::Align<134217728>) => Some( 33554432)); + test!(#[repr(C, packed(134217728))] (u8; elain::Align<268435456>) => Some(134217728)); + test!(#[repr(C, packed(268435456))] (u8; elain::Align<268435456>) => Some(268435456)); + */ + + // Test that `align(N)` does not limit the offset of the trailing field. + test!(#[repr(C, align( 1))] (u8; elain::Align< 2>) => Some( 2)); + test!(#[repr(C, align( 2))] (u8; elain::Align< 4>) => Some( 4)); + test!(#[repr(C, align( 4))] (u8; elain::Align< 8>) => Some( 8)); + test!(#[repr(C, align( 8))] (u8; elain::Align< 16>) => Some( 16)); + test!(#[repr(C, align( 16))] (u8; elain::Align< 32>) => Some( 32)); + test!(#[repr(C, align( 32))] (u8; elain::Align< 64>) => Some( 64)); + test!(#[repr(C, align( 64))] (u8; elain::Align< 128>) => Some( 128)); + test!(#[repr(C, align( 128))] (u8; elain::Align< 256>) => Some( 256)); + test!(#[repr(C, align( 256))] (u8; elain::Align< 512>) => Some( 512)); + test!(#[repr(C, align( 512))] (u8; elain::Align< 1024>) => Some( 1024)); + test!(#[repr(C, align( 1024))] (u8; elain::Align< 2048>) => Some( 2048)); + test!(#[repr(C, align( 2048))] (u8; elain::Align< 4096>) => Some( 4096)); + test!(#[repr(C, align( 4096))] (u8; elain::Align< 8192>) => Some( 8192)); + test!(#[repr(C, align( 8192))] (u8; elain::Align< 16384>) => Some( 16384)); + test!(#[repr(C, align( 16384))] (u8; elain::Align< 32768>) => Some( 32768)); + test!(#[repr(C, align( 32768))] (u8; elain::Align< 65536>) => Some( 65536)); + /* Alignments above 65536 are not yet supported. + test!(#[repr(C, align( 65536))] (u8; elain::Align< 131072>) => Some( 131072)); + test!(#[repr(C, align( 131072))] (u8; elain::Align< 262144>) => Some( 262144)); + test!(#[repr(C, align( 262144))] (u8; elain::Align< 524288>) => Some( 524288)); + test!(#[repr(C, align( 524288))] (u8; elain::Align< 1048576>) => Some( 1048576)); + test!(#[repr(C, align( 1048576))] (u8; elain::Align< 2097152>) => Some( 2097152)); + test!(#[repr(C, align( 2097152))] (u8; elain::Align< 4194304>) => Some( 4194304)); + test!(#[repr(C, align( 4194304))] (u8; elain::Align< 8388608>) => Some( 8388608)); + test!(#[repr(C, align( 8388608))] (u8; elain::Align< 16777216>) => Some( 16777216)); + test!(#[repr(C, align( 16777216))] (u8; elain::Align< 33554432>) => Some( 33554432)); + test!(#[repr(C, align( 33554432))] (u8; elain::Align< 67108864>) => Some( 67108864)); + test!(#[repr(C, align( 67108864))] (u8; elain::Align< 33554432>) => Some( 33554432)); + test!(#[repr(C, align( 33554432))] (u8; elain::Align<134217728>) => Some(134217728)); + test!(#[repr(C, align(134217728))] (u8; elain::Align<268435456>) => Some(268435456)); + */ + } + + // TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove + // this `cfg` when `size_of_val_raw` is stabilized. + #[allow(clippy::decimal_literal_representation)] + #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] + #[test] + fn test_align_of_dst() { + // Test that `align_of!` correctly computes the alignment of DSTs. + assert_eq!(align_of!([elain::Align<1>]), Some(1)); + assert_eq!(align_of!([elain::Align<2>]), Some(2)); + assert_eq!(align_of!([elain::Align<4>]), Some(4)); + assert_eq!(align_of!([elain::Align<8>]), Some(8)); + assert_eq!(align_of!([elain::Align<16>]), Some(16)); + assert_eq!(align_of!([elain::Align<32>]), Some(32)); + assert_eq!(align_of!([elain::Align<64>]), Some(64)); + assert_eq!(align_of!([elain::Align<128>]), Some(128)); + assert_eq!(align_of!([elain::Align<256>]), Some(256)); + assert_eq!(align_of!([elain::Align<512>]), Some(512)); + assert_eq!(align_of!([elain::Align<1024>]), Some(1024)); + assert_eq!(align_of!([elain::Align<2048>]), Some(2048)); + assert_eq!(align_of!([elain::Align<4096>]), Some(4096)); + assert_eq!(align_of!([elain::Align<8192>]), Some(8192)); + assert_eq!(align_of!([elain::Align<16384>]), Some(16384)); + assert_eq!(align_of!([elain::Align<32768>]), Some(32768)); + assert_eq!(align_of!([elain::Align<65536>]), Some(65536)); + /* Alignments above 65536 are not yet supported. + assert_eq!(align_of!([elain::Align<131072>]), Some(131072)); + assert_eq!(align_of!([elain::Align<262144>]), Some(262144)); + assert_eq!(align_of!([elain::Align<524288>]), Some(524288)); + assert_eq!(align_of!([elain::Align<1048576>]), Some(1048576)); + assert_eq!(align_of!([elain::Align<2097152>]), Some(2097152)); + assert_eq!(align_of!([elain::Align<4194304>]), Some(4194304)); + assert_eq!(align_of!([elain::Align<8388608>]), Some(8388608)); + assert_eq!(align_of!([elain::Align<16777216>]), Some(16777216)); + assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); + assert_eq!(align_of!([elain::Align<67108864>]), Some(67108864)); + assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); + assert_eq!(align_of!([elain::Align<134217728>]), Some(134217728)); + assert_eq!(align_of!([elain::Align<268435456>]), Some(268435456)); + */ + } + + #[test] + fn test_struct_has_padding() { + // Test that, for each provided repr, `struct_has_padding!` reports the + // expected value. + macro_rules! test { + (#[$cfg:meta] ($($ts:ty),*) => $expect:expr) => {{ + #[$cfg] + struct Test($($ts),*); + assert_eq!(struct_has_padding!(Test, $($ts),*), $expect); + }}; + (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),*) => $expect:expr) => { + test!(#[$cfg] ($($ts),*) => $expect); + test!($(#[$cfgs])* ($($ts),*) => $expect); + }; + } + + test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] () => false); + test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8) => false); + test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8, ()) => false); + test!(#[repr(C)] #[repr(packed)] (u8, u8) => false); + + test!(#[repr(C)] (u8, AU64) => true); + // Rust won't let you put `#[repr(packed)]` on a type which contains a + // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. + // It's not ideal, but it definitely has align > 1 on /some/ of our CI + // targets, and this isn't a particularly complex macro we're testing + // anyway. + test!(#[repr(packed)] (u8, u64) => false); + } + + #[test] + fn test_union_has_padding() { + // Test that, for each provided repr, `union_has_padding!` reports the + // expected value. + macro_rules! test { + (#[$cfg:meta] {$($fs:ident: $ts:ty),*} => $expect:expr) => {{ + #[$cfg] + #[allow(unused)] // fields are never read + union Test{ $($fs: $ts),* } + assert_eq!(union_has_padding!(Test, $($ts),*), $expect); + }}; + (#[$cfg:meta] $(#[$cfgs:meta])* {$($fs:ident: $ts:ty),*} => $expect:expr) => { + test!(#[$cfg] {$($fs: $ts),*} => $expect); + test!($(#[$cfgs])* {$($fs: $ts),*} => $expect); + }; + } + + test!(#[repr(C)] #[repr(packed)] {a: u8} => false); + test!(#[repr(C)] #[repr(packed)] {a: u8, b: u8} => false); + + // Rust won't let you put `#[repr(packed)]` on a type which contains a + // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. + // It's not ideal, but it definitely has align > 1 on /some/ of our CI + // targets, and this isn't a particularly complex macro we're testing + // anyway. + test!(#[repr(C)] #[repr(packed)] {a: u8, b: u64} => true); + } +} diff --git a/third_party/rust/zerocopy/src/macros.rs b/third_party/rust/zerocopy/src/macros.rs new file mode 100644 index 0000000000..2da78af7df --- /dev/null +++ b/third_party/rust/zerocopy/src/macros.rs @@ -0,0 +1,417 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +/// Documents multiple unsafe blocks with a single safety comment. +/// +/// Invoked as: +/// +/// ```rust,ignore +/// safety_comment! { +/// // Non-doc comments come first. +/// /// SAFETY: +/// /// Safety comment starts on its own line. +/// macro_1!(args); +/// macro_2! { args }; +/// /// SAFETY: +/// /// Subsequent safety comments are allowed but not required. +/// macro_3! { args }; +/// } +/// ``` +/// +/// The macro invocations are emitted, each decorated with the following +/// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`. +macro_rules! safety_comment { + (#[doc = r" SAFETY:"] $($(#[$attr:meta])* $macro:ident!$args:tt;)*) => { + #[allow(clippy::undocumented_unsafe_blocks, unused_attributes)] + const _: () = { $($(#[$attr])* $macro!$args;)* }; + } +} + +/// Unsafely implements trait(s) for a type. +/// +/// # Safety +/// +/// The trait impl must be sound. +/// +/// When implementing `TryFromBytes`: +/// - If no `is_bit_valid` impl is provided, then it must be valid for +/// `is_bit_valid` to unconditionally return `true`. In other words, it must +/// be the case that any initialized sequence of bytes constitutes a valid +/// instance of `$ty`. +/// - If an `is_bit_valid` impl is provided, then: +/// - Regardless of whether the provided closure takes a `Ptr<$repr>` or +/// `&$repr` argument, it must be the case that, given `t: *mut $ty` and +/// `let r = t as *mut $repr`, `r` refers to an object of equal or lesser +/// size than the object referred to by `t`. +/// - If the provided closure takes a `&$repr` argument, then given a `Ptr<'a, +/// $ty>` which satisfies the preconditions of +/// `TryFromBytes::<$ty>::is_bit_valid`, it must be guaranteed that the +/// memory referenced by that `Ptr` always contains a valid `$repr`. +/// - The alignment of `$repr` is less than or equal to the alignment of +/// `$ty`. +/// - The impl of `is_bit_valid` must only return `true` for its argument +/// `Ptr<$repr>` if the original `Ptr<$ty>` refers to a valid `$ty`. +macro_rules! unsafe_impl { + // Implement `$trait` for `$ty` with no bounds. + ($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident: &$repr:ty| $is_bit_valid:expr)?) => { + $(#[$attr])* + unsafe impl $trait for $ty { + unsafe_impl!(@method $trait $(; |$candidate: &$repr| $is_bit_valid)?); + } + }; + // Implement all `$traits` for `$ty` with no bounds. + ($ty:ty: $($traits:ident),*) => { + $( unsafe_impl!($ty: $traits); )* + }; + // This arm is identical to the following one, except it contains a + // preceding `const`. If we attempt to handle these with a single arm, there + // is an inherent ambiguity between `const` (the keyword) and `const` (the + // ident match for `$tyvar:ident`). + // + // To explain how this works, consider the following invocation: + // + // unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo); + // + // In this invocation, here are the assignments to meta-variables: + // + // |---------------|------------| + // | Meta-variable | Assignment | + // |---------------|------------| + // | $constname | N | + // | $constty | usize | + // | $tyvar | T | + // | $optbound | Sized | + // | $bound | Copy | + // | $trait | Clone | + // | $ty | Foo | + // |---------------|------------| + // + // The following arm has the same behavior with the exception of the lack of + // support for a leading `const` parameter. + ( + $(#[$attr:meta])* + const $constname:ident : $constty:ident $(,)? + $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* + => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => { + unsafe_impl!( + @inner + $(#[$attr])* + @const $constname: $constty, + $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)* + => $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)? + ); + }; + ( + $(#[$attr:meta])* + $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* + => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => { + unsafe_impl!( + @inner + $(#[$attr])* + $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)* + => $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)? + ); + }; + ( + @inner + $(#[$attr:meta])* + $(@const $constname:ident : $constty:ident,)* + $($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)* + => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => { + $(#[$attr])* + unsafe impl<$(const $constname: $constty,)* $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> $trait for $ty { + unsafe_impl!(@method $trait $(; |$candidate: $(&$ref_repr)? $(Ptr<$ptr_repr>)?| $is_bit_valid)?); + } + }; + + (@method TryFromBytes ; |$candidate:ident: &$repr:ty| $is_bit_valid:expr) => { + #[inline] + unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool { + // SAFETY: + // - The argument to `cast_unsized` is `|p| p as *mut _` as required + // by that method's safety precondition. + // - The caller has promised that the cast results in an object of + // equal or lesser size. + // - The caller has promised that `$repr`'s alignment is less than + // or equal to `Self`'s alignment. + #[allow(clippy::as_conversions)] + let candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) }; + // SAFETY: + // - The caller has promised that the referenced memory region will + // contain a valid `$repr` for `'a`. + // - The memory may not be referenced by any mutable references. + // This is a precondition of `is_bit_valid`. + // - The memory may not be mutated even via `UnsafeCell`s. This is a + // precondition of `is_bit_valid`. + // - There must not exist any references to the same memory region + // which contain `UnsafeCell`s at byte ranges which are not + // identical to the byte ranges at which `T` contains + // `UnsafeCell`s. This is a precondition of `is_bit_valid`. + let $candidate: &$repr = unsafe { candidate.as_ref() }; + $is_bit_valid + } + }; + (@method TryFromBytes ; |$candidate:ident: Ptr<$repr:ty>| $is_bit_valid:expr) => { + #[inline] + unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool { + // SAFETY: + // - The argument to `cast_unsized` is `|p| p as *mut _` as required + // by that method's safety precondition. + // - The caller has promised that the cast results in an object of + // equal or lesser size. + // - The caller has promised that `$repr`'s alignment is less than + // or equal to `Self`'s alignment. + #[allow(clippy::as_conversions)] + let $candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) }; + $is_bit_valid + } + }; + (@method TryFromBytes) => { #[inline(always)] unsafe fn is_bit_valid(_: Ptr<'_, Self>) -> bool { true } }; + (@method $trait:ident) => { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + }; + (@method $trait:ident; |$_candidate:ident $(: &$_ref_repr:ty)? $(: NonNull<$_ptr_repr:ty>)?| $_is_bit_valid:expr) => { + compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`"); + }; +} + +/// Implements a trait for a type, bounding on each memeber of the power set of +/// a set of type variables. This is useful for implementing traits for tuples +/// or `fn` types. +/// +/// The last argument is the name of a macro which will be called in every +/// `impl` block, and is expected to expand to the name of the type for which to +/// implement the trait. +/// +/// For example, the invocation: +/// ```ignore +/// unsafe_impl_for_power_set!(A, B => Foo for type!(...)) +/// ``` +/// ...expands to: +/// ```ignore +/// unsafe impl Foo for type!() { ... } +/// unsafe impl Foo for type!(B) { ... } +/// unsafe impl Foo for type!(A, B) { ... } +/// ``` +macro_rules! unsafe_impl_for_power_set { + ($first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => { + unsafe_impl_for_power_set!($($rest),* $(-> $ret)? => $trait for $macro!(...)); + unsafe_impl_for_power_set!(@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...)); + }; + ($(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => { + unsafe_impl_for_power_set!(@impl $(-> $ret)? => $trait for $macro!(...)); + }; + (@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => { + unsafe impl<$($vars,)* $($ret)?> $trait for $macro!($($vars),* $(-> $ret)?) { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + } + }; +} + +/// Expands to an `Option` type with the given argument types and +/// return type. Designed for use with `unsafe_impl_for_power_set`. +macro_rules! opt_extern_c_fn { + ($($args:ident),* -> $ret:ident) => { Option $ret> }; +} + +/// Expands to a `Option` type with the given argument types and return +/// type. Designed for use with `unsafe_impl_for_power_set`. +macro_rules! opt_fn { + ($($args:ident),* -> $ret:ident) => { Option $ret> }; +} + +/// Implements trait(s) for a type or verifies the given implementation by +/// referencing an existing (derived) implementation. +/// +/// This macro exists so that we can provide zerocopy-derive as an optional +/// dependency and still get the benefit of using its derives to validate that +/// our trait impls are sound. +/// +/// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`, +/// `impl_or_verify!` emits the provided trait impl. When compiling with either +/// of those cfgs, it is expected that the type in question is deriving the +/// traits instead. In this case, `impl_or_verify!` emits code which validates +/// that the given trait impl is at least as restrictive as the the impl emitted +/// by the custom derive. This has the effect of confirming that the impl which +/// is emitted when the `derive` feature is disabled is actually sound (on the +/// assumption that the impl emitted by the custom derive is sound). +/// +/// The caller is still required to provide a safety comment (e.g. using the +/// `safety_comment!` macro) . The reason for this restriction is that, while +/// `impl_or_verify!` can guarantee that the provided impl is sound when it is +/// compiled with the appropriate cfgs, there is no way to guarantee that it is +/// ever compiled with those cfgs. In particular, it would be possible to +/// accidentally place an `impl_or_verify!` call in a context that is only ever +/// compiled when the `derive` feature is disabled. If that were to happen, +/// there would be nothing to prevent an unsound trait impl from being emitted. +/// Requiring a safety comment reduces the likelihood of emitting an unsound +/// impl in this case, and also provides useful documentation for readers of the +/// code. +/// +/// ## Example +/// +/// ```rust,ignore +/// // Note that these derives are gated by `feature = "derive"` +/// #[cfg_attr(any(feature = "derive", test), derive(FromZeroes, FromBytes, AsBytes, Unaligned))] +/// #[repr(transparent)] +/// struct Wrapper(T); +/// +/// safety_comment! { +/// /// SAFETY: +/// /// `Wrapper` is `repr(transparent)`, so it is sound to implement any +/// /// zerocopy trait if `T` implements that trait. +/// impl_or_verify!(T: FromZeroes => FromZeroes for Wrapper); +/// impl_or_verify!(T: FromBytes => FromBytes for Wrapper); +/// impl_or_verify!(T: AsBytes => AsBytes for Wrapper); +/// impl_or_verify!(T: Unaligned => Unaligned for Wrapper); +/// } +/// ``` +macro_rules! impl_or_verify { + // The following two match arms follow the same pattern as their + // counterparts in `unsafe_impl!`; see the documentation on those arms for + // more details. + ( + const $constname:ident : $constty:ident $(,)? + $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* + => $trait:ident for $ty:ty + ) => { + impl_or_verify!(@impl { unsafe_impl!( + const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty + ); }); + impl_or_verify!(@verify $trait, { + impl Subtrait for $ty {} + }); + }; + ( + $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* + => $trait:ident for $ty:ty + ) => { + impl_or_verify!(@impl { unsafe_impl!( + $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty + ); }); + impl_or_verify!(@verify $trait, { + impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} + }); + }; + ( + $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* + => $trait:ident for $ty:ty + ) => { + unsafe_impl!( + @inner + $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)* + => $trait for $ty + ); + }; + (@impl $impl_block:tt) => { + #[cfg(not(any(feature = "derive", test)))] + const _: () = { $impl_block }; + }; + (@verify $trait:ident, $impl_block:tt) => { + #[cfg(any(feature = "derive", test))] + const _: () = { + trait Subtrait: $trait {} + $impl_block + }; + }; +} + +/// Implements `KnownLayout` for a sized type. +macro_rules! impl_known_layout { + ($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { + $(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)* + }; + ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { + $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)* + }; + ($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* }; + (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => { + const _: () = { + use core::ptr::NonNull; + + // SAFETY: Delegates safety to `DstLayout::for_type`. + unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {} + + const LAYOUT: DstLayout = DstLayout::for_type::<$ty>(); + + // SAFETY: `.cast` preserves address and provenance. + // + // TODO(#429): Add documentation to `.cast` that promises that + // it preserves provenance. + #[inline(always)] + fn raw_from_ptr_len(bytes: NonNull, _elems: usize) -> NonNull { + bytes.cast::() + } + } + }; + }; +} + +/// Implements `KnownLayout` for a type in terms of the implementation of +/// another type with the same representation. +/// +/// # Safety +/// +/// - `$ty` and `$repr` must have the same: +/// - Fixed prefix size +/// - Alignment +/// - (For DSTs) trailing slice element size +/// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`, +/// and this operation must preserve referent size (ie, `size_of_val_raw`). +macro_rules! unsafe_impl_known_layout { + ($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => { + const _: () = { + use core::ptr::NonNull; + + unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + + const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT; + + // SAFETY: All operations preserve address and provenance. + // Caller has promised that the `as` cast preserves size. + // + // TODO(#429): Add documentation to `NonNull::new_unchecked` + // that it preserves provenance. + #[inline(always)] + #[allow(unused_qualifications)] // for `core::ptr::NonNull` + fn raw_from_ptr_len(bytes: NonNull, elems: usize) -> NonNull { + #[allow(clippy::as_conversions)] + let ptr = <$repr>::raw_from_ptr_len(bytes, elems).as_ptr() as *mut Self; + // SAFETY: `ptr` was converted from `bytes`, which is non-null. + unsafe { NonNull::new_unchecked(ptr) } + } + } + }; + }; +} + +/// Uses `align_of` to confirm that a type or set of types have alignment 1. +/// +/// Note that `align_of` requires `T: Sized`, so this macro doesn't work for +/// unsized types. +macro_rules! assert_unaligned { + ($ty:ty) => { + // We only compile this assertion under `cfg(test)` to avoid taking an + // extra non-dev dependency (and making this crate more expensive to + // compile for our dependents). + #[cfg(test)] + static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1); + }; + ($($ty:ty),*) => { + $(assert_unaligned!($ty);)* + }; +} diff --git a/third_party/rust/zerocopy/src/post_monomorphization_compile_fail_tests.rs b/third_party/rust/zerocopy/src/post_monomorphization_compile_fail_tests.rs new file mode 100644 index 0000000000..32505b6693 --- /dev/null +++ b/third_party/rust/zerocopy/src/post_monomorphization_compile_fail_tests.rs @@ -0,0 +1,118 @@ +// Copyright 2018 The Fuchsia Authors +// +// Licensed under the 2-Clause BSD License , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//! Code that should fail to compile during the post-monomorphization compiler +//! pass. +//! +//! Due to [a limitation with the `trybuild` crate][trybuild-issue], we cannot +//! use our UI testing framework to test compilation failures that are +//! encountered after monomorphization has complated. This module has one item +//! for each such test we would prefer to have as a UI test, with the code in +//! question appearing as a rustdoc example which is marked with `compile_fail`. +//! This has the effect of causing doctests to fail if any of these examples +//! compile successfully. +//! +//! This is very much a hack and not a complete replacement for UI tests - most +//! notably because this only provides a single "compile vs fail" bit of +//! information, but does not allow us to depend upon the specific error that +//! causes compilation to fail. +//! +//! [trybuild-issue]: https://github.com/dtolnay/trybuild/issues/241 + +// Miri doesn't detect post-monimorphization failures as compile-time failures, +// but instead as runtime failures. +#![cfg(not(miri))] + +/// ```compile_fail +/// use core::cell::{Ref, RefCell}; +/// +/// let refcell = RefCell::new([0u8, 1, 2, 3]); +/// let core_ref = refcell.borrow(); +/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]); +/// +/// // `zc_ref` now stores `core_ref` internally. +/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref).unwrap(); +/// +/// // This causes `core_ref` to get dropped and synthesizes a Rust +/// // reference to the memory `core_ref` was pointing at. +/// let rust_ref = zc_ref.into_ref(); +/// +/// // UB!!! This mutates `rust_ref`'s referent while it's alive. +/// *refcell.borrow_mut() = [0, 0, 0, 0]; +/// +/// println!("{}", rust_ref); +/// ``` +#[allow(unused)] +const REFCELL_REF_INTO_REF: () = (); + +/// ```compile_fail +/// use core::cell::{RefCell, RefMut}; +/// +/// let refcell = RefCell::new([0u8, 1, 2, 3]); +/// let core_ref_mut = refcell.borrow_mut(); +/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]); +/// +/// // `zc_ref` now stores `core_ref_mut` internally. +/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref_mut).unwrap(); +/// +/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust +/// // reference to the memory `core_ref` was pointing at. +/// let rust_ref_mut = zc_ref.into_mut(); +/// +/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive. +/// *refcell.borrow_mut() = [0, 0, 0, 0]; +/// +/// println!("{}", rust_ref_mut); +/// ``` +#[allow(unused)] +const REFCELL_REFMUT_INTO_MUT: () = (); + +/// ```compile_fail +/// use core::cell::{Ref, RefCell}; +/// +/// let refcell = RefCell::new([0u8, 1, 2, 3]); +/// let core_ref = refcell.borrow(); +/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]); +/// +/// // `zc_ref` now stores `core_ref` internally. +/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref).unwrap(); +/// +/// // This causes `core_ref` to get dropped and synthesizes a Rust +/// // reference to the memory `core_ref` was pointing at. +/// let rust_ref = zc_ref.into_slice(); +/// +/// // UB!!! This mutates `rust_ref`'s referent while it's alive. +/// *refcell.borrow_mut() = [0, 0, 0, 0]; +/// +/// println!("{:?}", rust_ref); +/// ``` +#[allow(unused)] +const REFCELL_REFMUT_INTO_SLICE: () = (); + +/// ```compile_fail +/// use core::cell::{RefCell, RefMut}; +/// +/// let refcell = RefCell::new([0u8, 1, 2, 3]); +/// let core_ref_mut = refcell.borrow_mut(); +/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]); +/// +/// // `zc_ref` now stores `core_ref_mut` internally. +/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref_mut).unwrap(); +/// +/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust +/// // reference to the memory `core_ref` was pointing at. +/// let rust_ref_mut = zc_ref.into_mut_slice(); +/// +/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive. +/// *refcell.borrow_mut() = [0, 0, 0, 0]; +/// +/// println!("{:?}", rust_ref_mut); +/// ``` +#[allow(unused)] +const REFCELL_REFMUT_INTO_MUT_SLICE: () = (); diff --git a/third_party/rust/zerocopy/src/third_party/rust/LICENSE-APACHE b/third_party/rust/zerocopy/src/third_party/rust/LICENSE-APACHE new file mode 100644 index 0000000000..1b5ec8b78e --- /dev/null +++ b/third_party/rust/zerocopy/src/third_party/rust/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/rust/zerocopy/src/third_party/rust/LICENSE-MIT b/third_party/rust/zerocopy/src/third_party/rust/LICENSE-MIT new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/third_party/rust/zerocopy/src/third_party/rust/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/zerocopy/src/third_party/rust/README.fuchsia b/third_party/rust/zerocopy/src/third_party/rust/README.fuchsia new file mode 100644 index 0000000000..e0a23dd8e5 --- /dev/null +++ b/third_party/rust/zerocopy/src/third_party/rust/README.fuchsia @@ -0,0 +1,7 @@ +Name: rust +License File: LICENSE-APACHE +License File: LICENSE-MIT +Description: + +See https://github.com/google/zerocopy/pull/492 for an explanation of why this +file exists. diff --git a/third_party/rust/zerocopy/src/third_party/rust/layout.rs b/third_party/rust/zerocopy/src/third_party/rust/layout.rs new file mode 100644 index 0000000000..19ef7c6982 --- /dev/null +++ b/third_party/rust/zerocopy/src/third_party/rust/layout.rs @@ -0,0 +1,45 @@ +use core::num::NonZeroUsize; + +/// Returns the amount of padding we must insert after `len` bytes to ensure +/// that the following address will satisfy `align` (measured in bytes). +/// +/// e.g., if `len` is 9, then `padding_needed_for(len, 4)` returns 3, because +/// that is the minimum number of bytes of padding required to get a 4-aligned +/// address (assuming that the corresponding memory block starts at a 4-aligned +/// address). +/// +/// The return value of this function has no meaning if `align` is not a +/// power-of-two. +/// +/// # Panics +/// +/// May panic if `align` is not a power of two. +// +// TODO(#419): Replace `len` with a witness type for region size. +#[allow(unused)] +#[inline(always)] +pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize { + // Rounded up value is: + // len_rounded_up = (len + align - 1) & !(align - 1); + // and then we return the padding difference: `len_rounded_up - len`. + // + // We use modular arithmetic throughout: + // + // 1. align is guaranteed to be > 0, so align - 1 is always + // valid. + // + // 2. `len + align - 1` can overflow by at most `align - 1`, + // so the &-mask with `!(align - 1)` will ensure that in the + // case of overflow, `len_rounded_up` will itself be 0. + // Thus the returned padding, when added to `len`, yields 0, + // which trivially satisfies the alignment `align`. + // + // (Of course, attempts to allocate blocks of memory whose + // size and padding overflow in the above manner should cause + // the allocator to yield an error anyway.) + + let align = align.get(); + debug_assert!(align.is_power_of_two()); + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + len_rounded_up.wrapping_sub(len) +} diff --git a/third_party/rust/zerocopy/src/util.rs b/third_party/rust/zerocopy/src/util.rs new file mode 100644 index 0000000000..b35cc079c1 --- /dev/null +++ b/third_party/rust/zerocopy/src/util.rs @@ -0,0 +1,808 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[path = "third_party/rust/layout.rs"] +pub(crate) mod core_layout; + +use core::{mem, num::NonZeroUsize}; + +pub(crate) mod ptr { + use core::{ + fmt::{Debug, Formatter}, + marker::PhantomData, + ptr::NonNull, + }; + + use crate::{util::AsAddress, KnownLayout, _CastType}; + + /// A raw pointer with more restrictions. + /// + /// `Ptr` is similar to `NonNull`, but it is more restrictive in the + /// following ways: + /// - It must derive from a valid allocation + /// - It must reference a byte range which is contained inside the + /// allocation from which it derives + /// - As a consequence, the byte range it references must have a size + /// which does not overflow `isize` + /// - It must satisfy `T`'s alignment requirement + /// + /// Thanks to these restrictions, it is easier to prove the soundness of + /// some operations using `Ptr`s. + /// + /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. + /// + /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html + pub struct Ptr<'a, T: 'a + ?Sized> { + // INVARIANTS: + // 1. `ptr` is derived from some valid Rust allocation, `A` + // 2. `ptr` has the same provenance as `A` + // 3. `ptr` addresses a byte range which is entirely contained in `A` + // 4. `ptr` addresses a byte range whose length fits in an `isize` + // 5. `ptr` addresses a byte range which does not wrap around the address + // space + // 6. `ptr` is validly-aligned for `T` + // 7. `A` is guaranteed to live for at least `'a` + // 8. `T: 'a` + ptr: NonNull, + _lifetime: PhantomData<&'a ()>, + } + + impl<'a, T: ?Sized> Copy for Ptr<'a, T> {} + impl<'a, T: ?Sized> Clone for Ptr<'a, T> { + #[inline] + fn clone(&self) -> Self { + *self + } + } + + impl<'a, T: ?Sized> Ptr<'a, T> { + /// Returns a shared reference to the value. + /// + /// # Safety + /// + /// For the duration of `'a`: + /// - The referenced memory must contain a validly-initialized `T` for + /// the duration of `'a`. + /// - The referenced memory must not also be referenced by any mutable + /// references. + /// - The referenced memory must not be mutated, even via an + /// [`UnsafeCell`]. + /// - There must not exist any references to the same memory region + /// which contain `UnsafeCell`s at byte ranges which are not identical + /// to the byte ranges at which `T` contains `UnsafeCell`s. + /// + /// [`UnsafeCell`]: core::cell::UnsafeCell + // TODO(#429): The safety requirements are likely overly-restrictive. + // Notably, mutation via `UnsafeCell`s is probably fine. Once the rules + // are more clearly defined, we should relax the safety requirements. + // For an example of why this is subtle, see: + // https://github.com/rust-lang/unsafe-code-guidelines/issues/463#issuecomment-1736771593 + #[allow(unused)] + pub(crate) unsafe fn as_ref(&self) -> &'a T { + // SAFETY: + // - By invariant, `self.ptr` is properly-aligned for `T`. + // - By invariant, `self.ptr` is "dereferenceable" in that it points + // to a single allocation. + // - By invariant, the allocation is live for `'a`. + // - The caller promises that no mutable references exist to this + // region during `'a`. + // - The caller promises that `UnsafeCell`s match exactly. + // - The caller promises that no mutation will happen during `'a`, + // even via `UnsafeCell`s. + // - The caller promises that the memory region contains a + // validly-intialized `T`. + unsafe { self.ptr.as_ref() } + } + + /// Casts to a different (unsized) target type. + /// + /// # Safety + /// + /// The caller promises that + /// - `cast(p)` is implemented exactly as follows: `|p: *mut T| p as + /// *mut U`. + /// - The size of the object referenced by the resulting pointer is less + /// than or equal to the size of the object referenced by `self`. + /// - The alignment of `U` is less than or equal to the alignment of + /// `T`. + pub(crate) unsafe fn cast_unsized *mut U>( + self, + cast: F, + ) -> Ptr<'a, U> { + let ptr = cast(self.ptr.as_ptr()); + // SAFETY: Caller promises that `cast` is just an `as` cast. We call + // `cast` on `self.ptr.as_ptr()`, which is non-null by construction. + let ptr = unsafe { NonNull::new_unchecked(ptr) }; + // SAFETY: + // - By invariant, `self.ptr` is derived from some valid Rust + // allocation, and since `ptr` is just `self.ptr as *mut U`, so is + // `ptr`. + // - By invariant, `self.ptr` has the same provenance as `A`, and so + // the same is true of `ptr`. + // - By invariant, `self.ptr` addresses a byte range which is + // entirely contained in `A`, and so the same is true of `ptr`. + // - By invariant, `self.ptr` addresses a byte range whose length + // fits in an `isize`, and so the same is true of `ptr`. + // - By invariant, `self.ptr` addresses a byte range which does not + // wrap around the address space, and so the same is true of + // `ptr`. + // - By invariant, `self.ptr` is validly-aligned for `T`. Since + // `ptr` has the same address, and since the caller promises that + // the alignment of `U` is less than or equal to the alignment of + // `T`, `ptr` is validly-aligned for `U`. + // - By invariant, `A` is guaranteed to live for at least `'a`. + // - `U: 'a` + Ptr { ptr, _lifetime: PhantomData } + } + } + + impl<'a> Ptr<'a, [u8]> { + /// Attempts to cast `self` to a `U` using the given cast type. + /// + /// Returns `None` if the resulting `U` would be invalidly-aligned or if + /// no `U` can fit in `self`. On success, returns a pointer to the + /// largest-possible `U` which fits in `self`. + /// + /// # Safety + /// + /// The caller may assume that this implementation is correct, and may + /// rely on that assumption for the soundness of their code. In + /// particular, the caller may assume that, if `try_cast_into` returns + /// `Some((ptr, split_at))`, then: + /// - If this is a prefix cast, `ptr` refers to the byte range `[0, + /// split_at)` in `self`. + /// - If this is a suffix cast, `ptr` refers to the byte range + /// `[split_at, self.len())` in `self`. + /// + /// # Panics + /// + /// Panics if `U` is a DST whose trailing slice element is zero-sized. + pub(crate) fn try_cast_into( + &self, + cast_type: _CastType, + ) -> Option<(Ptr<'a, U>, usize)> { + // PANICS: By invariant, the byte range addressed by `self.ptr` does + // not wrap around the address space. This implies that the sum of + // the address (represented as a `usize`) and length do not overflow + // `usize`, as required by `validate_cast_and_convert_metadata`. + // Thus, this call to `validate_cast_and_convert_metadata` won't + // panic. + let (elems, split_at) = U::LAYOUT.validate_cast_and_convert_metadata( + AsAddress::addr(self.ptr.as_ptr()), + self.len(), + cast_type, + )?; + let offset = match cast_type { + _CastType::_Prefix => 0, + _CastType::_Suffix => split_at, + }; + + let ptr = self.ptr.cast::().as_ptr(); + // SAFETY: `offset` is either `0` or `split_at`. + // `validate_cast_and_convert_metadata` promises that `split_at` is + // in the range `[0, self.len()]`. Thus, in both cases, `offset` is + // in `[0, self.len()]`. Thus: + // - The resulting pointer is in or one byte past the end of the + // same byte range as `self.ptr`. Since, by invariant, `self.ptr` + // addresses a byte range entirely contained within a single + // allocation, the pointer resulting from this operation is within + // or one byte past the end of that same allocation. + // - By invariant, `self.len() <= isize::MAX`. Since `offset <= + // self.len()`, `offset <= isize::MAX`. + // - By invariant, `self.ptr` addresses a byte range which does not + // wrap around the address space. This means that the base pointer + // plus the `self.len()` does not overflow `usize`. Since `offset + // <= self.len()`, this addition does not overflow `usize`. + let base = unsafe { ptr.add(offset) }; + // SAFETY: Since `add` is not allowed to wrap around, the preceding line + // produces a pointer whose address is greater than or equal to that of + // `ptr`. Since `ptr` is a `NonNull`, `base` is also non-null. + let base = unsafe { NonNull::new_unchecked(base) }; + let ptr = U::raw_from_ptr_len(base, elems); + // SAFETY: + // - By invariant, `self.ptr` is derived from some valid Rust + // allocation, `A`, and has the same provenance as `A`. All + // operations performed on `self.ptr` and values derived from it + // in this method preserve provenance, so: + // - `ptr` is derived from a valid Rust allocation, `A`. + // - `ptr` has the same provenance as `A`. + // - `validate_cast_and_convert_metadata` promises that the object + // described by `elems` and `split_at` lives at a byte range which + // is a subset of the input byte range. Thus: + // - Since, by invariant, `self.ptr` addresses a byte range + // entirely contained in `A`, so does `ptr`. + // - Since, by invariant, `self.ptr` addresses a range whose + // length is not longer than `isize::MAX` bytes, so does `ptr`. + // - Since, by invariant, `self.ptr` addresses a range which does + // not wrap around the address space, so does `ptr`. + // - `validate_cast_and_convert_metadata` promises that the object + // described by `split_at` is validly-aligned for `U`. + // - By invariant on `self`, `A` is guaranteed to live for at least + // `'a`. + // - `U: 'a` by trait bound. + Some((Ptr { ptr, _lifetime: PhantomData }, split_at)) + } + + /// Attempts to cast `self` into a `U`, failing if all of the bytes of + /// `self` cannot be treated as a `U`. + /// + /// In particular, this method fails if `self` is not validly-aligned + /// for `U` or if `self`'s size is not a valid size for `U`. + /// + /// # Safety + /// + /// On success, the caller may assume that the returned pointer + /// references the same byte range as `self`. + #[allow(unused)] + #[inline(always)] + pub(crate) fn try_cast_into_no_leftover( + &self, + ) -> Option> { + // TODO(#67): Remove this allow. See NonNulSlicelExt for more + // details. + #[allow(unstable_name_collisions)] + match self.try_cast_into(_CastType::_Prefix) { + Some((slf, split_at)) if split_at == self.len() => Some(slf), + Some(_) | None => None, + } + } + } + + impl<'a, T> Ptr<'a, [T]> { + /// The number of slice elements referenced by `self`. + /// + /// # Safety + /// + /// Unsafe code my rely on `len` satisfying the above contract. + fn len(&self) -> usize { + #[allow(clippy::as_conversions)] + let slc = self.ptr.as_ptr() as *const [()]; + // SAFETY: + // - `()` has alignment 1, so `slc` is trivially aligned. + // - `slc` was derived from a non-null pointer. + // - The size is 0 regardless of the length, so it is sound to + // materialize a reference regardless of location. + // - By invariant, `self.ptr` has valid provenance. + let slc = unsafe { &*slc }; + // This is correct because the preceding `as` cast preserves the + // number of slice elements. Per + // https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#slice-dst-pointer-to-pointer-cast: + // + // For slice types like `[T]` and `[U]`, the raw pointer types + // `*const [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode + // the number of elements in this slice. Casts between these raw + // pointer types preserve the number of elements. Note that, as a + // consequence, such casts do *not* necessarily preserve the size + // of the pointer's referent (e.g., casting `*const [u16]` to + // `*const [u8]` will result in a raw pointer which refers to an + // object of half the size of the original). The same holds for + // `str` and any compound type whose unsized tail is a slice type, + // such as struct `Foo(i32, [u8])` or `(u64, Foo)`. + // + // TODO(#429), + // TODO(https://github.com/rust-lang/reference/pull/1417): Once this + // text is available on the Stable docs, cite those instead of the + // Nightly docs. + slc.len() + } + + pub(crate) fn iter(&self) -> impl Iterator> { + // TODO(#429): Once `NonNull::cast` documents that it preserves + // provenance, cite those docs. + let base = self.ptr.cast::().as_ptr(); + (0..self.len()).map(move |i| { + // TODO(https://github.com/rust-lang/rust/issues/74265): Use + // `NonNull::get_unchecked_mut`. + + // SAFETY: If the following conditions are not satisfied + // `pointer::cast` may induce Undefined Behavior [1]: + // > 1. Both the starting and resulting pointer must be either + // > in bounds or one byte past the end of the same allocated + // > object. + // > 2. The computed offset, in bytes, cannot overflow an + // > `isize`. + // > 3. The offset being in bounds cannot rely on “wrapping + // > around” the address space. That is, the + // > infinite-precision sum must fit in a `usize`. + // + // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add + // + // We satisfy all three of these conditions here: + // 1. `base` (by invariant on `self`) points to an allocated + // object. By contract, `self.len()` accurately reflects the + // number of elements in the slice. `i` is in bounds of + // `c.len()` by construction, and so the result of this + // addition cannot overflow past the end of the allocation + // referred to by `c`. + // 2. By invariant on `Ptr`, `self` addresses a byte range whose + // length fits in an `isize`. Since `elem` is contained in + // `self`, the computed offset of `elem` must fit within + // `isize.` + // 3. By invariant on `Ptr`, `self` addresses a byte range which + // does not wrap around the address space. Since `elem` is + // contained in `self`, the computed offset of `elem` must + // wrap around the address space. + // + // TODO(#429): Once `pointer::add` documents that it preserves + // provenance, cite those docs. + let elem = unsafe { base.add(i) }; + + // SAFETY: + // - `elem` must not be null. `base` is constructed from a + // `NonNull` pointer, and the addition that produces `elem` + // must not overflow or wrap around, so `elem >= base > 0`. + // + // TODO(#429): Once `NonNull::new_unchecked` documents that it + // preserves provenance, cite those docs. + let elem = unsafe { NonNull::new_unchecked(elem) }; + + // SAFETY: The safety invariants of `Ptr` (see definition) are + // satisfied: + // 1. `elem` is derived from a valid Rust allocation, because + // `self` is derived from a valid Rust allocation, by + // invariant on `Ptr` + // 2. `elem` has the same provenance as `self`, because it + // derived from `self` using a series of + // provenance-preserving operations + // 3. `elem` is entirely contained in the allocation of `self` + // (see above) + // 4. `elem` addresses a byte range whose length fits in an + // `isize` (see above) + // 5. `elem` addresses a byte range which does not wrap around + // the address space (see above) + // 6. `elem` is validly-aligned for `T`. `self`, which + // represents a `[T]` is validly aligned for `T`, and `elem` + // is an element within that `[T]` + // 7. The allocation of `elem` is guaranteed to live for at + // least `'a`, because `elem` is entirely contained in + // `self`, which lives for at least `'a` by invariant on + // `Ptr`. + // 8. `T: 'a`, because `elem` is an element within `[T]`, and + // `[T]: 'a` by invariant on `Ptr` + Ptr { ptr: elem, _lifetime: PhantomData } + }) + } + } + + impl<'a, T: 'a + ?Sized> From<&'a T> for Ptr<'a, T> { + #[inline(always)] + fn from(t: &'a T) -> Ptr<'a, T> { + // SAFETY: `t` points to a valid Rust allocation, `A`, by + // construction. Thus: + // - `ptr` is derived from `A` + // - Since we use `NonNull::from`, which preserves provenance, `ptr` + // has the same provenance as `A` + // - Since `NonNull::from` creates a pointer which addresses the + // same bytes as `t`, `ptr` addresses a byte range entirely + // contained in (in this case, identical to) `A` + // - Since `t: &T`, it addresses no more than `isize::MAX` bytes [1] + // - Since `t: &T`, it addresses a byte range which does not wrap + // around the address space [2] + // - Since it is constructed from a valid `&T`, `ptr` is + // validly-aligned for `T` + // - Since `t: &'a T`, the allocation `A` is guaranteed to live for + // at least `'a` + // - `T: 'a` by trait bound + // + // TODO(#429), + // TODO(https://github.com/rust-lang/rust/issues/116181): Once it's + // documented, reference the guarantee that `NonNull::from` + // preserves provenance. + // + // TODO(#429), + // TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465): + // - [1] Where does the reference document that allocations fit in + // `isize`? + // - [2] Where does the reference document that allocations don't + // wrap around the address space? + Ptr { ptr: NonNull::from(t), _lifetime: PhantomData } + } + } + + impl<'a, T: 'a + ?Sized> Debug for Ptr<'a, T> { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + self.ptr.fmt(f) + } + } + + #[cfg(test)] + mod tests { + use core::mem::{self, MaybeUninit}; + + use super::*; + use crate::{util::testutil::AU64, FromBytes}; + + #[test] + fn test_ptrtry_cast_into_soundness() { + // This test is designed so that if `Ptr::try_cast_into_xxx` are + // buggy, it will manifest as unsoundness that Miri can detect. + + // - If `size_of::() == 0`, `N == 4` + // - Else, `N == 4 * size_of::()` + fn test() { + let mut bytes = [MaybeUninit::::uninit(); N]; + let initialized = [MaybeUninit::new(0u8); N]; + for start in 0..=bytes.len() { + for end in start..=bytes.len() { + // Set all bytes to uninitialized other than those in + // the range we're going to pass to `try_cast_from`. + // This allows Miri to detect out-of-bounds reads + // because they read uninitialized memory. Without this, + // some out-of-bounds reads would still be in-bounds of + // `bytes`, and so might spuriously be accepted. + bytes = [MaybeUninit::::uninit(); N]; + let bytes = &mut bytes[start..end]; + // Initialize only the byte range we're going to pass to + // `try_cast_from`. + bytes.copy_from_slice(&initialized[start..end]); + + let bytes = { + let bytes: *const [MaybeUninit] = bytes; + #[allow(clippy::as_conversions)] + let bytes = bytes as *const [u8]; + // SAFETY: We just initialized these bytes to valid + // `u8`s. + unsafe { &*bytes } + }; + + /// # Safety + /// + /// - `slf` must reference a byte range which is + /// entirely initialized. + /// - `slf` must reference a byte range which is only + /// referenced by shared references which do not + /// contain `UnsafeCell`s during its lifetime. + unsafe fn validate_and_get_len( + slf: Ptr<'_, T>, + ) -> usize { + // SAFETY: + // - Since all bytes in `slf` are initialized and + // `T: FromBytes`, `slf` contains a valid `T`. + // - The caller promises that the referenced memory + // is not also referenced by any mutable + // references. + // - The caller promises that the referenced memory + // is not also referenced as a type which contains + // `UnsafeCell`s. + let t = unsafe { slf.as_ref() }; + + let bytes = { + let len = mem::size_of_val(t); + let t: *const T = t; + // SAFETY: + // - We know `t`'s bytes are all initialized + // because we just read it from `slf`, which + // points to an initialized range of bytes. If + // there's a bug and this doesn't hold, then + // that's exactly what we're hoping Miri will + // catch! + // - Since `T: FromBytes`, `T` doesn't contain + // any `UnsafeCell`s, so it's okay for `t: T` + // and a `&[u8]` to the same memory to be + // alive concurrently. + unsafe { core::slice::from_raw_parts(t.cast::(), len) } + }; + + // This assertion ensures that `t`'s bytes are read + // and compared to another value, which in turn + // ensures that Miri gets a chance to notice if any + // of `t`'s bytes are uninitialized, which they + // shouldn't be (see the comment above). + assert_eq!(bytes, vec![0u8; bytes.len()]); + + mem::size_of_val(t) + } + + for cast_type in [_CastType::_Prefix, _CastType::_Suffix] { + if let Some((slf, split_at)) = + Ptr::from(bytes).try_cast_into::(cast_type) + { + // SAFETY: All bytes in `bytes` have been + // initialized. + let len = unsafe { validate_and_get_len(slf) }; + match cast_type { + _CastType::_Prefix => assert_eq!(split_at, len), + _CastType::_Suffix => assert_eq!(split_at, bytes.len() - len), + } + } + } + + if let Some(slf) = Ptr::from(bytes).try_cast_into_no_leftover::() { + // SAFETY: All bytes in `bytes` have been + // initialized. + let len = unsafe { validate_and_get_len(slf) }; + assert_eq!(len, bytes.len()); + } + } + } + } + + macro_rules! test { + ($($ty:ty),*) => { + $({ + const S: usize = core::mem::size_of::<$ty>(); + const N: usize = if S == 0 { 4 } else { S * 4 }; + test::(); + // We don't support casting into DSTs whose trailing slice + // element is a ZST. + if S > 0 { + test::(); + } + // TODO: Test with a slice DST once we have any that + // implement `KnownLayout + FromBytes`. + })* + }; + } + + test!(()); + test!(u8, u16, u32, u64, u128, usize, AU64); + test!(i8, i16, i32, i64, i128, isize); + test!(f32, f64); + } + } +} + +pub(crate) trait AsAddress { + fn addr(self) -> usize; +} + +impl<'a, T: ?Sized> AsAddress for &'a T { + #[inline(always)] + fn addr(self) -> usize { + let ptr: *const T = self; + AsAddress::addr(ptr) + } +} + +impl<'a, T: ?Sized> AsAddress for &'a mut T { + #[inline(always)] + fn addr(self) -> usize { + let ptr: *const T = self; + AsAddress::addr(ptr) + } +} + +impl AsAddress for *const T { + #[inline(always)] + fn addr(self) -> usize { + // TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use + // `.addr()` instead of `as usize` once it's stable, and get rid of this + // `allow`. Currently, `as usize` is the only way to accomplish this. + #[allow(clippy::as_conversions)] + #[cfg_attr(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, allow(lossy_provenance_casts))] + return self.cast::<()>() as usize; + } +} + +impl AsAddress for *mut T { + #[inline(always)] + fn addr(self) -> usize { + let ptr: *const T = self; + AsAddress::addr(ptr) + } +} + +/// Is `t` aligned to `mem::align_of::()`? +#[inline(always)] +pub(crate) fn aligned_to(t: T) -> bool { + // `mem::align_of::()` is guaranteed to return a non-zero value, which in + // turn guarantees that this mod operation will not panic. + #[allow(clippy::arithmetic_side_effects)] + let remainder = t.addr() % mem::align_of::(); + remainder == 0 +} + +/// Round `n` down to the largest value `m` such that `m <= n` and `m % align == +/// 0`. +/// +/// # Panics +/// +/// May panic if `align` is not a power of two. Even if it doesn't panic in this +/// case, it will produce nonsense results. +#[inline(always)] +pub(crate) const fn round_down_to_next_multiple_of_alignment( + n: usize, + align: NonZeroUsize, +) -> usize { + let align = align.get(); + debug_assert!(align.is_power_of_two()); + + // Subtraction can't underflow because `align.get() >= 1`. + #[allow(clippy::arithmetic_side_effects)] + let mask = !(align - 1); + n & mask +} + +pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { + if a.get() < b.get() { + b + } else { + a + } +} + +pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { + if a.get() > b.get() { + b + } else { + a + } +} + +/// Since we support multiple versions of Rust, there are often features which +/// have been stabilized in the most recent stable release which do not yet +/// exist (stably) on our MSRV. This module provides polyfills for those +/// features so that we can write more "modern" code, and just remove the +/// polyfill once our MSRV supports the corresponding feature. Without this, +/// we'd have to write worse/more verbose code and leave TODO comments sprinkled +/// throughout the codebase to update to the new pattern once it's stabilized. +/// +/// Each trait is imported as `_` at the crate root; each polyfill should "just +/// work" at usage sites. +pub(crate) mod polyfills { + use core::ptr::{self, NonNull}; + + // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our + // MSRV is 1.70, when that function was stabilized. + // + // TODO(#67): Once our MSRV is 1.70, remove this. + pub(crate) trait NonNullExt { + fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>; + } + + impl NonNullExt for NonNull { + #[inline(always)] + fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> { + let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len); + // SAFETY: `ptr` is converted from `data`, which is non-null. + unsafe { NonNull::new_unchecked(ptr) } + } + } +} + +#[cfg(test)] +pub(crate) mod testutil { + use core::fmt::{self, Display, Formatter}; + + use crate::*; + + /// A `T` which is aligned to at least `align_of::()`. + #[derive(Default)] + pub(crate) struct Align { + pub(crate) t: T, + _a: [A; 0], + } + + impl Align { + pub(crate) fn set_default(&mut self) { + self.t = T::default(); + } + } + + impl Align { + pub(crate) const fn new(t: T) -> Align { + Align { t, _a: [] } + } + } + + // A `u64` with alignment 8. + // + // Though `u64` has alignment 8 on some platforms, it's not guaranteed. + // By contrast, `AU64` is guaranteed to have alignment 8. + #[derive( + KnownLayout, + FromZeroes, + FromBytes, + AsBytes, + Eq, + PartialEq, + Ord, + PartialOrd, + Default, + Debug, + Copy, + Clone, + )] + #[repr(C, align(8))] + pub(crate) struct AU64(pub(crate) u64); + + impl AU64 { + // Converts this `AU64` to bytes using this platform's endianness. + pub(crate) fn to_bytes(self) -> [u8; 8] { + crate::transmute!(self) + } + } + + impl Display for AU64 { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } + } + + #[derive( + FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone, + )] + #[repr(C)] + pub(crate) struct Nested { + _t: T, + _u: U, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_round_down_to_next_multiple_of_alignment() { + fn alt_impl(n: usize, align: NonZeroUsize) -> usize { + let mul = n / align.get(); + mul * align.get() + } + + for align in [1, 2, 4, 8, 16] { + for n in 0..256 { + let align = NonZeroUsize::new(align).unwrap(); + let want = alt_impl(n, align); + let got = round_down_to_next_multiple_of_alignment(n, align); + assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({n}, {align})"); + } + } + } +} + +#[cfg(kani)] +mod proofs { + use super::*; + + #[kani::proof] + fn prove_round_down_to_next_multiple_of_alignment() { + fn model_impl(n: usize, align: NonZeroUsize) -> usize { + assert!(align.get().is_power_of_two()); + let mul = n / align.get(); + mul * align.get() + } + + let align: NonZeroUsize = kani::any(); + kani::assume(align.get().is_power_of_two()); + let n: usize = kani::any(); + + let expected = model_impl(n, align); + let actual = round_down_to_next_multiple_of_alignment(n, align); + assert_eq!(expected, actual, "round_down_to_next_multiple_of_alignment({n}, {align})"); + } + + // Restricted to nightly since we use the unstable `usize::next_multiple_of` + // in our model implementation. + #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] + #[kani::proof] + fn prove_padding_needed_for() { + fn model_impl(len: usize, align: NonZeroUsize) -> usize { + let padded = len.next_multiple_of(align.get()); + let padding = padded - len; + padding + } + + let align: NonZeroUsize = kani::any(); + kani::assume(align.get().is_power_of_two()); + let len: usize = kani::any(); + // Constrain `len` to valid Rust lengths, since our model implementation + // isn't robust to overflow. + kani::assume(len <= isize::MAX as usize); + kani::assume(align.get() < 1 << 29); + + let expected = model_impl(len, align); + let actual = core_layout::padding_needed_for(len, align); + assert_eq!(expected, actual, "padding_needed_for({len}, {align})"); + + let padded_len = actual + len; + assert_eq!(padded_len % align, 0); + assert!(padded_len / align >= len / align); + } +} diff --git a/third_party/rust/zerocopy/src/wrappers.rs b/third_party/rust/zerocopy/src/wrappers.rs new file mode 100644 index 0000000000..532d872978 --- /dev/null +++ b/third_party/rust/zerocopy/src/wrappers.rs @@ -0,0 +1,503 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use core::{ + cmp::Ordering, + fmt::{self, Debug, Display, Formatter}, + hash::Hash, + mem::{self, ManuallyDrop}, + ops::{Deref, DerefMut}, + ptr, +}; + +use super::*; + +/// A type with no alignment requirement. +/// +/// An `Unalign` wraps a `T`, removing any alignment requirement. `Unalign` +/// has the same size and bit validity as `T`, but not necessarily the same +/// alignment [or ABI]. This is useful if a type with an alignment requirement +/// needs to be read from a chunk of memory which provides no alignment +/// guarantees. +/// +/// Since `Unalign` has no alignment requirement, the inner `T` may not be +/// properly aligned in memory. There are five ways to access the inner `T`: +/// - by value, using [`get`] or [`into_inner`] +/// - by reference inside of a callback, using [`update`] +/// - fallibly by reference, using [`try_deref`] or [`try_deref_mut`]; these can +/// fail if the `Unalign` does not satisfy `T`'s alignment requirement at +/// runtime +/// - unsafely by reference, using [`deref_unchecked`] or +/// [`deref_mut_unchecked`]; it is the caller's responsibility to ensure that +/// the `Unalign` satisfies `T`'s alignment requirement +/// - (where `T: Unaligned`) infallibly by reference, using [`Deref::deref`] or +/// [`DerefMut::deref_mut`] +/// +/// [or ABI]: https://github.com/google/zerocopy/issues/164 +/// [`get`]: Unalign::get +/// [`into_inner`]: Unalign::into_inner +/// [`update`]: Unalign::update +/// [`try_deref`]: Unalign::try_deref +/// [`try_deref_mut`]: Unalign::try_deref_mut +/// [`deref_unchecked`]: Unalign::deref_unchecked +/// [`deref_mut_unchecked`]: Unalign::deref_mut_unchecked +// NOTE: This type is sound to use with types that need to be dropped. The +// reason is that the compiler-generated drop code automatically moves all +// values to aligned memory slots before dropping them in-place. This is not +// well-documented, but it's hinted at in places like [1] and [2]. However, this +// also means that `T` must be `Sized`; unless something changes, we can never +// support unsized `T`. [3] +// +// [1] https://github.com/rust-lang/rust/issues/54148#issuecomment-420529646 +// [2] https://github.com/google/zerocopy/pull/126#discussion_r1018512323 +// [3] https://github.com/google/zerocopy/issues/209 +#[allow(missing_debug_implementations)] +#[derive(Default, Copy)] +#[cfg_attr( + any(feature = "derive", test), + derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned) +)] +#[repr(C, packed)] +pub struct Unalign(T); + +#[cfg(not(any(feature = "derive", test)))] +impl_known_layout!(T => Unalign); + +safety_comment! { + /// SAFETY: + /// - `Unalign` is `repr(packed)`, so it is unaligned regardless of the + /// alignment of `T`, and so we don't require that `T: Unaligned` + /// - `Unalign` has the same bit validity as `T`, and so it is + /// `FromZeroes`, `FromBytes`, or `AsBytes` exactly when `T` is as well. + impl_or_verify!(T => Unaligned for Unalign); + impl_or_verify!(T: FromZeroes => FromZeroes for Unalign); + impl_or_verify!(T: FromBytes => FromBytes for Unalign); + impl_or_verify!(T: AsBytes => AsBytes for Unalign); +} + +// Note that `Unalign: Clone` only if `T: Copy`. Since the inner `T` may not be +// aligned, there's no way to safely call `T::clone`, and so a `T: Clone` bound +// is not sufficient to implement `Clone` for `Unalign`. +impl Clone for Unalign { + #[inline(always)] + fn clone(&self) -> Unalign { + *self + } +} + +impl Unalign { + /// Constructs a new `Unalign`. + #[inline(always)] + pub const fn new(val: T) -> Unalign { + Unalign(val) + } + + /// Consumes `self`, returning the inner `T`. + #[inline(always)] + pub const fn into_inner(self) -> T { + // Use this instead of `mem::transmute` since the latter can't tell + // that `Unalign` and `T` have the same size. + #[repr(C)] + union Transmute { + u: ManuallyDrop>, + t: ManuallyDrop, + } + + // SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same + // layout as `T`. `ManuallyDrop` is guaranteed to have the same + // layout as `U`, and so `ManuallyDrop>` has the same layout + // as `ManuallyDrop`. Since `Transmute` is `#[repr(C)]`, its `t` + // and `u` fields both start at the same offset (namely, 0) within the + // union. + // + // We do this instead of just destructuring in order to prevent + // `Unalign`'s `Drop::drop` from being run, since dropping is not + // supported in `const fn`s. + // + // TODO(https://github.com/rust-lang/rust/issues/73255): Destructure + // instead of using unsafe. + unsafe { ManuallyDrop::into_inner(Transmute { u: ManuallyDrop::new(self) }.t) } + } + + /// Attempts to return a reference to the wrapped `T`, failing if `self` is + /// not properly aligned. + /// + /// If `self` does not satisfy `mem::align_of::()`, then it is unsound to + /// return a reference to the wrapped `T`, and `try_deref` returns `None`. + /// + /// If `T: Unaligned`, then `Unalign` implements [`Deref`], and callers + /// may prefer [`Deref::deref`], which is infallible. + #[inline(always)] + pub fn try_deref(&self) -> Option<&T> { + if !crate::util::aligned_to::<_, T>(self) { + return None; + } + + // SAFETY: `deref_unchecked`'s safety requirement is that `self` is + // aligned to `align_of::()`, which we just checked. + unsafe { Some(self.deref_unchecked()) } + } + + /// Attempts to return a mutable reference to the wrapped `T`, failing if + /// `self` is not properly aligned. + /// + /// If `self` does not satisfy `mem::align_of::()`, then it is unsound to + /// return a reference to the wrapped `T`, and `try_deref_mut` returns + /// `None`. + /// + /// If `T: Unaligned`, then `Unalign` implements [`DerefMut`], and + /// callers may prefer [`DerefMut::deref_mut`], which is infallible. + #[inline(always)] + pub fn try_deref_mut(&mut self) -> Option<&mut T> { + if !crate::util::aligned_to::<_, T>(&*self) { + return None; + } + + // SAFETY: `deref_mut_unchecked`'s safety requirement is that `self` is + // aligned to `align_of::()`, which we just checked. + unsafe { Some(self.deref_mut_unchecked()) } + } + + /// Returns a reference to the wrapped `T` without checking alignment. + /// + /// If `T: Unaligned`, then `Unalign` implements[ `Deref`], and callers + /// may prefer [`Deref::deref`], which is safe. + /// + /// # Safety + /// + /// If `self` does not satisfy `mem::align_of::()`, then + /// `self.deref_unchecked()` may cause undefined behavior. + #[inline(always)] + pub const unsafe fn deref_unchecked(&self) -> &T { + // SAFETY: `Unalign` is `repr(transparent)`, so there is a valid `T` + // at the same memory location as `self`. It has no alignment guarantee, + // but the caller has promised that `self` is properly aligned, so we + // know that it is sound to create a reference to `T` at this memory + // location. + // + // We use `mem::transmute` instead of `&*self.get_ptr()` because + // dereferencing pointers is not stable in `const` on our current MSRV + // (1.56 as of this writing). + unsafe { mem::transmute(self) } + } + + /// Returns a mutable reference to the wrapped `T` without checking + /// alignment. + /// + /// If `T: Unaligned`, then `Unalign` implements[ `DerefMut`], and + /// callers may prefer [`DerefMut::deref_mut`], which is safe. + /// + /// # Safety + /// + /// If `self` does not satisfy `mem::align_of::()`, then + /// `self.deref_mut_unchecked()` may cause undefined behavior. + #[inline(always)] + pub unsafe fn deref_mut_unchecked(&mut self) -> &mut T { + // SAFETY: `self.get_mut_ptr()` returns a raw pointer to a valid `T` at + // the same memory location as `self`. It has no alignment guarantee, + // but the caller has promised that `self` is properly aligned, so we + // know that the pointer itself is aligned, and thus that it is sound to + // create a reference to a `T` at this memory location. + unsafe { &mut *self.get_mut_ptr() } + } + + /// Gets an unaligned raw pointer to the inner `T`. + /// + /// # Safety + /// + /// The returned raw pointer is not necessarily aligned to + /// `align_of::()`. Most functions which operate on raw pointers require + /// those pointers to be aligned, so calling those functions with the result + /// of `get_ptr` will be undefined behavior if alignment is not guaranteed + /// using some out-of-band mechanism. In general, the only functions which + /// are safe to call with this pointer are those which are explicitly + /// documented as being sound to use with an unaligned pointer, such as + /// [`read_unaligned`]. + /// + /// [`read_unaligned`]: core::ptr::read_unaligned + #[inline(always)] + pub const fn get_ptr(&self) -> *const T { + ptr::addr_of!(self.0) + } + + /// Gets an unaligned mutable raw pointer to the inner `T`. + /// + /// # Safety + /// + /// The returned raw pointer is not necessarily aligned to + /// `align_of::()`. Most functions which operate on raw pointers require + /// those pointers to be aligned, so calling those functions with the result + /// of `get_ptr` will be undefined behavior if alignment is not guaranteed + /// using some out-of-band mechanism. In general, the only functions which + /// are safe to call with this pointer are those which are explicitly + /// documented as being sound to use with an unaligned pointer, such as + /// [`read_unaligned`]. + /// + /// [`read_unaligned`]: core::ptr::read_unaligned + // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`. + #[inline(always)] + pub fn get_mut_ptr(&mut self) -> *mut T { + ptr::addr_of_mut!(self.0) + } + + /// Sets the inner `T`, dropping the previous value. + // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`. + #[inline(always)] + pub fn set(&mut self, t: T) { + *self = Unalign::new(t); + } + + /// Updates the inner `T` by calling a function on it. + /// + /// If [`T: Unaligned`], then `Unalign` implements [`DerefMut`], and that + /// impl should be preferred over this method when performing updates, as it + /// will usually be faster and more ergonomic. + /// + /// For large types, this method may be expensive, as it requires copying + /// `2 * size_of::()` bytes. \[1\] + /// + /// \[1\] Since the inner `T` may not be aligned, it would not be sound to + /// invoke `f` on it directly. Instead, `update` moves it into a + /// properly-aligned location in the local stack frame, calls `f` on it, and + /// then moves it back to its original location in `self`. + /// + /// [`T: Unaligned`]: Unaligned + #[inline] + pub fn update O>(&mut self, f: F) -> O { + // On drop, this moves `copy` out of itself and uses `ptr::write` to + // overwrite `slf`. + struct WriteBackOnDrop { + copy: ManuallyDrop, + slf: *mut Unalign, + } + + impl Drop for WriteBackOnDrop { + fn drop(&mut self) { + // SAFETY: We never use `copy` again as required by + // `ManuallyDrop::take`. + let copy = unsafe { ManuallyDrop::take(&mut self.copy) }; + // SAFETY: `slf` is the raw pointer value of `self`. We know it + // is valid for writes and properly aligned because `self` is a + // mutable reference, which guarantees both of these properties. + unsafe { ptr::write(self.slf, Unalign::new(copy)) }; + } + } + + // SAFETY: We know that `self` is valid for reads, properly aligned, and + // points to an initialized `Unalign` because it is a mutable + // reference, which guarantees all of these properties. + // + // Since `T: !Copy`, it would be unsound in the general case to allow + // both the original `Unalign` and the copy to be used by safe code. + // We guarantee that the copy is used to overwrite the original in the + // `Drop::drop` impl of `WriteBackOnDrop`. So long as this `drop` is + // called before any other safe code executes, soundness is upheld. + // While this method can terminate in two ways (by returning normally or + // by unwinding due to a panic in `f`), in both cases, `write_back` is + // dropped - and its `drop` called - before any other safe code can + // execute. + let copy = unsafe { ptr::read(self) }.into_inner(); + let mut write_back = WriteBackOnDrop { copy: ManuallyDrop::new(copy), slf: self }; + + let ret = f(&mut write_back.copy); + + drop(write_back); + ret + } +} + +impl Unalign { + /// Gets a copy of the inner `T`. + // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`. + #[inline(always)] + pub fn get(&self) -> T { + let Unalign(val) = *self; + val + } +} + +impl Deref for Unalign { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + // SAFETY: `deref_unchecked`'s safety requirement is that `self` is + // aligned to `align_of::()`. `T: Unaligned` guarantees that + // `align_of::() == 1`, and all pointers are one-aligned because all + // addresses are divisible by 1. + unsafe { self.deref_unchecked() } + } +} + +impl DerefMut for Unalign { + #[inline(always)] + fn deref_mut(&mut self) -> &mut T { + // SAFETY: `deref_mut_unchecked`'s safety requirement is that `self` is + // aligned to `align_of::()`. `T: Unaligned` guarantees that + // `align_of::() == 1`, and all pointers are one-aligned because all + // addresses are divisible by 1. + unsafe { self.deref_mut_unchecked() } + } +} + +impl PartialOrd> for Unalign { + #[inline(always)] + fn partial_cmp(&self, other: &Unalign) -> Option { + PartialOrd::partial_cmp(self.deref(), other.deref()) + } +} + +impl Ord for Unalign { + #[inline(always)] + fn cmp(&self, other: &Unalign) -> Ordering { + Ord::cmp(self.deref(), other.deref()) + } +} + +impl PartialEq> for Unalign { + #[inline(always)] + fn eq(&self, other: &Unalign) -> bool { + PartialEq::eq(self.deref(), other.deref()) + } +} + +impl Eq for Unalign {} + +impl Hash for Unalign { + #[inline(always)] + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.deref().hash(state); + } +} + +impl Debug for Unalign { + #[inline(always)] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Debug::fmt(self.deref(), f) + } +} + +impl Display for Unalign { + #[inline(always)] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self.deref(), f) + } +} + +#[cfg(test)] +mod tests { + use core::panic::AssertUnwindSafe; + + use super::*; + use crate::util::testutil::*; + + /// A `T` which is guaranteed not to satisfy `align_of::()`. + /// + /// It must be the case that `align_of::() < align_of::()` in order + /// fot this type to work properly. + #[repr(C)] + struct ForceUnalign { + // The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is + // placed at the minimum offset that guarantees its alignment. If + // `align_of::() < align_of::()`, then that offset will be + // guaranteed *not* to satisfy `align_of::()`. + _u: u8, + t: T, + _a: [A; 0], + } + + impl ForceUnalign { + const fn new(t: T) -> ForceUnalign { + ForceUnalign { _u: 0, t, _a: [] } + } + } + + #[test] + fn test_unalign() { + // Test methods that don't depend on alignment. + let mut u = Unalign::new(AU64(123)); + assert_eq!(u.get(), AU64(123)); + assert_eq!(u.into_inner(), AU64(123)); + assert_eq!(u.get_ptr(), <*const _>::cast::(&u)); + assert_eq!(u.get_mut_ptr(), <*mut _>::cast::(&mut u)); + u.set(AU64(321)); + assert_eq!(u.get(), AU64(321)); + + // Test methods that depend on alignment (when alignment is satisfied). + let mut u: Align<_, AU64> = Align::new(Unalign::new(AU64(123))); + assert_eq!(u.t.try_deref(), Some(&AU64(123))); + assert_eq!(u.t.try_deref_mut(), Some(&mut AU64(123))); + // SAFETY: The `Align<_, AU64>` guarantees proper alignment. + assert_eq!(unsafe { u.t.deref_unchecked() }, &AU64(123)); + // SAFETY: The `Align<_, AU64>` guarantees proper alignment. + assert_eq!(unsafe { u.t.deref_mut_unchecked() }, &mut AU64(123)); + *u.t.try_deref_mut().unwrap() = AU64(321); + assert_eq!(u.t.get(), AU64(321)); + + // Test methods that depend on alignment (when alignment is not + // satisfied). + let mut u: ForceUnalign<_, AU64> = ForceUnalign::new(Unalign::new(AU64(123))); + assert_eq!(u.t.try_deref(), None); + assert_eq!(u.t.try_deref_mut(), None); + + // Test methods that depend on `T: Unaligned`. + let mut u = Unalign::new(123u8); + assert_eq!(u.try_deref(), Some(&123)); + assert_eq!(u.try_deref_mut(), Some(&mut 123)); + assert_eq!(u.deref(), &123); + assert_eq!(u.deref_mut(), &mut 123); + *u = 21; + assert_eq!(u.get(), 21); + + // Test that some `Unalign` functions and methods are `const`. + const _UNALIGN: Unalign = Unalign::new(0); + const _UNALIGN_PTR: *const u64 = _UNALIGN.get_ptr(); + const _U64: u64 = _UNALIGN.into_inner(); + // Make sure all code is considered "used". + // + // TODO(https://github.com/rust-lang/rust/issues/104084): Remove this + // attribute. + #[allow(dead_code)] + const _: () = { + let x: Align<_, AU64> = Align::new(Unalign::new(AU64(123))); + // Make sure that `deref_unchecked` is `const`. + // + // SAFETY: The `Align<_, AU64>` guarantees proper alignment. + let au64 = unsafe { x.t.deref_unchecked() }; + match au64 { + AU64(123) => {} + _ => unreachable!(), + } + }; + } + + #[test] + fn test_unalign_update() { + let mut u = Unalign::new(AU64(123)); + u.update(|a| a.0 += 1); + assert_eq!(u.get(), AU64(124)); + + // Test that, even if the callback panics, the original is still + // correctly overwritten. Use a `Box` so that Miri is more likely to + // catch any unsoundness (which would likely result in two `Box`es for + // the same heap object, which is the sort of thing that Miri would + // probably catch). + let mut u = Unalign::new(Box::new(AU64(123))); + let res = std::panic::catch_unwind(AssertUnwindSafe(|| { + u.update(|a| { + a.0 += 1; + panic!(); + }) + })); + assert!(res.is_err()); + assert_eq!(u.into_inner(), Box::new(AU64(124))); + } +} diff --git a/third_party/rust/zerocopy/testdata/include_value/data b/third_party/rust/zerocopy/testdata/include_value/data new file mode 100644 index 0000000000..85df50785d --- /dev/null +++ b/third_party/rust/zerocopy/testdata/include_value/data @@ -0,0 +1 @@ +abcd \ No newline at end of file diff --git a/third_party/rust/zerocopy/tests/trybuild.rs b/third_party/rust/zerocopy/tests/trybuild.rs new file mode 100644 index 0000000000..24abc28622 --- /dev/null +++ b/third_party/rust/zerocopy/tests/trybuild.rs @@ -0,0 +1,41 @@ +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use testutil::ToolchainVersion; + +#[test] +#[cfg_attr(miri, ignore)] +fn ui() { + let version = ToolchainVersion::extract_from_pwd().unwrap(); + // See the doc comment on this method for an explanation of what this does + // and why we store source files in different directories. + let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning(); + + let t = trybuild::TestCases::new(); + t.compile_fail(format!("tests/{source_files_dirname}/*.rs")); +} + +// The file `invalid-impls.rs` directly includes `src/macros.rs` in order to +// test the `impl_or_verify!` macro which is defined in that file. Specifically, +// it tests the verification portion of that macro, which is enabled when +// `cfg(any(feature = "derive", test))`. While `--cfg test` is of course passed +// to the code in the file you're reading right now, `trybuild` does not pass +// `--cfg test` when it invokes Cargo. As a result, this `trybuild` test only +// tests the correct behavior when the "derive" feature is enabled. +#[cfg(feature = "derive")] +#[test] +#[cfg_attr(miri, ignore)] +fn ui_invalid_impls() { + let version = ToolchainVersion::extract_from_pwd().unwrap(); + // See the doc comment on this method for an explanation of what this does + // and why we store source files in different directories. + let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning(); + + let t = trybuild::TestCases::new(); + t.compile_fail(format!("tests/{source_files_dirname}/invalid-impls/*.rs")); +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.rs new file mode 100644 index 0000000000..45b6138f47 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.rs @@ -0,0 +1,12 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// Should fail because `UnsafeCell: !FromBytes`. +const NOT_FROM_BYTES: core::cell::UnsafeCell = + include_value!("../../testdata/include_value/data"); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.stderr new file mode 100644 index 0000000000..21f6443bbf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/include_value_not_from_bytes.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `UnsafeCell: FromBytes` is not satisfied + --> tests/ui-msrv/include_value_not_from_bytes.rs:12:5 + | +12 | include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `UnsafeCell` + | +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-msrv/include_value_not_from_bytes.rs:12:5 + | +12 | include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.rs b/third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.rs new file mode 100644 index 0000000000..d87b30698b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.rs @@ -0,0 +1,11 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// Should fail because the file is 4 bytes long, not 8. +const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.stderr b/third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.stderr new file mode 100644 index 0000000000..30045849d7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/include_value_wrong_size.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/include_value_wrong_size.rs:11:25 + | +11 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 4]` (32 bits) + = note: target type: `u64` (64 bits) + = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.rs b/third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.rs new file mode 100644 index 0000000000..ea963907df --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.rs @@ -0,0 +1,29 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// Since some macros from `macros.rs` are unused. +#![allow(unused)] + +extern crate zerocopy; +extern crate zerocopy_derive; + +include!("../../../src/macros.rs"); + +use zerocopy::*; +use zerocopy_derive::*; + +fn main() {} + +#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] +#[repr(transparent)] +struct Foo(T); + +impl_or_verify!(T => FromZeroes for Foo); +impl_or_verify!(T => FromBytes for Foo); +impl_or_verify!(T => AsBytes for Foo); +impl_or_verify!(T => Unaligned for Foo); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.stderr b/third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.stderr new file mode 100644 index 0000000000..c1de466ece --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.stderr @@ -0,0 +1,127 @@ +error[E0277]: the trait bound `T: zerocopy::FromZeroes` is not satisfied + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} + | ^^^^^^^^ the trait `zerocopy::FromZeroes` is not implemented for `T` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1 + | +26 | impl_or_verify!(T => FromZeroes for Foo); + | ------------------------------------------- in this macro invocation + | +note: required because of the requirements on the impl of `zerocopy::FromZeroes` for `Foo` + --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^^ +note: required by a bound in `_::Subtrait` + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `_::Subtrait` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1 + | +26 | impl_or_verify!(T => FromZeroes for Foo); + | ------------------------------------------- in this macro invocation + = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +26 | impl_or_verify!(T: zerocopy::FromZeroes => FromZeroes for Foo); + | ++++++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} + | ^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1 + | +27 | impl_or_verify!(T => FromBytes for Foo); + | ------------------------------------------ in this macro invocation + | +note: required because of the requirements on the impl of `zerocopy::FromBytes` for `Foo` + --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:22 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `_::Subtrait` + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `_::Subtrait` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1 + | +27 | impl_or_verify!(T => FromBytes for Foo); + | ------------------------------------------ in this macro invocation + = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +27 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); + | +++++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::AsBytes` is not satisfied + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} + | ^^^^^^^^ the trait `zerocopy::AsBytes` is not implemented for `T` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1 + | +28 | impl_or_verify!(T => AsBytes for Foo); + | ---------------------------------------- in this macro invocation + | +note: required because of the requirements on the impl of `zerocopy::AsBytes` for `Foo` + --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:33 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^ +note: required by a bound in `_::Subtrait` + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `_::Subtrait` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1 + | +28 | impl_or_verify!(T => AsBytes for Foo); + | ---------------------------------------- in this macro invocation + = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +28 | impl_or_verify!(T: zerocopy::AsBytes => AsBytes for Foo); + | +++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} + | ^^^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1 + | +29 | impl_or_verify!(T => Unaligned for Foo); + | ------------------------------------------ in this macro invocation + | +note: required because of the requirements on the impl of `zerocopy::Unaligned` for `Foo` + --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:42 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `_::Subtrait` + --> tests/ui-msrv/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `_::Subtrait` + | + ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1 + | +29 | impl_or_verify!(T => Unaligned for Foo); + | ------------------------------------------ in this macro invocation + = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +29 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); + | +++++++++++++++++++++ diff --git a/third_party/rust/zerocopy/tests/ui-msrv/max-align.rs b/third_party/rust/zerocopy/tests/ui-msrv/max-align.rs new file mode 100644 index 0000000000..53e3eb9b0a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/max-align.rs @@ -0,0 +1,99 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[repr(C, align(1))] +struct Align1; + +#[repr(C, align(2))] +struct Align2; + +#[repr(C, align(4))] +struct Align4; + +#[repr(C, align(8))] +struct Align8; + +#[repr(C, align(16))] +struct Align16; + +#[repr(C, align(32))] +struct Align32; + +#[repr(C, align(64))] +struct Align64; + +#[repr(C, align(128))] +struct Align128; + +#[repr(C, align(256))] +struct Align256; + +#[repr(C, align(512))] +struct Align512; + +#[repr(C, align(1024))] +struct Align1024; + +#[repr(C, align(2048))] +struct Align2048; + +#[repr(C, align(4096))] +struct Align4096; + +#[repr(C, align(8192))] +struct Align8192; + +#[repr(C, align(16384))] +struct Align16384; + +#[repr(C, align(32768))] +struct Align32768; + +#[repr(C, align(65536))] +struct Align65536; + +#[repr(C, align(131072))] +struct Align131072; + +#[repr(C, align(262144))] +struct Align262144; + +#[repr(C, align(524288))] +struct Align524288; + +#[repr(C, align(1048576))] +struct Align1048576; + +#[repr(C, align(2097152))] +struct Align2097152; + +#[repr(C, align(4194304))] +struct Align4194304; + +#[repr(C, align(8388608))] +struct Align8388608; + +#[repr(C, align(16777216))] +struct Align16777216; + +#[repr(C, align(33554432))] +struct Align33554432; + +#[repr(C, align(67108864))] +struct Align67108864; + +#[repr(C, align(134217728))] +struct Align13421772; + +#[repr(C, align(268435456))] +struct Align26843545; + +#[repr(C, align(1073741824))] +struct Align1073741824; + +fn main() {} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/max-align.stderr b/third_party/rust/zerocopy/tests/ui-msrv/max-align.stderr new file mode 100644 index 0000000000..6ab6e47e2b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/max-align.stderr @@ -0,0 +1,5 @@ +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 + --> tests/ui-msrv/max-align.rs:96:11 + | +96 | #[repr(C, align(1073741824))] + | ^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.rs new file mode 100644 index 0000000000..c4caaff917 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.rs @@ -0,0 +1,18 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.stderr new file mode 100644 index 0000000000..b4afbbd60c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-msrv/transmute-dst-not-frombytes.rs:18:41 + | +18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-msrv/transmute-dst-not-frombytes.rs:18:41 + | +18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.rs new file mode 100644 index 0000000000..0928564dd5 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a type of smaller +// alignment to one of larger alignment. +const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.stderr new file mode 100644 index 0000000000..033031c91b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.stderr @@ -0,0 +1,36 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:39 + | +19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf<[u8; 2]>` (8 bits) + = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: mutable references are not allowed in constants + --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:54 + | +19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + +error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], AU16>` in constants + --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:39 + | +19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:59 + | +19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); + | --------------------^^^^^^^^- + | | | + | | creates a temporary which is freed while still in use + | temporary value is freed at the end of this statement + | using this value as a constant requires that borrow lasts for `'static` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.rs new file mode 100644 index 0000000000..021b562f18 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.rs @@ -0,0 +1,20 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; + +// `transmute_mut!` cannot, generally speaking, be used in const contexts. +const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.stderr new file mode 100644 index 0000000000..30bfe45412 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-const.stderr @@ -0,0 +1,41 @@ +warning: taking a mutable reference to a `const` item + --> tests/ui-msrv/transmute-mut-const.rs:20:52 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> tests/ui-msrv/transmute-mut-const.rs:17:1 + | +17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: mutable references are not allowed in constants + --> tests/ui-msrv/transmute-mut-const.rs:20:52 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + +error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], [u8; 2]>` in constants + --> tests/ui-msrv/transmute-mut-const.rs:20:37 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/ui-msrv/transmute-mut-const.rs:20:57 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | --------------------^^^^^^^^^^^^- + | | | + | | creates a temporary which is freed while still in use + | temporary value is freed at the end of this statement + | using this value as a constant requires that borrow lasts for `'static` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.rs new file mode 100644 index 0000000000..7068f1026d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_mut(u: &mut u8) -> &mut T { + // `transmute_mut!` requires the destination type to be concrete. + transmute_mut!(u) +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.stderr new file mode 100644 index 0000000000..f6b54ce1c2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-mut-dst-generic.rs:17:5 + | +17 | transmute_mut!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `T` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-mut-dst-generic.rs:17:5 + | +17 | transmute_mut!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (8 bits) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs new file mode 100644 index 0000000000..33a9ecd955 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting into a non-reference +// destination type. +const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr new file mode 100644 index 0000000000..8f0ea801ef --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.rs new file mode 100644 index 0000000000..b72f12928c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the destination type implements `AsBytes` +const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr new file mode 100644 index 0000000000..7e2dd78b8f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `Dst: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-mut-dst-not-asbytes.rs:24:36 + | +24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Dst` + | +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-msrv/transmute-mut-dst-not-asbytes.rs:24:36 + | +24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs new file mode 100644 index 0000000000..102fcedc9a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr new file mode 100644 index 0000000000..663e085a30 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38 + | +24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` + | +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38 + | +24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.rs new file mode 100644 index 0000000000..693ccda56f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting into an unsized destination +// type. +const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.stderr new file mode 100644 index 0000000000..cb60a82a78 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.stderr @@ -0,0 +1,108 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(e: T) -> U; + | ^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.rs new file mode 100644 index 0000000000..c31765e4b9 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.rs @@ -0,0 +1,15 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +fn main() {} + +fn increase_lifetime() { + let mut x = 0u64; + // It is illegal to increase the lifetime scope. + let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr new file mode 100644 index 0000000000..5ff7145966 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr @@ -0,0 +1,9 @@ +error[E0597]: `x` does not live long enough + --> tests/ui-msrv/transmute-mut-illegal-lifetime.rs:14:56 + | +14 | let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); + | ---------------- ^^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `x` is borrowed for `'static` +15 | } + | - `x` dropped here while still borrowed diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.rs new file mode 100644 index 0000000000..c6eec3a9c2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// We require that the size of the destination type is not smaller than the size +// of the source type. +const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.stderr new file mode 100644 index 0000000000..2bfc21898b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.stderr @@ -0,0 +1,36 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:32 + | +17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 2]` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: mutable references are not allowed in constants + --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:47 + | +17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + +error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], u8>` in constants + --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:32 + | +17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:52 + | +17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); + | --------------------^^^^^^^^- + | | | + | | creates a temporary which is freed while still in use + | temporary value is freed at the end of this statement + | using this value as a constant requires that borrow lasts for `'static` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.rs new file mode 100644 index 0000000000..a4657c2838 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.stderr new file mode 100644 index 0000000000..6e866a0d32 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-size-increase.stderr @@ -0,0 +1,36 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-mut-size-increase.rs:17:37 + | +17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `[u8; 2]` (16 bits) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: mutable references are not allowed in constants + --> tests/ui-msrv/transmute-mut-size-increase.rs:17:52 + | +17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); + | ^^^^^^^^ + | + = note: see issue #57349 for more information + +error[E0015]: cannot call non-const fn `transmute_mut::` in constants + --> tests/ui-msrv/transmute-mut-size-increase.rs:17:37 + | +17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/ui-msrv/transmute-mut-size-increase.rs:17:57 + | +17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); + | --------------------^^^- + | | | + | | creates a temporary which is freed while still in use + | temporary value is freed at the end of this statement + | using this value as a constant requires that borrow lasts for `'static` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.rs new file mode 100644 index 0000000000..aed7ded96f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_mut(t: &mut T) -> &mut U { + // `transmute_mut!` requires the source and destination types to be + // concrete. + transmute_mut!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.stderr new file mode 100644 index 0000000000..1162f21f9c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-mut-src-dst-generic.rs:18:5 + | +18 | transmute_mut!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `U` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-mut-src-dst-generic.rs:18:5 + | +18 | transmute_mut!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.rs new file mode 100644 index 0000000000..98cc520889 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting between non-reference source +// and destination types. +const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr new file mode 100644 index 0000000000..c500a93af7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-mut-src-dst-not-references.rs:17:59 + | +17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&mut _`, found `usize` + | | help: consider mutably borrowing here: `&mut 0usize` + | expected due to this + | + = note: expected mutable reference `&mut _` + found type `usize` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.rs new file mode 100644 index 0000000000..1bebcf2d68 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting between unsized source and +// destination types. +const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr new file mode 100644 index 0000000000..00201a6b68 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr @@ -0,0 +1,237 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(e: T) -> U; + | ^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.rs new file mode 100644 index 0000000000..a3ef397876 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes}; + +fn main() {} + +fn transmute_mut(t: &mut T) -> &mut u8 { + // `transmute_mut!` requires the source type to be concrete. + transmute_mut!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.stderr new file mode 100644 index 0000000000..8a9296ca66 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-generic.stderr @@ -0,0 +1,10 @@ +error[E0405]: cannot find trait `FromBytes` in this scope + --> tests/ui-msrv/transmute-mut-src-generic.rs:15:31 + | +15 | fn transmute_mut(t: &mut T) -> &mut u8 { + | ^^^^^^^^^ not found in this scope + | +help: consider importing this trait + | +11 | use zerocopy::FromBytes; + | diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.rs new file mode 100644 index 0000000000..08088d0db6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +fn ref_src_immutable() { + // `transmute_mut!` requires that its source type be a mutable reference. + let _: &mut u8 = transmute_mut!(&0u8); +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.stderr new file mode 100644 index 0000000000..8262f169a2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-mut-src-immutable.rs:17:37 + | +17 | let _: &mut u8 = transmute_mut!(&0u8); + | ---------------^^^^- + | | | + | | types differ in mutability + | expected due to this + | + = note: expected mutable reference `&mut _` + found reference `&u8` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.rs new file mode 100644 index 0000000000..bf8bc32592 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a non-reference source +// type. +const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr new file mode 100644 index 0000000000..3a6bdf78a6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-mut-src-not-a-reference.rs:17:53 + | +17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&mut _`, found `usize` + | | help: consider mutably borrowing here: `&mut 0usize` + | expected due to this + | + = note: expected mutable reference `&mut _` + found type `usize` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.rs new file mode 100644 index 0000000000..6a14f12fd0 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.stderr new file mode 100644 index 0000000000..4056975829 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Src: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src` + | +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src` + | +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.rs new file mode 100644 index 0000000000..2ebe03601b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the source type implements `FromBytes` +const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..b859c41cd2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.rs new file mode 100644 index 0000000000..413dd68d89 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.rs @@ -0,0 +1,16 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from an unsized source type. +const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.stderr new file mode 100644 index 0000000000..6b18695e66 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.stderr @@ -0,0 +1,198 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(e: T) -> U; + | ^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.rs new file mode 100644 index 0000000000..5af8859332 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.rs @@ -0,0 +1,20 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// It is unclear whether we can or should support this transmutation, especially +// in a const context. This test ensures that even if such a transmutation +// becomes valid due to the requisite implementations of `FromBytes` being +// added, that we re-examine whether it should specifically be valid in a const +// context. +const POINTER_VALUE: usize = transmute!(&0usize as *const usize); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.stderr new file mode 100644 index 0000000000..06b1bbaf2d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.stderr @@ -0,0 +1,37 @@ +error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize` + | + = help: the following implementations were found: + + + + + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize` + | + = help: the following implementations were found: + + + + + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.rs new file mode 100644 index 0000000000..bf1988c66b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a type of smaller +// alignment to one of larger alignment. +const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.stderr new file mode 100644 index 0000000000..72864e144d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-alignment-increase.rs:19:35 + | +19 | const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf<[u8; 2]>` (8 bits) + = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.rs new file mode 100644 index 0000000000..bf4a0f9adf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, FromBytes}; + +fn main() {} + +fn transmute_ref(u: &u8) -> &T { + // `transmute_ref!` requires the destination type to be concrete. + transmute_ref!(u) +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.stderr new file mode 100644 index 0000000000..ec7ec74894 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-dst-generic.rs:17:5 + | +17 | transmute_ref!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `T` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-dst-generic.rs:17:5 + | +17 | transmute_ref!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (8 bits) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.rs new file mode 100644 index 0000000000..fa0e6e4c9b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +fn ref_dst_mutable() { + // `transmute_ref!` requires that its destination type be an immutable + // reference. + let _: &mut u8 = transmute_ref!(&0u8); +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.stderr new file mode 100644 index 0000000000..5ccf2cd20d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs new file mode 100644 index 0000000000..de55f9acdf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting into a non-reference +// destination type. +const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr new file mode 100644 index 0000000000..9a61c4c7ce --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs new file mode 100644 index 0000000000..d81f64d21b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr new file mode 100644 index 0000000000..d317675446 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:18:42 + | +18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy` + | +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:18:42 + | +18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.rs new file mode 100644 index 0000000000..625f1fac07 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting into an unsized destination +// type. +const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.stderr new file mode 100644 index 0000000000..78135de876 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.stderr @@ -0,0 +1,94 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(e: T) -> U; + | ^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.rs new file mode 100644 index 0000000000..8dd191e6f4 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.rs @@ -0,0 +1,15 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +fn main() {} + +fn increase_lifetime() { + let x = 0u64; + // It is illegal to increase the lifetime scope. + let _: &'static u64 = zerocopy::transmute_ref!(&x); +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr new file mode 100644 index 0000000000..866ea56a66 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr @@ -0,0 +1,9 @@ +error[E0597]: `x` does not live long enough + --> tests/ui-msrv/transmute-ref-illegal-lifetime.rs:14:52 + | +14 | let _: &'static u64 = zerocopy::transmute_ref!(&x); + | ------------ ^^ borrowed value does not live long enough + | | + | type annotation requires that `x` is borrowed for `'static` +15 | } + | - `x` dropped here while still borrowed diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.rs new file mode 100644 index 0000000000..1d66a54ef7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// Although this is not a soundness requirement, we currently require that the +// size of the destination type is not smaller than the size of the source type. +const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.stderr new file mode 100644 index 0000000000..95669f9063 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-size-decrease.rs:17:28 + | +17 | const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 2]` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.rs new file mode 100644 index 0000000000..cdca560b30 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.stderr new file mode 100644 index 0000000000..10f0e1038c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-size-increase.rs:17:33 + | +17 | const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `[u8; 2]` (16 bits) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.rs new file mode 100644 index 0000000000..409d785b20 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_ref(t: &T) -> &U { + // `transmute_ref!` requires the source and destination types to be + // concrete. + transmute_ref!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.stderr new file mode 100644 index 0000000000..eb3268fa8f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-src-dst-generic.rs:18:5 + | +18 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `U` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-src-dst-generic.rs:18:5 + | +18 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.rs new file mode 100644 index 0000000000..114e917b54 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting between non-reference source +// and destination types. +const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr new file mode 100644 index 0000000000..2c5e23b6dd --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr @@ -0,0 +1,42 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:54 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ---------------^^^^^^- + | | | + | | expected reference, found `usize` + | | help: consider borrowing here: `&0usize` + | expected due to this + | + = note: expected reference `&_` + found type `usize` + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.rs new file mode 100644 index 0000000000..6bfe7ffdfd --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting between unsized source and +// destination types. +const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr new file mode 100644 index 0000000000..adfd59792a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr @@ -0,0 +1,195 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(e: T) -> U; + | ^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.rs new file mode 100644 index 0000000000..010281c32e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, AsBytes}; + +fn main() {} + +fn transmute_ref(t: &T) -> &u8 { + // `transmute_ref!` requires the source type to be concrete. + transmute_ref!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.stderr new file mode 100644 index 0000000000..4cb3e51bc7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-src-generic.rs:17:5 + | +17 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-ref-src-generic.rs:17:5 + | +17 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.rs new file mode 100644 index 0000000000..90661b3e2c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a non-reference source +// type. +const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr new file mode 100644 index 0000000000..0f4aeec9e2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> tests/ui-msrv/transmute-ref-src-not-a-reference.rs:17:49 + | +17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); + | ---------------^^^^^^- + | | | + | | expected reference, found `usize` + | | help: consider borrowing here: `&0usize` + | expected due to this + | + = note: expected reference `&_` + found type `usize` diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.rs new file mode 100644 index 0000000000..6ab19f3c82 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.stderr new file mode 100644 index 0000000000..6b80d4f494 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.rs new file mode 100644 index 0000000000..14e72b4ddc --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.rs @@ -0,0 +1,16 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from an unsized source type. +const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.stderr new file mode 100644 index 0000000000..43bac53595 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.stderr @@ -0,0 +1,170 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(e: T) -> U; + | ^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.rs new file mode 100644 index 0000000000..1d56831f22 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// Although this is not a soundness requirement, we currently require that the +// size of the destination type is not smaller than the size of the source type. +const DECREASE_SIZE: u8 = transmute!(AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.stderr new file mode 100644 index 0000000000..ffa5688485 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-size-decrease.rs:19:27 + | +19 | const DECREASE_SIZE: u8 = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AU16` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.rs new file mode 100644 index 0000000000..32f9363089 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: AU16 = transmute!(0u8); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.stderr new file mode 100644 index 0000000000..865d0caf9e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-msrv/transmute-size-increase.rs:19:29 + | +19 | const INCREASE_SIZE: AU16 = transmute!(0u8); + | ^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `AU16` (16 bits) + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.rs new file mode 100644 index 0000000000..dd730216b6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); diff --git a/third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.stderr new file mode 100644 index 0000000000..93eeda0c26 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.rs new file mode 100644 index 0000000000..45b6138f47 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.rs @@ -0,0 +1,12 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// Should fail because `UnsafeCell: !FromBytes`. +const NOT_FROM_BYTES: core::cell::UnsafeCell = + include_value!("../../testdata/include_value/data"); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.stderr new file mode 100644 index 0000000000..d948a0db81 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/include_value_not_from_bytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `UnsafeCell: FromBytes` is not satisfied + --> tests/ui-nightly/include_value_not_from_bytes.rs:12:5 + | +12 | include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `UnsafeCell` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-nightly/include_value_not_from_bytes.rs:12:5 + | +12 | include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.rs b/third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.rs new file mode 100644 index 0000000000..d87b30698b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.rs @@ -0,0 +1,11 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// Should fail because the file is 4 bytes long, not 8. +const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.stderr b/third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.stderr new file mode 100644 index 0000000000..f592ece1de --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/include_value_wrong_size.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/include_value_wrong_size.rs:11:25 + | +11 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 4]` (32 bits) + = note: target type: `u64` (64 bits) + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.rs b/third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.rs new file mode 100644 index 0000000000..ea963907df --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.rs @@ -0,0 +1,29 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// Since some macros from `macros.rs` are unused. +#![allow(unused)] + +extern crate zerocopy; +extern crate zerocopy_derive; + +include!("../../../src/macros.rs"); + +use zerocopy::*; +use zerocopy_derive::*; + +fn main() {} + +#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] +#[repr(transparent)] +struct Foo(T); + +impl_or_verify!(T => FromZeroes for Foo); +impl_or_verify!(T => FromBytes for Foo); +impl_or_verify!(T => AsBytes for Foo); +impl_or_verify!(T => Unaligned for Foo); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.stderr b/third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.stderr new file mode 100644 index 0000000000..e5651d169e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.stderr @@ -0,0 +1,107 @@ +error[E0277]: the trait bound `T: zerocopy::FromZeroes` is not satisfied + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:26:37 + | +26 | impl_or_verify!(T => FromZeroes for Foo); + | ^^^^^^ the trait `zerocopy::FromZeroes` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::FromZeroes` + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:10 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-nightly/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:26:1 + | +26 | impl_or_verify!(T => FromZeroes for Foo); + | ------------------------------------------- in this macro invocation + = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +26 | impl_or_verify!(T: zerocopy::FromZeroes => FromZeroes for Foo); + | ++++++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:27:36 + | +27 | impl_or_verify!(T => FromBytes for Foo); + | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::FromBytes` + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:22 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-nightly/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:27:1 + | +27 | impl_or_verify!(T => FromBytes for Foo); + | ------------------------------------------ in this macro invocation + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +27 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); + | +++++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::AsBytes` is not satisfied + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:28:34 + | +28 | impl_or_verify!(T => AsBytes for Foo); + | ^^^^^^ the trait `zerocopy::AsBytes` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::AsBytes` + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:33 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-nightly/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:28:1 + | +28 | impl_or_verify!(T => AsBytes for Foo); + | ---------------------------------------- in this macro invocation + = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +28 | impl_or_verify!(T: zerocopy::AsBytes => AsBytes for Foo); + | +++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:29:36 + | +29 | impl_or_verify!(T => Unaligned for Foo); + | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::Unaligned` + --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:42 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-nightly/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:29:1 + | +29 | impl_or_verify!(T => Unaligned for Foo); + | ------------------------------------------ in this macro invocation + = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +29 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); + | +++++++++++++++++++++ diff --git a/third_party/rust/zerocopy/tests/ui-nightly/max-align.rs b/third_party/rust/zerocopy/tests/ui-nightly/max-align.rs new file mode 100644 index 0000000000..53e3eb9b0a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/max-align.rs @@ -0,0 +1,99 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[repr(C, align(1))] +struct Align1; + +#[repr(C, align(2))] +struct Align2; + +#[repr(C, align(4))] +struct Align4; + +#[repr(C, align(8))] +struct Align8; + +#[repr(C, align(16))] +struct Align16; + +#[repr(C, align(32))] +struct Align32; + +#[repr(C, align(64))] +struct Align64; + +#[repr(C, align(128))] +struct Align128; + +#[repr(C, align(256))] +struct Align256; + +#[repr(C, align(512))] +struct Align512; + +#[repr(C, align(1024))] +struct Align1024; + +#[repr(C, align(2048))] +struct Align2048; + +#[repr(C, align(4096))] +struct Align4096; + +#[repr(C, align(8192))] +struct Align8192; + +#[repr(C, align(16384))] +struct Align16384; + +#[repr(C, align(32768))] +struct Align32768; + +#[repr(C, align(65536))] +struct Align65536; + +#[repr(C, align(131072))] +struct Align131072; + +#[repr(C, align(262144))] +struct Align262144; + +#[repr(C, align(524288))] +struct Align524288; + +#[repr(C, align(1048576))] +struct Align1048576; + +#[repr(C, align(2097152))] +struct Align2097152; + +#[repr(C, align(4194304))] +struct Align4194304; + +#[repr(C, align(8388608))] +struct Align8388608; + +#[repr(C, align(16777216))] +struct Align16777216; + +#[repr(C, align(33554432))] +struct Align33554432; + +#[repr(C, align(67108864))] +struct Align67108864; + +#[repr(C, align(134217728))] +struct Align13421772; + +#[repr(C, align(268435456))] +struct Align26843545; + +#[repr(C, align(1073741824))] +struct Align1073741824; + +fn main() {} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/max-align.stderr b/third_party/rust/zerocopy/tests/ui-nightly/max-align.stderr new file mode 100644 index 0000000000..0cadb9a99a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/max-align.stderr @@ -0,0 +1,5 @@ +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 + --> tests/ui-nightly/max-align.rs:96:11 + | +96 | #[repr(C, align(1073741824))] + | ^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.rs new file mode 100644 index 0000000000..c4caaff917 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.rs @@ -0,0 +1,18 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.stderr new file mode 100644 index 0000000000..a9f1f7becf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-nightly/transmute-dst-not-frombytes.rs:18:41 + | +18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-nightly/transmute-dst-not-frombytes.rs:18:41 + | +18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.rs new file mode 100644 index 0000000000..0928564dd5 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a type of smaller +// alignment to one of larger alignment. +const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.stderr new file mode 100644 index 0000000000..0666f8b526 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-mut-alignment-increase.rs:19:39 + | +19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf<[u8; 2]>` (8 bits) + = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.rs new file mode 100644 index 0000000000..021b562f18 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.rs @@ -0,0 +1,20 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; + +// `transmute_mut!` cannot, generally speaking, be used in const contexts. +const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.stderr new file mode 100644 index 0000000000..fa53ed09a9 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-const.stderr @@ -0,0 +1,42 @@ +warning: taking a mutable reference to a `const` item + --> tests/ui-nightly/transmute-mut-const.rs:20:52 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> tests/ui-nightly/transmute-mut-const.rs:17:1 + | +17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(const_item_mutation)]` on by default + +error[E0658]: mutable references are not allowed in constants + --> tests/ui-nightly/transmute-mut-const.rs:20:52 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants + --> tests/ui-nightly/transmute-mut-const.rs:20:37 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/ui-nightly/transmute-mut-const.rs:20:57 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | --------------------^^^^^^^^^^^^- + | | | + | | creates a temporary value which is freed while still in use + | temporary value is freed at the end of this statement + | using this value as a constant requires that borrow lasts for `'static` diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.rs new file mode 100644 index 0000000000..7068f1026d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_mut(u: &mut u8) -> &mut T { + // `transmute_mut!` requires the destination type to be concrete. + transmute_mut!(u) +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.stderr new file mode 100644 index 0000000000..f278558cf8 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-mut-dst-generic.rs:17:5 + | +17 | transmute_mut!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `T` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-mut-dst-generic.rs:17:5 + | +17 | transmute_mut!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (8 bits) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs new file mode 100644 index 0000000000..33a9ecd955 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting into a non-reference +// destination type. +const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr new file mode 100644 index 0000000000..a84547bd03 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.rs new file mode 100644 index 0000000000..b72f12928c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the destination type implements `AsBytes` +const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr new file mode 100644 index 0000000000..54c8e6023f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Dst: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-mut-dst-not-asbytes.rs:24:36 + | +24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-nightly/transmute-mut-dst-not-asbytes.rs:24:36 + | +24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs new file mode 100644 index 0000000000..102fcedc9a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr new file mode 100644 index 0000000000..ea2123bc0b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-nightly/transmute-mut-dst-not-frombytes.rs:24:38 + | +24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-nightly/transmute-mut-dst-not-frombytes.rs:24:38 + | +24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.rs new file mode 100644 index 0000000000..693ccda56f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting into an unsized destination +// type. +const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.stderr new file mode 100644 index 0000000000..a670e25013 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.stderr @@ -0,0 +1,86 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.rs new file mode 100644 index 0000000000..c31765e4b9 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.rs @@ -0,0 +1,15 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +fn main() {} + +fn increase_lifetime() { + let mut x = 0u64; + // It is illegal to increase the lifetime scope. + let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr new file mode 100644 index 0000000000..b826fcc7a9 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr @@ -0,0 +1,12 @@ +error[E0597]: `x` does not live long enough + --> tests/ui-nightly/transmute-mut-illegal-lifetime.rs:14:56 + | +12 | let mut x = 0u64; + | ----- binding `x` declared here +13 | // It is illegal to increase the lifetime scope. +14 | let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); + | ---------------- ^^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `x` is borrowed for `'static` +15 | } + | - `x` dropped here while still borrowed diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.rs new file mode 100644 index 0000000000..c6eec3a9c2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// We require that the size of the destination type is not smaller than the size +// of the source type. +const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.stderr new file mode 100644 index 0000000000..ac1e35cec7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-mut-size-decrease.rs:17:32 + | +17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 2]` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.rs new file mode 100644 index 0000000000..a4657c2838 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.stderr new file mode 100644 index 0000000000..d343bd65e6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-mut-size-increase.rs:17:37 + | +17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `[u8; 2]` (16 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.rs new file mode 100644 index 0000000000..aed7ded96f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_mut(t: &mut T) -> &mut U { + // `transmute_mut!` requires the source and destination types to be + // concrete. + transmute_mut!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.stderr new file mode 100644 index 0000000000..e3f3a3fd79 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-mut-src-dst-generic.rs:18:5 + | +18 | transmute_mut!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `U` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-mut-src-dst-generic.rs:18:5 + | +18 | transmute_mut!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.rs new file mode 100644 index 0000000000..98cc520889 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting between non-reference source +// and destination types. +const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr new file mode 100644 index 0000000000..df3cf2dba0 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:59 + | +17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&mut _`, found `usize` + | expected due to this + | + = note: expected mutable reference `&mut _` + found type `usize` +help: consider mutably borrowing here + | +17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(&mut 0usize); + | ++++ diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.rs new file mode 100644 index 0000000000..1bebcf2d68 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting between unsized source and +// destination types. +const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr new file mode 100644 index 0000000000..0f41a420eb --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr @@ -0,0 +1,231 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.rs new file mode 100644 index 0000000000..a3ef397876 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes}; + +fn main() {} + +fn transmute_mut(t: &mut T) -> &mut u8 { + // `transmute_mut!` requires the source type to be concrete. + transmute_mut!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.stderr new file mode 100644 index 0000000000..c06d775072 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-generic.stderr @@ -0,0 +1,10 @@ +error[E0405]: cannot find trait `FromBytes` in this scope + --> tests/ui-nightly/transmute-mut-src-generic.rs:15:31 + | +15 | fn transmute_mut(t: &mut T) -> &mut u8 { + | ^^^^^^^^^ not found in this scope + | +help: consider importing this trait + | +11 + use zerocopy::FromBytes; + | diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.rs new file mode 100644 index 0000000000..08088d0db6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +fn ref_src_immutable() { + // `transmute_mut!` requires that its source type be a mutable reference. + let _: &mut u8 = transmute_mut!(&0u8); +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.stderr new file mode 100644 index 0000000000..7b7969d5d5 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-mut-src-immutable.rs:17:37 + | +17 | let _: &mut u8 = transmute_mut!(&0u8); + | ---------------^^^^- + | | | + | | types differ in mutability + | expected due to this + | + = note: expected mutable reference `&mut _` + found reference `&u8` diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.rs new file mode 100644 index 0000000000..bf8bc32592 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a non-reference source +// type. +const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr new file mode 100644 index 0000000000..12b7674f0e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:53 + | +17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&mut _`, found `usize` + | expected due to this + | + = note: expected mutable reference `&mut _` + found type `usize` +help: consider mutably borrowing here + | +17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(&mut 0usize); + | ++++ diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.rs new file mode 100644 index 0000000000..6a14f12fd0 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.stderr new file mode 100644 index 0000000000..b755d3c654 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `Src: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.rs new file mode 100644 index 0000000000..2ebe03601b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the source type implements `FromBytes` +const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..5a9f0a7a7f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.rs new file mode 100644 index 0000000000..413dd68d89 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.rs @@ -0,0 +1,16 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from an unsized source type. +const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.stderr new file mode 100644 index 0000000000..99475adee0 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.stderr @@ -0,0 +1,158 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.rs new file mode 100644 index 0000000000..5af8859332 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.rs @@ -0,0 +1,20 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// It is unclear whether we can or should support this transmutation, especially +// in a const context. This test ensures that even if such a transmutation +// becomes valid due to the requisite implementations of `FromBytes` being +// added, that we re-examine whether it should specifically be valid in a const +// context. +const POINTER_VALUE: usize = transmute!(&0usize as *const usize); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.stderr new file mode 100644 index 0000000000..2fcba2fb6f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.stderr @@ -0,0 +1,30 @@ +error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `*const usize` + | required by a bound introduced by this call + | + = help: the trait `AsBytes` is implemented for `usize` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize` + | + = help: the trait `AsBytes` is implemented for `usize` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.rs new file mode 100644 index 0000000000..bf1988c66b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a type of smaller +// alignment to one of larger alignment. +const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.stderr new file mode 100644 index 0000000000..1cef246bc3 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-alignment-increase.rs:19:35 + | +19 | const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf<[u8; 2]>` (8 bits) + = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.rs new file mode 100644 index 0000000000..bf4a0f9adf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, FromBytes}; + +fn main() {} + +fn transmute_ref(u: &u8) -> &T { + // `transmute_ref!` requires the destination type to be concrete. + transmute_ref!(u) +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.stderr new file mode 100644 index 0000000000..4c94d501c2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-dst-generic.rs:17:5 + | +17 | transmute_ref!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `T` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-dst-generic.rs:17:5 + | +17 | transmute_ref!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (8 bits) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.rs new file mode 100644 index 0000000000..fa0e6e4c9b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +fn ref_dst_mutable() { + // `transmute_ref!` requires that its destination type be an immutable + // reference. + let _: &mut u8 = transmute_ref!(&0u8); +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.stderr new file mode 100644 index 0000000000..0cbdd176b8 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs new file mode 100644 index 0000000000..de55f9acdf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting into a non-reference +// destination type. +const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr new file mode 100644 index 0000000000..847d54732e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs new file mode 100644 index 0000000000..d81f64d21b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr new file mode 100644 index 0000000000..e4791d76b0 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-nightly/transmute-ref-dst-not-frombytes.rs:18:42 + | +18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-nightly/transmute-ref-dst-not-frombytes.rs:18:42 + | +18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.rs new file mode 100644 index 0000000000..625f1fac07 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting into an unsized destination +// type. +const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.stderr new file mode 100644 index 0000000000..3d0f6d0300 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.stderr @@ -0,0 +1,69 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.rs new file mode 100644 index 0000000000..8dd191e6f4 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.rs @@ -0,0 +1,15 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +fn main() {} + +fn increase_lifetime() { + let x = 0u64; + // It is illegal to increase the lifetime scope. + let _: &'static u64 = zerocopy::transmute_ref!(&x); +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr new file mode 100644 index 0000000000..e16a557611 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr @@ -0,0 +1,12 @@ +error[E0597]: `x` does not live long enough + --> tests/ui-nightly/transmute-ref-illegal-lifetime.rs:14:52 + | +12 | let x = 0u64; + | - binding `x` declared here +13 | // It is illegal to increase the lifetime scope. +14 | let _: &'static u64 = zerocopy::transmute_ref!(&x); + | ------------ ^^ borrowed value does not live long enough + | | + | type annotation requires that `x` is borrowed for `'static` +15 | } + | - `x` dropped here while still borrowed diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.rs new file mode 100644 index 0000000000..1d66a54ef7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// Although this is not a soundness requirement, we currently require that the +// size of the destination type is not smaller than the size of the source type. +const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.stderr new file mode 100644 index 0000000000..793ecc54c0 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-size-decrease.rs:17:28 + | +17 | const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 2]` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.rs new file mode 100644 index 0000000000..cdca560b30 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.stderr new file mode 100644 index 0000000000..40c69f63c4 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-size-increase.rs:17:33 + | +17 | const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `[u8; 2]` (16 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.rs new file mode 100644 index 0000000000..409d785b20 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_ref(t: &T) -> &U { + // `transmute_ref!` requires the source and destination types to be + // concrete. + transmute_ref!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.stderr new file mode 100644 index 0000000000..6a3a4fd95b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-src-dst-generic.rs:18:5 + | +18 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `U` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-src-dst-generic.rs:18:5 + | +18 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.rs new file mode 100644 index 0000000000..114e917b54 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting between non-reference source +// and destination types. +const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr new file mode 100644 index 0000000000..0f1f7fc7b3 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr @@ -0,0 +1,45 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:54 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&_`, found `usize` + | expected due to this + | + = note: expected reference `&_` + found type `usize` +help: consider borrowing here + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(&0usize); + | + + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.rs new file mode 100644 index 0000000000..6bfe7ffdfd --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting between unsized source and +// destination types. +const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr new file mode 100644 index 0000000000..02e62bce0b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr @@ -0,0 +1,183 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.rs new file mode 100644 index 0000000000..010281c32e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, AsBytes}; + +fn main() {} + +fn transmute_ref(t: &T) -> &u8 { + // `transmute_ref!` requires the source type to be concrete. + transmute_ref!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.stderr new file mode 100644 index 0000000000..a168f44bb4 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-src-generic.rs:17:5 + | +17 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-ref-src-generic.rs:17:5 + | +17 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.rs new file mode 100644 index 0000000000..90661b3e2c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a non-reference source +// type. +const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr new file mode 100644 index 0000000000..be477c6c5e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:49 + | +17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&_`, found `usize` + | expected due to this + | + = note: expected reference `&_` + found type `usize` +help: consider borrowing here + | +17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(&0usize); + | + diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.rs new file mode 100644 index 0000000000..6ab19f3c82 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.stderr new file mode 100644 index 0000000000..eb28ccf7c8 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.rs new file mode 100644 index 0000000000..14e72b4ddc --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.rs @@ -0,0 +1,16 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from an unsized source type. +const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.stderr new file mode 100644 index 0000000000..b280429b03 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.stderr @@ -0,0 +1,127 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.rs new file mode 100644 index 0000000000..1d56831f22 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// Although this is not a soundness requirement, we currently require that the +// size of the destination type is not smaller than the size of the source type. +const DECREASE_SIZE: u8 = transmute!(AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.stderr new file mode 100644 index 0000000000..83742d7824 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-size-decrease.rs:19:27 + | +19 | const DECREASE_SIZE: u8 = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AU16` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.rs new file mode 100644 index 0000000000..32f9363089 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: AU16 = transmute!(0u8); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.stderr new file mode 100644 index 0000000000..230bb17a77 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-nightly/transmute-size-increase.rs:19:29 + | +19 | const INCREASE_SIZE: AU16 = transmute!(0u8); + | ^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `AU16` (16 bits) + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.rs new file mode 100644 index 0000000000..dd730216b6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); diff --git a/third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.stderr new file mode 100644 index 0000000000..b36a820686 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.rs b/third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.rs new file mode 100644 index 0000000000..45b6138f47 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.rs @@ -0,0 +1,12 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// Should fail because `UnsafeCell: !FromBytes`. +const NOT_FROM_BYTES: core::cell::UnsafeCell = + include_value!("../../testdata/include_value/data"); diff --git a/third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.stderr new file mode 100644 index 0000000000..7e9a035dc3 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/include_value_not_from_bytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `UnsafeCell: FromBytes` is not satisfied + --> tests/ui-stable/include_value_not_from_bytes.rs:12:5 + | +12 | include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `UnsafeCell` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-stable/include_value_not_from_bytes.rs:12:5 + | +12 | include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.rs b/third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.rs new file mode 100644 index 0000000000..d87b30698b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.rs @@ -0,0 +1,11 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#[macro_use] +extern crate zerocopy; + +fn main() {} + +// Should fail because the file is 4 bytes long, not 8. +const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); diff --git a/third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.stderr b/third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.stderr new file mode 100644 index 0000000000..956d74c505 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/include_value_wrong_size.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/include_value_wrong_size.rs:11:25 + | +11 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 4]` (32 bits) + = note: target type: `u64` (64 bits) + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.rs b/third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.rs new file mode 100644 index 0000000000..ea963907df --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.rs @@ -0,0 +1,29 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// Since some macros from `macros.rs` are unused. +#![allow(unused)] + +extern crate zerocopy; +extern crate zerocopy_derive; + +include!("../../../src/macros.rs"); + +use zerocopy::*; +use zerocopy_derive::*; + +fn main() {} + +#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] +#[repr(transparent)] +struct Foo(T); + +impl_or_verify!(T => FromZeroes for Foo); +impl_or_verify!(T => FromBytes for Foo); +impl_or_verify!(T => AsBytes for Foo); +impl_or_verify!(T => Unaligned for Foo); diff --git a/third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.stderr b/third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.stderr new file mode 100644 index 0000000000..7737d67175 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.stderr @@ -0,0 +1,107 @@ +error[E0277]: the trait bound `T: zerocopy::FromZeroes` is not satisfied + --> tests/ui-stable/invalid-impls/invalid-impls.rs:26:37 + | +26 | impl_or_verify!(T => FromZeroes for Foo); + | ^^^^^^ the trait `zerocopy::FromZeroes` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::FromZeroes` + --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:10 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-stable/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-stable/invalid-impls/invalid-impls.rs:26:1 + | +26 | impl_or_verify!(T => FromZeroes for Foo); + | ------------------------------------------- in this macro invocation + = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +26 | impl_or_verify!(T: zerocopy::FromZeroes => FromZeroes for Foo); + | ++++++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied + --> tests/ui-stable/invalid-impls/invalid-impls.rs:27:36 + | +27 | impl_or_verify!(T => FromBytes for Foo); + | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::FromBytes` + --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:22 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-stable/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-stable/invalid-impls/invalid-impls.rs:27:1 + | +27 | impl_or_verify!(T => FromBytes for Foo); + | ------------------------------------------ in this macro invocation + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +27 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); + | +++++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::AsBytes` is not satisfied + --> tests/ui-stable/invalid-impls/invalid-impls.rs:28:34 + | +28 | impl_or_verify!(T => AsBytes for Foo); + | ^^^^^^ the trait `zerocopy::AsBytes` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::AsBytes` + --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:33 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-stable/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-stable/invalid-impls/invalid-impls.rs:28:1 + | +28 | impl_or_verify!(T => AsBytes for Foo); + | ---------------------------------------- in this macro invocation + = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +28 | impl_or_verify!(T: zerocopy::AsBytes => AsBytes for Foo); + | +++++++++++++++++++ + +error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied + --> tests/ui-stable/invalid-impls/invalid-impls.rs:29:36 + | +29 | impl_or_verify!(T => Unaligned for Foo); + | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` + | +note: required for `Foo` to implement `zerocopy::Unaligned` + --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:42 + | +22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro +note: required by a bound in `_::Subtrait` + --> tests/ui-stable/invalid-impls/../../../src/macros.rs + | + | trait Subtrait: $trait {} + | ^^^^^^ required by this bound in `Subtrait` + | + ::: tests/ui-stable/invalid-impls/invalid-impls.rs:29:1 + | +29 | impl_or_verify!(T => Unaligned for Foo); + | ------------------------------------------ in this macro invocation + = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +29 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); + | +++++++++++++++++++++ diff --git a/third_party/rust/zerocopy/tests/ui-stable/max-align.rs b/third_party/rust/zerocopy/tests/ui-stable/max-align.rs new file mode 100644 index 0000000000..53e3eb9b0a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/max-align.rs @@ -0,0 +1,99 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#[repr(C, align(1))] +struct Align1; + +#[repr(C, align(2))] +struct Align2; + +#[repr(C, align(4))] +struct Align4; + +#[repr(C, align(8))] +struct Align8; + +#[repr(C, align(16))] +struct Align16; + +#[repr(C, align(32))] +struct Align32; + +#[repr(C, align(64))] +struct Align64; + +#[repr(C, align(128))] +struct Align128; + +#[repr(C, align(256))] +struct Align256; + +#[repr(C, align(512))] +struct Align512; + +#[repr(C, align(1024))] +struct Align1024; + +#[repr(C, align(2048))] +struct Align2048; + +#[repr(C, align(4096))] +struct Align4096; + +#[repr(C, align(8192))] +struct Align8192; + +#[repr(C, align(16384))] +struct Align16384; + +#[repr(C, align(32768))] +struct Align32768; + +#[repr(C, align(65536))] +struct Align65536; + +#[repr(C, align(131072))] +struct Align131072; + +#[repr(C, align(262144))] +struct Align262144; + +#[repr(C, align(524288))] +struct Align524288; + +#[repr(C, align(1048576))] +struct Align1048576; + +#[repr(C, align(2097152))] +struct Align2097152; + +#[repr(C, align(4194304))] +struct Align4194304; + +#[repr(C, align(8388608))] +struct Align8388608; + +#[repr(C, align(16777216))] +struct Align16777216; + +#[repr(C, align(33554432))] +struct Align33554432; + +#[repr(C, align(67108864))] +struct Align67108864; + +#[repr(C, align(134217728))] +struct Align13421772; + +#[repr(C, align(268435456))] +struct Align26843545; + +#[repr(C, align(1073741824))] +struct Align1073741824; + +fn main() {} diff --git a/third_party/rust/zerocopy/tests/ui-stable/max-align.stderr b/third_party/rust/zerocopy/tests/ui-stable/max-align.stderr new file mode 100644 index 0000000000..ea472f2df7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/max-align.stderr @@ -0,0 +1,5 @@ +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 + --> tests/ui-stable/max-align.rs:96:11 + | +96 | #[repr(C, align(1073741824))] + | ^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.rs new file mode 100644 index 0000000000..c4caaff917 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.rs @@ -0,0 +1,18 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.stderr new file mode 100644 index 0000000000..b008bcdb10 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-stable/transmute-dst-not-frombytes.rs:18:41 + | +18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-stable/transmute-dst-not-frombytes.rs:18:41 + | +18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.rs new file mode 100644 index 0000000000..0928564dd5 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a type of smaller +// alignment to one of larger alignment. +const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.stderr new file mode 100644 index 0000000000..252fec9ef8 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-mut-alignment-increase.rs:19:39 + | +19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf<[u8; 2]>` (8 bits) + = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.rs new file mode 100644 index 0000000000..021b562f18 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.rs @@ -0,0 +1,20 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; + +// `transmute_mut!` cannot, generally speaking, be used in const contexts. +const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.stderr new file mode 100644 index 0000000000..a89ea67558 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-const.stderr @@ -0,0 +1,41 @@ +warning: taking a mutable reference to a `const` item + --> tests/ui-stable/transmute-mut-const.rs:20:52 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> tests/ui-stable/transmute-mut-const.rs:17:1 + | +17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(const_item_mutation)]` on by default + +error[E0658]: mutable references are not allowed in constants + --> tests/ui-stable/transmute-mut-const.rs:20:52 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + +error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants + --> tests/ui-stable/transmute-mut-const.rs:20:37 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/ui-stable/transmute-mut-const.rs:20:57 + | +20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); + | --------------------^^^^^^^^^^^^- + | | | + | | creates a temporary value which is freed while still in use + | temporary value is freed at the end of this statement + | using this value as a constant requires that borrow lasts for `'static` diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.rs new file mode 100644 index 0000000000..7068f1026d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_mut(u: &mut u8) -> &mut T { + // `transmute_mut!` requires the destination type to be concrete. + transmute_mut!(u) +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.stderr new file mode 100644 index 0000000000..0000eb0bab --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-mut-dst-generic.rs:17:5 + | +17 | transmute_mut!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `T` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-mut-dst-generic.rs:17:5 + | +17 | transmute_mut!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (8 bits) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.rs new file mode 100644 index 0000000000..33a9ecd955 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting into a non-reference +// destination type. +const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr new file mode 100644 index 0000000000..14ee444cc5 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | + = note: expected type `usize` + found mutable reference `&mut _` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.rs new file mode 100644 index 0000000000..b72f12928c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the destination type implements `AsBytes` +const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.stderr new file mode 100644 index 0000000000..f3cacca09d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Dst: AsBytes` is not satisfied + --> tests/ui-stable/transmute-mut-dst-not-asbytes.rs:24:36 + | +24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-stable/transmute-mut-dst-not-asbytes.rs:24:36 + | +24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.rs new file mode 100644 index 0000000000..102fcedc9a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr new file mode 100644 index 0000000000..39bb4fd96d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-stable/transmute-mut-dst-not-frombytes.rs:24:38 + | +24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-stable/transmute-mut-dst-not-frombytes.rs:24:38 + | +24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.rs new file mode 100644 index 0000000000..693ccda56f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting into an unsized destination +// type. +const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.stderr new file mode 100644 index 0000000000..07727850cd --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.stderr @@ -0,0 +1,106 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 + | +17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.rs new file mode 100644 index 0000000000..c31765e4b9 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.rs @@ -0,0 +1,15 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +fn main() {} + +fn increase_lifetime() { + let mut x = 0u64; + // It is illegal to increase the lifetime scope. + let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.stderr new file mode 100644 index 0000000000..7f128138f3 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.stderr @@ -0,0 +1,12 @@ +error[E0597]: `x` does not live long enough + --> tests/ui-stable/transmute-mut-illegal-lifetime.rs:14:56 + | +12 | let mut x = 0u64; + | ----- binding `x` declared here +13 | // It is illegal to increase the lifetime scope. +14 | let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); + | ---------------- ^^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `x` is borrowed for `'static` +15 | } + | - `x` dropped here while still borrowed diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.rs new file mode 100644 index 0000000000..c6eec3a9c2 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// We require that the size of the destination type is not smaller than the size +// of the source type. +const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.stderr new file mode 100644 index 0000000000..239991357d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-mut-size-decrease.rs:17:32 + | +17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 2]` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.rs new file mode 100644 index 0000000000..a4657c2838 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.stderr new file mode 100644 index 0000000000..1427c7b0e9 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-mut-size-increase.rs:17:37 + | +17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `[u8; 2]` (16 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.rs new file mode 100644 index 0000000000..aed7ded96f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_mut(t: &mut T) -> &mut U { + // `transmute_mut!` requires the source and destination types to be + // concrete. + transmute_mut!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.stderr new file mode 100644 index 0000000000..ddb8bb6fe7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-mut-src-dst-generic.rs:18:5 + | +18 | transmute_mut!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `U` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-mut-src-dst-generic.rs:18:5 + | +18 | transmute_mut!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.rs new file mode 100644 index 0000000000..98cc520889 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting between non-reference source +// and destination types. +const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.stderr new file mode 100644 index 0000000000..c0d9e0f0d3 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-mut-src-dst-not-references.rs:17:59 + | +17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&mut _`, found `usize` + | expected due to this + | + = note: expected mutable reference `&mut _` + found type `usize` +help: consider mutably borrowing here + | +17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(&mut 0usize); + | ++++ diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.rs new file mode 100644 index 0000000000..1bebcf2d68 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting between unsized source and +// destination types. +const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.stderr new file mode 100644 index 0000000000..8cf76649eb --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.stderr @@ -0,0 +1,288 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertDstIsAsBytes` + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.rs new file mode 100644 index 0000000000..a3ef397876 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_mut, AsBytes}; + +fn main() {} + +fn transmute_mut(t: &mut T) -> &mut u8 { + // `transmute_mut!` requires the source type to be concrete. + transmute_mut!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.stderr new file mode 100644 index 0000000000..fc4809e418 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-generic.stderr @@ -0,0 +1,10 @@ +error[E0405]: cannot find trait `FromBytes` in this scope + --> tests/ui-stable/transmute-mut-src-generic.rs:15:31 + | +15 | fn transmute_mut(t: &mut T) -> &mut u8 { + | ^^^^^^^^^ not found in this scope + | +help: consider importing this trait + | +11 + use zerocopy::FromBytes; + | diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.rs new file mode 100644 index 0000000000..08088d0db6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +fn ref_src_immutable() { + // `transmute_mut!` requires that its source type be a mutable reference. + let _: &mut u8 = transmute_mut!(&0u8); +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.stderr new file mode 100644 index 0000000000..0115c791d3 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-immutable.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-mut-src-immutable.rs:17:37 + | +17 | let _: &mut u8 = transmute_mut!(&0u8); + | ---------------^^^^- + | | | + | | types differ in mutability + | expected due to this + | + = note: expected mutable reference `&mut _` + found reference `&u8` diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.rs new file mode 100644 index 0000000000..bf8bc32592 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from a non-reference source +// type. +const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.stderr new file mode 100644 index 0000000000..8c1d9b47ba --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-mut-src-not-a-reference.rs:17:53 + | +17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&mut _`, found `usize` + | expected due to this + | + = note: expected mutable reference `&mut _` + found type `usize` +help: consider mutably borrowing here + | +17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(&mut 0usize); + | ++++ diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.rs new file mode 100644 index 0000000000..6a14f12fd0 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.stderr new file mode 100644 index 0000000000..9fc954654e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `Src: AsBytes` is not satisfied + --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: AsBytes` is not satisfied + --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36 + | +24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.rs new file mode 100644 index 0000000000..2ebe03601b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.rs @@ -0,0 +1,24 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +#[derive(zerocopy::AsBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)] +#[repr(C)] +struct Dst; + +// `transmute_mut` requires that the source type implements `FromBytes` +const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..cc4a19d724 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38 + | +24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.rs new file mode 100644 index 0000000000..413dd68d89 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.rs @@ -0,0 +1,16 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +fn main() {} + +// `transmute_mut!` does not support transmuting from an unsized source type. +const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.stderr new file mode 100644 index 0000000000..7f6def929d --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-mut-src-unsized.stderr @@ -0,0 +1,195 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertSrcIsAsBytes` + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35 + | +16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_mut` + --> src/macro_util.rs + | + | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_mut` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.rs new file mode 100644 index 0000000000..5af8859332 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.rs @@ -0,0 +1,20 @@ +// Copyright 2022 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// It is unclear whether we can or should support this transmutation, especially +// in a const context. This test ensures that even if such a transmutation +// becomes valid due to the requisite implementations of `FromBytes` being +// added, that we re-examine whether it should specifically be valid in a const +// context. +const POINTER_VALUE: usize = transmute!(&0usize as *const usize); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.stderr new file mode 100644 index 0000000000..4f4d583dbe --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ptr-to-usize.stderr @@ -0,0 +1,30 @@ +error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied + --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `*const usize` + | required by a bound introduced by this call + | + = help: the trait `AsBytes` is implemented for `usize` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied + --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize` + | + = help: the trait `AsBytes` is implemented for `usize` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30 + | +20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.rs new file mode 100644 index 0000000000..bf1988c66b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a type of smaller +// alignment to one of larger alignment. +const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.stderr new file mode 100644 index 0000000000..a34c4065d1 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-alignment-increase.rs:19:35 + | +19 | const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf<[u8; 2]>` (8 bits) + = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.rs new file mode 100644 index 0000000000..bf4a0f9adf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, FromBytes}; + +fn main() {} + +fn transmute_ref(u: &u8) -> &T { + // `transmute_ref!` requires the destination type to be concrete. + transmute_ref!(u) +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.stderr new file mode 100644 index 0000000000..e30b9f67a6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-dst-generic.rs:17:5 + | +17 | transmute_ref!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `T` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-dst-generic.rs:17:5 + | +17 | transmute_ref!(u) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (8 bits) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.rs new file mode 100644 index 0000000000..fa0e6e4c9b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +fn ref_dst_mutable() { + // `transmute_ref!` requires that its destination type be an immutable + // reference. + let _: &mut u8 = transmute_ref!(&0u8); +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.stderr new file mode 100644 index 0000000000..c70f6ea618 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22 + | +18 | let _: &mut u8 = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut u8` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.rs new file mode 100644 index 0000000000..de55f9acdf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting into a non-reference +// destination type. +const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr new file mode 100644 index 0000000000..ab3f90c2fd --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36 + | +17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.rs new file mode 100644 index 0000000000..d81f64d21b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref` requires that the destination type implements `FromBytes` +const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr new file mode 100644 index 0000000000..76d18c5e45 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied + --> tests/ui-stable/transmute-ref-dst-not-frombytes.rs:18:42 + | +18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and $N others +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-stable/transmute-ref-dst-not-frombytes.rs:18:42 + | +18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.rs new file mode 100644 index 0000000000..625f1fac07 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting into an unsized destination +// type. +const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.stderr new file mode 100644 index 0000000000..8a0c761466 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.stderr @@ -0,0 +1,89 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 + | +17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.rs new file mode 100644 index 0000000000..8dd191e6f4 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.rs @@ -0,0 +1,15 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +fn main() {} + +fn increase_lifetime() { + let x = 0u64; + // It is illegal to increase the lifetime scope. + let _: &'static u64 = zerocopy::transmute_ref!(&x); +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.stderr new file mode 100644 index 0000000000..1ef34feb7f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.stderr @@ -0,0 +1,12 @@ +error[E0597]: `x` does not live long enough + --> tests/ui-stable/transmute-ref-illegal-lifetime.rs:14:52 + | +12 | let x = 0u64; + | - binding `x` declared here +13 | // It is illegal to increase the lifetime scope. +14 | let _: &'static u64 = zerocopy::transmute_ref!(&x); + | ------------ ^^ borrowed value does not live long enough + | | + | type annotation requires that `x` is borrowed for `'static` +15 | } + | - `x` dropped here while still borrowed diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.rs new file mode 100644 index 0000000000..1d66a54ef7 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// Although this is not a soundness requirement, we currently require that the +// size of the destination type is not smaller than the size of the source type. +const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.stderr new file mode 100644 index 0000000000..f353b26ece --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-size-decrease.rs:17:28 + | +17 | const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[u8; 2]` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.rs new file mode 100644 index 0000000000..cdca560b30 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.stderr new file mode 100644 index 0000000000..f51eb63f4b --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-size-increase.rs:17:33 + | +17 | const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `[u8; 2]` (16 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.rs new file mode 100644 index 0000000000..409d785b20 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, AsBytes, FromBytes}; + +fn main() {} + +fn transmute_ref(t: &T) -> &U { + // `transmute_ref!` requires the source and destination types to be + // concrete. + transmute_ref!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.stderr new file mode 100644 index 0000000000..0905dc6d5f --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-src-dst-generic.rs:18:5 + | +18 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `U` (this type does not have a fixed size) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-src-dst-generic.rs:18:5 + | +18 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.rs new file mode 100644 index 0000000000..114e917b54 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting between non-reference source +// and destination types. +const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.stderr new file mode 100644 index 0000000000..8a80e991e6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.stderr @@ -0,0 +1,45 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:54 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&_`, found `usize` + | expected due to this + | + = note: expected reference `&_` + found type `usize` +help: consider borrowing here + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(&0usize); + | + + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 + | +17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` + | + = note: expected type `usize` + found reference `&_` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.rs new file mode 100644 index 0000000000..6bfe7ffdfd --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting between unsized source and +// destination types. +const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.stderr new file mode 100644 index 0000000000..ca62fcf7db --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.stderr @@ -0,0 +1,240 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsFromBytes` + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.rs new file mode 100644 index 0000000000..010281c32e --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::{transmute_ref, AsBytes}; + +fn main() {} + +fn transmute_ref(t: &T) -> &u8 { + // `transmute_ref!` requires the source type to be concrete. + transmute_ref!(t) +} diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.stderr new file mode 100644 index 0000000000..b6bbd1648a --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-generic.stderr @@ -0,0 +1,19 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-src-generic.rs:17:5 + | +17 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `T` (this type does not have a fixed size) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-ref-src-generic.rs:17:5 + | +17 | transmute_ref!(t) + | ^^^^^^^^^^^^^^^^^ + | + = note: source type: `AlignOf` (size can vary because of T) + = note: target type: `MaxAlignsOf` (size can vary because of T) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.rs new file mode 100644 index 0000000000..90661b3e2c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.rs @@ -0,0 +1,17 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from a non-reference source +// type. +const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.stderr new file mode 100644 index 0000000000..622c3db9ac --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> tests/ui-stable/transmute-ref-src-not-a-reference.rs:17:49 + | +17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); + | ---------------^^^^^^- + | | | + | | expected `&_`, found `usize` + | expected due to this + | + = note: expected reference `&_` + found type `usize` +help: consider borrowing here + | +17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(&0usize); + | + diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.rs new file mode 100644 index 0000000000..6ab19f3c82 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.stderr new file mode 100644 index 0000000000..2ded6baa03 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33 + | +18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.rs new file mode 100644 index 0000000000..14e72b4ddc --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.rs @@ -0,0 +1,16 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_ref; + +fn main() {} + +// `transmute_ref!` does not support transmuting from an unsized source type. +const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.stderr new file mode 100644 index 0000000000..b194d67473 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-ref-src-unsized.stderr @@ -0,0 +1,164 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute` + --> $RUST/core/src/intrinsics.rs + | + | pub fn transmute(src: Src) -> Dst; + | ^^^ required by this bound in `transmute` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf::::into_t` + --> src/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn into_t(self) -> T { + | ------ required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the left-hand-side of an assignment must have a statically known size + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + | #[inline(never)] // Make `missing_inline_in_public_items` happy. + | pub fn new(_t: T, _u: U) -> MaxAlignsOf { + | --- required by a bound in this associated function + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf` + --> src/macro_util.rs + | + | pub union MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `AlignOf` + --> src/macro_util.rs + | + | pub struct AlignOf { + | ^ required by this bound in `AlignOf` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 + | +16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `transmute_ref` + --> src/macro_util.rs + | + | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( + | ^^^ required by this bound in `transmute_ref` + = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.rs new file mode 100644 index 0000000000..1d56831f22 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// Although this is not a soundness requirement, we currently require that the +// size of the destination type is not smaller than the size of the source type. +const DECREASE_SIZE: u8 = transmute!(AU16(0)); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.stderr new file mode 100644 index 0000000000..0241662fdf --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-decrease.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-size-decrease.rs:19:27 + | +19 | const DECREASE_SIZE: u8 = transmute!(AU16(0)); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `AU16` (16 bits) + = note: target type: `u8` (8 bits) + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.rs new file mode 100644 index 0000000000..32f9363089 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.rs @@ -0,0 +1,19 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute!` does not support transmuting from a smaller type to a larger +// one. +const INCREASE_SIZE: AU16 = transmute!(0u8); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.stderr new file mode 100644 index 0000000000..87d82a208c --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-size-increase.stderr @@ -0,0 +1,9 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> tests/ui-stable/transmute-size-increase.rs:19:29 + | +19 | const INCREASE_SIZE: AU16 = transmute!(0u8); + | ^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `AU16` (16 bits) + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.rs b/third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.rs new file mode 100644 index 0000000000..dd730216b6 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.rs @@ -0,0 +1,18 @@ +// Copyright 2023 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +include!("../../zerocopy-derive/tests/util.rs"); + +extern crate zerocopy; + +use zerocopy::transmute; + +fn main() {} + +// `transmute` requires that the source type implements `AsBytes` +const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); diff --git a/third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.stderr b/third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.stderr new file mode 100644 index 0000000000..f2e834eb57 --- /dev/null +++ b/third_party/rust/zerocopy/tests/ui-stable/transmute-src-not-asbytes.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `AsBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied + --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `AsBytes`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others +note: required by a bound in `AssertIsAsBytes` + --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32 + | +18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes` + = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) -- cgit v1.2.3

    >, - total: u64, sets_cache: Vec>, raw_sets_cache: Vec, max_update_after_bind_descriptors_in_all_pools: u32, + current_update_after_bind_descriptors_in_all_pools: u32, + total: u32, } impl Drop for DescriptorAllocator { @@ -421,6 +423,7 @@ impl DescriptorAllocator { sets_cache: Vec::new(), raw_sets_cache: Vec::new(), max_update_after_bind_descriptors_in_all_pools, + current_update_after_bind_descriptors_in_all_pools: 0, } } @@ -449,8 +452,18 @@ impl DescriptorAllocator { return Ok(Vec::new()); } + let descriptor_count = count * layout_descriptor_count.total(); + let update_after_bind = flags.contains(DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND); + if update_after_bind + && self.max_update_after_bind_descriptors_in_all_pools + - self.current_update_after_bind_descriptors_in_all_pools + < descriptor_count + { + return Err(AllocationError::Fragmentation); + } + #[cfg(feature = "tracing")] tracing::trace!( "Allocating {} sets with layout {:?} @ {:?}", @@ -464,7 +477,14 @@ impl DescriptorAllocator { .entry((*layout_descriptor_count, update_after_bind)) .or_insert_with(|| DescriptorBucket::new(update_after_bind, *layout_descriptor_count)); match bucket.allocate(device, layout, count, &mut self.sets_cache) { - Ok(()) => Ok(core::mem::replace(&mut self.sets_cache, Vec::new())), + Ok(()) => { + self.total += descriptor_count; + if update_after_bind { + self.current_update_after_bind_descriptors_in_all_pools += descriptor_count; + } + + Ok(core::mem::take(&mut self.sets_cache)) + } Err(err) => { debug_assert!(self.raw_sets_cache.is_empty()); @@ -518,7 +538,7 @@ impl DescriptorAllocator { .get_mut(&last_key) .expect("Set must be allocated from this allocator"); - debug_assert!(u64::try_from(self.raw_sets_cache.len()) + debug_assert!(u32::try_from(self.raw_sets_cache.len()) .ok() .map_or(false, |count| count <= bucket.total)); @@ -536,7 +556,7 @@ impl DescriptorAllocator { .get_mut(&last_key) .expect("Set must be allocated from this allocator"); - debug_assert!(u64::try_from(self.raw_sets_cache.len()) + debug_assert!(u32::try_from(self.raw_sets_cache.len()) .ok() .map_or(false, |count| count <= bucket.total)); diff --git a/third_party/rust/hashbrown/.cargo-checksum.json b/third_party/rust/hashbrown/.cargo-checksum.json index 5561cde80d..0c5744048e 100644 --- a/third_party/rust/hashbrown/.cargo-checksum.json +++ b/third_party/rust/hashbrown/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"ade49a29d368e16ce508aee91b477ecbad7e2e52eb6fee7b4c1fc86199963f0e","Cargo.toml":"421b3a71d97faf0a7e52c3b2bfbe0f1c036b9dbf6232b4e5b41221bb54358f5a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"a536b3bb3f3521e59836080f05a4783150fa8484f759a31468ce3b6dba1f33eb","benches/bench.rs":"aadc39d815eadf094ed9357d946319df2d93194203bbccb7c33cea6951d654df","benches/insert_unique_unchecked.rs":"cb84275f22d5f95a5ac995ac6b2df74ffcf342765b401d27c95f2955c7b7cb9f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"ba105bf0853ebc45157f22116ad0f55d3bdab75e721d8e7a677c7b912d0c0c6d","src/external_trait_impls/rayon/map.rs":"2809e2a0071db8101c38789deb955f3830c5c3455eb1794ff64a0cf2ceb53fc7","src/external_trait_impls/rayon/mod.rs":"156de9c1ad0123334ea3b7e5a17444faf1b8bf971aa88a1f23e2f2d1c3021141","src/external_trait_impls/rayon/raw.rs":"e62c5f3ca5fffea47357e64b6f8c34cec94af62d9bd28a2b87934da46c22b66e","src/external_trait_impls/rayon/set.rs":"c4c44d44e56c2f59e9e1355662e29d8744ac96645ca4414127a359fb46cb0fbf","src/external_trait_impls/serde.rs":"0bc1a1f218d1ae7a5262557a5e3737b9334caf7d50c136dbdc75ff75680c223b","src/lib.rs":"c82fbee9684bfff40ef55d5f0c9f855c11f71f9fd1720fb084ef8331bdbc41d8","src/macros.rs":"36fe532656879c80f7753d13354b889f5b45caef451a1bb3a27dbc32d74c9878","src/map.rs":"df39edae67c569378dea9a4d928685cb4d06569712c6ac36a54df76fb5d87fe3","src/raw/alloc.rs":"184a0345bc2c7544b65c28724063be26b1f2b28dbaaa028a0b01192ccac25557","src/raw/bitmask.rs":"820d90b19b7e3433a1048ace008c9526331cd53a576cb0cfc1ff9960b6fe52f8","src/raw/generic.rs":"f5013a50d6d82d5cc8bad8b8c26c24d00fa810197f9f123256c58ac92e0d98f9","src/raw/mod.rs":"fa38247c6b3bd70636be50400debb9966a3446d49ee13e4f4e2dfe4ceed1b201","src/raw/sse2.rs":"838cfdb1daa1e70951ed25f985283b8b7ab4b46fa130f92eda152047ce6086f6","src/rustc_entry.rs":"cdd70972cba5b79ca1cad79869cb5e184d6dc4798ef90822e966ef89679ba011","src/scopeguard.rs":"d13de1b12897add7fe1c3eba6f906c9cc09d86509b6cfe06b95d63803fe9265c","src/set.rs":"6877d4a42eeadd681e3b8881528e4b20f14cfedbc11e9318bfcf425ef96d1546","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/rayon.rs":"83d5289771542203f539a41cccb889fbe7ce70f5adf5b903ac9f051e3ba13cfa","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"01cf39efb04646ef4c63a809ebb96dfa63cfec472bf8bdb6c121f6526d40c40e"},"package":"8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"} \ No newline at end of file +{"files":{"CHANGELOG.md":"1a844fe3b7466b41ca1d5914af197d5aeed7cb14f30ebe4be351367d7ca905d2","Cargo.toml":"c011f10385da722056537329f3fcf8c9b93af742e79e38885c0152a0105fc227","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"84c222ce49510535419d338b7532a72a2bf22b7466e44de78d92d25b6c7d636b","benches/bench.rs":"ef7bc025922f077d307c565640c005d056e3d6c1713448a95aae92d3c22c1005","benches/insert_unique_unchecked.rs":"cb84275f22d5f95a5ac995ac6b2df74ffcf342765b401d27c95f2955c7b7cb9f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"0625e6a5e3b8ecc8901a12aeeea54393fd84617fb3a14d98a34d2d2bddb8d257","src/external_trait_impls/rayon/helpers.rs":"ba105bf0853ebc45157f22116ad0f55d3bdab75e721d8e7a677c7b912d0c0c6d","src/external_trait_impls/rayon/map.rs":"96fdf39b3f601f77152d7ce84541b8f51f32b9274b7da9c294862892e721a5d8","src/external_trait_impls/rayon/mod.rs":"126edc882501dddd25e442d9236508b5b386eb8c0a9f5d654f2dd081086c1616","src/external_trait_impls/rayon/raw.rs":"04012fb2e99648819b4bc0044107ed3cb94013e242b7865075c5bd9ebf1b6865","src/external_trait_impls/rayon/set.rs":"7539348ff7bc6e3cce6b3c019d62dc401eea0138c578fef729c2593e8ead1cfa","src/external_trait_impls/rayon/table.rs":"8778d29509c68b5b7cb66859db025d3939ce22e7cf370b20ff3dea4fe4b29fd0","src/external_trait_impls/rkyv/hash_map.rs":"7abe24318143b776016052b05840656afc858b1ba5252f3d418d61972477f53d","src/external_trait_impls/rkyv/hash_set.rs":"38d969125d17d606492ec4ec9fc06b7e7118eb903240dacf40de21b9b06fa5c8","src/external_trait_impls/rkyv/mod.rs":"54399ce5574fd1d84b7b0cb4238fa3e898575e89a6724299be009d2172bda02e","src/external_trait_impls/serde.rs":"6dbe104dee16b453b6b048b541c6e02c6d067d970dfafd243fc4360288b0168c","src/lib.rs":"74e250c18e55994a4a902eaa06aca034559d6de53501ed4bf9010fabc67e88a2","src/macros.rs":"98a26b908fc0fbe6a58d008a317e550013d615eb3cc17a5054a573c62c1d74cb","src/map.rs":"d484f2f81e5b4acf4b615f187241e34c3016aaaca53a5e71019cceb993c4ebd7","src/raw/alloc.rs":"902f8588d0fdee3e5c3dc02410f41d4b38ac88843727387f929f3186b3a2d322","src/raw/bitmask.rs":"3b3dce8d6a48856ada19085abf43908f124ab3419fcf434b9ca64d7bff243f67","src/raw/generic.rs":"efc5e603be3e9a17935aef1836a38ce01c78a0093b2af0671548eb5459b37921","src/raw/mod.rs":"16bbabf42dde9f3fb17c4f7e768aef47752d839bf624b81d24a48af3d418b3a2","src/raw/neon.rs":"9907d8ebc36fc3df562dde478ea9b72213fda65288a304718d8647f0029dc9ad","src/raw/sse2.rs":"39038e3344e49f4638e211bcdbf56565ac53e90dce56172cc3b526fea911c2af","src/rustc_entry.rs":"8142ed89b50155602ef8c1628382bd62d3ee903920fe49d403d4100a278c6ba4","src/scopeguard.rs":"1a246e08a63c06cd8ad934bd7da229421bf804f991ae93cd7e242da27ca6c601","src/set.rs":"a620ed68bd1610b76c4c1890615d71b2c04928bf5b345133a0588a065bce06fa","src/table.rs":"7b7174099d2e3cade0caeddd73e29b7395f3b9f4f1f21013f885b52cd93438cb","tests/equivalent_trait.rs":"84faa3fe9d67c375d03fec81f0f1412c47862477d42e84e7d235258236338d5b","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/raw.rs":"43ed2f98877533a0905611d9a30f26b183dd3e103e3856eeab80e7b8ac7894d3","tests/rayon.rs":"39cb24ab45fce8087bb54948715c8b6973ebfba1a325292b5b3cd9aab50b5fd2","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"9f8011c29d1059aadb54b6dd4623521d5178b4278b4a56021ef2cee4bbb19fd9"},"package":"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"} \ No newline at end of file diff --git a/third_party/rust/hashbrown/CHANGELOG.md b/third_party/rust/hashbrown/CHANGELOG.md index 3354b54bb3..8c4068089a 100644 --- a/third_party/rust/hashbrown/CHANGELOG.md +++ b/third_party/rust/hashbrown/CHANGELOG.md @@ -7,35 +7,157 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Changed + +- Changed `hash_set::{Entry, VacantEntry}::insert` to return `OccupiedEntry`. (#495) + +## [v0.14.5] - 2024-04-28 + +### Fixed + +- Fixed index calculation in panic guard of `clone_from_impl`. (#511) + +## ~~[v0.14.4] - 2024-03-19~~ + +This release was _yanked_ due to a breaking change. + +## [v0.14.3] - 2023-11-26 + +### Added + +- Specialized `fold` implementation of iterators. (#480) + +### Fixed + +- Avoid using unstable `ptr::invalid_mut` on nightly. (#481) + +## [v0.14.2] - 2023-10-19 + +### Added + +- `HashTable` type which provides a low-level but safe API with explicit hashing. (#466) + +### Fixed + +- Disabled the use of NEON instructions on big-endian ARM. (#475) +- Disabled the use of NEON instructions on Miri. (#476) + +## [v0.14.1] - 2023-09-28 + +### Added + +- Allow serializing `HashMap`s that use a custom allocator. (#449) + +### Changed + +- Use the `Equivalent` trait from the `equivalent` crate. (#442) +- Slightly improved performance of table resizing. (#451) +- Relaxed MSRV to 1.63.0. (#457) +- Removed `Clone` requirement from custom allocators. (#468) + +### Fixed + +- Fixed custom allocators being leaked in some situations. (#439, #465) + +## [v0.14.0] - 2023-06-01 + +### Added + +- Support for `allocator-api2` crate + for interfacing with custom allocators on stable. (#417) +- Optimized implementation for ARM using NEON instructions. (#430) +- Support for rkyv serialization. (#432) +- `Equivalent` trait to look up values without `Borrow`. (#345) +- `Hash{Map,Set}::raw_table_mut` is added whic returns a mutable reference. (#404) +- Fast path for `clear` on empty tables. (#428) + +### Changed + +- Optimized insertion to only perform a single lookup. (#277) +- `DrainFilter` (`drain_filter`) has been renamed to `ExtractIf` and no longer drops remaining + elements when the iterator is dropped. #(374) +- Bumped MSRV to 1.64.0. (#431) +- `{Map,Set}::raw_table` now returns an immutable reference. (#404) +- `VacantEntry` and `OccupiedEntry` now use the default hasher if none is + specified in generics. (#389) +- `RawTable::data_start` now returns a `NonNull` to match `RawTable::data_end`. (#387) +- `RawIter::{reflect_insert, reflect_remove}` are now unsafe. (#429) +- `RawTable::find_potential` is renamed to `find_or_find_insert_slot` and returns an `InsertSlot`. (#429) +- `RawTable::remove` now also returns an `InsertSlot`. (#429) +- `InsertSlot` can be used to insert an element with `RawTable::insert_in_slot`. (#429) +- `RawIterHash` no longer has a lifetime tied to that of the `RawTable`. (#427) +- The trait bounds of `HashSet::raw_table` have been relaxed to not require `Eq + Hash`. (#423) +- `EntryRef::and_replace_entry_with` and `OccupiedEntryRef::replace_entry_with` + were changed to give a `&K` instead of a `&Q` to the closure. + +### Removed + +- Support for `bumpalo` as an allocator with custom wrapper. + Use `allocator-api2` feature in `bumpalo` to use it as an allocator + for `hashbrown` collections. (#417) + +## [v0.13.2] - 2023-01-12 + +### Fixed + +- Added `#[inline(always)]` to `find_inner`. (#375) +- Fixed `RawTable::allocation_info` for empty tables. (#376) + +## [v0.13.1] - 2022-11-10 + +### Added + +- Added `Equivalent` trait to customize key lookups. (#350) +- Added support for 16-bit targets. (#368) +- Added `RawTable::allocation_info` which provides information about the memory + usage of a table. (#371) + +### Changed + +- Bumped MSRV to 1.61.0. +- Upgraded to `ahash` 0.8. (#357) +- Make `with_hasher_in` const. (#355) +- The following methods have been removed from the `RawTable` API in favor of + safer alternatives: + - `RawTable::erase_no_drop` => Use `RawTable::erase` or `RawTable::remove` instead. + - `Bucket::read` => Use `RawTable::remove` instead. + - `Bucket::drop` => Use `RawTable::erase` instead. + - `Bucket::write` => Use `Bucket::as_mut` instead. + +### Fixed + +- Ensure that `HashMap` allocations don't exceed `isize::MAX`. (#362) +- Fixed issue with field retagging in scopeguard. (#359) + ## [v0.12.3] - 2022-07-17 -## Fixed +### Fixed - Fixed double-drop in `RawTable::clone_from`. (#348) ## [v0.12.2] - 2022-07-09 -## Added +### Added - Added `Entry` API for `HashSet`. (#342) - Added `Extend<&'a (K, V)> for HashMap`. (#340) - Added length-based short-circuiting for hash table iteration. (#338) - Added a function to access the `RawTable` of a `HashMap`. (#335) -## Changed +### Changed - Edited `do_alloc` to reduce LLVM IR generated. (#341) ## [v0.12.1] - 2022-05-02 -## Fixed +### Fixed - Fixed underflow in `RawIterRange::size_hint`. (#325) - Fixed the implementation of `Debug` for `ValuesMut` and `IntoValues`. (#325) ## [v0.12.0] - 2022-01-17 -## Added +### Added - Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297) - Added an `allocator()` getter to HashMap and HashSet. (#257) @@ -44,7 +166,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - Implement `From` on `HashSet` and `HashMap`. (#298) - Added `entry_ref` API to `HashMap`. (#201) -## Changed +### Changed - Bumped minimum Rust version to 1.56.1 and edition to 2021. - Use u64 for the GroupWord on WebAssembly. (#271) @@ -56,7 +178,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291) - Don't hash the key when searching in an empty table. (#305) -## Fixed +### Fixed - Guard against allocations exceeding isize::MAX. (#268) - Made `RawTable::insert_no_grow` unsafe. (#254) @@ -65,19 +187,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [v0.11.2] - 2021-03-25 -## Fixed +### Fixed - Added missing allocator type parameter to `HashMap`'s and `HashSet`'s `Clone` impls. (#252) ## [v0.11.1] - 2021-03-20 -## Fixed +### Fixed - Added missing `pub` modifier to `BumpWrapper`. (#251) ## [v0.11.0] - 2021-03-14 -## Added +### Added - Added safe `try_insert_no_grow` method to `RawTable`. (#229) - Added support for `bumpalo` as an allocator without the `nightly` feature. (#231) - Implemented `Default` for `RawTable`. (#237) @@ -86,22 +208,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - Added `From>` for `HashSet`. (#235) - Added `try_insert` method to `HashMap`. (#247) -## Changed +### Changed - The minimum Rust version has been bumped to 1.49.0. (#230) - Significantly improved compilation times by reducing the amount of generated IR. (#205) -## Removed +### Removed - We no longer re-export the unstable allocator items from the standard library, nor the stable shims approximating the same. (#227) - Removed hasher specialization support from `aHash`, which was resulting in inconsistent hashes being generated for a key. (#248) -## Fixed +### Fixed - Fixed union length comparison. (#228) ## ~~[v0.10.0] - 2021-01-16~~ This release was _yanked_ due to inconsistent hashes being generated with the `nightly` feature. (#248) -## Changed +### Changed - Parametrized `RawTable`, `HashSet` and `HashMap` over an allocator. (#133) - Improved branch prediction hints on stable. (#209) - Optimized hashing of primitive types with AHash using specialization. (#207) @@ -109,7 +231,7 @@ This release was _yanked_ due to inconsistent hashes being generated with the `n ## [v0.9.1] - 2020-09-28 -## Added +### Added - Added safe methods to `RawTable` (#202): - `get`: `find` and `as_ref` - `get_mut`: `find` and `as_mut` @@ -117,7 +239,7 @@ This release was _yanked_ due to inconsistent hashes being generated with the `n - `remove_entry`: `find` and `remove` - `erase_entry`: `find` and `erase` -## Changed +### Changed - Removed `from_key_hashed_nocheck`'s `Q: Hash`. (#200) - Made `RawTable::drain` safe. (#201) @@ -215,7 +337,7 @@ This release was _yanked_ due to inconsistent hashes being generated with the `n ## [v0.6.2] - 2019-10-23 ### Added -- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between +- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between runtime performance and compilation time. (#119) ## [v0.6.1] - 2019-10-04 @@ -363,7 +485,15 @@ This release was _yanked_ due to a breaking change for users of `no-default-feat - Initial release -[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...HEAD +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.14.5...HEAD +[v0.14.5]: https://github.com/rust-lang/hashbrown/compare/v0.14.4...v0.14.5 +[v0.14.4]: https://github.com/rust-lang/hashbrown/compare/v0.14.3...v0.14.4 +[v0.14.3]: https://github.com/rust-lang/hashbrown/compare/v0.14.2...v0.14.3 +[v0.14.2]: https://github.com/rust-lang/hashbrown/compare/v0.14.1...v0.14.2 +[v0.14.1]: https://github.com/rust-lang/hashbrown/compare/v0.14.0...v0.14.1 +[v0.14.0]: https://github.com/rust-lang/hashbrown/compare/v0.13.2...v0.14.0 +[v0.13.2]: https://github.com/rust-lang/hashbrown/compare/v0.13.1...v0.13.2 +[v0.13.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...v0.13.1 [v0.12.3]: https://github.com/rust-lang/hashbrown/compare/v0.12.2...v0.12.3 [v0.12.2]: https://github.com/rust-lang/hashbrown/compare/v0.12.1...v0.12.2 [v0.12.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...v0.12.1 diff --git a/third_party/rust/hashbrown/Cargo.toml b/third_party/rust/hashbrown/Cargo.toml index fb130d24d2..0a5434e494 100644 --- a/third_party/rust/hashbrown/Cargo.toml +++ b/third_party/rust/hashbrown/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.56.0" +rust-version = "1.63.0" name = "hashbrown" -version = "0.12.3" +version = "0.14.5" authors = ["Amanieu d'Antras "] exclude = [ ".github", @@ -33,7 +33,6 @@ categories = [ ] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/hashbrown" -resolver = "2" [package.metadata.docs.rs] features = [ @@ -42,9 +41,10 @@ features = [ "serde", "raw", ] +rustdoc-args = ["--generate-link-to-definition"] [dependencies.ahash] -version = "0.7.0" +version = "0.8.7" optional = true default-features = false @@ -53,9 +53,11 @@ version = "1.0.0" optional = true package = "rustc-std-workspace-alloc" -[dependencies.bumpalo] -version = "3.5.0" +[dependencies.allocator-api2] +version = "0.2.9" +features = ["alloc"] optional = true +default-features = false [dependencies.compiler_builtins] version = "0.1.2" @@ -66,15 +68,30 @@ version = "1.0.0" optional = true package = "rustc-std-workspace-core" +[dependencies.equivalent] +version = "1.0" +optional = true +default-features = false + [dependencies.rayon] version = "1.0" optional = true +[dependencies.rkyv] +version = "0.7.42" +features = ["alloc"] +optional = true +default-features = false + [dependencies.serde] version = "1.0.25" optional = true default-features = false +[dev-dependencies.bumpalo] +version = "3.13.0" +features = ["allocator-api2"] + [dev-dependencies.doc-comment] version = "0.3.1" @@ -91,17 +108,24 @@ features = ["small_rng"] [dev-dependencies.rayon] version = "1.0" +[dev-dependencies.rkyv] +version = "0.7.42" +features = ["validation"] + [dev-dependencies.serde_test] version = "1.0" [features] -ahash-compile-time-rng = ["ahash/compile-time-rng"] default = [ "ahash", "inline-more", + "allocator-api2", ] inline-more = [] -nightly = [] +nightly = [ + "allocator-api2?/nightly", + "bumpalo/allocator_api", +] raw = [] rustc-dep-of-std = [ "nightly", diff --git a/third_party/rust/hashbrown/README.md b/third_party/rust/hashbrown/README.md index 2eddcf3e29..5eaef8bd01 100644 --- a/third_party/rust/hashbrown/README.md +++ b/third_party/rust/hashbrown/README.md @@ -4,7 +4,7 @@ hashbrown [![Build Status](https://github.com/rust-lang/hashbrown/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-lang/hashbrown/actions) [![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown) [![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown) -[![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown) +[![Rust](https://img.shields.io/badge/rust-1.63.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown) This crate is a Rust port of Google's high-performance [SwissTable] hash map, adapted to make it a drop-in replacement for Rust's standard `HashMap` @@ -40,44 +40,44 @@ Compared to the previous implementation of `std::collections::HashMap` (Rust 1.3 With the hashbrown default AHash hasher: -| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | -|:------------------------|:-------------------:|------------------:|:------------:|---------:|---------| -| insert_ahash_highbits | 18,865 | 8,020 | -10,845 | -57.49% | x 2.35 | -| insert_ahash_random | 19,711 | 8,019 | -11,692 | -59.32% | x 2.46 | -| insert_ahash_serial | 19,365 | 6,463 | -12,902 | -66.63% | x 3.00 | -| insert_erase_ahash_highbits | 51,136 | 17,916 | -33,220 | -64.96% | x 2.85 | -| insert_erase_ahash_random | 51,157 | 17,688 | -33,469 | -65.42% | x 2.89 | -| insert_erase_ahash_serial | 45,479 | 14,895 | -30,584 | -67.25% | x 3.05 | -| iter_ahash_highbits | 1,399 | 1,092 | -307 | -21.94% | x 1.28 | -| iter_ahash_random | 1,586 | 1,059 | -527 | -33.23% | x 1.50 | -| iter_ahash_serial | 3,168 | 1,079 | -2,089 | -65.94% | x 2.94 | -| lookup_ahash_highbits | 32,351 | 4,792 | -27,559 | -85.19% | x 6.75 | -| lookup_ahash_random | 17,419 | 4,817 | -12,602 | -72.35% | x 3.62 | -| lookup_ahash_serial | 15,254 | 3,606 | -11,648 | -76.36% | x 4.23 | -| lookup_fail_ahash_highbits | 21,187 | 4,369 | -16,818 | -79.38% | x 4.85 | -| lookup_fail_ahash_random | 21,550 | 4,395 | -17,155 | -79.61% | x 4.90 | -| lookup_fail_ahash_serial | 19,450 | 3,176 | -16,274 | -83.67% | x 6.12 | +| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +| :-------------------------- | :----------------: | ----------------: | :----------: | ------: | ------- | +| insert_ahash_highbits | 18,865 | 8,020 | -10,845 | -57.49% | x 2.35 | +| insert_ahash_random | 19,711 | 8,019 | -11,692 | -59.32% | x 2.46 | +| insert_ahash_serial | 19,365 | 6,463 | -12,902 | -66.63% | x 3.00 | +| insert_erase_ahash_highbits | 51,136 | 17,916 | -33,220 | -64.96% | x 2.85 | +| insert_erase_ahash_random | 51,157 | 17,688 | -33,469 | -65.42% | x 2.89 | +| insert_erase_ahash_serial | 45,479 | 14,895 | -30,584 | -67.25% | x 3.05 | +| iter_ahash_highbits | 1,399 | 1,092 | -307 | -21.94% | x 1.28 | +| iter_ahash_random | 1,586 | 1,059 | -527 | -33.23% | x 1.50 | +| iter_ahash_serial | 3,168 | 1,079 | -2,089 | -65.94% | x 2.94 | +| lookup_ahash_highbits | 32,351 | 4,792 | -27,559 | -85.19% | x 6.75 | +| lookup_ahash_random | 17,419 | 4,817 | -12,602 | -72.35% | x 3.62 | +| lookup_ahash_serial | 15,254 | 3,606 | -11,648 | -76.36% | x 4.23 | +| lookup_fail_ahash_highbits | 21,187 | 4,369 | -16,818 | -79.38% | x 4.85 | +| lookup_fail_ahash_random | 21,550 | 4,395 | -17,155 | -79.61% | x 4.90 | +| lookup_fail_ahash_serial | 19,450 | 3,176 | -16,274 | -83.67% | x 6.12 | With the libstd default SipHash hasher: -|name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | -|:------------------------|:-------------------:|------------------:|:------------:|---------:|---------| -|insert_std_highbits |19,216 |16,885 | -2,331 | -12.13% | x 1.14 | -|insert_std_random |19,179 |17,034 | -2,145 | -11.18% | x 1.13 | -|insert_std_serial |19,462 |17,493 | -1,969 | -10.12% | x 1.11 | -|insert_erase_std_highbits |50,825 |35,847 | -14,978 | -29.47% | x 1.42 | -|insert_erase_std_random |51,448 |35,392 | -16,056 | -31.21% | x 1.45 | -|insert_erase_std_serial |87,711 |38,091 | -49,620 | -56.57% | x 2.30 | -|iter_std_highbits |1,378 |1,159 | -219 | -15.89% | x 1.19 | -|iter_std_random |1,395 |1,132 | -263 | -18.85% | x 1.23 | -|iter_std_serial |1,704 |1,105 | -599 | -35.15% | x 1.54 | -|lookup_std_highbits |17,195 |13,642 | -3,553 | -20.66% | x 1.26 | -|lookup_std_random |17,181 |13,773 | -3,408 | -19.84% | x 1.25 | -|lookup_std_serial |15,483 |13,651 | -1,832 | -11.83% | x 1.13 | -|lookup_fail_std_highbits |20,926 |13,474 | -7,452 | -35.61% | x 1.55 | -|lookup_fail_std_random |21,766 |13,505 | -8,261 | -37.95% | x 1.61 | -|lookup_fail_std_serial |19,336 |13,519 | -5,817 | -30.08% | x 1.43 | +| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +| :------------------------ | :----------------: | ----------------: | :----------: | ------: | ------- | +| insert_std_highbits | 19,216 | 16,885 | -2,331 | -12.13% | x 1.14 | +| insert_std_random | 19,179 | 17,034 | -2,145 | -11.18% | x 1.13 | +| insert_std_serial | 19,462 | 17,493 | -1,969 | -10.12% | x 1.11 | +| insert_erase_std_highbits | 50,825 | 35,847 | -14,978 | -29.47% | x 1.42 | +| insert_erase_std_random | 51,448 | 35,392 | -16,056 | -31.21% | x 1.45 | +| insert_erase_std_serial | 87,711 | 38,091 | -49,620 | -56.57% | x 2.30 | +| iter_std_highbits | 1,378 | 1,159 | -219 | -15.89% | x 1.19 | +| iter_std_random | 1,395 | 1,132 | -263 | -18.85% | x 1.23 | +| iter_std_serial | 1,704 | 1,105 | -599 | -35.15% | x 1.54 | +| lookup_std_highbits | 17,195 | 13,642 | -3,553 | -20.66% | x 1.26 | +| lookup_std_random | 17,181 | 13,773 | -3,408 | -19.84% | x 1.25 | +| lookup_std_serial | 15,483 | 13,651 | -1,832 | -11.83% | x 1.13 | +| lookup_fail_std_highbits | 20,926 | 13,474 | -7,452 | -35.61% | x 1.55 | +| lookup_fail_std_random | 21,766 | 13,505 | -8,261 | -37.95% | x 1.61 | +| lookup_fail_std_serial | 19,336 | 13,519 | -5,817 | -30.08% | x 1.43 | ## Usage @@ -85,7 +85,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -hashbrown = "0.12" +hashbrown = "0.14" ``` Then: @@ -101,14 +101,13 @@ This crate has the following Cargo features: - `nightly`: Enables nightly-only features including: `#[may_dangle]`. - `serde`: Enables serde serialization support. +- `rkyv`: Enables rkyv serialization support. - `rayon`: Enables rayon parallel iterator support. - `raw`: Enables access to the experimental and unsafe `RawTable` API. - `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost of compilation time. (enabled by default) -- `bumpalo`: Provides a `BumpWrapper` type which allows `bumpalo` to be used for memory allocation. - `ahash`: Compiles with ahash as default hasher. (enabled by default) -- `ahash-compile-time-rng`: Activates the `compile-time-rng` feature of ahash. For targets with no random number generator -this pre-generates seeds at compile time and embeds them as constants. See [aHash's documentation](https://github.com/tkaitchuck/aHash#flags) (disabled by default) +- `allocator-api2`: Enables support for allocators that support `allocator-api2`. (enabled by default) ## License diff --git a/third_party/rust/hashbrown/benches/bench.rs b/third_party/rust/hashbrown/benches/bench.rs index c393b9a706..346bd7ef89 100644 --- a/third_party/rust/hashbrown/benches/bench.rs +++ b/third_party/rust/hashbrown/benches/bench.rs @@ -311,7 +311,7 @@ fn rehash_in_place(b: &mut Bencher) { // Each loop triggers one rehash for _ in 0..10 { - for i in 0..224 { + for i in 0..223 { set.insert(i); } diff --git a/third_party/rust/hashbrown/src/external_trait_impls/mod.rs b/third_party/rust/hashbrown/src/external_trait_impls/mod.rs index ef497836cb..01d386b046 100644 --- a/third_party/rust/hashbrown/src/external_trait_impls/mod.rs +++ b/third_party/rust/hashbrown/src/external_trait_impls/mod.rs @@ -1,4 +1,6 @@ #[cfg(feature = "rayon")] pub(crate) mod rayon; +#[cfg(feature = "rkyv")] +mod rkyv; #[cfg(feature = "serde")] mod serde; diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rayon/map.rs b/third_party/rust/hashbrown/src/external_trait_impls/rayon/map.rs index 14d91c220c..2534dc9b2b 100644 --- a/third_party/rust/hashbrown/src/external_trait_impls/rayon/map.rs +++ b/third_party/rust/hashbrown/src/external_trait_impls/rayon/map.rs @@ -232,11 +232,11 @@ impl fmt::Debug for ParValuesMut<'_, K, V> { /// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter /// [`HashMap`]: /hashbrown/struct.HashMap.html /// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html -pub struct IntoParIter { +pub struct IntoParIter { inner: RawIntoParIter<(K, V), A>, } -impl ParallelIterator for IntoParIter { +impl ParallelIterator for IntoParIter { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] @@ -248,9 +248,7 @@ impl ParallelIterator for IntoPar } } -impl fmt::Debug - for IntoParIter -{ +impl fmt::Debug for IntoParIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ParIter { inner: unsafe { self.inner.par_iter() }, @@ -267,11 +265,11 @@ impl fmt::Debug /// /// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain /// [`HashMap`]: /hashbrown/struct.HashMap.html -pub struct ParDrain<'a, K, V, A: Allocator + Clone = Global> { +pub struct ParDrain<'a, K, V, A: Allocator = Global> { inner: RawParDrain<'a, (K, V), A>, } -impl ParallelIterator for ParDrain<'_, K, V, A> { +impl ParallelIterator for ParDrain<'_, K, V, A> { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] @@ -283,9 +281,7 @@ impl ParallelIterator for ParDrai } } -impl fmt::Debug - for ParDrain<'_, K, V, A> -{ +impl fmt::Debug for ParDrain<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ParIter { inner: unsafe { self.inner.par_iter() }, @@ -295,7 +291,7 @@ impl fmt::Debug } } -impl HashMap { +impl HashMap { /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. #[cfg_attr(feature = "inline-more", inline)] pub fn par_keys(&self) -> ParKeys<'_, K, V> { @@ -315,7 +311,7 @@ impl HashMap { } } -impl HashMap { +impl HashMap { /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. #[cfg_attr(feature = "inline-more", inline)] pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { @@ -340,7 +336,7 @@ where K: Eq + Hash + Sync, V: PartialEq + Sync, S: BuildHasher + Sync, - A: Allocator + Clone + Sync, + A: Allocator + Sync, { /// Returns `true` if the map is equal to another, /// i.e. both maps contain the same keys mapped to the same values. @@ -354,9 +350,7 @@ where } } -impl IntoParallelIterator - for HashMap -{ +impl IntoParallelIterator for HashMap { type Item = (K, V); type Iter = IntoParIter; @@ -368,9 +362,7 @@ impl IntoParallelIterator } } -impl<'a, K: Sync, V: Sync, S, A: Allocator + Clone> IntoParallelIterator - for &'a HashMap -{ +impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap { type Item = (&'a K, &'a V); type Iter = ParIter<'a, K, V>; @@ -383,9 +375,7 @@ impl<'a, K: Sync, V: Sync, S, A: Allocator + Clone> IntoParallelIterator } } -impl<'a, K: Sync, V: Send, S, A: Allocator + Clone> IntoParallelIterator - for &'a mut HashMap -{ +impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap { type Item = (&'a K, &'a mut V); type Iter = ParIterMut<'a, K, V>; @@ -424,7 +414,7 @@ where K: Eq + Hash + Send, V: Send, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn par_extend(&mut self, par_iter: I) where @@ -440,7 +430,7 @@ where K: Copy + Eq + Hash + Sync, V: Copy + Sync, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn par_extend(&mut self, par_iter: I) where @@ -456,7 +446,7 @@ where K: Eq + Hash, S: BuildHasher, I: IntoParallelIterator, - A: Allocator + Clone, + A: Allocator, HashMap: Extend, { let (list, len) = super::helpers::collect(par_iter); @@ -561,10 +551,7 @@ mod test_par_map { assert_eq!(value.load(Ordering::Relaxed), 100); // retain only half - let _v: Vec<_> = hm - .into_par_iter() - .filter(|&(ref key, _)| key.k < 50) - .collect(); + let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect(); assert_eq!(key.load(Ordering::Relaxed), 50); assert_eq!(value.load(Ordering::Relaxed), 50); @@ -611,7 +598,7 @@ mod test_par_map { assert_eq!(value.load(Ordering::Relaxed), 100); // retain only half - let _v: Vec<_> = hm.drain().filter(|&(ref key, _)| key.k < 50).collect(); + let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect(); assert!(hm.is_empty()); assert_eq!(key.load(Ordering::Relaxed), 50); diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rayon/mod.rs b/third_party/rust/hashbrown/src/external_trait_impls/rayon/mod.rs index 99337a1ce3..61ca69b61d 100644 --- a/third_party/rust/hashbrown/src/external_trait_impls/rayon/mod.rs +++ b/third_party/rust/hashbrown/src/external_trait_impls/rayon/mod.rs @@ -2,3 +2,4 @@ mod helpers; pub(crate) mod map; pub(crate) mod raw; pub(crate) mod set; +pub(crate) mod table; diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rayon/raw.rs b/third_party/rust/hashbrown/src/external_trait_impls/rayon/raw.rs index 883303e278..612be47a55 100644 --- a/third_party/rust/hashbrown/src/external_trait_impls/rayon/raw.rs +++ b/third_party/rust/hashbrown/src/external_trait_impls/rayon/raw.rs @@ -1,7 +1,6 @@ use crate::raw::Bucket; use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable}; use crate::scopeguard::guard; -use alloc::alloc::dealloc; use core::marker::PhantomData; use core::mem; use core::ptr::NonNull; @@ -76,18 +75,18 @@ impl UnindexedProducer for ParIterProducer { } /// Parallel iterator which consumes a table and returns elements. -pub struct RawIntoParIter { +pub struct RawIntoParIter { table: RawTable, } -impl RawIntoParIter { +impl RawIntoParIter { #[cfg_attr(feature = "inline-more", inline)] pub(super) unsafe fn par_iter(&self) -> RawParIter { self.table.par_iter() } } -impl ParallelIterator for RawIntoParIter { +impl ParallelIterator for RawIntoParIter { type Item = T; #[cfg_attr(feature = "inline-more", inline)] @@ -97,9 +96,9 @@ impl ParallelIterator for RawIntoParIter ParallelIterator for RawIntoParIter { +pub struct RawParDrain<'a, T, A: Allocator = Global> { // We don't use a &'a mut RawTable because we want RawParDrain to be // covariant over T. table: NonNull>, marker: PhantomData<&'a RawTable>, } -unsafe impl Send for RawParDrain<'_, T, A> {} +unsafe impl Send for RawParDrain<'_, T, A> {} -impl RawParDrain<'_, T, A> { +impl RawParDrain<'_, T, A> { #[cfg_attr(feature = "inline-more", inline)] pub(super) unsafe fn par_iter(&self) -> RawParIter { self.table.as_ref().par_iter() } } -impl ParallelIterator for RawParDrain<'_, T, A> { +impl ParallelIterator for RawParDrain<'_, T, A> { type Item = T; #[cfg_attr(feature = "inline-more", inline)] @@ -143,7 +142,7 @@ impl ParallelIterator for RawParDrain<'_, T, A> { } } -impl Drop for RawParDrain<'_, T, A> { +impl Drop for RawParDrain<'_, T, A> { fn drop(&mut self) { // If drive_unindexed is not called then simply clear the table. unsafe { @@ -204,7 +203,7 @@ impl Drop for ParDrainProducer { } } -impl RawTable { +impl RawTable { /// Returns a parallel iterator over the elements in a `RawTable`. #[cfg_attr(feature = "inline-more", inline)] pub unsafe fn par_iter(&self) -> RawParIter { diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rayon/set.rs b/third_party/rust/hashbrown/src/external_trait_impls/rayon/set.rs index ee4f6e6693..3de98fccb8 100644 --- a/third_party/rust/hashbrown/src/external_trait_impls/rayon/set.rs +++ b/third_party/rust/hashbrown/src/external_trait_impls/rayon/set.rs @@ -16,11 +16,11 @@ use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, Pa /// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter /// [`HashSet`]: /hashbrown/struct.HashSet.html /// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html -pub struct IntoParIter { +pub struct IntoParIter { inner: map::IntoParIter, } -impl ParallelIterator for IntoParIter { +impl ParallelIterator for IntoParIter { type Item = T; fn drive_unindexed(self, consumer: C) -> C::Result @@ -38,11 +38,11 @@ impl ParallelIterator for IntoParIter { +pub struct ParDrain<'a, T, A: Allocator = Global> { inner: map::ParDrain<'a, T, (), A>, } -impl ParallelIterator for ParDrain<'_, T, A> { +impl ParallelIterator for ParDrain<'_, T, A> { type Item = T; fn drive_unindexed(self, consumer: C) -> C::Result @@ -85,7 +85,7 @@ impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { /// /// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParDifference<'a, T, S, A: Allocator + Clone = Global> { +pub struct ParDifference<'a, T, S, A: Allocator = Global> { a: &'a HashSet, b: &'a HashSet, } @@ -94,7 +94,7 @@ impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A> where T: Eq + Hash + Sync, S: BuildHasher + Sync, - A: Allocator + Clone + Sync, + A: Allocator + Sync, { type Item = &'a T; @@ -118,7 +118,7 @@ where /// /// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParSymmetricDifference<'a, T, S, A: Allocator + Clone = Global> { +pub struct ParSymmetricDifference<'a, T, S, A: Allocator = Global> { a: &'a HashSet, b: &'a HashSet, } @@ -127,7 +127,7 @@ impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A> where T: Eq + Hash + Sync, S: BuildHasher + Sync, - A: Allocator + Clone + Sync, + A: Allocator + Sync, { type Item = &'a T; @@ -150,7 +150,7 @@ where /// /// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParIntersection<'a, T, S, A: Allocator + Clone = Global> { +pub struct ParIntersection<'a, T, S, A: Allocator = Global> { a: &'a HashSet, b: &'a HashSet, } @@ -159,7 +159,7 @@ impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A> where T: Eq + Hash + Sync, S: BuildHasher + Sync, - A: Allocator + Clone + Sync, + A: Allocator + Sync, { type Item = &'a T; @@ -181,7 +181,7 @@ where /// /// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParUnion<'a, T, S, A: Allocator + Clone = Global> { +pub struct ParUnion<'a, T, S, A: Allocator = Global> { a: &'a HashSet, b: &'a HashSet, } @@ -190,7 +190,7 @@ impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A> where T: Eq + Hash + Sync, S: BuildHasher + Sync, - A: Allocator + Clone + Sync, + A: Allocator + Sync, { type Item = &'a T; @@ -216,7 +216,7 @@ impl HashSet where T: Eq + Hash + Sync, S: BuildHasher + Sync, - A: Allocator + Clone + Sync, + A: Allocator + Sync, { /// Visits (potentially in parallel) the values representing the union, /// i.e. all the values in `self` or `other`, without duplicates. @@ -289,7 +289,7 @@ where impl HashSet where T: Eq + Hash + Send, - A: Allocator + Clone + Send, + A: Allocator + Send, { /// Consumes (potentially in parallel) all values in an arbitrary order, /// while preserving the set's allocated memory for reuse. @@ -301,7 +301,7 @@ where } } -impl IntoParallelIterator for HashSet { +impl IntoParallelIterator for HashSet { type Item = T; type Iter = IntoParIter; @@ -313,7 +313,7 @@ impl IntoParallelIterator for HashSet IntoParallelIterator for &'a HashSet { +impl<'a, T: Sync, S, A: Allocator> IntoParallelIterator for &'a HashSet { type Item = &'a T; type Iter = ParIter<'a, T>; @@ -374,7 +374,7 @@ fn extend(set: &mut HashSet, par_iter: I) where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, I: IntoParallelIterator, HashSet: Extend, { diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rayon/table.rs b/third_party/rust/hashbrown/src/external_trait_impls/rayon/table.rs new file mode 100644 index 0000000000..e8e50944ad --- /dev/null +++ b/third_party/rust/hashbrown/src/external_trait_impls/rayon/table.rs @@ -0,0 +1,252 @@ +//! Rayon extensions for `HashTable`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_table::HashTable; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashTable.html#method.par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_ref() }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { x.as_ref() }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashTable.html#method.par_iter_mut +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T: Send> ParallelIterator for ParIterMut<'a, T> { + type Item = &'a mut T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_mut() }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashTable.html#method.into_par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashTable.html#method.par_drain +/// [`HashTable`]: /hashbrown/struct.HashTable.html +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: RawParDrain<'a, T, A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashTable { + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.raw.par_drain(), + } + } +} + +impl IntoParallelIterator for HashTable { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.raw.into_par_iter(), + } + } +} + +impl<'a, T: Sync, A: Allocator> IntoParallelIterator for &'a HashTable { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, T: Send, A: Allocator> IntoParallelIterator for &'a mut HashTable { + type Item = &'a mut T; + type Iter = ParIterMut<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +#[cfg(test)] +mod test_par_table { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::{ + hash_map::{make_hash, DefaultHashBuilder}, + hash_table::HashTable, + }; + + #[test] + fn test_iterate() { + let hasher = DefaultHashBuilder::default(); + let mut a = HashTable::new(); + for i in 0..32 { + a.insert_unique(make_hash(&hasher, &i), i, |x| make_hash(&hasher, x)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_move_iter() { + let hasher = DefaultHashBuilder::default(); + let hs = { + let mut hs = HashTable::new(); + + hs.insert_unique(make_hash(&hasher, &'a'), 'a', |x| make_hash(&hasher, x)); + hs.insert_unique(make_hash(&hasher, &'b'), 'b', |x| make_hash(&hasher, x)); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } +} diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_map.rs b/third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_map.rs new file mode 100644 index 0000000000..fae7f76763 --- /dev/null +++ b/third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_map.rs @@ -0,0 +1,125 @@ +use crate::HashMap; +use core::{ + borrow::Borrow, + hash::{BuildHasher, Hash}, +}; +use rkyv::{ + collections::hash_map::{ArchivedHashMap, HashMapResolver}, + ser::{ScratchSpace, Serializer}, + Archive, Deserialize, Fallible, Serialize, +}; + +impl Archive for HashMap +where + K::Archived: Hash + Eq, +{ + type Archived = ArchivedHashMap; + type Resolver = HashMapResolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ArchivedHashMap::resolve_from_len(self.len(), pos, resolver, out); + } +} + +impl Serialize for HashMap +where + K: Serialize + Hash + Eq, + K::Archived: Hash + Eq, + V: Serialize, + S: Serializer + ScratchSpace + ?Sized, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + unsafe { ArchivedHashMap::serialize_from_iter(self.iter(), serializer) } + } +} + +impl + Deserialize, D> for ArchivedHashMap +where + K::Archived: Deserialize + Hash + Eq, + V::Archived: Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let mut result = HashMap::with_capacity_and_hasher(self.len(), S::default()); + for (k, v) in self.iter() { + result.insert(k.deserialize(deserializer)?, v.deserialize(deserializer)?); + } + Ok(result) + } +} + +impl, V, AK: Hash + Eq, AV: PartialEq, S: BuildHasher> + PartialEq> for ArchivedHashMap +{ + #[inline] + fn eq(&self, other: &HashMap) -> bool { + if self.len() != other.len() { + false + } else { + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| value.eq(v))) + } + } +} + +impl, V, AK: Hash + Eq, AV: PartialEq> + PartialEq> for HashMap +{ + #[inline] + fn eq(&self, other: &ArchivedHashMap) -> bool { + other.eq(self) + } +} + +#[cfg(test)] +mod tests { + use crate::HashMap; + use alloc::string::String; + use rkyv::{ + archived_root, check_archived_root, + ser::{serializers::AllocSerializer, Serializer}, + Deserialize, Infallible, + }; + + #[test] + fn index_map() { + let mut value = HashMap::new(); + value.insert(String::from("foo"), 10); + value.insert(String::from("bar"), 20); + value.insert(String::from("baz"), 40); + value.insert(String::from("bat"), 80); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + let archived = unsafe { archived_root::>(result.as_ref()) }; + + assert_eq!(value.len(), archived.len()); + for (k, v) in value.iter() { + let (ak, av) = archived.get_key_value(k.as_str()).unwrap(); + assert_eq!(k, ak); + assert_eq!(v, av); + } + + let deserialized: HashMap = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(value, deserialized); + } + + #[test] + fn validate_index_map() { + let mut value = HashMap::new(); + value.insert(String::from("foo"), 10); + value.insert(String::from("bar"), 20); + value.insert(String::from("baz"), 40); + value.insert(String::from("bat"), 80); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + check_archived_root::>(result.as_ref()) + .expect("failed to validate archived index map"); + } +} diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_set.rs b/third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_set.rs new file mode 100644 index 0000000000..c8a69cf4fc --- /dev/null +++ b/third_party/rust/hashbrown/src/external_trait_impls/rkyv/hash_set.rs @@ -0,0 +1,123 @@ +use crate::HashSet; +use core::{ + borrow::Borrow, + hash::{BuildHasher, Hash}, +}; +use rkyv::{ + collections::hash_set::{ArchivedHashSet, HashSetResolver}, + ser::{ScratchSpace, Serializer}, + Archive, Deserialize, Fallible, Serialize, +}; + +impl Archive for HashSet +where + K::Archived: Hash + Eq, +{ + type Archived = ArchivedHashSet; + type Resolver = HashSetResolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ArchivedHashSet::::resolve_from_len(self.len(), pos, resolver, out); + } +} + +impl Serialize for HashSet +where + K::Archived: Hash + Eq, + K: Serialize + Hash + Eq, + S: ScratchSpace + Serializer + ?Sized, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + unsafe { ArchivedHashSet::serialize_from_iter(self.iter(), serializer) } + } +} + +impl Deserialize, D> for ArchivedHashSet +where + K: Archive + Hash + Eq, + K::Archived: Deserialize + Hash + Eq, + D: Fallible + ?Sized, + S: Default + BuildHasher, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let mut result = HashSet::with_hasher(S::default()); + for k in self.iter() { + result.insert(k.deserialize(deserializer)?); + } + Ok(result) + } +} + +impl, AK: Hash + Eq, S: BuildHasher> PartialEq> + for ArchivedHashSet +{ + #[inline] + fn eq(&self, other: &HashSet) -> bool { + if self.len() != other.len() { + false + } else { + self.iter().all(|key| other.get(key).is_some()) + } + } +} + +impl, AK: Hash + Eq, S: BuildHasher> PartialEq> + for HashSet +{ + #[inline] + fn eq(&self, other: &ArchivedHashSet) -> bool { + other.eq(self) + } +} + +#[cfg(test)] +mod tests { + use crate::HashSet; + use alloc::string::String; + use rkyv::{ + archived_root, check_archived_root, + ser::{serializers::AllocSerializer, Serializer}, + Deserialize, Infallible, + }; + + #[test] + fn index_set() { + let mut value = HashSet::new(); + value.insert(String::from("foo")); + value.insert(String::from("bar")); + value.insert(String::from("baz")); + value.insert(String::from("bat")); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + let archived = unsafe { archived_root::>(result.as_ref()) }; + + assert_eq!(value.len(), archived.len()); + for k in value.iter() { + let ak = archived.get(k.as_str()).unwrap(); + assert_eq!(k, ak); + } + + let deserialized: HashSet = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(value, deserialized); + } + + #[test] + fn validate_index_set() { + let mut value = HashSet::new(); + value.insert(String::from("foo")); + value.insert(String::from("bar")); + value.insert(String::from("baz")); + value.insert(String::from("bat")); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + check_archived_root::>(result.as_ref()) + .expect("failed to validate archived index set"); + } +} diff --git a/third_party/rust/hashbrown/src/external_trait_impls/rkyv/mod.rs b/third_party/rust/hashbrown/src/external_trait_impls/rkyv/mod.rs new file mode 100644 index 0000000000..2bde6a0653 --- /dev/null +++ b/third_party/rust/hashbrown/src/external_trait_impls/rkyv/mod.rs @@ -0,0 +1,2 @@ +mod hash_map; +mod hash_set; diff --git a/third_party/rust/hashbrown/src/external_trait_impls/serde.rs b/third_party/rust/hashbrown/src/external_trait_impls/serde.rs index 4d62deeb7a..0a76dbec25 100644 --- a/third_party/rust/hashbrown/src/external_trait_impls/serde.rs +++ b/third_party/rust/hashbrown/src/external_trait_impls/serde.rs @@ -11,6 +11,7 @@ mod size_hint { } mod map { + use crate::raw::Allocator; use core::fmt; use core::hash::{BuildHasher, Hash}; use core::marker::PhantomData; @@ -21,11 +22,12 @@ mod map { use super::size_hint; - impl Serialize for HashMap + impl Serialize for HashMap where K: Serialize + Eq + Hash, V: Serialize, H: BuildHasher, + A: Allocator, { #[cfg_attr(feature = "inline-more", inline)] fn serialize(&self, serializer: S) -> Result @@ -36,40 +38,46 @@ mod map { } } - impl<'de, K, V, S> Deserialize<'de> for HashMap + impl<'de, K, V, S, A> Deserialize<'de> for HashMap where K: Deserialize<'de> + Eq + Hash, V: Deserialize<'de>, S: BuildHasher + Default, + A: Allocator + Default, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - struct MapVisitor { - marker: PhantomData>, + struct MapVisitor + where + A: Allocator, + { + marker: PhantomData>, } - impl<'de, K, V, S> Visitor<'de> for MapVisitor + impl<'de, K, V, S, A> Visitor<'de> for MapVisitor where K: Deserialize<'de> + Eq + Hash, V: Deserialize<'de>, S: BuildHasher + Default, + A: Allocator + Default, { - type Value = HashMap; + type Value = HashMap; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a map") } #[cfg_attr(feature = "inline-more", inline)] - fn visit_map(self, mut map: A) -> Result + fn visit_map(self, mut map: M) -> Result where - A: MapAccess<'de>, + M: MapAccess<'de>, { - let mut values = HashMap::with_capacity_and_hasher( + let mut values = HashMap::with_capacity_and_hasher_in( size_hint::cautious(map.size_hint()), S::default(), + A::default(), ); while let Some((key, value)) = map.next_entry()? { @@ -89,6 +97,7 @@ mod map { } mod set { + use crate::raw::Allocator; use core::fmt; use core::hash::{BuildHasher, Hash}; use core::marker::PhantomData; @@ -99,10 +108,11 @@ mod set { use super::size_hint; - impl Serialize for HashSet + impl Serialize for HashSet where T: Serialize + Eq + Hash, H: BuildHasher, + A: Allocator, { #[cfg_attr(feature = "inline-more", inline)] fn serialize(&self, serializer: S) -> Result @@ -113,38 +123,44 @@ mod set { } } - impl<'de, T, S> Deserialize<'de> for HashSet + impl<'de, T, S, A> Deserialize<'de> for HashSet where T: Deserialize<'de> + Eq + Hash, S: BuildHasher + Default, + A: Allocator + Default, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - struct SeqVisitor { - marker: PhantomData>, + struct SeqVisitor + where + A: Allocator, + { + marker: PhantomData>, } - impl<'de, T, S> Visitor<'de> for SeqVisitor + impl<'de, T, S, A> Visitor<'de> for SeqVisitor where T: Deserialize<'de> + Eq + Hash, S: BuildHasher + Default, + A: Allocator + Default, { - type Value = HashSet; + type Value = HashSet; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a sequence") } #[cfg_attr(feature = "inline-more", inline)] - fn visit_seq(self, mut seq: A) -> Result + fn visit_seq(self, mut seq: M) -> Result where - A: SeqAccess<'de>, + M: SeqAccess<'de>, { - let mut values = HashSet::with_capacity_and_hasher( + let mut values = HashSet::with_capacity_and_hasher_in( size_hint::cautious(seq.size_hint()), S::default(), + A::default(), ); while let Some(value) = seq.next_element()? { @@ -166,12 +182,15 @@ mod set { where D: Deserializer<'de>, { - struct SeqInPlaceVisitor<'a, T, S>(&'a mut HashSet); + struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet) + where + A: Allocator; - impl<'a, 'de, T, S> Visitor<'de> for SeqInPlaceVisitor<'a, T, S> + impl<'a, 'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'a, T, S, A> where T: Deserialize<'de> + Eq + Hash, S: BuildHasher + Default, + A: Allocator, { type Value = (); @@ -180,9 +199,9 @@ mod set { } #[cfg_attr(feature = "inline-more", inline)] - fn visit_seq(self, mut seq: A) -> Result + fn visit_seq(self, mut seq: M) -> Result where - A: SeqAccess<'de>, + M: SeqAccess<'de>, { self.0.clear(); self.0.reserve(size_hint::cautious(seq.size_hint())); diff --git a/third_party/rust/hashbrown/src/lib.rs b/third_party/rust/hashbrown/src/lib.rs index bc1c971303..f03ddb6ad9 100644 --- a/third_party/rust/hashbrown/src/lib.rs +++ b/third_party/rust/hashbrown/src/lib.rs @@ -20,9 +20,8 @@ extend_one, allocator_api, slice_ptr_get, - nonnull_slice_from_raw_parts, maybe_uninit_array_assume_init, - build_hasher_simple_hash_one + strict_provenance ) )] #![allow( @@ -37,6 +36,8 @@ )] #![warn(missing_docs)] #![warn(rust_2018_idioms)] +#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))] +#![cfg_attr(feature = "nightly", allow(internal_features))] #[cfg(test)] #[macro_use] @@ -81,6 +82,7 @@ mod map; mod rustc_entry; mod scopeguard; mod set; +mod table; pub mod hash_map { //! A hash map implemented with quadratic probing and SIMD lookup. @@ -113,9 +115,63 @@ pub mod hash_set { pub use crate::external_trait_impls::rayon::set::*; } } +pub mod hash_table { + //! A hash table implemented with quadratic probing and SIMD lookup. + pub use crate::table::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash tables. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::table::*; + } +} pub use crate::map::HashMap; pub use crate::set::HashSet; +pub use crate::table::HashTable; + +#[cfg(feature = "equivalent")] +pub use equivalent::Equivalent; + +// This is only used as a fallback when building as part of `std`. +#[cfg(not(feature = "equivalent"))] +/// Key equivalence trait. +/// +/// This trait defines the function used to compare the input value with the +/// map keys (or set values) during a lookup operation such as [`HashMap::get`] +/// or [`HashSet::contains`]. +/// It is provided with a blanket implementation based on the +/// [`Borrow`](core::borrow::Borrow) trait. +/// +/// # Correctness +/// +/// Equivalent values must hash to the same value. +pub trait Equivalent { + /// Checks if this value is equivalent to the given key. + /// + /// Returns `true` if both values are equivalent, and `false` otherwise. + /// + /// # Correctness + /// + /// When this function returns `true`, both `self` and `key` must hash to + /// the same value. + fn equivalent(&self, key: &K) -> bool; +} + +#[cfg(not(feature = "equivalent"))] +impl Equivalent for Q +where + Q: Eq, + K: core::borrow::Borrow, +{ + fn equivalent(&self, key: &K) -> bool { + self == key.borrow() + } +} /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] @@ -130,21 +186,3 @@ pub enum TryReserveError { layout: alloc::alloc::Layout, }, } - -/// Wrapper around `Bump` which allows it to be used as an allocator for -/// `HashMap`, `HashSet` and `RawTable`. -/// -/// `Bump` can be used directly without this wrapper on nightly if you enable -/// the `allocator-api` feature of the `bumpalo` crate. -#[cfg(feature = "bumpalo")] -#[derive(Clone, Copy, Debug)] -pub struct BumpWrapper<'a>(pub &'a bumpalo::Bump); - -#[cfg(feature = "bumpalo")] -#[test] -fn test_bumpalo() { - use bumpalo::Bump; - let bump = Bump::new(); - let mut map = HashMap::new_in(BumpWrapper(&bump)); - map.insert(0, 1); -} diff --git a/third_party/rust/hashbrown/src/macros.rs b/third_party/rust/hashbrown/src/macros.rs index f8ef917b14..eaba6bed1f 100644 --- a/third_party/rust/hashbrown/src/macros.rs +++ b/third_party/rust/hashbrown/src/macros.rs @@ -37,7 +37,7 @@ macro_rules! cfg_if { // semicolon is all the remaining items (@__items ($($not:meta,)*) ; ) => {}; (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { - // Emit all items within one block, applying an approprate #[cfg]. The + // Emit all items within one block, applying an appropriate #[cfg]. The // #[cfg] will require all `$m` matchers specified and must also negate // all previous matchers. cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } diff --git a/third_party/rust/hashbrown/src/map.rs b/third_party/rust/hashbrown/src/map.rs index a5d3ccb97e..88a826582b 100644 --- a/third_party/rust/hashbrown/src/map.rs +++ b/third_party/rust/hashbrown/src/map.rs @@ -1,16 +1,18 @@ -use crate::raw::{Allocator, Bucket, Global, RawDrain, RawIntoIter, RawIter, RawTable}; -use crate::TryReserveError; +use crate::raw::{ + Allocator, Bucket, Global, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawTable, +}; +use crate::{Equivalent, TryReserveError}; use core::borrow::Borrow; use core::fmt::{self, Debug}; use core::hash::{BuildHasher, Hash}; -use core::iter::{FromIterator, FusedIterator}; +use core::iter::FusedIterator; use core::marker::PhantomData; use core::mem; use core::ops::Index; /// Default hasher for `HashMap`. #[cfg(feature = "ahash")] -pub type DefaultHashBuilder = ahash::RandomState; +pub type DefaultHashBuilder = core::hash::BuildHasherDefault; /// Dummy default hasher for `HashMap`. #[cfg(not(feature = "ahash"))] @@ -182,10 +184,10 @@ pub enum DefaultHashBuilder {} /// use hashbrown::HashMap; /// /// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] -/// .iter().cloned().collect(); +/// .into_iter().collect(); /// // use the values stored in map /// ``` -pub struct HashMap { +pub struct HashMap { pub(crate) hash_builder: S, pub(crate) table: RawTable<(K, V), A>, } @@ -209,13 +211,12 @@ impl Clone for HashMap(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ +pub(crate) fn make_hasher(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ where - K: Borrow, Q: Hash, S: BuildHasher, { - move |val| make_hash::(hash_builder, &val.0) + move |val| make_hash::(hash_builder, &val.0) } /// Ensures that a single closure type across uses of this which, in turn prevents multiple @@ -223,10 +224,9 @@ where #[cfg_attr(feature = "inline-more", inline)] fn equivalent_key(k: &Q) -> impl Fn(&(K, V)) -> bool + '_ where - K: Borrow, - Q: ?Sized + Eq, + Q: ?Sized + Equivalent, { - move |x| k.eq(x.0.borrow()) + move |x| k.equivalent(&x.0) } /// Ensures that a single closure type across uses of this which, in turn prevents multiple @@ -234,17 +234,15 @@ where #[cfg_attr(feature = "inline-more", inline)] fn equivalent(k: &Q) -> impl Fn(&K) -> bool + '_ where - K: Borrow, - Q: ?Sized + Eq, + Q: ?Sized + Equivalent, { - move |x| k.eq(x.borrow()) + move |x| k.equivalent(x) } #[cfg(not(feature = "nightly"))] #[cfg_attr(feature = "inline-more", inline)] -pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 where - K: Borrow, Q: Hash + ?Sized, S: BuildHasher, { @@ -256,38 +254,14 @@ where #[cfg(feature = "nightly")] #[cfg_attr(feature = "inline-more", inline)] -pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 where - K: Borrow, Q: Hash + ?Sized, S: BuildHasher, { hash_builder.hash_one(val) } -#[cfg(not(feature = "nightly"))] -#[cfg_attr(feature = "inline-more", inline)] -pub(crate) fn make_insert_hash(hash_builder: &S, val: &K) -> u64 -where - K: Hash, - S: BuildHasher, -{ - use core::hash::Hasher; - let mut state = hash_builder.build_hasher(); - val.hash(&mut state); - state.finish() -} - -#[cfg(feature = "nightly")] -#[cfg_attr(feature = "inline-more", inline)] -pub(crate) fn make_insert_hash(hash_builder: &S, val: &K) -> u64 -where - K: Hash, - S: BuildHasher, -{ - hash_builder.hash_one(val) -} - #[cfg(feature = "ahash")] impl HashMap { /// Creates an empty `HashMap`. @@ -295,6 +269,18 @@ impl HashMap { /// The hash map is initially created with a capacity of 0, so it will not allocate until it /// is first inserted into. /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher`](HashMap::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// /// # Examples /// /// ``` @@ -313,6 +299,18 @@ impl HashMap { /// The hash map will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash map will not allocate. /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher`](HashMap::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// /// # Examples /// /// ``` @@ -328,11 +326,46 @@ impl HashMap { } #[cfg(feature = "ahash")] -impl HashMap { +impl HashMap { /// Creates an empty `HashMap` using the given allocator. /// /// The hash map is initially created with a capacity of 0, so it will not allocate until it /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher_in`](HashMap::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::new_in(&bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// + /// // The created HashMap also doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// // Now we insert element inside created HashMap + /// map.insert("One", 1); + /// // We can see that the HashMap holds 1 element + /// assert_eq!(map.len(), 1); + /// // And it also allocates some capacity + /// assert!(map.capacity() > 1); + /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn new_in(alloc: A) -> Self { Self::with_hasher_in(DefaultHashBuilder::default(), alloc) @@ -342,6 +375,46 @@ impl HashMap { /// /// The hash map will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher_in`](HashMap::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::with_capacity_in(5, &bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = map.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashMap + /// map.insert("One", 1); + /// map.insert("Two", 2); + /// map.insert("Three", 3); + /// map.insert("Four", 4); + /// map.insert("Five", 5); + /// + /// // We can see that the HashMap holds 5 elements + /// assert_eq!(map.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(map.capacity(), empty_map_capacity) + /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Self::with_capacity_and_hasher_in(capacity, DefaultHashBuilder::default(), alloc) @@ -355,14 +428,21 @@ impl HashMap { /// The hash map is initially created with a capacity of 0, so it will not /// allocate until it is first inserted into. /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. /// /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the HashMap to be useful, see its documentation for details. /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// /// # Examples /// /// ``` @@ -376,8 +456,6 @@ impl HashMap { /// /// map.insert(1, 2); /// ``` - /// - /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html #[cfg_attr(feature = "inline-more", inline)] pub const fn with_hasher(hash_builder: S) -> Self { Self { @@ -392,14 +470,21 @@ impl HashMap { /// The hash map will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash map will not allocate. /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. /// /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the HashMap to be useful, see its documentation for details. /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// /// # Examples /// /// ``` @@ -413,8 +498,6 @@ impl HashMap { /// /// map.insert(1, 2); /// ``` - /// - /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html #[cfg_attr(feature = "inline-more", inline)] pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { Self { @@ -424,7 +507,7 @@ impl HashMap { } } -impl HashMap { +impl HashMap { /// Returns a reference to the underlying allocator. #[inline] pub fn allocator(&self) -> &A { @@ -434,12 +517,19 @@ impl HashMap { /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. It will be allocated with the given allocator. /// - /// The created map has the default initial capacity. + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html /// /// # Examples /// @@ -452,7 +542,7 @@ impl HashMap { /// map.insert(1, 2); /// ``` #[cfg_attr(feature = "inline-more", inline)] - pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + pub const fn with_hasher_in(hash_builder: S, alloc: A) -> Self { Self { hash_builder, table: RawTable::new_in(alloc), @@ -465,10 +555,16 @@ impl HashMap { /// The hash map will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash map will not allocate. /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html /// /// # Examples /// @@ -810,14 +906,11 @@ impl HashMap { /// /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); /// assert_eq!(map.len(), 8); - /// let capacity_before_retain = map.capacity(); /// /// map.retain(|&k, _| k % 2 == 0); /// /// // We can see, that the number of elements inside map is changed. /// assert_eq!(map.len(), 4); - /// // But map capacity is equal to old one. - /// assert_eq!(map.capacity(), capacity_before_retain); /// /// let mut vec: Vec<(i32, i32)> = map.iter().map(|(&k, &v)| (k, v)).collect(); /// vec.sort_unstable(); @@ -844,26 +937,25 @@ impl HashMap { /// In other words, move all pairs `(k, v)` such that `f(&k, &mut v)` returns `true` out /// into another iterator. /// - /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of /// whether you choose to keep or remove it. /// - /// When the returned DrainedFilter is dropped, any remaining elements that satisfy - /// the predicate are dropped from the table. - /// - /// It is unspecified how many more elements will be subjected to the closure - /// if a panic occurs in the closure, or a panic occurs while dropping an element, - /// or if the `DrainFilter` value is leaked. + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. /// /// Keeps the allocated memory for reuse. /// + /// [`retain()`]: HashMap::retain + /// /// # Examples /// /// ``` /// use hashbrown::HashMap; /// /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); - /// let capacity_before_drain_filter = map.capacity(); - /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// + /// let drained: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); /// /// let mut evens = drained.keys().cloned().collect::>(); /// let mut odds = map.keys().cloned().collect::>(); @@ -872,27 +964,24 @@ impl HashMap { /// /// assert_eq!(evens, vec![0, 2, 4, 6]); /// assert_eq!(odds, vec![1, 3, 5, 7]); - /// // Map capacity is equal to old one. - /// assert_eq!(map.capacity(), capacity_before_drain_filter); /// /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); /// /// { // Iterator is dropped without being consumed. - /// let d = map.drain_filter(|k, _v| k % 2 != 0); + /// let d = map.extract_if(|k, _v| k % 2 != 0); /// } /// - /// // But the map lens have been reduced by half - /// // even if we do not use DrainFilter iterator. - /// assert_eq!(map.len(), 4); + /// // ExtractIf was not exhausted, therefore no elements were drained. + /// assert_eq!(map.len(), 8); /// ``` #[cfg_attr(feature = "inline-more", inline)] - pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, K, V, F, A> + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, K, V, F, A> where F: FnMut(&K, &mut V) -> bool, { - DrainFilter { + ExtractIf { f, - inner: DrainFilterInner { + inner: RawExtractIf { iter: unsafe { self.table.iter() }, table: &mut self.table, }, @@ -984,7 +1073,7 @@ impl HashMap where K: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashMap`. The collection may reserve more space to avoid @@ -992,9 +1081,12 @@ where /// /// # Panics /// - /// Panics if the new allocation size overflows [`usize`]. + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashMap::try_reserve) instead + /// if you want to handle memory allocation failure. /// - /// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html /// /// # Examples /// @@ -1012,7 +1104,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn reserve(&mut self, additional: usize) { self.table - .reserve(additional, make_hasher::(&self.hash_builder)); + .reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)); } /// Tries to reserve capacity for at least `additional` more elements to be inserted @@ -1062,7 +1154,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.table - .try_reserve(additional, make_hasher::(&self.hash_builder)) + .try_reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)) } /// Shrinks the capacity of the map as much as possible. It will drop @@ -1084,7 +1176,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn shrink_to_fit(&mut self) { self.table - .shrink_to(0, make_hasher::(&self.hash_builder)); + .shrink_to(0, make_hasher::<_, V, S>(&self.hash_builder)); } /// Shrinks the capacity of the map with a lower limit. It will drop @@ -1113,7 +1205,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn shrink_to(&mut self, min_capacity: usize) { self.table - .shrink_to(min_capacity, make_hasher::(&self.hash_builder)); + .shrink_to(min_capacity, make_hasher::<_, V, S>(&self.hash_builder)); } /// Gets the given key's corresponding entry in the map for in-place manipulation. @@ -1137,7 +1229,7 @@ where /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> { - let hash = make_insert_hash::(&self.hash_builder, &key); + let hash = make_hash::(&self.hash_builder, &key); if let Some(elem) = self.table.find(hash, equivalent_key(&key)) { Entry::Occupied(OccupiedEntry { hash, @@ -1174,10 +1266,9 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn entry_ref<'a, 'b, Q: ?Sized>(&'a mut self, key: &'b Q) -> EntryRef<'a, 'b, K, Q, V, S, A> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { - let hash = make_hash::(&self.hash_builder, key); + let hash = make_hash::(&self.hash_builder, key); if let Some(elem) = self.table.find(hash, equivalent_key(key)) { EntryRef::Occupied(OccupiedEntryRef { hash, @@ -1216,12 +1307,11 @@ where #[inline] pub fn get(&self, k: &Q) -> Option<&V> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { // Avoid `Option::map` because it bloats LLVM IR. match self.get_inner(k) { - Some(&(_, ref v)) => Some(v), + Some((_, v)) => Some(v), None => None, } } @@ -1248,12 +1338,11 @@ where #[inline] pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { // Avoid `Option::map` because it bloats LLVM IR. match self.get_inner(k) { - Some(&(ref key, ref value)) => Some((key, value)), + Some((key, value)) => Some((key, value)), None => None, } } @@ -1261,13 +1350,12 @@ where #[inline] fn get_inner(&self, k: &Q) -> Option<&(K, V)> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { if self.table.is_empty() { None } else { - let hash = make_hash::(&self.hash_builder, k); + let hash = make_hash::(&self.hash_builder, k); self.table.get(hash, equivalent_key(k)) } } @@ -1298,8 +1386,7 @@ where #[inline] pub fn get_key_value_mut(&mut self, k: &Q) -> Option<(&K, &mut V)> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { // Avoid `Option::map` because it bloats LLVM IR. match self.get_inner_mut(k) { @@ -1330,8 +1417,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn contains_key(&self, k: &Q) -> bool where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { self.get_inner(k).is_some() } @@ -1362,8 +1448,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { // Avoid `Option::map` because it bloats LLVM IR. match self.get_inner_mut(k) { @@ -1375,13 +1460,12 @@ where #[inline] fn get_inner_mut(&mut self, k: &Q) -> Option<&mut (K, V)> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { if self.table.is_empty() { None } else { - let hash = make_hash::(&self.hash_builder, k); + let hash = make_hash::(&self.hash_builder, k); self.table.get_mut(hash, equivalent_key(k)) } } @@ -1431,8 +1515,7 @@ where /// ``` pub fn get_many_mut(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { self.get_many_mut_inner(ks).map(|res| res.map(|(_, v)| v)) } @@ -1487,8 +1570,7 @@ where ks: [&Q; N], ) -> Option<[&'_ mut V; N]> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { self.get_many_unchecked_mut_inner(ks) .map(|res| res.map(|(_, v)| v)) @@ -1543,8 +1625,7 @@ where ks: [&Q; N], ) -> Option<[(&'_ K, &'_ mut V); N]> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { self.get_many_mut_inner(ks) .map(|res| res.map(|(k, v)| (&*k, v))) @@ -1599,8 +1680,7 @@ where ks: [&Q; N], ) -> Option<[(&'_ K, &'_ mut V); N]> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { self.get_many_unchecked_mut_inner(ks) .map(|res| res.map(|(k, v)| (&*k, v))) @@ -1611,12 +1691,11 @@ where ks: [&Q; N], ) -> Option<[&'_ mut (K, V); N]> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { let hashes = self.build_hashes_inner(ks); self.table - .get_many_mut(hashes, |i, (k, _)| ks[i].eq(k.borrow())) + .get_many_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) } unsafe fn get_many_unchecked_mut_inner( @@ -1624,22 +1703,20 @@ where ks: [&Q; N], ) -> Option<[&'_ mut (K, V); N]> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { let hashes = self.build_hashes_inner(ks); self.table - .get_many_unchecked_mut(hashes, |i, (k, _)| ks[i].eq(k.borrow())) + .get_many_unchecked_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) } fn build_hashes_inner(&self, ks: [&Q; N]) -> [u64; N] where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { let mut hashes = [0_u64; N]; for i in 0..N { - hashes[i] = make_hash::(&self.hash_builder, ks[i]); + hashes[i] = make_hash::(&self.hash_builder, ks[i]); } hashes } @@ -1672,13 +1749,19 @@ where /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn insert(&mut self, k: K, v: V) -> Option { - let hash = make_insert_hash::(&self.hash_builder, &k); - if let Some((_, item)) = self.table.get_mut(hash, equivalent_key(&k)) { - Some(mem::replace(item, v)) - } else { - self.table - .insert(hash, (k, v), make_hasher::(&self.hash_builder)); - None + let hash = make_hash::(&self.hash_builder, &k); + let hasher = make_hasher::<_, V, S>(&self.hash_builder); + match self + .table + .find_or_find_insert_slot(hash, equivalent_key(&k), hasher) + { + Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)), + Err(slot) => { + unsafe { + self.table.insert_in_slot(hash, slot, (k, v)); + } + None + } } } @@ -1733,10 +1816,10 @@ where /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) { - let hash = make_insert_hash::(&self.hash_builder, &k); + let hash = make_hash::(&self.hash_builder, &k); let bucket = self .table - .insert(hash, (k, v), make_hasher::(&self.hash_builder)); + .insert(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder)); let (k_ref, v_ref) = unsafe { bucket.as_mut() }; (k_ref, v_ref) } @@ -1801,19 +1884,17 @@ where /// assert!(map.is_empty() && map.capacity() == 0); /// /// map.insert(1, "a"); - /// let capacity_before_remove = map.capacity(); /// /// assert_eq!(map.remove(&1), Some("a")); /// assert_eq!(map.remove(&1), None); /// - /// // Now map holds none elements but capacity is equal to the old one - /// assert!(map.len() == 0 && map.capacity() == capacity_before_remove); + /// // Now map holds none elements + /// assert!(map.is_empty()); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove(&mut self, k: &Q) -> Option where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { // Avoid `Option::map` because it bloats LLVM IR. match self.remove_entry(k) { @@ -1842,26 +1923,24 @@ where /// assert!(map.is_empty() && map.capacity() == 0); /// /// map.insert(1, "a"); - /// let capacity_before_remove = map.capacity(); /// /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); /// assert_eq!(map.remove(&1), None); /// - /// // Now map hold none elements but capacity is equal to the old one - /// assert!(map.len() == 0 && map.capacity() == capacity_before_remove); + /// // Now map hold none elements + /// assert!(map.is_empty()); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> where - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { - let hash = make_hash::(&self.hash_builder, k); + let hash = make_hash::(&self.hash_builder, k); self.table.remove_entry(hash, equivalent_key(k)) } } -impl HashMap { +impl HashMap { /// Creates a raw entry builder for the HashMap. /// /// Raw entries provide the lowest level of control for searching and @@ -2013,19 +2092,31 @@ impl HashMap { RawEntryBuilder { map: self } } + /// Returns a reference to the [`RawTable`] used underneath [`HashMap`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// See [`raw_table_mut`] for more. + /// + /// [`raw_table_mut`]: Self::raw_table_mut + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table(&self) -> &RawTable<(K, V), A> { + &self.table + } + /// Returns a mutable reference to the [`RawTable`] used underneath [`HashMap`]. /// This function is only available if the `raw` feature of the crate is enabled. /// /// # Note /// - /// Calling the function safe, but using raw hash table API's may require + /// Calling this function is safe, but using the raw hash table API may require /// unsafe functions or blocks. /// /// `RawTable` API gives the lowest level of control under the map that can be useful /// for extending the HashMap's API, but may lead to *[undefined behavior]*. /// /// [`HashMap`]: struct.HashMap.html - /// [`RawTable`]: raw/struct.RawTable.html + /// [`RawTable`]: crate::raw::RawTable /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples @@ -2049,9 +2140,9 @@ impl HashMap { /// where /// F: Fn(&(K, V)) -> bool, /// { - /// let raw_table = map.raw_table(); + /// let raw_table = map.raw_table_mut(); /// match raw_table.find(hash, is_match) { - /// Some(bucket) => Some(unsafe { raw_table.remove(bucket) }), + /// Some(bucket) => Some(unsafe { raw_table.remove(bucket).0 }), /// None => None, /// } /// } @@ -2070,7 +2161,7 @@ impl HashMap { /// ``` #[cfg(feature = "raw")] #[cfg_attr(feature = "inline-more", inline)] - pub fn raw_table(&mut self) -> &mut RawTable<(K, V), A> { + pub fn raw_table_mut(&mut self) -> &mut RawTable<(K, V), A> { &mut self.table } } @@ -2080,7 +2171,7 @@ where K: Eq + Hash, V: PartialEq, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn eq(&self, other: &Self) -> bool { if self.len() != other.len() { @@ -2097,7 +2188,7 @@ where K: Eq + Hash, V: Eq, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { } @@ -2105,7 +2196,7 @@ impl Debug for HashMap where K: Debug, V: Debug, - A: Allocator + Clone, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() @@ -2115,7 +2206,7 @@ where impl Default for HashMap where S: Default, - A: Default + Allocator + Clone, + A: Default + Allocator, { /// Creates an empty `HashMap`, with the `Default` value for the hasher and allocator. /// @@ -2140,10 +2231,10 @@ where impl Index<&Q> for HashMap where - K: Eq + Hash + Borrow, - Q: Eq + Hash, + K: Eq + Hash, + Q: Hash + Equivalent, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { type Output = V; @@ -2174,7 +2265,7 @@ where impl From<[(K, V); N]> for HashMap where K: Eq + Hash, - A: Default + Allocator + Clone, + A: Default + Allocator, { /// # Examples /// @@ -2319,11 +2410,11 @@ impl IterMut<'_, K, V> { /// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None); /// ``` -pub struct IntoIter { +pub struct IntoIter { inner: RawIntoIter<(K, V), A>, } -impl IntoIter { +impl IntoIter { /// Returns a iterator of references over the remaining items. #[cfg_attr(feature = "inline-more", inline)] pub(super) fn iter(&self) -> Iter<'_, K, V> { @@ -2363,11 +2454,11 @@ impl IntoIter { /// assert_eq!(keys.next(), None); /// assert_eq!(keys.next(), None); /// ``` -pub struct IntoKeys { +pub struct IntoKeys { inner: IntoIter, } -impl Iterator for IntoKeys { +impl Iterator for IntoKeys { type Item = K; #[inline] @@ -2378,18 +2469,26 @@ impl Iterator for IntoKeys { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } } -impl ExactSizeIterator for IntoKeys { +impl ExactSizeIterator for IntoKeys { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl FusedIterator for IntoKeys {} +impl FusedIterator for IntoKeys {} -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() .entries(self.inner.iter().map(|(k, _)| k)) @@ -2425,11 +2524,11 @@ impl fmt::Debug for IntoKeys /// assert_eq!(values.next(), None); /// assert_eq!(values.next(), None); /// ``` -pub struct IntoValues { +pub struct IntoValues { inner: IntoIter, } -impl Iterator for IntoValues { +impl Iterator for IntoValues { type Item = V; #[inline] @@ -2440,18 +2539,26 @@ impl Iterator for IntoValues { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } -impl ExactSizeIterator for IntoValues { +impl ExactSizeIterator for IntoValues { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl FusedIterator for IntoValues {} +impl FusedIterator for IntoValues {} -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() .entries(self.inner.iter().map(|(_, v)| v)) @@ -2583,11 +2690,11 @@ impl fmt::Debug for Values<'_, K, V> { /// assert_eq!(drain_iter.next(), None); /// assert_eq!(drain_iter.next(), None); /// ``` -pub struct Drain<'a, K, V, A: Allocator + Clone = Global> { +pub struct Drain<'a, K, V, A: Allocator = Global> { inner: RawDrain<'a, (K, V), A>, } -impl Drain<'_, K, V, A> { +impl Drain<'_, K, V, A> { /// Returns a iterator of references over the remaining items. #[cfg_attr(feature = "inline-more", inline)] pub(super) fn iter(&self) -> Iter<'_, K, V> { @@ -2601,10 +2708,10 @@ impl Drain<'_, K, V, A> { /// A draining iterator over entries of a `HashMap` which don't satisfy the predicate /// `f(&k, &mut v)` in arbitrary order. The iterator element type is `(K, V)`. /// -/// This `struct` is created by the [`drain_filter`] method on [`HashMap`]. See its +/// This `struct` is created by the [`extract_if`] method on [`HashMap`]. See its /// documentation for more. /// -/// [`drain_filter`]: struct.HashMap.html#method.drain_filter +/// [`extract_if`]: struct.HashMap.html#method.extract_if /// [`HashMap`]: struct.HashMap.html /// /// # Examples @@ -2614,63 +2721,40 @@ impl Drain<'_, K, V, A> { /// /// let mut map: HashMap = [(1, "a"), (2, "b"), (3, "c")].into(); /// -/// let mut drain_filter = map.drain_filter(|k, _v| k % 2 != 0); -/// let mut vec = vec![drain_filter.next(), drain_filter.next()]; +/// let mut extract_if = map.extract_if(|k, _v| k % 2 != 0); +/// let mut vec = vec![extract_if.next(), extract_if.next()]; /// -/// // The `DrainFilter` iterator produces items in arbitrary order, so the +/// // The `ExtractIf` iterator produces items in arbitrary order, so the /// // items must be sorted to test them against a sorted array. /// vec.sort_unstable(); /// assert_eq!(vec, [Some((1, "a")),Some((3, "c"))]); /// /// // It is fused iterator -/// assert_eq!(drain_filter.next(), None); -/// assert_eq!(drain_filter.next(), None); -/// drop(drain_filter); +/// assert_eq!(extract_if.next(), None); +/// assert_eq!(extract_if.next(), None); +/// drop(extract_if); /// /// assert_eq!(map.len(), 1); /// ``` -pub struct DrainFilter<'a, K, V, F, A: Allocator + Clone = Global> +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, V, F, A: Allocator = Global> where F: FnMut(&K, &mut V) -> bool, { f: F, - inner: DrainFilterInner<'a, K, V, A>, -} - -impl<'a, K, V, F, A> Drop for DrainFilter<'a, K, V, F, A> -where - F: FnMut(&K, &mut V) -> bool, - A: Allocator + Clone, -{ - #[cfg_attr(feature = "inline-more", inline)] - fn drop(&mut self) { - while let Some(item) = self.next() { - let guard = ConsumeAllOnDrop(self); - drop(item); - mem::forget(guard); - } - } -} - -pub(super) struct ConsumeAllOnDrop<'a, T: Iterator>(pub &'a mut T); - -impl Drop for ConsumeAllOnDrop<'_, T> { - #[cfg_attr(feature = "inline-more", inline)] - fn drop(&mut self) { - self.0.for_each(drop); - } + inner: RawExtractIf<'a, (K, V), A>, } -impl Iterator for DrainFilter<'_, K, V, F, A> +impl Iterator for ExtractIf<'_, K, V, F, A> where F: FnMut(&K, &mut V) -> bool, - A: Allocator + Clone, + A: Allocator, { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] fn next(&mut self) -> Option { - self.inner.next(&mut self.f) + self.inner.next(|&mut (ref k, ref mut v)| (self.f)(k, v)) } #[inline] @@ -2679,31 +2763,7 @@ where } } -impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} - -/// Portions of `DrainFilter` shared with `set::DrainFilter` -pub(super) struct DrainFilterInner<'a, K, V, A: Allocator + Clone> { - pub iter: RawIter<(K, V)>, - pub table: &'a mut RawTable<(K, V), A>, -} - -impl DrainFilterInner<'_, K, V, A> { - #[cfg_attr(feature = "inline-more", inline)] - pub(super) fn next(&mut self, f: &mut F) -> Option<(K, V)> - where - F: FnMut(&K, &mut V) -> bool, - { - unsafe { - for item in &mut self.iter { - let &mut (ref key, ref mut value) = item.as_mut(); - if f(key, value) { - return Some(self.table.remove(item)); - } - } - } - None - } -} +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} /// A mutable iterator over the values of a `HashMap` in arbitrary order. /// The iterator element type is `&'a mut V`. @@ -2791,7 +2851,7 @@ pub struct ValuesMut<'a, K, V> { /// /// assert_eq!(map.len(), 6); /// ``` -pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator + Clone = Global> { +pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator = Global> { map: &'a mut HashMap, } @@ -2879,7 +2939,7 @@ pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator + Clone = Global> { /// vec.sort_unstable(); /// assert_eq!(vec, [('a', 10), ('b', 20), ('c', 30), ('d', 40), ('e', 50), ('f', 60)]); /// ``` -pub enum RawEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { +pub enum RawEntryMut<'a, K, V, S, A: Allocator = Global> { /// An occupied entry. /// /// # Examples @@ -2970,7 +3030,7 @@ pub enum RawEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { /// assert_eq!(map.get(&"b"), None); /// assert_eq!(map.len(), 1); /// ``` -pub struct RawOccupiedEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { +pub struct RawOccupiedEntryMut<'a, K, V, S, A: Allocator = Global> { elem: Bucket<(K, V)>, table: &'a mut RawTable<(K, V), A>, hash_builder: &'a S, @@ -2981,7 +3041,7 @@ where K: Send, V: Send, S: Send, - A: Send + Allocator + Clone, + A: Send + Allocator, { } unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S, A> @@ -2989,7 +3049,7 @@ where K: Sync, V: Sync, S: Sync, - A: Sync + Allocator + Clone, + A: Sync + Allocator, { } @@ -3041,7 +3101,7 @@ where /// } /// assert!(map[&"c"] == 30 && map.len() == 3); /// ``` -pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { +pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator = Global> { table: &'a mut RawTable<(K, V), A>, hash_builder: &'a S, } @@ -3080,11 +3140,11 @@ pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); /// } /// ``` -pub struct RawEntryBuilder<'a, K, V, S, A: Allocator + Clone = Global> { +pub struct RawEntryBuilder<'a, K, V, S, A: Allocator = Global> { map: &'a HashMap, } -impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilderMut<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { /// Creates a `RawEntryMut` from the given key. /// /// # Examples @@ -3103,10 +3163,9 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilderMut<'a, K, V, S, A> { pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S, A> where S: BuildHasher, - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { - let hash = make_hash::(&self.map.hash_builder, k); + let hash = make_hash::(&self.map.hash_builder, k); self.from_key_hashed_nocheck(hash, k) } @@ -3136,14 +3195,13 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilderMut<'a, K, V, S, A> { #[allow(clippy::wrong_self_convention)] pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S, A> where - K: Borrow, - Q: Eq, + Q: Equivalent, { self.from_hash(hash, equivalent(k)) } } -impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilderMut<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { /// Creates a `RawEntryMut` from the given hash and matching function. /// /// # Examples @@ -3194,7 +3252,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilderMut<'a, K, V, S, A> { } } -impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilder<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> RawEntryBuilder<'a, K, V, S, A> { /// Access an immutable entry by key. /// /// # Examples @@ -3211,10 +3269,9 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilder<'a, K, V, S, A> { pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> where S: BuildHasher, - K: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { - let hash = make_hash::(&self.map.hash_builder, k); + let hash = make_hash::(&self.map.hash_builder, k); self.from_key_hashed_nocheck(hash, k) } @@ -3242,8 +3299,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilder<'a, K, V, S, A> { #[allow(clippy::wrong_self_convention)] pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> where - K: Borrow, - Q: Eq, + Q: Equivalent, { self.from_hash(hash, equivalent(k)) } @@ -3254,7 +3310,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilder<'a, K, V, S, A> { F: FnMut(&K) -> bool, { match self.map.table.get(hash, |(k, _)| is_match(k)) { - Some(&(ref key, ref value)) => Some((key, value)), + Some((key, value)) => Some((key, value)), None => None, } } @@ -3289,7 +3345,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilder<'a, K, V, S, A> { } } -impl<'a, K, V, S, A: Allocator + Clone> RawEntryMut<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> RawEntryMut<'a, K, V, S, A> { /// Sets the value of the entry, and returns a RawOccupiedEntryMut. /// /// # Examples @@ -3483,7 +3539,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawEntryMut<'a, K, V, S, A> { } } -impl<'a, K, V, S, A: Allocator + Clone> RawOccupiedEntryMut<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> RawOccupiedEntryMut<'a, K, V, S, A> { /// Gets a reference to the key in the entry. /// /// # Examples @@ -3650,7 +3706,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawOccupiedEntryMut<'a, K, V, S, A> { #[cfg_attr(feature = "inline-more", inline)] pub fn get_key_value(&self) -> (&K, &V) { unsafe { - let &(ref key, ref value) = self.elem.as_ref(); + let (key, value) = self.elem.as_ref(); (key, value) } } @@ -3822,7 +3878,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawOccupiedEntryMut<'a, K, V, S, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove_entry(self) -> (K, V) { - unsafe { self.table.remove(self.elem) } + unsafe { self.table.remove(self.elem).0 } } /// Provides shared access to the key and owned access to the value of @@ -3882,7 +3938,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawOccupiedEntryMut<'a, K, V, S, A> { } } -impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> RawVacantEntryMut<'a, K, V, S, A> { /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. /// @@ -3906,7 +3962,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> { K: Hash, S: BuildHasher, { - let hash = make_insert_hash::(self.hash_builder, &key); + let hash = make_hash::(self.hash_builder, &key); self.insert_hashed_nocheck(hash, key, value) } @@ -3950,7 +4006,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> { let &mut (ref mut k, ref mut v) = self.table.insert_entry( hash, (key, value), - make_hasher::(self.hash_builder), + make_hasher::<_, V, S>(self.hash_builder), ); (k, v) } @@ -4014,11 +4070,11 @@ impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> { K: Hash, S: BuildHasher, { - let hash = make_insert_hash::(self.hash_builder, &key); + let hash = make_hash::(self.hash_builder, &key); let elem = self.table.insert( hash, (key, value), - make_hasher::(self.hash_builder), + make_hasher::<_, V, S>(self.hash_builder), ); RawOccupiedEntryMut { elem, @@ -4028,13 +4084,13 @@ impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> { } } -impl Debug for RawEntryBuilderMut<'_, K, V, S, A> { +impl Debug for RawEntryBuilderMut<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawEntryBuilder").finish() } } -impl Debug for RawEntryMut<'_, K, V, S, A> { +impl Debug for RawEntryMut<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), @@ -4043,7 +4099,7 @@ impl Debug for RawEntryMut<'_, K, V } } -impl Debug for RawOccupiedEntryMut<'_, K, V, S, A> { +impl Debug for RawOccupiedEntryMut<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") .field("key", self.key()) @@ -4052,13 +4108,13 @@ impl Debug for RawOccupiedEntryMut< } } -impl Debug for RawVacantEntryMut<'_, K, V, S, A> { +impl Debug for RawVacantEntryMut<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawVacantEntryMut").finish() } } -impl Debug for RawEntryBuilder<'_, K, V, S, A> { +impl Debug for RawEntryBuilder<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawEntryBuilder").finish() } @@ -4109,7 +4165,7 @@ impl Debug for RawEntryBuilder<'_, K, V, S, A> { /// ``` pub enum Entry<'a, K, V, S, A = Global> where - A: Allocator + Clone, + A: Allocator, { /// An occupied entry. /// @@ -4142,7 +4198,7 @@ where Vacant(VacantEntry<'a, K, V, S, A>), } -impl Debug for Entry<'_, K, V, S, A> { +impl Debug for Entry<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -4191,7 +4247,7 @@ impl Debug for Entry<'_, K, V, S, A /// assert_eq!(map.get(&"c"), None); /// assert_eq!(map.len(), 2); /// ``` -pub struct OccupiedEntry<'a, K, V, S, A: Allocator + Clone = Global> { +pub struct OccupiedEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { hash: u64, key: Option, elem: Bucket<(K, V)>, @@ -4203,7 +4259,7 @@ where K: Send, V: Send, S: Send, - A: Send + Allocator + Clone, + A: Send + Allocator, { } unsafe impl Sync for OccupiedEntry<'_, K, V, S, A> @@ -4211,11 +4267,11 @@ where K: Sync, V: Sync, S: Sync, - A: Sync + Allocator + Clone, + A: Sync + Allocator, { } -impl Debug for OccupiedEntry<'_, K, V, S, A> { +impl Debug for OccupiedEntry<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) @@ -4254,13 +4310,13 @@ impl Debug for OccupiedEntry<'_, K, /// } /// assert!(map[&"b"] == 20 && map.len() == 2); /// ``` -pub struct VacantEntry<'a, K, V, S, A: Allocator + Clone = Global> { +pub struct VacantEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { hash: u64, key: K, table: &'a mut HashMap, } -impl Debug for VacantEntry<'_, K, V, S, A> { +impl Debug for VacantEntry<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } @@ -4320,7 +4376,7 @@ impl Debug for VacantEntry<'_, K, V, S, A> /// ``` pub enum EntryRef<'a, 'b, K, Q: ?Sized, V, S, A = Global> where - A: Allocator + Clone, + A: Allocator, { /// An occupied entry. /// @@ -4353,7 +4409,7 @@ where Vacant(VacantEntryRef<'a, 'b, K, Q, V, S, A>), } -impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator + Clone> Debug +impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator> Debug for EntryRef<'_, '_, K, Q, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -4431,7 +4487,7 @@ impl<'a, K: Borrow, Q: ?Sized> AsRef for KeyOrRef<'a, K, Q> { /// assert_eq!(map.get("c"), None); /// assert_eq!(map.len(), 2); /// ``` -pub struct OccupiedEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone = Global> { +pub struct OccupiedEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator = Global> { hash: u64, key: Option>, elem: Bucket<(K, V)>, @@ -4444,7 +4500,7 @@ where Q: Sync + ?Sized, V: Send, S: Send, - A: Send + Allocator + Clone, + A: Send + Allocator, { } unsafe impl<'a, 'b, K, Q, V, S, A> Sync for OccupiedEntryRef<'a, 'b, K, Q, V, S, A> @@ -4453,16 +4509,16 @@ where Q: Sync + ?Sized, V: Sync, S: Sync, - A: Sync + Allocator + Clone, + A: Sync + Allocator, { } -impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator + Clone> Debug +impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator> Debug for OccupiedEntryRef<'_, '_, K, Q, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntryRef") - .field("key", &self.key()) + .field("key", &self.key().borrow()) .field("value", &self.get()) .finish() } @@ -4498,13 +4554,13 @@ impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator + Clone> Debug /// } /// assert!(map["b"] == 20 && map.len() == 2); /// ``` -pub struct VacantEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone = Global> { +pub struct VacantEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator = Global> { hash: u64, key: KeyOrRef<'b, K, Q>, table: &'a mut HashMap, } -impl, Q: ?Sized + Debug, V, S, A: Allocator + Clone> Debug +impl, Q: ?Sized + Debug, V, S, A: Allocator> Debug for VacantEntryRef<'_, '_, K, Q, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -4536,14 +4592,14 @@ impl, Q: ?Sized + Debug, V, S, A: Allocator + Clone> Debug /// } /// assert_eq!(map[&"a"], 100); /// ``` -pub struct OccupiedError<'a, K, V, S, A: Allocator + Clone = Global> { +pub struct OccupiedError<'a, K, V, S, A: Allocator = Global> { /// The entry in the map that was already occupied. pub entry: OccupiedEntry<'a, K, V, S, A>, /// The value which was not inserted, because the entry was already occupied. pub value: V, } -impl Debug for OccupiedError<'_, K, V, S, A> { +impl Debug for OccupiedError<'_, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedError") .field("key", self.entry.key()) @@ -4553,9 +4609,7 @@ impl Debug for OccupiedError<'_, K, } } -impl<'a, K: Debug, V: Debug, S, A: Allocator + Clone> fmt::Display - for OccupiedError<'a, K, V, S, A> -{ +impl<'a, K: Debug, V: Debug, S, A: Allocator> fmt::Display for OccupiedError<'a, K, V, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -4567,7 +4621,7 @@ impl<'a, K: Debug, V: Debug, S, A: Allocator + Clone> fmt::Display } } -impl<'a, K, V, S, A: Allocator + Clone> IntoIterator for &'a HashMap { +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -4599,7 +4653,7 @@ impl<'a, K, V, S, A: Allocator + Clone> IntoIterator for &'a HashMap } } -impl<'a, K, V, S, A: Allocator + Clone> IntoIterator for &'a mut HashMap { +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -4636,7 +4690,7 @@ impl<'a, K, V, S, A: Allocator + Clone> IntoIterator for &'a mut HashMap IntoIterator for HashMap { +impl IntoIterator for HashMap { type Item = (K, V); type IntoIter = IntoIter; @@ -4684,6 +4738,17 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_ref(); + f(acc, (k, v)) + }) + } } impl ExactSizeIterator for Iter<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] @@ -4712,6 +4777,17 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_mut(); + f(acc, (k, v)) + }) + } } impl ExactSizeIterator for IterMut<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] @@ -4731,7 +4807,7 @@ where } } -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] @@ -4742,16 +4818,24 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { #[cfg_attr(feature = "inline-more", inline)] fn len(&self) -> usize { self.inner.len() } } -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } @@ -4772,6 +4856,14 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } } impl ExactSizeIterator for Keys<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] @@ -4796,6 +4888,14 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } impl ExactSizeIterator for Values<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] @@ -4820,6 +4920,14 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } impl ExactSizeIterator for ValuesMut<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] @@ -4837,7 +4945,7 @@ impl fmt::Debug for ValuesMut<'_, K, V> { } } -impl<'a, K, V, A: Allocator + Clone> Iterator for Drain<'a, K, V, A> { +impl<'a, K, V, A: Allocator> Iterator for Drain<'a, K, V, A> { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] @@ -4848,27 +4956,35 @@ impl<'a, K, V, A: Allocator + Clone> Iterator for Drain<'a, K, V, A> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } -impl ExactSizeIterator for Drain<'_, K, V, A> { +impl ExactSizeIterator for Drain<'_, K, V, A> { #[cfg_attr(feature = "inline-more", inline)] fn len(&self) -> usize { self.inner.len() } } -impl FusedIterator for Drain<'_, K, V, A> {} +impl FusedIterator for Drain<'_, K, V, A> {} impl fmt::Debug for Drain<'_, K, V, A> where K: fmt::Debug, V: fmt::Debug, - A: Allocator + Clone, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } -impl<'a, K, V, S, A: Allocator + Clone> Entry<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> Entry<'a, K, V, S, A> { /// Sets the value of the entry, and returns an OccupiedEntry. /// /// # Examples @@ -5115,7 +5231,7 @@ impl<'a, K, V, S, A: Allocator + Clone> Entry<'a, K, V, S, A> { } } -impl<'a, K, V: Default, S, A: Allocator + Clone> Entry<'a, K, V, S, A> { +impl<'a, K, V: Default, S, A: Allocator> Entry<'a, K, V, S, A> { /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// @@ -5148,7 +5264,7 @@ impl<'a, K, V: Default, S, A: Allocator + Clone> Entry<'a, K, V, S, A> { } } -impl<'a, K, V, S, A: Allocator + Clone> OccupiedEntry<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { /// Gets a reference to the key in the entry. /// /// # Examples @@ -5183,7 +5299,6 @@ impl<'a, K, V, S, A: Allocator + Clone> OccupiedEntry<'a, K, V, S, A> { /// assert!(map.is_empty() && map.capacity() == 0); /// /// map.entry("poneyland").or_insert(12); - /// let capacity_before_remove = map.capacity(); /// /// if let Entry::Occupied(o) = map.entry("poneyland") { /// // We delete the entry from the map. @@ -5191,12 +5306,12 @@ impl<'a, K, V, S, A: Allocator + Clone> OccupiedEntry<'a, K, V, S, A> { /// } /// /// assert_eq!(map.contains_key("poneyland"), false); - /// // Now map hold none elements but capacity is equal to the old one - /// assert!(map.len() == 0 && map.capacity() == capacity_before_remove); + /// // Now map hold none elements + /// assert!(map.is_empty()); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove_entry(self) -> (K, V) { - unsafe { self.table.table.remove(self.elem) } + unsafe { self.table.table.remove(self.elem).0 } } /// Gets a reference to the value in the entry. @@ -5319,15 +5434,14 @@ impl<'a, K, V, S, A: Allocator + Clone> OccupiedEntry<'a, K, V, S, A> { /// assert!(map.is_empty() && map.capacity() == 0); /// /// map.entry("poneyland").or_insert(12); - /// let capacity_before_remove = map.capacity(); /// /// if let Entry::Occupied(o) = map.entry("poneyland") { /// assert_eq!(o.remove(), 12); /// } /// /// assert_eq!(map.contains_key("poneyland"), false); - /// // Now map hold none elements but capacity is equal to the old one - /// assert!(map.len() == 0 && map.capacity() == capacity_before_remove); + /// // Now map hold none elements + /// assert!(map.is_empty()); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove(self) -> V { @@ -5505,7 +5619,7 @@ impl<'a, K, V, S, A: Allocator + Clone> OccupiedEntry<'a, K, V, S, A> { } } -impl<'a, K, V, S, A: Allocator + Clone> VacantEntry<'a, K, V, S, A> { +impl<'a, K, V, S, A: Allocator> VacantEntry<'a, K, V, S, A> { /// Gets a reference to the key that would be used when inserting a value /// through the `VacantEntry`. /// @@ -5567,7 +5681,7 @@ impl<'a, K, V, S, A: Allocator + Clone> VacantEntry<'a, K, V, S, A> { let entry = table.insert_entry( self.hash, (self.key, value), - make_hasher::(&self.table.hash_builder), + make_hasher::<_, V, S>(&self.table.hash_builder), ); &mut entry.1 } @@ -5581,7 +5695,7 @@ impl<'a, K, V, S, A: Allocator + Clone> VacantEntry<'a, K, V, S, A> { let elem = self.table.table.insert( self.hash, (self.key, value), - make_hasher::(&self.table.hash_builder), + make_hasher::<_, V, S>(&self.table.hash_builder), ); OccupiedEntry { hash: self.hash, @@ -5592,7 +5706,7 @@ impl<'a, K, V, S, A: Allocator + Clone> VacantEntry<'a, K, V, S, A> { } } -impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, S, A> { +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { /// Sets the value of the entry, and returns an OccupiedEntryRef. /// /// # Examples @@ -5682,10 +5796,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, /// Ensures a value is in the entry by inserting, if empty, the result of the default function. /// This method allows for generating key-derived values for insertion by providing the default - /// function a reference to the key that was moved during the `.entry_ref(key)` method call. - /// - /// The reference to the moved key is provided so that cloning or copying the key is - /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// function an access to the borrower form of the key. /// /// # Examples /// @@ -5737,7 +5848,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, K: Borrow, { match *self { - EntryRef::Occupied(ref entry) => entry.key(), + EntryRef::Occupied(ref entry) => entry.key().borrow(), EntryRef::Vacant(ref entry) => entry.key(), } } @@ -5833,8 +5944,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, #[cfg_attr(feature = "inline-more", inline)] pub fn and_replace_entry_with(self, f: F) -> Self where - F: FnOnce(&Q, V) -> Option, - K: Borrow, + F: FnOnce(&K, V) -> Option, { match self { EntryRef::Occupied(entry) => entry.replace_entry_with(f), @@ -5843,7 +5953,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, } } -impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, S, A> { +impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// @@ -5876,7 +5986,7 @@ impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator + Clone> EntryRef<'a, 'b, } } -impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> { +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> { /// Gets a reference to the key in the entry. /// /// # Examples @@ -5893,11 +6003,8 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// } /// ``` #[cfg_attr(feature = "inline-more", inline)] - pub fn key(&self) -> &Q - where - K: Borrow, - { - unsafe { &self.elem.as_ref().0 }.borrow() + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } } /// Take the ownership of the key and value from the map. @@ -5914,7 +6021,6 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// assert!(map.is_empty() && map.capacity() == 0); /// /// map.entry_ref("poneyland").or_insert(12); - /// let capacity_before_remove = map.capacity(); /// /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") { /// // We delete the entry from the map. @@ -5923,11 +6029,11 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// /// assert_eq!(map.contains_key("poneyland"), false); /// // Now map hold none elements but capacity is equal to the old one - /// assert!(map.len() == 0 && map.capacity() == capacity_before_remove); + /// assert!(map.is_empty()); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove_entry(self) -> (K, V) { - unsafe { self.table.table.remove(self.elem) } + unsafe { self.table.table.remove(self.elem).0 } } /// Gets a reference to the value in the entry. @@ -6048,7 +6154,6 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// assert!(map.is_empty() && map.capacity() == 0); /// /// map.entry_ref("poneyland").or_insert(12); - /// let capacity_before_remove = map.capacity(); /// /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") { /// assert_eq!(o.remove(), 12); @@ -6056,7 +6161,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// /// assert_eq!(map.contains_key("poneyland"), false); /// // Now map hold none elements but capacity is equal to the old one - /// assert!(map.len() == 0 && map.capacity() == capacity_before_remove); + /// assert!(map.is_empty()); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove(self) -> V { @@ -6068,7 +6173,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// /// # Panics /// - /// Will panic if this OccupiedEntry was created through [`EntryRef::insert`]. + /// Will panic if this OccupiedEntryRef was created through [`EntryRef::insert`]. /// /// # Examples /// @@ -6110,7 +6215,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// /// # Panics /// - /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// Will panic if this OccupiedEntryRef was created through [`EntryRef::insert`]. /// /// # Examples /// @@ -6138,7 +6243,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, /// fn reclaim_memory(map: &mut HashMap, usize>, keys: &[Rc]) { /// for key in keys { /// if let EntryRef::Occupied(entry) = map.entry_ref(key.as_ref()) { - /// /// Replaces the entry's key with our version of it in `keys`. + /// // Replaces the entry's key with our version of it in `keys`. /// entry.replace_key(); /// } /// } @@ -6204,8 +6309,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, #[cfg_attr(feature = "inline-more", inline)] pub fn replace_entry_with(self, f: F) -> EntryRef<'a, 'b, K, Q, V, S, A> where - F: FnOnce(&Q, V) -> Option, - K: Borrow, + F: FnOnce(&K, V) -> Option, { unsafe { let mut spare_key = None; @@ -6213,7 +6317,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, self.table .table .replace_bucket_with(self.elem.clone(), |(key, value)| { - if let Some(new_value) = f(key.borrow(), value) { + if let Some(new_value) = f(&key, value) { Some((key, new_value)) } else { spare_key = Some(KeyOrRef::Owned(key)); @@ -6234,7 +6338,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, } } -impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> VacantEntryRef<'a, 'b, K, Q, V, S, A> { +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'a, 'b, K, Q, V, S, A> { /// Gets a reference to the key that would be used when inserting a value /// through the `VacantEntryRef`. /// @@ -6305,7 +6409,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> VacantEntryRef<'a, 'b, K, let entry = table.insert_entry( self.hash, (self.key.into_owned(), value), - make_hasher::(&self.table.hash_builder), + make_hasher::<_, V, S>(&self.table.hash_builder), ); &mut entry.1 } @@ -6319,7 +6423,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> VacantEntryRef<'a, 'b, K, let elem = self.table.table.insert( self.hash, (self.key.into_owned(), value), - make_hasher::(&self.table.hash_builder), + make_hasher::<_, V, S>(&self.table.hash_builder), ); OccupiedEntryRef { hash: self.hash, @@ -6334,7 +6438,7 @@ impl FromIterator<(K, V)> for HashMap where K: Eq + Hash, S: BuildHasher + Default, - A: Default + Allocator + Clone, + A: Default + Allocator, { #[cfg_attr(feature = "inline-more", inline)] fn from_iter>(iter: T) -> Self { @@ -6354,7 +6458,7 @@ impl Extend<(K, V)> for HashMap where K: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { /// Inserts all new key-values from the iterator to existing `HashMap`. /// Replace values with existing keys with new values returned from the iterator. @@ -6438,7 +6542,7 @@ where K: Eq + Hash + Copy, V: Copy, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { /// Inserts all new key-values from the iterator to existing `HashMap`. /// Replace values with existing keys with new values returned from the iterator. @@ -6455,17 +6559,17 @@ where /// map.insert(1, 100); /// /// let arr = [(1, 1), (2, 2)]; - /// let some_iter = arr.iter().map(|&(k, v)| (k, v)); + /// let some_iter = arr.iter().map(|(k, v)| (k, v)); /// map.extend(some_iter); /// // Replace values with existing keys with new values returned from the iterator. /// // So that the map.get(&1) doesn't return Some(&100). /// assert_eq!(map.get(&1), Some(&1)); /// /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; - /// map.extend(some_vec.iter().map(|&(k, v)| (k, v))); + /// map.extend(some_vec.iter().map(|(k, v)| (k, v))); /// /// let some_arr = [(5, 5), (6, 6)]; - /// map.extend(some_arr.iter().map(|&(k, v)| (k, v))); + /// map.extend(some_arr.iter().map(|(k, v)| (k, v))); /// /// // You can also extend from another HashMap /// let mut new_map = HashMap::new(); @@ -6503,7 +6607,7 @@ where K: Eq + Hash + Copy, V: Copy, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { /// Inserts all new key-values from the iterator to existing `HashMap`. /// Replace values with existing keys with new values returned from the iterator. @@ -6570,12 +6674,12 @@ fn assert_covariance() { fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { v } - fn into_iter_key<'new, A: Allocator + Clone>( + fn into_iter_key<'new, A: Allocator>( v: IntoIter<&'static str, u8, A>, ) -> IntoIter<&'new str, u8, A> { v } - fn into_iter_val<'new, A: Allocator + Clone>( + fn into_iter_val<'new, A: Allocator>( v: IntoIter, ) -> IntoIter { v @@ -6605,6 +6709,12 @@ mod test_map { use super::Entry::{Occupied, Vacant}; use super::EntryRef; use super::{HashMap, RawEntryMut}; + use alloc::string::{String, ToString}; + use alloc::sync::Arc; + use allocator_api2::alloc::{AllocError, Allocator, Global}; + use core::alloc::Layout; + use core::ptr::NonNull; + use core::sync::atomic::{AtomicI8, Ordering}; use rand::{rngs::SmallRng, Rng, SeedableRng}; use std::borrow::ToOwned; use std::cell::RefCell; @@ -6695,7 +6805,7 @@ mod test_map { assert_eq!(m2.len(), 2); } - thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } + thread_local! { static DROP_VECTOR: RefCell> = const { RefCell::new(Vec::new()) } } #[derive(Hash, PartialEq, Eq)] struct Droppable { @@ -6827,7 +6937,6 @@ mod test_map { } }); - #[allow(clippy::let_underscore_drop)] // kind-of a false positive for _ in half.by_ref() {} DROP_VECTOR.with(|v| { @@ -7155,10 +7264,10 @@ mod test_map { map.insert(1, 2); map.insert(3, 4); - let map_str = format!("{:?}", map); + let map_str = format!("{map:?}"); assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); - assert_eq!(format!("{:?}", empty), "{}"); + assert_eq!(format!("{empty:?}"), "{}"); } #[test] @@ -7474,7 +7583,7 @@ mod test_map { // Test for #19292 fn check(m: &HashMap) { for k in m.keys() { - assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); } } @@ -7510,7 +7619,7 @@ mod test_map { // Test for #19292 fn check(m: &HashMap) { for k in m.keys() { - assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); } } @@ -7559,6 +7668,7 @@ mod test_map { } #[test] + #[allow(clippy::needless_borrow)] fn test_extend_ref_kv_tuple() { use std::ops::AddAssign; let mut a = HashMap::new(); @@ -7580,7 +7690,7 @@ mod test_map { let vec: Vec<_> = (100..200).map(|i| (i, i)).collect(); a.extend(iter); a.extend(&vec); - a.extend(&create_arr::(200, 1)); + a.extend(create_arr::(200, 1)); assert_eq!(a.len(), 300); @@ -7981,7 +8091,7 @@ mod test_map { // Test for #19292 fn check(m: &HashMap) { for k in m.keys() { - assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); } } @@ -8011,7 +8121,7 @@ mod test_map { // Test for #19292 fn check(m: &HashMap) { for k in m.keys() { - assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); } } @@ -8049,10 +8159,10 @@ mod test_map { } #[test] - fn test_drain_filter() { + fn test_extract_if() { { let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); - let drained = map.drain_filter(|&k, _| k % 2 == 0); + let drained = map.extract_if(|&k, _| k % 2 == 0); let mut out = drained.collect::>(); out.sort_unstable(); assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); @@ -8060,7 +8170,7 @@ mod test_map { } { let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); - drop(map.drain_filter(|&k, _| k % 2 == 0)); + map.extract_if(|&k, _| k % 2 == 0).for_each(drop); assert_eq!(map.len(), 4); } } @@ -8070,27 +8180,32 @@ mod test_map { fn test_try_reserve() { use crate::TryReserveError::{AllocError, CapacityOverflow}; - const MAX_USIZE: usize = usize::MAX; + const MAX_ISIZE: usize = isize::MAX as usize; let mut empty_bytes: HashMap = HashMap::new(); - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(usize::MAX) { } else { panic!("usize::MAX should trigger an overflow!"); } - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 16) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_ISIZE) { + } else { + panic!("isize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_ISIZE / 5) { } else { // This may succeed if there is enough free memory. Attempt to // allocate a few more hashmaps to ensure the allocation will fail. let mut empty_bytes2: HashMap = HashMap::new(); - let _ = empty_bytes2.try_reserve(MAX_USIZE / 16); + let _ = empty_bytes2.try_reserve(MAX_ISIZE / 5); let mut empty_bytes3: HashMap = HashMap::new(); - let _ = empty_bytes3.try_reserve(MAX_USIZE / 16); + let _ = empty_bytes3.try_reserve(MAX_ISIZE / 5); let mut empty_bytes4: HashMap = HashMap::new(); - if let Err(AllocError { .. }) = empty_bytes4.try_reserve(MAX_USIZE / 16) { + if let Err(AllocError { .. }) = empty_bytes4.try_reserve(MAX_ISIZE / 5) { } else { - panic!("usize::MAX / 8 should trigger an OOM!"); + panic!("isize::MAX / 5 should trigger an OOM!"); } } } @@ -8104,7 +8219,7 @@ mod test_map { let mut map: HashMap<_, _> = xs.iter().copied().collect(); let compute_hash = |map: &HashMap, k: i32| -> u64 { - super::make_insert_hash::(map.hasher(), &k) + super::make_hash::(map.hasher(), &k) }; // Existing key (insert) @@ -8266,21 +8381,21 @@ mod test_map { loop { // occasionally remove some elements if i < n && rng.gen_bool(0.1) { - let hash_value = super::make_insert_hash(&hash_builder, &i); + let hash_value = super::make_hash(&hash_builder, &i); unsafe { let e = map.table.find(hash_value, |q| q.0.eq(&i)); if let Some(e) = e { it.reflect_remove(&e); - let t = map.table.remove(e); + let t = map.table.remove(e).0; removed.push(t); left -= 1; } else { - assert!(removed.contains(&(i, 2 * i)), "{} not in {:?}", i, removed); + assert!(removed.contains(&(i, 2 * i)), "{i} not in {removed:?}"); let e = map.table.insert( hash_value, (i, 2 * i), - super::make_hasher::(&hash_builder), + super::make_hasher::<_, usize, _>(&hash_builder), ); it.reflect_insert(&e); if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) { @@ -8405,4 +8520,441 @@ mod test_map { map2.clone_from(&map1); } + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_from_memory_leaks() { + use alloc::vec::Vec; + + struct CheckedClone { + panic_in_clone: bool, + need_drop: Vec, + } + impl Clone for CheckedClone { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + need_drop: self.need_drop.clone(), + } + } + } + let mut map1 = HashMap::new(); + map1.insert( + 1, + CheckedClone { + panic_in_clone: false, + need_drop: vec![0, 1, 2], + }, + ); + map1.insert( + 2, + CheckedClone { + panic_in_clone: false, + need_drop: vec![3, 4, 5], + }, + ); + map1.insert( + 3, + CheckedClone { + panic_in_clone: true, + need_drop: vec![6, 7, 8], + }, + ); + let _map2 = map1.clone(); + } + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl MyAlloc { + fn new(drop_count: Arc) -> Self { + MyAlloc { + _inner: Arc::new(MyAllocInner { drop_count }), + } + } + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + #[test] + fn test_hashmap_into_iter_bug() { + let dropped: Arc = Arc::new(AtomicI8::new(1)); + + { + let mut map = HashMap::with_capacity_in(10, MyAlloc::new(dropped.clone())); + for i in 0..10 { + map.entry(i).or_insert_with(|| "i".to_string()); + } + + for (k, v) in map { + println!("{}, {}", k, v); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + #[derive(Debug)] + struct CheckedCloneDrop { + panic_in_clone: bool, + panic_in_drop: bool, + dropped: bool, + data: T, + } + + impl CheckedCloneDrop { + fn new(panic_in_clone: bool, panic_in_drop: bool, data: T) -> Self { + CheckedCloneDrop { + panic_in_clone, + panic_in_drop, + dropped: false, + data, + } + } + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + panic_in_drop: self.panic_in_drop, + dropped: self.dropped, + data: self.data.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + /// Return hashmap with predefined distribution of elements. + /// All elements will be located in the same order as elements + /// returned by iterator. + /// + /// This function does not panic, but returns an error as a `String` + /// to distinguish between a test panic and an error in the input data. + fn get_test_map( + iter: I, + mut fun: impl FnMut(u64) -> T, + alloc: A, + ) -> Result, DefaultHashBuilder, A>, String> + where + I: Iterator + Clone + ExactSizeIterator, + A: Allocator, + T: PartialEq + core::fmt::Debug, + { + use crate::scopeguard::guard; + + let mut map: HashMap, _, A> = + HashMap::with_capacity_in(iter.size_hint().0, alloc); + { + let mut guard = guard(&mut map, |map| { + for (_, value) in map.iter_mut() { + value.panic_in_drop = false + } + }); + + let mut count = 0; + // Hash and Key must be equal to each other for controlling the elements placement. + for (panic_in_clone, panic_in_drop) in iter.clone() { + if core::mem::needs_drop::() && panic_in_drop { + return Err(String::from( + "panic_in_drop can be set with a type that doesn't need to be dropped", + )); + } + guard.table.insert( + count, + ( + count, + CheckedCloneDrop::new(panic_in_clone, panic_in_drop, fun(count)), + ), + |(k, _)| *k, + ); + count += 1; + } + + // Let's check that all elements are located as we wanted + let mut check_count = 0; + for ((key, value), (panic_in_clone, panic_in_drop)) in guard.iter().zip(iter) { + if *key != check_count { + return Err(format!( + "key != check_count,\nkey: `{}`,\ncheck_count: `{}`", + key, check_count + )); + } + if value.dropped + || value.panic_in_clone != panic_in_clone + || value.panic_in_drop != panic_in_drop + || value.data != fun(check_count) + { + return Err(format!( + "Value is not equal to expected,\nvalue: `{:?}`,\nexpected: \ + `CheckedCloneDrop {{ panic_in_clone: {}, panic_in_drop: {}, dropped: {}, data: {:?} }}`", + value, panic_in_clone, panic_in_drop, false, fun(check_count) + )); + } + check_count += 1; + } + + if guard.len() != check_count as usize { + return Err(format!( + "map.len() != check_count,\nmap.len(): `{}`,\ncheck_count: `{}`", + guard.len(), + check_count + )); + } + + if count != check_count { + return Err(format!( + "count != check_count,\ncount: `{}`,\ncheck_count: `{}`", + count, check_count + )); + } + core::mem::forget(guard); + } + Ok(map) + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + const ARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + const DISARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_memory_leaks_and_double_drop_one() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap>, DefaultHashBuilder, MyAlloc> = + match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // Clone should normally clone a few elements, and then (when the + // clone function panics), deallocate both its own memory, memory + // of `dropped: Arc` and the memory of already cloned + // elements (Vec memory inside CheckedCloneDrop). + let _map2 = map.clone(); + } + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_memory_leaks_and_double_drop_two() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap, DefaultHashBuilder, _> = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + let mut map2 = match get_test_map( + DISARMED_FLAGS.into_iter().zip(ARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // The `clone_from` should try to drop the elements of `map2` without + // double drop and leaking the allocator. Elements that have not been + // dropped leak their memory. + map2.clone_from(&map); + } + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = + match get_test_map(ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), |n| vec![n * 2], MyAlloc::new(dropped.clone())) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() != scope_map.table.buckets() { + return format!( + "map.table.buckets() != scope_map.table.buckets(),\nleft: `{}`,\nright: `{}`", + map.table.buckets(), scope_map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are not equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_not_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + [DISARMED].into_iter().zip([DISARMED]), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n * 2], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() == scope_map.table.buckets() { + return format!( + "map.table.buckets() == scope_map.table.buckets(): `{}`", + map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } } diff --git a/third_party/rust/hashbrown/src/raw/alloc.rs b/third_party/rust/hashbrown/src/raw/alloc.rs index ba09ea9de7..15299e7b09 100644 --- a/third_party/rust/hashbrown/src/raw/alloc.rs +++ b/third_party/rust/hashbrown/src/raw/alloc.rs @@ -1,5 +1,9 @@ pub(crate) use self::inner::{do_alloc, Allocator, Global}; +// Nightly-case. +// Use unstable `allocator_api` feature. +// This is compatible with `allocator-api2` which can be enabled or not. +// This is used when building for `std`. #[cfg(feature = "nightly")] mod inner { use crate::alloc::alloc::Layout; @@ -7,28 +11,44 @@ mod inner { use core::ptr::NonNull; #[allow(clippy::map_err_ignore)] - pub fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { match alloc.allocate(layout) { Ok(ptr) => Ok(ptr.as_non_null_ptr()), Err(_) => Err(()), } } +} - #[cfg(feature = "bumpalo")] - unsafe impl Allocator for crate::BumpWrapper<'_> { - #[inline] - fn allocate(&self, layout: Layout) -> Result, core::alloc::AllocError> { - match self.0.try_alloc_layout(layout) { - Ok(ptr) => Ok(NonNull::slice_from_raw_parts(ptr, layout.size())), - Err(_) => Err(core::alloc::AllocError), - } +// Basic non-nightly case. +// This uses `allocator-api2` enabled by default. +// If any crate enables "nightly" in `allocator-api2`, +// this will be equivalent to the nightly case, +// since `allocator_api2::alloc::Allocator` would be re-export of +// `core::alloc::Allocator`. +#[cfg(all(not(feature = "nightly"), feature = "allocator-api2"))] +mod inner { + use crate::alloc::alloc::Layout; + pub use allocator_api2::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr.cast()), + Err(_) => Err(()), } - #[inline] - unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) {} } } -#[cfg(not(feature = "nightly"))] +// No-defaults case. +// When building with default-features turned off and +// neither `nightly` nor `allocator-api2` is enabled, +// this will be used. +// Making it impossible to use any custom allocator with collections defined +// in this crate. +// Any crate in build-tree can enable `allocator-api2`, +// or `nightly` without disturbing users that don't want to use it. +#[cfg(not(any(feature = "nightly", feature = "allocator-api2")))] mod inner { use crate::alloc::alloc::{alloc, dealloc, Layout}; use core::ptr::NonNull; @@ -41,6 +61,7 @@ mod inner { #[derive(Copy, Clone)] pub struct Global; + unsafe impl Allocator for Global { #[inline] fn allocate(&self, layout: Layout) -> Result, ()> { @@ -51,6 +72,7 @@ mod inner { dealloc(ptr.as_ptr(), layout); } } + impl Default for Global { #[inline] fn default() -> Self { @@ -58,16 +80,7 @@ mod inner { } } - pub fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { alloc.allocate(layout) } - - #[cfg(feature = "bumpalo")] - unsafe impl Allocator for crate::BumpWrapper<'_> { - #[allow(clippy::map_err_ignore)] - fn allocate(&self, layout: Layout) -> Result, ()> { - self.0.try_alloc_layout(layout).map_err(|_| ()) - } - unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) {} - } } diff --git a/third_party/rust/hashbrown/src/raw/bitmask.rs b/third_party/rust/hashbrown/src/raw/bitmask.rs index 7d4f9fc387..6576b3c5c0 100644 --- a/third_party/rust/hashbrown/src/raw/bitmask.rs +++ b/third_party/rust/hashbrown/src/raw/bitmask.rs @@ -1,6 +1,6 @@ -use super::imp::{BitMaskWord, BITMASK_MASK, BITMASK_STRIDE}; -#[cfg(feature = "nightly")] -use core::intrinsics; +use super::imp::{ + BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE, +}; /// A bit mask which contains the result of a `Match` operation on a `Group` and /// allows iterating through them. @@ -8,75 +8,55 @@ use core::intrinsics; /// The bit mask is arranged so that low-order bits represent lower memory /// addresses for group match results. /// -/// For implementation reasons, the bits in the set may be sparsely packed, so -/// that there is only one bit-per-byte used (the high bit, 7). If this is the +/// For implementation reasons, the bits in the set may be sparsely packed with +/// groups of 8 bits representing one element. If any of these bits are non-zero +/// then this element is considered to true in the mask. If this is the /// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be /// performed on counts/indices to normalize this difference. `BITMASK_MASK` is /// similarly a mask of all the actually-used bits. +/// +/// To iterate over a bit mask, it must be converted to a form where only 1 bit +/// is set per element. This is done by applying `BITMASK_ITER_MASK` on the +/// mask bits. #[derive(Copy, Clone)] -pub struct BitMask(pub BitMaskWord); +pub(crate) struct BitMask(pub(crate) BitMaskWord); #[allow(clippy::use_self)] impl BitMask { /// Returns a new `BitMask` with all bits inverted. #[inline] #[must_use] - pub fn invert(self) -> Self { + #[allow(dead_code)] + pub(crate) fn invert(self) -> Self { BitMask(self.0 ^ BITMASK_MASK) } - /// Flip the bit in the mask for the entry at the given index. - /// - /// Returns the bit's previous state. - #[inline] - #[allow(clippy::cast_ptr_alignment)] - #[cfg(feature = "raw")] - pub unsafe fn flip(&mut self, index: usize) -> bool { - // NOTE: The + BITMASK_STRIDE - 1 is to set the high bit. - let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1); - self.0 ^= mask; - // The bit was set if the bit is now 0. - self.0 & mask == 0 - } - /// Returns a new `BitMask` with the lowest bit removed. #[inline] #[must_use] - pub fn remove_lowest_bit(self) -> Self { + fn remove_lowest_bit(self) -> Self { BitMask(self.0 & (self.0 - 1)) } + /// Returns whether the `BitMask` has at least one set bit. #[inline] - pub fn any_bit_set(self) -> bool { + pub(crate) fn any_bit_set(self) -> bool { self.0 != 0 } /// Returns the first set bit in the `BitMask`, if there is one. #[inline] - pub fn lowest_set_bit(self) -> Option { - if self.0 == 0 { - None + pub(crate) fn lowest_set_bit(self) -> Option { + if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { + Some(Self::nonzero_trailing_zeros(nonzero)) } else { - Some(unsafe { self.lowest_set_bit_nonzero() }) + None } } - /// Returns the first set bit in the `BitMask`, if there is one. The - /// bitmask must not be empty. - #[inline] - #[cfg(feature = "nightly")] - pub unsafe fn lowest_set_bit_nonzero(self) -> usize { - intrinsics::cttz_nonzero(self.0) as usize / BITMASK_STRIDE - } - #[inline] - #[cfg(not(feature = "nightly"))] - pub unsafe fn lowest_set_bit_nonzero(self) -> usize { - self.trailing_zeros() - } - /// Returns the number of trailing zeroes in the `BitMask`. #[inline] - pub fn trailing_zeros(self) -> usize { + pub(crate) fn trailing_zeros(self) -> usize { // ARM doesn't have a trailing_zeroes instruction, and instead uses // reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM // versions (pre-ARMv7) don't have RBIT and need to emulate it @@ -89,9 +69,21 @@ impl BitMask { } } + /// Same as above but takes a `NonZeroBitMaskWord`. + #[inline] + fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + // SAFETY: A byte-swapped non-zero value is still non-zero. + let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; + swapped.leading_zeros() as usize / BITMASK_STRIDE + } else { + nonzero.trailing_zeros() as usize / BITMASK_STRIDE + } + } + /// Returns the number of leading zeroes in the `BitMask`. #[inline] - pub fn leading_zeros(self) -> usize { + pub(crate) fn leading_zeros(self) -> usize { self.0.leading_zeros() as usize / BITMASK_STRIDE } } @@ -102,13 +94,32 @@ impl IntoIterator for BitMask { #[inline] fn into_iter(self) -> BitMaskIter { - BitMaskIter(self) + // A BitMask only requires each element (group of bits) to be non-zero. + // However for iteration we need each element to only contain 1 bit. + BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) } } /// Iterator over the contents of a `BitMask`, returning the indices of set /// bits. -pub struct BitMaskIter(BitMask); +#[derive(Copy, Clone)] +pub(crate) struct BitMaskIter(pub(crate) BitMask); + +impl BitMaskIter { + /// Flip the bit in the mask for the entry at the given index. + /// + /// Returns the bit's previous state. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + #[cfg(feature = "raw")] + pub(crate) unsafe fn flip(&mut self, index: usize) -> bool { + // NOTE: The + BITMASK_STRIDE - 1 is to set the high bit. + let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1); + self.0 .0 ^= mask; + // The bit was set if the bit is now 0. + self.0 .0 & mask == 0 + } +} impl Iterator for BitMaskIter { type Item = usize; diff --git a/third_party/rust/hashbrown/src/raw/generic.rs b/third_party/rust/hashbrown/src/raw/generic.rs index b4d31e62c2..c668b0642a 100644 --- a/third_party/rust/hashbrown/src/raw/generic.rs +++ b/third_party/rust/hashbrown/src/raw/generic.rs @@ -5,26 +5,29 @@ use core::{mem, ptr}; // Use the native word size as the group size. Using a 64-bit group size on // a 32-bit architecture will just end up being more expensive because // shifts and multiplies will need to be emulated. -#[cfg(any( - target_pointer_width = "64", - target_arch = "aarch64", - target_arch = "x86_64", - target_arch = "wasm32", -))] -type GroupWord = u64; -#[cfg(all( - target_pointer_width = "32", - not(target_arch = "aarch64"), - not(target_arch = "x86_64"), - not(target_arch = "wasm32"), -))] -type GroupWord = u32; -pub type BitMaskWord = GroupWord; -pub const BITMASK_STRIDE: usize = 8; +cfg_if! { + if #[cfg(any( + target_pointer_width = "64", + target_arch = "aarch64", + target_arch = "x86_64", + target_arch = "wasm32", + ))] { + type GroupWord = u64; + type NonZeroGroupWord = core::num::NonZeroU64; + } else { + type GroupWord = u32; + type NonZeroGroupWord = core::num::NonZeroU32; + } +} + +pub(crate) type BitMaskWord = GroupWord; +pub(crate) type NonZeroBitMaskWord = NonZeroGroupWord; +pub(crate) const BITMASK_STRIDE: usize = 8; // We only care about the highest bit of each byte for the mask. #[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)] -pub const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080_u64 as GroupWord; +pub(crate) const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080_u64 as GroupWord; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; /// Helper function to replicate a byte across a `GroupWord`. #[inline] @@ -37,7 +40,7 @@ fn repeat(byte: u8) -> GroupWord { /// /// This implementation uses a word-sized integer. #[derive(Copy, Clone)] -pub struct Group(GroupWord); +pub(crate) struct Group(GroupWord); // We perform all operations in the native endianness, and convert to // little-endian just before creating a BitMask. The can potentially @@ -46,14 +49,14 @@ pub struct Group(GroupWord); #[allow(clippy::use_self)] impl Group { /// Number of bytes in the group. - pub const WIDTH: usize = mem::size_of::(); + pub(crate) const WIDTH: usize = mem::size_of::(); /// Returns a full group of empty bytes, suitable for use as the initial /// value for an empty hash table. /// /// This is guaranteed to be aligned to the group size. #[inline] - pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { #[repr(C)] struct AlignedBytes { _align: [Group; 0], @@ -69,7 +72,7 @@ impl Group { /// Loads a group of bytes starting at the given address. #[inline] #[allow(clippy::cast_ptr_alignment)] // unaligned load - pub unsafe fn load(ptr: *const u8) -> Self { + pub(crate) unsafe fn load(ptr: *const u8) -> Self { Group(ptr::read_unaligned(ptr.cast())) } @@ -77,7 +80,7 @@ impl Group { /// aligned to `mem::align_of::()`. #[inline] #[allow(clippy::cast_ptr_alignment)] - pub unsafe fn load_aligned(ptr: *const u8) -> Self { + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { // FIXME: use align_offset once it stabilizes debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); Group(ptr::read(ptr.cast())) @@ -87,7 +90,7 @@ impl Group { /// aligned to `mem::align_of::()`. #[inline] #[allow(clippy::cast_ptr_alignment)] - pub unsafe fn store_aligned(self, ptr: *mut u8) { + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { // FIXME: use align_offset once it stabilizes debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); ptr::write(ptr.cast(), self.0); @@ -104,7 +107,7 @@ impl Group { /// - This only happens if there is at least 1 true match. /// - The chance of this happening is very low (< 1% chance per byte). #[inline] - pub fn match_byte(self, byte: u8) -> BitMask { + pub(crate) fn match_byte(self, byte: u8) -> BitMask { // This algorithm is derived from // https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord let cmp = self.0 ^ repeat(byte); @@ -114,7 +117,7 @@ impl Group { /// Returns a `BitMask` indicating all bytes in the group which are /// `EMPTY`. #[inline] - pub fn match_empty(self) -> BitMask { + pub(crate) fn match_empty(self) -> BitMask { // If the high bit is set, then the byte must be either: // 1111_1111 (EMPTY) or 1000_0000 (DELETED). // So we can just check if the top two bits are 1 by ANDing them. @@ -124,14 +127,14 @@ impl Group { /// Returns a `BitMask` indicating all bytes in the group which are /// `EMPTY` or `DELETED`. #[inline] - pub fn match_empty_or_deleted(self) -> BitMask { + pub(crate) fn match_empty_or_deleted(self) -> BitMask { // A byte is EMPTY or DELETED iff the high bit is set BitMask((self.0 & repeat(0x80)).to_le()) } /// Returns a `BitMask` indicating all bytes in the group which are full. #[inline] - pub fn match_full(self) -> BitMask { + pub(crate) fn match_full(self) -> BitMask { self.match_empty_or_deleted().invert() } @@ -140,7 +143,7 @@ impl Group { /// - `DELETED => EMPTY` /// - `FULL => DELETED` #[inline] - pub fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 // and high_bit = 0 (FULL) to 1000_0000 // diff --git a/third_party/rust/hashbrown/src/raw/mod.rs b/third_party/rust/hashbrown/src/raw/mod.rs index 211b818a5f..c8e8e29122 100644 --- a/third_party/rust/hashbrown/src/raw/mod.rs +++ b/third_party/rust/hashbrown/src/raw/mod.rs @@ -4,7 +4,6 @@ use crate::TryReserveError; use core::iter::FusedIterator; use core::marker::PhantomData; use core::mem; -use core::mem::ManuallyDrop; use core::mem::MaybeUninit; use core::ptr::NonNull; use core::{hint, ptr}; @@ -21,12 +20,21 @@ cfg_if! { if #[cfg(all( target_feature = "sse2", any(target_arch = "x86", target_arch = "x86_64"), - not(miri) + not(miri), ))] { mod sse2; use sse2 as imp; + } else if #[cfg(all( + target_arch = "aarch64", + target_feature = "neon", + // NEON intrinsics are currently broken on big-endian targets. + // See https://github.com/rust-lang/stdarch/issues/1484. + target_endian = "little", + not(miri), + ))] { + mod neon; + use neon as imp; } else { - #[path = "generic.rs"] mod generic; use generic as imp; } @@ -37,36 +45,24 @@ pub(crate) use self::alloc::{do_alloc, Allocator, Global}; mod bitmask; -use self::bitmask::{BitMask, BitMaskIter}; +use self::bitmask::BitMaskIter; use self::imp::Group; // Branch prediction hint. This is currently only available on nightly but it // consistently improves performance by 10-15%. +#[cfg(not(feature = "nightly"))] +use core::convert::identity as likely; +#[cfg(not(feature = "nightly"))] +use core::convert::identity as unlikely; #[cfg(feature = "nightly")] use core::intrinsics::{likely, unlikely}; -// On stable we can use #[cold] to get a equivalent effect: this attributes -// suggests that the function is unlikely to be called -#[cfg(not(feature = "nightly"))] -#[inline] -#[cold] -fn cold() {} - -#[cfg(not(feature = "nightly"))] -#[inline] -fn likely(b: bool) -> bool { - if !b { - cold(); - } - b -} -#[cfg(not(feature = "nightly"))] -#[inline] -fn unlikely(b: bool) -> bool { - if b { - cold(); - } - b +// FIXME: use strict provenance functions once they are stable. +// Implement it with a transmute for now. +#[inline(always)] +#[allow(clippy::useless_transmute)] // clippy is wrong, cast and transmute are different here +fn invalid_mut(addr: usize) -> *mut T { + unsafe { core::mem::transmute(addr) } } #[inline] @@ -101,6 +97,13 @@ impl Fallibility { } } +trait SizedTypeProperties: Sized { + const IS_ZERO_SIZED: bool = mem::size_of::() == 0; + const NEEDS_DROP: bool = mem::needs_drop::(); +} + +impl SizedTypeProperties for T {} + /// Control byte value for an empty bucket. const EMPTY: u8 = 0b1111_1111; @@ -134,6 +137,13 @@ fn h1(hash: u64) -> usize { hash as usize } +// Constant for h2 function that grabing the top 7 bits of the hash. +const MIN_HASH_LEN: usize = if mem::size_of::() < mem::size_of::() { + mem::size_of::() +} else { + mem::size_of::() +}; + /// Secondary hash function, saved in the low 7 bits of the control byte. #[inline] #[allow(clippy::cast_possible_truncation)] @@ -141,8 +151,8 @@ fn h2(hash: u64) -> u8 { // Grab the top 7 bits of the hash. While the hash is normally a full 64-bit // value, some hash functions (such as FxHash) produce a usize result // instead, which means that the top 32 bits are 0 on 32-bit platforms. - let hash_len = usize::min(mem::size_of::(), mem::size_of::()); - let top7 = hash >> (hash_len * 8 - 7); + // So we use MIN_HASH_LEN constant to handle this. + let top7 = hash >> (MIN_HASH_LEN * 8 - 7); (top7 & 0x7f) as u8 // truncation } @@ -230,11 +240,15 @@ struct TableLayout { impl TableLayout { #[inline] - fn new() -> Self { + const fn new() -> Self { let layout = Layout::new::(); Self { size: layout.size(), - ctrl_align: usize::max(layout.align(), Group::WIDTH), + ctrl_align: if layout.align() > Group::WIDTH { + layout.align() + } else { + Group::WIDTH + }, } } @@ -248,6 +262,12 @@ impl TableLayout { size.checked_mul(buckets)?.checked_add(ctrl_align - 1)? & !(ctrl_align - 1); let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?; + // We need an additional check to ensure that the allocation doesn't + // exceed `isize::MAX` (https://github.com/rust-lang/rust/pull/95295). + if len > isize::MAX as usize - (ctrl_align - 1) { + return None; + } + Some(( unsafe { Layout::from_size_align_unchecked(len, ctrl_align) }, ctrl_offset, @@ -255,14 +275,9 @@ impl TableLayout { } } -/// Returns a Layout which describes the allocation required for a hash table, -/// and the offset of the control bytes in the allocation. -/// (the offset is also one past last element of buckets) -/// -/// Returns `None` if an overflow occurs. -#[cfg_attr(feature = "inline-more", inline)] -fn calculate_layout(buckets: usize) -> Option<(Layout, usize)> { - TableLayout::new::().calculate_layout_for(buckets) +/// A reference to an empty bucket into which an can be inserted. +pub struct InsertSlot { + index: usize, } /// A reference to a hash table bucket containing a `T`. @@ -290,11 +305,79 @@ impl Clone for Bucket { } impl Bucket { + /// Creates a [`Bucket`] that contain pointer to the data. + /// The pointer calculation is performed by calculating the + /// offset from given `base` pointer (convenience for + /// `base.as_ptr().sub(index)`). + /// + /// `index` is in units of `T`; e.g., an `index` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// If the `T` is a ZST, then we instead track the index of the element + /// in the table so that `erase` works properly (return + /// `NonNull::new_unchecked((index + 1) as *mut T)`) + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and the safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for the [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * the `base` pointer must not be `dangling` and must points to the + /// end of the first `value element` from the `data part` of the table, i.e. + /// must be the pointer that returned by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets #[inline] unsafe fn from_base_index(base: NonNull, index: usize) -> Self { - let ptr = if mem::size_of::() == 0 { - // won't overflow because index must be less than length - (index + 1) as *mut T + // If mem::size_of::() != 0 then return a pointer to an `element` in + // the data part of the table (we start counting from "0", so that + // in the expression T[last], the "last" index actually one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"): + // + // `from_base_index(base, 1).as_ptr()` returns a pointer that + // points here in the data part of the table + // (to the start of T1) + // | + // | `base: NonNull` must point here + // | (to the end of T0 or to the start of C0) + // v v + // [Padding], Tlast, ..., |T1|, T0, |C0, C1, ..., Clast + // ^ + // `from_base_index(base, 1)` returns a pointer + // that points here in the data part of the table + // (to the end of T1) + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes + // or metadata for data. + let ptr = if T::IS_ZERO_SIZED { + // won't overflow because index must be less than length (bucket_mask) + // and bucket_mask is guaranteed to be less than `isize::MAX` + // (see TableLayout::calculate_layout_for method) + invalid_mut(index + 1) } else { base.as_ptr().sub(index) }; @@ -302,27 +385,183 @@ impl Bucket { ptr: NonNull::new_unchecked(ptr), } } + + /// Calculates the index of a [`Bucket`] as distance between two pointers + /// (convenience for `base.as_ptr().offset_from(self.ptr.as_ptr()) as usize`). + /// The returned value is in units of T: the distance in bytes divided by + /// [`core::mem::size_of::()`]. + /// + /// If the `T` is a ZST, then we return the index of the element in + /// the table so that `erase` works properly (return `self.ptr.as_ptr() as usize - 1`). + /// + /// This function is the inverse of [`from_base_index`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*const T>::offset_from`] method of `*const T`. + /// + /// Thus, in order to uphold the safety contracts for [`<*const T>::offset_from`] + /// method, as well as for the correct logic of the work of this crate, the + /// following rules are necessary and sufficient: + /// + /// * `base` contained pointer must not be `dangling` and must point to the + /// end of the first `element` from the `data part` of the table, i.e. + /// must be a pointer that returns by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `self` also must not contain dangling pointer; + /// + /// * both `self` and `base` must be created from the same [`RawTable`] + /// (or [`RawTableInner`]). + /// + /// If `mem::size_of::() == 0`, this function is always safe. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`from_base_index`]: crate::raw::Bucket::from_base_index + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTableInner`]: RawTableInner + /// [`<*const T>::offset_from`]: https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.offset_from #[inline] unsafe fn to_base_index(&self, base: NonNull) -> usize { - if mem::size_of::() == 0 { + // If mem::size_of::() != 0 then return an index under which we used to store the + // `element` in the data part of the table (we start counting from "0", so + // that in the expression T[last], the "last" index actually is one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"). + // For example for 5th element in table calculation is performed like this: + // + // mem::size_of::() + // | + // | `self = from_base_index(base, 5)` that returns pointer + // | that points here in tha data part of the table + // | (to the end of T5) + // | | `base: NonNull` must point here + // v | (to the end of T0 or to the start of C0) + // /???\ v v + // [Padding], Tlast, ..., |T10|, ..., T5|, T4, T3, T2, T1, T0, |C0, C1, C2, C3, C4, C5, ..., C10, ..., Clast + // \__________ __________/ + // \/ + // `bucket.to_base_index(base)` = 5 + // (base.as_ptr() as usize - self.ptr.as_ptr() as usize) / mem::size_of::() + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes or metadata for data. + if T::IS_ZERO_SIZED { + // this can not be UB self.ptr.as_ptr() as usize - 1 } else { offset_from(base.as_ptr(), self.ptr.as_ptr()) } } + + /// Acquires the underlying raw pointer `*mut T` to `data`. + /// + /// # Note + /// + /// If `T` is not [`Copy`], do not use `*mut T` methods that can cause calling the + /// destructor of `T` (for example the [`<*mut T>::drop_in_place`] method), because + /// for properly dropping the data we also need to clear `data` control bytes. If we + /// drop data, but do not clear `data control byte` it leads to double drop when + /// [`RawTable`] goes out of scope. + /// + /// If you modify an already initialized `value`, so [`Hash`] and [`Eq`] on the new + /// `T` value and its borrowed form *must* match those for the old `T` value, as the map + /// will not re-evaluate where the new value should go, meaning the value may become + /// "lost" if their location does not reflect their state. + /// + /// [`RawTable`]: crate::raw::RawTable + /// [`<*mut T>::drop_in_place`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.drop_in_place + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value = ("a", 100); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, i32)> = table.find(hash, |(k1, _)| k1 == &value.0).unwrap(); + /// + /// assert_eq!(unsafe { &*bucket.as_ptr() }, &("a", 100)); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` #[inline] pub fn as_ptr(&self) -> *mut T { - if mem::size_of::() == 0 { + if T::IS_ZERO_SIZED { // Just return an arbitrary ZST pointer which is properly aligned - mem::align_of::() as *mut T + // invalid pointer is good enough for ZST + invalid_mut(mem::align_of::()) } else { unsafe { self.ptr.as_ptr().sub(1) } } } + + /// Create a new [`Bucket`] that is offset from the `self` by the given + /// `offset`. The pointer calculation is performed by calculating the + /// offset from `self` pointer (convenience for `self.ptr.as_ptr().sub(offset)`). + /// This function is used for iterators. + /// + /// `offset` is in units of `T`; e.g., a `offset` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * `self` contained pointer must not be `dangling`; + /// + /// * `self.to_base_index() + ofset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + ofset) <= RawTableInner.bucket_mask` or, in other + /// words, `self.to_base_index() + ofset + 1` must be no greater than the number returned + /// by the function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `self.to_base_index() + ofset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + ofset) <= RawTableInner.bucket_mask` or, in other words, + /// `self.to_base_index() + ofset + 1` must be no greater than the number returned by the + /// function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets #[inline] unsafe fn next_n(&self, offset: usize) -> Self { - let ptr = if mem::size_of::() == 0 { - (self.ptr.as_ptr() as usize + offset) as *mut T + let ptr = if T::IS_ZERO_SIZED { + // invalid pointer is good enough for ZST + invalid_mut(self.ptr.as_ptr() as usize + offset) } else { self.ptr.as_ptr().sub(offset) }; @@ -330,26 +569,212 @@ impl Bucket { ptr: NonNull::new_unchecked(ptr), } } + + /// Executes the destructor (if any) of the pointed-to `data`. + /// + /// # Safety + /// + /// See [`ptr::drop_in_place`] for safety concerns. + /// + /// You should use [`RawTable::erase`] instead of this function, + /// or be careful with calling this function directly, because for + /// properly dropping the data we need also clear `data` control bytes. + /// If we drop data, but do not erase `data control byte` it leads to + /// double drop when [`RawTable`] goes out of scope. + /// + /// [`ptr::drop_in_place`]: https://doc.rust-lang.org/core/ptr/fn.drop_in_place.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::erase`]: crate::raw::RawTable::erase #[cfg_attr(feature = "inline-more", inline)] - pub unsafe fn drop(&self) { + pub(crate) unsafe fn drop(&self) { self.as_ptr().drop_in_place(); } + + /// Reads the `value` from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// # Safety + /// + /// See [`ptr::read`] for safety concerns. + /// + /// You should use [`RawTable::remove`] instead of this function, + /// or be careful with calling this function directly, because compiler + /// calls its destructor when readed `value` goes out of scope. It + /// can cause double dropping when [`RawTable`] goes out of scope, + /// because of not erased `data control byte`. + /// + /// [`ptr::read`]: https://doc.rust-lang.org/core/ptr/fn.read.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::remove`]: crate::raw::RawTable::remove #[inline] - pub unsafe fn read(&self) -> T { + pub(crate) unsafe fn read(&self) -> T { self.as_ptr().read() } + + /// Overwrites a memory location with the given `value` without reading + /// or dropping the old value (like [`ptr::write`] function). + /// + /// # Safety + /// + /// See [`ptr::write`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`ptr::write`]: https://doc.rust-lang.org/core/ptr/fn.write.html + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html #[inline] - pub unsafe fn write(&self, val: T) { + pub(crate) unsafe fn write(&self, val: T) { self.as_ptr().write(val); } + + /// Returns a shared immutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_ref`] for safety concerns. + /// + /// [`NonNull::as_ref`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_ref + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value: (&str, String) = ("A pony", "is a small horse".to_owned()); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, String)> = table.find(hash, |(k, _)| k == &value.0).unwrap(); + /// + /// assert_eq!( + /// unsafe { bucket.as_ref() }, + /// &("A pony", "is a small horse".to_owned()) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` #[inline] pub unsafe fn as_ref<'a>(&self) -> &'a T { &*self.as_ptr() } + + /// Returns a unique mutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_mut`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`NonNull::as_mut`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_mut + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value: (&str, String) = ("A pony", "is a small horse".to_owned()); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, String)> = table.find(hash, |(k, _)| k == &value.0).unwrap(); + /// + /// unsafe { + /// bucket + /// .as_mut() + /// .1 + /// .push_str(" less than 147 cm at the withers") + /// }; + /// assert_eq!( + /// unsafe { bucket.as_ref() }, + /// &( + /// "A pony", + /// "is a small horse less than 147 cm at the withers".to_owned() + /// ) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` #[inline] pub unsafe fn as_mut<'a>(&self) -> &'a mut T { &mut *self.as_ptr() } + + /// Copies `size_of` bytes from `other` to `self`. The source + /// and destination may *not* overlap. + /// + /// # Safety + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns. + /// + /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of + /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values + /// in the region beginning at `*self` and the region beginning at `*other` can + /// [violate memory safety]. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`ptr::copy_nonoverlapping`]: https://doc.rust-lang.org/core/ptr/fn.copy_nonoverlapping.html + /// [`read`]: https://doc.rust-lang.org/core/ptr/fn.read.html + /// [violate memory safety]: https://doc.rust-lang.org/std/ptr/fn.read.html#ownership-of-the-returned-value + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html #[cfg(feature = "raw")] #[inline] pub unsafe fn copy_from_nonoverlapping(&self, other: &Self) { @@ -358,15 +783,16 @@ impl Bucket { } /// A raw hash table with an unsafe API. -pub struct RawTable { - table: RawTableInner, +pub struct RawTable { + table: RawTableInner, + alloc: A, // Tell dropck that we own instances of T. marker: PhantomData, } /// Non-generic part of `RawTable` which allows functions to be instantiated only once regardless /// of how many different key-value types are used. -struct RawTableInner { +struct RawTableInner { // Mask to get an index from a hash value. The value is one less than the // number of buckets in the table. bucket_mask: usize, @@ -380,8 +806,6 @@ struct RawTableInner { // Number of elements in the table, only really used by len() items: usize, - - alloc: A, } impl RawTable { @@ -393,7 +817,8 @@ impl RawTable { #[inline] pub const fn new() -> Self { Self { - table: RawTableInner::new_in(Global), + table: RawTableInner::NEW, + alloc: Global, marker: PhantomData, } } @@ -412,7 +837,9 @@ impl RawTable { } } -impl RawTable { +impl RawTable { + const TABLE_LAYOUT: TableLayout = TableLayout::new::(); + /// Creates a new empty hash table without allocating any memory, using the /// given allocator. /// @@ -420,9 +847,10 @@ impl RawTable { /// leave the data pointer dangling since that bucket is never written to /// due to our load factor forcing us to always have at least 1 free bucket. #[inline] - pub fn new_in(alloc: A) -> Self { + pub const fn new_in(alloc: A) -> Self { Self { - table: RawTableInner::new_in(alloc), + table: RawTableInner::NEW, + alloc, marker: PhantomData, } } @@ -440,73 +868,97 @@ impl RawTable { Ok(Self { table: RawTableInner::new_uninitialized( - alloc, - TableLayout::new::(), + &alloc, + Self::TABLE_LAYOUT, buckets, fallibility, )?, + alloc, marker: PhantomData, }) } - /// Attempts to allocate a new hash table with at least enough capacity - /// for inserting the given number of elements without reallocating. - fn fallible_with_capacity( - alloc: A, - capacity: usize, - fallibility: Fallibility, - ) -> Result { + /// Attempts to allocate a new hash table using the given allocator, with at least enough + /// capacity for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { Ok(Self { table: RawTableInner::fallible_with_capacity( - alloc, - TableLayout::new::(), + &alloc, + Self::TABLE_LAYOUT, capacity, - fallibility, + Fallibility::Fallible, )?, + alloc, marker: PhantomData, }) } - /// Attempts to allocate a new hash table using the given allocator, with at least enough - /// capacity for inserting the given number of elements without reallocating. - #[cfg(feature = "raw")] - pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { - Self::fallible_with_capacity(alloc, capacity, Fallibility::Fallible) - } - /// Allocates a new hash table using the given allocator, with at least enough capacity for /// inserting the given number of elements without reallocating. pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { - // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - match Self::fallible_with_capacity(alloc, capacity, Fallibility::Infallible) { - Ok(capacity) => capacity, - Err(_) => unsafe { hint::unreachable_unchecked() }, + Self { + table: RawTableInner::with_capacity(&alloc, Self::TABLE_LAYOUT, capacity), + alloc, + marker: PhantomData, } } /// Returns a reference to the underlying allocator. #[inline] pub fn allocator(&self) -> &A { - &self.table.alloc + &self.alloc } - /// Deallocates the table without dropping any entries. - #[cfg_attr(feature = "inline-more", inline)] - unsafe fn free_buckets(&mut self) { - self.table.free_buckets(TableLayout::new::()); + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub fn data_end(&self) -> NonNull { + // `self.table.ctrl.cast()` returns pointer that + // points here (to the end of `T0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTable::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + self.table.ctrl.cast() } - /// Returns pointer to one past last element of data table. + /// Returns pointer to start of data table. #[inline] - pub unsafe fn data_end(&self) -> NonNull { - NonNull::new_unchecked(self.table.ctrl.as_ptr().cast()) + #[cfg(any(feature = "raw", feature = "nightly"))] + pub unsafe fn data_start(&self) -> NonNull { + NonNull::new_unchecked(self.data_end().as_ptr().wrapping_sub(self.buckets())) } - /// Returns pointer to start of data table. + /// Return the information about memory allocated by the table. + /// + /// `RawTable` allocates single memory block to store both data and metadata. + /// This function returns allocation size and alignment and the beginning of the area. + /// These are the arguments which will be passed to `dealloc` when the table is dropped. + /// + /// This function might be useful for memory profiling. #[inline] - #[cfg(feature = "nightly")] - pub unsafe fn data_start(&self) -> *mut T { - self.data_end().as_ptr().wrapping_sub(self.buckets()) + #[cfg(feature = "raw")] + pub fn allocation_info(&self) -> (NonNull, Layout) { + // SAFETY: We use the same `table_layout` that was used to allocate + // this table. + unsafe { self.table.allocation_info_or_zero(Self::TABLE_LAYOUT) } } /// Returns the index of a bucket from a `Bucket`. @@ -516,8 +968,55 @@ impl RawTable { } /// Returns a pointer to an element in the table. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the caller of this function must observe the + /// following safety rules: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTable::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// [`RawTable::buckets`]: RawTable::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] pub unsafe fn bucket(&self, index: usize) -> Bucket { + // If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + // (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + // the "buckets" number of our `RawTable`, i.e. "n = RawTable::buckets() - 1"): + // + // `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + // part of the `RawTable`, i.e. to the start of T3 (see `Bucket::as_ptr`) + // | + // | `base = self.data_end()` points here + // | (to the start of CT0 or to the end of T0) + // v v + // [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + // ^ \__________ __________/ + // `table.bucket(3)` returns a pointer that points \/ + // here in the `data` part of the `RawTable` (to additional control bytes + // the end of T3) `m = Group::WIDTH - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`; + // CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + // the heap works properly, even if the result of `h1(hash) & self.table.bucket_mask` + // is equal to `self.table.bucket_mask`). See also `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.table.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.table.bucket_mask = self.buckets() - 1`. debug_assert_ne!(self.table.bucket_mask, 0); debug_assert!(index < self.buckets()); Bucket::from_base_index(self.data_end(), index) @@ -525,8 +1024,7 @@ impl RawTable { /// Erases an element from the table without dropping it. #[cfg_attr(feature = "inline-more", inline)] - #[deprecated(since = "0.8.1", note = "use erase or remove instead")] - pub unsafe fn erase_no_drop(&mut self, item: &Bucket) { + unsafe fn erase_no_drop(&mut self, item: &Bucket) { let index = self.bucket_index(item); self.table.erase(index); } @@ -534,7 +1032,6 @@ impl RawTable { /// Erases an element from the table, dropping it in place. #[cfg_attr(feature = "inline-more", inline)] #[allow(clippy::needless_pass_by_value)] - #[allow(deprecated)] pub unsafe fn erase(&mut self, item: Bucket) { // Erase the element from the table first since drop might panic. self.erase_no_drop(&item); @@ -558,12 +1055,18 @@ impl RawTable { } /// Removes an element from the table, returning it. + /// + /// This also returns an `InsertSlot` pointing to the newly free bucket. #[cfg_attr(feature = "inline-more", inline)] #[allow(clippy::needless_pass_by_value)] - #[allow(deprecated)] - pub unsafe fn remove(&mut self, item: Bucket) -> T { + pub unsafe fn remove(&mut self, item: Bucket) -> (T, InsertSlot) { self.erase_no_drop(&item); - item.read() + ( + item.read(), + InsertSlot { + index: self.bucket_index(&item), + }, + ) } /// Finds and removes an element from the table, returning it. @@ -571,7 +1074,7 @@ impl RawTable { pub fn remove_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option { // Avoid `Option::map` because it bloats LLVM IR. match self.find(hash, eq) { - Some(bucket) => Some(unsafe { self.remove(bucket) }), + Some(bucket) => Some(unsafe { self.remove(bucket).0 }), None => None, } } @@ -585,18 +1088,17 @@ impl RawTable { /// Removes all elements from the table without freeing the backing memory. #[cfg_attr(feature = "inline-more", inline)] pub fn clear(&mut self) { + if self.is_empty() { + // Special case empty table to avoid surprising O(capacity) time. + return; + } // Ensure that the table is reset even if one of the drops panic let mut self_ = guard(self, |self_| self_.clear_no_drop()); unsafe { - self_.drop_elements(); - } - } - - unsafe fn drop_elements(&mut self) { - if mem::needs_drop::() && !self.is_empty() { - for item in self.iter() { - item.drop(); - } + // SAFETY: ScopeGuard sets to zero the `items` field of the table + // even in case of panic during the dropping of the elements so + // that there will be no double drop of the elements. + self_.table.drop_elements::(); } } @@ -607,7 +1109,16 @@ impl RawTable { // space for. let min_size = usize::max(self.table.items, min_size); if min_size == 0 { - *self = Self::new_in(self.table.alloc.clone()); + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } return; } @@ -624,14 +1135,33 @@ impl RawTable { if min_buckets < self.buckets() { // Fast path if the table is empty if self.table.items == 0 { - *self = Self::with_capacity_in(min_size, self.table.alloc.clone()); + let new_inner = + RawTableInner::with_capacity(&self.alloc, Self::TABLE_LAYOUT, min_size); + let mut old_inner = mem::replace(&mut self.table, new_inner); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } } else { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - if self - .resize(min_size, hasher, Fallibility::Infallible) - .is_err() - { - unsafe { hint::unreachable_unchecked() } + unsafe { + // SAFETY: + // 1. We know for sure that `min_size >= self.table.items`. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + if self + .resize(min_size, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: The result of calling the `resize` function cannot be an error + // because `fallibility == Fallibility::Infallible. + hint::unreachable_unchecked() + } } } } @@ -641,13 +1171,18 @@ impl RawTable { /// without reallocation. #[cfg_attr(feature = "inline-more", inline)] pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { - if additional > self.table.growth_left { + if unlikely(additional > self.table.growth_left) { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - if self - .reserve_rehash(additional, hasher, Fallibility::Infallible) - .is_err() - { - unsafe { hint::unreachable_unchecked() } + unsafe { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + if self + .reserve_rehash(additional, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: All allocation errors will be caught inside `RawTableInner::reserve_rehash`. + hint::unreachable_unchecked() + } } } } @@ -661,28 +1196,45 @@ impl RawTable { hasher: impl Fn(&T) -> u64, ) -> Result<(), TryReserveError> { if additional > self.table.growth_left { - self.reserve_rehash(additional, hasher, Fallibility::Fallible) + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + unsafe { self.reserve_rehash(additional, hasher, Fallibility::Fallible) } } else { Ok(()) } } /// Out-of-line slow path for `reserve` and `try_reserve`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[cold] #[inline(never)] - fn reserve_rehash( + unsafe fn reserve_rehash( &mut self, additional: usize, hasher: impl Fn(&T) -> u64, fallibility: Fallibility, ) -> Result<(), TryReserveError> { unsafe { + // SAFETY: + // 1. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 2. The `drop` function is the actual drop function of the elements stored in + // the table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. self.table.reserve_rehash_inner( + &self.alloc, additional, &|table, index| hasher(table.bucket::(index).as_ref()), fallibility, - TableLayout::new::(), - if mem::needs_drop::() { + Self::TABLE_LAYOUT, + if T::NEEDS_DROP { Some(mem::transmute(ptr::drop_in_place:: as unsafe fn(*mut T))) } else { None @@ -693,20 +1245,50 @@ impl RawTable { /// Allocates a new table of a different size and moves the contents of the /// current table into it. - fn resize( + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// The caller of this function must ensure that `capacity >= self.table.items` + /// otherwise: + /// + /// * If `self.table.items != 0`, calling of this function with `capacity` + /// equal to 0 (`capacity == 0`) results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.table.items > capacity_to_buckets(capacity)` + /// calling this function results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.table.items > capacity_to_buckets(capacity)` + /// calling this function are never return (will go into an + /// infinite loop). + /// + /// See [`RawTableInner::find_insert_slot`] for more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn resize( &mut self, capacity: usize, hasher: impl Fn(&T) -> u64, fallibility: Fallibility, ) -> Result<(), TryReserveError> { - unsafe { - self.table.resize_inner( - capacity, - &|table, index| hasher(table.bucket::(index).as_ref()), - fallibility, - TableLayout::new::(), - ) - } + // SAFETY: + // 1. The caller of this function guarantees that `capacity >= self.table.items`. + // 2. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.resize_inner( + &self.alloc, + capacity, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + ) } /// Inserts a new element into the table, and returns its raw bucket. @@ -715,22 +1297,27 @@ impl RawTable { #[cfg_attr(feature = "inline-more", inline)] pub fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket { unsafe { - let mut index = self.table.find_insert_slot(hash); + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose `RawTable::new_uninitialized` in a public API. + // + // 2. We reserve additional space (if necessary) right after calling this function. + let mut slot = self.table.find_insert_slot(hash); - // We can avoid growing the table once we have reached our load - // factor if we are replacing a tombstone. This works since the - // number of EMPTY slots does not change in this case. - let old_ctrl = *self.table.ctrl(index); + // We can avoid growing the table once we have reached our load factor if we are replacing + // a tombstone. This works since the number of EMPTY slots does not change in this case. + // + // SAFETY: The function is guaranteed to return [`InsertSlot`] that contains an index + // in the range `0..=self.buckets()`. + let old_ctrl = *self.table.ctrl(slot.index); if unlikely(self.table.growth_left == 0 && special_is_empty(old_ctrl)) { self.reserve(1, hasher); - index = self.table.find_insert_slot(hash); + // SAFETY: We know for sure that `RawTableInner` has control bytes + // initialized and that there is extra space in the table. + slot = self.table.find_insert_slot(hash); } - self.table.record_item_insert_at(index, old_ctrl, hash); - - let bucket = self.bucket(index); - bucket.write(value); - bucket + self.insert_in_slot(hash, slot, value) } } @@ -796,9 +1383,9 @@ impl RawTable { { let index = self.bucket_index(&bucket); let old_ctrl = *self.table.ctrl(index); - debug_assert!(is_full(old_ctrl)); + debug_assert!(self.is_bucket_full(index)); let old_growth_left = self.table.growth_left; - let item = self.remove(bucket); + let item = self.remove(bucket).0; if let Some(new_item) = f(item) { self.table.growth_left = old_growth_left; self.table.set_ctrl(index, old_ctrl); @@ -810,29 +1397,90 @@ impl RawTable { } } - /// Searches for an element in the table. + /// Searches for an element in the table. If the element is not found, + /// returns `Err` with the position of a slot where an element with the + /// same hash could be inserted. + /// + /// This function may resize the table if additional space is required for + /// inserting an element. #[inline] - pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { - let result = self.table.find_inner(hash, &mut |index| unsafe { - eq(self.bucket(index).as_ref()) - }); + pub fn find_or_find_insert_slot( + &mut self, + hash: u64, + mut eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Result, InsertSlot> { + self.reserve(1, hasher); - // Avoid `Option::map` because it bloats LLVM IR. - match result { - Some(index) => Some(unsafe { self.bucket(index) }), - None => None, + unsafe { + // SAFETY: + // 1. We know for sure that there is at least one empty `bucket` in the table. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since we will + // never expose `RawTable::new_uninitialized` in a public API. + // 3. The `find_or_find_insert_slot_inner` function returns the `index` of only the full bucket, + // which is in the range `0..self.buckets()` (since there is at least one empty `bucket` in + // the table), so calling `self.bucket(index)` and `Bucket::as_ref` is safe. + match self + .table + .find_or_find_insert_slot_inner(hash, &mut |index| eq(self.bucket(index).as_ref())) + { + // SAFETY: See explanation above. + Ok(index) => Ok(self.bucket(index)), + Err(slot) => Err(slot), + } } } - /// Gets a reference to an element in the table. + /// Inserts a new element into the table in the given slot, and returns its + /// raw bucket. + /// + /// # Safety + /// + /// `slot` must point to a slot previously returned by + /// `find_or_find_insert_slot`, and no mutation of the table must have + /// occurred since that call. #[inline] - pub fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { - // Avoid `Option::map` because it bloats LLVM IR. - match self.find(hash, eq) { - Some(bucket) => Some(unsafe { bucket.as_ref() }), - None => None, - } - } + pub unsafe fn insert_in_slot(&mut self, hash: u64, slot: InsertSlot, value: T) -> Bucket { + let old_ctrl = *self.table.ctrl(slot.index); + self.table.record_item_insert_at(slot.index, old_ctrl, hash); + + let bucket = self.bucket(slot.index); + bucket.write(value); + bucket + } + + /// Searches for an element in the table. + #[inline] + pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since we + // will never expose `RawTable::new_uninitialized` in a public API. + // 1. The `find_inner` function returns the `index` of only the full bucket, which is in + // the range `0..self.buckets()`, so calling `self.bucket(index)` and `Bucket::as_ref` + // is safe. + let result = self + .table + .find_inner(hash, &mut |index| eq(self.bucket(index).as_ref())); + + // Avoid `Option::map` because it bloats LLVM IR. + match result { + // SAFETY: See explanation above. + Some(index) => Some(self.bucket(index)), + None => None, + } + } + } + + /// Gets a reference to an element in the table. + #[inline] + pub fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } /// Gets a mutable reference to an element in the table. #[inline] @@ -928,17 +1576,27 @@ impl RawTable { self.table.bucket_mask + 1 } + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + pub unsafe fn is_bucket_full(&self, index: usize) -> bool { + self.table.is_bucket_full(index) + } + /// Returns an iterator over every element in the table. It is up to /// the caller to ensure that the `RawTable` outlives the `RawIter`. /// Because we cannot make the `next` method unsafe on the `RawIter` /// struct, we have to make the `iter` method unsafe. #[inline] pub unsafe fn iter(&self) -> RawIter { - let data = Bucket::from_base_index(self.data_end(), 0); - RawIter { - iter: RawIterRange::new(self.table.ctrl.as_ptr(), data, self.table.buckets()), - items: self.table.items, - } + // SAFETY: + // 1. The caller must uphold the safety contract for `iter` method. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + self.table.iter() } /// Returns an iterator over occupied buckets that could match a given hash. @@ -952,7 +1610,7 @@ impl RawTable { /// `RawIterHash` struct, we have to make the `iter_hash` method unsafe. #[cfg_attr(feature = "inline-more", inline)] #[cfg(feature = "raw")] - pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash<'_, T, A> { + pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash { RawIterHash::new(self, hash) } @@ -978,8 +1636,8 @@ impl RawTable { debug_assert_eq!(iter.len(), self.len()); RawDrain { iter, - table: ManuallyDrop::new(mem::replace(self, Self::new_in(self.table.alloc.clone()))), - orig_table: NonNull::from(self), + table: mem::replace(&mut self.table, RawTableInner::NEW), + orig_table: NonNull::from(&mut self.table), marker: PhantomData, } } @@ -993,31 +1651,31 @@ impl RawTable { pub unsafe fn into_iter_from(self, iter: RawIter) -> RawIntoIter { debug_assert_eq!(iter.len(), self.len()); - let alloc = self.table.alloc.clone(); let allocation = self.into_allocation(); RawIntoIter { iter, allocation, marker: PhantomData, - alloc, } } /// Converts the table into a raw allocation. The contents of the table /// should be dropped using a `RawIter` before freeing the allocation. #[cfg_attr(feature = "inline-more", inline)] - pub(crate) fn into_allocation(self) -> Option<(NonNull, Layout)> { + pub(crate) fn into_allocation(self) -> Option<(NonNull, Layout, A)> { let alloc = if self.table.is_empty_singleton() { None } else { // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. - let (layout, ctrl_offset) = match calculate_layout::(self.table.buckets()) { - Some(lco) => lco, - None => unsafe { hint::unreachable_unchecked() }, - }; + let (layout, ctrl_offset) = + match Self::TABLE_LAYOUT.calculate_layout_for(self.table.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; Some(( unsafe { NonNull::new_unchecked(self.table.ctrl.as_ptr().sub(ctrl_offset)) }, layout, + unsafe { ptr::read(&self.alloc) }, )) }; mem::forget(self); @@ -1025,41 +1683,62 @@ impl RawTable { } } -unsafe impl Send for RawTable +unsafe impl Send for RawTable where T: Send, A: Send, { } -unsafe impl Sync for RawTable +unsafe impl Sync for RawTable where T: Sync, A: Sync, { } -impl RawTableInner { +impl RawTableInner { + const NEW: Self = RawTableInner::new(); + + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never accessed + /// due to our load factor forcing us to always have at least 1 free bucket. #[inline] - const fn new_in(alloc: A) -> Self { + const fn new() -> Self { Self { // Be careful to cast the entire slice to a raw pointer. ctrl: unsafe { NonNull::new_unchecked(Group::static_empty() as *const _ as *mut u8) }, bucket_mask: 0, items: 0, growth_left: 0, - alloc, } } } -impl RawTableInner { +impl RawTableInner { + /// Allocates a new [`RawTableInner`] with the given number of buckets. + /// The control bytes and buckets are left uninitialized. + /// + /// # Safety + /// + /// The caller of this function must ensure that the `buckets` is power of two + /// and also initialize all control bytes of the length `self.bucket_mask + 1 + + /// Group::WIDTH` with the [`EMPTY`] bytes. + /// + /// See also [`Allocator`] API for other safety concerns. + /// + /// [`Allocator`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html #[cfg_attr(feature = "inline-more", inline)] - unsafe fn new_uninitialized( - alloc: A, + unsafe fn new_uninitialized( + alloc: &A, table_layout: TableLayout, buckets: usize, fallibility: Fallibility, - ) -> Result { + ) -> Result + where + A: Allocator, + { debug_assert!(buckets.is_power_of_two()); // Avoid `Option::ok_or_else` because it bloats LLVM IR. @@ -1068,45 +1747,48 @@ impl RawTableInner { None => return Err(fallibility.capacity_overflow()), }; - // We need an additional check to ensure that the allocation doesn't - // exceed `isize::MAX`. We can skip this check on 64-bit systems since - // such allocations will never succeed anyways. - // - // This mirrors what Vec does in the standard library. - if mem::size_of::() < 8 && layout.size() > isize::MAX as usize { - return Err(fallibility.capacity_overflow()); - } - - let ptr: NonNull = match do_alloc(&alloc, layout) { + let ptr: NonNull = match do_alloc(alloc, layout) { Ok(block) => block.cast(), Err(_) => return Err(fallibility.alloc_err(layout)), }; + // SAFETY: null pointer will be caught in above check let ctrl = NonNull::new_unchecked(ptr.as_ptr().add(ctrl_offset)); Ok(Self { ctrl, bucket_mask: buckets - 1, items: 0, growth_left: bucket_mask_to_capacity(buckets - 1), - alloc, }) } + /// Attempts to allocate a new [`RawTableInner`] with at least enough + /// capacity for inserting the given number of elements without reallocating. + /// + /// All the control bytes are initialized with the [`EMPTY`] bytes. #[inline] - fn fallible_with_capacity( - alloc: A, + fn fallible_with_capacity( + alloc: &A, table_layout: TableLayout, capacity: usize, fallibility: Fallibility, - ) -> Result { + ) -> Result + where + A: Allocator, + { if capacity == 0 { - Ok(Self::new_in(alloc)) + Ok(Self::NEW) } else { + // SAFETY: We checked that we could successfully allocate the new table, and then + // initialized all control bytes with the constant `EMPTY` byte. unsafe { let buckets = capacity_to_buckets(capacity).ok_or_else(|| fallibility.capacity_overflow())?; let result = Self::new_uninitialized(alloc, table_layout, buckets, fallibility)?; + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `self.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. result.ctrl(0).write_bytes(EMPTY, result.num_ctrl_bytes()); Ok(result) @@ -1114,66 +1796,397 @@ impl RawTableInner { } } - /// Searches for an empty or deleted bucket which is suitable for inserting - /// a new element and sets the hash for that slot. + /// Allocates a new [`RawTableInner`] with at least enough capacity for inserting + /// the given number of elements without reallocating. + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`fallible_with_capacity`] instead if you want to + /// handle memory allocation failure. + /// + /// All the control bytes are initialized with the [`EMPTY`] bytes. + /// + /// [`fallible_with_capacity`]: RawTableInner::fallible_with_capacity + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + fn with_capacity(alloc: &A, table_layout: TableLayout, capacity: usize) -> Self + where + A: Allocator, + { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + match Self::fallible_with_capacity(alloc, table_layout, capacity, Fallibility::Infallible) { + Ok(table_inner) => table_inner, + // SAFETY: All allocation errors will be caught inside `RawTableInner::new_uninitialized`. + Err(_) => unsafe { hint::unreachable_unchecked() }, + } + } + + /// Fixes up an insertion slot returned by the [`RawTableInner::find_insert_slot_in_group`] method. + /// + /// In tables smaller than the group width (`self.buckets() < Group::WIDTH`), trailing control + /// bytes outside the range of the table are filled with [`EMPTY`] entries. These will unfortunately + /// trigger a match of [`RawTableInner::find_insert_slot_in_group`] function. This is because + /// the `Some(bit)` returned by `group.match_empty_or_deleted().lowest_set_bit()` after masking + /// (`(probe_seq.pos + bit) & self.bucket_mask`) may point to a full bucket that is already occupied. + /// We detect this situation here and perform a second scan starting at the beginning of the table. + /// This second scan is guaranteed to find an empty slot (due to the load factor) before hitting the + /// trailing control bytes (containing [`EMPTY`] bytes). + /// + /// If this function is called correctly, it is guaranteed to return [`InsertSlot`] with an + /// index of an empty or deleted bucket in the range `0..self.buckets()` (see `Warning` and + /// `Safety`). + /// + /// # Warning + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise if the table is less than + /// the group width (`self.buckets() < Group::WIDTH`) this function returns an index outside of the + /// table indices range `0..self.buckets()` (`0..=self.bucket_mask`). Attempt to write data at that + /// index will cause immediate [`undefined behavior`]. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::ctrl`] method. + /// Thus, in order to uphold those safety contracts, as well as for the correct logic of the work + /// of this crate, the following rules are necessary and sufficient: + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise calling this + /// function results in [`undefined behavior`]. + /// + /// * This function must only be used on insertion slots found by [`RawTableInner::find_insert_slot_in_group`] + /// (after the `find_insert_slot_in_group` function, but before insertion into the table). + /// + /// * The `index` must not be greater than the `self.bucket_mask`, i.e. `(index + 1) <= self.buckets()` + /// (this one is provided by the [`RawTableInner::find_insert_slot_in_group`] function). + /// + /// Calling this function with an index not provided by [`RawTableInner::find_insert_slot_in_group`] + /// may result in [`undefined behavior`] even if the index satisfies the safety rules of the + /// [`RawTableInner::ctrl`] function (`index < self.bucket_mask + 1 + Group::WIDTH`). + /// + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::find_insert_slot_in_group`]: RawTableInner::find_insert_slot_in_group + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn fix_insert_slot(&self, mut index: usize) -> InsertSlot { + // SAFETY: The caller of this function ensures that `index` is in the range `0..=self.bucket_mask`. + if unlikely(self.is_bucket_full(index)) { + debug_assert!(self.bucket_mask < Group::WIDTH); + // SAFETY: + // + // * Since the caller of this function ensures that the control bytes are properly + // initialized and `ptr = self.ctrl(0)` points to the start of the array of control + // bytes, therefore: `ctrl` is valid for reads, properly aligned to `Group::WIDTH` + // and points to the properly initialized control bytes (see also + // `TableLayout::calculate_layout_for` and `ptr::read`); + // + // * Because the caller of this function ensures that the index was provided by the + // `self.find_insert_slot_in_group()` function, so for for tables larger than the + // group width (self.buckets() >= Group::WIDTH), we will never end up in the given + // branch, since `(probe_seq.pos + bit) & self.bucket_mask` in `find_insert_slot_in_group` + // cannot return a full bucket index. For tables smaller than the group width, calling + // the `unwrap_unchecked` function is also safe, as the trailing control bytes outside + // the range of the table are filled with EMPTY bytes (and we know for sure that there + // is at least one FULL bucket), so this second scan either finds an empty slot (due to + // the load factor) or hits the trailing control bytes (containing EMPTY). + index = Group::load_aligned(self.ctrl(0)) + .match_empty_or_deleted() + .lowest_set_bit() + .unwrap_unchecked(); + } + InsertSlot { index } + } + + /// Finds the position to insert something in a group. + /// + /// **This may have false positives and must be fixed up with `fix_insert_slot` + /// before it's used.** + /// + /// The function is guaranteed to return the index of an empty or deleted [`Bucket`] + /// in the range `0..self.buckets()` (`0..=self.bucket_mask`). + #[inline] + fn find_insert_slot_in_group(&self, group: &Group, probe_seq: &ProbeSeq) -> Option { + let bit = group.match_empty_or_deleted().lowest_set_bit(); + + if likely(bit.is_some()) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + Some((probe_seq.pos + bit.unwrap()) & self.bucket_mask) + } else { + None + } + } + + /// Searches for an element in the table, or a potential slot where that element could + /// be inserted (an empty or deleted [`Bucket`] index). + /// + /// This uses dynamic dispatch to reduce the amount of code generated, but that is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element (as `Ok(index)`). If the element is not found and there is at least 1 + /// empty or deleted [`Bucket`] in the table, the function is guaranteed to return + /// [InsertSlot] with an index in the range `0..self.buckets()`, but in any case, + /// if this function returns [`InsertSlot`], it will contain an index in the range + /// `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. /// - /// There must be at least 1 empty bucket in the table. + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] - unsafe fn prepare_insert_slot(&self, hash: u64) -> (usize, u8) { - let index = self.find_insert_slot(hash); + unsafe fn find_or_find_insert_slot_inner( + &self, + hash: u64, + eq: &mut dyn FnMut(usize) -> bool, + ) -> Result { + let mut insert_slot = None; + + let h2_hash = h2(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because mumber of + // buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_byte(h2_hash) { + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Ok(index); + } + } + + // We didn't find the element we were looking for in the group, try to get an + // insertion slot from the group if we don't have one yet. + if likely(insert_slot.is_none()) { + insert_slot = self.find_insert_slot_in_group(&group, &probe_seq); + } + + // Only stop the search if the group contains at least one empty element. + // Otherwise, the element that we are looking for might be in a following group. + if likely(group.match_empty().any_bit_set()) { + // We must have found a insert slot by now, since the current group contains at + // least one. For tables smaller than the group width, there will still be an + // empty element in the current (and only) group due to the load factor. + unsafe { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + return Err(self.fix_insert_slot(insert_slot.unwrap_unchecked())); + } + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an empty or deleted bucket which is suitable for inserting a new + /// element and sets the hash for that slot. Returns an index of that slot and the + /// old control byte stored in the found index. + /// + /// This function does not check if the given element exists in the table. Also, + /// this function does not check if there is enough space in the table to insert + /// a new element. Caller of the funtion must make ensure that the table has at + /// least 1 empty or deleted `bucket`, otherwise this function will never return + /// (will go into an infinite loop) for tables larger than the group width, or + /// return an index outside of the table indices range if the table is less than + /// the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return an `index` in the range `0..self.buckets()`, but in any case, + /// if this function returns an `index` it will be in the range `0..=self.buckets()`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for the + /// [`RawTableInner::set_ctrl_h2`] and [`RawTableInner::find_insert_slot`] methods. + /// Thus, in order to uphold the safety contracts for that methods, as well as for + /// the correct logic of the work of this crate, you must observe the following rules + /// when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated and has properly initialized + /// control bytes otherwise calling this function results in [`undefined behavior`]. + /// + /// * The caller of this function must ensure that the "data" parts of the table + /// will have an entry in the returned index (matching the given hash) right + /// after calling this function. + /// + /// Attempt to write data at the `index` returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// The caller must independently increase the `items` field of the table, and also, + /// if the old control byte was [`EMPTY`], then decrease the table's `growth_left` + /// field, and do not change it if the old control byte was [`DELETED`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::set_ctrl_h2`]: RawTableInner::set_ctrl_h2 + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + #[inline] + unsafe fn prepare_insert_slot(&mut self, hash: u64) -> (usize, u8) { + // SAFETY: Caller of this function ensures that the control bytes are properly initialized. + let index: usize = self.find_insert_slot(hash).index; + // SAFETY: + // 1. The `find_insert_slot` function either returns an `index` less than or + // equal to `self.buckets() = self.bucket_mask + 1` of the table, or never + // returns if it cannot find an empty or deleted slot. + // 2. The caller of this function guarantees that the table has already been + // allocated let old_ctrl = *self.ctrl(index); self.set_ctrl_h2(index, hash); (index, old_ctrl) } /// Searches for an empty or deleted bucket which is suitable for inserting - /// a new element. + /// a new element, returning the `index` for the new [`Bucket`]. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return [`InsertSlot`] with an index in the range `0..self.buckets()`, + /// but in any case, if this function returns [`InsertSlot`], it will contain an index + /// in the range `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. /// - /// There must be at least 1 empty bucket in the table. + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] - fn find_insert_slot(&self, hash: u64) -> usize { + unsafe fn find_insert_slot(&self, hash: u64) -> InsertSlot { let mut probe_seq = self.probe_seq(hash); loop { - unsafe { - let group = Group::load(self.ctrl(probe_seq.pos)); - if let Some(bit) = group.match_empty_or_deleted().lowest_set_bit() { - let result = (probe_seq.pos + bit) & self.bucket_mask; - - // In tables smaller than the group width, trailing control - // bytes outside the range of the table are filled with - // EMPTY entries. These will unfortunately trigger a - // match, but once masked may point to a full bucket that - // is already occupied. We detect this situation here and - // perform a second scan starting at the beginning of the - // table. This second scan is guaranteed to find an empty - // slot (due to the load factor) before hitting the trailing - // control bytes (containing EMPTY). - if unlikely(is_full(*self.ctrl(result))) { - debug_assert!(self.bucket_mask < Group::WIDTH); - debug_assert_ne!(probe_seq.pos, 0); - return Group::load_aligned(self.ctrl(0)) - .match_empty_or_deleted() - .lowest_set_bit_nonzero(); - } + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because mumber of + // buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; - return result; + let index = self.find_insert_slot_in_group(&group, &probe_seq); + if likely(index.is_some()) { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + unsafe { + return self.fix_insert_slot(index.unwrap_unchecked()); } } probe_seq.move_next(self.bucket_mask); } } - /// Searches for an element in the table. This uses dynamic dispatch to reduce the amount of - /// code generated, but it is eliminated by LLVM optimizations. - #[inline] - fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option { + /// Searches for an element in a table, returning the `index` of the found element. + /// This uses dynamic dispatch to reduce the amount of code generated, but it is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, + /// this function will also never return (will go into an infinite loop). + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element as `Some(index)`, so the index will always be in the range + /// `0..self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option { let h2_hash = h2(hash); let mut probe_seq = self.probe_seq(hash); loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask`. + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new_in). let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; for bit in group.match_byte(h2_hash) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. let index = (probe_seq.pos + bit) & self.bucket_mask; if likely(eq(index)) { @@ -1189,12 +2202,52 @@ impl RawTableInner { } } + /// Prepares for rehashing data in place (that is, without allocating new memory). + /// Converts all full index `control bytes` to `DELETED` and all `DELETED` control + /// bytes to `EMPTY`, i.e. performs the following conversion: + /// + /// - `EMPTY` control bytes -> `EMPTY`; + /// - `DELETED` control bytes -> `EMPTY`; + /// - `FULL` control bytes -> `DELETED`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The caller of this function must convert the `DELETED` bytes back to `FULL` + /// bytes when re-inserting them into their ideal position (which was impossible + /// to do during the first insert due to tombstones). If the caller does not do + /// this, then calling this function may result in a memory leak. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise + /// calling this function results in [`undefined behavior`]. + /// + /// Calling this function on a table that has not been allocated results in + /// [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[allow(clippy::mut_mut)] #[inline] unsafe fn prepare_rehash_in_place(&mut self) { - // Bulk convert all full control bytes to DELETED, and all DELETED - // control bytes to EMPTY. This effectively frees up all buckets - // containing a DELETED entry. + // Bulk convert all full control bytes to DELETED, and all DELETED control bytes to EMPTY. + // This effectively frees up all buckets containing a DELETED entry. + // + // SAFETY: + // 1. `i` is guaranteed to be within bounds since we are iterating from zero to `buckets - 1`; + // 2. Even if `i` will be `i == self.bucket_mask`, it is safe to call `Group::load_aligned` + // due to the extended control bytes range, which is `self.bucket_mask + 1 + Group::WIDTH`; + // 3. The caller of this function guarantees that [`RawTableInner`] has already been allocated; + // 4. We can use `Group::load_aligned` and `Group::store_aligned` here since we start from 0 + // and go to the end with a step equal to `Group::WIDTH` (see TableLayout::calculate_layout_for). for i in (0..self.buckets()).step_by(Group::WIDTH) { let group = Group::load_aligned(self.ctrl(i)); let group = group.convert_special_to_empty_and_full_to_deleted(); @@ -1203,15 +2256,245 @@ impl RawTableInner { // Fix up the trailing control bytes. See the comments in set_ctrl // for the handling of tables smaller than the group width. - if self.buckets() < Group::WIDTH { + // + // SAFETY: The caller of this function guarantees that [`RawTableInner`] + // has already been allocated + if unlikely(self.buckets() < Group::WIDTH) { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe self.ctrl(0) .copy_to(self.ctrl(Group::WIDTH), self.buckets()); } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe self.ctrl(0) .copy_to(self.ctrl(self.buckets()), Group::WIDTH); } } + /// Returns an iterator over every element in the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result + /// is [`undefined behavior`]: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `RawIter`. Because we cannot make the `next` method unsafe on + /// the `RawIter` struct, we have to make the `iter` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise using the returned [`RawIter`] results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.data_end()` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. `data` bucket index in the table is equal to the `ctrl` index (i.e. + // equal to zero). + // 3. We pass the exact value of buckets of the table to the function. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let data = Bucket::from_base_index(self.data_end(), 0); + RawIter { + // SAFETY: See explanation above + iter: RawIterRange::new(self.ctrl.as_ptr(), data, self.buckets()), + items: self.items, + } + } + + /// Executes the destructors (if any) of the values stored in the table. + /// + /// # Note + /// + /// This function does not erase the control bytes of the table and does + /// not make any changes to the `items` or `growth_left` fields of the + /// table. If necessary, the caller of this function must manually set + /// up these table fields, for example using the [`clear_no_drop`] function. + /// + /// Be careful during calling this function, because drop function of + /// the elements can panic, and this can leave table in an inconsistent + /// state. + /// + /// # Safety + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise calling this function may result in [`undefined behavior`]. + /// + /// If `T` is a type that should be dropped and **the table is not empty**, + /// calling this function more than once results in [`undefined behavior`]. + /// + /// If `T` is not [`Copy`], attempting to use values stored in the table after + /// calling this function may result in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`Bucket::drop`] / [`Bucket::as_ptr`] methods, for more information + /// about of properly removing or saving `element` from / into the [`RawTable`] / + /// [`RawTableInner`]. + /// + /// [`Bucket::drop`]: Bucket::drop + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`clear_no_drop`]: RawTableInner::clear_no_drop + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_elements(&mut self) { + // Check that `self.items != 0`. Protects against the possibility + // of creating an iterator on an table with uninitialized control bytes. + if T::NEEDS_DROP && self.items != 0 { + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `RawIter` iterator, and the caller of this function + // must uphold the safety contract for `drop_elements` method. + for item in self.iter::() { + // SAFETY: The caller must uphold the safety contract for + // `drop_elements` method. + item.drop(); + } + } + } + + /// Executes the destructors (if any) of the values stored in the table and than + /// deallocates the table. + /// + /// # Note + /// + /// Calling this function automatically makes invalid (dangling) all instances of + /// buckets ([`Bucket`]) and makes invalid (dangling) the `ctrl` field of the table. + /// + /// This function does not make any changes to the `bucket_mask`, `items` or `growth_left` + /// fields of the table. If necessary, the caller of this function must manually set + /// up these table fields. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * Calling this function more than once; + /// + /// * The type `T` must be the actual type of the elements stored in the table. + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that + /// was used to allocate this table. + /// + /// The caller of this function should pay attention to the possibility of the + /// elements' drop function panicking, because this: + /// + /// * May leave the table in an inconsistent state; + /// + /// * Memory is never deallocated, so a memory leak may occur. + /// + /// Attempt to use the `ctrl` field of the table (dereference) after calling this + /// function results in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`RawTableInner::drop_elements`] or [`RawTableInner::free_buckets`] + /// for more information. + /// + /// [`RawTableInner::drop_elements`]: RawTableInner::drop_elements + /// [`RawTableInner::free_buckets`]: RawTableInner::free_buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_inner_table(&mut self, alloc: &A, table_layout: TableLayout) { + if !self.is_empty_singleton() { + unsafe { + // SAFETY: The caller must uphold the safety contract for `drop_inner_table` method. + self.drop_elements::(); + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller must uphold the safety contract for `drop_inner_table` method. + self.free_buckets(alloc, table_layout); + } + } + } + + /// Returns a pointer to an element in the table (convenience for + /// `Bucket::from_base_index(self.data_end::(), index)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived from the + /// safety rules of the [`Bucket::from_base_index`] function. Therefore, when calling + /// this function, the following safety rules must be observed: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// * The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`Bucket`] may result in [`undefined behavior`]. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + /// part of the `RawTableInner`, i.e. to the start of T3 (see [`Bucket::as_ptr`]) + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// ^ \__________ __________/ + /// `table.bucket(3)` returns a pointer that points \/ + /// here in the `data` part of the `RawTableInner` additional control bytes + /// (to the end of T3) `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`Bucket::from_base_index`]: Bucket::from_base_index + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] unsafe fn bucket(&self, index: usize) -> Bucket { debug_assert_ne!(self.bucket_mask, 0); @@ -1219,6 +2502,52 @@ impl RawTableInner { Bucket::from_base_index(self.data_end(), index) } + /// Returns a raw `*mut u8` pointer to the start of the `data` element in the table + /// (convenience for `self.data_end::().as_ptr().sub((index + 1) * size_of)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned `*mut u8`, + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`; + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket_ptr(3, mem::size_of::())` returns a pointer that points here in the + /// `data` part of the `RawTableInner`, i.e. to the start of T3 + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// \__________ __________/ + /// \/ + /// additional control bytes + /// `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] unsafe fn bucket_ptr(&self, index: usize, size_of: usize) -> *mut u8 { debug_assert_ne!(self.bucket_mask, 0); @@ -1227,9 +2556,44 @@ impl RawTableInner { base.sub((index + 1) * size_of) } + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation (convenience for `self.ctrl.cast()`). + /// + /// This function actually returns a pointer to the end of the `data element` at + /// index "0" (zero). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Note + /// + /// The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`NonNull`] may result in [`undefined behavior`]. + /// + /// ```none + /// `table.data_end::()` returns pointer that points here + /// (to the end of `T0`) + /// ∨ + /// [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + /// \________ ________/ + /// \/ + /// `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`. + /// CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + /// with loading `Group` bytes from the heap works properly, even if the result + /// of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + /// `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] - unsafe fn data_end(&self) -> NonNull { - NonNull::new_unchecked(self.ctrl.as_ptr().cast()) + fn data_end(&self) -> NonNull { + self.ctrl.cast() } /// Returns an iterator-like object for a probe sequence on the table. @@ -1240,6 +2604,8 @@ impl RawTableInner { #[inline] fn probe_seq(&self, hash: u64) -> ProbeSeq { ProbeSeq { + // This is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. pos: h1(hash) & self.bucket_mask, stride: 0, } @@ -1250,7 +2616,7 @@ impl RawTableInner { #[cfg(feature = "raw")] #[inline] unsafe fn prepare_insert_no_grow(&mut self, hash: u64) -> Result { - let index = self.find_insert_slot(hash); + let index = self.find_insert_slot(hash).index; let old_ctrl = *self.ctrl(index); if unlikely(self.growth_left == 0 && special_is_empty(old_ctrl)) { Err(()) @@ -1277,13 +2643,68 @@ impl RawTableInner { /// Sets a control byte to the hash, and possibly also the replicated control byte at /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl`] + /// method. Thus, in order to uphold the safety contracts for the method, you must observe the + /// following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl`]: RawTableInner::set_ctrl + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] - unsafe fn set_ctrl_h2(&self, index: usize, hash: u64) { + unsafe fn set_ctrl_h2(&mut self, index: usize, hash: u64) { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl_h2`] self.set_ctrl(index, h2(hash)); } + /// Replaces the hash in the control byte at the given index with the provided one, + /// and possibly also replicates the new control byte at the end of the array of control + /// bytes, returning the old control byte. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl_h2`] + /// and [`RawTableInner::ctrl`] methods. Thus, in order to uphold the safety contracts for both + /// methods, you must observe the following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl_h2`]: RawTableInner::set_ctrl_h2 + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] - unsafe fn replace_ctrl_h2(&self, index: usize, hash: u64) -> u8 { + unsafe fn replace_ctrl_h2(&mut self, index: usize, hash: u64) -> u8 { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::replace_ctrl_h2`] let prev_ctrl = *self.ctrl(index); self.set_ctrl_h2(index, hash); prev_ctrl @@ -1291,10 +2712,35 @@ impl RawTableInner { /// Sets a control byte, and possibly also the replicated control byte at /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] - unsafe fn set_ctrl(&self, index: usize, ctrl: u8) { + unsafe fn set_ctrl(&mut self, index: usize, ctrl: u8) { // Replicate the first Group::WIDTH control bytes at the end of - // the array without using a branch: + // the array without using a branch. If the tables smaller than + // the group width (self.buckets() < Group::WIDTH), + // `index2 = Group::WIDTH + index`, otherwise `index2` is: + // // - If index >= Group::WIDTH then index == index2. // - Otherwise index2 == self.bucket_mask + 1 + index. // @@ -1311,16 +2757,43 @@ impl RawTableInner { // --------------------------------------------- // | [A] | [B] | [EMPTY] | [EMPTY] | [A] | [B] | // --------------------------------------------- + + // This is the same as `(index.wrapping_sub(Group::WIDTH)) % self.buckets() + Group::WIDTH` + // because the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. let index2 = ((index.wrapping_sub(Group::WIDTH)) & self.bucket_mask) + Group::WIDTH; + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl`] *self.ctrl(index) = ctrl; *self.ctrl(index2) = ctrl; } /// Returns a pointer to a control byte. + /// + /// # Safety + /// + /// For the allocated [`RawTableInner`], the result is [`Undefined Behavior`], + /// if the `index` is greater than the `self.bucket_mask + 1 + Group::WIDTH`. + /// In that case, calling this function with `index == self.bucket_mask + 1 + Group::WIDTH` + /// will return a pointer to the end of the allocated table and it is useless on its own. + /// + /// Calling this function with `index >= self.bucket_mask + 1 + Group::WIDTH` on a + /// table that has not been allocated results in [`Undefined Behavior`]. + /// + /// So to satisfy both requirements you should always follow the rule that + /// `index < self.bucket_mask + 1 + Group::WIDTH` + /// + /// Calling this function on [`RawTableInner`] that are not already allocated is safe + /// for read-only purpose. + /// + /// See also [`Bucket::as_ptr()`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr()`]: Bucket::as_ptr() + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] unsafe fn ctrl(&self, index: usize) -> *mut u8 { debug_assert!(index < self.num_ctrl_bytes()); + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::ctrl`] self.ctrl.as_ptr().add(index) } @@ -1329,6 +2802,17 @@ impl RawTableInner { self.bucket_mask + 1 } + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + unsafe fn is_bucket_full(&self, index: usize) -> bool { + debug_assert!(index < self.buckets()); + is_full(*self.ctrl(index)) + } + #[inline] fn num_ctrl_bytes(&self) -> usize { self.bucket_mask + 1 + Group::WIDTH @@ -1339,25 +2823,45 @@ impl RawTableInner { self.bucket_mask == 0 } + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating, + /// and return it inside ScopeGuard to protect against panic in the hash + /// function. + /// + /// # Note + /// + /// It is recommended (but not required): + /// + /// * That the new table's `capacity` be greater than or equal to `self.items`. + /// + /// * The `alloc` is the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `table_layout` is the same [`TableLayout`] as the `TableLayout` used + /// to allocate this table. + /// + /// If `table_layout` does not match the `TableLayout` that was used to allocate + /// this table, then using `mem::swap` with the `self` and the new table returned + /// by this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[allow(clippy::mut_mut)] #[inline] - unsafe fn prepare_resize( + fn prepare_resize<'a, A>( &self, + alloc: &'a A, table_layout: TableLayout, capacity: usize, fallibility: Fallibility, - ) -> Result, TryReserveError> { + ) -> Result, TryReserveError> + where + A: Allocator, + { debug_assert!(self.items <= capacity); // Allocate and initialize the new table. - let mut new_table = RawTableInner::fallible_with_capacity( - self.alloc.clone(), - table_layout, - capacity, - fallibility, - )?; - new_table.growth_left -= self.items; - new_table.items = self.items; + let new_table = + RawTableInner::fallible_with_capacity(alloc, table_layout, capacity, fallibility)?; // The hash function may panic, in which case we simply free the new // table without dropping any elements that may have been copied into @@ -1367,7 +2871,11 @@ impl RawTableInner { // the comment at the bottom of this function. Ok(guard(new_table, move |self_| { if !self_.is_empty_singleton() { - self_.free_buckets(table_layout); + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that the `alloc` and `table_layout` matches the + // [`Allocator`] and [`TableLayout`] used to allocate this table. + unsafe { self_.free_buckets(alloc, table_layout) }; } })) } @@ -1376,16 +2884,38 @@ impl RawTableInner { /// /// This uses dynamic dispatch to reduce the amount of /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table. + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[allow(clippy::inline_always)] #[inline(always)] - unsafe fn reserve_rehash_inner( + unsafe fn reserve_rehash_inner( &mut self, + alloc: &A, additional: usize, hasher: &dyn Fn(&mut Self, usize) -> u64, fallibility: Fallibility, layout: TableLayout, drop: Option, - ) -> Result<(), TryReserveError> { + ) -> Result<(), TryReserveError> + where + A: Allocator, + { // Avoid `Option::ok_or_else` because it bloats LLVM IR. let new_items = match self.items.checked_add(additional) { Some(new_items) => new_items, @@ -1395,12 +2925,30 @@ impl RawTableInner { if new_items <= full_capacity / 2 { // Rehash in-place without re-allocating if we have plenty of spare // capacity that is locked up due to DELETED entries. + + // SAFETY: + // 1. We know for sure that `[`RawTableInner`]` has already been allocated + // (since new_items <= full_capacity / 2); + // 2. The caller ensures that `drop` function is the actual drop function of + // the elements stored in the table. + // 3. The caller ensures that `layout` matches the [`TableLayout`] that was + // used to allocate this table. + // 4. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. self.rehash_in_place(hasher, layout.size, drop); Ok(()) } else { // Otherwise, conservatively resize to at least the next size up // to avoid churning deletes into frequent rehashes. + // + // SAFETY: + // 1. We know for sure that `capacity >= self.items`. + // 2. The caller ensures that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. self.resize_inner( + alloc, usize::max(new_items, full_capacity + 1), hasher, fallibility, @@ -1409,48 +2957,160 @@ impl RawTableInner { } } + /// Returns an iterator over full buckets indices in the table. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `FullBucketsIndices`. Because we cannot make the `next` method + /// unsafe on the `FullBucketsIndices` struct, we have to make the + /// `full_buckets_indices` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + #[inline(always)] + unsafe fn full_buckets_indices(&self) -> FullBucketsIndices { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.ctrl(0)` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. The value of `items` is equal to the amount of data (values) added + // to the table. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, Group::WIDTH + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + let ctrl = NonNull::new_unchecked(self.ctrl(0)); + + FullBucketsIndices { + // Load the first group + // SAFETY: See explanation above. + current_group: Group::load_aligned(ctrl.as_ptr()).match_full().into_iter(), + group_first_index: 0, + ctrl, + items: self.items, + } + } + /// Allocates a new table of a different size and moves the contents of the /// current table into it. /// /// This uses dynamic dispatch to reduce the amount of /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table; + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The caller of this function must ensure that `capacity >= self.items` + /// otherwise: + /// + /// * If `self.items != 0`, calling of this function with `capacity == 0` + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// are never return (will go into an infinite loop). + /// + /// Note: It is recommended (but not required) that the new table's `capacity` + /// be greater than or equal to `self.items`. In case if `capacity <= self.items` + /// this function can never return. See [`RawTableInner::find_insert_slot`] for + /// more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[allow(clippy::inline_always)] #[inline(always)] - unsafe fn resize_inner( + unsafe fn resize_inner( &mut self, + alloc: &A, capacity: usize, hasher: &dyn Fn(&mut Self, usize) -> u64, fallibility: Fallibility, layout: TableLayout, - ) -> Result<(), TryReserveError> { - let mut new_table = self.prepare_resize(layout, capacity, fallibility)?; - - // Copy all elements to the new table. - for i in 0..self.buckets() { - if !is_full(*self.ctrl(i)) { - continue; - } - + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // SAFETY: We know for sure that `alloc` and `layout` matches the [`Allocator`] and [`TableLayout`] + // that were used to allocate this table. + let mut new_table = self.prepare_resize(alloc, layout, capacity, fallibility)?; + + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `FullBucketsIndices` iterator, and the caller of this + // function ensures that the control bytes are properly initialized. + for full_byte_index in self.full_buckets_indices() { // This may panic. - let hash = hasher(self, i); + let hash = hasher(self, full_byte_index); + // SAFETY: // We can use a simpler version of insert() here since: - // - there are no DELETED entries. - // - we know there is enough space in the table. - // - all elements are unique. - let (index, _) = new_table.prepare_insert_slot(hash); - + // 1. There are no DELETED entries. + // 2. We know there is enough space in the table. + // 3. All elements are unique. + // 4. The caller of this function guarantees that `capacity > 0` + // so `new_table` must already have some allocated memory. + // 5. We set `growth_left` and `items` fields of the new table + // after the loop. + // 6. We insert into the table, at the returned index, the data + // matching the given hash immediately after calling this function. + let (new_index, _) = new_table.prepare_insert_slot(hash); + + // SAFETY: + // + // * `src` is valid for reads of `layout.size` bytes, since the + // table is alive and the `full_byte_index` is guaranteed to be + // within bounds (see `FullBucketsIndices::next_impl`); + // + // * `dst` is valid for writes of `layout.size` bytes, since the + // caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate old table and we have the `new_index` + // returned by `prepare_insert_slot`. + // + // * Both `src` and `dst` are properly aligned. + // + // * Both `src` and `dst` point to different region of memory. ptr::copy_nonoverlapping( - self.bucket_ptr(i, layout.size), - new_table.bucket_ptr(index, layout.size), + self.bucket_ptr(full_byte_index, layout.size), + new_table.bucket_ptr(new_index, layout.size), layout.size, ); } + // The hash function didn't panic, so we can safely set the + // `growth_left` and `items` fields of the new table. + new_table.growth_left -= self.items; + new_table.items = self.items; + // We successfully copied all elements without panicking. Now replace // self with the new table. The old table will have its memory freed but // the items will not be dropped (since they have been moved into the // new table). + // SAFETY: The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. mem::swap(self, &mut new_table); Ok(()) @@ -1463,6 +3123,21 @@ impl RawTableInner { /// /// This uses dynamic dispatch to reduce the amount of /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[allow(clippy::inline_always)] #[cfg_attr(feature = "inline-more", inline(always))] #[cfg_attr(not(feature = "inline-more"), inline)] @@ -1506,8 +3181,10 @@ impl RawTableInner { let hash = hasher(*guard, i); // Search for a suitable place to put it - let new_i = guard.find_insert_slot(hash); - let new_i_p = guard.bucket_ptr(new_i, size_of); + // + // SAFETY: Caller of this function ensures that the control bytes + // are properly initialized. + let new_i = guard.find_insert_slot(hash).index; // Probing works by scanning through all of the control // bytes in groups, which may not be aligned to the group @@ -1519,6 +3196,8 @@ impl RawTableInner { continue 'outer; } + let new_i_p = guard.bucket_ptr(new_i, size_of); + // We are moving the current item to a new position. Write // our H2 to the control byte of the new position. let prev_ctrl = guard.replace_ctrl_h2(new_i, hash); @@ -1545,17 +3224,107 @@ impl RawTableInner { mem::forget(guard); } + /// Deallocates the table without dropping any entries. + /// + /// # Note + /// + /// This function must be called only after [`drop_elements`](RawTableInner::drop_elements), + /// else it can lead to leaking of memory. Also calling this function automatically + /// makes invalid (dangling) all instances of buckets ([`Bucket`]) and makes invalid + /// (dangling) the `ctrl` field of the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that was used + /// to allocate this table. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[inline] + unsafe fn free_buckets(&mut self, alloc: &A, table_layout: TableLayout) + where + A: Allocator, + { + // SAFETY: The caller must uphold the safety contract for `free_buckets` + // method. + let (ptr, layout) = self.allocation_info(table_layout); + alloc.deallocate(ptr, layout); + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. + /// + /// # Safety + /// + /// Caller of this function must observe the following safety rules: + /// + /// * The [`RawTableInner`] has already been allocated, otherwise + /// calling this function results in [`undefined behavior`] + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate #[inline] - unsafe fn free_buckets(&mut self, table_layout: TableLayout) { + unsafe fn allocation_info(&self, table_layout: TableLayout) -> (NonNull, Layout) { + debug_assert!( + !self.is_empty_singleton(), + "this function can only be called on non-empty tables" + ); + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. let (layout, ctrl_offset) = match table_layout.calculate_layout_for(self.buckets()) { Some(lco) => lco, - None => hint::unreachable_unchecked(), + None => unsafe { hint::unreachable_unchecked() }, }; - self.alloc.deallocate( - NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)), + ( + // SAFETY: The caller must uphold the safety contract for `allocation_info` method. + unsafe { NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)) }, layout, - ); + ) + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. If [`RawTableInner`] has not been allocated, this + /// function return `dangling` pointer and `()` (unit) layout. + /// + /// # Safety + /// + /// The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[cfg(feature = "raw")] + unsafe fn allocation_info_or_zero(&self, table_layout: TableLayout) -> (NonNull, Layout) { + if self.is_empty_singleton() { + (NonNull::dangling(), Layout::new::<()>()) + } else { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + unsafe { self.allocation_info(table_layout) } + } } /// Marks all table buckets as empty without dropping their contents. @@ -1570,27 +3339,95 @@ impl RawTableInner { self.growth_left = bucket_mask_to_capacity(self.bucket_mask); } + /// Erases the [`Bucket`]'s control byte at the given index so that it does not + /// triggered as full, decreases the `items` of the table and, if it can be done, + /// increases `self.growth_left`. + /// + /// This function does not actually erase / drop the [`Bucket`] itself, i.e. it + /// does not make any changes to the `data` parts of the table. The caller of this + /// function must take care to properly drop the `data`, otherwise calling this + /// function may result in a memory leak. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * It must be the full control byte at the given position; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// Calling this function on a table with no elements is unspecified, but calling subsequent + /// functions is likely to result in [`undefined behavior`] due to overflow subtraction + /// (`self.items -= 1 cause overflow when self.items == 0`). + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[inline] unsafe fn erase(&mut self, index: usize) { - debug_assert!(is_full(*self.ctrl(index))); + debug_assert!(self.is_bucket_full(index)); + + // This is the same as `index.wrapping_sub(Group::WIDTH) % self.buckets()` because + // the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. let index_before = index.wrapping_sub(Group::WIDTH) & self.bucket_mask; + // SAFETY: + // - The caller must uphold the safety contract for `erase` method; + // - `index_before` is guaranteed to be in range due to masking with `self.bucket_mask` let empty_before = Group::load(self.ctrl(index_before)).match_empty(); let empty_after = Group::load(self.ctrl(index)).match_empty(); - // If we are inside a continuous block of Group::WIDTH full or deleted - // cells then a probe window may have seen a full block when trying to - // insert. We therefore need to keep that block non-empty so that - // lookups will continue searching to the next probe window. + // Inserting and searching in the map is performed by two key functions: + // + // - The `find_insert_slot` function that looks up the index of any `EMPTY` or `DELETED` + // slot in a group to be able to insert. If it doesn't find an `EMPTY` or `DELETED` + // slot immediately in the first group, it jumps to the next `Group` looking for it, + // and so on until it has gone through all the groups in the control bytes. // - // Note that in this context `leading_zeros` refers to the bytes at the - // end of a group, while `trailing_zeros` refers to the bytes at the - // beginning of a group. + // - The `find_inner` function that looks for the index of the desired element by looking + // at all the `FULL` bytes in the group. If it did not find the element right away, and + // there is no `EMPTY` byte in the group, then this means that the `find_insert_slot` + // function may have found a suitable slot in the next group. Therefore, `find_inner` + // jumps further, and if it does not find the desired element and again there is no `EMPTY` + // byte, then it jumps further, and so on. The search stops only if `find_inner` function + // finds the desired element or hits an `EMPTY` slot/byte. + // + // Accordingly, this leads to two consequences: + // + // - The map must have `EMPTY` slots (bytes); + // + // - You can't just mark the byte to be erased as `EMPTY`, because otherwise the `find_inner` + // function may stumble upon an `EMPTY` byte before finding the desired element and stop + // searching. + // + // Thus it is necessary to check all bytes after and before the erased element. If we are in + // a contiguous `Group` of `FULL` or `DELETED` bytes (the number of `FULL` or `DELETED` bytes + // before and after is greater than or equal to `Group::WIDTH`), then we must mark our byte as + // `DELETED` in order for the `find_inner` function to go further. On the other hand, if there + // is at least one `EMPTY` slot in the `Group`, then the `find_inner` function will still stumble + // upon an `EMPTY` byte, so we can safely mark our erased byte as `EMPTY` as well. + // + // Finally, since `index_before == (index.wrapping_sub(Group::WIDTH) & self.bucket_mask) == index` + // and given all of the above, tables smaller than the group width (self.buckets() < Group::WIDTH) + // cannot have `DELETED` bytes. + // + // Note that in this context `leading_zeros` refers to the bytes at the end of a group, while + // `trailing_zeros` refers to the bytes at the beginning of a group. let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH { DELETED } else { self.growth_left += 1; EMPTY }; + // SAFETY: the caller must uphold the safety contract for `erase` method. self.set_ctrl(index, ctrl); self.items -= 1; } @@ -1599,12 +3436,16 @@ impl RawTableInner { impl Clone for RawTable { fn clone(&self) -> Self { if self.table.is_empty_singleton() { - Self::new_in(self.table.alloc.clone()) + Self::new_in(self.alloc.clone()) } else { unsafe { // Avoid `Result::ok_or_else` because it bloats LLVM IR. - let new_table = match Self::new_uninitialized( - self.table.alloc.clone(), + // + // SAFETY: This is safe as we are taking the size of an already allocated table + // and therefore сapacity overflow cannot occur, `self.table.buckets()` is power + // of two and all allocator errors will be caught inside `RawTableInner::new_uninitialized`. + let mut new_table = match Self::new_uninitialized( + self.alloc.clone(), self.table.buckets(), Fallibility::Infallible, ) { @@ -1612,24 +3453,32 @@ impl Clone for RawTable { Err(_) => hint::unreachable_unchecked(), }; - // If cloning fails then we need to free the allocation for the - // new table. However we don't run its drop since its control - // bytes are not initialized yet. - let mut guard = guard(ManuallyDrop::new(new_table), |new_table| { - new_table.free_buckets(); - }); - - guard.clone_from_spec(self); - - // Disarm the scope guard and return the newly created table. - ManuallyDrop::into_inner(ScopeGuard::into_inner(guard)) + // Cloning elements may fail (the clone function may panic). But we don't + // need to worry about uninitialized control bits, since: + // 1. The number of items (elements) in the table is zero, which means that + // the control bits will not be readed by Drop function. + // 2. The `clone_from_spec` method will first copy all control bits from + // `self` (thus initializing them). But this will not affect the `Drop` + // function, since the `clone_from_spec` function sets `items` only after + // successfully clonning all elements. + new_table.clone_from_spec(self); + new_table } } } fn clone_from(&mut self, source: &Self) { if source.table.is_empty_singleton() { - *self = Self::new_in(self.table.alloc.clone()); + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } } else { unsafe { // Make sure that if any panics occurs, we clear the table and @@ -1644,27 +3493,38 @@ impl Clone for RawTable { // // This leak is unavoidable: we can't try dropping more elements // since this could lead to another panic and abort the process. - self_.drop_elements(); + // + // SAFETY: If something gets wrong we clear our table right after + // dropping the elements, so there is no double drop, since `items` + // will be equal to zero. + self_.table.drop_elements::(); // If necessary, resize our table to match the source. if self_.buckets() != source.buckets() { - // Skip our drop by using ptr::write. - if !self_.table.is_empty_singleton() { - self_.free_buckets(); + let new_inner = match RawTableInner::new_uninitialized( + &self_.alloc, + Self::TABLE_LAYOUT, + source.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }; + // Replace the old inner with new uninitialized one. It's ok, since if something gets + // wrong `ScopeGuard` will initialize all control bytes and leave empty table. + let mut old_inner = mem::replace(&mut self_.table, new_inner); + if !old_inner.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that `alloc` and `table_layout` matches + // the [`Allocator`] and [`TableLayout`] that were used to allocate this table. + old_inner.free_buckets(&self_.alloc, Self::TABLE_LAYOUT); } - (&mut **self_ as *mut Self).write( - // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - match Self::new_uninitialized( - self_.table.alloc.clone(), - source.buckets(), - Fallibility::Infallible, - ) { - Ok(table) => table, - Err(_) => hint::unreachable_unchecked(), - }, - ); } + // Cloning elements may fail (the clone function may panic), but the `ScopeGuard` + // inside the `clone_from_impl` function will take care of that, dropping all + // cloned elements if necessary. Our `ScopeGuard` will clear the table. self_.clone_from_spec(source); // Disarm the scope guard if cloning was successful. @@ -1696,7 +3556,8 @@ impl RawTableClone for RawTable { .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); source .data_start() - .copy_to_nonoverlapping(self.data_start(), self.table.buckets()); + .as_ptr() + .copy_to_nonoverlapping(self.data_start().as_ptr(), self.table.buckets()); self.table.items = source.table.items; self.table.growth_left = source.table.growth_left; @@ -1720,9 +3581,9 @@ impl RawTable { // to make sure we drop only the elements that have been // cloned so far. let mut guard = guard((0, &mut *self), |(index, self_)| { - if mem::needs_drop::() && !self_.is_empty() { - for i in 0..=*index { - if is_full(*self_.table.ctrl(i)) { + if T::NEEDS_DROP { + for i in 0..*index { + if self_.is_bucket_full(i) { self_.bucket(i).drop(); } } @@ -1735,7 +3596,7 @@ impl RawTable { to.write(from.as_ref().clone()); // Update the index in case we need to unwind. - guard.0 = index; + guard.0 = index + 1; } // Successfully cloned all items, no need to clean up. @@ -1757,7 +3618,7 @@ impl RawTable { { self.clear(); - let guard_self = guard(&mut *self, |self_| { + let mut guard_self = guard(&mut *self, |self_| { // Clear the partially copied table if a panic occurs, otherwise // items and growth_left will be out of sync with the contents // of the table. @@ -1790,7 +3651,7 @@ impl RawTable { } } -impl Default for RawTable { +impl Default for RawTable { #[inline] fn default() -> Self { Self::new_in(Default::default()) @@ -1798,31 +3659,41 @@ impl Default for RawTable { } #[cfg(feature = "nightly")] -unsafe impl<#[may_dangle] T, A: Allocator + Clone> Drop for RawTable { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawTable { #[cfg_attr(feature = "inline-more", inline)] fn drop(&mut self) { - if !self.table.is_empty_singleton() { - unsafe { - self.drop_elements(); - self.free_buckets(); - } + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); } } } #[cfg(not(feature = "nightly"))] -impl Drop for RawTable { +impl Drop for RawTable { #[cfg_attr(feature = "inline-more", inline)] fn drop(&mut self) { - if !self.table.is_empty_singleton() { - unsafe { - self.drop_elements(); - self.free_buckets(); - } + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); } } } -impl IntoIterator for RawTable { +impl IntoIterator for RawTable { type Item = T; type IntoIter = RawIntoIter; @@ -1840,7 +3711,7 @@ impl IntoIterator for RawTable { pub(crate) struct RawIterRange { // Mask of full buckets in the current group. Bits are cleared from this // mask as each element is processed. - current_group: BitMask, + current_group: BitMaskIter, // Pointer to the buckets for the current group. data: Bucket, @@ -1856,19 +3727,44 @@ pub(crate) struct RawIterRange { impl RawIterRange { /// Returns a `RawIterRange` covering a subset of a table. /// - /// The control byte address must be aligned to the group size. + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * `ctrl` must be [valid] for reads, i.e. table outlives the `RawIterRange`; + /// + /// * `ctrl` must be properly aligned to the group size (Group::WIDTH); + /// + /// * `ctrl` must point to the array of properly initialized control bytes; + /// + /// * `data` must be the [`Bucket`] at the `ctrl` index in the table; + /// + /// * the value of `len` must be less than or equal to the number of table buckets, + /// and the returned value of `ctrl.as_ptr().add(len).offset_from(ctrl.as_ptr())` + /// must be positive. + /// + /// * The `ctrl.add(len)` pointer must be either in bounds or one + /// byte past the end of the same [allocated table]. + /// + /// * The `len` must be a power of two. + /// + /// [valid]: https://doc.rust-lang.org/std/ptr/index.html#safety + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[cfg_attr(feature = "inline-more", inline)] unsafe fn new(ctrl: *const u8, data: Bucket, len: usize) -> Self { debug_assert_ne!(len, 0); debug_assert_eq!(ctrl as usize % Group::WIDTH, 0); + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] let end = ctrl.add(len); // Load the first group and advance ctrl to point to the next group + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] let current_group = Group::load_aligned(ctrl).match_full(); let next_ctrl = ctrl.add(Group::WIDTH); Self { - current_group, + current_group: current_group.into_iter(), data, next_ctrl, end, @@ -1925,8 +3821,7 @@ impl RawIterRange { #[cfg_attr(feature = "inline-more", inline)] unsafe fn next_impl(&mut self) -> Option> { loop { - if let Some(index) = self.current_group.lowest_set_bit() { - self.current_group = self.current_group.remove_lowest_bit(); + if let Some(index) = self.current_group.next() { return Some(self.data.next_n(index)); } @@ -1939,7 +3834,86 @@ impl RawIterRange { // than the group size where the trailing control bytes are all // EMPTY. On larger tables self.end is guaranteed to be aligned // to the group size (since tables are power-of-two sized). - self.current_group = Group::load_aligned(self.next_ctrl).match_full(); + self.current_group = Group::load_aligned(self.next_ctrl).match_full().into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } + + /// Folds every element into an accumulator by applying an operation, + /// returning the final result. + /// + /// `fold_impl()` takes three arguments: the number of items remaining in + /// the iterator, an initial value, and a closure with two arguments: an + /// 'accumulator', and an element. The closure returns the value that the + /// accumulator should have for the next iteration. + /// + /// The initial value is the value the accumulator will have on the first call. + /// + /// After applying this closure to every element of the iterator, `fold_impl()` + /// returns the accumulator. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `RawIterRange`; + /// + /// * The provided `n` value must match the actual number of items + /// in the table. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::while_let_on_iterator)] + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn fold_impl(mut self, mut n: usize, mut acc: B, mut f: F) -> B + where + F: FnMut(B, Bucket) -> B, + { + loop { + while let Some(index) = self.current_group.next() { + // The returned `index` will always be in the range `0..Group::WIDTH`, + // so that calling `self.data.next_n(index)` is safe (see detailed explanation below). + debug_assert!(n != 0); + let bucket = self.data.next_n(index); + acc = f(acc, bucket); + n -= 1; + } + + if n == 0 { + return acc; + } + + // SAFETY: The caller of this function ensures that: + // + // 1. The provided `n` value matches the actual number of items in the table; + // 2. The table is alive and did not moved. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.current_group` will read bytes + // from the `self.buckets() - Group::WIDTH` index. We know also that + // `self.current_group.next()` will always retun indices within the range + // `0..Group::WIDTH`. + // + // Knowing all of the above and taking into account that we are synchronizing + // the `self.data` index with the index we used to read the `self.current_group`, + // the subsequent `self.data.next_n(index)` will always return a bucket with + // an index number less than `self.buckets()`. + // + // The last `self.next_ctrl`, whose index would be `self.buckets()`, will never + // actually be read, since we should have already yielded all the elements of + // the table. + self.current_group = Group::load_aligned(self.next_ctrl).match_full().into_iter(); self.data = self.data.next_n(Group::WIDTH); self.next_ctrl = self.next_ctrl.add(Group::WIDTH); } @@ -2016,7 +3990,7 @@ impl RawIter { /// This method should be called _before_ the removal is made. It is not necessary to call this /// method if you are removing an item that this iterator yielded in the past. #[cfg(feature = "raw")] - pub fn reflect_remove(&mut self, b: &Bucket) { + pub unsafe fn reflect_remove(&mut self, b: &Bucket) { self.reflect_toggle_full(b, false); } @@ -2030,36 +4004,76 @@ impl RawIter { /// /// This method should be called _after_ the given insert is made. #[cfg(feature = "raw")] - pub fn reflect_insert(&mut self, b: &Bucket) { + pub unsafe fn reflect_insert(&mut self, b: &Bucket) { self.reflect_toggle_full(b, true); } /// Refresh the iterator so that it reflects a change to the state of the given bucket. #[cfg(feature = "raw")] - fn reflect_toggle_full(&mut self, b: &Bucket, is_insert: bool) { - unsafe { - if b.as_ptr() > self.iter.data.as_ptr() { - // The iterator has already passed the bucket's group. - // So the toggle isn't relevant to this iterator. - return; + unsafe fn reflect_toggle_full(&mut self, b: &Bucket, is_insert: bool) { + if b.as_ptr() > self.iter.data.as_ptr() { + // The iterator has already passed the bucket's group. + // So the toggle isn't relevant to this iterator. + return; + } + + if self.iter.next_ctrl < self.iter.end + && b.as_ptr() <= self.iter.data.next_n(Group::WIDTH).as_ptr() + { + // The iterator has not yet reached the bucket's group. + // We don't need to reload anything, but we do need to adjust the item count. + + if cfg!(debug_assertions) { + // Double-check that the user isn't lying to us by checking the bucket state. + // To do that, we need to find its control byte. We know that self.iter.data is + // at self.iter.next_ctrl - Group::WIDTH, so we work from there: + let offset = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let ctrl = self.iter.next_ctrl.sub(Group::WIDTH).add(offset); + // This method should be called _before_ a removal, or _after_ an insert, + // so in both cases the ctrl byte should indicate that the bucket is full. + assert!(is_full(*ctrl)); } - if self.iter.next_ctrl < self.iter.end - && b.as_ptr() <= self.iter.data.next_n(Group::WIDTH).as_ptr() - { - // The iterator has not yet reached the bucket's group. - // We don't need to reload anything, but we do need to adjust the item count. + if is_insert { + self.items += 1; + } else { + self.items -= 1; + } - if cfg!(debug_assertions) { - // Double-check that the user isn't lying to us by checking the bucket state. - // To do that, we need to find its control byte. We know that self.iter.data is - // at self.iter.next_ctrl - Group::WIDTH, so we work from there: - let offset = offset_from(self.iter.data.as_ptr(), b.as_ptr()); - let ctrl = self.iter.next_ctrl.sub(Group::WIDTH).add(offset); - // This method should be called _before_ a removal, or _after_ an insert, - // so in both cases the ctrl byte should indicate that the bucket is full. - assert!(is_full(*ctrl)); - } + return; + } + + // The iterator is at the bucket group that the toggled bucket is in. + // We need to do two things: + // + // - Determine if the iterator already yielded the toggled bucket. + // If it did, we're done. + // - Otherwise, update the iterator cached group so that it won't + // yield a to-be-removed bucket, or _will_ yield a to-be-added bucket. + // We'll also need to update the item count accordingly. + if let Some(index) = self.iter.current_group.0.lowest_set_bit() { + let next_bucket = self.iter.data.next_n(index); + if b.as_ptr() > next_bucket.as_ptr() { + // The toggled bucket is "before" the bucket the iterator would yield next. We + // therefore don't need to do anything --- the iterator has already passed the + // bucket in question. + // + // The item count must already be correct, since a removal or insert "prior" to + // the iterator's position wouldn't affect the item count. + } else { + // The removed bucket is an upcoming bucket. We need to make sure it does _not_ + // get yielded, and also that it's no longer included in the item count. + // + // NOTE: We can't just reload the group here, both since that might reflect + // inserts we've already passed, and because that might inadvertently unset the + // bits for _other_ removals. If we do that, we'd have to also decrement the + // item count for those other bits that we unset. But the presumably subsequent + // call to reflect for those buckets might _also_ decrement the item count. + // Instead, we _just_ flip the bit for the particular bucket the caller asked + // us to reflect. + let our_bit = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let was_full = self.iter.current_group.flip(our_bit); + debug_assert_ne!(was_full, is_insert); if is_insert { self.items += 1; @@ -2067,65 +4081,23 @@ impl RawIter { self.items -= 1; } - return; - } - - // The iterator is at the bucket group that the toggled bucket is in. - // We need to do two things: - // - // - Determine if the iterator already yielded the toggled bucket. - // If it did, we're done. - // - Otherwise, update the iterator cached group so that it won't - // yield a to-be-removed bucket, or _will_ yield a to-be-added bucket. - // We'll also need to update the item count accordingly. - if let Some(index) = self.iter.current_group.lowest_set_bit() { - let next_bucket = self.iter.data.next_n(index); - if b.as_ptr() > next_bucket.as_ptr() { - // The toggled bucket is "before" the bucket the iterator would yield next. We - // therefore don't need to do anything --- the iterator has already passed the - // bucket in question. - // - // The item count must already be correct, since a removal or insert "prior" to - // the iterator's position wouldn't affect the item count. - } else { - // The removed bucket is an upcoming bucket. We need to make sure it does _not_ - // get yielded, and also that it's no longer included in the item count. - // - // NOTE: We can't just reload the group here, both since that might reflect - // inserts we've already passed, and because that might inadvertently unset the - // bits for _other_ removals. If we do that, we'd have to also decrement the - // item count for those other bits that we unset. But the presumably subsequent - // call to reflect for those buckets might _also_ decrement the item count. - // Instead, we _just_ flip the bit for the particular bucket the caller asked - // us to reflect. - let our_bit = offset_from(self.iter.data.as_ptr(), b.as_ptr()); - let was_full = self.iter.current_group.flip(our_bit); - debug_assert_ne!(was_full, is_insert); - - if is_insert { - self.items += 1; + if cfg!(debug_assertions) { + if b.as_ptr() == next_bucket.as_ptr() { + // The removed bucket should no longer be next + debug_assert_ne!(self.iter.current_group.0.lowest_set_bit(), Some(index)); } else { - self.items -= 1; - } - - if cfg!(debug_assertions) { - if b.as_ptr() == next_bucket.as_ptr() { - // The removed bucket should no longer be next - debug_assert_ne!(self.iter.current_group.lowest_set_bit(), Some(index)); - } else { - // We should not have changed what bucket comes next. - debug_assert_eq!(self.iter.current_group.lowest_set_bit(), Some(index)); - } + // We should not have changed what bucket comes next. + debug_assert_eq!(self.iter.current_group.0.lowest_set_bit(), Some(index)); } } - } else { - // We must have already iterated past the removed item. } + } else { + // We must have already iterated past the removed item. } } unsafe fn drop_elements(&mut self) { - if mem::needs_drop::() && self.len() != 0 { + if T::NEEDS_DROP && self.items != 0 { for item in self { item.drop(); } @@ -2159,9 +4131,8 @@ impl Iterator for RawIter { self.iter.next_impl::() }; - if nxt.is_some() { - self.items -= 1; - } + debug_assert!(nxt.is_some()); + self.items -= 1; nxt } @@ -2170,33 +4141,160 @@ impl Iterator for RawIter { fn size_hint(&self) -> (usize, Option) { (self.items, Some(self.items)) } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + unsafe { self.iter.fold_impl(self.items, init, f) } + } } impl ExactSizeIterator for RawIter {} impl FusedIterator for RawIter {} +/// Iterator which returns an index of every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding index of that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields indices of the buckets is unspecified +/// and may change in the future. +pub(crate) struct FullBucketsIndices { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Initial value of the bytes' indices of the current group (relative + // to the start of the control bytes). + group_first_index: usize, + + // Pointer to the current group of control bytes, + // Must be aligned to the group size (Group::WIDTH). + ctrl: NonNull, + + // Number of elements in the table. + items: usize, +} + +impl FullBucketsIndices { + /// Advances the iterator and returns the next value. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `FullBucketsIndices`; + /// + /// * It never tries to iterate after getting all elements. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn next_impl(&mut self) -> Option { + loop { + if let Some(index) = self.current_group.next() { + // The returned `self.group_first_index + index` will always + // be in the range `0..self.buckets()`. See explanation below. + return Some(self.group_first_index + index); + } + + // SAFETY: The caller of this function ensures that: + // + // 1. It never tries to iterate after getting all the elements; + // 2. The table is alive and did not moved; + // 3. The first `self.ctrl` pointed to the start of the array of control bytes. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // the start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.ctrl` will be equal to + // the `self.buckets() - Group::WIDTH`, so `self.current_group.next()` + // will always contains indices within the range `0..Group::WIDTH`, + // and subsequent `self.group_first_index + index` will always return a + // number less than `self.buckets()`. + self.ctrl = NonNull::new_unchecked(self.ctrl.as_ptr().add(Group::WIDTH)); + + // SAFETY: See explanation above. + self.current_group = Group::load_aligned(self.ctrl.as_ptr()) + .match_full() + .into_iter(); + self.group_first_index += Group::WIDTH; + } + } +} + +impl Iterator for FullBucketsIndices { + type Item = usize; + + /// Advances the iterator and returns the next value. It is up to + /// the caller to ensure that the `RawTable` outlives the `FullBucketsIndices`, + /// because we cannot make the `next` method unsafe. + #[inline(always)] + fn next(&mut self) -> Option { + // Return if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: + // 1. We check number of items to yield using `items` field. + // 2. The caller ensures that the table is alive and has not moved. + self.next_impl() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } +} + +impl ExactSizeIterator for FullBucketsIndices {} +impl FusedIterator for FullBucketsIndices {} + /// Iterator which consumes a table and returns elements. -pub struct RawIntoIter { +pub struct RawIntoIter { iter: RawIter, - allocation: Option<(NonNull, Layout)>, + allocation: Option<(NonNull, Layout, A)>, marker: PhantomData, - alloc: A, } -impl RawIntoIter { +impl RawIntoIter { #[cfg_attr(feature = "inline-more", inline)] pub fn iter(&self) -> RawIter { self.iter.clone() } } -unsafe impl Send for RawIntoIter +unsafe impl Send for RawIntoIter where T: Send, A: Send, { } -unsafe impl Sync for RawIntoIter +unsafe impl Sync for RawIntoIter where T: Sync, A: Sync, @@ -2204,7 +4302,7 @@ where } #[cfg(feature = "nightly")] -unsafe impl<#[may_dangle] T, A: Allocator + Clone> Drop for RawIntoIter { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawIntoIter { #[cfg_attr(feature = "inline-more", inline)] fn drop(&mut self) { unsafe { @@ -2212,14 +4310,14 @@ unsafe impl<#[may_dangle] T, A: Allocator + Clone> Drop for RawIntoIter { self.iter.drop_elements(); // Free the table - if let Some((ptr, layout)) = self.allocation { - self.alloc.deallocate(ptr, layout); + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); } } } } #[cfg(not(feature = "nightly"))] -impl Drop for RawIntoIter { +impl Drop for RawIntoIter { #[cfg_attr(feature = "inline-more", inline)] fn drop(&mut self) { unsafe { @@ -2227,14 +4325,14 @@ impl Drop for RawIntoIter { self.iter.drop_elements(); // Free the table - if let Some((ptr, layout)) = self.allocation { - self.alloc.deallocate(ptr, layout); + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); } } } } -impl Iterator for RawIntoIter { +impl Iterator for RawIntoIter { type Item = T; #[cfg_attr(feature = "inline-more", inline)] @@ -2248,45 +4346,45 @@ impl Iterator for RawIntoIter { } } -impl ExactSizeIterator for RawIntoIter {} -impl FusedIterator for RawIntoIter {} +impl ExactSizeIterator for RawIntoIter {} +impl FusedIterator for RawIntoIter {} /// Iterator which consumes elements without freeing the table storage. -pub struct RawDrain<'a, T, A: Allocator + Clone = Global> { +pub struct RawDrain<'a, T, A: Allocator = Global> { iter: RawIter, // The table is moved into the iterator for the duration of the drain. This // ensures that an empty table is left if the drain iterator is leaked // without dropping. - table: ManuallyDrop>, - orig_table: NonNull>, + table: RawTableInner, + orig_table: NonNull, // We don't use a &'a mut RawTable because we want RawDrain to be // covariant over T. marker: PhantomData<&'a RawTable>, } -impl RawDrain<'_, T, A> { +impl RawDrain<'_, T, A> { #[cfg_attr(feature = "inline-more", inline)] pub fn iter(&self) -> RawIter { self.iter.clone() } } -unsafe impl Send for RawDrain<'_, T, A> +unsafe impl Send for RawDrain<'_, T, A> where T: Send, A: Send, { } -unsafe impl Sync for RawDrain<'_, T, A> +unsafe impl Sync for RawDrain<'_, T, A> where T: Sync, A: Sync, { } -impl Drop for RawDrain<'_, T, A> { +impl Drop for RawDrain<'_, T, A> { #[cfg_attr(feature = "inline-more", inline)] fn drop(&mut self) { unsafe { @@ -2300,12 +4398,12 @@ impl Drop for RawDrain<'_, T, A> { // Move the now empty table back to its original location. self.orig_table .as_ptr() - .copy_from_nonoverlapping(&*self.table, 1); + .copy_from_nonoverlapping(&self.table, 1); } } } -impl Iterator for RawDrain<'_, T, A> { +impl Iterator for RawDrain<'_, T, A> { type Item = T; #[cfg_attr(feature = "inline-more", inline)] @@ -2322,21 +4420,36 @@ impl Iterator for RawDrain<'_, T, A> { } } -impl ExactSizeIterator for RawDrain<'_, T, A> {} -impl FusedIterator for RawDrain<'_, T, A> {} +impl ExactSizeIterator for RawDrain<'_, T, A> {} +impl FusedIterator for RawDrain<'_, T, A> {} /// Iterator over occupied buckets that could match a given hash. /// /// `RawTable` only stores 7 bits of the hash value, so this iterator may return /// items that have a hash value different than the one provided. You should /// always validate the returned values before using them. -pub struct RawIterHash<'a, T, A: Allocator + Clone = Global> { - inner: RawIterHashInner<'a, A>, +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields buckets is unspecified and may +/// change in the future. +pub struct RawIterHash { + inner: RawIterHashInner, _marker: PhantomData, } -struct RawIterHashInner<'a, A: Allocator + Clone> { - table: &'a RawTableInner, +struct RawIterHashInner { + // See `RawTableInner`'s corresponding fields for details. + // We can't store a `*const RawTableInner` as it would get + // invalidated by the user calling `&mut` methods on `RawTable`. + bucket_mask: usize, + ctrl: NonNull, // The top 7 bits of the hash. h2_hash: u8, @@ -2350,71 +4463,105 @@ struct RawIterHashInner<'a, A: Allocator + Clone> { bitmask: BitMaskIter, } -impl<'a, T, A: Allocator + Clone> RawIterHash<'a, T, A> { +impl RawIterHash { #[cfg_attr(feature = "inline-more", inline)] #[cfg(feature = "raw")] - fn new(table: &'a RawTable, hash: u64) -> Self { + unsafe fn new(table: &RawTable, hash: u64) -> Self { RawIterHash { inner: RawIterHashInner::new(&table.table, hash), _marker: PhantomData, } } } -impl<'a, A: Allocator + Clone> RawIterHashInner<'a, A> { +impl RawIterHashInner { #[cfg_attr(feature = "inline-more", inline)] #[cfg(feature = "raw")] - fn new(table: &'a RawTableInner, hash: u64) -> Self { - unsafe { - let h2_hash = h2(hash); - let probe_seq = table.probe_seq(hash); - let group = Group::load(table.ctrl(probe_seq.pos)); - let bitmask = group.match_byte(h2_hash).into_iter(); - - RawIterHashInner { - table, - h2_hash, - probe_seq, - group, - bitmask, - } + unsafe fn new(table: &RawTableInner, hash: u64) -> Self { + let h2_hash = h2(hash); + let probe_seq = table.probe_seq(hash); + let group = Group::load(table.ctrl(probe_seq.pos)); + let bitmask = group.match_byte(h2_hash).into_iter(); + + RawIterHashInner { + bucket_mask: table.bucket_mask, + ctrl: table.ctrl, + h2_hash, + probe_seq, + group, + bitmask, } } } -impl<'a, T, A: Allocator + Clone> Iterator for RawIterHash<'a, T, A> { +impl Iterator for RawIterHash { type Item = Bucket; fn next(&mut self) -> Option> { unsafe { match self.inner.next() { - Some(index) => Some(self.inner.table.bucket(index)), + Some(index) => { + // Can't use `RawTable::bucket` here as we don't have + // an actual `RawTable` reference to use. + debug_assert!(index <= self.inner.bucket_mask); + let bucket = Bucket::from_base_index(self.inner.ctrl.cast(), index); + Some(bucket) + } None => None, } } } } -impl<'a, A: Allocator + Clone> Iterator for RawIterHashInner<'a, A> { +impl Iterator for RawIterHashInner { type Item = usize; fn next(&mut self) -> Option { unsafe { loop { if let Some(bit) = self.bitmask.next() { - let index = (self.probe_seq.pos + bit) & self.table.bucket_mask; + let index = (self.probe_seq.pos + bit) & self.bucket_mask; return Some(index); } if likely(self.group.match_empty().any_bit_set()) { return None; } - self.probe_seq.move_next(self.table.bucket_mask); - self.group = Group::load(self.table.ctrl(self.probe_seq.pos)); + self.probe_seq.move_next(self.bucket_mask); + + // Can't use `RawTableInner::ctrl` here as we don't have + // an actual `RawTableInner` reference to use. + let index = self.probe_seq.pos; + debug_assert!(index < self.bucket_mask + 1 + Group::WIDTH); + let group_ctrl = self.ctrl.as_ptr().add(index); + + self.group = Group::load(group_ctrl); self.bitmask = self.group.match_byte(self.h2_hash).into_iter(); } } } } +pub(crate) struct RawExtractIf<'a, T, A: Allocator> { + pub iter: RawIter, + pub table: &'a mut RawTable, +} + +impl RawExtractIf<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn next(&mut self, mut f: F) -> Option + where + F: FnMut(&mut T) -> bool, + { + unsafe { + for item in &mut self.iter { + if f(item.as_mut()) { + return Some(self.table.remove(item).0); + } + } + } + None + } +} + #[cfg(test)] mod test_map { use super::*; @@ -2457,4 +4604,214 @@ mod test_map { assert!(table.find(i + 100, |x| *x == i + 100).is_none()); } } + + /// CHECKING THAT WE ARE NOT TRYING TO READ THE MEMORY OF + /// AN UNINITIALIZED TABLE DURING THE DROP + #[test] + fn test_drop_uninitialized() { + use ::alloc::vec::Vec; + + let table = unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap() + }; + drop(table); + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_drop_zero_items() { + use ::alloc::vec::Vec; + unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + let table = + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap(); + + // WE SIMULATE, AS IT WERE, A FULL TABLE. + + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `table.table.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + table + .table + .ctrl(0) + .write_bytes(EMPTY, table.table.num_ctrl_bytes()); + + // SAFETY: table.capacity() is guaranteed to be smaller than table.buckets() + table.table.ctrl(0).write_bytes(0, table.capacity()); + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + if table.buckets() < Group::WIDTH { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(Group::WIDTH), table.table.buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(table.table.buckets()), Group::WIDTH); + } + drop(table); + } + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_catch_panic_clone_from() { + use ::alloc::sync::Arc; + use ::alloc::vec::Vec; + use allocator_api2::alloc::{AllocError, Allocator, Global}; + use core::sync::atomic::{AtomicI8, Ordering}; + use std::thread; + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + struct CheckedCloneDrop { + panic_in_clone: bool, + dropped: bool, + need_drop: Vec, + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + dropped: self.dropped, + need_drop: self.need_drop.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + let mut table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + + for (idx, panic_in_clone) in core::iter::repeat(DISARMED).take(7).enumerate() { + let idx = idx as u64; + table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx], + }, + ), + |(k, _)| *k, + ); + } + + assert_eq!(table.len(), 7); + + thread::scope(|s| { + let result = s.spawn(|| { + let armed_flags = [ + DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + let mut scope_table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + for (idx, &panic_in_clone) in armed_flags.iter().enumerate() { + let idx = idx as u64; + scope_table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx + 100], + }, + ), + |(k, _)| *k, + ); + } + table.clone_from(&scope_table); + }); + assert!(result.join().is_err()); + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(table.len(), 0); + assert_eq!(unsafe { table.iter().count() }, 0); + assert_eq!(unsafe { table.iter().iter.count() }, 0); + + for idx in 0..table.buckets() { + let idx = idx as u64; + assert!( + table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 1); + } } diff --git a/third_party/rust/hashbrown/src/raw/neon.rs b/third_party/rust/hashbrown/src/raw/neon.rs new file mode 100644 index 0000000000..44e82d57d5 --- /dev/null +++ b/third_party/rust/hashbrown/src/raw/neon.rs @@ -0,0 +1,124 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::arch::aarch64 as neon; +use core::mem; +use core::num::NonZeroU64; + +pub(crate) type BitMaskWord = u64; +pub(crate) type NonZeroBitMaskWord = NonZeroU64; +pub(crate) const BITMASK_STRIDE: usize = 8; +pub(crate) const BITMASK_MASK: BitMaskWord = !0; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = 0x8080_8080_8080_8080; + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a 64-bit NEON value. +#[derive(Copy, Clone)] +pub(crate) struct Group(neon::uint8x8_t); + +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const u8) -> Self { + Group(neon::vld1_u8(ptr)) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(neon::vld1_u8(ptr)) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + neon::vst1_u8(ptr, self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which *may* + /// have the given value. + #[inline] + pub(crate) fn match_byte(self, byte: u8) -> BitMask { + unsafe { + let cmp = neon::vceq_u8(self.0, neon::vdup_n_u8(byte)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_byte(EMPTY) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + unsafe { + let cmp = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + unsafe { + let cmp = neon::vcgez_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + unsafe { + let special = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + Group(neon::vorr_u8(special, neon::vdup_n_u8(0x80))) + } + } +} diff --git a/third_party/rust/hashbrown/src/raw/sse2.rs b/third_party/rust/hashbrown/src/raw/sse2.rs index a0bf6da804..956ba5d265 100644 --- a/third_party/rust/hashbrown/src/raw/sse2.rs +++ b/third_party/rust/hashbrown/src/raw/sse2.rs @@ -1,28 +1,31 @@ use super::bitmask::BitMask; use super::EMPTY; use core::mem; +use core::num::NonZeroU16; #[cfg(target_arch = "x86")] use core::arch::x86; #[cfg(target_arch = "x86_64")] use core::arch::x86_64 as x86; -pub type BitMaskWord = u16; -pub const BITMASK_STRIDE: usize = 1; -pub const BITMASK_MASK: BitMaskWord = 0xffff; +pub(crate) type BitMaskWord = u16; +pub(crate) type NonZeroBitMaskWord = NonZeroU16; +pub(crate) const BITMASK_STRIDE: usize = 1; +pub(crate) const BITMASK_MASK: BitMaskWord = 0xffff; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; /// Abstraction over a group of control bytes which can be scanned in /// parallel. /// /// This implementation uses a 128-bit SSE value. #[derive(Copy, Clone)] -pub struct Group(x86::__m128i); +pub(crate) struct Group(x86::__m128i); // FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 #[allow(clippy::use_self)] impl Group { /// Number of bytes in the group. - pub const WIDTH: usize = mem::size_of::(); + pub(crate) const WIDTH: usize = mem::size_of::(); /// Returns a full group of empty bytes, suitable for use as the initial /// value for an empty hash table. @@ -30,7 +33,7 @@ impl Group { /// This is guaranteed to be aligned to the group size. #[inline] #[allow(clippy::items_after_statements)] - pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { #[repr(C)] struct AlignedBytes { _align: [Group; 0], @@ -46,7 +49,7 @@ impl Group { /// Loads a group of bytes starting at the given address. #[inline] #[allow(clippy::cast_ptr_alignment)] // unaligned load - pub unsafe fn load(ptr: *const u8) -> Self { + pub(crate) unsafe fn load(ptr: *const u8) -> Self { Group(x86::_mm_loadu_si128(ptr.cast())) } @@ -54,7 +57,7 @@ impl Group { /// aligned to `mem::align_of::()`. #[inline] #[allow(clippy::cast_ptr_alignment)] - pub unsafe fn load_aligned(ptr: *const u8) -> Self { + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { // FIXME: use align_offset once it stabilizes debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); Group(x86::_mm_load_si128(ptr.cast())) @@ -64,7 +67,7 @@ impl Group { /// aligned to `mem::align_of::()`. #[inline] #[allow(clippy::cast_ptr_alignment)] - pub unsafe fn store_aligned(self, ptr: *mut u8) { + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { // FIXME: use align_offset once it stabilizes debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); x86::_mm_store_si128(ptr.cast(), self.0); @@ -73,7 +76,7 @@ impl Group { /// Returns a `BitMask` indicating all bytes in the group which have /// the given value. #[inline] - pub fn match_byte(self, byte: u8) -> BitMask { + pub(crate) fn match_byte(self, byte: u8) -> BitMask { #[allow( clippy::cast_possible_wrap, // byte: u8 as i8 // byte: i32 as u16 @@ -91,14 +94,14 @@ impl Group { /// Returns a `BitMask` indicating all bytes in the group which are /// `EMPTY`. #[inline] - pub fn match_empty(self) -> BitMask { + pub(crate) fn match_empty(self) -> BitMask { self.match_byte(EMPTY) } /// Returns a `BitMask` indicating all bytes in the group which are /// `EMPTY` or `DELETED`. #[inline] - pub fn match_empty_or_deleted(self) -> BitMask { + pub(crate) fn match_empty_or_deleted(self) -> BitMask { #[allow( // byte: i32 as u16 // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the @@ -114,7 +117,7 @@ impl Group { /// Returns a `BitMask` indicating all bytes in the group which are full. #[inline] - pub fn match_full(&self) -> BitMask { + pub(crate) fn match_full(&self) -> BitMask { self.match_empty_or_deleted().invert() } @@ -123,7 +126,7 @@ impl Group { /// - `DELETED => EMPTY` /// - `FULL => DELETED` #[inline] - pub fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 // and high_bit = 0 (FULL) to 1000_0000 // diff --git a/third_party/rust/hashbrown/src/rustc_entry.rs b/third_party/rust/hashbrown/src/rustc_entry.rs index 2e84595269..defbd4bb88 100644 --- a/third_party/rust/hashbrown/src/rustc_entry.rs +++ b/third_party/rust/hashbrown/src/rustc_entry.rs @@ -1,5 +1,5 @@ use self::RustcEntry::*; -use crate::map::{make_insert_hash, Drain, HashMap, IntoIter, Iter, IterMut}; +use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut}; use crate::raw::{Allocator, Bucket, Global, RawTable}; use core::fmt::{self, Debug}; use core::hash::{BuildHasher, Hash}; @@ -9,7 +9,7 @@ impl HashMap where K: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { /// Gets the given key's corresponding entry in the map for in-place manipulation. /// @@ -32,7 +32,7 @@ where /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> { - let hash = make_insert_hash(&self.hash_builder, &key); + let hash = make_hash(&self.hash_builder, &key); if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { RustcEntry::Occupied(RustcOccupiedEntry { key: Some(key), @@ -62,7 +62,7 @@ where /// [`rustc_entry`]: struct.HashMap.html#method.rustc_entry pub enum RustcEntry<'a, K, V, A = Global> where - A: Allocator + Clone, + A: Allocator, { /// An occupied entry. Occupied(RustcOccupiedEntry<'a, K, V, A>), @@ -71,7 +71,7 @@ where Vacant(RustcVacantEntry<'a, K, V, A>), } -impl Debug for RustcEntry<'_, K, V, A> { +impl Debug for RustcEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -86,7 +86,7 @@ impl Debug for RustcEntry<'_, K, V, A> /// [`RustcEntry`]: enum.RustcEntry.html pub struct RustcOccupiedEntry<'a, K, V, A = Global> where - A: Allocator + Clone, + A: Allocator, { key: Option, elem: Bucket<(K, V)>, @@ -97,18 +97,18 @@ unsafe impl Send for RustcOccupiedEntry<'_, K, V, A> where K: Send, V: Send, - A: Allocator + Clone + Send, + A: Allocator + Send, { } unsafe impl Sync for RustcOccupiedEntry<'_, K, V, A> where K: Sync, V: Sync, - A: Allocator + Clone + Sync, + A: Allocator + Sync, { } -impl Debug for RustcOccupiedEntry<'_, K, V, A> { +impl Debug for RustcOccupiedEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) @@ -123,20 +123,20 @@ impl Debug for RustcOccupiedEntry<'_, /// [`RustcEntry`]: enum.RustcEntry.html pub struct RustcVacantEntry<'a, K, V, A = Global> where - A: Allocator + Clone, + A: Allocator, { hash: u64, key: K, table: &'a mut RawTable<(K, V), A>, } -impl Debug for RustcVacantEntry<'_, K, V, A> { +impl Debug for RustcVacantEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } } -impl<'a, K, V, A: Allocator + Clone> RustcEntry<'a, K, V, A> { +impl<'a, K, V, A: Allocator> RustcEntry<'a, K, V, A> { /// Sets the value of the entry, and returns a RustcOccupiedEntry. /// /// # Examples @@ -265,7 +265,7 @@ impl<'a, K, V, A: Allocator + Clone> RustcEntry<'a, K, V, A> { } } -impl<'a, K, V: Default, A: Allocator + Clone> RustcEntry<'a, K, V, A> { +impl<'a, K, V: Default, A: Allocator> RustcEntry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// @@ -293,7 +293,7 @@ impl<'a, K, V: Default, A: Allocator + Clone> RustcEntry<'a, K, V, A> { } } -impl<'a, K, V, A: Allocator + Clone> RustcOccupiedEntry<'a, K, V, A> { +impl<'a, K, V, A: Allocator> RustcOccupiedEntry<'a, K, V, A> { /// Gets a reference to the key in the entry. /// /// # Examples @@ -330,7 +330,7 @@ impl<'a, K, V, A: Allocator + Clone> RustcOccupiedEntry<'a, K, V, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove_entry(self) -> (K, V) { - unsafe { self.table.remove(self.elem) } + unsafe { self.table.remove(self.elem).0 } } /// Gets a reference to the value in the entry. @@ -518,7 +518,7 @@ impl<'a, K, V, A: Allocator + Clone> RustcOccupiedEntry<'a, K, V, A> { } } -impl<'a, K, V, A: Allocator + Clone> RustcVacantEntry<'a, K, V, A> { +impl<'a, K, V, A: Allocator> RustcVacantEntry<'a, K, V, A> { /// Gets a reference to the key that would be used when inserting a value /// through the `RustcVacantEntry`. /// diff --git a/third_party/rust/hashbrown/src/scopeguard.rs b/third_party/rust/hashbrown/src/scopeguard.rs index f85e6ab0ed..382d06043e 100644 --- a/third_party/rust/hashbrown/src/scopeguard.rs +++ b/third_party/rust/hashbrown/src/scopeguard.rs @@ -1,6 +1,6 @@ // Extracted from the scopeguard crate use core::{ - mem, + mem::ManuallyDrop, ops::{Deref, DerefMut}, ptr, }; @@ -28,15 +28,13 @@ where #[inline] pub fn into_inner(guard: Self) -> T { // Cannot move out of Drop-implementing types, so - // ptr::read the value and forget the guard. + // ptr::read the value out of a ManuallyDrop + // Don't use mem::forget as that might invalidate value + let guard = ManuallyDrop::new(guard); unsafe { let value = ptr::read(&guard.value); - // read the closure so that it is dropped, and assign it to a local - // variable to ensure that it is only dropped after the guard has - // been forgotten. (In case the Drop impl of the closure, or that - // of any consumed captured variable, panics). - let _dropfn = ptr::read(&guard.dropfn); - mem::forget(guard); + // read the closure so that it is dropped + let _ = ptr::read(&guard.dropfn); value } } diff --git a/third_party/rust/hashbrown/src/set.rs b/third_party/rust/hashbrown/src/set.rs index 2a4dcea52c..2125a7ac81 100644 --- a/third_party/rust/hashbrown/src/set.rs +++ b/third_party/rust/hashbrown/src/set.rs @@ -1,14 +1,14 @@ -use crate::TryReserveError; +#[cfg(feature = "raw")] +use crate::raw::RawTable; +use crate::{Equivalent, TryReserveError}; use alloc::borrow::ToOwned; -use core::borrow::Borrow; use core::fmt; use core::hash::{BuildHasher, Hash}; -use core::iter::{Chain, FromIterator, FusedIterator}; -use core::mem; +use core::iter::{Chain, FusedIterator}; use core::ops::{BitAnd, BitOr, BitXor, Sub}; -use super::map::{self, ConsumeAllOnDrop, DefaultHashBuilder, DrainFilterInner, HashMap, Keys}; -use crate::raw::{Allocator, Global}; +use super::map::{self, DefaultHashBuilder, HashMap, Keys}; +use crate::raw::{Allocator, Global, RawExtractIf}; // Future Optimization (FIXME!) // ============================= @@ -102,7 +102,7 @@ use crate::raw::{Allocator, Global}; /// use hashbrown::HashSet; /// /// let viking_names: HashSet<&'static str> = -/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); +/// [ "Einar", "Olaf", "Harald" ].into_iter().collect(); /// // use the values stored in the set /// ``` /// @@ -112,7 +112,7 @@ use crate::raw::{Allocator, Global}; /// [`HashMap`]: struct.HashMap.html /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html /// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html -pub struct HashSet { +pub struct HashSet { pub(crate) map: HashMap, } @@ -135,6 +135,18 @@ impl HashSet { /// The hash set is initially created with a capacity of 0, so it will not allocate until it /// is first inserted into. /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher`](HashSet::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// /// # Examples /// /// ``` @@ -153,6 +165,18 @@ impl HashSet { /// The hash set will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash set will not allocate. /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher`](HashSet::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// /// # Examples /// /// ``` @@ -169,12 +193,24 @@ impl HashSet { } #[cfg(feature = "ahash")] -impl HashSet { +impl HashSet { /// Creates an empty `HashSet`. /// /// The hash set is initially created with a capacity of 0, so it will not allocate until it /// is first inserted into. /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher_in`](HashSet::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// /// # Examples /// /// ``` @@ -193,6 +229,18 @@ impl HashSet { /// The hash set will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash set will not allocate. /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher_in`](HashSet::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// /// # Examples /// /// ``` @@ -208,7 +256,7 @@ impl HashSet { } } -impl HashSet { +impl HashSet { /// Returns the number of elements the set can hold without reallocating. /// /// # Examples @@ -287,7 +335,7 @@ impl HashSet { /// ``` /// use hashbrown::HashSet; /// - /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); /// assert!(!set.is_empty()); /// /// // print 1, 2, 3 in an arbitrary order @@ -314,7 +362,7 @@ impl HashSet { /// use hashbrown::HashSet; /// /// let xs = [1,2,3,4,5,6]; - /// let mut set: HashSet = xs.iter().cloned().collect(); + /// let mut set: HashSet = xs.into_iter().collect(); /// set.retain(|&k| k % 2 == 0); /// assert_eq!(set.len(), 3); /// ``` @@ -331,8 +379,11 @@ impl HashSet { /// In other words, move all elements `e` such that `f(&e)` returns `true` out /// into another iterator. /// - /// When the returned DrainedFilter is dropped, any remaining elements that satisfy - /// the predicate are dropped from the set. + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashSet::retain /// /// # Examples /// @@ -340,7 +391,7 @@ impl HashSet { /// use hashbrown::HashSet; /// /// let mut set: HashSet = (0..8).collect(); - /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// let drained: HashSet = set.extract_if(|v| v % 2 == 0).collect(); /// /// let mut evens = drained.into_iter().collect::>(); /// let mut odds = set.into_iter().collect::>(); @@ -351,13 +402,13 @@ impl HashSet { /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[cfg_attr(feature = "inline-more", inline)] - pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, T, F, A> + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool, { - DrainFilter { + ExtractIf { f, - inner: DrainFilterInner { + inner: RawExtractIf { iter: unsafe { self.map.table.iter() }, table: &mut self.map.table, }, @@ -386,16 +437,23 @@ impl HashSet { /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// - /// The hash set is also created with the default initial capacity. + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. /// /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. + /// the HashSet to be useful, see its documentation for details. /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html /// /// # Examples /// @@ -407,8 +465,6 @@ impl HashSet { /// let mut set = HashSet::with_hasher(s); /// set.insert(2); /// ``` - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[cfg_attr(feature = "inline-more", inline)] pub const fn with_hasher(hasher: S) -> Self { Self { @@ -422,13 +478,20 @@ impl HashSet { /// The hash set will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash set will not allocate. /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. /// /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html /// /// # Examples /// @@ -440,8 +503,6 @@ impl HashSet { /// let mut set = HashSet::with_capacity_and_hasher(10, s); /// set.insert(1); /// ``` - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[cfg_attr(feature = "inline-more", inline)] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { Self { @@ -452,7 +513,7 @@ impl HashSet { impl HashSet where - A: Allocator + Clone, + A: Allocator, { /// Returns a reference to the underlying allocator. #[inline] @@ -463,12 +524,23 @@ where /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// - /// The hash set is also created with the default initial capacity. + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html /// /// # Examples /// @@ -481,7 +553,7 @@ where /// set.insert(2); /// ``` #[cfg_attr(feature = "inline-more", inline)] - pub fn with_hasher_in(hasher: S, alloc: A) -> Self { + pub const fn with_hasher_in(hasher: S, alloc: A) -> Self { Self { map: HashMap::with_hasher_in(hasher, alloc), } @@ -493,10 +565,20 @@ where /// The hash set will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash set will not allocate. /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html /// /// # Examples /// @@ -539,7 +621,7 @@ impl HashSet where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to avoid @@ -547,7 +629,12 @@ where /// /// # Panics /// - /// Panics if the new allocation size overflows `usize`. + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashSet::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html /// /// # Examples /// @@ -637,8 +724,8 @@ where /// /// ``` /// use hashbrown::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); /// /// // Can be seen as `a - b`. /// for x in a.difference(&b) { @@ -668,8 +755,8 @@ where /// /// ``` /// use hashbrown::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); /// /// // Print 1, 4 in arbitrary order. /// for x in a.symmetric_difference(&b) { @@ -696,8 +783,8 @@ where /// /// ``` /// use hashbrown::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); /// /// // Print 2, 3 in arbitrary order. /// for x in a.intersection(&b) { @@ -727,8 +814,8 @@ where /// /// ``` /// use hashbrown::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); /// /// // Print 1, 2, 3, 4 in arbitrary order. /// for x in a.union(&b) { @@ -763,7 +850,7 @@ where /// ``` /// use hashbrown::HashSet; /// - /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); /// assert_eq!(set.contains(&1), true); /// assert_eq!(set.contains(&4), false); /// ``` @@ -773,8 +860,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn contains(&self, value: &Q) -> bool where - T: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { self.map.contains_key(value) } @@ -790,7 +876,7 @@ where /// ``` /// use hashbrown::HashSet; /// - /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); /// assert_eq!(set.get(&2), Some(&2)); /// assert_eq!(set.get(&4), None); /// ``` @@ -800,8 +886,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn get(&self, value: &Q) -> Option<&T> where - T: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { // Avoid `Option::map` because it bloats LLVM IR. match self.map.get_key_value(value) { @@ -818,7 +903,7 @@ where /// ``` /// use hashbrown::HashSet; /// - /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); /// assert_eq!(set.len(), 3); /// assert_eq!(set.get_or_insert(2), &2); /// assert_eq!(set.get_or_insert(100), &100); @@ -856,8 +941,7 @@ where #[inline] pub fn get_or_insert_owned(&mut self, value: &Q) -> &T where - T: Borrow, - Q: Hash + Eq + ToOwned, + Q: Hash + Equivalent + ToOwned, { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. @@ -889,8 +973,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T where - T: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, F: FnOnce(&Q) -> T, { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with @@ -951,7 +1034,7 @@ where /// ``` /// use hashbrown::HashSet; /// - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); /// let mut b = HashSet::new(); /// /// assert_eq!(a.is_disjoint(&b), true); @@ -972,7 +1055,7 @@ where /// ``` /// use hashbrown::HashSet; /// - /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let sup: HashSet<_> = [1, 2, 3].into_iter().collect(); /// let mut set = HashSet::new(); /// /// assert_eq!(set.is_subset(&sup), true); @@ -993,7 +1076,7 @@ where /// ``` /// use hashbrown::HashSet; /// - /// let sub: HashSet<_> = [1, 2].iter().cloned().collect(); + /// let sub: HashSet<_> = [1, 2].into_iter().collect(); /// let mut set = HashSet::new(); /// /// assert_eq!(set.is_superset(&sub), false); @@ -1106,8 +1189,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn remove(&mut self, value: &Q) -> bool where - T: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { self.map.remove(value).is_some() } @@ -1123,7 +1205,7 @@ where /// ``` /// use hashbrown::HashSet; /// - /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); /// assert_eq!(set.take(&2), Some(2)); /// assert_eq!(set.take(&2), None); /// ``` @@ -1133,8 +1215,7 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn take(&mut self, value: &Q) -> Option where - T: Borrow, - Q: Hash + Eq, + Q: Hash + Equivalent, { // Avoid `Option::map` because it bloats LLVM IR. match self.map.remove_entry(value) { @@ -1144,11 +1225,53 @@ where } } +impl HashSet { + /// Returns a reference to the [`RawTable`] used underneath [`HashSet`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the set that can be useful + /// for extending the HashSet's API, but may lead to *[undefined behavior]*. + /// + /// [`HashSet`]: struct.HashSet.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table(&self) -> &RawTable<(T, ()), A> { + self.map.raw_table() + } + + /// Returns a mutable reference to the [`RawTable`] used underneath [`HashSet`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the set that can be useful + /// for extending the HashSet's API, but may lead to *[undefined behavior]*. + /// + /// [`HashSet`]: struct.HashSet.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table_mut(&mut self) -> &mut RawTable<(T, ()), A> { + self.map.raw_table_mut() + } +} + impl PartialEq for HashSet where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn eq(&self, other: &Self) -> bool { if self.len() != other.len() { @@ -1163,14 +1286,14 @@ impl Eq for HashSet where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { } impl fmt::Debug for HashSet where T: fmt::Debug, - A: Allocator + Clone, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() @@ -1179,7 +1302,7 @@ where impl From> for HashSet where - A: Allocator + Clone, + A: Allocator, { fn from(map: HashMap) -> Self { Self { map } @@ -1190,7 +1313,7 @@ impl FromIterator for HashSet where T: Eq + Hash, S: BuildHasher + Default, - A: Default + Allocator + Clone, + A: Default + Allocator, { #[cfg_attr(feature = "inline-more", inline)] fn from_iter>(iter: I) -> Self { @@ -1205,7 +1328,7 @@ where impl From<[T; N]> for HashSet where T: Eq + Hash, - A: Default + Allocator + Clone, + A: Default + Allocator, { /// # Examples /// @@ -1225,7 +1348,7 @@ impl Extend for HashSet where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { #[cfg_attr(feature = "inline-more", inline)] fn extend>(&mut self, iter: I) { @@ -1249,7 +1372,7 @@ impl<'a, T, S, A> Extend<&'a T> for HashSet where T: 'a + Eq + Hash + Copy, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { #[cfg_attr(feature = "inline-more", inline)] fn extend>(&mut self, iter: I) { @@ -1272,7 +1395,7 @@ where impl Default for HashSet where S: Default, - A: Default + Allocator + Clone, + A: Default + Allocator, { /// Creates an empty `HashSet` with the `Default` value for the hasher. #[cfg_attr(feature = "inline-more", inline)] @@ -1287,7 +1410,7 @@ impl BitOr<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default, - A: Allocator + Clone, + A: Allocator, { type Output = HashSet; @@ -1320,7 +1443,7 @@ impl BitAnd<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default, - A: Allocator + Clone, + A: Allocator, { type Output = HashSet; @@ -1431,7 +1554,7 @@ pub struct Iter<'a, K> { /// /// [`HashSet`]: struct.HashSet.html /// [`into_iter`]: struct.HashSet.html#method.into_iter -pub struct IntoIter { +pub struct IntoIter { iter: map::IntoIter, } @@ -1442,23 +1565,24 @@ pub struct IntoIter { /// /// [`HashSet`]: struct.HashSet.html /// [`drain`]: struct.HashSet.html#method.drain -pub struct Drain<'a, K, A: Allocator + Clone = Global> { +pub struct Drain<'a, K, A: Allocator = Global> { iter: map::Drain<'a, K, (), A>, } /// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`. /// -/// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. See its +/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. See its /// documentation for more. /// -/// [`drain_filter`]: struct.HashSet.html#method.drain_filter +/// [`extract_if`]: struct.HashSet.html#method.extract_if /// [`HashSet`]: struct.HashSet.html -pub struct DrainFilter<'a, K, F, A: Allocator + Clone = Global> +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, F, A: Allocator = Global> where F: FnMut(&K) -> bool, { f: F, - inner: DrainFilterInner<'a, K, (), A>, + inner: RawExtractIf<'a, (K, ()), A>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1468,7 +1592,7 @@ where /// /// [`HashSet`]: struct.HashSet.html /// [`intersection`]: struct.HashSet.html#method.intersection -pub struct Intersection<'a, T, S, A: Allocator + Clone = Global> { +pub struct Intersection<'a, T, S, A: Allocator = Global> { // iterator of the first set iter: Iter<'a, T>, // the second set @@ -1482,7 +1606,7 @@ pub struct Intersection<'a, T, S, A: Allocator + Clone = Global> { /// /// [`HashSet`]: struct.HashSet.html /// [`difference`]: struct.HashSet.html#method.difference -pub struct Difference<'a, T, S, A: Allocator + Clone = Global> { +pub struct Difference<'a, T, S, A: Allocator = Global> { // iterator of the first set iter: Iter<'a, T>, // the second set @@ -1496,7 +1620,7 @@ pub struct Difference<'a, T, S, A: Allocator + Clone = Global> { /// /// [`HashSet`]: struct.HashSet.html /// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference -pub struct SymmetricDifference<'a, T, S, A: Allocator + Clone = Global> { +pub struct SymmetricDifference<'a, T, S, A: Allocator = Global> { iter: Chain, Difference<'a, T, S, A>>, } @@ -1507,11 +1631,11 @@ pub struct SymmetricDifference<'a, T, S, A: Allocator + Clone = Global> { /// /// [`HashSet`]: struct.HashSet.html /// [`union`]: struct.HashSet.html#method.union -pub struct Union<'a, T, S, A: Allocator + Clone = Global> { +pub struct Union<'a, T, S, A: Allocator = Global> { iter: Chain, Difference<'a, T, S, A>>, } -impl<'a, T, S, A: Allocator + Clone> IntoIterator for &'a HashSet { +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1521,7 +1645,7 @@ impl<'a, T, S, A: Allocator + Clone> IntoIterator for &'a HashSet { } } -impl IntoIterator for HashSet { +impl IntoIterator for HashSet { type Item = T; type IntoIter = IntoIter; @@ -1572,6 +1696,14 @@ impl<'a, K> Iterator for Iter<'a, K> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } impl<'a, K> ExactSizeIterator for Iter<'a, K> { #[cfg_attr(feature = "inline-more", inline)] @@ -1587,7 +1719,7 @@ impl fmt::Debug for Iter<'_, K> { } } -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = K; #[cfg_attr(feature = "inline-more", inline)] @@ -1602,23 +1734,31 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } } -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { #[cfg_attr(feature = "inline-more", inline)] fn len(&self) -> usize { self.iter.len() } } -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let entries_iter = self.iter.iter().map(|(k, _)| k); f.debug_list().entries(entries_iter).finish() } } -impl Iterator for Drain<'_, K, A> { +impl Iterator for Drain<'_, K, A> { type Item = K; #[cfg_attr(feature = "inline-more", inline)] @@ -1633,37 +1773,31 @@ impl Iterator for Drain<'_, K, A> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } } -impl ExactSizeIterator for Drain<'_, K, A> { +impl ExactSizeIterator for Drain<'_, K, A> { #[cfg_attr(feature = "inline-more", inline)] fn len(&self) -> usize { self.iter.len() } } -impl FusedIterator for Drain<'_, K, A> {} +impl FusedIterator for Drain<'_, K, A> {} -impl fmt::Debug for Drain<'_, K, A> { +impl fmt::Debug for Drain<'_, K, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let entries_iter = self.iter.iter().map(|(k, _)| k); f.debug_list().entries(entries_iter).finish() } } -impl<'a, K, F, A: Allocator + Clone> Drop for DrainFilter<'a, K, F, A> -where - F: FnMut(&K) -> bool, -{ - #[cfg_attr(feature = "inline-more", inline)] - fn drop(&mut self) { - while let Some(item) = self.next() { - let guard = ConsumeAllOnDrop(self); - drop(item); - mem::forget(guard); - } - } -} - -impl Iterator for DrainFilter<'_, K, F, A> +impl Iterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool, { @@ -1671,9 +1805,9 @@ where #[cfg_attr(feature = "inline-more", inline)] fn next(&mut self) -> Option { - let f = &mut self.f; - let (k, _) = self.inner.next(&mut |k, _| f(k))?; - Some(k) + self.inner + .next(|&mut (ref k, ())| (self.f)(k)) + .map(|(k, ())| k) } #[inline] @@ -1682,12 +1816,9 @@ where } } -impl FusedIterator for DrainFilter<'_, K, F, A> where - F: FnMut(&K) -> bool -{ -} +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} -impl Clone for Intersection<'_, T, S, A> { +impl Clone for Intersection<'_, T, S, A> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { Intersection { @@ -1701,7 +1832,7 @@ impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { type Item = &'a T; @@ -1720,13 +1851,27 @@ where let (_, upper) = self.iter.size_hint(); (0, upper) } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + f(acc, elt) + } else { + acc + } + }) + } } impl fmt::Debug for Intersection<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1737,11 +1882,11 @@ impl FusedIterator for Intersection<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { } -impl Clone for Difference<'_, T, S, A> { +impl Clone for Difference<'_, T, S, A> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { Difference { @@ -1755,7 +1900,7 @@ impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { type Item = &'a T; @@ -1774,13 +1919,27 @@ where let (_, upper) = self.iter.size_hint(); (0, upper) } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + acc + } else { + f(acc, elt) + } + }) + } } impl FusedIterator for Difference<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { } @@ -1788,14 +1947,14 @@ impl fmt::Debug for Difference<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } -impl Clone for SymmetricDifference<'_, T, S, A> { +impl Clone for SymmetricDifference<'_, T, S, A> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { SymmetricDifference { @@ -1808,7 +1967,7 @@ impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { type Item = &'a T; @@ -1820,13 +1979,21 @@ where fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } impl FusedIterator for SymmetricDifference<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { } @@ -1834,14 +2001,14 @@ impl fmt::Debug for SymmetricDifference<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } -impl Clone for Union<'_, T, S, A> { +impl Clone for Union<'_, T, S, A> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { Union { @@ -1854,7 +2021,7 @@ impl FusedIterator for Union<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { } @@ -1862,7 +2029,7 @@ impl fmt::Debug for Union<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1873,7 +2040,7 @@ impl<'a, T, S, A> Iterator for Union<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, - A: Allocator + Clone, + A: Allocator, { type Item = &'a T; @@ -1885,6 +2052,14 @@ where fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } /// A view into a single entry in a set, which may either be vacant or occupied. @@ -1925,7 +2100,7 @@ where /// ``` pub enum Entry<'a, T, S, A = Global> where - A: Allocator + Clone, + A: Allocator, { /// An occupied entry. /// @@ -1958,7 +2133,7 @@ where Vacant(VacantEntry<'a, T, S, A>), } -impl fmt::Debug for Entry<'_, T, S, A> { +impl fmt::Debug for Entry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -2003,11 +2178,11 @@ impl fmt::Debug for Entry<'_, T, S, A> { /// assert_eq!(set.get(&"c"), None); /// assert_eq!(set.len(), 2); /// ``` -pub struct OccupiedEntry<'a, T, S, A: Allocator + Clone = Global> { +pub struct OccupiedEntry<'a, T, S, A: Allocator = Global> { inner: map::OccupiedEntry<'a, T, (), S, A>, } -impl fmt::Debug for OccupiedEntry<'_, T, S, A> { +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("value", self.get()) @@ -2041,17 +2216,17 @@ impl fmt::Debug for OccupiedEntry<'_, T, /// } /// assert!(set.contains("b") && set.len() == 2); /// ``` -pub struct VacantEntry<'a, T, S, A: Allocator + Clone = Global> { +pub struct VacantEntry<'a, T, S, A: Allocator = Global> { inner: map::VacantEntry<'a, T, (), S, A>, } -impl fmt::Debug for VacantEntry<'_, T, S, A> { +impl fmt::Debug for VacantEntry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.get()).finish() } } -impl<'a, T, S, A: Allocator + Clone> Entry<'a, T, S, A> { +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { /// Sets the value of the entry, and returns an OccupiedEntry. /// /// # Examples @@ -2128,7 +2303,7 @@ impl<'a, T, S, A: Allocator + Clone> Entry<'a, T, S, A> { } } -impl OccupiedEntry<'_, T, S, A> { +impl OccupiedEntry<'_, T, S, A> { /// Gets a reference to the value in the entry. /// /// # Examples @@ -2215,7 +2390,7 @@ impl OccupiedEntry<'_, T, S, A> { } } -impl<'a, T, S, A: Allocator + Clone> VacantEntry<'a, T, S, A> { +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { /// Gets a reference to the value that would be used when inserting /// through the `VacantEntry`. /// @@ -2295,34 +2470,30 @@ fn assert_covariance() { fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { v } - fn into_iter<'new, A: Allocator + Clone>( - v: IntoIter<&'static str, A>, - ) -> IntoIter<&'new str, A> { + fn into_iter<'new, A: Allocator>(v: IntoIter<&'static str, A>) -> IntoIter<&'new str, A> { v } - fn difference<'a, 'new, A: Allocator + Clone>( + fn difference<'a, 'new, A: Allocator>( v: Difference<'a, &'static str, DefaultHashBuilder, A>, ) -> Difference<'a, &'new str, DefaultHashBuilder, A> { v } - fn symmetric_difference<'a, 'new, A: Allocator + Clone>( + fn symmetric_difference<'a, 'new, A: Allocator>( v: SymmetricDifference<'a, &'static str, DefaultHashBuilder, A>, ) -> SymmetricDifference<'a, &'new str, DefaultHashBuilder, A> { v } - fn intersection<'a, 'new, A: Allocator + Clone>( + fn intersection<'a, 'new, A: Allocator>( v: Intersection<'a, &'static str, DefaultHashBuilder, A>, ) -> Intersection<'a, &'new str, DefaultHashBuilder, A> { v } - fn union<'a, 'new, A: Allocator + Clone>( + fn union<'a, 'new, A: Allocator>( v: Union<'a, &'static str, DefaultHashBuilder, A>, ) -> Union<'a, &'new str, DefaultHashBuilder, A> { v } - fn drain<'new, A: Allocator + Clone>( - d: Drain<'static, &'static str, A>, - ) -> Drain<'new, &'new str, A> { + fn drain<'new, A: Allocator>(d: Drain<'static, &'static str, A>) -> Drain<'new, &'new str, A> { d } } @@ -2613,10 +2784,10 @@ mod test_set { set.insert(1); set.insert(2); - let set_str = format!("{:?}", set); + let set_str = format!("{set:?}"); assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); - assert_eq!(format!("{:?}", empty), "{}"); + assert_eq!(format!("{empty:?}"), "{}"); } #[test] @@ -2649,7 +2820,7 @@ mod test_set { assert_eq!(last_i, 49); } - for _ in &s { + if !s.is_empty() { panic!("s should be empty!"); } @@ -2663,6 +2834,7 @@ mod test_set { use core::hash; #[derive(Debug)] + #[allow(dead_code)] struct Foo(&'static str, i32); impl PartialEq for Foo { @@ -2691,11 +2863,12 @@ mod test_set { } #[test] + #[allow(clippy::needless_borrow)] fn test_extend_ref() { let mut a = HashSet::new(); a.insert(1); - a.extend(&[2, 3, 4]); + a.extend([2, 3, 4]); assert_eq!(a.len(), 4); assert!(a.contains(&1)); @@ -2730,10 +2903,10 @@ mod test_set { } #[test] - fn test_drain_filter() { + fn test_extract_if() { { let mut set: HashSet = (0..8).collect(); - let drained = set.drain_filter(|&k| k % 2 == 0); + let drained = set.extract_if(|&k| k % 2 == 0); let mut out = drained.collect::>(); out.sort_unstable(); assert_eq!(vec![0, 2, 4, 6], out); @@ -2741,7 +2914,7 @@ mod test_set { } { let mut set: HashSet = (0..8).collect(); - drop(set.drain_filter(|&k| k % 2 == 0)); + set.extract_if(|&k| k % 2 == 0).for_each(drop); assert_eq!(set.len(), 4, "Removes non-matching items on drop"); } } @@ -2787,4 +2960,11 @@ mod test_set { set.insert(i); } } + + #[test] + fn collect() { + // At the time of writing, this hits the ZST case in from_base_index + // (and without the `map`, it does not). + let mut _set: HashSet<_> = (0..3).map(|_| ()).collect(); + } } diff --git a/third_party/rust/hashbrown/src/table.rs b/third_party/rust/hashbrown/src/table.rs new file mode 100644 index 0000000000..faf8a6330f --- /dev/null +++ b/third_party/rust/hashbrown/src/table.rs @@ -0,0 +1,2070 @@ +use core::{fmt, iter::FusedIterator, marker::PhantomData}; + +use crate::{ + raw::{ + Allocator, Bucket, Global, InsertSlot, RawDrain, RawExtractIf, RawIntoIter, RawIter, + RawTable, + }, + TryReserveError, +}; + +/// Low-level hash table with explicit hashing. +/// +/// The primary use case for this type over [`HashMap`] or [`HashSet`] is to +/// support types that do not implement the [`Hash`] and [`Eq`] traits, but +/// instead require additional data not contained in the key itself to compute a +/// hash and compare two elements for equality. +/// +/// Examples of when this can be useful include: +/// - An `IndexMap` implementation where indices into a `Vec` are stored as +/// elements in a `HashTable`. Hashing and comparing the elements +/// requires indexing the associated `Vec` to get the actual value referred to +/// by the index. +/// - Avoiding re-computing a hash when it is already known. +/// - Mutating the key of an element in a way that doesn't affect its hash. +/// +/// To achieve this, `HashTable` methods that search for an element in the table +/// require a hash value and equality function to be explicitly passed in as +/// arguments. The method will then iterate over the elements with the given +/// hash and call the equality function on each of them, until a match is found. +/// +/// In most cases, a `HashTable` will not be exposed directly in an API. It will +/// instead be wrapped in a helper type which handles the work of calculating +/// hash values and comparing elements. +/// +/// Due to its low-level nature, this type provides fewer guarantees than +/// [`HashMap`] and [`HashSet`]. Specifically, the API allows you to shoot +/// yourself in the foot by having multiple elements with identical keys in the +/// table. The table itself will still function correctly and lookups will +/// arbitrarily return one of the matching elements. However you should avoid +/// doing this because it changes the runtime of hash table operations from +/// `O(1)` to `O(k)` where `k` is the number of duplicate entries. +/// +/// [`HashMap`]: super::HashMap +/// [`HashSet`]: super::HashSet +pub struct HashTable +where + A: Allocator, +{ + pub(crate) raw: RawTable, +} + +impl HashTable { + /// Creates an empty `HashTable`. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::new(); + /// assert_eq!(table.len(), 0); + /// assert_eq!(table.capacity(), 0); + /// ``` + pub const fn new() -> Self { + Self { + raw: RawTable::new(), + } + } + + /// Creates an empty `HashTable` with the specified capacity. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::with_capacity(10); + /// assert_eq!(table.len(), 0); + /// assert!(table.capacity() >= 10); + /// ``` + pub fn with_capacity(capacity: usize) -> Self { + Self { + raw: RawTable::with_capacity(capacity), + } + } +} + +impl HashTable +where + A: Allocator, +{ + /// Creates an empty `HashTable` using the given allocator. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use bumpalo::Bump; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::new_in(&bump); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// + /// // The created HashTable also doesn't allocate memory + /// assert_eq!(table.capacity(), 0); + /// + /// // Now we insert element inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// // We can see that the HashTable holds 1 element + /// assert_eq!(table.len(), 1); + /// // And it also allocates some capacity + /// assert!(table.capacity() > 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub const fn new_in(alloc: A) -> Self { + Self { + raw: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashTable` with the specified capacity using the given allocator. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use bumpalo::Bump; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::with_capacity_in(5, &bump); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = table.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// table.insert_unique(hasher(&"Two"), "Two", hasher); + /// table.insert_unique(hasher(&"Three"), "Three", hasher); + /// table.insert_unique(hasher(&"Four"), "Four", hasher); + /// table.insert_unique(hasher(&"Five"), "Five", hasher); + /// + /// // We can see that the HashTable holds 5 elements + /// assert_eq!(table.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(table.capacity(), empty_map_capacity) + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + raw: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the underlying allocator. + pub fn allocator(&self) -> &A { + self.raw.allocator() + } + + /// Returns a reference to an entry in the table with the given hash and + /// which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// assert_eq!(table.find(hasher(&2), |&val| val == 2), Some(&2)); + /// assert_eq!(table.find(hasher(&4), |&val| val == 4), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + self.raw.get(hash, eq) + } + + /// Returns a mutable reference to an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// When mutating an entry, you should ensure that it still retains the same + /// hash value as when it was inserted, otherwise lookups of that entry may + /// fail to find it. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Some(val) = table.find_mut(hasher(&1), |val| val.0 == 1) { + /// val.1 = "b"; + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), Some(&(1, "b"))); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + self.raw.get_mut(hash, eq) + } + + /// Returns an `OccupiedEntry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table. Call + /// [`HashTable::entry`] instead if you wish to insert an entry if the + /// lookup fails. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Ok(entry) = table.find_entry(hasher(&1), |val| val.0 == 1) { + /// entry.remove(); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn find_entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + ) -> Result, AbsentEntry<'_, T, A>> { + match self.raw.find(hash, eq) { + Some(bucket) => Ok(OccupiedEntry { + hash, + bucket, + table: self, + }), + None => Err(AbsentEntry { table: self }), + } + } + + /// Returns an `Entry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table, or insert a new + /// entry with the given hash if one doesn't already exist. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// This method may grow the table in preparation for an insertion. Call + /// [`HashTable::find_entry`] if this is undesirable. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Entry::Occupied(entry) = table.entry(hasher(&1), |val| val.0 == 1, |val| hasher(&val.0)) + /// { + /// entry.remove(); + /// } + /// if let Entry::Vacant(entry) = table.entry(hasher(&2), |val| val.0 == 2, |val| hasher(&val.0)) { + /// entry.insert((2, "b")); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), Some(&(2, "b"))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Entry<'_, T, A> { + match self.raw.find_or_find_insert_slot(hash, eq, hasher) { + Ok(bucket) => Entry::Occupied(OccupiedEntry { + hash, + bucket, + table: self, + }), + Err(insert_slot) => Entry::Vacant(VacantEntry { + hash, + insert_slot, + table: self, + }), + } + } + + /// Inserts an element into the `HashTable` with the given hash value, but + /// without checking whether an equivalent element already exists within the + /// table. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut v = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert_unique( + &mut self, + hash: u64, + value: T, + hasher: impl Fn(&T) -> u64, + ) -> OccupiedEntry<'_, T, A> { + let bucket = self.raw.insert(hash, value, hasher); + OccupiedEntry { + hash, + bucket, + table: self, + } + } + + /// Clears the table, removing all values. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut v = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// v.clear(); + /// assert!(v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn clear(&mut self) { + self.raw.clear(); + } + + /// Shrinks the capacity of the table as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to_fit(hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to_fit(&mut self, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(self.len(), hasher) + } + + /// Shrinks the capacity of the table with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to(10, hasher); + /// assert!(table.capacity() >= 10); + /// table.shrink_to(0, hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to(&mut self, min_capacity: usize, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(min_capacity, hasher); + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashTable::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.reserve(10, hasher); + /// assert!(table.capacity() >= 10); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + self.raw.reserve(additional, hasher) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table + /// .try_reserve(10, hasher) + /// .expect("why is the test harness OOMing on 10 bytes?"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + self.raw.try_reserve(additional, hasher) + } + + /// Returns the number of elements the table can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let table: HashTable = HashTable::with_capacity(100); + /// assert!(table.capacity() >= 100); + /// ``` + pub fn capacity(&self) -> usize { + self.raw.capacity() + } + + /// Returns the number of elements in the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert_eq!(v.len(), 0); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert_eq!(v.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn len(&self) -> usize { + self.raw.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert!(v.is_empty()); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert!(!v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn is_empty(&self) -> bool { + self.raw.is_empty() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "b", hasher); + /// table.insert_unique(hasher(&"b"), "b", hasher); + /// + /// // Will print in an arbitrary order. + /// for x in table.iter() { + /// println!("{}", x); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements in arbitrary order, + /// with mutable references to the elements. + /// The iterator element type is `&'a mut T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// + /// // Update all values + /// for val in table.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(table.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in &table { + /// println!("val: {}", val); + /// vec.push(*val); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [2, 4, 6]); + /// + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=6 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// table.retain(|&mut x| x % 2 == 0); + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.raw.iter() { + if !f(item.as_mut()) { + self.raw.erase(item); + } + } + } + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=3 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// assert!(!table.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in table.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(table.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + inner: self.raw.drain(), + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashTable::retain + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 0..8 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// let drained: Vec = table.extract_if(|&mut v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = table.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.raw.iter() }, + table: &mut self.raw, + }, + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the + /// keys are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + self.raw.get_many_mut(hashes, eq) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](`HashTable::get_many_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + self.raw.get_many_unchecked_mut(hashes, eq) + } +} + +impl IntoIterator for HashTable +where + A: Allocator, +{ + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.raw.into_iter(), + } + } +} + +impl<'a, T, A> IntoIterator for &'a HashTable +where + A: Allocator, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T, A> IntoIterator for &'a mut HashTable +where + A: Allocator, +{ + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl Default for HashTable +where + A: Allocator + Default, +{ + fn default() -> Self { + Self { + raw: Default::default(), + } + } +} + +impl Clone for HashTable +where + T: Clone, + A: Allocator + Clone, +{ + fn clone(&self) -> Self { + Self { + raw: self.raw.clone(), + } + } +} + +impl fmt::Debug for HashTable +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +/// A view into a single entry in a table, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashTable`]. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`entry`]: struct.HashTable.html#method.entry +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_> = table.entry(hasher(&"a"), |&x| x == "a", hasher); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert("a"); +/// assert_eq!(table.len(), 3); +/// // Nonexistent value (insert) +/// table.entry(hasher(&"d"), |&x| x == "d", hasher).insert("d"); +/// +/// // Existing value (or_insert) +/// table +/// .entry(hasher(&"b"), |&x| x == "b", hasher) +/// .or_insert("b"); +/// // Nonexistent value (or_insert) +/// table +/// .entry(hasher(&"e"), |&x| x == "e", hasher) +/// .or_insert("e"); +/// +/// println!("Our HashTable: {:?}", table); +/// +/// let mut vec: Vec<_> = table.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub enum Entry<'a, T, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in ["a", "b"] { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => {} + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Occupied(OccupiedEntry<'a, T, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::<&str>::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => {} + /// Entry::Occupied(_) => unreachable!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Vacant(VacantEntry<'a, T, A>), +} + +impl fmt::Debug for Entry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +impl<'a, T, A> Entry<'a, T, A> +where + A: Allocator, +{ + /// Sets the value of the entry, replacing any existing value if there is + /// one, and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// let entry = table + /// .entry(hasher(&"horseyland"), |&x| x == "horseyland", hasher) + /// .insert("horseyland"); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(mut entry) => { + *entry.get_mut() = value; + entry + } + Entry::Vacant(entry) => entry.insert(value), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // nonexistent key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// + /// // existing key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// assert_eq!(table.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert(self, default: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty.. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry(hasher("poneyland"), |x| x == "poneyland", |val| hasher(val)) + /// .or_insert_with(|| "poneyland".to_string()); + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |x| x == "poneyland") + /// .is_some()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert_with(self, default: impl FnOnce() -> T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 42)) + /// ); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 43)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} + +/// A view into an occupied entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// let _entry_o: OccupiedEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap(); +/// assert_eq!(table.len(), 3); +/// +/// // Existing key +/// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(table.len(), 3); +/// +/// // Existing key (take) +/// match table.entry(hasher(&"c"), |&x| x == "c", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove().0, "c"); +/// } +/// } +/// assert_eq!(table.find(hasher(&"c"), |&x| x == "c"), None); +/// assert_eq!(table.len(), 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct OccupiedEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + bucket: Bucket, + table: &'a mut HashTable, +} + +unsafe impl Send for OccupiedEntry<'_, T, A> +where + T: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, T, A> +where + T: Sync, + A: Sync + Allocator, +{ +} + +impl fmt::Debug for OccupiedEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +impl<'a, T, A> OccupiedEntry<'a, T, A> +where + A: Allocator, +{ + /// Takes the value out of the entry, and returns it along with a + /// `VacantEntry` that can be used to insert another value with the same + /// hash as the one that was just removed. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// // The table is empty + /// assert!(table.is_empty() && table.capacity() == 0); + /// + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// let capacity_before_remove = table.capacity(); + /// + /// if let Entry::Occupied(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// assert_eq!(o.remove().0, "poneyland"); + /// } + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_none()); + /// // Now table hold none elements but capacity is equal to the old one + /// assert!(table.len() == 0 && table.capacity() == capacity_before_remove); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> (T, VacantEntry<'a, T, A>) { + let (val, slot) = unsafe { self.table.raw.remove(self.bucket) }; + ( + val, + VacantEntry { + hash: self.hash, + insert_slot: slot, + table: self.table, + }, + ) + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// + /// match table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get(&self) -> &T { + unsafe { self.bucket.as_ref() } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// if let Entry::Occupied(mut o) = table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// o.get_mut().1 += 10; + /// assert_eq!(o.get().1, 22); + /// + /// // We can use the same Entry multiple times. + /// o.get_mut().1 += 2; + /// } + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 24)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the table itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// let value: &mut (&str, u32); + /// match table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// value.1 += 10; + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 22)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn into_mut(self) -> &'a mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the OccupiedEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// A view into a vacant entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, VacantEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: VacantEntry<_, _> = match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert("a"); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct VacantEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + insert_slot: InsertSlot, + table: &'a mut HashTable, +} + +impl fmt::Debug for VacantEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("VacantEntry") + } +} + +impl<'a, T, A> VacantEntry<'a, T, A> +where + A: Allocator, +{ + /// Inserts a new element into the table with the hash that was used to + /// obtain the `VacantEntry`. + /// + /// An `OccupiedEntry` is returned for the newly inserted element. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// if let Entry::Vacant(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// o.insert("poneyland"); + /// } + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&x| x == "poneyland"), + /// Some(&"poneyland") + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + let bucket = unsafe { + self.table + .raw + .insert_in_slot(self.hash, self.insert_slot, value) + }; + OccupiedEntry { + hash: self.hash, + bucket, + table: self.table, + } + } + + /// Converts the VacantEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// Type representing the absence of an entry, as returned by [`HashTable::find_entry`]. +/// +/// This type only exists due to [limitations] in Rust's NLL borrow checker. In +/// the future, `find_entry` will return an `Option` and this +/// type will be removed. +/// +/// [limitations]: https://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/#polonius +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{AbsentEntry, Entry, HashTable}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: AbsentEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap_err(); +/// entry_v +/// .into_table() +/// .insert_unique(hasher(&"a"), "a", hasher); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct AbsentEntry<'a, T, A = Global> +where + A: Allocator, +{ + table: &'a mut HashTable, +} + +impl fmt::Debug for AbsentEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("AbsentEntry") + } +} + +impl<'a, T, A> AbsentEntry<'a, T, A> +where + A: Allocator, +{ + /// Converts the AbsentEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// An iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a T`. +/// +/// This `struct` is created by the [`iter`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashTable.html#method.iter +/// [`HashTable`]: struct.HashTable.html +pub struct Iter<'a, T> { + inner: RawIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) }) + } +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +/// A mutable iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a mut T`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashTable.html#method.iter_mut +/// [`HashTable`]: struct.HashTable.html +pub struct IterMut<'a, T> { + inner: RawIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) }) + } +} + +impl ExactSizeIterator for IterMut<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IterMut<'_, T> {} + +/// An owning iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `T`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashTable`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The table cannot be used after calling that method. +/// +/// [`into_iter`]: struct.HashTable.html#method.into_iter +/// [`HashTable`]: struct.HashTable.html +/// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html +pub struct IntoIter +where + A: Allocator, +{ + inner: RawIntoIter, +} + +impl Iterator for IntoIter +where + A: Allocator, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} + +impl ExactSizeIterator for IntoIter +where + A: Allocator, +{ + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoIter where A: Allocator {} + +/// A draining iterator over the items of a `HashTable`. +/// +/// This `struct` is created by the [`drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`drain`]: struct.HashTable.html#method.drain +pub struct Drain<'a, T, A: Allocator = Global> { + inner: RawDrain<'a, T, A>, +} + +impl Drain<'_, T, A> { + /// Returns a iterator of references over the remaining items. + fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +impl Iterator for Drain<'_, T, A> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for Drain<'_, T, A> { + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, T, A> {} + +impl fmt::Debug for Drain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by [`HashTable::extract_if`]. See its +/// documentation for more. +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, T, F, A: Allocator = Global> +where + F: FnMut(&mut T) -> bool, +{ + f: F, + inner: RawExtractIf<'a, T, A>, +} + +impl Iterator for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next(|val| (self.f)(val)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool {} diff --git a/third_party/rust/hashbrown/tests/equivalent_trait.rs b/third_party/rust/hashbrown/tests/equivalent_trait.rs new file mode 100644 index 0000000000..713dddd53c --- /dev/null +++ b/third_party/rust/hashbrown/tests/equivalent_trait.rs @@ -0,0 +1,53 @@ +use hashbrown::Equivalent; +use hashbrown::HashMap; + +use std::hash::Hash; + +#[derive(Debug, Hash)] +pub struct Pair(pub A, pub B); + +impl PartialEq<(A, B)> for Pair +where + C: PartialEq, + D: PartialEq, +{ + fn eq(&self, rhs: &(A, B)) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } +} + +impl Equivalent for Pair +where + Pair: PartialEq, + A: Hash + Eq, + B: Hash + Eq, +{ + fn equivalent(&self, other: &X) -> bool { + *self == *other + } +} + +#[test] +fn test_lookup() { + let s = String::from; + let mut map = HashMap::new(); + map.insert((s("a"), s("b")), 1); + map.insert((s("a"), s("x")), 2); + + assert!(map.contains_key(&Pair("a", "b"))); + assert!(!map.contains_key(&Pair("b", "a"))); +} + +#[test] +fn test_string_str() { + let s = String::from; + let mut map = HashMap::new(); + map.insert(s("a"), 1); + map.insert(s("b"), 2); + map.insert(s("x"), 3); + map.insert(s("y"), 4); + + assert!(map.contains_key("a")); + assert!(!map.contains_key("z")); + assert_eq!(map.remove("b"), Some(2)); +} diff --git a/third_party/rust/hashbrown/tests/raw.rs b/third_party/rust/hashbrown/tests/raw.rs new file mode 100644 index 0000000000..858836e63b --- /dev/null +++ b/third_party/rust/hashbrown/tests/raw.rs @@ -0,0 +1,11 @@ +#![cfg(feature = "raw")] + +use hashbrown::raw::RawTable; +use std::mem; + +#[test] +fn test_allocation_info() { + assert_eq!(RawTable::<()>::new().allocation_info().1.size(), 0); + assert_eq!(RawTable::::new().allocation_info().1.size(), 0); + assert!(RawTable::::with_capacity(1).allocation_info().1.size() > mem::size_of::()); +} diff --git a/third_party/rust/hashbrown/tests/rayon.rs b/third_party/rust/hashbrown/tests/rayon.rs index 8c603c5c41..d55e5a9804 100644 --- a/third_party/rust/hashbrown/tests/rayon.rs +++ b/third_party/rust/hashbrown/tests/rayon.rs @@ -356,7 +356,9 @@ fn set_seq_par_equivalence_into_iter_empty() { let vec_seq = SET_EMPTY.clone().into_iter().collect::>(); let vec_par = SET_EMPTY.clone().into_par_iter().collect::>(); - assert_eq3!(vec_seq, vec_par, []); + // Work around type inference failure introduced by rend dev-dependency. + let empty: [char; 0] = []; + assert_eq3!(vec_seq, vec_par, empty); } #[test] diff --git a/third_party/rust/hashbrown/tests/set.rs b/third_party/rust/hashbrown/tests/set.rs index 5ae1ec98ec..86ec964766 100644 --- a/third_party/rust/hashbrown/tests/set.rs +++ b/third_party/rust/hashbrown/tests/set.rs @@ -27,7 +27,7 @@ fn test_hashset_insert_remove() { assert_eq!(m.insert(x.clone()), true); } for (i, x) in tx.iter().enumerate() { - println!("removing {} {:?}", i, x); + println!("removing {i} {x:?}"); assert_eq!(m.remove(x), true); } } diff --git a/third_party/rust/hashlink/.cargo-checksum.json b/third_party/rust/hashlink/.cargo-checksum.json index 2eca6e96e0..fdc962b32f 100644 --- a/third_party/rust/hashlink/.cargo-checksum.json +++ b/third_party/rust/hashlink/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"198cbb28cb803006c074811eece27e07e2cce6b463750fffcc47c6255d10e82c","Cargo.toml":"ff6fc403d9a7b64a597026915c1bc52c70d990d9929dd414667e78798dfaf1f7","LICENSE-APACHE":"c144680885b29e4719e2a51f0aab5439a1e02d980692b5aaf086cae12727f28b","LICENSE-MIT":"e915669a595b11a200873df8286561881b0e04932f6412a585db6297ba0bc97c","README.md":"acc16f95f79df4789a0f116c8748242aac2c17e38ab91d6d5e59c89271ca51e9","src/lib.rs":"12f7bf2e1bdc312fd9740b639983916a2e7a8582c588902af8c4ac71b9032fde","src/linked_hash_map.rs":"cd88b14beac407986d23ea3ab944dd666f62a7a75c99151296b2b1eef54d3569","src/linked_hash_set.rs":"36892b3a9a3388fe2a5454051a691dd38d512771f08a1638ba8322afc65dfe61","src/lru_cache.rs":"d2322af90780a3ef192f25d213f5af38e1dc6492a323fb361757d53692058774","src/serde.rs":"451a34dec0e29d205f997710bf9e733836832f6402e36640f3b6de272a1fd9d4","tests/linked_hash_map.rs":"c2d259c9d0325f4b73268dc686b8cca8fc3c778c757012825a82474026f28634","tests/linked_hash_set.rs":"bfaa3018a99c5c36cf0059bf7836142c2cc69be7f03a8c20bd52131f877e2eec","tests/lru_cache.rs":"c0328001d53e2a0d1ef6fb36550e8cbb989ef1914cef3657f1832b280f4d4572","tests/serde.rs":"d359b4125009705dcba9219ee5f027bbe8bb18008c111e3541c41e141f9b02f2"},"package":"69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa"} \ No newline at end of file +{"files":{"CHANGELOG.md":"3479e430ed4bfcd38ac0d9bff95873d8e018e462e0c2dd370a58c282a47caa59","Cargo.toml":"ab72ee61c8eebd28e3904c50b819f13f5be04441b8bfc1fba06607877f94a344","LICENSE-APACHE":"c144680885b29e4719e2a51f0aab5439a1e02d980692b5aaf086cae12727f28b","LICENSE-MIT":"e915669a595b11a200873df8286561881b0e04932f6412a585db6297ba0bc97c","README.md":"acc16f95f79df4789a0f116c8748242aac2c17e38ab91d6d5e59c89271ca51e9","src/lib.rs":"12f7bf2e1bdc312fd9740b639983916a2e7a8582c588902af8c4ac71b9032fde","src/linked_hash_map.rs":"cd88b14beac407986d23ea3ab944dd666f62a7a75c99151296b2b1eef54d3569","src/linked_hash_set.rs":"36892b3a9a3388fe2a5454051a691dd38d512771f08a1638ba8322afc65dfe61","src/lru_cache.rs":"d2322af90780a3ef192f25d213f5af38e1dc6492a323fb361757d53692058774","src/serde.rs":"451a34dec0e29d205f997710bf9e733836832f6402e36640f3b6de272a1fd9d4","tests/linked_hash_map.rs":"c2d259c9d0325f4b73268dc686b8cca8fc3c778c757012825a82474026f28634","tests/linked_hash_set.rs":"bfaa3018a99c5c36cf0059bf7836142c2cc69be7f03a8c20bd52131f877e2eec","tests/lru_cache.rs":"c0328001d53e2a0d1ef6fb36550e8cbb989ef1914cef3657f1832b280f4d4572","tests/serde.rs":"4e0b1c19c3c542f0b9adac72f6ff32907da6bb58b4f1810dcdf9cd4e2eef34b1"},"package":"0761a1b9491c4f2e3d66aa0f62d0fba0af9a0e2852e4d48ea506632a4b56e6aa"} \ No newline at end of file diff --git a/third_party/rust/hashlink/CHANGELOG.md b/third_party/rust/hashlink/CHANGELOG.md index 0cec7be6c0..9d4bd44470 100644 --- a/third_party/rust/hashlink/CHANGELOG.md +++ b/third_party/rust/hashlink/CHANGELOG.md @@ -1,3 +1,6 @@ +## [0.8.2] +- bump hashbrown to 0.13 + ## [0.8.1] - Add `retain_with_order` methods, equivalent to `retain` but which iterate through the map in the proper linked list order diff --git a/third_party/rust/hashlink/Cargo.toml b/third_party/rust/hashlink/Cargo.toml index 308f9f77c3..474901d947 100644 --- a/third_party/rust/hashlink/Cargo.toml +++ b/third_party/rust/hashlink/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "hashlink" -version = "0.8.1" +version = "0.8.2" authors = ["kyren "] description = "HashMap-like containers that hold their key-value pairs in a user controllable order" documentation = "https://docs.rs/hashlink" @@ -22,14 +22,14 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/kyren/hashlink" [dependencies.hashbrown] -version = "0.12.0" +version = "0.13" [dependencies.serde] version = "1.0" optional = true -[dev-dependencies.fxhash] -version = "0.2.1" +[dev-dependencies.rustc-hash] +version = "1.1" [dev-dependencies.serde_test] version = "1.0" diff --git a/third_party/rust/hashlink/tests/serde.rs b/third_party/rust/hashlink/tests/serde.rs index d397a245fa..2cf4a3e3fb 100644 --- a/third_party/rust/hashlink/tests/serde.rs +++ b/third_party/rust/hashlink/tests/serde.rs @@ -1,7 +1,9 @@ #![cfg(feature = "serde_impl")] -use fxhash::FxBuildHasher; +use std::hash::BuildHasherDefault; + use hashlink::{LinkedHashMap, LinkedHashSet}; +use rustc_hash::FxHasher; use serde_test::{assert_tokens, Token}; #[test] @@ -35,14 +37,14 @@ fn map_serde_tokens() { #[test] fn map_serde_tokens_empty_generic() { - let map = LinkedHashMap::::with_hasher(FxBuildHasher::default()); + let map = LinkedHashMap::>::default(); assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); } #[test] fn map_serde_tokens_generic() { - let mut map = LinkedHashMap::with_hasher(FxBuildHasher::default()); + let mut map = LinkedHashMap::>::default(); map.insert('a', 10); map.insert('b', 20); map.insert('c', 30); @@ -90,7 +92,7 @@ fn set_serde_tokens() { #[test] fn set_serde_tokens_generic() { - let mut set = LinkedHashSet::with_hasher(FxBuildHasher::default()); + let mut set = LinkedHashSet::>::default(); set.insert('a'); set.insert('b'); set.insert('c'); diff --git a/third_party/rust/indexmap/.cargo-checksum.json b/third_party/rust/indexmap/.cargo-checksum.json index 0f44683d7f..50a4338741 100644 --- a/third_party/rust/indexmap/.cargo-checksum.json +++ b/third_party/rust/indexmap/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"1290d383adfdcd24f158a4619afb5547d633c83c0a1ab3b5c1ee0dabe4fb1f36","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.md":"f8b02aa7c20fc0f5bc13de9e9e78899ec8cdbc16c2db880a1d0bc14c25b07542","RELEASES.md":"85d9d9bc78e94df7ce90300bb94099b9ab2696d1b3f6b815c22761522878e679","benches/bench.rs":"3b2900abbc9e8a60af78b0395222ee75e86bc68519a0f38477387d1572eed397","benches/faststring.rs":"5fdd6cdb19d0557ed58f241e809a240cf8939d9e5b87a72d5f127f81ab98380b","build.rs":"558b4d0b9e9b3a44f7e1a2b69f7a7567ea721cd45cb54f4e458e850bf702f35c","src/arbitrary.rs":"bb8bda10f686abe57eef1446d3fc3fc6fb251f95629b28c20e620a4838c43db8","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"ea2cbe4f6cc2c4a75f42c9fc936503e6bee0f136c60f6811a2a9907ed8886443","src/macros.rs":"80c22f630e7f81e6fa663ca4c9e50cf5f332c8905d72d1338bd16f24eb353c2a","src/map.rs":"2e9cbfa240865cfd6b6b972bdbdb39283e6302dd2d0d72b3c2bfce4414bf5729","src/map/core.rs":"8422cd774c5db7d83cdeb0c5836c10f29caa1bee8d95b0d674b01b32e7ce80d8","src/map/core/raw.rs":"4e5fac4fecccc352268351d8b1f82b345067b5c029bba7e6ab88e8f8bc799c6a","src/mutable_keys.rs":"a919065b59000286eb11c7d46f6896bf0a1d484c9dac5e61d80bb8990c9fbedb","src/rayon/map.rs":"1a508c7c95c5d56113b851f7ce140d62ad541f1c6129352a7ec62d5bea7af4a1","src/rayon/mod.rs":"019e9379ccab57a299ab5b5a2c0efc7561b77a715a5afe8f797c7e8330c6206c","src/rayon/set.rs":"ba00e88e90fb7ab803589f99f24b595d60309e541aae3d01fdde21bff3840194","src/rustc.rs":"fe7a348c5a10a66880cb6c737593fe79d3b6de40f44ba0d7b89204aa95e14a3a","src/serde.rs":"d45ec8fb9c02594ca6f2e9b20764778b2b4193a24a52f1e233160a33efc6e683","src/serde_seq.rs":"c54a52fa607b6ccddda1e76e829778ca304c49b5f434edc5e582a5386c35d662","src/set.rs":"0a57affb623fa6b28df18cc14841e4f076cbd1da5c809635d202f865640af1ee","src/util.rs":"ab712bce71b54cf2763e6010e64bb5944d1d59ce15e2f2beffa7ceed204d6a68","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"1addbc6cbcb1aae5b8bde0fb0e18197d947e8f13244e4ae7ebf97bdda00eafea","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"} \ No newline at end of file +{"files":{"Cargo.toml":"34db4bcb2f85a5e3980eb06d3ec4aac3fa0ef6ff48b57ef28aba6dfc1fbeedbb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.md":"98781168dcaf64ed3eecbf7146311045433773486259a372b985c9ae28545017","RELEASES.md":"0f8b4d3a352bddda55384f2ffa804b39e7d73aefa27364c56378d0043756e491","benches/bench.rs":"3b2900abbc9e8a60af78b0395222ee75e86bc68519a0f38477387d1572eed397","benches/faststring.rs":"5fdd6cdb19d0557ed58f241e809a240cf8939d9e5b87a72d5f127f81ab98380b","src/arbitrary.rs":"068713b1e8e762dbe9e4d19d555e77c17e59408335a40f4777d6100340605655","src/borsh.rs":"74121b426379d4f7365757ffd4f3dd469543fa1635193460fe268799a78a0706","src/lib.rs":"57ca834c31a7bb70821f476de916486ab58b9ad3922761153972b5f3923fe078","src/macros.rs":"1493afee2db2c9744be99e5fc32d0cd3742b8a3dbb31fa786ebbe28f1387e7d6","src/map.rs":"d1422353531e6114778033e901b30c8138da048075582fb396d299211958044c","src/map/core.rs":"eb291748598e1aa9112ee068a9a5fea7b1190114c4007de179528408f7439faa","src/map/core/entry.rs":"7d987cc5099099e0c9020afa7b3c23d20f11812dce9d684db03ff390f4068691","src/map/core/raw.rs":"30cc048f7c7f0deb2eb1c699a15e6b18dff1187404228c55e404c0d5bfe11f3e","src/map/core/raw_entry_v1.rs":"0942938c167aca6c892bd78e431d2b7366443e1d6f4f0d930b0bf72ca3ab8054","src/map/iter.rs":"ae0023c1ccc78ac765dc43fe51f233f2fca1ebba132490db8429941183d2c497","src/map/mutable.rs":"9d8dded5a95a21fba2d97ef64610627fae97dffc096e872b0c378ae8b63de53b","src/map/serde_seq.rs":"ce06b5bb816c15ea8fe3d2c358baa90fe6f45ecb585623a69592d6de69319194","src/map/slice.rs":"c0d770a6ce47fa4f3d9c82b468504c567dc4031d8f3694603e2b5bcc295cf3e1","src/map/tests.rs":"714674a55103dc57c16d9fe2916d462a655dc217e079a7e0ed5a62ab0f9749f1","src/rayon/map.rs":"0fad36851fdf6894695e526c684c9b3afeac82e29016e6a523eea68cc3b2d19d","src/rayon/mod.rs":"1c9c13b5cf6974f652ded53b014774944c761f079a77a61b3bc52eaa3d4b972b","src/rayon/set.rs":"4b076dbfd9a7eb2fd65783f1c8a5acabe075403f3d05e30c337676acec25d8ee","src/rustc.rs":"fe7a348c5a10a66880cb6c737593fe79d3b6de40f44ba0d7b89204aa95e14a3a","src/serde.rs":"23fd6b5e8f6795e4121693ac16dab61e76c4d8c83e6da1b3ef26d081fae28e79","src/set.rs":"fe9ca3fea8c1156a13ffccdf49d8acb9c79433586c1dfc71ef21ecfcebfd8b14","src/set/iter.rs":"a387c48eff0338b5c8f4e2059403bd665a9c8037634cc5860f80b72a4fbbed30","src/set/mutable.rs":"83ac1719a5eb5bdefac0e9eaa87b80ed98e39c5f2bb4cb69143e3fbff4302e6d","src/set/slice.rs":"9b5aa57e3510d5e17a91a6eaa2ee66a3d79d40b171beb86f7dd9208277135900","src/set/tests.rs":"d9c182cd776ca9182b5284f06eacc70c5f33a66aff3021c35134ffd1d7630c05","src/util.rs":"dbd57cfdac2a72db8c5ce83bf288bcaf33b5ae59adddcd088792a624c4c0e909","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"9759dcc34d86d9635d9d18be6358f5f3e3c0f995874b64b5a7ca4b582f4acedb","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"} \ No newline at end of file diff --git a/third_party/rust/indexmap/Cargo.toml b/third_party/rust/indexmap/Cargo.toml index 28f3618f01..51d6e6e97c 100644 --- a/third_party/rust/indexmap/Cargo.toml +++ b/third_party/rust/indexmap/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.56" +rust-version = "1.63" name = "indexmap" -version = "1.9.3" +version = "2.2.6" description = "A hash table with consistent order and fast iteration." documentation = "https://docs.rs/indexmap/" readme = "README.md" @@ -26,22 +26,27 @@ categories = [ "no-std", ] license = "Apache-2.0 OR MIT" -repository = "https://github.com/bluss/indexmap" - -[package.metadata.release] -no-dev-version = true -tag-name = "{{version}}" +repository = "https://github.com/indexmap-rs/indexmap" [package.metadata.docs.rs] features = [ "arbitrary", "quickcheck", - "serde-1", + "serde", + "borsh", "rayon", ] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" [profile.bench] -debug = true +debug = 2 [lib] bench = false @@ -51,8 +56,17 @@ version = "1.0" optional = true default-features = false +[dependencies.borsh] +version = "1.2" +optional = true +default-features = false + +[dependencies.equivalent] +version = "1.0" +default-features = false + [dependencies.hashbrown] -version = "0.12" +version = "0.14.1" features = ["raw"] default-features = false @@ -62,7 +76,7 @@ optional = true default-features = false [dependencies.rayon] -version = "1.4.1" +version = "1.5.3" optional = true [dependencies.rustc-rayon] @@ -82,7 +96,7 @@ version = "1.0" version = "0.2.1" [dev-dependencies.itertools] -version = "0.10" +version = "0.12" [dev-dependencies.lazy_static] version = "1.3" @@ -98,11 +112,10 @@ features = ["small_rng"] [dev-dependencies.serde_derive] version = "1.0" -[build-dependencies.autocfg] -version = "1" - [features] -serde-1 = ["serde"] +default = ["std"] std = [] test_debug = [] -test_low_transition_point = [] + +[lints.clippy] +style = "allow" diff --git a/third_party/rust/indexmap/README.md b/third_party/rust/indexmap/README.md index d80b7099ce..9112d52893 100644 --- a/third_party/rust/indexmap/README.md +++ b/third_party/rust/indexmap/README.md @@ -1,9 +1,9 @@ # indexmap -[![build status](https://github.com/bluss/indexmap/workflows/Continuous%20integration/badge.svg?branch=master)](https://github.com/bluss/indexmap/actions) +[![build status](https://github.com/indexmap-rs/indexmap/workflows/Continuous%20integration/badge.svg?branch=master)](https://github.com/indexmap-rs/indexmap/actions) [![crates.io](https://img.shields.io/crates/v/indexmap.svg)](https://crates.io/crates/indexmap) [![docs](https://docs.rs/indexmap/badge.svg)](https://docs.rs/indexmap) -[![rustc](https://img.shields.io/badge/rust-1.56%2B-orange.svg)](https://img.shields.io/badge/rust-1.56%2B-orange.svg) +[![rustc](https://img.shields.io/badge/rust-1.63%2B-orange.svg)](https://img.shields.io/badge/rust-1.63%2B-orange.svg) A pure-Rust hash table which preserves (in a limited sense) insertion order. @@ -26,7 +26,9 @@ was indexmap, a hash table that has following properties: - Order is **independent of hash function** and hash values of keys. - Fast to iterate. - Indexed in compact space. -- Preserves insertion order **as long** as you don't call `.remove()`. +- Preserves insertion order **as long** as you don't call `.remove()`, + `.swap_remove()`, or other methods that explicitly change order. + The alternate `.shift_remove()` does preserve relative order. - Uses hashbrown for the inner table, just like Rust's libstd `HashMap` does. ## Performance @@ -52,4 +54,4 @@ which is roughly: # Recent Changes -See [RELEASES.md](https://github.com/bluss/indexmap/blob/master/RELEASES.md). +See [RELEASES.md](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md). diff --git a/third_party/rust/indexmap/RELEASES.md b/third_party/rust/indexmap/RELEASES.md index 7ea8b702e0..8c033db042 100644 --- a/third_party/rust/indexmap/RELEASES.md +++ b/third_party/rust/indexmap/RELEASES.md @@ -1,388 +1,508 @@ -- 1.9.3 +# Releases - - Bump the `rustc-rayon` dependency, for compiler use only. +## 2.2.6 -- 1.9.2 +- Added trait `MutableValues` for opt-in mutable access to set values. - - `IndexMap` and `IndexSet` both implement `arbitrary::Arbitrary<'_>` and - `quickcheck::Arbitrary` if those optional dependency features are enabled. +## 2.2.5 -- 1.9.1 +- Added optional `borsh` serialization support. - - The MSRV now allows Rust 1.56.0 as well. However, currently `hashbrown` - 0.12.1 requires 1.56.1, so users on 1.56.0 should downgrade that to 0.12.0 - until there is a later published version relaxing its requirement. +## 2.2.4 -- 1.9.0 +- Added an `insert_sorted` method on `IndexMap`, `IndexSet`, and `VacantEntry`. +- Avoid hashing for lookups in single-entry maps. +- Limit preallocated memory in `serde` deserializers. - - **MSRV**: Rust 1.56.1 or later is now required. +## 2.2.3 - - The `hashbrown` dependency has been updated to version 0.12. +- Added `move_index` and `swap_indices` methods to `IndexedEntry`, + `OccupiedEntry`, and `RawOccupiedEntryMut`, functioning like the existing + methods on `IndexMap`. +- Added `shift_insert` methods on `VacantEntry` and `RawVacantEntryMut`, as + well as `shift_insert_hashed_nocheck` on the latter, to insert the new entry + at a particular index. +- Added `shift_insert` methods on `IndexMap` and `IndexSet` to insert a new + entry at a particular index, or else move an existing entry there. - - `IterMut` and `ValuesMut` now implement `Debug`. +## 2.2.2 - - The new `IndexMap::shrink_to` and `IndexSet::shrink_to` methods shrink - the capacity with a lower bound. +- Added indexing methods to raw entries: `RawEntryBuilder::from_hash_full`, + `RawEntryBuilder::index_from_hash`, and `RawEntryMut::index`. - - The new `IndexMap::move_index` and `IndexSet::move_index` methods change - the position of an item from one index to another, shifting the items - between to accommodate the move. +## 2.2.1 -- 1.8.2 +- Corrected the signature of `RawOccupiedEntryMut::into_key(self) -> &'a mut K`, + This a breaking change from 2.2.0, but that version was published for less + than a day and has now been yanked. - - Bump the `rustc-rayon` dependency, for compiler use only. +## 2.2.0 -- 1.8.1 +- The new `IndexMap::get_index_entry` method finds an entry by its index for + in-place manipulation. - - The new `IndexSet::replace_full` will return the index of the item along - with the replaced value, if any, by @zakcutner in PR [222]. +- The `Keys` iterator now implements `Index` for quick access to the + entry's key, compared to indexing the map to get the value. -[222]: https://github.com/bluss/indexmap/pull/222 +- The new `IndexMap::splice` and `IndexSet::splice` methods will drain the + given range as an iterator, and then replace that range with entries from + an input iterator. -- 1.8.0 +- The new trait `RawEntryApiV1` offers opt-in access to a raw entry API for + `IndexMap`, corresponding to the unstable API on `HashSet` as of Rust 1.75. - - The new `IndexMap::into_keys` and `IndexMap::into_values` will consume - the map into keys or values, respectively, matching Rust 1.54's `HashMap` - methods, by @taiki-e in PR [195]. +- Many `IndexMap` and `IndexSet` methods have relaxed their type constraints, + e.g. removing `K: Hash` on methods that don't actually need to hash. - - More of the iterator types implement `Debug`, `ExactSizeIterator`, and - `FusedIterator`, by @cuviper in PR [196]. +- Removal methods `remove`, `remove_entry`, and `take` are now deprecated + in favor of their `shift_` or `swap_` prefixed variants, which are more + explicit about their effect on the index and order of remaining items. + The deprecated methods will remain to guide drop-in replacements from + `HashMap` and `HashSet` toward the prefixed methods. - - `IndexMap` and `IndexSet` now implement rayon's `ParallelDrainRange`, - by @cuviper in PR [197]. +## 2.1.0 - - `IndexMap::with_hasher` and `IndexSet::with_hasher` are now `const` - functions, allowing static maps and sets, by @mwillsey in PR [203]. +- Empty slices can now be created with `map::Slice::{new, new_mut}` and + `set::Slice::new`. In addition, `Slice::new`, `len`, and `is_empty` are + now `const` functions on both types. - - `IndexMap` and `IndexSet` now implement `From` for arrays, matching - Rust 1.56's implementation for `HashMap`, by @rouge8 in PR [205]. +- `IndexMap`, `IndexSet`, and their respective `Slice`s all have binary + search methods for sorted data: map `binary_search_keys` and set + `binary_search` for plain comparison, `binary_search_by` for custom + comparators, `binary_search_by_key` for key extraction, and + `partition_point` for boolean conditions. - - `IndexMap` and `IndexSet` now have methods `sort_unstable_keys`, - `sort_unstable_by`, `sorted_unstable_by`, and `par_*` equivalents, - which sort in-place without preserving the order of equal items, by - @bhgomes in PR [211]. +## 2.0.2 -[195]: https://github.com/bluss/indexmap/pull/195 -[196]: https://github.com/bluss/indexmap/pull/196 -[197]: https://github.com/bluss/indexmap/pull/197 -[203]: https://github.com/bluss/indexmap/pull/203 -[205]: https://github.com/bluss/indexmap/pull/205 -[211]: https://github.com/bluss/indexmap/pull/211 +- The `hashbrown` dependency has been updated to version 0.14.1 to + complete the support for Rust 1.63. -- 1.7.0 +## 2.0.1 - - **MSRV**: Rust 1.49 or later is now required. +- **MSRV**: Rust 1.63.0 is now supported as well, pending publication of + `hashbrown`'s relaxed MSRV (or use cargo `--ignore-rust-version`). - - The `hashbrown` dependency has been updated to version 0.11. +## 2.0.0 -- 1.6.2 +- **MSRV**: Rust 1.64.0 or later is now required. - - Fixed to match `std` behavior, `OccupiedEntry::key` now references the - existing key in the map instead of the lookup key, by @cuviper in PR [170]. +- The `"std"` feature is no longer auto-detected. It is included in the + default feature set, or else can be enabled like any other Cargo feature. - - The new `Entry::or_insert_with_key` matches Rust 1.50's `Entry` method, - passing `&K` to the callback to create a value, by @cuviper in PR [175]. +- The `"serde-1"` feature has been removed, leaving just the optional + `"serde"` dependency to be enabled like a feature itself. -[170]: https://github.com/bluss/indexmap/pull/170 -[175]: https://github.com/bluss/indexmap/pull/175 +- `IndexMap::get_index_mut` now returns `Option<(&K, &mut V)>`, changing + the key part from `&mut K` to `&K`. There is also a new alternative + `MutableKeys::get_index_mut2` to access the former behavior. -- 1.6.1 +- The new `map::Slice` and `set::Slice` offer a linear view of maps + and sets, behaving a lot like normal `[(K, V)]` and `[T]` slices. Notably, + comparison traits like `Eq` only consider items in order, rather than hash + lookups, and slices even implement `Hash`. - - The new `serde_seq` module implements `IndexMap` serialization as a - sequence to ensure order is preserved, by @cuviper in PR [158]. +- `IndexMap` and `IndexSet` now have `sort_by_cached_key` and + `par_sort_by_cached_key` methods which perform stable sorts in place + using a key extraction function. - - New methods on maps and sets work like the `Vec`/slice methods by the same name: - `truncate`, `split_off`, `first`, `first_mut`, `last`, `last_mut`, and - `swap_indices`, by @cuviper in PR [160]. +- `IndexMap` and `IndexSet` now have `reserve_exact`, `try_reserve`, and + `try_reserve_exact` methods that correspond to the same methods on `Vec`. + However, exactness only applies to the direct capacity for items, while the + raw hash table still follows its own rules for capacity and load factor. -[158]: https://github.com/bluss/indexmap/pull/158 -[160]: https://github.com/bluss/indexmap/pull/160 +- The `Equivalent` trait is now re-exported from the `equivalent` crate, + intended as a common base to allow types to work with multiple map types. -- 1.6.0 +- The `hashbrown` dependency has been updated to version 0.14. - - **MSRV**: Rust 1.36 or later is now required. +- The `serde_seq` module has been moved from the crate root to below the + `map` module. - - The `hashbrown` dependency has been updated to version 0.9. +## 1.9.3 -- 1.5.2 +- Bump the `rustc-rayon` dependency, for compiler use only. - - The new "std" feature will force the use of `std` for users that explicitly - want the default `S = RandomState`, bypassing the autodetection added in 1.3.0, - by @cuviper in PR [145]. +## 1.9.2 -[145]: https://github.com/bluss/indexmap/pull/145 +- `IndexMap` and `IndexSet` both implement `arbitrary::Arbitrary<'_>` and + `quickcheck::Arbitrary` if those optional dependency features are enabled. -- 1.5.1 +## 1.9.1 - - Values can now be indexed by their `usize` position by @cuviper in PR [132]. +- The MSRV now allows Rust 1.56.0 as well. However, currently `hashbrown` + 0.12.1 requires 1.56.1, so users on 1.56.0 should downgrade that to 0.12.0 + until there is a later published version relaxing its requirement. - - Some of the generic bounds have been relaxed to match `std` by @cuviper in PR [141]. +## 1.9.0 - - `drain` now accepts any `R: RangeBounds` by @cuviper in PR [142]. +- **MSRV**: Rust 1.56.1 or later is now required. -[132]: https://github.com/bluss/indexmap/pull/132 -[141]: https://github.com/bluss/indexmap/pull/141 -[142]: https://github.com/bluss/indexmap/pull/142 +- The `hashbrown` dependency has been updated to version 0.12. -- 1.5.0 +- `IterMut` and `ValuesMut` now implement `Debug`. - - **MSRV**: Rust 1.32 or later is now required. +- The new `IndexMap::shrink_to` and `IndexSet::shrink_to` methods shrink + the capacity with a lower bound. - - The inner hash table is now based on `hashbrown` by @cuviper in PR [131]. - This also completes the method `reserve` and adds `shrink_to_fit`. +- The new `IndexMap::move_index` and `IndexSet::move_index` methods change + the position of an item from one index to another, shifting the items + between to accommodate the move. - - Add new methods `get_key_value`, `remove_entry`, `swap_remove_entry`, - and `shift_remove_entry`, by @cuviper in PR [136] +## 1.8.2 - - `Clone::clone_from` reuses allocations by @cuviper in PR [125] +- Bump the `rustc-rayon` dependency, for compiler use only. - - Add new method `reverse` by @linclelinkpart5 in PR [128] +## 1.8.1 -[125]: https://github.com/bluss/indexmap/pull/125 -[128]: https://github.com/bluss/indexmap/pull/128 -[131]: https://github.com/bluss/indexmap/pull/131 -[136]: https://github.com/bluss/indexmap/pull/136 +- The new `IndexSet::replace_full` will return the index of the item along + with the replaced value, if any, by @zakcutner in PR [222]. -- 1.4.0 +[222]: https://github.com/indexmap-rs/indexmap/pull/222 - - Add new method `get_index_of` by @Thermatrix in PR [115] and [120] +## 1.8.0 - - Fix build script rebuild-if-changed configuration to use "build.rs"; - fixes issue [123]. Fix by @cuviper. +- The new `IndexMap::into_keys` and `IndexMap::into_values` will consume + the map into keys or values, respectively, matching Rust 1.54's `HashMap` + methods, by @taiki-e in PR [195]. - - Dev-dependencies (rand and quickcheck) have been updated. The crate's tests - now run using Rust 1.32 or later (MSRV for building the crate has not changed). - by @kjeremy and @bluss +- More of the iterator types implement `Debug`, `ExactSizeIterator`, and + `FusedIterator`, by @cuviper in PR [196]. -[123]: https://github.com/bluss/indexmap/issues/123 -[115]: https://github.com/bluss/indexmap/pull/115 -[120]: https://github.com/bluss/indexmap/pull/120 +- `IndexMap` and `IndexSet` now implement rayon's `ParallelDrainRange`, + by @cuviper in PR [197]. -- 1.3.2 +- `IndexMap::with_hasher` and `IndexSet::with_hasher` are now `const` + functions, allowing static maps and sets, by @mwillsey in PR [203]. - - Maintenance update to regenerate the published `Cargo.toml`. +- `IndexMap` and `IndexSet` now implement `From` for arrays, matching + Rust 1.56's implementation for `HashMap`, by @rouge8 in PR [205]. -- 1.3.1 +- `IndexMap` and `IndexSet` now have methods `sort_unstable_keys`, + `sort_unstable_by`, `sorted_unstable_by`, and `par_*` equivalents, + which sort in-place without preserving the order of equal items, by + @bhgomes in PR [211]. - - Maintenance update for formatting and `autocfg` 1.0. +[195]: https://github.com/indexmap-rs/indexmap/pull/195 +[196]: https://github.com/indexmap-rs/indexmap/pull/196 +[197]: https://github.com/indexmap-rs/indexmap/pull/197 +[203]: https://github.com/indexmap-rs/indexmap/pull/203 +[205]: https://github.com/indexmap-rs/indexmap/pull/205 +[211]: https://github.com/indexmap-rs/indexmap/pull/211 -- 1.3.0 +## 1.7.0 - - The deprecation messages in the previous version have been removed. - (The methods have not otherwise changed.) Docs for removal methods have been - improved. - - From Rust 1.36, this crate supports being built **without std**, requiring - `alloc` instead. This is enabled automatically when it is detected that - `std` is not available. There is no crate feature to enable/disable to - trigger this. The new build-dep `autocfg` enables this. +- **MSRV**: Rust 1.49 or later is now required. -- 1.2.0 +- The `hashbrown` dependency has been updated to version 0.11. - - Plain `.remove()` now has a deprecation message, it informs the user - about picking one of the removal functions `swap_remove` and `shift_remove` - which have different performance and order semantics. - Plain `.remove()` will not be removed, the warning message and method - will remain until further. +## 1.6.2 - - Add new method `shift_remove` for order preserving removal on the map, - and `shift_take` for the corresponding operation on the set. +- Fixed to match `std` behavior, `OccupiedEntry::key` now references the + existing key in the map instead of the lookup key, by @cuviper in PR [170]. - - Add methods `swap_remove`, `swap_remove_entry` to `Entry`. +- The new `Entry::or_insert_with_key` matches Rust 1.50's `Entry` method, + passing `&K` to the callback to create a value, by @cuviper in PR [175]. - - Fix indexset/indexmap to support full paths, like `indexmap::indexmap!()` +[170]: https://github.com/indexmap-rs/indexmap/pull/170 +[175]: https://github.com/indexmap-rs/indexmap/pull/175 - - Internal improvements: fix warnings, deprecations and style lints +## 1.6.1 -- 1.1.0 +- The new `serde_seq` module implements `IndexMap` serialization as a + sequence to ensure order is preserved, by @cuviper in PR [158]. - - Added optional feature `"rayon"` that adds parallel iterator support - to `IndexMap` and `IndexSet` using Rayon. This includes all the regular - iterators in parallel versions, and parallel sort. +- New methods on maps and sets work like the `Vec`/slice methods by the same name: + `truncate`, `split_off`, `first`, `first_mut`, `last`, `last_mut`, and + `swap_indices`, by @cuviper in PR [160]. - - Implemented `Clone` for `map::{Iter, Keys, Values}` and - `set::{Difference, Intersection, Iter, SymmetricDifference, Union}` +[158]: https://github.com/indexmap-rs/indexmap/pull/158 +[160]: https://github.com/indexmap-rs/indexmap/pull/160 - - Implemented `Debug` for `map::{Entry, IntoIter, Iter, Keys, Values}` and - `set::{Difference, Intersection, IntoIter, Iter, SymmetricDifference, Union}` +## 1.6.0 - - Serde trait `IntoDeserializer` are implemented for `IndexMap` and `IndexSet`. +- **MSRV**: Rust 1.36 or later is now required. - - Minimum Rust version requirement increased to Rust 1.30 for development builds. +- The `hashbrown` dependency has been updated to version 0.9. -- 1.0.2 +## 1.5.2 - - The new methods `IndexMap::insert_full` and `IndexSet::insert_full` are - both like `insert` with the index included in the return value. +- The new "std" feature will force the use of `std` for users that explicitly + want the default `S = RandomState`, bypassing the autodetection added in 1.3.0, + by @cuviper in PR [145]. - - The new method `Entry::and_modify` can be used to modify occupied - entries, matching the new methods of `std` maps in Rust 1.26. +[145]: https://github.com/indexmap-rs/indexmap/pull/145 - - The new method `Entry::or_default` inserts a default value in unoccupied - entries, matching the new methods of `std` maps in Rust 1.28. +## 1.5.1 -- 1.0.1 +- Values can now be indexed by their `usize` position by @cuviper in PR [132]. - - Document Rust version policy for the crate (see rustdoc) +- Some of the generic bounds have been relaxed to match `std` by @cuviper in PR [141]. -- 1.0.0 +- `drain` now accepts any `R: RangeBounds` by @cuviper in PR [142]. - - This is the 1.0 release for `indexmap`! (the crate and datastructure - formerly known as “ordermap”) - - `OccupiedEntry::insert` changed its signature, to use `&mut self` for - the method receiver, matching the equivalent method for a standard - `HashMap`. Thanks to @dtolnay for finding this bug. - - The deprecated old names from ordermap were removed: `OrderMap`, - `OrderSet`, `ordermap!{}`, `orderset!{}`. Use the new `IndexMap` - etc names instead. +[132]: https://github.com/indexmap-rs/indexmap/pull/132 +[141]: https://github.com/indexmap-rs/indexmap/pull/141 +[142]: https://github.com/indexmap-rs/indexmap/pull/142 -- 0.4.1 +## 1.5.0 - - Renamed crate to `indexmap`; the `ordermap` crate is now deprecated - and the types `OrderMap/Set` now have a deprecation notice. +- **MSRV**: Rust 1.32 or later is now required. -- 0.4.0 +- The inner hash table is now based on `hashbrown` by @cuviper in PR [131]. + This also completes the method `reserve` and adds `shrink_to_fit`. - - This is the last release series for this `ordermap` under that name, - because the crate is **going to be renamed** to `indexmap` (with types - `IndexMap`, `IndexSet`) and no change in functionality! - - The map and its associated structs moved into the `map` submodule of the - crate, so that the map and set are symmetric +- Add new methods `get_key_value`, `remove_entry`, `swap_remove_entry`, + and `shift_remove_entry`, by @cuviper in PR [136] + +- `Clone::clone_from` reuses allocations by @cuviper in PR [125] + +- Add new method `reverse` by @linclelinkpart5 in PR [128] + +[125]: https://github.com/indexmap-rs/indexmap/pull/125 +[128]: https://github.com/indexmap-rs/indexmap/pull/128 +[131]: https://github.com/indexmap-rs/indexmap/pull/131 +[136]: https://github.com/indexmap-rs/indexmap/pull/136 + +## 1.4.0 + +- Add new method `get_index_of` by @Thermatrix in PR [115] and [120] + +- Fix build script rebuild-if-changed configuration to use "build.rs"; + fixes issue [123]. Fix by @cuviper. + +- Dev-dependencies (rand and quickcheck) have been updated. The crate's tests + now run using Rust 1.32 or later (MSRV for building the crate has not changed). + by @kjeremy and @bluss + +[123]: https://github.com/indexmap-rs/indexmap/issues/123 +[115]: https://github.com/indexmap-rs/indexmap/pull/115 +[120]: https://github.com/indexmap-rs/indexmap/pull/120 + +## 1.3.2 + +- Maintenance update to regenerate the published `Cargo.toml`. + +## 1.3.1 + +- Maintenance update for formatting and `autocfg` 1.0. + +## 1.3.0 + +- The deprecation messages in the previous version have been removed. + (The methods have not otherwise changed.) Docs for removal methods have been + improved. +- From Rust 1.36, this crate supports being built **without std**, requiring + `alloc` instead. This is enabled automatically when it is detected that + `std` is not available. There is no crate feature to enable/disable to + trigger this. The new build-dep `autocfg` enables this. + +## 1.2.0 + +- Plain `.remove()` now has a deprecation message, it informs the user + about picking one of the removal functions `swap_remove` and `shift_remove` + which have different performance and order semantics. + Plain `.remove()` will not be removed, the warning message and method + will remain until further. + +- Add new method `shift_remove` for order preserving removal on the map, + and `shift_take` for the corresponding operation on the set. + +- Add methods `swap_remove`, `swap_remove_entry` to `Entry`. + +- Fix indexset/indexmap to support full paths, like `indexmap::indexmap!()` + +- Internal improvements: fix warnings, deprecations and style lints + +## 1.1.0 + +- Added optional feature `"rayon"` that adds parallel iterator support + to `IndexMap` and `IndexSet` using Rayon. This includes all the regular + iterators in parallel versions, and parallel sort. + +- Implemented `Clone` for `map::{Iter, Keys, Values}` and + `set::{Difference, Intersection, Iter, SymmetricDifference, Union}` + +- Implemented `Debug` for `map::{Entry, IntoIter, Iter, Keys, Values}` and + `set::{Difference, Intersection, IntoIter, Iter, SymmetricDifference, Union}` + +- Serde trait `IntoDeserializer` are implemented for `IndexMap` and `IndexSet`. + +- Minimum Rust version requirement increased to Rust 1.30 for development builds. + +## 1.0.2 + +- The new methods `IndexMap::insert_full` and `IndexSet::insert_full` are + both like `insert` with the index included in the return value. + +- The new method `Entry::and_modify` can be used to modify occupied + entries, matching the new methods of `std` maps in Rust 1.26. + +- The new method `Entry::or_default` inserts a default value in unoccupied + entries, matching the new methods of `std` maps in Rust 1.28. + +## 1.0.1 + +- Document Rust version policy for the crate (see rustdoc) + +## 1.0.0 + +- This is the 1.0 release for `indexmap`! (the crate and datastructure + formerly known as “ordermap”) +- `OccupiedEntry::insert` changed its signature, to use `&mut self` for + the method receiver, matching the equivalent method for a standard + `HashMap`. Thanks to @dtolnay for finding this bug. +- The deprecated old names from ordermap were removed: `OrderMap`, + `OrderSet`, `ordermap!{}`, `orderset!{}`. Use the new `IndexMap` + etc names instead. + +## 0.4.1 + +- Renamed crate to `indexmap`; the `ordermap` crate is now deprecated + and the types `OrderMap/Set` now have a deprecation notice. + +## 0.4.0 + +- This is the last release series for this `ordermap` under that name, + because the crate is **going to be renamed** to `indexmap` (with types + `IndexMap`, `IndexSet`) and no change in functionality! +- The map and its associated structs moved into the `map` submodule of the + crate, so that the map and set are symmetric + The iterators, `Entry` and other structs are now under `ordermap::map::` - - Internally refactored `OrderMap` so that all the main algorithms - (insertion, lookup, removal etc) that don't use the `S` parameter (the - hasher) are compiled without depending on `S`, which reduces generics bloat. +- Internally refactored `OrderMap` so that all the main algorithms + (insertion, lookup, removal etc) that don't use the `S` parameter (the + hasher) are compiled without depending on `S`, which reduces generics bloat. - - `Entry` no longer has a type parameter `S`, which is just like - the standard `HashMap`'s entry. +- `Entry` no longer has a type parameter `S`, which is just like + the standard `HashMap`'s entry. - - Minimum Rust version requirement increased to Rust 1.18 +- Minimum Rust version requirement increased to Rust 1.18 -- 0.3.5 +## 0.3.5 - - Documentation improvements +- Documentation improvements -- 0.3.4 +## 0.3.4 - - The `.retain()` methods for `OrderMap` and `OrderSet` now - traverse the elements in order, and the retained elements **keep their order** - - Added new methods `.sort_by()`, `.sort_keys()` to `OrderMap` and - `.sort_by()`, `.sort()` to `OrderSet`. These methods allow you to - sort the maps in place efficiently. +- The `.retain()` methods for `OrderMap` and `OrderSet` now + traverse the elements in order, and the retained elements **keep their order** +- Added new methods `.sort_by()`, `.sort_keys()` to `OrderMap` and + `.sort_by()`, `.sort()` to `OrderSet`. These methods allow you to + sort the maps in place efficiently. -- 0.3.3 +## 0.3.3 - - Document insertion behaviour better by @lucab - - Updated dependences (no feature changes) by @ignatenkobrain +- Document insertion behaviour better by @lucab +- Updated dependences (no feature changes) by @ignatenkobrain -- 0.3.2 +## 0.3.2 - - Add `OrderSet` by @cuviper! - - `OrderMap::drain` is now (too) a double ended iterator. +- Add `OrderSet` by @cuviper! +- `OrderMap::drain` is now (too) a double ended iterator. -- 0.3.1 +## 0.3.1 - - In all ordermap iterators, forward the `collect` method to the underlying - iterator as well. - - Add crates.io categories. +- In all ordermap iterators, forward the `collect` method to the underlying + iterator as well. +- Add crates.io categories. -- 0.3.0 +## 0.3.0 - - The methods `get_pair`, `get_pair_index` were both replaced by - `get_full` (and the same for the mutable case). - - Method `swap_remove_pair` replaced by `swap_remove_full`. - - Add trait `MutableKeys` for opt-in mutable key access. Mutable key access - is only possible through the methods of this extension trait. - - Add new trait `Equivalent` for key equivalence. This extends the - `Borrow` trait mechanism for `OrderMap::get` in a backwards compatible - way, just some minor type inference related issues may become apparent. - See [#10] for more information. - - Implement `Extend<(&K, &V)>` by @xfix. +- The methods `get_pair`, `get_pair_index` were both replaced by + `get_full` (and the same for the mutable case). +- Method `swap_remove_pair` replaced by `swap_remove_full`. +- Add trait `MutableKeys` for opt-in mutable key access. Mutable key access + is only possible through the methods of this extension trait. +- Add new trait `Equivalent` for key equivalence. This extends the + `Borrow` trait mechanism for `OrderMap::get` in a backwards compatible + way, just some minor type inference related issues may become apparent. + See [#10] for more information. +- Implement `Extend<(&K, &V)>` by @xfix. -[#10]: https://github.com/bluss/ordermap/pull/10 +[#10]: https://github.com/indexmap-rs/indexmap/pull/10 -- 0.2.13 +## 0.2.13 - - Fix deserialization to support custom hashers by @Techcable. - - Add methods `.index()` on the entry types by @garro95. +- Fix deserialization to support custom hashers by @Techcable. +- Add methods `.index()` on the entry types by @garro95. -- 0.2.12 +## 0.2.12 - - Add methods `.with_hasher()`, `.hasher()`. +- Add methods `.with_hasher()`, `.hasher()`. -- 0.2.11 +## 0.2.11 - - Support `ExactSizeIterator` for the iterators. By @Binero. - - Use `Box<[Pos]>` internally, saving a word in the `OrderMap` struct. - - Serde support, with crate feature `"serde-1"`. By @xfix. +- Support `ExactSizeIterator` for the iterators. By @Binero. +- Use `Box<[Pos]>` internally, saving a word in the `OrderMap` struct. +- Serde support, with crate feature `"serde-1"`. By @xfix. -- 0.2.10 +## 0.2.10 - - Add iterator `.drain(..)` by @stevej. +- Add iterator `.drain(..)` by @stevej. -- 0.2.9 +## 0.2.9 - - Add method `.is_empty()` by @overvenus. - - Implement `PartialEq, Eq` by @overvenus. - - Add method `.sorted_by()`. +- Add method `.is_empty()` by @overvenus. +- Implement `PartialEq, Eq` by @overvenus. +- Add method `.sorted_by()`. -- 0.2.8 +## 0.2.8 - - Add iterators `.values()` and `.values_mut()`. - - Fix compatibility with 32-bit platforms. +- Add iterators `.values()` and `.values_mut()`. +- Fix compatibility with 32-bit platforms. -- 0.2.7 +## 0.2.7 - - Add `.retain()`. +- Add `.retain()`. -- 0.2.6 +## 0.2.6 - - Add `OccupiedEntry::remove_entry` and other minor entry methods, - so that it now has all the features of `HashMap`'s entries. +- Add `OccupiedEntry::remove_entry` and other minor entry methods, + so that it now has all the features of `HashMap`'s entries. -- 0.2.5 +## 0.2.5 - - Improved `.pop()` slightly. +- Improved `.pop()` slightly. -- 0.2.4 +## 0.2.4 - - Improved performance of `.insert()` ([#3]) by @pczarn. +- Improved performance of `.insert()` ([#3]) by @pczarn. -[#3]: https://github.com/bluss/ordermap/pull/3 +[#3]: https://github.com/indexmap-rs/indexmap/pull/3 -- 0.2.3 +## 0.2.3 - - Generalize `Entry` for now, so that it works on hashmaps with non-default - hasher. However, there's a lingering compat issue since libstd `HashMap` - does not parameterize its entries by the hasher (`S` typarm). - - Special case some iterator methods like `.nth()`. +- Generalize `Entry` for now, so that it works on hashmaps with non-default + hasher. However, there's a lingering compat issue since libstd `HashMap` + does not parameterize its entries by the hasher (`S` typarm). +- Special case some iterator methods like `.nth()`. -- 0.2.2 +## 0.2.2 - - Disable the verbose `Debug` impl by default. +- Disable the verbose `Debug` impl by default. -- 0.2.1 +## 0.2.1 - - Fix doc links and clarify docs. +- Fix doc links and clarify docs. -- 0.2.0 +## 0.2.0 - - Add more `HashMap` methods & compat with its API. - - Experimental support for `.entry()` (the simplest parts of the API). - - Add `.reserve()` (placeholder impl). - - Add `.remove()` as synonym for `.swap_remove()`. - - Changed `.insert()` to swap value if the entry already exists, and - return `Option`. - - Experimental support as an *indexed* hash map! Added methods - `.get_index()`, `.get_index_mut()`, `.swap_remove_index()`, - `.get_pair_index()`, `.get_pair_index_mut()`. +- Add more `HashMap` methods & compat with its API. +- Experimental support for `.entry()` (the simplest parts of the API). +- Add `.reserve()` (placeholder impl). +- Add `.remove()` as synonym for `.swap_remove()`. +- Changed `.insert()` to swap value if the entry already exists, and + return `Option`. +- Experimental support as an *indexed* hash map! Added methods + `.get_index()`, `.get_index_mut()`, `.swap_remove_index()`, + `.get_pair_index()`, `.get_pair_index_mut()`. -- 0.1.2 +## 0.1.2 - - Implement the 32/32 split idea for `Pos` which improves cache utilization - and lookup performance. +- Implement the 32/32 split idea for `Pos` which improves cache utilization + and lookup performance. -- 0.1.1 +## 0.1.1 - - Initial release. +- Initial release. diff --git a/third_party/rust/indexmap/build.rs b/third_party/rust/indexmap/build.rs deleted file mode 100644 index 9f9fa054f8..0000000000 --- a/third_party/rust/indexmap/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - // If "std" is explicitly requested, don't bother probing the target for it. - match std::env::var_os("CARGO_FEATURE_STD") { - Some(_) => autocfg::emit("has_std"), - None => autocfg::new().emit_sysroot_crate("std"), - } - autocfg::rerun_path("build.rs"); -} diff --git a/third_party/rust/indexmap/src/arbitrary.rs b/third_party/rust/indexmap/src/arbitrary.rs index 1347c8b54f..7798438c15 100644 --- a/third_party/rust/indexmap/src/arbitrary.rs +++ b/third_party/rust/indexmap/src/arbitrary.rs @@ -1,4 +1,5 @@ #[cfg(feature = "arbitrary")] +#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))] mod impl_arbitrary { use crate::{IndexMap, IndexSet}; use arbitrary::{Arbitrary, Result, Unstructured}; @@ -35,6 +36,7 @@ mod impl_arbitrary { } #[cfg(feature = "quickcheck")] +#[cfg_attr(docsrs, doc(cfg(feature = "quickcheck")))] mod impl_quickcheck { use crate::{IndexMap, IndexSet}; use alloc::boxed::Box; diff --git a/third_party/rust/indexmap/src/borsh.rs b/third_party/rust/indexmap/src/borsh.rs new file mode 100644 index 0000000000..c485bd5222 --- /dev/null +++ b/third_party/rust/indexmap/src/borsh.rs @@ -0,0 +1,122 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "borsh")))] + +use alloc::vec::Vec; +use core::hash::BuildHasher; +use core::hash::Hash; +use core::mem::size_of; + +use borsh::error::ERROR_ZST_FORBIDDEN; +use borsh::io::{Error, ErrorKind, Read, Result, Write}; +use borsh::{BorshDeserialize, BorshSerialize}; + +use crate::map::IndexMap; +use crate::set::IndexSet; + +impl BorshSerialize for IndexMap +where + K: BorshSerialize, + V: BorshSerialize, +{ + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + check_zst::()?; + + let iterator = self.iter(); + + u32::try_from(iterator.len()) + .map_err(|_| ErrorKind::InvalidData)? + .serialize(writer)?; + + for (key, value) in iterator { + key.serialize(writer)?; + value.serialize(writer)?; + } + + Ok(()) + } +} + +impl BorshDeserialize for IndexMap +where + K: BorshDeserialize + Eq + Hash, + V: BorshDeserialize, + S: BuildHasher + Default, +{ + #[inline] + fn deserialize_reader(reader: &mut R) -> Result { + check_zst::()?; + let vec = >::deserialize_reader(reader)?; + Ok(vec.into_iter().collect::>()) + } +} + +impl BorshSerialize for IndexSet +where + T: BorshSerialize, +{ + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + check_zst::()?; + + let iterator = self.iter(); + + u32::try_from(iterator.len()) + .map_err(|_| ErrorKind::InvalidData)? + .serialize(writer)?; + + for item in iterator { + item.serialize(writer)?; + } + + Ok(()) + } +} + +impl BorshDeserialize for IndexSet +where + T: BorshDeserialize + Eq + Hash, + S: BuildHasher + Default, +{ + #[inline] + fn deserialize_reader(reader: &mut R) -> Result { + check_zst::()?; + let vec = >::deserialize_reader(reader)?; + Ok(vec.into_iter().collect::>()) + } +} + +fn check_zst() -> Result<()> { + if size_of::() == 0 { + return Err(Error::new(ErrorKind::InvalidData, ERROR_ZST_FORBIDDEN)); + } + Ok(()) +} + +#[cfg(test)] +mod borsh_tests { + use super::*; + + #[test] + fn map_borsh_roundtrip() { + let original_map: IndexMap = { + let mut map = IndexMap::new(); + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + map + }; + let serialized_map = borsh::to_vec(&original_map).unwrap(); + let deserialized_map: IndexMap = + BorshDeserialize::try_from_slice(&serialized_map).unwrap(); + assert_eq!(original_map, deserialized_map); + } + + #[test] + fn set_borsh_roundtrip() { + let original_map: IndexSet = [1, 2, 3, 4, 5, 6].into_iter().collect(); + let serialized_map = borsh::to_vec(&original_map).unwrap(); + let deserialized_map: IndexSet = + BorshDeserialize::try_from_slice(&serialized_map).unwrap(); + assert_eq!(original_map, deserialized_map); + } +} diff --git a/third_party/rust/indexmap/src/equivalent.rs b/third_party/rust/indexmap/src/equivalent.rs deleted file mode 100644 index ad6635ffac..0000000000 --- a/third_party/rust/indexmap/src/equivalent.rs +++ /dev/null @@ -1,27 +0,0 @@ -use core::borrow::Borrow; - -/// Key equivalence trait. -/// -/// This trait allows hash table lookup to be customized. -/// It has one blanket implementation that uses the regular `Borrow` solution, -/// just like `HashMap` and `BTreeMap` do, so that you can pass `&str` to lookup -/// into a map with `String` keys and so on. -/// -/// # Contract -/// -/// The implementor **must** hash like `K`, if it is hashable. -pub trait Equivalent { - /// Compare self to `key` and return `true` if they are equal. - fn equivalent(&self, key: &K) -> bool; -} - -impl Equivalent for Q -where - Q: Eq, - K: Borrow, -{ - #[inline] - fn equivalent(&self, key: &K) -> bool { - *self == *key.borrow() - } -} diff --git a/third_party/rust/indexmap/src/lib.rs b/third_party/rust/indexmap/src/lib.rs index 6e94936124..7d88ffef08 100644 --- a/third_party/rust/indexmap/src/lib.rs +++ b/third_party/rust/indexmap/src/lib.rs @@ -1,7 +1,6 @@ // We *mostly* avoid unsafe code, but `map::core::raw` allows it to use `RawTable` buckets. #![deny(unsafe_code)] #![warn(rust_2018_idioms)] -#![doc(html_root_url = "https://docs.rs/indexmap/1/")] #![no_std] //! [`IndexMap`] is a hash table where the iteration order of the key-value @@ -10,11 +9,7 @@ //! [`IndexSet`] is a corresponding hash set using the same implementation and //! with similar properties. //! -//! [`IndexMap`]: map/struct.IndexMap.html -//! [`IndexSet`]: set/struct.IndexSet.html -//! -//! -//! ### Feature Highlights +//! ### Highlights //! //! [`IndexMap`] and [`IndexSet`] are drop-in compatible with the std `HashMap` //! and `HashSet`, but they also have some features of note: @@ -24,11 +19,44 @@ //! - The [`Equivalent`] trait, which offers more flexible equality definitions //! between borrowed and owned versions of keys. //! - The [`MutableKeys`][map::MutableKeys] trait, which gives opt-in mutable -//! access to hash map keys. +//! access to map keys, and [`MutableValues`][set::MutableValues] for sets. +//! +//! ### Feature Flags +//! +//! To reduce the amount of compiled code in the crate by default, certain +//! features are gated behind [feature flags]. These allow you to opt in to (or +//! out of) functionality. Below is a list of the features available in this +//! crate. +//! +//! * `std`: Enables features which require the Rust standard library. For more +//! information see the section on [`no_std`]. +//! * `rayon`: Enables parallel iteration and other parallel methods. +//! * `serde`: Adds implementations for [`Serialize`] and [`Deserialize`] +//! to [`IndexMap`] and [`IndexSet`]. Alternative implementations for +//! (de)serializing [`IndexMap`] as an ordered sequence are available in the +//! [`map::serde_seq`] module. +//! * `borsh`: Adds implementations for [`BorshSerialize`] and [`BorshDeserialize`] +//! to [`IndexMap`] and [`IndexSet`]. +//! * `arbitrary`: Adds implementations for the [`arbitrary::Arbitrary`] trait +//! to [`IndexMap`] and [`IndexSet`]. +//! * `quickcheck`: Adds implementations for the [`quickcheck::Arbitrary`] trait +//! to [`IndexMap`] and [`IndexSet`]. +//! +//! _Note: only the `std` feature is enabled by default._ +//! +//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section +//! [`no_std`]: #no-standard-library-targets +//! [`Serialize`]: `::serde::Serialize` +//! [`Deserialize`]: `::serde::Deserialize` +//! [`BorshSerialize`]: `::borsh::BorshSerialize` +//! [`BorshDeserialize`]: `::borsh::BorshDeserialize` +//! [`arbitrary::Arbitrary`]: `::arbitrary::Arbitrary` +//! [`quickcheck::Arbitrary`]: `::quickcheck::Arbitrary` //! //! ### Alternate Hashers //! -//! [`IndexMap`] and [`IndexSet`] have a default hasher type `S = RandomState`, +//! [`IndexMap`] and [`IndexSet`] have a default hasher type +//! [`S = RandomState`][std::collections::hash_map::RandomState], //! just like the standard `HashMap` and `HashSet`, which is resistant to //! HashDoS attacks but not the most performant. Type aliases can make it easier //! to use alternate hashers: @@ -53,33 +81,31 @@ //! //! ### Rust Version //! -//! This version of indexmap requires Rust 1.56 or later. +//! This version of indexmap requires Rust 1.63 or later. //! -//! The indexmap 1.x release series will use a carefully considered version -//! upgrade policy, where in a later 1.x version, we will raise the minimum +//! The indexmap 2.x release series will use a carefully considered version +//! upgrade policy, where in a later 2.x version, we will raise the minimum //! required Rust version. //! //! ## No Standard Library Targets //! -//! This crate supports being built without `std`, requiring -//! `alloc` instead. This is enabled automatically when it is detected that -//! `std` is not available. There is no crate feature to enable/disable to -//! trigger this. It can be tested by building for a std-less target. +//! This crate supports being built without `std`, requiring `alloc` instead. +//! This is chosen by disabling the default "std" cargo feature, by adding +//! `default-features = false` to your dependency specification. //! //! - Creating maps and sets using [`new`][IndexMap::new] and -//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`. -//! Use methods [`IndexMap::default`][def], -//! [`with_hasher`][IndexMap::with_hasher], +//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`. +//! Use methods [`IndexMap::default`], [`with_hasher`][IndexMap::with_hasher], //! [`with_capacity_and_hasher`][IndexMap::with_capacity_and_hasher] instead. //! A no-std compatible hasher will be needed as well, for example //! from the crate `twox-hash`. //! - Macros [`indexmap!`] and [`indexset!`] are unavailable without `std`. -//! -//! [def]: map/struct.IndexMap.html#impl-Default + +#![cfg_attr(docsrs, feature(doc_cfg))] extern crate alloc; -#[cfg(has_std)] +#[cfg(feature = "std")] #[macro_use] extern crate std; @@ -88,12 +114,10 @@ use alloc::vec::{self, Vec}; mod arbitrary; #[macro_use] mod macros; -mod equivalent; -mod mutable_keys; +#[cfg(feature = "borsh")] +mod borsh; #[cfg(feature = "serde")] mod serde; -#[cfg(feature = "serde")] -pub mod serde_seq; mod util; pub mod map; @@ -107,9 +131,9 @@ mod rayon; #[cfg(feature = "rustc-rayon")] mod rustc; -pub use crate::equivalent::Equivalent; pub use crate::map::IndexMap; pub use crate::set::IndexSet; +pub use equivalent::Equivalent; // shared private items @@ -192,3 +216,59 @@ trait Entries { where F: FnOnce(&mut [Self::Entry]); } + +/// The error type for [`try_reserve`][IndexMap::try_reserve] methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct TryReserveError { + kind: TryReserveErrorKind, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum TryReserveErrorKind { + // The standard library's kind is currently opaque to us, otherwise we could unify this. + Std(alloc::collections::TryReserveError), + CapacityOverflow, + AllocError { layout: alloc::alloc::Layout }, +} + +// These are not `From` so we don't expose them in our public API. +impl TryReserveError { + fn from_alloc(error: alloc::collections::TryReserveError) -> Self { + Self { + kind: TryReserveErrorKind::Std(error), + } + } + + fn from_hashbrown(error: hashbrown::TryReserveError) -> Self { + Self { + kind: match error { + hashbrown::TryReserveError::CapacityOverflow => { + TryReserveErrorKind::CapacityOverflow + } + hashbrown::TryReserveError::AllocError { layout } => { + TryReserveErrorKind::AllocError { layout } + } + }, + } + } +} + +impl core::fmt::Display for TryReserveError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let reason = match &self.kind { + TryReserveErrorKind::Std(e) => return core::fmt::Display::fmt(e, f), + TryReserveErrorKind::CapacityOverflow => { + " because the computed capacity exceeded the collection's maximum" + } + TryReserveErrorKind::AllocError { .. } => { + " because the memory allocator returned an error" + } + }; + f.write_str("memory allocation failed")?; + f.write_str(reason) + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for TryReserveError {} diff --git a/third_party/rust/indexmap/src/macros.rs b/third_party/rust/indexmap/src/macros.rs index ca26287be9..b347de22dd 100644 --- a/third_party/rust/indexmap/src/macros.rs +++ b/third_party/rust/indexmap/src/macros.rs @@ -1,6 +1,7 @@ -#[cfg(has_std)] +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[macro_export] -/// Create an `IndexMap` from a list of key-value pairs +/// Create an [`IndexMap`][crate::IndexMap] from a list of key-value pairs /// /// ## Example /// @@ -19,25 +20,25 @@ /// assert_eq!(map.keys().next(), Some(&"a")); /// ``` macro_rules! indexmap { - (@single $($x:tt)*) => (()); - (@count $($rest:expr),*) => (<[()]>::len(&[$($crate::indexmap!(@single $rest)),*])); - ($($key:expr => $value:expr,)+) => { $crate::indexmap!($($key => $value),+) }; ($($key:expr => $value:expr),*) => { { - let _cap = $crate::indexmap!(@count $($key),*); - let mut _map = $crate::IndexMap::with_capacity(_cap); + // Note: `stringify!($key)` is just here to consume the repetition, + // but we throw away that string literal during constant evaluation. + const CAP: usize = <[()]>::len(&[$({ stringify!($key); }),*]); + let mut map = $crate::IndexMap::with_capacity(CAP); $( - _map.insert($key, $value); + map.insert($key, $value); )* - _map + map } }; } -#[cfg(has_std)] +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[macro_export] -/// Create an `IndexSet` from a list of values +/// Create an [`IndexSet`][crate::IndexSet] from a list of values /// /// ## Example /// @@ -56,18 +57,17 @@ macro_rules! indexmap { /// assert_eq!(set.iter().next(), Some(&"a")); /// ``` macro_rules! indexset { - (@single $($x:tt)*) => (()); - (@count $($rest:expr),*) => (<[()]>::len(&[$($crate::indexset!(@single $rest)),*])); - ($($value:expr,)+) => { $crate::indexset!($($value),+) }; ($($value:expr),*) => { { - let _cap = $crate::indexset!(@count $($value),*); - let mut _set = $crate::IndexSet::with_capacity(_cap); + // Note: `stringify!($value)` is just here to consume the repetition, + // but we throw away that string literal during constant evaluation. + const CAP: usize = <[()]>::len(&[$({ stringify!($value); }),*]); + let mut set = $crate::IndexSet::with_capacity(CAP); $( - _set.insert($value); + set.insert($value); )* - _set + set } }; } diff --git a/third_party/rust/indexmap/src/map.rs b/third_party/rust/indexmap/src/map.rs index d39448d06d..82824c9002 100644 --- a/third_party/rust/indexmap/src/map.rs +++ b/third_party/rust/indexmap/src/map.rs @@ -1,36 +1,50 @@ -//! `IndexMap` is a hash table where the iteration order of the key-value +//! [`IndexMap`] is a hash table where the iteration order of the key-value //! pairs is independent of the hash values of the keys. mod core; +mod iter; +mod mutable; +mod slice; -pub use crate::mutable_keys::MutableKeys; +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +pub mod serde_seq; + +#[cfg(test)] +mod tests; + +pub use self::core::raw_entry_v1::{self, RawEntryApiV1}; +pub use self::core::{Entry, IndexedEntry, OccupiedEntry, VacantEntry}; +pub use self::iter::{ + Drain, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Splice, Values, ValuesMut, +}; +pub use self::mutable::MutableKeys; +pub use self::slice::Slice; #[cfg(feature = "rayon")] pub use crate::rayon::map as rayon; -use crate::vec::{self, Vec}; use ::core::cmp::Ordering; use ::core::fmt; use ::core::hash::{BuildHasher, Hash, Hasher}; -use ::core::iter::FusedIterator; +use ::core::mem; use ::core::ops::{Index, IndexMut, RangeBounds}; -use ::core::slice::{Iter as SliceIter, IterMut as SliceIterMut}; +use alloc::boxed::Box; +use alloc::vec::Vec; -#[cfg(has_std)] +#[cfg(feature = "std")] use std::collections::hash_map::RandomState; use self::core::IndexMapCore; -use crate::equivalent::Equivalent; -use crate::util::third; -use crate::{Bucket, Entries, HashValue}; - -pub use self::core::{Entry, OccupiedEntry, VacantEntry}; +use crate::util::{third, try_simplify_range}; +use crate::{Bucket, Entries, Equivalent, HashValue, TryReserveError}; /// A hash table where the iteration order of the key-value pairs is independent /// of the hash values of the keys. /// -/// The interface is closely compatible with the standard `HashMap`, but also -/// has additional features. +/// The interface is closely compatible with the standard +/// [`HashMap`][std::collections::HashMap], +/// but also has additional features. /// /// # Order /// @@ -41,7 +55,8 @@ pub use self::core::{Entry, OccupiedEntry, VacantEntry}; /// All iterators traverse the map in *the order*. /// /// The insertion order is preserved, with **notable exceptions** like the -/// `.remove()` or `.swap_remove()` methods. Methods such as `.sort_by()` of +/// [`.remove()`][Self::remove] or [`.swap_remove()`][Self::swap_remove] methods. +/// Methods such as [`.sort_by()`][Self::sort_by] of /// course result in a new order, depending on the sorting order. /// /// # Indices @@ -67,12 +82,12 @@ pub use self::core::{Entry, OccupiedEntry, VacantEntry}; /// assert_eq!(letters[&'u'], 1); /// assert_eq!(letters.get(&'y'), None); /// ``` -#[cfg(has_std)] +#[cfg(feature = "std")] pub struct IndexMap { pub(crate) core: IndexMapCore, hash_builder: S, } -#[cfg(not(has_std))] +#[cfg(not(feature = "std"))] pub struct IndexMap { pub(crate) core: IndexMapCore, hash_builder: S, @@ -128,19 +143,22 @@ where K: fmt::Debug, V: fmt::Debug, { + #[cfg(not(feature = "test_debug"))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if cfg!(not(feature = "test_debug")) { - f.debug_map().entries(self.iter()).finish() - } else { - // Let the inner `IndexMapCore` print all of its details - f.debug_struct("IndexMap") - .field("core", &self.core) - .finish() - } + f.debug_map().entries(self.iter()).finish() + } + + #[cfg(feature = "test_debug")] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Let the inner `IndexMapCore` print all of its details + f.debug_struct("IndexMap") + .field("core", &self.core) + .finish() } } -#[cfg(has_std)] +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl IndexMap { /// Create a new map. (Does not allocate.) #[inline] @@ -186,6 +204,11 @@ impl IndexMap { } } + /// Return the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the map might be able to hold more, + /// but is guaranteed to be able to hold at least this many. + /// /// Computes in **O(1)** time. pub fn capacity(&self) -> usize { self.core.capacity() @@ -214,52 +237,38 @@ impl IndexMap { /// Return an iterator over the key-value pairs of the map, in their order pub fn iter(&self) -> Iter<'_, K, V> { - Iter { - iter: self.as_entries().iter(), - } + Iter::new(self.as_entries()) } /// Return an iterator over the key-value pairs of the map, in their order pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { - IterMut { - iter: self.as_entries_mut().iter_mut(), - } + IterMut::new(self.as_entries_mut()) } /// Return an iterator over the keys of the map, in their order pub fn keys(&self) -> Keys<'_, K, V> { - Keys { - iter: self.as_entries().iter(), - } + Keys::new(self.as_entries()) } /// Return an owning iterator over the keys of the map, in their order pub fn into_keys(self) -> IntoKeys { - IntoKeys { - iter: self.into_entries().into_iter(), - } + IntoKeys::new(self.into_entries()) } /// Return an iterator over the values of the map, in their order pub fn values(&self) -> Values<'_, K, V> { - Values { - iter: self.as_entries().iter(), - } + Values::new(self.as_entries()) } /// Return an iterator over mutable references to the values of the map, /// in their order pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { - ValuesMut { - iter: self.as_entries_mut().iter_mut(), - } + ValuesMut::new(self.as_entries_mut()) } /// Return an owning iterator over the values of the map, in their order pub fn into_values(self) -> IntoValues { - IntoValues { - iter: self.into_entries().into_iter(), - } + IntoValues::new(self.into_entries()) } /// Remove all key-value pairs in the map, while preserving its capacity. @@ -279,7 +288,7 @@ impl IndexMap { /// Clears the `IndexMap` in the given index range, returning those /// key-value pairs as a drain iterator. /// - /// The range may be any type that implements `RangeBounds`, + /// The range may be any type that implements [`RangeBounds`], /// including all of the `std::ops::Range*` types, or even a tuple pair of /// `Bound` start and end values. To drain the map entirely, use `RangeFull` /// like `map.drain(..)`. @@ -293,9 +302,7 @@ impl IndexMap { where R: RangeBounds, { - Drain { - iter: self.core.drain(range), - } + Drain::new(self.core.drain(range)) } /// Splits the collection into two at the given index. @@ -314,13 +321,7 @@ impl IndexMap { hash_builder: self.hash_builder.clone(), } } -} -impl IndexMap -where - K: Hash + Eq, - S: BuildHasher, -{ /// Reserve capacity for `additional` more key-value pairs. /// /// Computes in **O(n)** time. @@ -328,6 +329,37 @@ where self.core.reserve(additional); } + /// Reserve capacity for `additional` more key-value pairs, without over-allocating. + /// + /// Unlike `reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn reserve_exact(&mut self, additional: usize) { + self.core.reserve_exact(additional); + } + + /// Try to reserve capacity for `additional` more key-value pairs. + /// + /// Computes in **O(n)** time. + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.core.try_reserve(additional) + } + + /// Try to reserve capacity for `additional` more key-value pairs, without over-allocating. + /// + /// Unlike `try_reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.core.try_reserve_exact(additional) + } + /// Shrink the capacity of the map as much as possible. /// /// Computes in **O(n)** time. @@ -341,26 +373,27 @@ where pub fn shrink_to(&mut self, min_capacity: usize) { self.core.shrink_to(min_capacity); } +} - fn hash(&self, key: &Q) -> HashValue { - let mut h = self.hash_builder.build_hasher(); - key.hash(&mut h); - HashValue(h.finish() as usize) - } - +impl IndexMap +where + K: Hash + Eq, + S: BuildHasher, +{ /// Insert a key-value pair in the map. /// /// If an equivalent key already exists in the map: the key remains and /// retains in its place in the order, its corresponding value is updated - /// with `value` and the older value is returned inside `Some(_)`. + /// with `value`, and the older value is returned inside `Some(_)`. /// /// If no equivalent key existed in the map: the new key-value pair is /// inserted, last in order, and `None` is returned. /// /// Computes in **O(1)** time (amortized average). /// - /// See also [`entry`](#method.entry) if you you want to insert *or* modify - /// or if you need to get the index of the corresponding key-value pair. + /// See also [`entry`][Self::entry] if you want to insert *or* modify, + /// or [`insert_full`][Self::insert_full] if you need to get the index of + /// the corresponding key-value pair. pub fn insert(&mut self, key: K, value: V) -> Option { self.insert_full(key, value).1 } @@ -369,20 +402,77 @@ where /// /// If an equivalent key already exists in the map: the key remains and /// retains in its place in the order, its corresponding value is updated - /// with `value` and the older value is returned inside `(index, Some(_))`. + /// with `value`, and the older value is returned inside `(index, Some(_))`. /// /// If no equivalent key existed in the map: the new key-value pair is /// inserted, last in order, and `(index, None)` is returned. /// /// Computes in **O(1)** time (amortized average). /// - /// See also [`entry`](#method.entry) if you you want to insert *or* modify - /// or if you need to get the index of the corresponding key-value pair. + /// See also [`entry`][Self::entry] if you want to insert *or* modify. pub fn insert_full(&mut self, key: K, value: V) -> (usize, Option) { let hash = self.hash(&key); self.core.insert_full(hash, key, value) } + /// Insert a key-value pair in the map at its ordered position among sorted keys. + /// + /// This is equivalent to finding the position with + /// [`binary_search_keys`][Self::binary_search_keys], then either updating + /// it or calling [`shift_insert`][Self::shift_insert] for a new key. + /// + /// If the sorted key is found in the map, its corresponding value is + /// updated with `value`, and the older value is returned inside + /// `(index, Some(_))`. Otherwise, the new key-value pair is inserted at + /// the sorted position, and `(index, None)` is returned. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). Instead of repeating calls to + /// `insert_sorted`, it may be faster to call batched [`insert`][Self::insert] + /// or [`extend`][Self::extend] and only call [`sort_keys`][Self::sort_keys] + /// or [`sort_unstable_keys`][Self::sort_unstable_keys] once. + pub fn insert_sorted(&mut self, key: K, value: V) -> (usize, Option) + where + K: Ord, + { + match self.binary_search_keys(&key) { + Ok(i) => (i, Some(mem::replace(&mut self[i], value))), + Err(i) => (i, self.shift_insert(i, key, value)), + } + } + + /// Insert a key-value pair in the map at the given index. + /// + /// If an equivalent key already exists in the map: the key remains and + /// is moved to the new position in the map, its corresponding value is updated + /// with `value`, and the older value is returned inside `Some(_)`. + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted at the given index, and `None` is returned. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + /// + /// See also [`entry`][Self::entry] if you want to insert *or* modify, + /// perhaps only using the index for new entries with [`VacantEntry::shift_insert`]. + pub fn shift_insert(&mut self, index: usize, key: K, value: V) -> Option { + match self.entry(key) { + Entry::Occupied(mut entry) => { + let old = mem::replace(entry.get_mut(), value); + entry.move_index(index); + Some(old) + } + Entry::Vacant(entry) => { + entry.shift_insert(index, value); + None + } + } + } + /// Get the given key’s corresponding entry in the map for insertion and/or /// in-place manipulation. /// @@ -392,12 +482,61 @@ where self.core.entry(hash, key) } + /// Creates a splicing iterator that replaces the specified range in the map + /// with the given `replace_with` key-value iterator and yields the removed + /// items. `replace_with` does not need to be the same length as `range`. + /// + /// The `range` is removed even if the iterator is not consumed until the + /// end. It is unspecified how many elements are removed from the map if the + /// `Splice` value is leaked. + /// + /// The input iterator `replace_with` is only consumed when the `Splice` + /// value is dropped. If a key from the iterator matches an existing entry + /// in the map (outside of `range`), then the value will be updated in that + /// position. Otherwise, the new key-value pair will be inserted in the + /// replaced `range`. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the map. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// let mut map = IndexMap::from([(0, '_'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]); + /// let new = [(5, 'E'), (4, 'D'), (3, 'C'), (2, 'B'), (1, 'A')]; + /// let removed: Vec<_> = map.splice(2..4, new).collect(); + /// + /// // 1 and 4 got new values, while 5, 3, and 2 were newly inserted. + /// assert!(map.into_iter().eq([(0, '_'), (1, 'A'), (5, 'E'), (3, 'C'), (2, 'B'), (4, 'D')])); + /// assert_eq!(removed, &[(2, 'b'), (3, 'c')]); + /// ``` + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, K, V, S> + where + R: RangeBounds, + I: IntoIterator, + { + Splice::new(self, range, replace_with.into_iter()) + } +} + +impl IndexMap +where + S: BuildHasher, +{ + pub(crate) fn hash(&self, key: &Q) -> HashValue { + let mut h = self.hash_builder.build_hasher(); + key.hash(&mut h); + HashValue(h.finish() as usize) + } + /// Return `true` if an equivalent to `key` exists in the map. /// /// Computes in **O(1)** time (average). - pub fn contains_key(&self, key: &Q) -> bool + pub fn contains_key(&self, key: &Q) -> bool where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.get_index_of(key).is_some() } @@ -406,9 +545,9 @@ where /// else `None`. /// /// Computes in **O(1)** time (average). - pub fn get(&self, key: &Q) -> Option<&V> + pub fn get(&self, key: &Q) -> Option<&V> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { if let Some(i) = self.get_index_of(key) { let entry = &self.as_entries()[i]; @@ -422,9 +561,9 @@ where /// if it is present, else `None`. /// /// Computes in **O(1)** time (average). - pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> + pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { if let Some(i) = self.get_index_of(key) { let entry = &self.as_entries()[i]; @@ -435,9 +574,9 @@ where } /// Return item index, key and value - pub fn get_full(&self, key: &Q) -> Option<(usize, &K, &V)> + pub fn get_full(&self, key: &Q) -> Option<(usize, &K, &V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { if let Some(i) = self.get_index_of(key) { let entry = &self.as_entries()[i]; @@ -450,21 +589,23 @@ where /// Return item index, if it exists in the map /// /// Computes in **O(1)** time (average). - pub fn get_index_of(&self, key: &Q) -> Option + pub fn get_index_of(&self, key: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { - if self.is_empty() { - None - } else { - let hash = self.hash(key); - self.core.get_index_of(hash, key) + match self.as_entries() { + [] => None, + [x] => key.equivalent(&x.key).then_some(0), + _ => { + let hash = self.hash(key); + self.core.get_index_of(hash, key) + } } } - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { if let Some(i) = self.get_index_of(key) { let entry = &mut self.as_entries_mut()[i]; @@ -474,9 +615,9 @@ where } } - pub fn get_full_mut(&mut self, key: &Q) -> Option<(usize, &K, &mut V)> + pub fn get_full_mut(&mut self, key: &Q) -> Option<(usize, &K, &mut V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { if let Some(i) = self.get_index_of(key) { let entry = &mut self.as_entries_mut()[i]; @@ -486,46 +627,33 @@ where } } - pub(crate) fn get_full_mut2_impl( - &mut self, - key: &Q, - ) -> Option<(usize, &mut K, &mut V)> - where - Q: Hash + Equivalent, - { - if let Some(i) = self.get_index_of(key) { - let entry = &mut self.as_entries_mut()[i]; - Some((i, &mut entry.key, &mut entry.value)) - } else { - None - } - } - /// Remove the key-value pair equivalent to `key` and return /// its value. /// - /// **NOTE:** This is equivalent to `.swap_remove(key)`, if you need to - /// preserve the order of the keys in the map, use `.shift_remove(key)` - /// instead. - /// - /// Computes in **O(1)** time (average). - pub fn remove(&mut self, key: &Q) -> Option + /// **NOTE:** This is equivalent to [`.swap_remove(key)`][Self::swap_remove], replacing this + /// entry's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the keys in the map, use + /// [`.shift_remove(key)`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the map order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(&mut self, key: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.swap_remove(key) } /// Remove and return the key-value pair equivalent to `key`. /// - /// **NOTE:** This is equivalent to `.swap_remove_entry(key)`, if you need to - /// preserve the order of the keys in the map, use `.shift_remove_entry(key)` - /// instead. - /// - /// Computes in **O(1)** time (average). - pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> + /// **NOTE:** This is equivalent to [`.swap_remove_entry(key)`][Self::swap_remove_entry], + /// replacing this entry's position with the last element, and it is deprecated in favor of + /// calling that explicitly. If you need to preserve the relative order of the keys in the map, + /// use [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead. + #[deprecated(note = "`remove_entry` disrupts the map order -- \ + use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")] + pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.swap_remove_entry(key) } @@ -533,32 +661,32 @@ where /// Remove the key-value pair equivalent to `key` and return /// its value. /// - /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs /// the position of what used to be the last element!** /// /// Return `None` if `key` is not in map. /// /// Computes in **O(1)** time (average). - pub fn swap_remove(&mut self, key: &Q) -> Option + pub fn swap_remove(&mut self, key: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.swap_remove_full(key).map(third) } /// Remove and return the key-value pair equivalent to `key`. /// - /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs /// the position of what used to be the last element!** /// /// Return `None` if `key` is not in map. /// /// Computes in **O(1)** time (average). - pub fn swap_remove_entry(&mut self, key: &Q) -> Option<(K, V)> + pub fn swap_remove_entry(&mut self, key: &Q) -> Option<(K, V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { match self.swap_remove_full(key) { Some((_, key, value)) => Some((key, value)), @@ -569,53 +697,59 @@ where /// Remove the key-value pair equivalent to `key` and return it and /// the index it had. /// - /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs /// the position of what used to be the last element!** /// /// Return `None` if `key` is not in map. /// /// Computes in **O(1)** time (average). - pub fn swap_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> + pub fn swap_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { - if self.is_empty() { - return None; + match self.as_entries() { + [x] if key.equivalent(&x.key) => { + let (k, v) = self.core.pop()?; + Some((0, k, v)) + } + [_] | [] => None, + _ => { + let hash = self.hash(key); + self.core.swap_remove_full(hash, key) + } } - let hash = self.hash(key); - self.core.swap_remove_full(hash, key) } /// Remove the key-value pair equivalent to `key` and return /// its value. /// - /// Like `Vec::remove`, the pair is removed by shifting all of the + /// Like [`Vec::remove`], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Return `None` if `key` is not in map. /// /// Computes in **O(n)** time (average). - pub fn shift_remove(&mut self, key: &Q) -> Option + pub fn shift_remove(&mut self, key: &Q) -> Option where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { self.shift_remove_full(key).map(third) } /// Remove and return the key-value pair equivalent to `key`. /// - /// Like `Vec::remove`, the pair is removed by shifting all of the + /// Like [`Vec::remove`], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Return `None` if `key` is not in map. /// /// Computes in **O(n)** time (average). - pub fn shift_remove_entry(&mut self, key: &Q) -> Option<(K, V)> + pub fn shift_remove_entry(&mut self, key: &Q) -> Option<(K, V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { match self.shift_remove_full(key) { Some((_, key, value)) => Some((key, value)), @@ -626,24 +760,32 @@ where /// Remove the key-value pair equivalent to `key` and return it and /// the index it had. /// - /// Like `Vec::remove`, the pair is removed by shifting all of the + /// Like [`Vec::remove`], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Return `None` if `key` is not in map. /// /// Computes in **O(n)** time (average). - pub fn shift_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> + pub fn shift_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> where - Q: Hash + Equivalent, + Q: ?Sized + Hash + Equivalent, { - if self.is_empty() { - return None; + match self.as_entries() { + [x] if key.equivalent(&x.key) => { + let (k, v) = self.core.pop()?; + Some((0, k, v)) + } + [_] | [] => None, + _ => { + let hash = self.hash(key); + self.core.shift_remove_full(hash, key) + } } - let hash = self.hash(key); - self.core.shift_remove_full(hash, key) } +} +impl IndexMap { /// Remove the last key-value pair /// /// This preserves the order of the remaining elements. @@ -667,15 +809,12 @@ where self.core.retain_in_order(move |k, v| keep(k, v)); } - pub(crate) fn retain_mut(&mut self, keep: F) - where - F: FnMut(&mut K, &mut V) -> bool, - { - self.core.retain_in_order(keep); - } - /// Sort the map’s key-value pairs by the default ordering of the keys. /// + /// This is a stable sort -- but equivalent keys should not normally coexist in + /// a map at all, so [`sort_unstable_keys`][Self::sort_unstable_keys] is preferred + /// because it is generally faster and doesn't allocate auxiliary memory. + /// /// See [`sort_by`](Self::sort_by) for details. pub fn sort_keys(&mut self) where @@ -713,9 +852,7 @@ where { let mut entries = self.into_entries(); entries.sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); - IntoIter { - iter: entries.into_iter(), - } + IntoIter::new(entries) } /// Sort the map's key-value pairs by the default ordering of the keys, but @@ -759,9 +896,82 @@ where { let mut entries = self.into_entries(); entries.sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); - IntoIter { - iter: entries.into_iter(), - } + IntoIter::new(entries) + } + + /// Sort the map’s key-value pairs in place using a sort-key extraction function. + /// + /// During sorting, the function is called at most once per entry, by using temporary storage + /// to remember the results of its evaluation. The order of calls to the function is + /// unspecified and may change between versions of `indexmap` or the standard library. + /// + /// Computes in **O(m n + n log n + c)** time () and **O(n)** space, where the function is + /// **O(m)**, *n* is the length of the map, and *c* the capacity. The sort is stable. + pub fn sort_by_cached_key(&mut self, mut sort_key: F) + where + T: Ord, + F: FnMut(&K, &V) -> T, + { + self.with_entries(move |entries| { + entries.sort_by_cached_key(move |a| sort_key(&a.key, &a.value)); + }); + } + + /// Search over a sorted map for a key. + /// + /// Returns the position where that key is present, or the position where it can be inserted to + /// maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the key up + /// using [`get_index_of`][IndexMap::get_index_of], but this can also position missing keys. + pub fn binary_search_keys(&self, x: &K) -> Result + where + K: Ord, + { + self.as_slice().binary_search_keys(x) + } + + /// Search over a sorted map with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> Ordering, + { + self.as_slice().binary_search_by(f) + } + + /// Search over a sorted map with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> B, + B: Ord, + { + self.as_slice().binary_search_by_key(b, f) + } + + /// Returns the index of the partition point of a sorted map according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point