Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

File diff suppressed because one or more lines are too long

842
vendor/bevy_reflect/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,842 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "assert_type_match"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bevy_macro_utils"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052eeebcb8e7e072beea5031b227d9a290f8a7fbbb947573ab6ec81df0fb94be"
dependencies = [
"parking_lot",
"proc-macro2",
"quote",
"syn",
"toml_edit",
]
[[package]]
name = "bevy_platform"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7573dc824a1b08b4c93fdbe421c53e1e8188e9ca1dd74a414455fe571facb47"
dependencies = [
"cfg-if",
"critical-section",
"foldhash",
"getrandom 0.2.16",
"hashbrown",
"portable-atomic",
"portable-atomic-util",
"serde",
"spin",
"web-time",
]
[[package]]
name = "bevy_ptr"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df7370d0e46b60e071917711d0860721f5347bc958bf325975ae6913a5dfcf01"
[[package]]
name = "bevy_reflect"
version = "0.16.1"
dependencies = [
"assert_type_match",
"bevy_platform",
"bevy_ptr",
"bevy_reflect_derive",
"bevy_utils",
"bincode",
"derive_more",
"disqualified",
"downcast-rs",
"erased-serde",
"foldhash",
"glam",
"hashbrown",
"petgraph",
"rmp-serde",
"ron",
"serde",
"serde_json",
"smallvec",
"smol_str",
"static_assertions",
"thiserror",
"uuid",
"variadics_please",
"wgpu-types",
]
[[package]]
name = "bevy_reflect_derive"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ddadc55fe16b45faaa54ab2f9cb00548013c74812e8b018aa172387103cce6"
dependencies = [
"bevy_macro_utils",
"proc-macro2",
"quote",
"syn",
"uuid",
]
[[package]]
name = "bevy_utils"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f7a8905a125d2017e8561beefb7f2f5e67e93ff6324f072ad87c5fd6ec3b99"
dependencies = [
"bevy_platform",
"thread_local",
]
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"bincode_derive",
"serde",
"unty",
]
[[package]]
name = "bincode_derive"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
dependencies = [
"virtue",
]
[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
dependencies = [
"serde",
]
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "derive_more"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "disqualified"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd"
[[package]]
name = "downcast-rs"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea8a8b81cacc08888170eef4d13b775126db426d0b348bee9d18c2c1eaf123cf"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "erased-serde"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7"
dependencies = [
"serde",
"typeid",
]
[[package]]
name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
]
[[package]]
name = "glam"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
dependencies = [
"serde",
]
[[package]]
name = "hashbrown"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
dependencies = [
"equivalent",
"serde",
]
[[package]]
name = "indexmap"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "petgraph"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
dependencies = [
"fixedbitset",
"indexmap",
"serde",
"serde_derive",
]
[[package]]
name = "portable-atomic"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
dependencies = [
"critical-section",
]
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "redox_syscall"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
dependencies = [
"bitflags",
]
[[package]]
name = "rmp"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4"
dependencies = [
"byteorder",
"num-traits",
"paste",
]
[[package]]
name = "rmp-serde"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db"
dependencies = [
"byteorder",
"rmp",
"serde",
]
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags",
"serde",
"serde_derive",
]
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[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.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
[[package]]
name = "smol_str"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
dependencies = [
"serde",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"portable-atomic",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "toml_datetime"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
[[package]]
name = "toml_edit"
version = "0.22.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
[[package]]
name = "typeid"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "uuid"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
"getrandom 0.3.3",
"js-sys",
"serde",
"wasm-bindgen",
]
[[package]]
name = "variadics_please"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "virtue"
version = "0.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "wgpu-types"
version = "24.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c"
dependencies = [
"bitflags",
"js-sys",
"log",
"serde",
"web-sys",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]

238
vendor/bevy_reflect/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,238 @@
# 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 = "2024"
rust-version = "1.85.0"
name = "bevy_reflect"
version = "0.16.1"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Dynamically interact with rust types"
homepage = "https://bevyengine.org"
readme = "README.md"
keywords = ["bevy"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/bevyengine/bevy"
resolver = "2"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"-Zunstable-options",
"--generate-link-to-definition",
]
[features]
critical-section = [
"bevy_platform/critical-section",
"bevy_utils/critical-section",
]
debug = ["debug_stack"]
debug_stack = ["std"]
default = [
"std",
"smallvec",
"debug",
]
documentation = ["bevy_reflect_derive/documentation"]
functions = ["bevy_reflect_derive/functions"]
glam = ["dep:glam"]
hashbrown = ["dep:hashbrown"]
petgraph = [
"dep:petgraph",
"std",
]
smallvec = ["dep:smallvec"]
std = [
"bevy_utils/std",
"erased-serde/std",
"downcast-rs/std",
"serde/std",
"glam?/std",
"smol_str?/std",
"uuid?/std",
"bevy_platform/std",
"wgpu-types?/std",
]
uuid = ["dep:uuid"]
web = [
"bevy_platform/web",
"uuid?/js",
]
wgpu-types = ["dep:wgpu-types"]
[lib]
name = "bevy_reflect"
path = "src/lib.rs"
[[example]]
name = "reflect_docs"
path = "examples/reflect_docs.rs"
required-features = ["documentation"]
[dependencies.assert_type_match]
version = "0.1.1"
[dependencies.bevy_platform]
version = "0.16.1"
features = [
"alloc",
"serialize",
]
default-features = false
[dependencies.bevy_ptr]
version = "0.16.1"
[dependencies.bevy_reflect_derive]
version = "0.16.1"
[dependencies.bevy_utils]
version = "0.16.1"
features = ["alloc"]
default-features = false
[dependencies.derive_more]
version = "1"
features = ["from"]
default-features = false
[dependencies.disqualified]
version = "1.0"
default-features = false
[dependencies.downcast-rs]
version = "2"
default-features = false
[dependencies.erased-serde]
version = "0.4"
features = ["alloc"]
default-features = false
[dependencies.foldhash]
version = "0.1.3"
default-features = false
[dependencies.glam]
version = "0.29.3"
features = ["serde"]
optional = true
default-features = false
[dependencies.hashbrown]
version = "0.15.1"
optional = true
default-features = false
[dependencies.petgraph]
version = "0.7"
features = ["serde-1"]
optional = true
[dependencies.serde]
version = "1"
features = ["alloc"]
default-features = false
[dependencies.smallvec]
version = "1.11"
optional = true
default-features = false
[dependencies.smol_str]
version = "0.2.0"
features = ["serde"]
optional = true
default-features = false
[dependencies.thiserror]
version = "2"
default-features = false
[dependencies.uuid]
version = "1.13.1"
features = [
"v4",
"serde",
]
optional = true
default-features = false
[dependencies.variadics_please]
version = "1.1"
[dependencies.wgpu-types]
version = "24"
features = ["serde"]
optional = true
default-features = false
[dev-dependencies.bincode]
version = "2.0"
features = ["serde"]
[dev-dependencies.rmp-serde]
version = "1.1"
[dev-dependencies.ron]
version = "0.8.0"
[dev-dependencies.serde]
version = "1"
features = ["derive"]
[dev-dependencies.serde_json]
version = "1.0.140"
[dev-dependencies.static_assertions]
version = "1.1.0"
[lints.clippy]
alloc_instead_of_core = "warn"
allow_attributes = "warn"
allow_attributes_without_reason = "warn"
doc_markdown = "warn"
manual_let_else = "warn"
match_same_arms = "warn"
needless_lifetimes = "allow"
nonstandard_macro_braces = "warn"
print_stderr = "warn"
print_stdout = "warn"
ptr_as_ptr = "warn"
ptr_cast_constness = "warn"
redundant_closure_for_method_calls = "warn"
redundant_else = "warn"
ref_as_ptr = "warn"
semicolon_if_nothing_returned = "warn"
std_instead_of_alloc = "warn"
std_instead_of_core = "warn"
too_long_first_doc_paragraph = "allow"
too_many_arguments = "allow"
type_complexity = "allow"
undocumented_unsafe_blocks = "warn"
unwrap_or_default = "warn"
[lints.rust]
missing_docs = "warn"
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "warn"
unused_qualifications = "warn"
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = ["cfg(docsrs_dep)"]

176
vendor/bevy_reflect/LICENSE-APACHE vendored Normal file
View File

@@ -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

19
vendor/bevy_reflect/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,19 @@
MIT License
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.

172
vendor/bevy_reflect/README.md vendored Normal file
View File

@@ -0,0 +1,172 @@
# Bevy Reflect
[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/bevyengine/bevy#license)
[![Crates.io](https://img.shields.io/crates/v/bevy.svg)](https://crates.io/crates/bevy_reflect)
[![Downloads](https://img.shields.io/crates/d/bevy_reflect.svg)](https://crates.io/crates/bevy_reflect)
[![Docs](https://docs.rs/bevy_reflect/badge.svg)](https://docs.rs/bevy_reflect/latest/bevy_reflect/)
[![Discord](https://img.shields.io/discord/691052431525675048.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/bevy)
This crate enables you to dynamically interact with Rust types:
* Derive the `Reflect` traits
* Interact with fields using their names (for named structs) or indices (for tuple structs)
* "Patch" your types with new values
* Look up nested fields using "path strings"
* Iterate over struct fields
* Automatically serialize and deserialize via Serde (without explicit serde impls)
* Trait "reflection"
## Features
### Derive the `Reflect` traits
```rust ignore
// this will automatically implement the `Reflect` trait and the `Struct` trait (because the type is a struct)
#[derive(Reflect)]
struct Foo {
a: u32,
b: Bar,
c: Vec<i32>,
d: Vec<Baz>,
}
// this will automatically implement the `Reflect` trait and the `TupleStruct` trait (because the type is a tuple struct)
#[derive(Reflect)]
struct Bar(String);
#[derive(Reflect)]
struct Baz {
value: f32,
}
// We will use this value to illustrate `bevy_reflect` features
let mut foo = Foo {
a: 1,
b: Bar("hello".to_string()),
c: vec![1, 2],
d: vec![Baz { value: 3.14 }],
};
```
### Interact with fields using their names
```rust ignore
assert_eq!(*foo.get_field::<u32>("a").unwrap(), 1);
*foo.get_field_mut::<u32>("a").unwrap() = 2;
assert_eq!(foo.a, 2);
```
### "Patch" your types with new values
```rust ignore
let mut dynamic_struct = DynamicStruct::default();
dynamic_struct.insert("a", 42u32);
dynamic_struct.insert("c", vec![3, 4, 5]);
foo.apply(&dynamic_struct);
assert_eq!(foo.a, 42);
assert_eq!(foo.c, vec![3, 4, 5]);
```
### Look up nested fields using "path strings"
```rust ignore
let value = *foo.get_path::<f32>("d[0].value").unwrap();
assert_eq!(value, 3.14);
```
### Iterate over struct fields
```rust ignore
for (i, value: &Reflect) in foo.iter_fields().enumerate() {
let field_name = foo.name_at(i).unwrap();
if let Some(value) = value.downcast_ref::<u32>() {
println!("{} is a u32 with the value: {}", field_name, *value);
}
}
```
### Automatically serialize and deserialize via Serde (without explicit serde impls)
```rust ignore
let mut registry = TypeRegistry::default();
registry.register::<u32>();
registry.register::<i32>();
registry.register::<f32>();
registry.register::<String>();
registry.register::<Bar>();
registry.register::<Baz>();
let serializer = ReflectSerializer::new(&foo, &registry);
let serialized = ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let dynamic_struct = value.take::<DynamicStruct>().unwrap();
assert!(foo.reflect_partial_eq(&dynamic_struct).unwrap());
```
### Trait "reflection"
Call a trait on a given `&dyn Reflect` reference without knowing the underlying type!
```rust ignore
#[derive(Reflect)]
#[reflect(DoThing)]
struct MyType {
value: String,
}
impl DoThing for MyType {
fn do_thing(&self) -> String {
format!("{} World!", self.value)
}
}
#[reflect_trait]
pub trait DoThing {
fn do_thing(&self) -> String;
}
// First, lets box our type as a Box<dyn Reflect>
let reflect_value: Box<dyn Reflect> = Box::new(MyType {
value: "Hello".to_string(),
});
// This means we no longer have direct access to MyType or its methods. We can only call Reflect methods on reflect_value.
// What if we want to call `do_thing` on our type? We could downcast using reflect_value.downcast_ref::<MyType>(), but what if we
// don't know the type at compile time?
// Normally in rust we would be out of luck at this point. Lets use our new reflection powers to do something cool!
let mut type_registry = TypeRegistry::default();
type_registry.register::<MyType>();
// The #[reflect] attribute we put on our DoThing trait generated a new `ReflectDoThing` struct, which implements TypeData.
// This was added to MyType's TypeRegistration.
let reflect_do_thing = type_registry
.get_type_data::<ReflectDoThing>(reflect_value.type_id())
.unwrap();
// We can use this generated type to convert our `&dyn Reflect` reference to a `&dyn DoThing` reference
let my_trait: &dyn DoThing = reflect_do_thing.get(&*reflect_value).unwrap();
// Which means we can now call do_thing(). Magic!
println!("{}", my_trait.do_thing());
// This works because the #[reflect(MyTrait)] we put on MyType informed the Reflect derive to insert a new instance
// of ReflectDoThing into MyType's registration. The instance knows how to cast &dyn Reflect to &dyn DoThing, because it
// knows that &dyn Reflect should first be downcasted to &MyType, which can then be safely casted to &dyn DoThing
```
## Why make this?
The whole point of Rust is static safety! Why build something that makes it easy to throw it all away?
* Some problems are inherently dynamic (scripting, some types of serialization / deserialization)
* Sometimes the dynamic way is easier
* Sometimes the dynamic way puts less burden on your users to derive a bunch of traits (this was a big motivator for the Bevy project)

View File

@@ -0,0 +1,52 @@
//! This example illustrates how you can reflect doc comments.
//!
//! There may be cases where you may want to collect a reflected item's documentation.
//! For example, you may want to generate schemas or other external documentation for scripting.
//! Or perhaps you want your custom editor to display tooltips for certain properties that match the documentation.
//!
//! These scenarios can readily be achieved by using `bevy_reflect` with the `documentation` feature.
#![expect(clippy::print_stdout, reason = "Allowed in examples.")]
use bevy_reflect::{Reflect, TypeInfo, Typed};
fn main() {
//! This function will simply demonstrate how you can access a type's documentation.
//!
//! Please note that the code below uses a standard struct with named fields; however, this isn't
//! exclusive to them. It can work for all kinds of data types including tuple structs and enums too!
/// The struct that defines our player.
///
/// # Example
///
/// ```
/// let player = Player::new("Urist McPlayer");
/// ```
#[derive(Reflect)]
struct Player {
/// The player's name.
name: String,
/// The player's current health points.
hp: u8,
// Some regular comment (i.e. not a doc comment)
max_hp: u8,
}
// Using `TypeInfo` we can access all of the doc comments on the `Player` struct above:
let player_info = <Player as Typed>::type_info();
// From here, we already have access to the struct's docs:
let player_docs = player_info.docs().unwrap();
assert_eq!(" The struct that defines our player.\n\n # Example\n\n ```\n let player = Player::new(\"Urist McPlayer\");\n ```", player_docs);
println!("=====[ Player ]=====\n{player_docs}");
// We can then iterate through our struct's fields to get their documentation as well:
if let TypeInfo::Struct(struct_info) = player_info {
for field in struct_info.iter() {
let field_name = field.name();
let field_docs = field.docs().unwrap_or("<NO_DOCUMENTATION>");
println!("-----[ Player::{field_name} ]-----\n{field_docs}");
}
}
}

525
vendor/bevy_reflect/src/array.rs vendored Normal file
View File

@@ -0,0 +1,525 @@
use crate::generics::impl_generic_info_methods;
use crate::{
type_info::impl_type_methods, utility::reflect_hasher, ApplyError, Generics, MaybeTyped,
PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo,
TypePath,
};
use alloc::{boxed::Box, vec::Vec};
use bevy_reflect_derive::impl_type_path;
use core::{
any::Any,
fmt::{Debug, Formatter},
hash::{Hash, Hasher},
};
/// A trait used to power [array-like] operations via [reflection].
///
/// This corresponds to true Rust arrays like `[T; N]`,
/// but also to any fixed-size linear sequence types.
/// It is expected that implementors of this trait uphold this contract
/// and maintain a fixed size as returned by the [`Array::len`] method.
///
/// Due to the [type-erasing] nature of the reflection API as a whole,
/// this trait does not make any guarantees that the implementor's elements
/// are homogeneous (i.e. all the same type).
///
/// This trait has a blanket implementation over Rust arrays of up to 32 items.
/// This implementation can technically contain more than 32,
/// but the blanket [`GetTypeRegistration`] is only implemented up to the 32
/// item limit due to a [limitation] on [`Deserialize`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Array};
///
/// let foo: &dyn Array = &[123_u32, 456_u32, 789_u32];
/// assert_eq!(foo.len(), 3);
///
/// let field: &dyn PartialReflect = foo.get(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
/// [reflection]: crate
/// [`List`]: crate::List
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
/// [`GetTypeRegistration`]: crate::GetTypeRegistration
/// [limitation]: https://github.com/serde-rs/serde/issues/1937
/// [`Deserialize`]: ::serde::Deserialize
pub trait Array: PartialReflect {
/// Returns a reference to the element at `index`, or `None` if out of bounds.
fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of elements in the array.
fn len(&self) -> usize;
/// Returns `true` if the collection contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the array.
fn iter(&self) -> ArrayIter;
/// Drain the elements of this array to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the list, producing a [`DynamicArray`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_array` instead")]
fn clone_dynamic(&self) -> DynamicArray {
self.to_dynamic_array()
}
/// Creates a new [`DynamicArray`] from this array.
fn to_dynamic_array(&self) -> DynamicArray {
DynamicArray {
represented_type: self.get_represented_type_info(),
values: self.iter().map(PartialReflect::to_dynamic).collect(),
}
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_array_info(&self) -> Option<&'static ArrayInfo> {
self.get_represented_type_info()?.as_array().ok()
}
}
/// A container for compile-time array info.
#[derive(Clone, Debug)]
pub struct ArrayInfo {
ty: Type,
generics: Generics,
item_info: fn() -> Option<&'static TypeInfo>,
item_ty: Type,
capacity: usize,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl ArrayInfo {
/// Create a new [`ArrayInfo`].
///
/// # Arguments
///
/// * `capacity`: The maximum capacity of the underlying array.
pub fn new<TArray: Array + TypePath, TItem: Reflect + MaybeTyped + TypePath>(
capacity: usize,
) -> Self {
Self {
ty: Type::of::<TArray>(),
generics: Generics::new(),
item_info: TItem::maybe_type_info,
item_ty: Type::of::<TItem>(),
capacity,
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this array.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// The compile-time capacity of the array.
pub fn capacity(&self) -> usize {
self.capacity
}
impl_type_methods!(ty);
/// The [`TypeInfo`] of the array item.
///
/// Returns `None` if the array item does not contain static type information,
/// such as for dynamic types.
pub fn item_info(&self) -> Option<&'static TypeInfo> {
(self.item_info)()
}
/// The [type] of the array item.
///
/// [type]: Type
pub fn item_ty(&self) -> Type {
self.item_ty
}
/// The docstring of this array, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// A fixed-size list of reflected values.
///
/// This differs from [`DynamicList`] in that the size of the [`DynamicArray`]
/// is constant, whereas a [`DynamicList`] can have items added and removed.
///
/// This isn't to say that a [`DynamicArray`] is immutable— its items
/// can be mutated— just that the _number_ of items cannot change.
///
/// [`DynamicList`]: crate::DynamicList
#[derive(Debug)]
pub struct DynamicArray {
pub(crate) represented_type: Option<&'static TypeInfo>,
pub(crate) values: Box<[Box<dyn PartialReflect>]>,
}
impl DynamicArray {
#[inline]
pub fn new(values: Box<[Box<dyn PartialReflect>]>) -> Self {
Self {
represented_type: None,
values,
}
}
/// Sets the [type] to be represented by this `DynamicArray`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Array`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Array(_)),
"expected TypeInfo::Array but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
}
impl PartialReflect for DynamicArray {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
array_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
array_try_apply(self, value)
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Array
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Array(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Array(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Array(self)
}
#[inline]
fn reflect_hash(&self) -> Option<u64> {
array_hash(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
array_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicArray(")?;
array_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl Array for DynamicArray {
#[inline]
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
self.values.get(index).map(|value| &**value)
}
#[inline]
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.values.get_mut(index).map(|value| &mut **value)
}
#[inline]
fn len(&self) -> usize {
self.values.len()
}
#[inline]
fn iter(&self) -> ArrayIter {
ArrayIter::new(self)
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.values.into_vec()
}
}
impl FromIterator<Box<dyn PartialReflect>> for DynamicArray {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect::<Vec<_>>().into_boxed_slice(),
}
}
}
impl<T: PartialReflect> FromIterator<T> for DynamicArray {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|value| Box::new(value).into_partial_reflect())
.collect()
}
}
impl IntoIterator for DynamicArray {
type Item = Box<dyn PartialReflect>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_vec().into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicArray {
type Item = &'a dyn PartialReflect;
type IntoIter = ArrayIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl_type_path!((in bevy_reflect) DynamicArray);
/// An iterator over an [`Array`].
pub struct ArrayIter<'a> {
array: &'a dyn Array,
index: usize,
}
impl ArrayIter<'_> {
/// Creates a new [`ArrayIter`].
#[inline]
pub const fn new(array: &dyn Array) -> ArrayIter {
ArrayIter { array, index: 0 }
}
}
impl<'a> Iterator for ArrayIter<'a> {
type Item = &'a dyn PartialReflect;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let value = self.array.get(self.index);
self.index += value.is_some() as usize;
value
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.array.len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for ArrayIter<'a> {}
/// Returns the `u64` hash of the given [array](Array).
#[inline]
pub fn array_hash<A: Array + ?Sized>(array: &A) -> Option<u64> {
let mut hasher = reflect_hasher();
Any::type_id(array).hash(&mut hasher);
array.len().hash(&mut hasher);
for value in array.iter() {
hasher.write_u64(value.reflect_hash()?);
}
Some(hasher.finish())
}
/// Applies the reflected [array](Array) data to the given [array](Array).
///
/// # Panics
///
/// * Panics if the two arrays have differing lengths.
/// * Panics if the reflected value is not a [valid array](ReflectRef::Array).
#[inline]
pub fn array_apply<A: Array + ?Sized>(array: &mut A, reflect: &dyn PartialReflect) {
if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
if array.len() != reflect_array.len() {
panic!("Attempted to apply different sized `Array` types.");
}
for (i, value) in reflect_array.iter().enumerate() {
let v = array.get_mut(i).unwrap();
v.apply(value);
}
} else {
panic!("Attempted to apply a non-`Array` type to an `Array` type.");
}
}
/// Tries to apply the reflected [array](Array) data to the given [array](Array) and
/// returns a Result.
///
/// # Errors
///
/// * Returns an [`ApplyError::DifferentSize`] if the two arrays have differing lengths.
/// * Returns an [`ApplyError::MismatchedKinds`] if the reflected value is not a
/// [valid array](ReflectRef::Array).
/// * Returns any error that is generated while applying elements to each other.
#[inline]
pub fn array_try_apply<A: Array>(
array: &mut A,
reflect: &dyn PartialReflect,
) -> Result<(), ApplyError> {
let reflect_array = reflect.reflect_ref().as_array()?;
if array.len() != reflect_array.len() {
return Err(ApplyError::DifferentSize {
from_size: reflect_array.len(),
to_size: array.len(),
});
}
for (i, value) in reflect_array.iter().enumerate() {
let v = array.get_mut(i).unwrap();
v.try_apply(value)?;
}
Ok(())
}
/// Compares two [arrays](Array) (one concrete and one reflected) to see if they
/// are equal.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn array_partial_eq<A: Array + ?Sized>(
array: &A,
reflect: &dyn PartialReflect,
) -> Option<bool> {
match reflect.reflect_ref() {
ReflectRef::Array(reflect_array) if reflect_array.len() == array.len() => {
for (a, b) in array.iter().zip(reflect_array.iter()) {
let eq_result = a.reflect_partial_eq(b);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}
}
_ => return Some(false),
}
Some(true)
}
/// The default debug formatter for [`Array`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
///
/// let my_array: &dyn Reflect = &[1, 2, 3];
/// println!("{:#?}", my_array);
///
/// // Output:
///
/// // [
/// // 1,
/// // 2,
/// // 3,
/// // ]
/// ```
#[inline]
pub fn array_debug(dyn_array: &dyn Array, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_list();
for item in dyn_array.iter() {
debug.entry(&item as &dyn Debug);
}
debug.finish()
}
#[cfg(test)]
mod tests {
use crate::Reflect;
use alloc::boxed::Box;
#[test]
fn next_index_increment() {
const SIZE: usize = if cfg!(debug_assertions) {
4
} else {
// If compiled in release mode, verify we dont overflow
usize::MAX
};
let b = Box::new([(); SIZE]).into_reflect();
let array = b.reflect_ref().as_array().unwrap();
let mut iter = array.iter();
iter.index = SIZE - 1;
assert!(iter.next().is_some());
// When None we should no longer increase index
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
}
}

446
vendor/bevy_reflect/src/attributes.rs vendored Normal file
View File

@@ -0,0 +1,446 @@
use crate::Reflect;
use alloc::boxed::Box;
use bevy_utils::TypeIdMap;
use core::{
any::TypeId,
fmt::{Debug, Formatter},
};
/// A collection of custom attributes for a type, field, or variant.
///
/// These attributes can be created with the [`Reflect` derive macro].
///
/// Attributes are stored by their [`TypeId`].
/// Because of this, there can only be one attribute per type.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{Reflect, Typed, TypeInfo};
/// use core::ops::RangeInclusive;
/// #[derive(Reflect)]
/// struct Slider {
/// #[reflect(@RangeInclusive::<f32>::new(0.0, 1.0))]
/// value: f32
/// }
///
/// let TypeInfo::Struct(info) = <Slider as Typed>::type_info() else {
/// panic!("expected struct info");
/// };
///
/// let range = info.field("value").unwrap().get_attribute::<RangeInclusive<f32>>().unwrap();
/// assert_eq!(0.0..=1.0, *range);
/// ```
///
/// [`Reflect` derive macro]: derive@crate::Reflect
#[derive(Default)]
pub struct CustomAttributes {
attributes: TypeIdMap<CustomAttribute>,
}
impl CustomAttributes {
/// Inserts a custom attribute into the collection.
///
/// Note that this will overwrite any existing attribute of the same type.
pub fn with_attribute<T: Reflect>(mut self, value: T) -> Self {
self.attributes
.insert(TypeId::of::<T>(), CustomAttribute::new(value));
self
}
/// Returns `true` if this collection contains a custom attribute of the specified type.
pub fn contains<T: Reflect>(&self) -> bool {
self.attributes.contains_key(&TypeId::of::<T>())
}
/// Returns `true` if this collection contains a custom attribute with the specified [`TypeId`].
pub fn contains_by_id(&self, id: TypeId) -> bool {
self.attributes.contains_key(&id)
}
/// Gets a custom attribute by type.
pub fn get<T: Reflect>(&self) -> Option<&T> {
self.attributes.get(&TypeId::of::<T>())?.value::<T>()
}
/// Gets a custom attribute by its [`TypeId`].
pub fn get_by_id(&self, id: TypeId) -> Option<&dyn Reflect> {
Some(self.attributes.get(&id)?.reflect_value())
}
/// Returns an iterator over all custom attributes.
pub fn iter(&self) -> impl ExactSizeIterator<Item = (&TypeId, &dyn Reflect)> {
self.attributes
.iter()
.map(|(key, value)| (key, value.reflect_value()))
}
/// Returns the number of custom attributes in this collection.
pub fn len(&self) -> usize {
self.attributes.len()
}
/// Returns `true` if this collection is empty.
pub fn is_empty(&self) -> bool {
self.attributes.is_empty()
}
}
impl Debug for CustomAttributes {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_set().entries(self.attributes.values()).finish()
}
}
struct CustomAttribute {
value: Box<dyn Reflect>,
}
impl CustomAttribute {
pub fn new<T: Reflect>(value: T) -> Self {
Self {
value: Box::new(value),
}
}
pub fn value<T: Reflect>(&self) -> Option<&T> {
self.value.downcast_ref()
}
pub fn reflect_value(&self) -> &dyn Reflect {
&*self.value
}
}
impl Debug for CustomAttribute {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.value.debug(f)
}
}
/// Implements methods for accessing custom attributes.
///
/// Implements the following methods:
///
/// * `fn custom_attributes(&self) -> &CustomAttributes`
/// * `fn get_attribute<T: Reflect>(&self) -> Option<&T>`
/// * `fn get_attribute_by_id(&self, id: TypeId) -> Option<&dyn Reflect>`
/// * `fn has_attribute<T: Reflect>(&self) -> bool`
/// * `fn has_attribute_by_id(&self, id: TypeId) -> bool`
///
/// # Params
///
/// * `$self` - The name of the variable containing the custom attributes (usually `self`).
/// * `$attributes` - The name of the field containing the [`CustomAttributes`].
/// * `$term` - (Optional) The term used to describe the type containing the custom attributes.
/// This is purely used to generate better documentation. Defaults to `"item"`.
macro_rules! impl_custom_attribute_methods {
($self:ident . $attributes:ident, $term:literal) => {
$crate::attributes::impl_custom_attribute_methods!($self, &$self.$attributes, "item");
};
($self:ident, $attributes:expr, $term:literal) => {
#[doc = concat!("Returns the custom attributes for this ", $term, ".")]
pub fn custom_attributes(&$self) -> &$crate::attributes::CustomAttributes {
$attributes
}
/// Gets a custom attribute by type.
///
/// For dynamically accessing an attribute, see [`get_attribute_by_id`](Self::get_attribute_by_id).
pub fn get_attribute<T: $crate::Reflect>(&$self) -> Option<&T> {
$self.custom_attributes().get::<T>()
}
/// Gets a custom attribute by its [`TypeId`](core::any::TypeId).
///
/// This is the dynamic equivalent of [`get_attribute`](Self::get_attribute).
pub fn get_attribute_by_id(&$self, id: ::core::any::TypeId) -> Option<&dyn $crate::Reflect> {
$self.custom_attributes().get_by_id(id)
}
#[doc = concat!("Returns `true` if this ", $term, " has a custom attribute of the specified type.")]
#[doc = "\n\nFor dynamically checking if an attribute exists, see [`has_attribute_by_id`](Self::has_attribute_by_id)."]
pub fn has_attribute<T: $crate::Reflect>(&$self) -> bool {
$self.custom_attributes().contains::<T>()
}
#[doc = concat!("Returns `true` if this ", $term, " has a custom attribute with the specified [`TypeId`](::core::any::TypeId).")]
#[doc = "\n\nThis is the dynamic equivalent of [`has_attribute`](Self::has_attribute)"]
pub fn has_attribute_by_id(&$self, id: ::core::any::TypeId) -> bool {
$self.custom_attributes().contains_by_id(id)
}
};
}
pub(crate) use impl_custom_attribute_methods;
#[cfg(test)]
mod tests {
use super::*;
use crate::{type_info::Typed, TypeInfo, VariantInfo};
use alloc::{format, string::String};
use core::ops::RangeInclusive;
#[derive(Reflect, PartialEq, Debug)]
struct Tooltip(String);
impl Tooltip {
fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
}
#[test]
fn should_get_custom_attribute() {
let attributes = CustomAttributes::default().with_attribute(0.0..=1.0);
let value = attributes.get::<RangeInclusive<f64>>().unwrap();
assert_eq!(&(0.0..=1.0), value);
}
#[test]
fn should_get_custom_attribute_dynamically() {
let attributes = CustomAttributes::default().with_attribute(String::from("Hello, World!"));
let value = attributes.get_by_id(TypeId::of::<String>()).unwrap();
assert!(value
.reflect_partial_eq(&String::from("Hello, World!"))
.unwrap());
}
#[test]
fn should_debug_custom_attributes() {
let attributes = CustomAttributes::default().with_attribute("My awesome custom attribute!");
let debug = format!("{:?}", attributes);
assert_eq!(r#"{"My awesome custom attribute!"}"#, debug);
#[derive(Reflect)]
struct Foo {
value: i32,
}
let attributes = CustomAttributes::default().with_attribute(Foo { value: 42 });
let debug = format!("{:?}", attributes);
assert_eq!(
r#"{bevy_reflect::attributes::tests::Foo { value: 42 }}"#,
debug
);
}
#[test]
fn should_derive_custom_attributes_on_struct_container() {
#[derive(Reflect)]
#[reflect(@Tooltip::new("My awesome custom attribute!"))]
struct Slider {
value: f32,
}
let TypeInfo::Struct(info) = Slider::type_info() else {
panic!("expected struct info");
};
let tooltip = info.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("My awesome custom attribute!"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_struct_fields() {
#[derive(Reflect)]
struct Slider {
#[reflect(@0.0..=1.0)]
#[reflect(@Tooltip::new("Range: 0.0 to 1.0"))]
value: f32,
}
let TypeInfo::Struct(info) = Slider::type_info() else {
panic!("expected struct info");
};
let field = info.field("value").unwrap();
let range = field.get_attribute::<RangeInclusive<f64>>().unwrap();
assert_eq!(&(0.0..=1.0), range);
let tooltip = field.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("Range: 0.0 to 1.0"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_tuple_container() {
#[derive(Reflect)]
#[reflect(@Tooltip::new("My awesome custom attribute!"))]
struct Slider(f32);
let TypeInfo::TupleStruct(info) = Slider::type_info() else {
panic!("expected tuple struct info");
};
let tooltip = info.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("My awesome custom attribute!"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_tuple_struct_fields() {
#[derive(Reflect)]
struct Slider(
#[reflect(@0.0..=1.0)]
#[reflect(@Tooltip::new("Range: 0.0 to 1.0"))]
f32,
);
let TypeInfo::TupleStruct(info) = Slider::type_info() else {
panic!("expected tuple struct info");
};
let field = info.field_at(0).unwrap();
let range = field.get_attribute::<RangeInclusive<f64>>().unwrap();
assert_eq!(&(0.0..=1.0), range);
let tooltip = field.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("Range: 0.0 to 1.0"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_enum_container() {
#[derive(Reflect)]
#[reflect(@Tooltip::new("My awesome custom attribute!"))]
enum Color {
Transparent,
Grayscale(f32),
Rgb { r: u8, g: u8, b: u8 },
}
let TypeInfo::Enum(info) = Color::type_info() else {
panic!("expected enum info");
};
let tooltip = info.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("My awesome custom attribute!"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_enum_variants() {
#[derive(Reflect, Debug, PartialEq)]
enum Display {
Toggle,
Slider,
Picker,
}
#[derive(Reflect)]
enum Color {
#[reflect(@Display::Toggle)]
Transparent,
#[reflect(@Display::Slider)]
Grayscale(f32),
#[reflect(@Display::Picker)]
Rgb { r: u8, g: u8, b: u8 },
}
let TypeInfo::Enum(info) = Color::type_info() else {
panic!("expected enum info");
};
let VariantInfo::Unit(transparent_variant) = info.variant("Transparent").unwrap() else {
panic!("expected unit variant");
};
let display = transparent_variant.get_attribute::<Display>().unwrap();
assert_eq!(&Display::Toggle, display);
let VariantInfo::Tuple(grayscale_variant) = info.variant("Grayscale").unwrap() else {
panic!("expected tuple variant");
};
let display = grayscale_variant.get_attribute::<Display>().unwrap();
assert_eq!(&Display::Slider, display);
let VariantInfo::Struct(rgb_variant) = info.variant("Rgb").unwrap() else {
panic!("expected struct variant");
};
let display = rgb_variant.get_attribute::<Display>().unwrap();
assert_eq!(&Display::Picker, display);
}
#[test]
fn should_derive_custom_attributes_on_enum_variant_fields() {
#[derive(Reflect)]
enum Color {
Transparent,
Grayscale(#[reflect(@0.0..=1.0_f32)] f32),
Rgb {
#[reflect(@0..=255u8)]
r: u8,
#[reflect(@0..=255u8)]
g: u8,
#[reflect(@0..=255u8)]
b: u8,
},
}
let TypeInfo::Enum(info) = Color::type_info() else {
panic!("expected enum info");
};
let VariantInfo::Tuple(grayscale_variant) = info.variant("Grayscale").unwrap() else {
panic!("expected tuple variant");
};
let field = grayscale_variant.field_at(0).unwrap();
let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();
assert_eq!(&(0.0..=1.0), range);
let VariantInfo::Struct(rgb_variant) = info.variant("Rgb").unwrap() else {
panic!("expected struct variant");
};
let field = rgb_variant.field("g").unwrap();
let range = field.get_attribute::<RangeInclusive<u8>>().unwrap();
assert_eq!(&(0..=255), range);
}
#[test]
fn should_allow_unit_struct_attribute_values() {
#[derive(Reflect)]
struct Required;
#[derive(Reflect)]
struct Foo {
#[reflect(@Required)]
value: i32,
}
let TypeInfo::Struct(info) = Foo::type_info() else {
panic!("expected struct info");
};
let field = info.field("value").unwrap();
assert!(field.has_attribute::<Required>());
}
#[test]
fn should_accept_last_attribute() {
#[derive(Reflect)]
struct Foo {
#[reflect(@false)]
#[reflect(@true)]
value: i32,
}
let TypeInfo::Struct(info) = Foo::type_info() else {
panic!("expected struct info");
};
let field = info.field("value").unwrap();
assert!(field.get_attribute::<bool>().unwrap());
}
}

View File

@@ -0,0 +1,419 @@
use bevy_reflect_derive::impl_type_path;
use crate::{
enum_debug, enum_hash, enum_partial_eq, ApplyError, DynamicStruct, DynamicTuple, Enum,
PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple,
TypeInfo, VariantFieldIter, VariantType,
};
use alloc::{boxed::Box, string::String};
use core::fmt::Formatter;
use derive_more::derive::From;
/// A dynamic representation of an enum variant.
#[derive(Debug, Default, From)]
pub enum DynamicVariant {
#[default]
Unit,
Tuple(DynamicTuple),
Struct(DynamicStruct),
}
impl Clone for DynamicVariant {
fn clone(&self) -> Self {
match self {
DynamicVariant::Unit => DynamicVariant::Unit,
DynamicVariant::Tuple(data) => DynamicVariant::Tuple(data.to_dynamic_tuple()),
DynamicVariant::Struct(data) => DynamicVariant::Struct(data.to_dynamic_struct()),
}
}
}
impl From<()> for DynamicVariant {
fn from(_: ()) -> Self {
Self::Unit
}
}
/// A dynamic representation of an enum.
///
/// This allows for enums to be configured at runtime.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{DynamicEnum, DynamicVariant, Reflect, PartialReflect};
///
/// // The original enum value
/// let mut value: Option<usize> = Some(123);
///
/// // Create a DynamicEnum to represent the new value
/// let mut dyn_enum = DynamicEnum::new(
/// "None",
/// DynamicVariant::Unit
/// );
///
/// // Apply the DynamicEnum as a patch to the original value
/// value.apply(dyn_enum.as_partial_reflect());
///
/// // Tada!
/// assert_eq!(None, value);
/// ```
#[derive(Default, Debug)]
pub struct DynamicEnum {
represented_type: Option<&'static TypeInfo>,
variant_name: String,
variant_index: usize,
variant: DynamicVariant,
}
impl DynamicEnum {
/// Create a new [`DynamicEnum`] to represent an enum at runtime.
///
/// # Arguments
///
/// * `variant_name`: The name of the variant to set
/// * `variant`: The variant data
pub fn new<I: Into<String>, V: Into<DynamicVariant>>(variant_name: I, variant: V) -> Self {
Self {
represented_type: None,
variant_index: 0,
variant_name: variant_name.into(),
variant: variant.into(),
}
}
/// Create a new [`DynamicEnum`] with a variant index to represent an enum at runtime.
///
/// # Arguments
///
/// * `variant_index`: The index of the variant to set
/// * `variant_name`: The name of the variant to set
/// * `variant`: The variant data
pub fn new_with_index<I: Into<String>, V: Into<DynamicVariant>>(
variant_index: usize,
variant_name: I,
variant: V,
) -> Self {
Self {
represented_type: None,
variant_index,
variant_name: variant_name.into(),
variant: variant.into(),
}
}
/// Sets the [type] to be represented by this `DynamicEnum`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Enum`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Enum(_)),
"expected TypeInfo::Enum but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Set the current enum variant represented by this struct.
pub fn set_variant<I: Into<String>, V: Into<DynamicVariant>>(&mut self, name: I, variant: V) {
self.variant_name = name.into();
self.variant = variant.into();
}
/// Set the current enum variant represented by this struct along with its variant index.
pub fn set_variant_with_index<I: Into<String>, V: Into<DynamicVariant>>(
&mut self,
variant_index: usize,
variant_name: I,
variant: V,
) {
self.variant_index = variant_index;
self.variant_name = variant_name.into();
self.variant = variant.into();
}
/// Get a reference to the [`DynamicVariant`] contained in `self`.
pub fn variant(&self) -> &DynamicVariant {
&self.variant
}
/// Get a mutable reference to the [`DynamicVariant`] contained in `self`.
///
/// Using the mut reference to switch to a different variant will ___not___ update the
/// internal tracking of the variant name and index.
///
/// If you want to switch variants, prefer one of the setters:
/// [`DynamicEnum::set_variant`] or [`DynamicEnum::set_variant_with_index`].
pub fn variant_mut(&mut self) -> &mut DynamicVariant {
&mut self.variant
}
/// Create a [`DynamicEnum`] from an existing one.
///
/// This is functionally the same as [`DynamicEnum::from_ref`] except it takes an owned value.
pub fn from<TEnum: Enum>(value: TEnum) -> Self {
Self::from_ref(&value)
}
/// Create a [`DynamicEnum`] from an existing one.
///
/// This is functionally the same as [`DynamicEnum::from`] except it takes a reference.
pub fn from_ref<TEnum: Enum + ?Sized>(value: &TEnum) -> Self {
let type_info = value.get_represented_type_info();
let mut dyn_enum = match value.variant_type() {
VariantType::Unit => DynamicEnum::new_with_index(
value.variant_index(),
value.variant_name(),
DynamicVariant::Unit,
),
VariantType::Tuple => {
let mut data = DynamicTuple::default();
for field in value.iter_fields() {
data.insert_boxed(field.value().to_dynamic());
}
DynamicEnum::new_with_index(
value.variant_index(),
value.variant_name(),
DynamicVariant::Tuple(data),
)
}
VariantType::Struct => {
let mut data = DynamicStruct::default();
for field in value.iter_fields() {
let name = field.name().unwrap();
data.insert_boxed(name, field.value().to_dynamic());
}
DynamicEnum::new_with_index(
value.variant_index(),
value.variant_name(),
DynamicVariant::Struct(data),
)
}
};
dyn_enum.set_represented_type(type_info);
dyn_enum
}
}
impl Enum for DynamicEnum {
fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
if let DynamicVariant::Struct(data) = &self.variant {
data.field(name)
} else {
None
}
}
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
if let DynamicVariant::Tuple(data) = &self.variant {
data.field(index)
} else {
None
}
}
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
if let DynamicVariant::Struct(data) = &mut self.variant {
data.field_mut(name)
} else {
None
}
}
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
if let DynamicVariant::Tuple(data) = &mut self.variant {
data.field_mut(index)
} else {
None
}
}
fn index_of(&self, name: &str) -> Option<usize> {
if let DynamicVariant::Struct(data) = &self.variant {
data.index_of(name)
} else {
None
}
}
fn name_at(&self, index: usize) -> Option<&str> {
if let DynamicVariant::Struct(data) = &self.variant {
data.name_at(index)
} else {
None
}
}
fn iter_fields(&self) -> VariantFieldIter {
VariantFieldIter::new(self)
}
fn field_len(&self) -> usize {
match &self.variant {
DynamicVariant::Unit => 0,
DynamicVariant::Tuple(data) => data.field_len(),
DynamicVariant::Struct(data) => data.field_len(),
}
}
fn variant_name(&self) -> &str {
&self.variant_name
}
fn variant_index(&self) -> usize {
self.variant_index
}
fn variant_type(&self) -> VariantType {
match &self.variant {
DynamicVariant::Unit => VariantType::Unit,
DynamicVariant::Tuple(..) => VariantType::Tuple,
DynamicVariant::Struct(..) => VariantType::Struct,
}
}
fn clone_dynamic(&self) -> DynamicEnum {
Self {
represented_type: self.represented_type,
variant_index: self.variant_index,
variant_name: self.variant_name.clone(),
variant: self.variant.clone(),
}
}
}
impl PartialReflect for DynamicEnum {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
#[inline]
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
let value = value.reflect_ref().as_enum()?;
if Enum::variant_name(self) == value.variant_name() {
// Same variant -> just update fields
match value.variant_type() {
VariantType::Struct => {
for field in value.iter_fields() {
let name = field.name().unwrap();
if let Some(v) = Enum::field_mut(self, name) {
v.try_apply(field.value())?;
}
}
}
VariantType::Tuple => {
for (index, field) in value.iter_fields().enumerate() {
if let Some(v) = Enum::field_at_mut(self, index) {
v.try_apply(field.value())?;
}
}
}
_ => {}
}
} else {
// New variant -> perform a switch
let dyn_variant = match value.variant_type() {
VariantType::Unit => DynamicVariant::Unit,
VariantType::Tuple => {
let mut dyn_tuple = DynamicTuple::default();
for field in value.iter_fields() {
dyn_tuple.insert_boxed(field.value().to_dynamic());
}
DynamicVariant::Tuple(dyn_tuple)
}
VariantType::Struct => {
let mut dyn_struct = DynamicStruct::default();
for field in value.iter_fields() {
dyn_struct.insert_boxed(field.name().unwrap(), field.value().to_dynamic());
}
DynamicVariant::Struct(dyn_struct)
}
};
self.set_variant(value.variant_name(), dyn_variant);
}
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Enum
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Enum(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Enum(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Enum(self)
}
#[inline]
fn reflect_hash(&self) -> Option<u64> {
enum_hash(self)
}
#[inline]
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
enum_partial_eq(self, value)
}
#[inline]
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicEnum(")?;
enum_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicEnum);

View File

@@ -0,0 +1,376 @@
use crate::generics::impl_generic_info_methods;
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
type_info::impl_type_methods,
DynamicEnum, Generics, PartialReflect, Type, TypePath, VariantInfo, VariantType,
};
use alloc::{boxed::Box, format, string::String};
use bevy_platform::collections::HashMap;
use bevy_platform::sync::Arc;
use core::slice::Iter;
/// A trait used to power [enum-like] operations via [reflection].
///
/// This allows enums to be processed and modified dynamically at runtime without
/// necessarily knowing the actual type.
/// Enums are much more complex than their struct counterparts.
/// As a result, users will need to be mindful of conventions, considerations,
/// and complications when working with this trait.
///
/// # Variants
///
/// An enum is a set of choices called _variants_.
/// An instance of an enum can only exist as one of these choices at any given time.
/// Consider Rust's [`Option<T>`]. It's an enum with two variants: [`None`] and [`Some`].
/// If you're `None`, you can't be `Some` and vice versa.
///
/// > ⚠️ __This is very important:__
/// > The [`Enum`] trait represents an enum _as one of its variants_.
/// > It does not represent the entire enum since that's not true to how enums work.
///
/// Variants come in a few [flavors](VariantType):
///
/// | Variant Type | Syntax |
/// | ------------ | ------------------------------ |
/// | Unit | `MyEnum::Foo` |
/// | Tuple | `MyEnum::Foo( i32, i32 )` |
/// | Struct | `MyEnum::Foo{ value: String }` |
///
/// As you can see, a unit variant contains no fields, while tuple and struct variants
/// can contain one or more fields.
/// The fields in a tuple variant is defined by their _order_ within the variant.
/// Index `0` represents the first field in the variant and so on.
/// Fields in struct variants (excluding tuple structs), on the other hand, are
/// represented by a _name_.
///
/// # Implementation
///
/// > 💡 This trait can be automatically implemented using [`#[derive(Reflect)]`](derive@crate::Reflect)
/// > on an enum definition.
///
/// Despite the fact that enums can represent multiple states, traits only exist in one state
/// and must be applied to the entire enum rather than a particular variant.
/// Because of this limitation, the [`Enum`] trait must not only _represent_ any of the
/// three variant types, but also define the _methods_ for all three as well.
///
/// What does this mean? It means that even though a unit variant contains no fields, a
/// representation of that variant using the [`Enum`] trait will still contain methods for
/// accessing fields!
/// Again, this is to account for _all three_ variant types.
///
/// We recommend using the built-in [`#[derive(Reflect)]`](derive@crate::Reflect) macro to automatically handle all the
/// implementation details for you.
/// However, if you _must_ implement this trait manually, there are a few things to keep in mind...
///
/// ## Field Order
///
/// While tuple variants identify their fields by the order in which they are defined, struct
/// variants identify fields by their name.
/// However, both should allow access to fields by their defined order.
///
/// The reason all fields, regardless of variant type, need to be accessible by their order is
/// due to field iteration.
/// We need a way to iterate through each field in a variant, and the easiest way of achieving
/// that is through the use of field order.
///
/// The derive macro adds proper struct variant handling for [`Enum::index_of`], [`Enum::name_at`]
/// and [`Enum::field_at[_mut]`](Enum::field_at) methods.
/// The first two methods are __required__ for all struct variant types.
/// By convention, implementors should also handle the last method as well, but this is not
/// a strict requirement.
///
/// ## Field Names
///
/// Implementors may choose to handle [`Enum::index_of`], [`Enum::name_at`], and
/// [`Enum::field[_mut]`](Enum::field) for tuple variants by considering stringified `usize`s to be
/// valid names (such as `"3"`).
/// This isn't wrong to do, but the convention set by the derive macro is that it isn't supported.
/// It's preferred that these strings be converted to their proper `usize` representations and
/// the [`Enum::field_at[_mut]`](Enum::field_at) methods be used instead.
///
/// [enum-like]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
/// [reflection]: crate
/// [`None`]: Option<T>::None
/// [`Some`]: Option<T>::Some
/// [`Reflect`]: bevy_reflect_derive::Reflect
pub trait Enum: PartialReflect {
/// Returns a reference to the value of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
/// Returns a reference to the value of the field (in the current variant) at the given index.
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
/// Returns a mutable reference to the value of the field (in the current variant) at the given index.
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the index of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn index_of(&self, name: &str) -> Option<usize>;
/// Returns the name of the field (in the current variant) with the given index.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn name_at(&self, index: usize) -> Option<&str>;
/// Returns an iterator over the values of the current variant's fields.
fn iter_fields(&self) -> VariantFieldIter;
/// Returns the number of fields in the current variant.
fn field_len(&self) -> usize;
/// The name of the current variant.
fn variant_name(&self) -> &str;
/// The index of the current variant.
fn variant_index(&self) -> usize;
/// The type of the current variant.
fn variant_type(&self) -> VariantType;
// Clones the enum into a [`DynamicEnum`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_enum` instead")]
fn clone_dynamic(&self) -> DynamicEnum {
self.to_dynamic_enum()
}
/// Creates a new [`DynamicEnum`] from this enum.
fn to_dynamic_enum(&self) -> DynamicEnum {
DynamicEnum::from_ref(self)
}
/// Returns true if the current variant's type matches the given one.
fn is_variant(&self, variant_type: VariantType) -> bool {
self.variant_type() == variant_type
}
/// Returns the full path to the current variant.
fn variant_path(&self) -> String {
format!("{}::{}", self.reflect_type_path(), self.variant_name())
}
/// Will return `None` if [`TypeInfo`] is not available.
///
/// [`TypeInfo`]: crate::TypeInfo
fn get_represented_enum_info(&self) -> Option<&'static EnumInfo> {
self.get_represented_type_info()?.as_enum().ok()
}
}
/// A container for compile-time enum info, used by [`TypeInfo`](crate::TypeInfo).
#[derive(Clone, Debug)]
pub struct EnumInfo {
ty: Type,
generics: Generics,
variants: Box<[VariantInfo]>,
variant_names: Box<[&'static str]>,
variant_indices: HashMap<&'static str, usize>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl EnumInfo {
/// Create a new [`EnumInfo`].
///
/// # Arguments
///
/// * `variants`: The variants of this enum in the order they are defined
pub fn new<TEnum: Enum + TypePath>(variants: &[VariantInfo]) -> Self {
let variant_indices = variants
.iter()
.enumerate()
.map(|(index, variant)| (variant.name(), index))
.collect::<HashMap<_, _>>();
let variant_names = variants.iter().map(VariantInfo::name).collect();
Self {
ty: Type::of::<TEnum>(),
generics: Generics::new(),
variants: variants.to_vec().into_boxed_slice(),
variant_names,
variant_indices,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this enum.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this enum.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// A slice containing the names of all variants in order.
pub fn variant_names(&self) -> &[&'static str] {
&self.variant_names
}
/// Get a variant with the given name.
pub fn variant(&self, name: &str) -> Option<&VariantInfo> {
self.variant_indices
.get(name)
.map(|index| &self.variants[*index])
}
/// Get a variant at the given index.
pub fn variant_at(&self, index: usize) -> Option<&VariantInfo> {
self.variants.get(index)
}
/// Get the index of the variant with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.variant_indices.get(name).copied()
}
/// Returns the full path to the given variant.
///
/// This does _not_ check if the given variant exists.
pub fn variant_path(&self, name: &str) -> String {
format!("{}::{name}", self.type_path())
}
/// Checks if a variant with the given name exists within this enum.
pub fn contains_variant(&self, name: &str) -> bool {
self.variant_indices.contains_key(name)
}
/// Iterate over the variants of this enum.
pub fn iter(&self) -> Iter<'_, VariantInfo> {
self.variants.iter()
}
/// The number of variants in this enum.
pub fn variant_len(&self) -> usize {
self.variants.len()
}
impl_type_methods!(ty);
/// The docstring of this enum, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "enum");
impl_generic_info_methods!(generics);
}
/// An iterator over the fields in the current enum variant.
pub struct VariantFieldIter<'a> {
container: &'a dyn Enum,
index: usize,
}
impl<'a> VariantFieldIter<'a> {
pub fn new(container: &'a dyn Enum) -> Self {
Self {
container,
index: 0,
}
}
}
impl<'a> Iterator for VariantFieldIter<'a> {
type Item = VariantField<'a>;
fn next(&mut self) -> Option<Self::Item> {
let value = match self.container.variant_type() {
VariantType::Unit => None,
VariantType::Tuple => Some(VariantField::Tuple(self.container.field_at(self.index)?)),
VariantType::Struct => {
let name = self.container.name_at(self.index)?;
Some(VariantField::Struct(name, self.container.field(name)?))
}
};
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.container.field_len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for VariantFieldIter<'a> {}
pub enum VariantField<'a> {
Struct(&'a str, &'a dyn PartialReflect),
Tuple(&'a dyn PartialReflect),
}
impl<'a> VariantField<'a> {
pub fn name(&self) -> Option<&'a str> {
if let Self::Struct(name, ..) = self {
Some(*name)
} else {
None
}
}
pub fn value(&self) -> &'a dyn PartialReflect {
match *self {
Self::Struct(_, value) | Self::Tuple(value) => value,
}
}
}
// Tests that need access to internal fields have to go here rather than in mod.rs
#[cfg(test)]
mod tests {
use crate::*;
#[derive(Reflect, Debug, PartialEq)]
enum MyEnum {
A,
B(usize, i32),
C { foo: f32, bar: bool },
}
#[test]
fn next_index_increment() {
// unit enums always return none, so index should stay at 0
let unit_enum = MyEnum::A;
let mut iter = unit_enum.iter_fields();
let size = iter.len();
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
// tuple enums we iter over each value (unnamed fields), stop after that
let tuple_enum = MyEnum::B(0, 1);
let mut iter = tuple_enum.iter_fields();
let size = iter.len();
for _ in 0..2 {
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
}
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
// struct enums, we iterate over each field in the struct
let struct_enum = MyEnum::C {
foo: 0.,
bar: false,
};
let mut iter = struct_enum.iter_fields();
let size = iter.len();
for _ in 0..2 {
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
}
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
}
}

121
vendor/bevy_reflect/src/enums/helpers.rs vendored Normal file
View File

@@ -0,0 +1,121 @@
use crate::{utility::reflect_hasher, Enum, PartialReflect, ReflectRef, VariantType};
use core::{
fmt::Debug,
hash::{Hash, Hasher},
};
/// Returns the `u64` hash of the given [enum](Enum).
#[inline]
pub fn enum_hash<TEnum: Enum>(value: &TEnum) -> Option<u64> {
let mut hasher = reflect_hasher();
core::any::Any::type_id(value).hash(&mut hasher);
value.variant_name().hash(&mut hasher);
value.variant_type().hash(&mut hasher);
for field in value.iter_fields() {
hasher.write_u64(field.value().reflect_hash()?);
}
Some(hasher.finish())
}
/// Compares an [`Enum`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is an enum;
/// - `b` is the same variant as `a`;
/// - For each field in `a`, `b` contains a field with the same name and
/// [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
#[inline]
pub fn enum_partial_eq<TEnum: Enum + ?Sized>(a: &TEnum, b: &dyn PartialReflect) -> Option<bool> {
// Both enums?
let ReflectRef::Enum(b) = b.reflect_ref() else {
return Some(false);
};
// Same variant name?
if a.variant_name() != b.variant_name() {
return Some(false);
}
// Same variant type?
if !a.is_variant(b.variant_type()) {
return Some(false);
}
match a.variant_type() {
VariantType::Struct => {
// Same struct fields?
for field in a.iter_fields() {
let field_name = field.name().unwrap();
if let Some(field_value) = b.field(field_name) {
if let Some(false) | None = field_value.reflect_partial_eq(field.value()) {
// Fields failed comparison
return Some(false);
}
} else {
// Field does not exist
return Some(false);
}
}
Some(true)
}
VariantType::Tuple => {
// Same tuple fields?
for (i, field) in a.iter_fields().enumerate() {
if let Some(field_value) = b.field_at(i) {
if let Some(false) | None = field_value.reflect_partial_eq(field.value()) {
// Fields failed comparison
return Some(false);
}
} else {
// Field does not exist
return Some(false);
}
}
Some(true)
}
_ => Some(true),
}
}
/// The default debug formatter for [`Enum`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
/// #[derive(Reflect)]
/// enum MyEnum {
/// A,
/// B (usize),
/// C {value: i32}
/// }
///
/// let my_enum: &dyn Reflect = &MyEnum::B(123);
/// println!("{:#?}", my_enum);
///
/// // Output:
///
/// // B (
/// // 123,
/// // )
/// ```
#[inline]
pub fn enum_debug(dyn_enum: &dyn Enum, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match dyn_enum.variant_type() {
VariantType::Unit => f.write_str(dyn_enum.variant_name()),
VariantType::Tuple => {
let mut debug = f.debug_tuple(dyn_enum.variant_name());
for field in dyn_enum.iter_fields() {
debug.field(&field.value() as &dyn Debug);
}
debug.finish()
}
VariantType::Struct => {
let mut debug = f.debug_struct(dyn_enum.variant_name());
for field in dyn_enum.iter_fields() {
debug.field(field.name().unwrap(), &field.value() as &dyn Debug);
}
debug.finish()
}
}
}

693
vendor/bevy_reflect/src/enums/mod.rs vendored Normal file
View File

@@ -0,0 +1,693 @@
mod dynamic_enum;
mod enum_trait;
mod helpers;
mod variants;
pub use dynamic_enum::*;
pub use enum_trait::*;
pub use helpers::*;
pub use variants::*;
#[cfg(test)]
mod tests {
use crate::*;
use alloc::boxed::Box;
#[derive(Reflect, Debug, PartialEq)]
enum MyEnum {
A,
B(usize, i32),
C { foo: f32, bar: bool },
}
#[test]
fn should_get_enum_type_info() {
let info = MyEnum::type_info();
if let TypeInfo::Enum(info) = info {
assert!(info.is::<MyEnum>(), "expected type to be `MyEnum`");
assert_eq!(MyEnum::type_path(), info.type_path());
assert_eq!(MyEnum::type_path(), info.type_path_table().path());
assert_eq!(MyEnum::type_ident(), info.type_path_table().ident());
assert_eq!(MyEnum::module_path(), info.type_path_table().module_path());
assert_eq!(MyEnum::crate_name(), info.type_path_table().crate_name());
assert_eq!(
MyEnum::short_type_path(),
info.type_path_table().short_path()
);
// === MyEnum::A === //
assert_eq!("A", info.variant_at(0).unwrap().name());
assert_eq!("A", info.variant("A").unwrap().name());
if let VariantInfo::Unit(variant) = info.variant("A").unwrap() {
assert_eq!("A", variant.name());
} else {
panic!("Expected `VariantInfo::Unit`");
}
// === MyEnum::B === //
assert_eq!("B", info.variant_at(1).unwrap().name());
assert_eq!("B", info.variant("B").unwrap().name());
if let VariantInfo::Tuple(variant) = info.variant("B").unwrap() {
assert!(variant.field_at(0).unwrap().is::<usize>());
assert!(variant.field_at(1).unwrap().is::<i32>());
assert!(variant
.field_at(0)
.unwrap()
.type_info()
.unwrap()
.is::<usize>());
assert!(variant
.field_at(1)
.unwrap()
.type_info()
.unwrap()
.is::<i32>());
} else {
panic!("Expected `VariantInfo::Tuple`");
}
// === MyEnum::C === //
assert_eq!("C", info.variant_at(2).unwrap().name());
assert_eq!("C", info.variant("C").unwrap().name());
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
assert!(variant.field_at(0).unwrap().is::<f32>());
assert!(variant.field("foo").unwrap().is::<f32>());
assert!(variant
.field("foo")
.unwrap()
.type_info()
.unwrap()
.is::<f32>());
} else {
panic!("Expected `VariantInfo::Struct`");
}
} else {
panic!("Expected `TypeInfo::Enum`");
}
}
#[test]
fn dynamic_enum_should_set_variant_fields() {
// === Unit === //
let mut value = MyEnum::A;
let dyn_enum = DynamicEnum::from(MyEnum::A);
value.apply(&dyn_enum);
assert_eq!(MyEnum::A, value);
// === Tuple === //
let mut value = MyEnum::B(0, 0);
let dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 321), value);
// === Struct === //
let mut value = MyEnum::C {
foo: 0.0,
bar: false,
};
let dyn_enum = DynamicEnum::from(MyEnum::C {
foo: 1.23,
bar: true,
});
value.apply(&dyn_enum);
assert_eq!(
MyEnum::C {
foo: 1.23,
bar: true,
},
value
);
}
#[test]
fn partial_dynamic_enum_should_set_variant_fields() {
// === Tuple === //
let mut value = MyEnum::B(0, 0);
let mut data = DynamicTuple::default();
data.insert(123usize);
let mut dyn_enum = DynamicEnum::default();
dyn_enum.set_variant("B", data);
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 0), value);
// === Struct === //
let mut value = MyEnum::C {
foo: 1.23,
bar: false,
};
let mut data = DynamicStruct::default();
data.insert("bar", true);
let mut dyn_enum = DynamicEnum::default();
dyn_enum.set_variant("C", data);
value.apply(&dyn_enum);
assert_eq!(
MyEnum::C {
foo: 1.23,
bar: true,
},
value
);
}
#[test]
fn dynamic_enum_should_apply_dynamic_enum() {
let mut a = DynamicEnum::from(MyEnum::B(123, 321));
let b = DynamicEnum::from(MyEnum::B(123, 321));
// Sanity check that equality check works
assert!(
a.reflect_partial_eq(&b).unwrap_or_default(),
"dynamic enums should be equal"
);
a.set_variant("A", ());
assert!(
!a.reflect_partial_eq(&b).unwrap_or_default(),
"dynamic enums should not be equal"
);
a.apply(&b);
assert!(a.reflect_partial_eq(&b).unwrap_or_default());
}
#[test]
fn dynamic_enum_should_change_variant() {
let mut value = MyEnum::A;
// === MyEnum::A -> MyEnum::B === //
let mut dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 321), value);
// === MyEnum::B -> MyEnum::C === //
let mut data = DynamicStruct::default();
data.insert("foo", 1.23_f32);
data.insert("bar", true);
dyn_enum.set_variant("C", data);
value.apply(&dyn_enum);
assert_eq!(
MyEnum::C {
foo: 1.23,
bar: true
},
value
);
// === MyEnum::C -> MyEnum::B === //
let mut data = DynamicTuple::default();
data.insert(123_usize);
data.insert(321_i32);
dyn_enum.set_variant("B", data);
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 321), value);
// === MyEnum::B -> MyEnum::A === //
dyn_enum.set_variant("A", ());
value.apply(&dyn_enum);
assert_eq!(MyEnum::A, value);
}
#[test]
fn dynamic_enum_should_return_is_dynamic() {
let dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
assert!(dyn_enum.is_dynamic());
}
#[test]
fn enum_should_iterate_fields() {
// === Unit === //
let value: &dyn Enum = &MyEnum::A;
assert_eq!(0, value.field_len());
let mut iter = value.iter_fields();
assert!(iter.next().is_none());
// === Tuple === //
let value: &dyn Enum = &MyEnum::B(123, 321);
assert_eq!(2, value.field_len());
let mut iter = value.iter_fields();
assert!(iter
.next()
.and_then(|field| field.value().reflect_partial_eq(&123_usize))
.unwrap_or_default());
assert!(iter
.next()
.and_then(|field| field.value().reflect_partial_eq(&321_i32))
.unwrap_or_default());
// === Struct === //
let value: &dyn Enum = &MyEnum::C {
foo: 1.23,
bar: true,
};
assert_eq!(2, value.field_len());
let mut iter = value.iter_fields();
assert!(iter
.next()
.and_then(|field| field
.value()
.reflect_partial_eq(&1.23_f32)
.and(field.name().map(|name| name == "foo")))
.unwrap_or_default());
assert!(iter
.next()
.and_then(|field| field
.value()
.reflect_partial_eq(&true)
.and(field.name().map(|name| name == "bar")))
.unwrap_or_default());
}
#[test]
fn enum_should_return_correct_variant_type() {
// === Unit === //
let value = MyEnum::A;
assert_eq!(VariantType::Unit, value.variant_type());
// === Tuple === //
let value = MyEnum::B(0, 0);
assert_eq!(VariantType::Tuple, value.variant_type());
// === Struct === //
let value = MyEnum::C {
foo: 1.23,
bar: true,
};
assert_eq!(VariantType::Struct, value.variant_type());
}
#[test]
fn enum_should_return_correct_variant_path() {
// === Unit === //
let value = MyEnum::A;
assert_eq!(
"bevy_reflect::enums::tests::MyEnum::A",
value.variant_path()
);
// === Tuple === //
let value = MyEnum::B(0, 0);
assert_eq!(
"bevy_reflect::enums::tests::MyEnum::B",
value.variant_path()
);
// === Struct === //
let value = MyEnum::C {
foo: 1.23,
bar: true,
};
assert_eq!(
"bevy_reflect::enums::tests::MyEnum::C",
value.variant_path()
);
}
#[test]
#[should_panic(
expected = "called `Result::unwrap()` on an `Err` value: MismatchedKinds { from_kind: Tuple, to_kind: Enum }"
)]
fn applying_non_enum_should_panic() {
let mut value = MyEnum::B(0, 0);
let mut dyn_tuple = DynamicTuple::default();
dyn_tuple.insert((123_usize, 321_i32));
value.apply(&dyn_tuple);
}
#[test]
fn enum_try_apply_should_detect_type_mismatch() {
#[derive(Reflect, Debug, PartialEq)]
enum MyEnumAnalogue {
A(u32),
B(usize, usize),
C { foo: f32, bar: u8 },
}
let mut target = MyEnumAnalogue::A(0);
// === Tuple === //
let result = target.try_apply(&MyEnum::B(0, 1));
assert!(
matches!(result, Err(ApplyError::MismatchedTypes { .. })),
"`result` was {result:?}"
);
// === Struct === //
target = MyEnumAnalogue::C { foo: 0.0, bar: 1 };
let result = target.try_apply(&MyEnum::C {
foo: 1.0,
bar: true,
});
assert!(
matches!(result, Err(ApplyError::MismatchedTypes { .. })),
"`result` was {result:?}"
);
// Type mismatch should occur after partial application.
assert_eq!(target, MyEnumAnalogue::C { foo: 1.0, bar: 1 });
}
#[test]
fn should_skip_ignored_fields() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum {
A,
B,
C {
#[reflect(ignore)]
foo: f32,
bar: bool,
},
}
if let TypeInfo::Enum(info) = TestEnum::type_info() {
assert_eq!(3, info.variant_len());
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
assert_eq!(
1,
variant.field_len(),
"expected one of the fields to be ignored"
);
assert!(variant.field_at(0).unwrap().is::<bool>());
} else {
panic!("expected `VariantInfo::Struct`");
}
} else {
panic!("expected `TypeInfo::Enum`");
}
}
#[test]
fn enum_should_allow_generics() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum<T: FromReflect> {
A,
B(T),
C { value: T },
}
if let TypeInfo::Enum(info) = TestEnum::<f32>::type_info() {
if let VariantInfo::Tuple(variant) = info.variant("B").unwrap() {
assert!(variant.field_at(0).unwrap().is::<f32>());
} else {
panic!("expected `VariantInfo::Struct`");
}
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
assert!(variant.field("value").unwrap().is::<f32>());
} else {
panic!("expected `VariantInfo::Struct`");
}
} else {
panic!("expected `TypeInfo::Enum`");
}
let mut value = TestEnum::<f32>::A;
// === Tuple === //
let mut data = DynamicTuple::default();
data.insert(1.23_f32);
let dyn_enum = DynamicEnum::new("B", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::B(1.23), value);
// === Struct === //
let mut data = DynamicStruct::default();
data.insert("value", 1.23_f32);
let dyn_enum = DynamicEnum::new("C", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::C { value: 1.23 }, value);
}
#[test]
fn enum_should_allow_struct_fields() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum {
A,
B(TestStruct),
C { value: TestStruct },
}
#[derive(Reflect, Debug, PartialEq)]
struct TestStruct(usize);
let mut value = TestEnum::A;
// === Tuple === //
let mut data = DynamicTuple::default();
data.insert(TestStruct(123));
let dyn_enum = DynamicEnum::new("B", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::B(TestStruct(123)), value);
// === Struct === //
let mut data = DynamicStruct::default();
data.insert("value", TestStruct(123));
let dyn_enum = DynamicEnum::new("C", data);
value.apply(&dyn_enum);
assert_eq!(
TestEnum::C {
value: TestStruct(123)
},
value
);
}
#[test]
fn enum_should_allow_nesting_enums() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum {
A,
B(OtherEnum),
C { value: OtherEnum },
}
#[derive(Reflect, Debug, PartialEq)]
enum OtherEnum {
A,
B(usize),
C { value: f32 },
}
let mut value = TestEnum::A;
// === Tuple === //
let mut data = DynamicTuple::default();
data.insert(OtherEnum::B(123));
let dyn_enum = DynamicEnum::new("B", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::B(OtherEnum::B(123)), value);
// === Struct === //
let mut data = DynamicStruct::default();
data.insert("value", OtherEnum::C { value: 1.23 });
let dyn_enum = DynamicEnum::new("C", data);
value.apply(&dyn_enum);
assert_eq!(
TestEnum::C {
value: OtherEnum::C { value: 1.23 }
},
value
);
}
#[test]
fn enum_should_apply() {
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
// === MyEnum::A -> MyEnum::A === //
value.apply(&MyEnum::A);
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
// === MyEnum::A -> MyEnum::B === //
value.apply(&MyEnum::B(123, 321));
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::B === //
value.apply(&MyEnum::B(321, 123));
assert!(value
.reflect_partial_eq(&MyEnum::B(321, 123))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::C === //
value.apply(&MyEnum::C {
foo: 1.23,
bar: true,
});
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 1.23,
bar: true
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::C === //
value.apply(&MyEnum::C {
foo: 3.21,
bar: false,
});
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 3.21,
bar: false
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::B === //
value.apply(&MyEnum::B(123, 321));
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::A === //
value.apply(&MyEnum::A);
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
}
#[test]
fn enum_should_set() {
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
// === MyEnum::A -> MyEnum::A === //
value.set(Box::new(MyEnum::A)).unwrap();
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
// === MyEnum::A -> MyEnum::B === //
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::B === //
value.set(Box::new(MyEnum::B(321, 123))).unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::B(321, 123))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::C === //
value
.set(Box::new(MyEnum::C {
foo: 1.23,
bar: true,
}))
.unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 1.23,
bar: true
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::C === //
value
.set(Box::new(MyEnum::C {
foo: 3.21,
bar: false,
}))
.unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 3.21,
bar: false
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::B === //
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::A === //
value.set(Box::new(MyEnum::A)).unwrap();
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
}
#[test]
fn enum_should_partial_eq() {
#[derive(Reflect)]
enum TestEnum {
A,
A1,
B(usize),
B1(usize),
B2(usize, usize),
C { value: i32 },
C1 { value: i32 },
C2 { value: f32 },
}
let a: &dyn PartialReflect = &TestEnum::A;
let b: &dyn PartialReflect = &TestEnum::A;
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::A == TestEnum::A"
);
let a: &dyn PartialReflect = &TestEnum::A;
let b: &dyn PartialReflect = &TestEnum::A1;
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::A != TestEnum::A1"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B(123);
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) == TestEnum::B(123)"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B(321);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B(321)"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B1(123);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B1(123)"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B2(123, 123);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B2(123, 123)"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C { value: 123 };
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} == TestEnum::C{{value: 123}}"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C { value: 321 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C{{value: 321}}"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C1 { value: 123 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C1{{value: 123}}"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C2 { value: 1.23 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C2{{value: 1.23}}"
);
}
}

View File

@@ -0,0 +1,381 @@
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
NamedField, UnnamedField,
};
use alloc::boxed::Box;
use bevy_platform::collections::HashMap;
use bevy_platform::sync::Arc;
use core::slice::Iter;
use thiserror::Error;
/// Describes the form of an enum variant.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum VariantType {
/// Struct enums take the form:
///
/// ```
/// enum MyEnum {
/// A {
/// foo: usize
/// }
/// }
/// ```
Struct,
/// Tuple enums take the form:
///
/// ```
/// enum MyEnum {
/// A(usize)
/// }
/// ```
Tuple,
/// Unit enums take the form:
///
/// ```
/// enum MyEnum {
/// A
/// }
/// ```
Unit,
}
/// A [`VariantInfo`]-specific error.
#[derive(Debug, Error)]
pub enum VariantInfoError {
/// Caused when a variant was expected to be of a certain [type], but was not.
///
/// [type]: VariantType
#[error("variant type mismatch: expected {expected:?}, received {received:?}")]
TypeMismatch {
expected: VariantType,
received: VariantType,
},
}
/// A container for compile-time enum variant info.
#[derive(Clone, Debug)]
pub enum VariantInfo {
/// Struct enums take the form:
///
/// ```
/// enum MyEnum {
/// A {
/// foo: usize
/// }
/// }
/// ```
Struct(StructVariantInfo),
/// Tuple enums take the form:
///
/// ```
/// enum MyEnum {
/// A(usize)
/// }
/// ```
Tuple(TupleVariantInfo),
/// Unit enums take the form:
///
/// ```
/// enum MyEnum {
/// A
/// }
/// ```
Unit(UnitVariantInfo),
}
impl VariantInfo {
pub fn name(&self) -> &'static str {
match self {
Self::Struct(info) => info.name(),
Self::Tuple(info) => info.name(),
Self::Unit(info) => info.name(),
}
}
/// The docstring of the underlying variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&str> {
match self {
Self::Struct(info) => info.docs(),
Self::Tuple(info) => info.docs(),
Self::Unit(info) => info.docs(),
}
}
/// Returns the [type] of this variant.
///
/// [type]: VariantType
pub fn variant_type(&self) -> VariantType {
match self {
Self::Struct(_) => VariantType::Struct,
Self::Tuple(_) => VariantType::Tuple,
Self::Unit(_) => VariantType::Unit,
}
}
impl_custom_attribute_methods!(
self,
match self {
Self::Struct(info) => info.custom_attributes(),
Self::Tuple(info) => info.custom_attributes(),
Self::Unit(info) => info.custom_attributes(),
},
"variant"
);
}
macro_rules! impl_cast_method {
($name:ident : $kind:ident => $info:ident) => {
#[doc = concat!("Attempts a cast to [`", stringify!($info), "`].")]
#[doc = concat!("\n\nReturns an error if `self` is not [`VariantInfo::", stringify!($kind), "`].")]
pub fn $name(&self) -> Result<&$info, VariantInfoError> {
match self {
Self::$kind(info) => Ok(info),
_ => Err(VariantInfoError::TypeMismatch {
expected: VariantType::$kind,
received: self.variant_type(),
}),
}
}
};
}
/// Conversion convenience methods for [`VariantInfo`].
impl VariantInfo {
impl_cast_method!(as_struct_variant: Struct => StructVariantInfo);
impl_cast_method!(as_tuple_variant: Tuple => TupleVariantInfo);
impl_cast_method!(as_unit_variant: Unit => UnitVariantInfo);
}
/// Type info for struct variants.
#[derive(Clone, Debug)]
pub struct StructVariantInfo {
name: &'static str,
fields: Box<[NamedField]>,
field_names: Box<[&'static str]>,
field_indices: HashMap<&'static str, usize>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl StructVariantInfo {
/// Create a new [`StructVariantInfo`].
pub fn new(name: &'static str, fields: &[NamedField]) -> Self {
let field_indices = Self::collect_field_indices(fields);
let field_names = fields.iter().map(NamedField::name).collect();
Self {
name,
fields: fields.to_vec().into_boxed_slice(),
field_names,
field_indices,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this variant.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this variant.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of this variant.
pub fn name(&self) -> &'static str {
self.name
}
/// A slice containing the names of all fields in order.
pub fn field_names(&self) -> &[&'static str] {
&self.field_names
}
/// Get the field with the given name.
pub fn field(&self, name: &str) -> Option<&NamedField> {
self.field_indices
.get(name)
.map(|index| &self.fields[*index])
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&NamedField> {
self.fields.get(index)
}
/// Get the index of the field with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.field_indices.get(name).copied()
}
/// Iterate over the fields of this variant.
pub fn iter(&self) -> Iter<'_, NamedField> {
self.fields.iter()
}
/// The total number of fields in this variant.
pub fn field_len(&self) -> usize {
self.fields.len()
}
fn collect_field_indices(fields: &[NamedField]) -> HashMap<&'static str, usize> {
fields
.iter()
.enumerate()
.map(|(index, field)| (field.name(), index))
.collect()
}
/// The docstring of this variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "variant");
}
/// Type info for tuple variants.
#[derive(Clone, Debug)]
pub struct TupleVariantInfo {
name: &'static str,
fields: Box<[UnnamedField]>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl TupleVariantInfo {
/// Create a new [`TupleVariantInfo`].
pub fn new(name: &'static str, fields: &[UnnamedField]) -> Self {
Self {
name,
fields: fields.to_vec().into_boxed_slice(),
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this variant.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this variant.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of this variant.
pub fn name(&self) -> &'static str {
self.name
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&UnnamedField> {
self.fields.get(index)
}
/// Iterate over the fields of this variant.
pub fn iter(&self) -> Iter<'_, UnnamedField> {
self.fields.iter()
}
/// The total number of fields in this variant.
pub fn field_len(&self) -> usize {
self.fields.len()
}
/// The docstring of this variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "variant");
}
/// Type info for unit variants.
#[derive(Clone, Debug)]
pub struct UnitVariantInfo {
name: &'static str,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl UnitVariantInfo {
/// Create a new [`UnitVariantInfo`].
pub fn new(name: &'static str) -> Self {
Self {
name,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this variant.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this variant.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of this variant.
pub fn name(&self) -> &'static str {
self.name
}
/// The docstring of this variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "variant");
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Reflect, Typed};
#[test]
fn should_return_error_on_invalid_cast() {
#[derive(Reflect)]
enum Foo {
Bar,
}
let info = Foo::type_info().as_enum().unwrap();
let variant = info.variant_at(0).unwrap();
assert!(matches!(
variant.as_tuple_variant(),
Err(VariantInfoError::TypeMismatch {
expected: VariantType::Tuple,
received: VariantType::Unit
})
));
}
}

61
vendor/bevy_reflect/src/error.rs vendored Normal file
View File

@@ -0,0 +1,61 @@
use crate::FieldId;
use alloc::{borrow::Cow, format};
use thiserror::Error;
/// An error that occurs when cloning a type via [`PartialReflect::reflect_clone`].
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
#[derive(Clone, Debug, Error, PartialEq, Eq)]
pub enum ReflectCloneError {
/// The type does not have a custom implementation for [`PartialReflect::reflect_clone`].
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
#[error("`PartialReflect::reflect_clone` not implemented for `{type_path}`")]
NotImplemented { type_path: Cow<'static, str> },
/// The type cannot be cloned via [`PartialReflect::reflect_clone`].
///
/// This type should be returned when a type is intentionally opting out of reflection cloning.
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
#[error("`{type_path}` cannot be made cloneable for `PartialReflect::reflect_clone`")]
NotCloneable { type_path: Cow<'static, str> },
/// The field cannot be cloned via [`PartialReflect::reflect_clone`].
///
/// When [deriving `Reflect`], this usually means that a field marked with `#[reflect(ignore)]`
/// is missing a `#[reflect(clone)]` attribute.
///
/// This may be intentional if the field is not meant/able to be cloned.
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
/// [deriving `Reflect`]: derive@crate::Reflect
#[error(
"field `{}` cannot be made cloneable for `PartialReflect::reflect_clone` (are you missing a `#[reflect(clone)]` attribute?)",
full_path(.field, .variant.as_deref(), .container_type_path)
)]
FieldNotCloneable {
field: FieldId,
variant: Option<Cow<'static, str>>,
container_type_path: Cow<'static, str>,
},
/// Could not downcast to the expected type.
///
/// Realistically this should only occur when a type has incorrectly implemented [`Reflect`].
///
/// [`Reflect`]: crate::Reflect
#[error("expected downcast to `{expected}`, but received `{received}`")]
FailedDowncast {
expected: Cow<'static, str>,
received: Cow<'static, str>,
},
}
fn full_path(
field: &FieldId,
variant: Option<&str>,
container_type_path: &str,
) -> alloc::string::String {
match variant {
Some(variant) => format!("{}::{}::{}", container_type_path, variant, field),
None => format!("{}::{}", container_type_path, field),
}
}

149
vendor/bevy_reflect/src/fields.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
type_info::impl_type_methods,
MaybeTyped, PartialReflect, Type, TypeInfo, TypePath,
};
use alloc::borrow::Cow;
use bevy_platform::sync::Arc;
use core::fmt::{Display, Formatter};
/// The named field of a reflected struct.
#[derive(Clone, Debug)]
pub struct NamedField {
name: &'static str,
type_info: fn() -> Option<&'static TypeInfo>,
ty: Type,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl NamedField {
/// Create a new [`NamedField`].
pub fn new<T: PartialReflect + MaybeTyped + TypePath>(name: &'static str) -> Self {
Self {
name,
type_info: T::maybe_type_info,
ty: Type::of::<T>(),
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this field.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this field.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of the field.
pub fn name(&self) -> &'static str {
self.name
}
/// The [`TypeInfo`] of the field.
///
///
/// Returns `None` if the field does not contain static type information,
/// such as for dynamic types.
pub fn type_info(&self) -> Option<&'static TypeInfo> {
(self.type_info)()
}
impl_type_methods!(ty);
/// The docstring of this field, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "field");
}
/// The unnamed field of a reflected tuple or tuple struct.
#[derive(Clone, Debug)]
pub struct UnnamedField {
index: usize,
type_info: fn() -> Option<&'static TypeInfo>,
ty: Type,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl UnnamedField {
pub fn new<T: PartialReflect + MaybeTyped + TypePath>(index: usize) -> Self {
Self {
index,
type_info: T::maybe_type_info,
ty: Type::of::<T>(),
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this field.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this field.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// Returns the index of the field.
pub fn index(&self) -> usize {
self.index
}
/// The [`TypeInfo`] of the field.
///
///
/// Returns `None` if the field does not contain static type information,
/// such as for dynamic types.
pub fn type_info(&self) -> Option<&'static TypeInfo> {
(self.type_info)()
}
impl_type_methods!(ty);
/// The docstring of this field, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "field");
}
/// A representation of a field's accessor.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FieldId {
Named(Cow<'static, str>),
Unnamed(usize),
}
impl Display for FieldId {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::Named(name) => Display::fmt(name, f),
Self::Unnamed(index) => Display::fmt(index, f),
}
}
}

128
vendor/bevy_reflect/src/from_reflect.rs vendored Normal file
View File

@@ -0,0 +1,128 @@
use crate::{FromType, PartialReflect, Reflect};
use alloc::boxed::Box;
/// A trait that enables types to be dynamically constructed from reflected data.
///
/// It's recommended to use the [derive macro] rather than manually implementing this trait.
///
/// `FromReflect` allows dynamic proxy types, like [`DynamicStruct`], to be used to generate
/// their concrete counterparts.
/// It can also be used to partially or fully clone a type (depending on whether it has
/// ignored fields or not).
///
/// In some cases, this trait may even be required.
/// Deriving [`Reflect`] on an enum requires all its fields to implement `FromReflect`.
/// Additionally, some complex types like `Vec<T>` require that their element types
/// implement this trait.
/// The reason for such requirements is that some operations require new data to be constructed,
/// such as swapping to a new variant or pushing data to a homogeneous list.
///
/// See the [crate-level documentation] to see how this trait can be used.
///
/// [derive macro]: bevy_reflect_derive::FromReflect
/// [`DynamicStruct`]: crate::DynamicStruct
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `FromReflect` so cannot be created through reflection",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait FromReflect: Reflect + Sized {
/// Constructs a concrete instance of `Self` from a reflected value.
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self>;
/// Attempts to downcast the given value to `Self` using,
/// constructing the value using [`from_reflect`] if that fails.
///
/// This method is more efficient than using [`from_reflect`] for cases where
/// the given value is likely a boxed instance of `Self` (i.e. `Box<Self>`)
/// rather than a boxed dynamic type (e.g. [`DynamicStruct`], [`DynamicList`], etc.).
///
/// [`from_reflect`]: Self::from_reflect
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicList`]: crate::DynamicList
fn take_from_reflect(
reflect: Box<dyn PartialReflect>,
) -> Result<Self, Box<dyn PartialReflect>> {
match reflect.try_take::<Self>() {
Ok(value) => Ok(value),
Err(value) => match Self::from_reflect(value.as_ref()) {
None => Err(value),
Some(value) => Ok(value),
},
}
}
}
/// Type data that represents the [`FromReflect`] trait and allows it to be used dynamically.
///
/// `FromReflect` allows dynamic types (e.g. [`DynamicStruct`], [`DynamicEnum`], etc.) to be converted
/// to their full, concrete types. This is most important when it comes to deserialization where it isn't
/// guaranteed that every field exists when trying to construct the final output.
///
/// However, to do this, you normally need to specify the exact concrete type:
///
/// ```
/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect};
/// #[derive(Reflect, PartialEq, Eq, Debug)]
/// struct Foo(#[reflect(default = "default_value")] usize);
///
/// fn default_value() -> usize { 123 }
///
/// let reflected = DynamicTupleStruct::default();
///
/// let concrete: Foo = <Foo as FromReflect>::from_reflect(&reflected).unwrap();
///
/// assert_eq!(Foo(123), concrete);
/// ```
///
/// In a dynamic context where the type might not be known at compile-time, this is nearly impossible to do.
/// That is why this type data struct exists— it allows us to construct the full type without knowing
/// what the actual type is.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{DynamicTupleStruct, Reflect, ReflectFromReflect, Typed, TypeRegistry, TypePath};
/// # #[derive(Reflect, PartialEq, Eq, Debug)]
/// # struct Foo(#[reflect(default = "default_value")] usize);
/// # fn default_value() -> usize { 123 }
/// # let mut registry = TypeRegistry::new();
/// # registry.register::<Foo>();
///
/// let mut reflected = DynamicTupleStruct::default();
/// reflected.set_represented_type(Some(<Foo as Typed>::type_info()));
///
/// let registration = registry.get_with_type_path(<Foo as TypePath>::type_path()).unwrap();
/// let rfr = registration.data::<ReflectFromReflect>().unwrap();
///
/// let concrete: Box<dyn Reflect> = rfr.from_reflect(&reflected).unwrap();
///
/// assert_eq!(Foo(123), concrete.take::<Foo>().unwrap());
/// ```
///
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicEnum`]: crate::DynamicEnum
#[derive(Clone)]
pub struct ReflectFromReflect {
from_reflect: fn(&dyn PartialReflect) -> Option<Box<dyn Reflect>>,
}
impl ReflectFromReflect {
/// Perform a [`FromReflect::from_reflect`] conversion on the given reflection object.
///
/// This will convert the object to a concrete type if it wasn't already, and return
/// the value as `Box<dyn Reflect>`.
pub fn from_reflect(&self, reflect_value: &dyn PartialReflect) -> Option<Box<dyn Reflect>> {
(self.from_reflect)(reflect_value)
}
}
impl<T: FromReflect> FromType<T> for ReflectFromReflect {
fn from_type() -> Self {
Self {
from_reflect: |reflect_value| {
T::from_reflect(reflect_value).map(|value| Box::new(value) as Box<dyn Reflect>)
},
}
}
}

214
vendor/bevy_reflect/src/func/args/arg.rs vendored Normal file
View File

@@ -0,0 +1,214 @@
use crate::{
func::args::{ArgError, FromArg, Ownership},
PartialReflect, Reflect, TypePath,
};
use alloc::{boxed::Box, string::ToString};
use core::ops::Deref;
/// Represents an argument that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug)]
pub struct Arg<'a> {
index: usize,
value: ArgValue<'a>,
}
impl<'a> Arg<'a> {
/// Create a new [`Arg`] with the given index and value.
pub fn new(index: usize, value: ArgValue<'a>) -> Self {
Self { index, value }
}
/// The index of the argument.
pub fn index(&self) -> usize {
self.index
}
/// Set the index of the argument.
pub(crate) fn set_index(&mut self, index: usize) {
self.index = index;
}
/// The value of the argument.
pub fn value(&self) -> &ArgValue<'a> {
&self.value
}
/// Take the value of the argument.
pub fn take_value(self) -> ArgValue<'a> {
self.value
}
/// Take the value of the argument and attempt to convert it to a concrete value, `T`.
///
/// This is a convenience method for calling [`FromArg::from_arg`] on the argument.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let a = 1u32;
/// let b = 2u32;
/// let mut c = 3u32;
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
///
/// let a = args.take::<u32>().unwrap();
/// assert_eq!(a, 1);
///
/// let b = args.take::<&u32>().unwrap();
/// assert_eq!(*b, 2);
///
/// let c = args.take::<&mut u32>().unwrap();
/// assert_eq!(*c, 3);
/// ```
pub fn take<T: FromArg>(self) -> Result<T::This<'a>, ArgError> {
T::from_arg(self)
}
/// Returns `Ok(T)` if the argument is [`ArgValue::Owned`].
///
/// If the argument is not owned, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_owned(value);
/// let value = args.take_owned::<u32>().unwrap();
/// assert_eq!(value, 123);
/// ```
pub fn take_owned<T: Reflect + TypePath>(self) -> Result<T, ArgError> {
match self.value {
ArgValue::Owned(arg) => arg.try_take().map_err(|arg| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
}),
ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Owned,
received: Ownership::Ref,
}),
ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Owned,
received: Ownership::Mut,
}),
}
}
/// Returns `Ok(&T)` if the argument is [`ArgValue::Ref`].
///
/// If the argument is not a reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_ref(&value);
/// let value = args.take_ref::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_ref<T: Reflect + TypePath>(self) -> Result<&'a T, ArgError> {
match self.value {
ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Ref,
received: Ownership::Owned,
}),
ArgValue::Ref(arg) => {
Ok(arg
.try_downcast_ref()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
})?)
}
ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Ref,
received: Ownership::Mut,
}),
}
}
/// Returns `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
///
/// If the argument is not a mutable reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let mut value = 123u32;
/// let mut args = ArgList::new().with_mut(&mut value);
/// let value = args.take_mut::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_mut<T: Reflect + TypePath>(self) -> Result<&'a mut T, ArgError> {
match self.value {
ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Mut,
received: Ownership::Owned,
}),
ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Mut,
received: Ownership::Ref,
}),
ArgValue::Mut(arg) => {
let received = alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string());
Ok(arg
.try_downcast_mut()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received,
})?)
}
}
}
/// Returns `true` if the argument is of type `T`.
pub fn is<T: TypePath>(&self) -> bool {
self.value
.try_as_reflect()
.map(<dyn Reflect>::is::<T>)
.unwrap_or_default()
}
}
/// Represents an argument that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug)]
pub enum ArgValue<'a> {
Owned(Box<dyn PartialReflect>),
Ref(&'a dyn PartialReflect),
Mut(&'a mut dyn PartialReflect),
}
impl<'a> Deref for ArgValue<'a> {
type Target = dyn PartialReflect;
fn deref(&self) -> &Self::Target {
match self {
ArgValue::Owned(arg) => arg.as_ref(),
ArgValue::Ref(arg) => *arg,
ArgValue::Mut(arg) => *arg,
}
}
}

View File

@@ -0,0 +1,311 @@
use crate::func::args::ArgCountOutOfBoundsError;
use core::fmt::{Debug, Formatter};
/// A container for zero or more argument counts for a function.
///
/// For most functions, this will contain a single count,
/// however, overloaded functions may contain more.
///
/// # Maximum Argument Count
///
/// The maximum number of arguments that can be represented by this struct is 63,
/// as given by [`ArgCount::MAX_COUNT`].
/// The reason for this is that all counts are stored internally as a single `u64`
/// with each bit representing a specific count based on its bit index.
///
/// This allows for a smaller memory footprint and faster lookups compared to a
/// `HashSet` or `Vec` of possible counts.
/// It's also more appropriate for representing the argument counts of a function
/// given that most functions will not have more than a few arguments.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArgCount {
/// The bits representing the argument counts.
///
/// Each bit represents a specific count based on its bit index.
bits: u64,
/// The total number of argument counts.
len: u8,
}
impl ArgCount {
/// The maximum number of arguments that can be represented by this struct.
pub const MAX_COUNT: usize = u64::BITS as usize - 1;
/// Create a new [`ArgCount`] with the given count.
///
/// # Errors
///
/// Returns an error if the count is greater than [`Self::MAX_COUNT`].
pub fn new(count: usize) -> Result<Self, ArgCountOutOfBoundsError> {
Ok(Self {
bits: 1 << Self::try_to_u8(count)?,
len: 1,
})
}
/// Adds the given count to this [`ArgCount`].
///
/// # Panics
///
/// Panics if the count is greater than [`Self::MAX_COUNT`].
pub fn add(&mut self, count: usize) {
self.try_add(count).unwrap();
}
/// Attempts to add the given count to this [`ArgCount`].
///
/// # Errors
///
/// Returns an error if the count is greater than [`Self::MAX_COUNT`].
pub fn try_add(&mut self, count: usize) -> Result<(), ArgCountOutOfBoundsError> {
let count = Self::try_to_u8(count)?;
if !self.contains_unchecked(count) {
self.len += 1;
self.bits |= 1 << count;
}
Ok(())
}
/// Removes the given count from this [`ArgCount`].
pub fn remove(&mut self, count: usize) {
self.try_remove(count).unwrap();
}
/// Attempts to remove the given count from this [`ArgCount`].
///
/// # Errors
///
/// Returns an error if the count is greater than [`Self::MAX_COUNT`].
pub fn try_remove(&mut self, count: usize) -> Result<(), ArgCountOutOfBoundsError> {
let count = Self::try_to_u8(count)?;
if self.contains_unchecked(count) {
self.len -= 1;
self.bits &= !(1 << count);
}
Ok(())
}
/// Checks if this [`ArgCount`] contains the given count.
pub fn contains(&self, count: usize) -> bool {
count < usize::BITS as usize && (self.bits >> count) & 1 == 1
}
/// Returns the total number of argument counts that this [`ArgCount`] contains.
pub fn len(&self) -> usize {
self.len as usize
}
/// Returns true if this [`ArgCount`] contains no argument counts.
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns an iterator over the argument counts in this [`ArgCount`].
pub fn iter(&self) -> ArgCountIter {
ArgCountIter {
count: *self,
index: 0,
found: 0,
}
}
/// Checks if this [`ArgCount`] contains the given count without any bounds checking.
///
/// # Panics
///
/// Panics if the count is greater than [`Self::MAX_COUNT`].
fn contains_unchecked(&self, count: u8) -> bool {
(self.bits >> count) & 1 == 1
}
/// Attempts to convert the given count to a `u8` within the bounds of the [maximum count].
///
/// [maximum count]: Self::MAX_COUNT
fn try_to_u8(count: usize) -> Result<u8, ArgCountOutOfBoundsError> {
if count > Self::MAX_COUNT {
Err(ArgCountOutOfBoundsError(count))
} else {
Ok(count as u8)
}
}
}
/// Defaults this [`ArgCount`] to empty.
///
/// This means that it contains no argument counts, including zero.
impl Default for ArgCount {
fn default() -> Self {
Self { bits: 0, len: 0 }
}
}
impl Debug for ArgCount {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}
/// An iterator for the argument counts in an [`ArgCount`].
pub struct ArgCountIter {
count: ArgCount,
index: u8,
found: u8,
}
impl Iterator for ArgCountIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.index as usize > ArgCount::MAX_COUNT {
return None;
}
if self.found == self.count.len {
// All counts have been found
return None;
}
if self.count.contains_unchecked(self.index) {
self.index += 1;
self.found += 1;
return Some(self.index as usize - 1);
}
self.index += 1;
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.count.len(), Some(self.count.len()))
}
}
impl ExactSizeIterator for ArgCountIter {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_default_to_empty() {
let count = ArgCount::default();
assert_eq!(count.len(), 0);
assert!(count.is_empty());
assert!(!count.contains(0));
}
#[test]
fn should_construct_with_count() {
let count = ArgCount::new(3).unwrap();
assert_eq!(count.len(), 1);
assert!(!count.is_empty());
assert!(count.contains(3));
}
#[test]
fn should_add_count() {
let mut count = ArgCount::default();
count.add(3);
assert_eq!(count.len(), 1);
assert!(count.contains(3));
}
#[test]
fn should_add_multiple_counts() {
let mut count = ArgCount::default();
count.add(3);
count.add(5);
count.add(7);
assert_eq!(count.len(), 3);
assert!(!count.contains(0));
assert!(!count.contains(1));
assert!(!count.contains(2));
assert!(count.contains(3));
assert!(count.contains(5));
assert!(count.contains(7));
}
#[test]
fn should_add_idempotently() {
let mut count = ArgCount::default();
count.add(3);
count.add(3);
assert_eq!(count.len(), 1);
assert!(count.contains(3));
}
#[test]
fn should_remove_count() {
let mut count = ArgCount::default();
count.add(3);
assert_eq!(count.len(), 1);
assert!(count.contains(3));
count.remove(3);
assert_eq!(count.len(), 0);
assert!(!count.contains(3));
}
#[test]
fn should_allow_removing_nonexistent_count() {
let mut count = ArgCount::default();
assert_eq!(count.len(), 0);
assert!(!count.contains(3));
count.remove(3);
assert_eq!(count.len(), 0);
assert!(!count.contains(3));
}
#[test]
fn should_iterate_over_counts() {
let mut count = ArgCount::default();
count.add(3);
count.add(5);
count.add(7);
let mut iter = count.iter();
assert_eq!(iter.len(), 3);
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), Some(5));
assert_eq!(iter.next(), Some(7));
assert_eq!(iter.next(), None);
}
#[test]
fn should_return_error_for_out_of_bounds_count() {
let count = ArgCount::new(64);
assert_eq!(count, Err(ArgCountOutOfBoundsError(64)));
let mut count = ArgCount::default();
assert_eq!(count.try_add(64), Err(ArgCountOutOfBoundsError(64)));
assert_eq!(count.try_remove(64), Err(ArgCountOutOfBoundsError(64)));
}
#[test]
fn should_return_false_for_out_of_bounds_contains() {
let count = ArgCount::default();
assert!(!count.contains(64));
}
}

View File

@@ -0,0 +1,36 @@
use alloc::borrow::Cow;
use thiserror::Error;
use crate::func::args::Ownership;
/// An error that occurs when converting an [argument].
///
/// [argument]: crate::func::args::Arg
#[derive(Debug, Error, PartialEq)]
pub enum ArgError {
/// The argument is not the expected type.
#[error("expected `{expected}` but received `{received}` (@ argument index {index})")]
UnexpectedType {
index: usize,
expected: Cow<'static, str>,
received: Cow<'static, str>,
},
/// The argument has the wrong ownership.
#[error("expected {expected} value but received {received} value (@ argument index {index})")]
InvalidOwnership {
index: usize,
expected: Ownership,
received: Ownership,
},
/// Occurs when attempting to access an argument from an empty [`ArgList`].
///
/// [`ArgList`]: crate::func::args::ArgList
#[error("expected an argument but received none")]
EmptyArgList,
}
/// The given argument count is out of bounds.
#[derive(Debug, Error, PartialEq)]
#[error("argument count out of bounds: {0}")]
pub struct ArgCountOutOfBoundsError(pub usize);

View File

@@ -0,0 +1,104 @@
use crate::func::args::{Arg, ArgError};
/// A trait for types that can be created from an [`Arg`].
///
/// This trait exists so that types can be automatically converted into an [`Arg`]
/// so they can be put into an [`ArgList`] and passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// This trait is used instead of a blanket [`From`] implementation due to coherence issues:
/// we can't implement `From<T>` for both `T` and `&T`/`&mut T`.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
///
/// [`ArgList`]: crate::func::args::ArgList
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
/// [derive macro]: derive@crate::Reflect
pub trait FromArg {
/// The type to convert into.
///
/// This should almost always be the same as `Self`, but with the lifetime `'a`.
///
/// The reason we use a separate associated type is to allow for the lifetime
/// to be tied to the argument, rather than the type itself.
type This<'a>;
/// Creates an item from an argument.
///
/// The argument must be of the expected type and ownership.
fn from_arg(arg: Arg) -> Result<Self::This<'_>, ArgError>;
}
/// Implements the [`FromArg`] trait for the given type.
///
/// This will implement it for `$ty`, `&$ty`, and `&mut $ty`.
///
/// See [`impl_function_traits`] for details on syntax.
///
/// [`impl_function_traits`]: crate::func::macros::impl_function_traits
macro_rules! impl_from_arg {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_owned()
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for &'static $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = &'from_arg $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_ref()
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for &'static mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = &'from_arg mut $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_mut()
}
}
};
}
pub(crate) use impl_from_arg;

View File

@@ -0,0 +1,101 @@
use alloc::borrow::Cow;
use crate::{
func::args::{GetOwnership, Ownership},
type_info::impl_type_methods,
Type, TypePath,
};
/// Type information for an [`Arg`] used in a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`Arg`]: crate::func::args::Arg
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Clone)]
pub struct ArgInfo {
/// The index of the argument within its function.
index: usize,
/// The name of the argument (if provided).
name: Option<Cow<'static, str>>,
/// The ownership of the argument.
ownership: Ownership,
/// The [type] of the argument.
///
/// [type]: Type
ty: Type,
}
impl ArgInfo {
/// Create a new [`ArgInfo`] with the given argument index and type `T`.
///
/// To set the name of the argument, use [`Self::with_name`].
pub fn new<T: TypePath + GetOwnership>(index: usize) -> Self {
Self {
index,
name: None,
ownership: T::ownership(),
ty: Type::of::<T>(),
}
}
/// Set the name of the argument.
///
/// Reflected arguments are not required to have a name and by default are not given one,
/// so this method must be called manually to set the name.
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.name = Some(name.into());
self
}
/// The index of the argument within its function.
pub fn index(&self) -> usize {
self.index
}
/// The name of the argument, if it was given one.
///
/// Note that this may return `None` even if the argument has a name.
/// This is because the name needs to be manually set using [`Self::with_name`]
/// since the name can't be inferred from the function type alone.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`]
/// and [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the name will always be `None`.
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut
/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
/// The ownership of the argument.
pub fn ownership(&self) -> Ownership {
self.ownership
}
impl_type_methods!(ty);
/// Get an ID representing the argument.
///
/// This will return `ArgId::Name` if the argument has a name,
/// otherwise `ArgId::Index`.
pub fn id(&self) -> ArgId {
self.name
.clone()
.map(ArgId::Name)
.unwrap_or_else(|| ArgId::Index(self.index))
}
}
/// A representation of an argument.
///
/// This is primarily used for error reporting and debugging.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArgId {
/// The index of the argument within its function.
Index(usize),
/// The name of the argument.
Name(Cow<'static, str>),
}

View File

@@ -0,0 +1,458 @@
use crate::{
func::{
args::{Arg, ArgValue, FromArg},
ArgError,
},
PartialReflect, Reflect, TypePath,
};
use alloc::{
boxed::Box,
collections::vec_deque::{Iter, VecDeque},
};
/// A list of arguments that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgValue, ArgList};
/// let foo = 123;
/// let bar = 456;
/// let mut baz = 789;
/// let args = ArgList::new()
/// // Push an owned argument
/// .with_owned(foo)
/// // Push an owned and boxed argument
/// .with_boxed(Box::new(foo))
/// // Push a reference argument
/// .with_ref(&bar)
/// // Push a mutable reference argument
/// .with_mut(&mut baz)
/// // Push a manually constructed argument
/// .with_arg(ArgValue::Ref(&3.14));
/// ```
///
/// [arguments]: Arg
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Default, Debug)]
pub struct ArgList<'a> {
list: VecDeque<Arg<'a>>,
/// A flag that indicates if the list needs to be re-indexed.
///
/// This flag should be set when an argument is removed from the beginning of the list,
/// so that any future push operations will re-index the arguments.
needs_reindex: bool,
}
impl<'a> ArgList<'a> {
/// Create a new empty list of arguments.
pub fn new() -> Self {
Self {
list: VecDeque::new(),
needs_reindex: false,
}
}
/// Push an [`ArgValue`] onto the list.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_arg(&mut self, arg: ArgValue<'a>) {
if self.needs_reindex {
for (index, arg) in self.list.iter_mut().enumerate() {
arg.set_index(index);
}
self.needs_reindex = false;
}
let index = self.list.len();
self.list.push_back(Arg::new(index, arg));
}
/// Push an [`ArgValue::Ref`] onto the list with the given reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_ref(&mut self, arg: &'a dyn PartialReflect) {
self.push_arg(ArgValue::Ref(arg));
}
/// Push an [`ArgValue::Mut`] onto the list with the given mutable reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_mut(&mut self, arg: &'a mut dyn PartialReflect) {
self.push_arg(ArgValue::Mut(arg));
}
/// Push an [`ArgValue::Owned`] onto the list with the given owned value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_owned(&mut self, arg: impl PartialReflect) {
self.push_arg(ArgValue::Owned(Box::new(arg)));
}
/// Push an [`ArgValue::Owned`] onto the list with the given boxed value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_boxed(&mut self, arg: Box<dyn PartialReflect>) {
self.push_arg(ArgValue::Owned(arg));
}
/// Push an [`ArgValue`] onto the list.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_arg(mut self, arg: ArgValue<'a>) -> Self {
self.push_arg(arg);
self
}
/// Push an [`ArgValue::Ref`] onto the list with the given reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_ref(self, arg: &'a dyn PartialReflect) -> Self {
self.with_arg(ArgValue::Ref(arg))
}
/// Push an [`ArgValue::Mut`] onto the list with the given mutable reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_mut(self, arg: &'a mut dyn PartialReflect) -> Self {
self.with_arg(ArgValue::Mut(arg))
}
/// Push an [`ArgValue::Owned`] onto the list with the given owned value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_owned(self, arg: impl PartialReflect) -> Self {
self.with_arg(ArgValue::Owned(Box::new(arg)))
}
/// Push an [`ArgValue::Owned`] onto the list with the given boxed value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_boxed(self, arg: Box<dyn PartialReflect>) -> Self {
self.with_arg(ArgValue::Owned(arg))
}
/// Remove the first argument in the list and return it.
///
/// It's generally preferred to use [`Self::take`] instead of this method
/// as it provides a more ergonomic way to immediately downcast the argument.
pub fn take_arg(&mut self) -> Result<Arg<'a>, ArgError> {
self.needs_reindex = true;
self.list.pop_front().ok_or(ArgError::EmptyArgList)
}
/// Remove the first argument in the list and return `Ok(T::This)`.
///
/// If the list is empty or the [`FromArg::from_arg`] call fails, returns an error.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let a = 1u32;
/// let b = 2u32;
/// let mut c = 3u32;
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
///
/// let a = args.take::<u32>().unwrap();
/// assert_eq!(a, 1);
///
/// let b = args.take::<&u32>().unwrap();
/// assert_eq!(*b, 2);
///
/// let c = args.take::<&mut u32>().unwrap();
/// assert_eq!(*c, 3);
/// ```
pub fn take<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
self.take_arg()?.take::<T>()
}
/// Remove the first argument in the list and return `Ok(T)` if the argument is [`ArgValue::Owned`].
///
/// If the list is empty or the argument is not owned, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_owned(value);
/// let value = args.take_owned::<u32>().unwrap();
/// assert_eq!(value, 123);
/// ```
pub fn take_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
self.take_arg()?.take_owned()
}
/// Remove the first argument in the list and return `Ok(&T)` if the argument is [`ArgValue::Ref`].
///
/// If the list is empty or the argument is not a reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_ref(&value);
/// let value = args.take_ref::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
self.take_arg()?.take_ref()
}
/// Remove the first argument in the list and return `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
///
/// If the list is empty or the argument is not a mutable reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let mut value = 123u32;
/// let mut args = ArgList::new().with_mut(&mut value);
/// let value = args.take_mut::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
self.take_arg()?.take_mut()
}
/// Remove the last argument in the list and return it.
///
/// It's generally preferred to use [`Self::pop`] instead of this method
/// as it provides a more ergonomic way to immediately downcast the argument.
pub fn pop_arg(&mut self) -> Result<Arg<'a>, ArgError> {
self.list.pop_back().ok_or(ArgError::EmptyArgList)
}
/// Remove the last argument in the list and return `Ok(T::This)`.
///
/// If the list is empty or the [`FromArg::from_arg`] call fails, returns an error.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let a = 1u32;
/// let b = 2u32;
/// let mut c = 3u32;
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
///
/// let c = args.pop::<&mut u32>().unwrap();
/// assert_eq!(*c, 3);
///
/// let b = args.pop::<&u32>().unwrap();
/// assert_eq!(*b, 2);
///
/// let a = args.pop::<u32>().unwrap();
/// assert_eq!(a, 1);
/// ```
pub fn pop<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
self.pop_arg()?.take::<T>()
}
/// Remove the last argument in the list and return `Ok(T)` if the argument is [`ArgValue::Owned`].
///
/// If the list is empty or the argument is not owned, returns an error.
///
/// It's generally preferred to use [`Self::pop`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_owned(value);
/// let value = args.pop_owned::<u32>().unwrap();
/// assert_eq!(value, 123);
/// ```
pub fn pop_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
self.pop_arg()?.take_owned()
}
/// Remove the last argument in the list and return `Ok(&T)` if the argument is [`ArgValue::Ref`].
///
/// If the list is empty or the argument is not a reference, returns an error.
///
/// It's generally preferred to use [`Self::pop`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_ref(&value);
/// let value = args.pop_ref::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn pop_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
self.pop_arg()?.take_ref()
}
/// Remove the last argument in the list and return `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
///
/// If the list is empty or the argument is not a mutable reference, returns an error.
///
/// It's generally preferred to use [`Self::pop`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let mut value = 123u32;
/// let mut args = ArgList::new().with_mut(&mut value);
/// let value = args.pop_mut::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn pop_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
self.pop_arg()?.take_mut()
}
/// Returns an iterator over the arguments in the list.
pub fn iter(&self) -> Iter<'_, Arg<'a>> {
self.list.iter()
}
/// Returns the number of arguments in the list.
pub fn len(&self) -> usize {
self.list.len()
}
/// Returns `true` if the list of arguments is empty.
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::String;
#[test]
fn should_push_arguments_in_order() {
let args = ArgList::new()
.with_owned(123)
.with_owned(456)
.with_owned(789);
assert_eq!(args.len(), 3);
assert_eq!(args.list[0].index(), 0);
assert_eq!(args.list[1].index(), 1);
assert_eq!(args.list[2].index(), 2);
}
#[test]
fn should_push_arg_with_correct_ownership() {
let a = String::from("a");
let b = String::from("b");
let mut c = String::from("c");
let d = String::from("d");
let e = String::from("e");
let f = String::from("f");
let mut g = String::from("g");
let args = ArgList::new()
.with_arg(ArgValue::Owned(Box::new(a)))
.with_arg(ArgValue::Ref(&b))
.with_arg(ArgValue::Mut(&mut c))
.with_owned(d)
.with_boxed(Box::new(e))
.with_ref(&f)
.with_mut(&mut g);
assert!(matches!(args.list[0].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[1].value(), &ArgValue::Ref(_)));
assert!(matches!(args.list[2].value(), &ArgValue::Mut(_)));
assert!(matches!(args.list[3].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[4].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[5].value(), &ArgValue::Ref(_)));
assert!(matches!(args.list[6].value(), &ArgValue::Mut(_)));
}
#[test]
fn should_take_args_in_order() {
let a = String::from("a");
let b = 123_i32;
let c = 456_usize;
let mut d = 5.78_f32;
let mut args = ArgList::new()
.with_owned(a)
.with_ref(&b)
.with_ref(&c)
.with_mut(&mut d);
assert_eq!(args.len(), 4);
assert_eq!(args.take_owned::<String>().unwrap(), String::from("a"));
assert_eq!(args.take::<&i32>().unwrap(), &123);
assert_eq!(args.take_ref::<usize>().unwrap(), &456);
assert_eq!(args.take_mut::<f32>().unwrap(), &mut 5.78);
assert_eq!(args.len(), 0);
}
#[test]
fn should_pop_args_in_reverse_order() {
let a = String::from("a");
let b = 123_i32;
let c = 456_usize;
let mut d = 5.78_f32;
let mut args = ArgList::new()
.with_owned(a)
.with_ref(&b)
.with_ref(&c)
.with_mut(&mut d);
assert_eq!(args.len(), 4);
assert_eq!(args.pop_mut::<f32>().unwrap(), &mut 5.78);
assert_eq!(args.pop_ref::<usize>().unwrap(), &456);
assert_eq!(args.pop::<&i32>().unwrap(), &123);
assert_eq!(args.pop_owned::<String>().unwrap(), String::from("a"));
assert_eq!(args.len(), 0);
}
#[test]
fn should_reindex_on_push_after_take() {
let mut args = ArgList::new()
.with_owned(123)
.with_owned(456)
.with_owned(789);
assert!(!args.needs_reindex);
args.take_arg().unwrap();
assert!(args.needs_reindex);
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
assert_eq!(args.list[0].index(), 1);
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
assert_eq!(args.list[1].index(), 2);
let args = args.with_owned(123);
assert!(!args.needs_reindex);
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
assert_eq!(args.list[0].index(), 0);
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
assert_eq!(args.list[1].index(), 1);
assert!(args.list[2].value().reflect_partial_eq(&123).unwrap());
assert_eq!(args.list[2].index(), 2);
}
}

View File

@@ -0,0 +1,20 @@
//! Argument types and utilities for working with [`DynamicFunction`] and [`DynamicFunctionMut`].
//!
//! [`DynamicFunction`]: crate::func::DynamicFunction
//! [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
pub use arg::*;
pub use count::*;
pub use error::*;
pub use from_arg::*;
pub use info::*;
pub use list::*;
pub use ownership::*;
mod arg;
mod count;
mod error;
mod from_arg;
mod info;
mod list;
mod ownership;

View File

@@ -0,0 +1,109 @@
use core::fmt::{Display, Formatter};
/// A trait for getting the ownership of a type.
///
/// This trait exists so that [`TypedFunction`] can automatically generate
/// [`FunctionInfo`] containing the proper [`Ownership`] for its [argument] types.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
///
/// [`TypedFunction`]: crate::func::TypedFunction
/// [`FunctionInfo`]: crate::func::FunctionInfo
/// [argument]: crate::func::args::Arg
/// [derive macro]: derive@crate::Reflect
pub trait GetOwnership {
/// Returns the ownership of [`Self`].
fn ownership() -> Ownership;
}
/// The ownership of a type.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Ownership {
/// The type is a reference (i.e. `&T`).
Ref,
/// The type is a mutable reference (i.e. `&mut T`).
Mut,
/// The type is owned (i.e. `T`).
Owned,
}
impl Display for Ownership {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::Ref => write!(f, "reference"),
Self::Mut => write!(f, "mutable reference"),
Self::Owned => write!(f, "owned"),
}
}
}
/// Implements the [`GetOwnership`] trait for the given type.
///
/// This will implement it for `$ty`, `&$ty`, and `&mut $ty`.
///
/// See [`impl_function_traits`] for details on syntax.
///
/// [`impl_function_traits`]: crate::func::macros::impl_function_traits
macro_rules! impl_get_ownership {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Owned
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for &'_ $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Ref
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for &'_ mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Mut
}
}
};
}
pub(crate) use impl_get_ownership;

View File

@@ -0,0 +1,805 @@
use crate::{
__macro_exports::RegisterForReflection,
func::{
args::{ArgCount, ArgList},
dynamic_function_internal::DynamicFunctionInternal,
info::FunctionInfo,
DynamicFunctionMut, Function, FunctionOverloadError, FunctionResult, IntoFunction,
IntoFunctionMut,
},
ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo, TypePath,
};
use alloc::{borrow::Cow, boxed::Box};
use bevy_platform::sync::Arc;
use bevy_reflect_derive::impl_type_path;
use core::fmt::{Debug, Formatter};
/// An [`Arc`] containing a callback to a reflected function.
///
/// The `Arc` is used to both ensure that it is `Send + Sync`
/// and to allow for the callback to be cloned.
///
/// Note that cloning is okay since we only ever need an immutable reference
/// to call a `dyn Fn` function.
/// If we were to contain a `dyn FnMut` instead, cloning would be a lot more complicated.
type ArcFn<'env> = Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>;
/// A dynamic representation of a function.
///
/// This type can be used to represent any callable that satisfies [`Fn`]
/// (or the reflection-based equivalent, [`ReflectFn`]).
/// That is, any function or closure that does not mutably borrow data from its environment.
///
/// For functions that do need to capture their environment mutably (i.e. mutable closures),
/// see [`DynamicFunctionMut`].
///
/// See the [module-level documentation] for more information.
///
/// You will generally not need to construct this manually.
/// Instead, many functions and closures can be automatically converted using the [`IntoFunction`] trait.
///
/// # Example
///
/// Most of the time, a [`DynamicFunction`] can be created using the [`IntoFunction`] trait:
///
/// ```
/// # use bevy_reflect::func::{ArgList, DynamicFunction, IntoFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// // Convert the function into a dynamic function using `IntoFunction::into_function`:
/// let mut func: DynamicFunction = add.into_function();
///
/// // Dynamically call it:
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
/// let value = func.call(args).unwrap().unwrap_owned();
///
/// // Check the result:
/// assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));
/// ```
///
/// [`ReflectFn`]: crate::func::ReflectFn
/// [module-level documentation]: crate::func
#[derive(Clone)]
pub struct DynamicFunction<'env> {
pub(super) internal: DynamicFunctionInternal<ArcFn<'env>>,
}
impl<'env> DynamicFunction<'env> {
/// Create a new [`DynamicFunction`].
///
/// The given function can be used to call out to any other callable,
/// including functions, closures, or methods.
///
/// It's important that the function signature matches the provided [`FunctionInfo`].
/// as this will be used to validate arguments when [calling] the function.
/// This is also required in order for [function overloading] to work correctly.
///
/// # Panics
///
/// This function may panic for any of the following reasons:
/// - No [`SignatureInfo`] is provided.
/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].
/// - The conversion to [`FunctionInfo`] fails.
///
/// [calling]: crate::func::dynamic_function::DynamicFunction::call
/// [`SignatureInfo`]: crate::func::SignatureInfo
/// [function overloading]: Self::with_overload
pub fn new<F: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>(
func: F,
info: impl TryInto<FunctionInfo, Error: Debug>,
) -> Self {
let arc = Arc::new(func);
#[cfg(not(target_has_atomic = "ptr"))]
#[expect(
unsafe_code,
reason = "unsized coercion is an unstable feature for non-std types"
)]
// SAFETY:
// - Coercion from `T` to `dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`
// is valid as `T: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`
// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
let arc = unsafe { ArcFn::<'env>::from_raw(Arc::into_raw(arc) as *const _) };
Self {
internal: DynamicFunctionInternal::new(arc, info.try_into().unwrap()),
}
}
/// Set the name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctions`]: DynamicFunction
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.internal = self.internal.with_name(name);
self
}
/// Add an overload to this function.
///
/// Overloads allow a single [`DynamicFunction`] to represent multiple functions of different signatures.
///
/// This can be used to handle multiple monomorphizations of a generic function
/// or to allow functions with a variable number of arguments.
///
/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.
/// For example, if the existing function had the signature `(i32, i32) -> i32`,
/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,
/// the one from `F` would replace the one from the existing function.
///
/// Overloaded functions retain the [name] of the original function.
///
/// # Panics
///
/// Panics if the function, `F`, contains a signature already found in this function.
///
/// For a non-panicking version, see [`try_with_overload`].
///
/// # Examples
///
/// ```
/// # use std::ops::Add;
/// # use bevy_reflect::func::{ArgList, IntoFunction};
/// #
/// fn add<T: Add<Output = T>>(a: T, b: T) -> T {
/// a + b
/// }
///
/// // Currently, the only generic type `func` supports is `i32`:
/// let mut func = add::<i32>.into_function();
///
/// // However, we can add an overload to handle `f32` as well:
/// func = func.with_overload(add::<f32>);
///
/// // Test `i32`:
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
///
/// // Test `f32`:
/// let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
///```
///
/// ```
/// # use bevy_reflect::func::{ArgList, IntoFunction};
/// #
/// fn add_2(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// fn add_3(a: i32, b: i32, c: i32) -> i32 {
/// a + b + c
/// }
///
/// // Currently, `func` only supports two arguments.
/// let mut func = add_2.into_function();
///
/// // However, we can add an overload to handle three arguments as well.
/// func = func.with_overload(add_3);
///
/// // Test two arguments:
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
///
/// // Test three arguments:
/// let args = ArgList::default()
/// .with_owned(25_i32)
/// .with_owned(75_i32)
/// .with_owned(100_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 200);
/// ```
///
///```should_panic
/// # use bevy_reflect::func::IntoFunction;
///
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// fn sub(a: i32, b: i32) -> i32 {
/// a - b
/// }
///
/// let mut func = add.into_function();
///
/// // This will panic because the function already has an argument signature for `(i32, i32)`:
/// func = func.with_overload(sub);
/// ```
///
/// [argument signature]: crate::func::signature::ArgumentSignature
/// [name]: Self::name
/// [`try_with_overload`]: Self::try_with_overload
pub fn with_overload<'a, F: IntoFunction<'a, Marker>, Marker>(
self,
function: F,
) -> DynamicFunction<'a>
where
'env: 'a,
{
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
panic!("{}", err);
})
}
/// Attempt to add an overload to this function.
///
/// If the function, `F`, contains a signature already found in this function,
/// an error will be returned along with the original function.
///
/// For a panicking version, see [`with_overload`].
///
/// [`with_overload`]: Self::with_overload
pub fn try_with_overload<F: IntoFunction<'env, Marker>, Marker>(
mut self,
function: F,
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
let function = function.into_function();
match self.internal.merge(function.internal) {
Ok(_) => Ok(self),
Err(err) => Err((Box::new(self), err)),
}
}
/// Call the function with the given arguments.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunction, ArgList};
/// let c = 23;
/// let add = |a: i32, b: i32| -> i32 {
/// a + b + c
/// };
///
/// let mut func = add.into_function().with_name("add");
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 123);
/// ```
///
/// # Errors
///
/// This method will return an error if the number of arguments provided does not match
/// the number of arguments expected by the function's [`FunctionInfo`].
///
/// The function itself may also return any errors it needs to.
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
self.internal.validate_args(&args)?;
let func = self.internal.get(&args)?;
func(args)
}
/// Returns the function info.
pub fn info(&self) -> &FunctionInfo {
self.internal.info()
}
/// The name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// This can be overridden using [`with_name`].
///
/// If the function was [overloaded], it will retain its original name if it had one.
///
/// [`DynamicFunctions`]: DynamicFunction
/// [`with_name`]: Self::with_name
/// [overloaded]: Self::with_overload
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.internal.name()
}
/// Returns `true` if the function is [overloaded].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunction;
/// let add = (|a: i32, b: i32| a + b).into_function();
/// assert!(!add.is_overloaded());
///
/// let add = add.with_overload(|a: f32, b: f32| a + b);
/// assert!(add.is_overloaded());
/// ```
///
/// [overloaded]: Self::with_overload
pub fn is_overloaded(&self) -> bool {
self.internal.is_overloaded()
}
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunction;
/// let add = (|a: i32, b: i32| a + b).into_function();
/// assert!(add.arg_count().contains(2));
///
/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);
/// assert!(add.arg_count().contains(2));
/// assert!(add.arg_count().contains(3));
/// ```
///
/// [overloaded]: Self::with_overload
pub fn arg_count(&self) -> ArgCount {
self.internal.arg_count()
}
}
impl Function for DynamicFunction<'static> {
fn name(&self) -> Option<&Cow<'static, str>> {
self.internal.name()
}
fn info(&self) -> &FunctionInfo {
self.internal.info()
}
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
self.call(args)
}
fn to_dynamic_function(&self) -> DynamicFunction<'static> {
self.clone()
}
}
impl PartialReflect for DynamicFunction<'static> {
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
None
}
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
match value.reflect_ref() {
ReflectRef::Function(func) => {
*self = func.to_dynamic_function();
Ok(())
}
_ => Err(ApplyError::MismatchedTypes {
from_type: value.reflect_type_path().into(),
to_type: Self::type_path().into(),
}),
}
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Function
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Function(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Function(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Function(self)
}
fn reflect_hash(&self) -> Option<u64> {
None
}
fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {
None
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Debug::fmt(self, f)
}
fn is_dynamic(&self) -> bool {
true
}
}
impl MaybeTyped for DynamicFunction<'static> {}
impl RegisterForReflection for DynamicFunction<'static> {}
impl_type_path!((in bevy_reflect) DynamicFunction<'env>);
/// Outputs the function's signature.
///
/// This takes the format: `DynamicFunction(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.
///
/// Names for arguments and the function itself are optional and will default to `_` if not provided.
///
/// If the function is [overloaded], the output will include the signatures of all overloads as a set.
/// For example, `DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.
///
/// [overloaded]: DynamicFunction::with_overload
impl<'env> Debug for DynamicFunction<'env> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicFunction({:?})", &self.internal)
}
}
impl<'env> IntoFunction<'env, ()> for DynamicFunction<'env> {
#[inline]
fn into_function(self) -> DynamicFunction<'env> {
self
}
}
impl<'env> IntoFunctionMut<'env, ()> for DynamicFunction<'env> {
#[inline]
fn into_function_mut(self) -> DynamicFunctionMut<'env> {
DynamicFunctionMut::from(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::signature::ArgumentSignature;
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
use crate::Type;
use alloc::{format, string::String, vec, vec::Vec};
use bevy_platform::collections::HashSet;
use core::ops::Add;
#[test]
fn should_overwrite_function_name() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
assert!(func.name().is_none());
let func = func.with_name("my_function");
assert_eq!(func.name().unwrap(), "my_function");
}
#[test]
fn should_convert_dynamic_function_with_into_function() {
fn make_closure<'env, F: IntoFunction<'env, M>, M>(f: F) -> DynamicFunction<'env> {
f.into_function()
}
let c = 23;
let function: DynamicFunction = make_closure(|a: i32, b: i32| a + b + c);
let _: DynamicFunction = make_closure(function);
}
#[test]
fn should_return_error_on_arg_count_mismatch() {
let func = (|a: i32, b: i32| a + b).into_function();
let args = ArgList::default().with_owned(25_i32);
let error = func.call(args).unwrap_err();
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: ArgCount::new(2).unwrap(),
received: 1
}
);
}
#[test]
fn should_return_error_on_arg_count_mismatch_overloaded() {
let func = (|a: i32, b: i32| a + b)
.into_function()
.with_overload(|a: i32, b: i32, c: i32| a + b + c);
let args = ArgList::default()
.with_owned(1_i32)
.with_owned(2_i32)
.with_owned(3_i32)
.with_owned(4_i32);
let error = func.call(args).unwrap_err();
let mut expected_count = ArgCount::new(2).unwrap();
expected_count.add(3);
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: expected_count,
received: 4
}
);
}
#[test]
fn should_clone_dynamic_function() {
let hello = String::from("Hello");
let greet = |name: &String| -> String { format!("{}, {}!", hello, name) };
let greet = greet.into_function().with_name("greet");
let clone = greet.clone();
assert_eq!(greet.name().unwrap(), "greet");
assert_eq!(clone.name().unwrap(), "greet");
let cloned_value = clone
.call(ArgList::default().with_ref(&String::from("world")))
.unwrap()
.unwrap_owned()
.try_take::<String>()
.unwrap();
assert_eq!(cloned_value, "Hello, world!");
}
#[test]
fn should_apply_function() {
let mut func: Box<dyn Function> = Box::new((|a: i32, b: i32| a + b).into_function());
func.apply(&((|a: i32, b: i32| a * b).into_function()));
let args = ArgList::new().with_owned(5_i32).with_owned(5_i32);
let result = func.reflect_call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 25);
}
#[test]
fn should_allow_recursive_dynamic_function() {
let factorial = DynamicFunction::new(
|mut args| {
let curr = args.pop::<i32>()?;
if curr == 0 {
return Ok(1_i32.into_return());
}
let arg = args.pop_arg()?;
let this = arg.value();
match this.reflect_ref() {
ReflectRef::Function(func) => {
let result = func.reflect_call(
ArgList::new()
.with_ref(this.as_partial_reflect())
.with_owned(curr - 1),
);
let value = result.unwrap().unwrap_owned().try_take::<i32>().unwrap();
Ok((curr * value).into_return())
}
_ => panic!("expected function"),
}
},
// The `FunctionInfo` doesn't really matter for this test
// so we can just give it dummy information.
SignatureInfo::anonymous()
.with_arg::<i32>("curr")
.with_arg::<()>("this"),
);
let args = ArgList::new().with_ref(&factorial).with_owned(5_i32);
let value = factorial.call(args).unwrap().unwrap_owned();
assert_eq!(value.try_take::<i32>().unwrap(), 120);
}
#[test]
fn should_allow_creating_manual_generic_dynamic_function() {
let func = DynamicFunction::new(
|mut args| {
let a = args.take_arg()?;
let b = args.take_arg()?;
if a.is::<i32>() {
let a = a.take::<i32>()?;
let b = b.take::<i32>()?;
Ok((a + b).into_return())
} else {
let a = a.take::<f32>()?;
let b = b.take::<f32>()?;
Ok((a + b).into_return())
}
},
vec![
SignatureInfo::named("add::<i32>")
.with_arg::<i32>("a")
.with_arg::<i32>("b")
.with_return::<i32>(),
SignatureInfo::named("add::<f32>")
.with_arg::<f32>("a")
.with_arg::<f32>("b")
.with_return::<f32>(),
],
);
assert_eq!(func.name().unwrap(), "add::<i32>");
let func = func.with_name("add");
assert_eq!(func.name().unwrap(), "add");
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
}
#[test]
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: MissingSignature")]
fn should_panic_on_missing_function_info() {
let _ = DynamicFunction::new(|_| Ok(().into_return()), Vec::new());
}
#[test]
fn should_allow_function_overloading() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let func = add::<i32>.into_function().with_overload(add::<f32>);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
}
#[test]
fn should_allow_variable_arguments_via_overloading() {
fn add_2(a: i32, b: i32) -> i32 {
a + b
}
fn add_3(a: i32, b: i32, c: i32) -> i32 {
a + b + c
}
let func = add_2.into_function().with_overload(add_3);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default()
.with_owned(25_i32)
.with_owned(75_i32)
.with_owned(100_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 200);
}
#[test]
fn should_allow_function_overloading_with_manual_overload() {
let manual = DynamicFunction::new(
|mut args| {
let a = args.take_arg()?;
let b = args.take_arg()?;
if a.is::<i32>() {
let a = a.take::<i32>()?;
let b = b.take::<i32>()?;
Ok((a + b).into_return())
} else {
let a = a.take::<f32>()?;
let b = b.take::<f32>()?;
Ok((a + b).into_return())
}
},
vec![
SignatureInfo::named("add::<i32>")
.with_arg::<i32>("a")
.with_arg::<i32>("b")
.with_return::<i32>(),
SignatureInfo::named("add::<f32>")
.with_arg::<f32>("a")
.with_arg::<f32>("b")
.with_return::<f32>(),
],
);
let func = manual.with_overload(|a: u32, b: u32| a + b);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<u32>().unwrap(), 100);
}
#[test]
fn should_return_error_on_unknown_overload() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let func = add::<i32>.into_function().with_overload(add::<f32>);
let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::NoOverload {
expected: [
ArgumentSignature::from_iter(vec![Type::of::<i32>(), Type::of::<i32>()]),
ArgumentSignature::from_iter(vec![Type::of::<f32>(), Type::of::<f32>()])
]
.into_iter()
.collect::<HashSet<_>>(),
received: ArgumentSignature::from_iter(vec![Type::of::<u32>(), Type::of::<u32>()]),
}
);
}
#[test]
fn should_debug_dynamic_function() {
fn greet(name: &String) -> String {
format!("Hello, {}!", name)
}
let function = greet.into_function();
let debug = format!("{:?}", function);
assert_eq!(debug, "DynamicFunction(fn bevy_reflect::func::dynamic_function::tests::should_debug_dynamic_function::greet(_: &alloc::string::String) -> alloc::string::String)");
}
#[test]
fn should_debug_anonymous_dynamic_function() {
let function = (|a: i32, b: i32| a + b).into_function();
let debug = format!("{:?}", function);
assert_eq!(debug, "DynamicFunction(fn _(_: i32, _: i32) -> i32)");
}
#[test]
fn should_debug_overloaded_dynamic_function() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let func = add::<i32>
.into_function()
.with_overload(add::<f32>)
.with_name("add");
let debug = format!("{:?}", func);
assert_eq!(
debug,
"DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})"
);
}
}

View File

@@ -0,0 +1,378 @@
use crate::func::args::ArgCount;
use crate::func::signature::{ArgListSignature, ArgumentSignature};
use crate::func::{ArgList, FunctionError, FunctionInfo, FunctionOverloadError};
use alloc::{borrow::Cow, vec, vec::Vec};
use bevy_platform::collections::HashMap;
use core::fmt::{Debug, Formatter};
/// An internal structure for storing a function and its corresponding [function information].
///
/// This is used to facilitate the sharing of functionality between [`DynamicFunction`]
/// and [`DynamicFunctionMut`].
///
/// [function information]: FunctionInfo
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Clone)]
pub(super) struct DynamicFunctionInternal<F> {
functions: Vec<F>,
info: FunctionInfo,
arg_map: HashMap<ArgumentSignature, usize>,
}
impl<F> DynamicFunctionInternal<F> {
/// Create a new instance of [`DynamicFunctionInternal`] with the given function
/// and its corresponding information.
pub fn new(func: F, info: FunctionInfo) -> Self {
let arg_map = info
.signatures()
.iter()
.map(|sig| (ArgumentSignature::from(sig), 0))
.collect();
Self {
functions: vec![func],
info,
arg_map,
}
}
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.info = self.info.with_name(Some(name.into()));
self
}
/// The name of the function.
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.info.name()
}
/// Returns `true` if the function is overloaded.
pub fn is_overloaded(&self) -> bool {
self.info.is_overloaded()
}
/// Get an immutable reference to the function.
///
/// If the function is not overloaded, it will always be returned regardless of the arguments.
/// Otherwise, the function will be selected based on the arguments provided.
///
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
pub fn get(&self, args: &ArgList) -> Result<&F, FunctionError> {
if !self.info.is_overloaded() {
return Ok(&self.functions[0]);
}
let signature = ArgListSignature::from(args);
self.arg_map
.get(&signature)
.map(|index| &self.functions[*index])
.ok_or_else(|| FunctionError::NoOverload {
expected: self.arg_map.keys().cloned().collect(),
received: ArgumentSignature::from(args),
})
}
/// Get a mutable reference to the function.
///
/// If the function is not overloaded, it will always be returned regardless of the arguments.
/// Otherwise, the function will be selected based on the arguments provided.
///
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
pub fn get_mut(&mut self, args: &ArgList) -> Result<&mut F, FunctionError> {
if !self.info.is_overloaded() {
return Ok(&mut self.functions[0]);
}
let signature = ArgListSignature::from(args);
self.arg_map
.get(&signature)
.map(|index| &mut self.functions[*index])
.ok_or_else(|| FunctionError::NoOverload {
expected: self.arg_map.keys().cloned().collect(),
received: ArgumentSignature::from(args),
})
}
/// Returns the function information contained in the map.
#[inline]
pub fn info(&self) -> &FunctionInfo {
&self.info
}
/// Returns the number of arguments the function expects.
///
/// For overloaded functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
pub fn arg_count(&self) -> ArgCount {
self.info.arg_count()
}
/// Helper method for validating that a given set of arguments are _potentially_ valid for this function.
///
/// Currently, this validates:
/// - The number of arguments is within the expected range
pub fn validate_args(&self, args: &ArgList) -> Result<(), FunctionError> {
let expected_arg_count = self.arg_count();
let received_arg_count = args.len();
if !expected_arg_count.contains(received_arg_count) {
Err(FunctionError::ArgCountMismatch {
expected: expected_arg_count,
received: received_arg_count,
})
} else {
Ok(())
}
}
/// Merge another [`DynamicFunctionInternal`] into this one.
///
/// If `other` contains any functions with the same signature as this one,
/// an error will be returned along with the original, unchanged instance.
///
/// Therefore, this method should always return an overloaded function if the merge is successful.
///
/// Additionally, if the merge succeeds, it should be guaranteed that the order
/// of the functions in the map will be preserved.
/// For example, merging `[func_a, func_b]` (self) with `[func_c, func_d]` (other) should result in
/// `[func_a, func_b, func_c, func_d]`.
/// And merging `[func_c, func_d]` (self) with `[func_a, func_b]` (other) should result in
/// `[func_c, func_d, func_a, func_b]`.
pub fn merge(&mut self, mut other: Self) -> Result<(), FunctionOverloadError> {
// Keep a separate map of the new indices to avoid mutating the existing one
// until we can be sure the merge will be successful.
let mut new_signatures = <HashMap<_, _>>::default();
for (sig, index) in other.arg_map {
if self.arg_map.contains_key(&sig) {
return Err(FunctionOverloadError::DuplicateSignature(sig));
}
new_signatures.insert(sig, self.functions.len() + index);
}
self.arg_map.reserve(new_signatures.len());
for (sig, index) in new_signatures {
self.arg_map.insert(sig, index);
}
self.functions.append(&mut other.functions);
self.info.extend_unchecked(other.info);
Ok(())
}
/// Maps the internally stored function(s) from type `F` to type `G`.
pub fn map_functions<G>(self, f: fn(F) -> G) -> DynamicFunctionInternal<G> {
DynamicFunctionInternal {
functions: self.functions.into_iter().map(f).collect(),
info: self.info,
arg_map: self.arg_map,
}
}
}
impl<F> Debug for DynamicFunctionInternal<F> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.info
.pretty_printer()
.include_fn_token()
.include_name()
.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{FunctionInfo, SignatureInfo};
use crate::Type;
#[test]
fn should_merge_single_into_single() {
let mut func_a = DynamicFunctionInternal::new(
'a',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
);
let func_b = DynamicFunctionInternal::new(
'b',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
);
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b']);
assert_eq!(func_a.info.signatures().len(), 2);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
])
);
}
#[test]
fn should_merge_single_into_overloaded() {
let mut func_a = DynamicFunctionInternal::new(
'a',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
);
let func_b = DynamicFunctionInternal {
functions: vec!['b', 'c'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
]),
};
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
assert_eq!(func_a.info.signatures().len(), 3);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 2),
])
);
}
#[test]
fn should_merge_overload_into_single() {
let mut func_a = DynamicFunctionInternal {
functions: vec!['a', 'b'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
]),
};
let func_b = DynamicFunctionInternal::new(
'c',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
);
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
assert_eq!(func_a.info.signatures().len(), 3);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),
])
);
}
#[test]
fn should_merge_overloaded_into_overloaded() {
let mut func_a = DynamicFunctionInternal {
functions: vec!['a', 'b'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
]),
};
let func_b = DynamicFunctionInternal {
functions: vec!['c', 'd'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
]),
};
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b', 'c', 'd']);
assert_eq!(func_a.info.signatures().len(), 4);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 3),
])
);
}
#[test]
fn should_return_error_on_duplicate_signature() {
let mut func_a = DynamicFunctionInternal::new(
'a',
FunctionInfo::new(
SignatureInfo::anonymous()
.with_arg::<i8>("arg0")
.with_arg::<i16>("arg1"),
),
);
let func_b = DynamicFunctionInternal {
functions: vec!['b', 'c'],
info: FunctionInfo::new(
SignatureInfo::anonymous()
.with_arg::<u8>("arg0")
.with_arg::<u16>("arg1"),
)
.with_overload(
SignatureInfo::anonymous()
.with_arg::<i8>("arg0")
.with_arg::<i16>("arg1"),
)
.unwrap(),
arg_map: HashMap::from_iter([
(
ArgumentSignature::from_iter([Type::of::<u8>(), Type::of::<u16>()]),
0,
),
(
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),
1,
),
]),
};
let FunctionOverloadError::DuplicateSignature(duplicate) =
func_a.merge(func_b).unwrap_err()
else {
panic!("Expected `FunctionOverloadError::DuplicateSignature`");
};
assert_eq!(
duplicate,
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()])
);
// Assert the original remains unchanged:
assert!(!func_a.is_overloaded());
assert_eq!(func_a.functions, vec!['a']);
assert_eq!(func_a.info.signatures().len(), 1);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([(
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),
0
),])
);
}
}

View File

@@ -0,0 +1,488 @@
use alloc::{borrow::Cow, boxed::Box};
use bevy_platform::sync::Arc;
use core::fmt::{Debug, Formatter};
use crate::func::{
args::{ArgCount, ArgList},
dynamic_function_internal::DynamicFunctionInternal,
DynamicFunction, FunctionInfo, FunctionOverloadError, FunctionResult, IntoFunctionMut,
};
/// A [`Box`] containing a callback to a reflected function.
type BoxFnMut<'env> = Box<dyn for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>;
/// A dynamic representation of a function.
///
/// This type can be used to represent any callable that satisfies [`FnMut`]
/// (or the reflection-based equivalent, [`ReflectFnMut`]).
/// That is, any function or closure.
///
/// For functions that do not need to capture their environment mutably,
/// it's recommended to use [`DynamicFunction`] instead.
///
/// This type can be seen as a superset of [`DynamicFunction`].
///
/// See the [module-level documentation] for more information.
///
/// You will generally not need to construct this manually.
/// Instead, many functions and closures can be automatically converted using the [`IntoFunctionMut`] trait.
///
/// # Example
///
/// Most of the time, a [`DynamicFunctionMut`] can be created using the [`IntoFunctionMut`] trait:
///
/// ```
/// # use bevy_reflect::func::{ArgList, DynamicFunctionMut, FunctionInfo, IntoFunctionMut};
/// #
/// let mut list: Vec<i32> = vec![1, 2, 3];
///
/// // `replace` is a closure that captures a mutable reference to `list`
/// let mut replace = |index: usize, value: i32| -> i32 {
/// let old_value = list[index];
/// list[index] = value;
/// old_value
/// };
///
/// // Since this closure mutably borrows data, we can't convert it into a regular `DynamicFunction`,
/// // as doing so would result in a compile-time error:
/// // let mut func: DynamicFunction = replace.into_function();
///
/// // Instead, we convert it into a `DynamicFunctionMut` using `IntoFunctionMut::into_function_mut`:
/// let mut func: DynamicFunctionMut = replace.into_function_mut();
///
/// // Dynamically call it:
/// let args = ArgList::default().with_owned(1_usize).with_owned(-2_i32);
/// let value = func.call(args).unwrap().unwrap_owned();
///
/// // Check the result:
/// assert_eq!(value.try_take::<i32>().unwrap(), 2);
///
/// // Note that `func` still has a reference to `list`,
/// // so we need to drop it before we can access `list` again.
/// // Alternatively, we could have invoked `func` with
/// // `DynamicFunctionMut::call_once` to immediately consume it.
/// drop(func);
/// assert_eq!(list, vec![1, -2, 3]);
/// ```
///
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
/// [module-level documentation]: crate::func
pub struct DynamicFunctionMut<'env> {
internal: DynamicFunctionInternal<BoxFnMut<'env>>,
}
impl<'env> DynamicFunctionMut<'env> {
/// Create a new [`DynamicFunctionMut`].
///
/// The given function can be used to call out to any other callable,
/// including functions, closures, or methods.
///
/// It's important that the function signature matches the provided [`FunctionInfo`].
/// as this will be used to validate arguments when [calling] the function.
/// This is also required in order for [function overloading] to work correctly.
///
/// # Panics
///
/// This function may panic for any of the following reasons:
/// - No [`SignatureInfo`] is provided.
/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].
/// - The conversion to [`FunctionInfo`] fails.
///
/// [calling]: crate::func::dynamic_function_mut::DynamicFunctionMut::call
/// [`SignatureInfo`]: crate::func::SignatureInfo
/// [function overloading]: Self::with_overload
pub fn new<F: for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>(
func: F,
info: impl TryInto<FunctionInfo, Error: Debug>,
) -> Self {
Self {
internal: DynamicFunctionInternal::new(Box::new(func), info.try_into().unwrap()),
}
}
/// Set the name of the function.
///
/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.internal = self.internal.with_name(name);
self
}
/// Add an overload to this function.
///
/// Overloads allow a single [`DynamicFunctionMut`] to represent multiple functions of different signatures.
///
/// This can be used to handle multiple monomorphizations of a generic function
/// or to allow functions with a variable number of arguments.
///
/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.
/// For example, if the existing function had the signature `(i32, i32) -> i32`,
/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,
/// the one from `F` would replace the one from the existing function.
///
/// Overloaded functions retain the [name] of the original function.
///
/// Note that it may be impossible to overload closures that mutably borrow from their environment
/// due to Rust's borrowing rules.
/// However, it's still possible to overload functions that do not capture their environment mutably,
/// or those that maintain mutually exclusive mutable references to their environment.
///
/// # Panics
///
/// Panics if the function, `F`, contains a signature already found in this function.
///
/// For a non-panicking version, see [`try_with_overload`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunctionMut;
/// let mut total_i32 = 0;
/// let mut add_i32 = |a: i32| total_i32 += a;
///
/// let mut total_f32 = 0.0;
/// let mut add_f32 = |a: f32| total_f32 += a;
///
/// // Currently, the only generic type `func` supports is `i32`.
/// let mut func = add_i32.into_function_mut();
///
/// // However, we can add an overload to handle `f32` as well:
/// func = func.with_overload(add_f32);
///
/// // Test `i32`:
/// let args = bevy_reflect::func::ArgList::new().with_owned(123_i32);
/// func.call(args).unwrap();
///
/// // Test `f32`:
/// let args = bevy_reflect::func::ArgList::new().with_owned(1.23_f32);
/// func.call(args).unwrap();
///
/// drop(func);
/// assert_eq!(total_i32, 123);
/// assert_eq!(total_f32, 1.23);
/// ```
///
/// [argument signature]: crate::func::signature::ArgumentSignature
/// [name]: Self::name
/// [`try_with_overload`]: Self::try_with_overload
pub fn with_overload<'a, F: IntoFunctionMut<'a, Marker>, Marker>(
self,
function: F,
) -> DynamicFunctionMut<'a>
where
'env: 'a,
{
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
panic!("{}", err);
})
}
/// Attempt to add an overload to this function.
///
/// If the function, `F`, contains a signature already found in this function,
/// an error will be returned along with the original function.
///
/// For a panicking version, see [`with_overload`].
///
/// [`with_overload`]: Self::with_overload
pub fn try_with_overload<F: IntoFunctionMut<'env, Marker>, Marker>(
mut self,
function: F,
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
let function = function.into_function_mut();
match self.internal.merge(function.internal) {
Ok(_) => Ok(self),
Err(err) => Err((Box::new(self), err)),
}
}
/// Call the function with the given arguments.
///
/// Variables that are captured mutably by this function
/// won't be usable until this function is dropped.
/// Consider using [`call_once`] if you want to consume the function
/// immediately after calling it.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};
/// let mut total = 0;
/// let add = |a: i32, b: i32| -> i32 {
/// total = a + b;
/// total
/// };
///
/// let mut func = add.into_function_mut().with_name("add");
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
/// ```
///
/// # Errors
///
/// This method will return an error if the number of arguments provided does not match
/// the number of arguments expected by the function's [`FunctionInfo`].
///
/// The function itself may also return any errors it needs to.
///
/// [`call_once`]: DynamicFunctionMut::call_once
pub fn call<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a> {
self.internal.validate_args(&args)?;
let func = self.internal.get_mut(&args)?;
func(args)
}
/// Call the function with the given arguments and consume it.
///
/// This is useful for functions that capture their environment mutably
/// because otherwise any captured variables would still be borrowed by it.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};
/// let mut count = 0;
/// let increment = |amount: i32| count += amount;
///
/// let increment_function = increment.into_function_mut();
/// let args = ArgList::new().with_owned(5_i32);
///
/// // We need to drop `increment_function` here so that we
/// // can regain access to `count`.
/// // `call_once` does this automatically for us.
/// increment_function.call_once(args).unwrap();
/// assert_eq!(count, 5);
/// ```
///
/// # Errors
///
/// This method will return an error if the number of arguments provided does not match
/// the number of arguments expected by the function's [`FunctionInfo`].
///
/// The function itself may also return any errors it needs to.
pub fn call_once(mut self, args: ArgList) -> FunctionResult {
self.call(args)
}
/// Returns the function info.
pub fn info(&self) -> &FunctionInfo {
self.internal.info()
}
/// The name of the function.
///
/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// This can be overridden using [`with_name`].
///
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
/// [`with_name`]: Self::with_name
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.internal.name()
}
/// Returns `true` if the function is [overloaded].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunctionMut;
/// let mut total_i32 = 0;
/// let increment = (|value: i32| total_i32 += value).into_function_mut();
/// assert!(!increment.is_overloaded());
///
/// let mut total_f32 = 0.0;
/// let increment = increment.with_overload(|value: f32| total_f32 += value);
/// assert!(increment.is_overloaded());
/// ```
///
/// [overloaded]: Self::with_overload
pub fn is_overloaded(&self) -> bool {
self.internal.is_overloaded()
}
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunctionMut;
/// let add = (|a: i32, b: i32| a + b).into_function_mut();
/// assert!(add.arg_count().contains(2));
///
/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);
/// assert!(add.arg_count().contains(2));
/// assert!(add.arg_count().contains(3));
/// ```
///
/// [overloaded]: Self::with_overload
pub fn arg_count(&self) -> ArgCount {
self.internal.arg_count()
}
}
/// Outputs the function's signature.
///
/// This takes the format: `DynamicFunctionMut(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.
///
/// Names for arguments and the function itself are optional and will default to `_` if not provided.
///
/// If the function is [overloaded], the output will include the signatures of all overloads as a set.
/// For example, `DynamicFunctionMut(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.
///
/// [overloaded]: DynamicFunctionMut::with_overload
impl<'env> Debug for DynamicFunctionMut<'env> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicFunctionMut({:?})", &self.internal)
}
}
impl<'env> From<DynamicFunction<'env>> for DynamicFunctionMut<'env> {
#[inline]
fn from(function: DynamicFunction<'env>) -> Self {
Self {
internal: function.internal.map_functions(arc_to_box),
}
}
}
/// Helper function from converting an [`Arc`] function to a [`Box`] function.
///
/// This is needed to help the compiler infer the correct types.
fn arc_to_box<'env>(
f: Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>,
) -> BoxFnMut<'env> {
Box::new(move |args| f(args))
}
impl<'env> IntoFunctionMut<'env, ()> for DynamicFunctionMut<'env> {
#[inline]
fn into_function_mut(self) -> DynamicFunctionMut<'env> {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
use alloc::vec;
use core::ops::Add;
#[test]
fn should_overwrite_function_name() {
let mut total = 0;
let func = (|a: i32, b: i32| total = a + b).into_function_mut();
assert!(func.name().is_none());
let func = func.with_name("my_function");
assert_eq!(func.name().unwrap(), "my_function");
}
#[test]
fn should_convert_dynamic_function_mut_with_into_function() {
fn make_closure<'env, F: IntoFunctionMut<'env, M>, M>(f: F) -> DynamicFunctionMut<'env> {
f.into_function_mut()
}
let mut total = 0;
let closure: DynamicFunctionMut = make_closure(|a: i32, b: i32| total = a + b);
let _: DynamicFunctionMut = make_closure(closure);
}
#[test]
fn should_return_error_on_arg_count_mismatch() {
let mut total = 0;
let mut func = (|a: i32, b: i32| total = a + b).into_function_mut();
let args = ArgList::default().with_owned(25_i32);
let error = func.call(args).unwrap_err();
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: ArgCount::new(2).unwrap(),
received: 1
}
);
let args = ArgList::default().with_owned(25_i32);
let error = func.call_once(args).unwrap_err();
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: ArgCount::new(2).unwrap(),
received: 1
}
);
}
#[test]
fn should_allow_creating_manual_generic_dynamic_function_mut() {
let mut total = 0_i32;
let func = DynamicFunctionMut::new(
|mut args| {
let value = args.take_arg()?;
if value.is::<i32>() {
let value = value.take::<i32>()?;
total += value;
} else {
let value = value.take::<i16>()?;
total += value as i32;
}
Ok(().into_return())
},
vec![
SignatureInfo::named("add::<i32>").with_arg::<i32>("value"),
SignatureInfo::named("add::<i16>").with_arg::<i16>("value"),
],
);
assert_eq!(func.name().unwrap(), "add::<i32>");
let mut func = func.with_name("add");
assert_eq!(func.name().unwrap(), "add");
let args = ArgList::default().with_owned(25_i32);
func.call(args).unwrap();
let args = ArgList::default().with_owned(75_i16);
func.call(args).unwrap();
drop(func);
assert_eq!(total, 100);
}
// Closures that mutably borrow from their environment cannot realistically
// be overloaded since that would break Rust's borrowing rules.
// However, we still need to verify overloaded functions work since a
// `DynamicFunctionMut` can also be made from a non-mutably borrowing closure/function.
#[test]
fn should_allow_function_overloading() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let mut func = add::<i32>.into_function_mut().with_overload(add::<f32>);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
}
}

71
vendor/bevy_reflect/src/func/error.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
use crate::func::signature::ArgumentSignature;
use crate::func::{
args::{ArgCount, ArgError},
Return,
};
use alloc::borrow::Cow;
use bevy_platform::collections::HashSet;
use thiserror::Error;
/// An error that occurs when calling a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Error, PartialEq)]
pub enum FunctionError {
/// An error occurred while converting an argument.
#[error(transparent)]
ArgError(#[from] ArgError),
/// The number of arguments provided does not match the expected number.
#[error("received {received} arguments but expected one of {expected:?}")]
ArgCountMismatch { expected: ArgCount, received: usize },
/// No overload was found for the given set of arguments.
#[error("no overload found for arguments with signature `{received:?}`, expected one of `{expected:?}`")]
NoOverload {
expected: HashSet<ArgumentSignature>,
received: ArgumentSignature,
},
}
/// The result of calling a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// Returns `Ok(value)` if the function was called successfully,
/// where `value` is the [`Return`] value of the function.
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
pub type FunctionResult<'a> = Result<Return<'a>, FunctionError>;
/// An error that occurs when attempting to add a function overload.
#[derive(Debug, Error, PartialEq)]
pub enum FunctionOverloadError {
/// A [`SignatureInfo`] was expected, but none was found.
///
/// [`SignatureInfo`]: crate::func::info::SignatureInfo
#[error("expected at least one `SignatureInfo` but found none")]
MissingSignature,
/// An error that occurs when attempting to add a function overload with a duplicate signature.
#[error("could not add function overload: duplicate found for signature `{0:?}`")]
DuplicateSignature(ArgumentSignature),
#[error(
"argument signature `{:?}` has too many arguments (max {})",
0,
ArgCount::MAX_COUNT
)]
TooManyArguments(ArgumentSignature),
}
/// An error that occurs when registering a function into a [`FunctionRegistry`].
///
/// [`FunctionRegistry`]: crate::func::FunctionRegistry
#[derive(Debug, Error, PartialEq)]
pub enum FunctionRegistrationError {
/// A function with the given name has already been registered.
///
/// Contains the duplicate function name.
#[error("a function has already been registered with name {0:?}")]
DuplicateName(Cow<'static, str>),
/// The function is missing a name by which it can be registered.
#[error("function name is missing")]
MissingName,
}

View File

@@ -0,0 +1,93 @@
use crate::{
func::{
args::{ArgCount, ArgList},
DynamicFunction, FunctionInfo, FunctionResult,
},
PartialReflect,
};
use alloc::borrow::Cow;
use core::fmt::Debug;
/// A trait used to power [function-like] operations via [reflection].
///
/// This trait allows types to be called like regular functions
/// with [`Reflect`]-based [arguments] and return values.
///
/// By default, this trait is currently only implemented for [`DynamicFunction`],
/// however, it is possible to implement this trait for custom function-like types.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunction, ArgList, Function};
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let func: Box<dyn Function> = Box::new(add.into_function());
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
/// let value = func.reflect_call(args).unwrap().unwrap_owned();
/// assert_eq!(value.try_take::<i32>().unwrap(), 100);
/// ```
///
/// [function-like]: crate::func
/// [reflection]: crate::Reflect
/// [`Reflect`]: crate::Reflect
/// [arguments]: crate::func::args
/// [`DynamicFunction`]: crate::func::DynamicFunction
pub trait Function: PartialReflect + Debug {
/// The name of the function, if any.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
fn name(&self) -> Option<&Cow<'static, str>>;
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// [overloaded]: crate::func#overloading-functions
fn arg_count(&self) -> ArgCount {
self.info().arg_count()
}
/// The [`FunctionInfo`] for this function.
fn info(&self) -> &FunctionInfo;
/// Call this function with the given arguments.
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
/// Clone this function into a [`DynamicFunction`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_function` instead")]
fn clone_dynamic(&self) -> DynamicFunction<'static> {
self.to_dynamic_function()
}
/// Creates a new [`DynamicFunction`] from this function.
fn to_dynamic_function(&self) -> DynamicFunction<'static>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::IntoFunction;
use alloc::boxed::Box;
#[test]
fn should_call_dyn_function() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let func: Box<dyn Function> = Box::new(add.into_function());
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let value = func.reflect_call(args).unwrap().unwrap_owned();
assert_eq!(value.try_take::<i32>().unwrap(), 100);
}
}

841
vendor/bevy_reflect/src/func/info.rs vendored Normal file
View File

@@ -0,0 +1,841 @@
use alloc::{borrow::Cow, boxed::Box, vec, vec::Vec};
use core::fmt::{Debug, Formatter};
use crate::{
func::args::{ArgCount, ArgCountOutOfBoundsError, ArgInfo, GetOwnership, Ownership},
func::signature::ArgumentSignature,
func::FunctionOverloadError,
type_info::impl_type_methods,
Type, TypePath,
};
use variadics_please::all_tuples;
/// Type information for a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// This information can be retrieved directly from certain functions and closures
/// using the [`TypedFunction`] trait, and manually constructed otherwise.
///
/// It is compromised of one or more [`SignatureInfo`] structs,
/// allowing it to represent functions with multiple sets of arguments (i.e. "overloaded functions").
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Clone)]
pub struct FunctionInfo {
name: Option<Cow<'static, str>>,
arg_count: ArgCount,
signatures: Box<[SignatureInfo]>,
}
impl FunctionInfo {
/// Create a new [`FunctionInfo`] for a function with the given signature.
///
/// # Panics
///
/// Panics if the given signature has more than the maximum number of arguments
/// as specified by [`ArgCount::MAX_COUNT`].
pub fn new(signature: SignatureInfo) -> Self {
Self {
name: signature.name.clone(),
arg_count: ArgCount::new(signature.arg_count()).unwrap(),
signatures: vec![signature].into(),
}
}
/// Create a new [`FunctionInfo`] from a set of signatures.
///
/// Returns an error if the given iterator is empty or contains duplicate signatures.
pub fn try_from_iter(
signatures: impl IntoIterator<Item = SignatureInfo>,
) -> Result<Self, FunctionOverloadError> {
let mut iter = signatures.into_iter();
let base = iter.next().ok_or(FunctionOverloadError::MissingSignature)?;
if base.arg_count() > ArgCount::MAX_COUNT {
return Err(FunctionOverloadError::TooManyArguments(
ArgumentSignature::from(&base),
));
}
let mut info = Self::new(base);
for signature in iter {
if signature.arg_count() > ArgCount::MAX_COUNT {
return Err(FunctionOverloadError::TooManyArguments(
ArgumentSignature::from(&signature),
));
}
info = info.with_overload(signature).map_err(|sig| {
FunctionOverloadError::DuplicateSignature(ArgumentSignature::from(&sig))
})?;
}
Ok(info)
}
/// The base signature for this function.
///
/// All functions—including overloaded functions—are guaranteed to have at least one signature.
/// The first signature used to define the [`FunctionInfo`] is considered the base signature.
pub fn base(&self) -> &SignatureInfo {
&self.signatures[0]
}
/// Whether this function is overloaded.
///
/// This is determined by the existence of multiple signatures.
pub fn is_overloaded(&self) -> bool {
self.signatures.len() > 1
}
/// Set the name of the function.
pub fn with_name(mut self, name: Option<impl Into<Cow<'static, str>>>) -> Self {
self.name = name.map(Into::into);
self
}
/// The name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`] or [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`std::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// For overloaded functions, this will be the name of the base signature,
/// unless manually overwritten using [`Self::with_name`].
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut
/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.name.as_ref()
}
/// Add a signature to this function.
///
/// If a signature with the same [`ArgumentSignature`] already exists,
/// an error is returned with the given signature.
///
/// # Panics
///
/// Panics if the given signature has more than the maximum number of arguments
/// as specified by [`ArgCount::MAX_COUNT`].
pub fn with_overload(mut self, signature: SignatureInfo) -> Result<Self, SignatureInfo> {
let is_duplicate = self.signatures.iter().any(|s| {
s.arg_count() == signature.arg_count()
&& ArgumentSignature::from(s) == ArgumentSignature::from(&signature)
});
if is_duplicate {
return Err(signature);
}
self.arg_count.add(signature.arg_count());
self.signatures = IntoIterator::into_iter(self.signatures)
.chain(Some(signature))
.collect();
Ok(self)
}
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// [overloaded]: crate::func#overloading-functions
pub fn arg_count(&self) -> ArgCount {
self.arg_count
}
/// The signatures of the function.
///
/// This is guaranteed to always contain at least one signature.
/// Overloaded functions will contain two or more.
pub fn signatures(&self) -> &[SignatureInfo] {
&self.signatures
}
/// Returns a wrapper around this info that implements [`Debug`] for pretty-printing the function.
///
/// This can be useful for more readable debugging and logging.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{FunctionInfo, TypedFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let info = add.get_function_info();
///
/// let pretty = info.pretty_printer();
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
/// ```
pub fn pretty_printer(&self) -> PrettyPrintFunctionInfo {
PrettyPrintFunctionInfo::new(self)
}
/// Extend this [`FunctionInfo`] with another without checking for duplicates.
///
/// # Panics
///
/// Panics if the given signature has more than the maximum number of arguments
/// as specified by [`ArgCount::MAX_COUNT`].
pub(super) fn extend_unchecked(&mut self, other: FunctionInfo) {
if self.name.is_none() {
self.name = other.name;
}
let signatures = core::mem::take(&mut self.signatures);
self.signatures = IntoIterator::into_iter(signatures)
.chain(IntoIterator::into_iter(other.signatures))
.collect();
self.arg_count = self
.signatures
.iter()
.fold(ArgCount::default(), |mut count, sig| {
count.add(sig.arg_count());
count
});
}
}
impl TryFrom<SignatureInfo> for FunctionInfo {
type Error = ArgCountOutOfBoundsError;
fn try_from(signature: SignatureInfo) -> Result<Self, Self::Error> {
let count = signature.arg_count();
if count > ArgCount::MAX_COUNT {
return Err(ArgCountOutOfBoundsError(count));
}
Ok(Self::new(signature))
}
}
impl TryFrom<Vec<SignatureInfo>> for FunctionInfo {
type Error = FunctionOverloadError;
fn try_from(signatures: Vec<SignatureInfo>) -> Result<Self, Self::Error> {
Self::try_from_iter(signatures)
}
}
impl<const N: usize> TryFrom<[SignatureInfo; N]> for FunctionInfo {
type Error = FunctionOverloadError;
fn try_from(signatures: [SignatureInfo; N]) -> Result<Self, Self::Error> {
Self::try_from_iter(signatures)
}
}
#[derive(Debug, Clone)]
pub struct SignatureInfo {
name: Option<Cow<'static, str>>,
args: Box<[ArgInfo]>,
return_info: ReturnInfo,
}
impl SignatureInfo {
/// Create a new [`SignatureInfo`] for a function with the given name.
pub fn named(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: Some(name.into()),
args: Box::new([]),
return_info: ReturnInfo::new::<()>(),
}
}
/// Create a new [`SignatureInfo`] with no name.
///
/// For the purposes of debugging and [registration],
/// it's recommended to use [`Self::named`] instead.
///
/// [registration]: crate::func::FunctionRegistry
pub fn anonymous() -> Self {
Self {
name: None,
args: Box::new([]),
return_info: ReturnInfo::new::<()>(),
}
}
/// Set the name of the function.
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.name = Some(name.into());
self
}
/// Push an argument onto the function's argument list.
///
/// The order in which this method is called matters as it will determine the index of the argument
/// based on the current number of arguments.
pub fn with_arg<T: TypePath + GetOwnership>(
mut self,
name: impl Into<Cow<'static, str>>,
) -> Self {
let index = self.args.len();
self.args = IntoIterator::into_iter(self.args)
.chain(Some(ArgInfo::new::<T>(index).with_name(name)))
.collect();
self
}
/// Set the arguments of the function.
///
/// This will completely replace any existing arguments.
///
/// It's preferable to use [`Self::with_arg`] to add arguments to the function
/// as it will automatically set the index of the argument.
pub fn with_args(mut self, args: Vec<ArgInfo>) -> Self {
self.args = IntoIterator::into_iter(self.args).chain(args).collect();
self
}
/// Set the [return information] of the function.
///
/// To manually set the [`ReturnInfo`] of the function, see [`Self::with_return_info`].
///
/// [return information]: ReturnInfo
pub fn with_return<T: TypePath + GetOwnership>(mut self) -> Self {
self.return_info = ReturnInfo::new::<T>();
self
}
/// Set the [return information] of the function.
///
/// This will completely replace any existing return information.
///
/// For a simpler, static version of this method, see [`Self::with_return`].
///
/// [return information]: ReturnInfo
pub fn with_return_info(mut self, return_info: ReturnInfo) -> Self {
self.return_info = return_info;
self
}
/// The name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`] or [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut
/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.name.as_ref()
}
/// The arguments of the function.
pub fn args(&self) -> &[ArgInfo] {
&self.args
}
/// The number of arguments the function takes.
pub fn arg_count(&self) -> usize {
self.args.len()
}
/// The return information of the function.
pub fn return_info(&self) -> &ReturnInfo {
&self.return_info
}
}
/// Information about the return type of a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Clone)]
pub struct ReturnInfo {
ty: Type,
ownership: Ownership,
}
impl ReturnInfo {
/// Create a new [`ReturnInfo`] representing the given type, `T`.
pub fn new<T: TypePath + GetOwnership>() -> Self {
Self {
ty: Type::of::<T>(),
ownership: T::ownership(),
}
}
impl_type_methods!(ty);
/// The ownership of this type.
pub fn ownership(&self) -> Ownership {
self.ownership
}
}
/// A wrapper around [`FunctionInfo`] that implements [`Debug`] for pretty-printing function information.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{FunctionInfo, PrettyPrintFunctionInfo, TypedFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let info = add.get_function_info();
///
/// let pretty = PrettyPrintFunctionInfo::new(&info);
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
/// ```
pub struct PrettyPrintFunctionInfo<'a> {
info: &'a FunctionInfo,
include_fn_token: bool,
include_name: bool,
}
impl<'a> PrettyPrintFunctionInfo<'a> {
/// Create a new pretty-printer for the given [`FunctionInfo`].
pub fn new(info: &'a FunctionInfo) -> Self {
Self {
info,
include_fn_token: false,
include_name: false,
}
}
/// Include the function name in the pretty-printed output.
pub fn include_name(mut self) -> Self {
self.include_name = true;
self
}
/// Include the `fn` token in the pretty-printed output.
pub fn include_fn_token(mut self) -> Self {
self.include_fn_token = true;
self
}
}
impl<'a> Debug for PrettyPrintFunctionInfo<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
if self.include_fn_token {
write!(f, "fn")?;
if self.include_name {
write!(f, " ")?;
}
}
match (self.include_name, self.info.name()) {
(true, Some(name)) => write!(f, "{}", name)?,
(true, None) => write!(f, "_")?,
_ => {}
}
if self.info.is_overloaded() {
// `{(arg0: i32, arg1: i32) -> (), (arg0: f32, arg1: f32) -> ()}`
let mut set = f.debug_set();
for signature in self.info.signatures() {
set.entry(&PrettyPrintSignatureInfo::new(signature));
}
set.finish()
} else {
// `(arg0: i32, arg1: i32) -> ()`
PrettyPrintSignatureInfo::new(self.info.base()).fmt(f)
}
}
}
/// A wrapper around [`SignatureInfo`] that implements [`Debug`] for pretty-printing function signature information.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{FunctionInfo, PrettyPrintSignatureInfo, TypedFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let info = add.get_function_info();
///
/// let pretty = PrettyPrintSignatureInfo::new(info.base());
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
/// ```
pub struct PrettyPrintSignatureInfo<'a> {
info: &'a SignatureInfo,
include_fn_token: bool,
include_name: bool,
}
impl<'a> PrettyPrintSignatureInfo<'a> {
/// Create a new pretty-printer for the given [`SignatureInfo`].
pub fn new(info: &'a SignatureInfo) -> Self {
Self {
info,
include_fn_token: false,
include_name: false,
}
}
/// Include the function name in the pretty-printed output.
pub fn include_name(mut self) -> Self {
self.include_name = true;
self
}
/// Include the `fn` token in the pretty-printed output.
pub fn include_fn_token(mut self) -> Self {
self.include_fn_token = true;
self
}
}
impl<'a> Debug for PrettyPrintSignatureInfo<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
if self.include_fn_token {
write!(f, "fn")?;
if self.include_name {
write!(f, " ")?;
}
}
match (self.include_name, self.info.name()) {
(true, Some(name)) => write!(f, "{}", name)?,
(true, None) => write!(f, "_")?,
_ => {}
}
write!(f, "(")?;
// We manually write the args instead of using `DebugTuple` to avoid trailing commas
// and (when used with `{:#?}`) unnecessary newlines
for (index, arg) in self.info.args().iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
let name = arg.name().unwrap_or("_");
let ty = arg.type_path();
write!(f, "{name}: {ty}")?;
}
let ret = self.info.return_info().type_path();
write!(f, ") -> {ret}")
}
}
/// A static accessor to compile-time type information for functions.
///
/// This is the equivalent of [`Typed`], but for function.
///
/// # Blanket Implementation
///
/// This trait has a blanket implementation that covers:
/// - Functions and methods defined with the `fn` keyword
/// - Anonymous functions
/// - Function pointers
/// - Closures that capture immutable references to their environment
/// - Closures that capture mutable references to their environment
/// - Closures that take ownership of captured variables
///
/// For each of the above cases, the function signature may only have up to 15 arguments,
/// not including an optional receiver argument (often `&self` or `&mut self`).
/// This optional receiver argument may be either a mutable or immutable reference to a type.
/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.
///
/// See the [module-level documentation] for more information on valid signatures.
///
/// Arguments and the return type are expected to implement both [`GetOwnership`] and [`TypePath`].
/// By default, these traits are automatically implemented when using the `Reflect` [derive macro].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgList, ReflectFnMut, TypedFunction};
/// #
/// fn print(value: String) {
/// println!("{}", value);
/// }
///
/// let info = print.get_function_info();
/// assert!(info.name().unwrap().ends_with("print"));
/// assert!(info.arg_count().contains(1));
/// assert_eq!(info.base().args()[0].type_path(), "alloc::string::String");
/// assert_eq!(info.base().return_info().type_path(), "()");
/// ```
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// [module-level documentation]: crate::func
/// [`Typed`]: crate::Typed
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait TypedFunction<Marker> {
/// Get the [`FunctionInfo`] for this type.
fn function_info() -> FunctionInfo;
/// Get the [`FunctionInfo`] for this type.
fn get_function_info(&self) -> FunctionInfo {
Self::function_info()
}
}
/// Helper macro for implementing [`TypedFunction`] on Rust functions.
///
/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):
/// - `FnMut(arg0, arg1, ..., argN) -> R`
/// - `FnMut(&Receiver, arg0, arg1, ..., argN) -> &R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &R`
macro_rules! impl_typed_function {
($(($Arg:ident, $arg:ident)),*) => {
// === (...) -> ReturnType === //
impl<$($Arg,)* ReturnType, Function> TypedFunction<fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: TypePath + GetOwnership,)*
ReturnType: TypePath + GetOwnership,
Function: FnMut($($Arg),*) -> ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 0;
vec![
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<ReturnType>())
)
}
}
// === (&self, ...) -> &ReturnType === //
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
for<'a> &'a Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&Receiver>(0),
$($crate::func::args::ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&ReturnType>())
)
}
}
// === (&mut self, ...) -> &mut ReturnType === //
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
for<'a> &'a mut Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a mut ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&mut Receiver>(0),
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&mut ReturnType>())
)
}
}
// === (&mut self, ...) -> &ReturnType === //
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
for<'a> &'a mut Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&mut Receiver>(0),
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&ReturnType>())
)
}
}
};
}
all_tuples!(impl_typed_function, 0, 15, Arg, arg);
/// Helper function for creating [`FunctionInfo`] with the proper name value.
///
/// Names are only given if:
/// - The function is not a closure
/// - The function is not a function pointer
/// - The function is not an anonymous function
///
/// This function relies on the [`type_name`] of `F` to determine this.
/// The following table describes the behavior for different types of functions:
///
/// | Category | `type_name` | `FunctionInfo::name` |
/// | ------------------ | ----------------------- | ----------------------- |
/// | Named function | `foo::bar::baz` | `Some("foo::bar::baz")` |
/// | Closure | `foo::bar::{{closure}}` | `None` |
/// | Anonymous function | `foo::bar::{{closure}}` | `None` |
/// | Function pointer | `fn() -> String` | `None` |
///
/// [`type_name`]: core::any::type_name
fn create_info<F>() -> SignatureInfo {
let name = core::any::type_name::<F>();
if name.ends_with("{{closure}}") || name.starts_with("fn(") {
SignatureInfo::anonymous()
} else {
SignatureInfo::named(name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_create_function_info() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
// Sanity check:
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_function_info::add"
);
let info = add.get_function_info();
assert_eq!(
info.name().unwrap(),
"bevy_reflect::func::info::tests::should_create_function_info::add"
);
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "i32");
}
#[test]
fn should_create_function_pointer_info() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let add = add as fn(i32, i32) -> i32;
// Sanity check:
assert_eq!(core::any::type_name_of_val(&add), "fn(i32, i32) -> i32");
let info = add.get_function_info();
assert!(info.name().is_none());
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "i32");
}
#[test]
fn should_create_anonymous_function_info() {
let add = |a: i32, b: i32| a + b;
// Sanity check:
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_anonymous_function_info::{{closure}}"
);
let info = add.get_function_info();
assert!(info.name().is_none());
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "i32");
}
#[test]
fn should_create_closure_info() {
let mut total = 0;
let add = |a: i32, b: i32| total = a + b;
// Sanity check:
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_closure_info::{{closure}}"
);
let info = add.get_function_info();
assert!(info.name().is_none());
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "()");
}
#[test]
fn should_pretty_print_info() {
// fn add(a: i32, b: i32) -> i32 {
// a + b
// }
//
// let info = add.get_function_info().with_name("add");
//
// let pretty = info.pretty_printer();
// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
//
// let pretty = info.pretty_printer().include_fn_token();
// assert_eq!(format!("{:?}", pretty), "fn(_: i32, _: i32) -> i32");
//
// let pretty = info.pretty_printer().include_name();
// assert_eq!(format!("{:?}", pretty), "add(_: i32, _: i32) -> i32");
//
// let pretty = info.pretty_printer().include_fn_token().include_name();
// assert_eq!(format!("{:?}", pretty), "fn add(_: i32, _: i32) -> i32");
}
}

View File

@@ -0,0 +1,68 @@
use crate::func::{DynamicFunction, ReflectFn, TypedFunction};
/// A trait for types that can be converted into a [`DynamicFunction`].
///
/// This trait is automatically implemented for any type that implements
/// [`ReflectFn`] and [`TypedFunction`].
///
/// See the [module-level documentation] for more information.
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [module-level documentation]: crate::func
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait IntoFunction<'env, Marker> {
/// Converts [`Self`] into a [`DynamicFunction`].
fn into_function(self) -> DynamicFunction<'env>;
}
impl<'env, F, Marker1, Marker2> IntoFunction<'env, (Marker1, Marker2)> for F
where
F: ReflectFn<'env, Marker1> + TypedFunction<Marker2> + Send + Sync + 'env,
{
fn into_function(self) -> DynamicFunction<'env> {
DynamicFunction::new(move |args| self.reflect_call(args), Self::function_info())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::ArgList;
#[test]
fn should_create_dynamic_function_from_closure() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_create_dynamic_function_from_function() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let func = add.into_function();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
fn should_default_closure_name_to_none() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
assert!(func.name().is_none());
}
}

View File

@@ -0,0 +1,83 @@
use crate::func::{DynamicFunctionMut, ReflectFnMut, TypedFunction};
/// A trait for types that can be converted into a [`DynamicFunctionMut`].
///
/// This trait is automatically implemented for any type that implements
/// [`ReflectFnMut`] and [`TypedFunction`].
///
/// This trait can be seen as a superset of [`IntoFunction`].
///
/// See the [module-level documentation] for more information.
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [`IntoFunction`]: crate::func::IntoFunction
/// [module-level documentation]: crate::func
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait IntoFunctionMut<'env, Marker> {
/// Converts [`Self`] into a [`DynamicFunctionMut`].
fn into_function_mut(self) -> DynamicFunctionMut<'env>;
}
impl<'env, F, Marker1, Marker2> IntoFunctionMut<'env, (Marker1, Marker2)> for F
where
F: ReflectFnMut<'env, Marker1> + TypedFunction<Marker2> + 'env,
{
fn into_function_mut(mut self) -> DynamicFunctionMut<'env> {
DynamicFunctionMut::new(
move |args| self.reflect_call_mut(args),
Self::function_info(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{ArgList, IntoFunction};
#[test]
fn should_create_dynamic_function_mut_from_closure() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_create_dynamic_function_mut_from_closure_with_mutable_capture() {
let mut total = 0;
let func = (|a: i32, b: i32| total = a + b).into_function_mut();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
func.call_once(args).unwrap();
assert_eq!(total, 100);
}
#[test]
fn should_create_dynamic_function_mut_from_function() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let mut func = add.into_function_mut();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
fn should_default_closure_name_to_none() {
let mut total = 0;
let func = (|a: i32, b: i32| total = a + b).into_function_mut();
assert!(func.name().is_none());
}
}

112
vendor/bevy_reflect/src/func/macros.rs vendored Normal file
View File

@@ -0,0 +1,112 @@
/// Helper macro to implement the necessary traits for function reflection.
///
/// This macro calls the following macros:
/// - [`impl_get_ownership`](crate::func::args::impl_get_ownership)
/// - [`impl_from_arg`](crate::func::args::impl_from_arg)
/// - [`impl_into_return`](crate::func::impl_into_return)
///
/// # Syntax
///
/// For non-generic types, the macro simply expects the type:
///
/// ```ignore
/// impl_function_traits!(foo::bar::Baz);
/// ```
///
/// For generic types, however, the generic type parameters must also be given in angle brackets (`<` and `>`):
///
/// ```ignore
/// impl_function_traits!(foo::bar::Baz<T, U>; <T: Clone, U>);
/// ```
///
/// For generic const parameters, they must be given in square brackets (`[` and `]`):
///
/// ```ignore
/// impl_function_traits!(foo::bar::Baz<T, N>; <T> [const N: usize]);
/// ```
macro_rules! impl_function_traits {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
$crate::func::args::impl_get_ownership!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
)?
$(
[
$(const $N : $size),*
]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
);
$crate::func::args::impl_from_arg!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
)?
$(
[
$(const $N : $size),*
]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
);
$crate::func::impl_into_return!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
)?
$(
[
$(const $N : $size),*
]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
);
};
}
pub(crate) use impl_function_traits;
/// Helper macro that returns the number of tokens it receives.
///
/// See [here] for details.
///
/// [here]: https://veykril.github.io/tlborm/decl-macros/building-blocks/counting.html#bit-twiddling
macro_rules! count_tokens {
() => { 0 };
($odd:tt $($a:tt $b:tt)*) => { ($crate::func::macros::count_tokens!($($a)*) << 1) | 1 };
($($a:tt $even:tt)*) => { $crate::func::macros::count_tokens!($($a)*) << 1 };
}
pub(crate) use count_tokens;

266
vendor/bevy_reflect/src/func/mod.rs vendored Normal file
View File

@@ -0,0 +1,266 @@
//! Reflection-based dynamic functions.
//!
//! This module provides a way to pass around and call functions dynamically
//! using the [`DynamicFunction`] and [`DynamicFunctionMut`] types.
//!
//! Many simple functions and closures can be automatically converted to these types
//! using the [`IntoFunction`] and [`IntoFunctionMut`] traits, respectively.
//!
//! Once this dynamic representation is created, it can be called with a set of arguments provided
//! via an [`ArgList`].
//!
//! This returns a [`FunctionResult`] containing the [`Return`] value,
//! which can be used to extract a [`PartialReflect`] trait object.
//!
//! # Example
//!
//! ```
//! # use bevy_reflect::PartialReflect;
//! # use bevy_reflect::func::args::ArgList;
//! # use bevy_reflect::func::{DynamicFunction, FunctionResult, IntoFunction, Return};
//! fn add(a: i32, b: i32) -> i32 {
//! a + b
//! }
//!
//! let mut func: DynamicFunction = add.into_function();
//! let args: ArgList = ArgList::default()
//! // Pushing a known type with owned ownership
//! .with_owned(25_i32)
//! // Pushing a reflected type with owned ownership
//! .with_boxed(Box::new(75_i32) as Box<dyn PartialReflect>);
//! let result: FunctionResult = func.call(args);
//! let value: Return = result.unwrap();
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&100));
//! ```
//!
//! # Types of Functions
//!
//! For simplicity, this module uses the umbrella term "function" to refer to any Rust callable:
//! code that can be invoked with a set of arguments to perform some action.
//!
//! In Rust, there are two main categories of callables: functions and closures.
//!
//! A "function" is a callable that does not capture its environment.
//! These are typically defined with the `fn` keyword, which are referred to as _named_ functions.
//! But they are also _anonymous_ functions, which are unnamed and defined with anonymous function syntax.
//!
//! ```rust
//! // This is a named function:
//! fn add(a: i32, b: i32) -> i32 {
//! a + b
//! }
//!
//! // This is an anonymous function:
//! let add = |a: i32, b: i32| a + b;
//! ```
//!
//! Closures, on the other hand, are special functions that do capture their environment.
//! These are always defined with anonymous function syntax.
//!
//! ```
//! // A closure that captures an immutable reference to a variable
//! let c = 123;
//! let add = |a: i32, b: i32| a + b + c;
//!
//! // A closure that captures a mutable reference to a variable
//! let mut total = 0;
//! let add = |a: i32, b: i32| total += a + b;
//!
//! // A closure that takes ownership of its captured variables by moving them
//! let c = 123;
//! let add = move |a: i32, b: i32| a + b + c;
//! ```
//!
//! # Valid Signatures
//!
//! Many of the traits in this module have default blanket implementations over a specific set of function signatures.
//!
//! These signatures are:
//! - `(...) -> R`
//! - `for<'a> (&'a arg, ...) -> &'a R`
//! - `for<'a> (&'a mut arg, ...) -> &'a R`
//! - `for<'a> (&'a mut arg, ...) -> &'a mut R`
//!
//! Where `...` represents 0 to 15 arguments (inclusive) of the form `T`, `&T`, or `&mut T`.
//! The lifetime of any reference to the return type `R`, must be tied to a "receiver" argument
//! (i.e. the first argument in the signature, normally `self`).
//!
//! Each trait will also have its own requirements for what traits are required for both arguments and return types,
//! but a good rule-of-thumb is that all types should derive [`Reflect`].
//!
//! The reason for such a small subset of valid signatures is due to limitations in Rust—
//! namely the [lack of variadic generics] and certain [coherence issues].
//!
//! For other functions that don't conform to one of the above signatures,
//! [`DynamicFunction`] and [`DynamicFunctionMut`] can instead be created manually.
//!
//! # Generic Functions
//!
//! In Rust, generic functions are [monomorphized] by the compiler,
//! which means that a separate copy of the function is generated for each concrete set of type parameters.
//!
//! When converting a generic function to a [`DynamicFunction`] or [`DynamicFunctionMut`],
//! the function must be manually monomorphized with concrete types.
//! In other words, you cannot write `add<T>.into_function()`.
//! Instead, you will need to write `add::<i32>.into_function()`.
//!
//! This means that reflected functions cannot be generic themselves.
//! To get around this limitation, you can consider [overloading] your function with multiple concrete types.
//!
//! # Overloading Functions
//!
//! Both [`DynamicFunction`] and [`DynamicFunctionMut`] support [function overloading].
//!
//! Function overloading allows one function to handle multiple types of arguments.
//! This is useful for simulating generic functions by having an overload for each known concrete type.
//! Additionally, it can also simulate [variadic functions]: functions that can be called with a variable number of arguments.
//!
//! Internally, this works by storing multiple functions in a map,
//! where each function is associated with a specific argument signature.
//!
//! To learn more, see the docs on [`DynamicFunction::with_overload`].
//!
//! # Function Registration
//!
//! This module also provides a [`FunctionRegistry`] that can be used to register functions and closures
//! by name so that they may be retrieved and called dynamically.
//!
//! ```
//! # use bevy_reflect::func::{ArgList, FunctionRegistry};
//! fn add(a: i32, b: i32) -> i32 {
//! a + b
//! }
//!
//! let mut registry = FunctionRegistry::default();
//!
//! // You can register functions and methods by their `core::any::type_name`:
//! registry.register(add).unwrap();
//!
//! // Or you can register them by a custom name:
//! registry.register_with_name("mul", |a: i32, b: i32| a * b).unwrap();
//!
//! // You can then retrieve and call these functions by name:
//! let reflect_add = registry.get(core::any::type_name_of_val(&add)).unwrap();
//! let value = reflect_add.call(ArgList::default().with_owned(10_i32).with_owned(5_i32)).unwrap();
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&15));
//!
//! let reflect_mul = registry.get("mul").unwrap();
//! let value = reflect_mul.call(ArgList::default().with_owned(10_i32).with_owned(5_i32)).unwrap();
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&50));
//! ```
//!
//! [`PartialReflect`]: crate::PartialReflect
//! [`Reflect`]: crate::Reflect
//! [lack of variadic generics]: https://poignardazur.github.io/2024/05/25/report-on-rustnl-variadics/
//! [coherence issues]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#coherence-leak-check
//! [monomorphized]: https://en.wikipedia.org/wiki/Monomorphization
//! [overloading]: #overloading-functions
//! [function overloading]: https://en.wikipedia.org/wiki/Function_overloading
//! [variadic functions]: https://en.wikipedia.org/wiki/Variadic_function
pub use args::{ArgError, ArgList, ArgValue};
pub use dynamic_function::*;
pub use dynamic_function_mut::*;
pub use error::*;
pub use function::*;
pub use info::*;
pub use into_function::*;
pub use into_function_mut::*;
pub use reflect_fn::*;
pub use reflect_fn_mut::*;
pub use registry::*;
pub use return_type::*;
pub mod args;
mod dynamic_function;
mod dynamic_function_internal;
mod dynamic_function_mut;
mod error;
mod function;
mod info;
mod into_function;
mod into_function_mut;
pub(crate) mod macros;
mod reflect_fn;
mod reflect_fn_mut;
mod registry;
mod return_type;
pub mod signature;
#[cfg(test)]
mod tests {
use alloc::borrow::Cow;
use super::*;
use crate::func::args::ArgCount;
use crate::{
func::args::{ArgError, ArgList, Ownership},
TypePath,
};
#[test]
fn should_error_on_missing_args() {
fn foo(_: i32) {}
let func = foo.into_function();
let args = ArgList::new();
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgCountMismatch {
expected: ArgCount::new(1).unwrap(),
received: 0
}
);
}
#[test]
fn should_error_on_too_many_args() {
fn foo() {}
let func = foo.into_function();
let args = ArgList::new().with_owned(123_i32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgCountMismatch {
expected: ArgCount::new(0).unwrap(),
received: 1
}
);
}
#[test]
fn should_error_on_invalid_arg_type() {
fn foo(_: i32) {}
let func = foo.into_function();
let args = ArgList::new().with_owned(123_u32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgError(ArgError::UnexpectedType {
index: 0,
expected: Cow::Borrowed(i32::type_path()),
received: Cow::Borrowed(u32::type_path())
})
);
}
#[test]
fn should_error_on_invalid_arg_ownership() {
fn foo(_: &i32) {}
let func = foo.into_function();
let args = ArgList::new().with_owned(123_i32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgError(ArgError::InvalidOwnership {
index: 0,
expected: Ownership::Ref,
received: Ownership::Owned
})
);
}
}

View File

@@ -0,0 +1,208 @@
use variadics_please::all_tuples;
use crate::{
func::{
args::{ArgCount, FromArg},
macros::count_tokens,
ArgList, FunctionError, FunctionResult, IntoReturn, ReflectFnMut,
},
Reflect, TypePath,
};
/// A reflection-based version of the [`Fn`] trait.
///
/// This allows functions to be called dynamically through [reflection].
///
/// # Blanket Implementation
///
/// This trait has a blanket implementation that covers:
/// - Functions and methods defined with the `fn` keyword
/// - Anonymous functions
/// - Function pointers
/// - Closures that capture immutable references to their environment
/// - Closures that take ownership of captured variables
///
/// For each of the above cases, the function signature may only have up to 15 arguments,
/// not including an optional receiver argument (often `&self` or `&mut self`).
/// This optional receiver argument may be either a mutable or immutable reference to a type.
/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.
///
/// See the [module-level documentation] for more information on valid signatures.
///
/// To handle functions that capture mutable references to their environment,
/// see the [`ReflectFnMut`] trait instead.
///
/// Arguments are expected to implement [`FromArg`], and the return type is expected to implement [`IntoReturn`].
/// Both of these traits are automatically implemented when using the `Reflect` [derive macro].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFn};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
///
/// let value = add.reflect_call(args).unwrap().unwrap_owned();
/// assert_eq!(value.try_take::<i32>().unwrap(), 100);
/// ```
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [reflection]: crate
/// [module-level documentation]: crate::func
/// [derive macro]: derive@crate::Reflect
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait ReflectFn<'env, Marker>: ReflectFnMut<'env, Marker> {
/// Call the function with the given arguments and return the result.
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
}
/// Helper macro for implementing [`ReflectFn`] on Rust functions.
///
/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):
/// - `Fn(arg0, arg1, ..., argN) -> R`
/// - `Fn(&Receiver, arg0, arg1, ..., argN) -> &R`
/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`
/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &R`
macro_rules! impl_reflect_fn {
($(($Arg:ident, $arg:ident)),*) => {
// === (...) -> ReturnType === //
impl<'env, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: FromArg,)*
// This clause allows us to convert `ReturnType` into `Return`
ReturnType: IntoReturn + Reflect,
Function: Fn($($Arg),*) -> ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn($($Arg::This<'a>),*) -> ReturnType + 'env,
{
#[expect(
clippy::allow_attributes,
reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."
)]
#[allow(
unused_mut,
reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."
)]
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!($($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)($($arg,)*).into_return())
}
}
// === (&self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> Fn(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_ref::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &mut ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&mut ReturnType` into `Return`
for<'a> &'a mut ReturnType: IntoReturn,
Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
};
}
all_tuples!(impl_reflect_fn, 0, 15, Arg, arg);

View File

@@ -0,0 +1,215 @@
use variadics_please::all_tuples;
use crate::{
func::{
args::{ArgCount, FromArg},
macros::count_tokens,
ArgList, FunctionError, FunctionResult, IntoReturn,
},
Reflect, TypePath,
};
/// A reflection-based version of the [`FnMut`] trait.
///
/// This allows functions to be called dynamically through [reflection].
///
/// This is a supertrait of [`ReflectFn`], and is used for functions that may mutate their environment,
/// such as closures that capture mutable references.
///
/// # Blanket Implementation
///
/// This trait has a blanket implementation that covers everything that [`ReflectFn`] does:
/// - Functions and methods defined with the `fn` keyword
/// - Anonymous functions
/// - Function pointers
/// - Closures that capture immutable references to their environment
/// - Closures that take ownership of captured variables
///
/// But also allows for:
/// - Closures that capture mutable references to their environment
///
/// For each of the above cases, the function signature may only have up to 15 arguments,
/// not including an optional receiver argument (often `&self` or `&mut self`).
/// This optional receiver argument may be either a mutable or immutable reference to a type.
/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.
///
/// See the [module-level documentation] for more information on valid signatures.
///
/// Arguments are expected to implement [`FromArg`], and the return type is expected to implement [`IntoReturn`].
/// Both of these traits are automatically implemented when using the `Reflect` [derive macro].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFnMut};
/// #
/// let mut list: Vec<i32> = vec![1, 3];
///
/// // `insert` is a closure that captures a mutable reference to `list`
/// let mut insert = |index: usize, value: i32| {
/// list.insert(index, value);
/// };
///
/// let args = ArgList::new().with_owned(1_usize).with_owned(2_i32);
///
/// insert.reflect_call_mut(args).unwrap();
/// assert_eq!(list, vec![1, 2, 3]);
/// ```
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [reflection]: crate
/// [`ReflectFn`]: crate::func::ReflectFn
/// [module-level documentation]: crate::func
/// [derive macro]: derive@crate::Reflect
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait ReflectFnMut<'env, Marker> {
/// Call the function with the given arguments and return the result.
fn reflect_call_mut<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a>;
}
/// Helper macro for implementing [`ReflectFnMut`] on Rust functions.
///
/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):
/// - `FnMut(arg0, arg1, ..., argN) -> R`
/// - `FnMut(&Receiver, arg0, arg1, ..., argN) -> &R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &R`
macro_rules! impl_reflect_fn_mut {
($(($Arg:ident, $arg:ident)),*) => {
// === (...) -> ReturnType === //
impl<'env, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: FromArg,)*
// This clause allows us to convert `ReturnType` into `Return`
ReturnType: IntoReturn + Reflect,
Function: FnMut($($Arg),*) -> ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut($($Arg::This<'a>),*) -> ReturnType + 'env,
{
#[expect(
clippy::allow_attributes,
reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."
)]
#[allow(
unused_mut,
reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."
)]
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!($($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)($($arg,)*).into_return())
}
}
// === (&self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_ref::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &mut ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&mut ReturnType` into `Return`
for<'a> &'a mut ReturnType: IntoReturn,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,
{
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
};
}
all_tuples!(impl_reflect_fn_mut, 0, 15, Arg, arg);

526
vendor/bevy_reflect/src/func/registry.rs vendored Normal file
View File

@@ -0,0 +1,526 @@
use alloc::borrow::Cow;
use bevy_platform::{
collections::HashMap,
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use core::fmt::Debug;
use crate::func::{
ArgList, DynamicFunction, FunctionRegistrationError, FunctionResult, IntoFunction,
};
/// A registry of [reflected functions].
///
/// This is the function-equivalent to the [`TypeRegistry`].
///
/// All functions must be `'static` as they are stored as [`DynamicFunction<'static>`].
///
/// [reflected functions]: crate::func
/// [`TypeRegistry`]: crate::TypeRegistry
#[derive(Default)]
pub struct FunctionRegistry {
/// Maps function [names] to their respective [`DynamicFunctions`].
///
/// [names]: DynamicFunction::name
/// [`DynamicFunctions`]: DynamicFunction
functions: HashMap<Cow<'static, str>, DynamicFunction<'static>>,
}
impl FunctionRegistry {
/// Attempts to register the given function.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// and mapped according to its [name].
///
/// Because the function must have a name,
/// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead
/// be registered using [`register_with_name`] or manually converted to a [`DynamicFunction`]
/// and named using [`DynamicFunction::with_name`].
/// Failure to do so will result in an error being returned.
///
/// If a registered function with the same name already exists,
/// it will not be registered again and an error will be returned.
/// To register the function anyway, overwriting any existing registration,
/// use [`overwrite_registration`] instead.
///
/// # Examples
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry};
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// # fn main() -> Result<(), FunctionRegistrationError> {
/// let mut registry = FunctionRegistry::default();
/// registry.register(add)?;
/// # Ok(())
/// # }
/// ```
///
/// Functions cannot be registered more than once.
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry, IntoFunction};
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let mut registry = FunctionRegistry::default();
/// registry.register(add).unwrap();
///
/// let result = registry.register(add);
/// assert!(matches!(result, Err(FunctionRegistrationError::DuplicateName(_))));
///
/// // Note that this simply relies on the name of the function to determine uniqueness.
/// // You can rename the function to register a separate instance of it.
/// let result = registry.register(add.into_function().with_name("add2"));
/// assert!(result.is_ok());
/// ```
///
/// Anonymous functions and closures should be registered using [`register_with_name`] or given a name using [`DynamicFunction::with_name`].
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry, IntoFunction};
///
/// let anonymous = || -> i32 { 123 };
///
/// let mut registry = FunctionRegistry::default();
///
/// let result = registry.register(|a: i32, b: i32| a + b);
/// assert!(matches!(result, Err(FunctionRegistrationError::MissingName)));
///
/// let result = registry.register_with_name("my_crate::add", |a: i32, b: i32| a + b);
/// assert!(result.is_ok());
///
/// let result = registry.register((|a: i32, b: i32| a * b).into_function().with_name("my_crate::mul"));
/// assert!(result.is_ok());
/// ```
///
/// [name]: DynamicFunction::name
/// [`register_with_name`]: Self::register_with_name
/// [`overwrite_registration`]: Self::overwrite_registration
pub fn register<F, Marker>(
&mut self,
function: F,
) -> Result<&mut Self, FunctionRegistrationError>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function();
let name = function
.name()
.ok_or(FunctionRegistrationError::MissingName)?
.clone();
self.functions
.try_insert(name, function.into_function())
.map_err(|err| FunctionRegistrationError::DuplicateName(err.entry.key().clone()))?;
Ok(self)
}
/// Attempts to register the given function with the given name.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// with its [name] set to the given name.
///
/// For named functions (e.g. `fn add(a: i32, b: i32) -> i32 { a + b }`) where a custom name is not needed,
/// it's recommended to use [`register`] instead as the generated name is guaranteed to be unique.
///
/// If a registered function with the same name already exists,
/// it will not be registered again and an error will be returned.
/// To register the function anyway, overwriting any existing registration,
/// use [`overwrite_registration_with_name`] instead.
///
/// To avoid conflicts, it's recommended to use a unique name for the function.
/// This can be achieved by "namespacing" the function with a unique identifier,
/// such as the name of your crate.
///
/// For example, to register a function, `add`, from a crate, `my_crate`,
/// you could use the name, `"my_crate::add"`.
///
/// Another approach could be to use the [type name] of the function,
/// however, it should be noted that anonymous functions and closures
/// are not guaranteed to have unique type names.
///
/// This method is a convenience around calling [`IntoFunction::into_function`] and [`DynamicFunction::with_name`]
/// on the function and inserting it into the registry using the [`register`] method.
///
/// # Examples
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry};
/// # fn main() -> Result<(), FunctionRegistrationError> {
/// fn mul(a: i32, b: i32) -> i32 {
/// a * b
/// }
///
/// let div = |a: i32, b: i32| a / b;
///
/// let mut registry = FunctionRegistry::default();
/// registry
/// // Registering an anonymous function with a unique name
/// .register_with_name("my_crate::add", |a: i32, b: i32| {
/// a + b
/// })?
/// // Registering an existing function with its type name
/// .register_with_name(core::any::type_name_of_val(&mul), mul)?
/// // Registering an existing function with a custom name
/// .register_with_name("my_crate::mul", mul)?;
///
/// // Be careful not to register anonymous functions with their type name.
/// // This code works but registers the function with a non-unique name like `foo::bar::{{closure}}`
/// registry.register_with_name(core::any::type_name_of_val(&div), div)?;
/// # Ok(())
/// # }
/// ```
///
/// Names must be unique.
///
/// ```should_panic
/// # use bevy_reflect::func::FunctionRegistry;
/// fn one() {}
/// fn two() {}
///
/// let mut registry = FunctionRegistry::default();
/// registry.register_with_name("my_function", one).unwrap();
///
/// // Panic! A function has already been registered with the name "my_function"
/// registry.register_with_name("my_function", two).unwrap();
/// ```
///
/// [name]: DynamicFunction::name
/// [`register`]: Self::register
/// [`overwrite_registration_with_name`]: Self::overwrite_registration_with_name
/// [type name]: core::any::type_name
pub fn register_with_name<F, Marker>(
&mut self,
name: impl Into<Cow<'static, str>>,
function: F,
) -> Result<&mut Self, FunctionRegistrationError>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function().with_name(name);
self.register(function)
}
/// Registers the given function, overwriting any existing registration.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// and mapped according to its [name].
///
/// Because the function must have a name,
/// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead
/// be registered using [`overwrite_registration_with_name`] or manually converted to a [`DynamicFunction`]
/// and named using [`DynamicFunction::with_name`].
/// Failure to do so will result in an error being returned.
///
/// To avoid overwriting existing registrations,
/// it's recommended to use the [`register`] method instead.
///
/// Returns the previous function with the same name, if any.
///
/// [name]: DynamicFunction::name
/// [`overwrite_registration_with_name`]: Self::overwrite_registration_with_name
/// [`register`]: Self::register
pub fn overwrite_registration<F, Marker>(
&mut self,
function: F,
) -> Result<Option<DynamicFunction<'static>>, FunctionRegistrationError>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function();
let name = function
.name()
.ok_or(FunctionRegistrationError::MissingName)?
.clone();
Ok(self.functions.insert(name, function))
}
/// Registers the given function, overwriting any existing registration.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// with its [name] set to the given name.
///
/// Functions are mapped according to their name.
/// To avoid overwriting existing registrations,
/// it's recommended to use the [`register_with_name`] method instead.
///
/// This method is a convenience around calling [`IntoFunction::into_function`] and [`DynamicFunction::with_name`]
/// on the function and inserting it into the registry using the [`overwrite_registration`] method.
///
/// Returns the previous function with the same name, if any.
///
/// [name]: DynamicFunction::name
/// [`register_with_name`]: Self::register_with_name
/// [`overwrite_registration`]: Self::overwrite_registration
pub fn overwrite_registration_with_name<F, Marker>(
&mut self,
name: impl Into<Cow<'static, str>>,
function: F,
) -> Option<DynamicFunction<'static>>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function().with_name(name);
match self.overwrite_registration(function) {
Ok(existing) => existing,
Err(FunctionRegistrationError::MissingName) => {
unreachable!("the function should have a name")
}
Err(FunctionRegistrationError::DuplicateName(_)) => {
unreachable!("should overwrite functions with the same name")
}
}
}
/// Calls the function with the given [name] and [args].
///
/// Returns `None` if no function with the given name is registered.
/// Otherwise, returns the result of the function call.
///
/// [name]: DynamicFunction::name
/// [args]: ArgList
pub fn call<'a>(&self, name: &str, args: ArgList<'a>) -> Option<FunctionResult<'a>> {
let func = self.get(name)?;
Some(func.call(args))
}
/// Get a reference to a registered function by [name].
///
/// [name]: DynamicFunction::name
pub fn get(&self, name: &str) -> Option<&DynamicFunction<'static>> {
self.functions.get(name)
}
/// Returns `true` if a function with the given [name] is registered.
///
/// [name]: DynamicFunction::name
pub fn contains(&self, name: &str) -> bool {
self.functions.contains_key(name)
}
/// Returns an iterator over all registered functions.
pub fn iter(&self) -> impl ExactSizeIterator<Item = &DynamicFunction<'static>> {
self.functions.values()
}
/// Returns the number of registered functions.
pub fn len(&self) -> usize {
self.functions.len()
}
/// Returns `true` if no functions are registered.
pub fn is_empty(&self) -> bool {
self.functions.is_empty()
}
}
impl Debug for FunctionRegistry {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_set().entries(self.functions.values()).finish()
}
}
/// A synchronized wrapper around a [`FunctionRegistry`].
#[derive(Clone, Default, Debug)]
pub struct FunctionRegistryArc {
pub internal: Arc<RwLock<FunctionRegistry>>,
}
impl FunctionRegistryArc {
/// Takes a read lock on the underlying [`FunctionRegistry`].
pub fn read(&self) -> RwLockReadGuard<'_, FunctionRegistry> {
self.internal.read().unwrap_or_else(PoisonError::into_inner)
}
/// Takes a write lock on the underlying [`FunctionRegistry`].
pub fn write(&self) -> RwLockWriteGuard<'_, FunctionRegistry> {
self.internal
.write()
.unwrap_or_else(PoisonError::into_inner)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{ArgList, IntoFunction};
use alloc::format;
#[test]
fn should_register_function() {
fn foo() -> i32 {
123
}
let mut registry = FunctionRegistry::default();
registry.register(foo).unwrap();
let function = registry.get(core::any::type_name_of_val(&foo)).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_anonymous_function() {
let mut registry = FunctionRegistry::default();
registry.register_with_name("foo", || 123_i32).unwrap();
let function = registry.get("foo").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_closure() {
let value = 123;
let foo = move || -> i32 { value };
let mut registry = FunctionRegistry::default();
registry.register_with_name("foo", foo).unwrap();
let function = registry.get("foo").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_dynamic_function() {
fn foo() -> i32 {
123
}
let function = foo.into_function().with_name("custom_name");
let mut registry = FunctionRegistry::default();
registry.register(function).unwrap();
let function = registry.get("custom_name").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_dynamic_closure() {
let value = 123;
let foo = move || -> i32 { value };
let function = foo.into_function().with_name("custom_name");
let mut registry = FunctionRegistry::default();
registry.register(function).unwrap();
let function = registry.get("custom_name").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_only_register_function_once() {
fn foo() -> i32 {
123
}
fn bar() -> i32 {
321
}
let name = core::any::type_name_of_val(&foo);
let mut registry = FunctionRegistry::default();
registry.register(foo).unwrap();
let result = registry.register(bar.into_function().with_name(name));
assert!(matches!(
result,
Err(FunctionRegistrationError::DuplicateName(_))
));
assert_eq!(registry.len(), 1);
let function = registry.get(name).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_allow_overwriting_registration() {
fn foo() -> i32 {
123
}
fn bar() -> i32 {
321
}
let name = core::any::type_name_of_val(&foo);
let mut registry = FunctionRegistry::default();
registry.register(foo).unwrap();
registry
.overwrite_registration(bar.into_function().with_name(name))
.unwrap();
assert_eq!(registry.len(), 1);
let function = registry.get(name).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&321));
}
#[test]
fn should_call_function_via_registry() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let mut registry = FunctionRegistry::default();
registry.register(add).unwrap();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = registry
.call(core::any::type_name_of_val(&add), args)
.unwrap();
let value = result.unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
fn should_error_on_missing_name() {
let foo = || -> i32 { 123 };
let function = foo.into_function();
let mut registry = FunctionRegistry::default();
let result = registry.register(function);
assert!(matches!(
result,
Err(FunctionRegistrationError::MissingName)
));
}
#[test]
fn should_debug_function_registry() {
fn foo() -> i32 {
123
}
let mut registry = FunctionRegistry::default();
registry.register_with_name("foo", foo).unwrap();
let debug = format!("{:?}", registry);
assert_eq!(debug, "{DynamicFunction(fn foo() -> i32)}");
}
}

View File

@@ -0,0 +1,166 @@
use crate::PartialReflect;
use alloc::boxed::Box;
/// The return type of a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug)]
pub enum Return<'a> {
/// The function returns an owned value.
///
/// This includes functions that return nothing (i.e. they return `()`).
Owned(Box<dyn PartialReflect>),
/// The function returns a reference to a value.
Ref(&'a dyn PartialReflect),
/// The function returns a mutable reference to a value.
Mut(&'a mut dyn PartialReflect),
}
impl<'a> Return<'a> {
/// Creates an [`Owned`](Self::Owned) unit (`()`) type.
pub fn unit() -> Self {
Self::Owned(Box::new(()))
}
/// Returns `true` if the return value is an [`Owned`](Self::Owned) unit (`()`) type.
pub fn is_unit(&self) -> bool {
match self {
Return::Owned(val) => val.represents::<()>(),
_ => false,
}
}
/// Unwraps the return value as an owned value.
///
/// # Panics
///
/// Panics if the return value is not [`Self::Owned`].
pub fn unwrap_owned(self) -> Box<dyn PartialReflect> {
match self {
Return::Owned(value) => value,
_ => panic!("expected owned value"),
}
}
/// Unwraps the return value as a reference to a value.
///
/// # Panics
///
/// Panics if the return value is not [`Self::Ref`].
pub fn unwrap_ref(self) -> &'a dyn PartialReflect {
match self {
Return::Ref(value) => value,
_ => panic!("expected reference value"),
}
}
/// Unwraps the return value as a mutable reference to a value.
///
/// # Panics
///
/// Panics if the return value is not [`Self::Mut`].
pub fn unwrap_mut(self) -> &'a mut dyn PartialReflect {
match self {
Return::Mut(value) => value,
_ => panic!("expected mutable reference value"),
}
}
}
/// A trait for types that can be converted into a [`Return`] value.
///
/// This trait exists so that types can be automatically converted into a [`Return`]
/// by [`ReflectFn`] and [`ReflectFnMut`].
///
/// This trait is used instead of a blanket [`Into`] implementation due to coherence issues:
/// we can't implement `Into<Return>` for both `T` and `&T`/`&mut T`.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
///
/// [`ReflectFn`]: crate::func::ReflectFn
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
/// [derive macro]: derive@crate::Reflect
pub trait IntoReturn {
/// Converts [`Self`] into a [`Return`] value.
fn into_return<'a>(self) -> Return<'a>
where
Self: 'a;
}
impl IntoReturn for () {
fn into_return<'a>(self) -> Return<'a> {
Return::unit()
}
}
/// Implements the [`IntoReturn`] trait for the given type.
///
/// This will implement it for `ty`, `&ty`, and `&mut ty`.
///
/// See [`impl_function_traits`] for details on syntax.
///
/// [`impl_function_traits`]: crate::func::macros::impl_function_traits
macro_rules! impl_into_return {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Owned(Box::new(self))
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for &'static $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Ref(self)
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for &'static mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Mut(self)
}
}
};
}
pub(crate) use impl_into_return;

View File

@@ -0,0 +1,236 @@
//! Function signature types.
//!
//! Function signatures differ from [`FunctionInfo`] and [`SignatureInfo`] in that they
//! are only concerned about the types and order of the arguments and return type of a function.
//!
//! The names of arguments do not matter,
//! nor does any other information about the function such as its name or other attributes.
//!
//! This makes signatures useful for comparing or hashing functions strictly based on their
//! arguments and return type.
//!
//! [`FunctionInfo`]: crate::func::info::FunctionInfo
use crate::func::args::ArgInfo;
use crate::func::{ArgList, SignatureInfo};
use crate::Type;
use alloc::boxed::Box;
use bevy_platform::collections::Equivalent;
use core::borrow::Borrow;
use core::fmt::{Debug, Formatter};
use core::hash::{Hash, Hasher};
use core::ops::{Deref, DerefMut};
/// The signature of a function.
///
/// This can be used as a way to compare or hash functions based on their arguments and return type.
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Signature {
args: ArgumentSignature,
ret: Type,
}
impl Signature {
/// Create a new function signature with the given argument signature and return type.
pub fn new(args: ArgumentSignature, ret: Type) -> Self {
Self { args, ret }
}
/// Get the argument signature of the function.
pub fn args(&self) -> &ArgumentSignature {
&self.args
}
/// Get the return type of the function.
pub fn return_type(&self) -> &Type {
&self.ret
}
}
impl Debug for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?} -> {:?}", self.args, self.ret)
}
}
impl<T: Borrow<SignatureInfo>> From<T> for Signature {
fn from(info: T) -> Self {
let info = info.borrow();
Self::new(ArgumentSignature::from(info), *info.return_info().ty())
}
}
/// A wrapper around a borrowed [`ArgList`] that can be used as an
/// [equivalent] of an [`ArgumentSignature`].
///
/// [equivalent]: Equivalent
pub(super) struct ArgListSignature<'a, 'b>(&'a ArgList<'b>);
impl Equivalent<ArgumentSignature> for ArgListSignature<'_, '_> {
fn equivalent(&self, key: &ArgumentSignature) -> bool {
self.len() == key.len() && self.iter().eq(key.iter())
}
}
impl<'a, 'b> ArgListSignature<'a, 'b> {
pub fn iter(&self) -> impl ExactSizeIterator<Item = &Type> {
self.0.iter().map(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
})
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl Eq for ArgListSignature<'_, '_> {}
impl PartialEq for ArgListSignature<'_, '_> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().eq(other.iter())
}
}
impl Hash for ArgListSignature<'_, '_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.iter().for_each(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
.hash(state);
});
}
}
impl<'a, 'b> From<&'a ArgList<'b>> for ArgListSignature<'a, 'b> {
fn from(args: &'a ArgList<'b>) -> Self {
Self(args)
}
}
/// The argument-portion of a function signature.
///
/// For example, given a function signature `(a: i32, b: f32) -> u32`,
/// the argument signature would be `(i32, f32)`.
///
/// This can be used as a way to compare or hash functions based on their arguments.
#[derive(Clone)]
pub struct ArgumentSignature(Box<[Type]>);
impl Debug for ArgumentSignature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut tuple = f.debug_tuple("");
for ty in self.0.iter() {
tuple.field(ty);
}
tuple.finish()
}
}
impl Deref for ArgumentSignature {
type Target = [Type];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ArgumentSignature {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Eq for ArgumentSignature {}
impl PartialEq for ArgumentSignature {
fn eq(&self, other: &Self) -> bool {
self.0.len() == other.0.len() && self.0.iter().eq(other.0.iter())
}
}
impl Hash for ArgumentSignature {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.iter().for_each(|ty| ty.hash(state));
}
}
impl FromIterator<Type> for ArgumentSignature {
fn from_iter<T: IntoIterator<Item = Type>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
impl<T: Borrow<SignatureInfo>> From<T> for ArgumentSignature {
fn from(info: T) -> Self {
Self(
info.borrow()
.args()
.iter()
.map(ArgInfo::ty)
.copied()
.collect(),
)
}
}
impl From<&ArgList<'_>> for ArgumentSignature {
fn from(args: &ArgList) -> Self {
Self(
args.iter()
.map(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
})
.copied()
.collect(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::TypedFunction;
use alloc::{format, string::String, vec};
#[test]
fn should_generate_signature_from_function_info() {
fn add(a: i32, b: f32) -> u32 {
(a as f32 + b).round() as u32
}
let info = add.get_function_info();
let signature = Signature::from(info.base());
assert_eq!(signature.args().0.len(), 2);
assert_eq!(signature.args().0[0], Type::of::<i32>());
assert_eq!(signature.args().0[1], Type::of::<f32>());
assert_eq!(*signature.return_type(), Type::of::<u32>());
}
#[test]
fn should_debug_signature() {
let signature = Signature::new(
ArgumentSignature::from_iter(vec![Type::of::<&mut String>(), Type::of::<i32>()]),
Type::of::<()>(),
);
assert_eq!(
format!("{:?}", signature),
"(&mut alloc::string::String, i32) -> ()"
);
}
}

339
vendor/bevy_reflect/src/generics.rs vendored Normal file
View File

@@ -0,0 +1,339 @@
use crate::type_info::impl_type_methods;
use crate::{Reflect, Type, TypePath};
use alloc::{borrow::Cow, boxed::Box};
use bevy_platform::sync::Arc;
use core::ops::Deref;
use derive_more::derive::From;
/// The generic parameters of a type.
///
/// This is automatically generated via the [`Reflect` derive macro]
/// and stored on the [`TypeInfo`] returned by [`Typed::type_info`]
/// for types that have generics.
///
/// It supports both type parameters and const parameters
/// so long as they implement [`TypePath`].
///
/// If the type has no generics, this will be empty.
///
/// If the type is marked with `#[reflect(type_path = false)]`,
/// the generics will be empty even if the type has generics.
///
/// [`Reflect` derive macro]: bevy_reflect_derive::Reflect
/// [`TypeInfo`]: crate::type_info::TypeInfo
/// [`Typed::type_info`]: crate::Typed::type_info
#[derive(Clone, Default, Debug)]
pub struct Generics(Box<[GenericInfo]>);
impl Generics {
/// Creates an empty set of generics.
pub fn new() -> Self {
Self(Box::new([]))
}
/// Finds the generic parameter with the given name.
///
/// Returns `None` if no such parameter exists.
pub fn get_named(&self, name: &str) -> Option<&GenericInfo> {
// For small sets of generics (the most common case),
// a linear search is often faster using a `HashMap`.
self.0.iter().find(|info| info.name() == name)
}
/// Adds the given generic parameter to the set.
pub fn with(mut self, info: impl Into<GenericInfo>) -> Self {
self.0 = IntoIterator::into_iter(self.0)
.chain(core::iter::once(info.into()))
.collect();
self
}
}
impl<T: Into<GenericInfo>> FromIterator<T> for Generics {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self(iter.into_iter().map(Into::into).collect())
}
}
impl Deref for Generics {
type Target = [GenericInfo];
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// An enum representing a generic parameter.
#[derive(Clone, Debug, From)]
pub enum GenericInfo {
/// A type parameter.
///
/// An example would be `T` in `struct Foo<T, U>`.
Type(TypeParamInfo),
/// A const parameter.
///
/// An example would be `N` in `struct Foo<const N: usize>`.
Const(ConstParamInfo),
}
impl GenericInfo {
/// The name of the generic parameter.
pub fn name(&self) -> &Cow<'static, str> {
match self {
Self::Type(info) => info.name(),
Self::Const(info) => info.name(),
}
}
/// Whether the generic parameter is a const parameter.
pub fn is_const(&self) -> bool {
match self {
Self::Type(_) => false,
Self::Const(_) => true,
}
}
impl_type_methods!(self => {
match self {
Self::Type(info) => info.ty(),
Self::Const(info) => info.ty(),
}
});
}
/// Type information for a generic type parameter.
///
/// An example of a type parameter would be `T` in `struct Foo<T>`.
#[derive(Clone, Debug)]
pub struct TypeParamInfo {
name: Cow<'static, str>,
ty: Type,
default: Option<Type>,
}
impl TypeParamInfo {
/// Creates a new type parameter with the given name.
pub fn new<T: TypePath + ?Sized>(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
ty: Type::of::<T>(),
default: None,
}
}
/// Sets the default type for the parameter.
pub fn with_default<T: TypePath + ?Sized>(mut self) -> Self {
self.default = Some(Type::of::<T>());
self
}
/// The name of the type parameter.
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
/// The default type for the parameter, if any.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{GenericInfo, Reflect, Typed};
/// #[derive(Reflect)]
/// struct Foo<T = f32>(T);
///
/// let generics = Foo::<String>::type_info().generics();
/// let GenericInfo::Type(info) = generics.get_named("T").unwrap() else {
/// panic!("expected a type parameter");
/// };
///
/// let default = info.default().unwrap();
///
/// assert!(default.is::<f32>());
/// ```
pub fn default(&self) -> Option<&Type> {
self.default.as_ref()
}
impl_type_methods!(ty);
}
/// Type information for a const generic parameter.
///
/// An example of a const parameter would be `N` in `struct Foo<const N: usize>`.
#[derive(Clone, Debug)]
pub struct ConstParamInfo {
name: Cow<'static, str>,
ty: Type,
// Rust currently only allows certain primitive types in const generic position,
// meaning that `Reflect` is guaranteed to be implemented for the default value.
default: Option<Arc<dyn Reflect>>,
}
impl ConstParamInfo {
/// Creates a new const parameter with the given name.
pub fn new<T: TypePath + ?Sized>(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
ty: Type::of::<T>(),
default: None,
}
}
/// Sets the default value for the parameter.
pub fn with_default<T: Reflect + 'static>(mut self, default: T) -> Self {
let arc = Arc::new(default);
#[cfg(not(target_has_atomic = "ptr"))]
#[expect(
unsafe_code,
reason = "unsized coercion is an unstable feature for non-std types"
)]
// SAFETY:
// - Coercion from `T` to `dyn Reflect` is valid as `T: Reflect + 'static`
// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
let arc = unsafe { Arc::from_raw(Arc::into_raw(arc) as *const dyn Reflect) };
self.default = Some(arc);
self
}
/// The name of the const parameter.
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
/// The default value for the parameter, if any.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{GenericInfo, Reflect, Typed};
/// #[derive(Reflect)]
/// struct Foo<const N: usize = 10>([u8; N]);
///
/// let generics = Foo::<5>::type_info().generics();
/// let GenericInfo::Const(info) = generics.get_named("N").unwrap() else {
/// panic!("expected a const parameter");
/// };
///
/// let default = info.default().unwrap();
///
/// assert_eq!(default.downcast_ref::<usize>().unwrap(), &10);
/// ```
pub fn default(&self) -> Option<&dyn Reflect> {
self.default.as_deref()
}
impl_type_methods!(ty);
}
macro_rules! impl_generic_info_methods {
// Implements both getter and setter methods for the given field.
($field:ident) => {
$crate::generics::impl_generic_info_methods!(self => &self.$field);
/// Sets the generic parameters for this type.
pub fn with_generics(mut self, generics: crate::generics::Generics) -> Self {
self.$field = generics;
self
}
};
// Implements only a getter method for the given expression.
($self:ident => $expr:expr) => {
/// Gets the generic parameters for this type.
pub fn generics(&$self) -> &crate::generics::Generics {
$expr
}
};
}
pub(crate) use impl_generic_info_methods;
#[cfg(test)]
mod tests {
use super::*;
use crate::{Reflect, Typed};
use alloc::string::String;
use core::fmt::Debug;
#[test]
fn should_maintain_order() {
#[derive(Reflect)]
struct Test<T, U: Debug, const N: usize>([(T, U); N]);
let generics = <Test<f32, String, 10> as Typed>::type_info()
.as_tuple_struct()
.unwrap()
.generics();
assert_eq!(generics.len(), 3);
let mut iter = generics.iter();
let t = iter.next().unwrap();
assert_eq!(t.name(), "T");
assert!(t.ty().is::<f32>());
assert!(!t.is_const());
let u = iter.next().unwrap();
assert_eq!(u.name(), "U");
assert!(u.ty().is::<String>());
assert!(!u.is_const());
let n = iter.next().unwrap();
assert_eq!(n.name(), "N");
assert!(n.ty().is::<usize>());
assert!(n.is_const());
assert!(iter.next().is_none());
}
#[test]
fn should_get_by_name() {
#[derive(Reflect)]
enum Test<T, U: Debug, const N: usize> {
Array([(T, U); N]),
}
let generics = <Test<f32, String, 10> as Typed>::type_info()
.as_enum()
.unwrap()
.generics();
let t = generics.get_named("T").unwrap();
assert_eq!(t.name(), "T");
assert!(t.ty().is::<f32>());
assert!(!t.is_const());
let u = generics.get_named("U").unwrap();
assert_eq!(u.name(), "U");
assert!(u.ty().is::<String>());
assert!(!u.is_const());
let n = generics.get_named("N").unwrap();
assert_eq!(n.name(), "N");
assert!(n.ty().is::<usize>());
assert!(n.is_const());
}
#[test]
fn should_store_defaults() {
#[derive(Reflect)]
struct Test<T, U: Debug = String, const N: usize = 10>([(T, U); N]);
let generics = <Test<f32> as Typed>::type_info()
.as_tuple_struct()
.unwrap()
.generics();
let GenericInfo::Type(u) = generics.get_named("U").unwrap() else {
panic!("expected a type parameter");
};
assert_eq!(u.default().unwrap(), &Type::of::<String>());
let GenericInfo::Const(n) = generics.get_named("N").unwrap() else {
panic!("expected a const parameter");
};
assert_eq!(n.default().unwrap().downcast_ref::<usize>().unwrap(), &10);
}
}

View File

@@ -0,0 +1,8 @@
use crate::impl_type_path;
impl_type_path!(::foldhash::fast::FoldHasher);
impl_type_path!(::foldhash::fast::FixedState);
impl_type_path!(::foldhash::fast::RandomState);
impl_type_path!(::foldhash::quality::FoldHasher);
impl_type_path!(::foldhash::quality::FixedState);
impl_type_path!(::foldhash::quality::RandomState);

575
vendor/bevy_reflect/src/impls/glam.rs vendored Normal file
View File

@@ -0,0 +1,575 @@
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use assert_type_match::assert_type_match;
use bevy_reflect_derive::{impl_reflect, impl_reflect_opaque};
use glam::*;
/// Reflects the given foreign type as an enum and asserts that the variants/fields match up.
macro_rules! reflect_enum {
($(#[$meta:meta])* enum $ident:ident { $($ty:tt)* } ) => {
impl_reflect!($(#[$meta])* enum $ident { $($ty)* });
#[assert_type_match($ident, test_only)]
#[expect(
clippy::upper_case_acronyms,
reason = "The variants used are not acronyms."
)]
enum $ident { $($ty)* }
};
}
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec2 {
x: i32,
y: i32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec3 {
x: i32,
y: i32,
z: i32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec4 {
x: i32,
y: i32,
z: i32,
w: i32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I8Vec2 {
x: i8,
y: i8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I8Vec3 {
x: i8,
y: i8,
z: i8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I8Vec4 {
x: i8,
y: i8,
z: i8,
w: i8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I16Vec2 {
x: i16,
y: i16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I16Vec3 {
x: i16,
y: i16,
z: i16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I16Vec4 {
x: i16,
y: i16,
z: i16,
w: i16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec2 {
x: i64,
y: i64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec3 {
x: i64,
y: i64,
z: i64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec4 {
x: i64,
y: i64,
z: i64,
w: i64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec2 {
x: u32,
y: u32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec3 {
x: u32,
y: u32,
z: u32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec4 {
x: u32,
y: u32,
z: u32,
w: u32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U8Vec2 {
x: u8,
y: u8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U8Vec3 {
x: u8,
y: u8,
z: u8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U8Vec4 {
x: u8,
y: u8,
z: u8,
w: u8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U16Vec2 {
x: u16,
y: u16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U16Vec3 {
x: u16,
y: u16,
z: u16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U16Vec4 {
x: u16,
y: u16,
z: u16,
w: u16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec2 {
x: u64,
y: u64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec3 {
x: u64,
y: u64,
z: u64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec4 {
x: u64,
y: u64,
z: u64,
w: u64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec2 {
x: f32,
y: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec3 {
x: f32,
y: f32,
z: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec3A {
x: f32,
y: f32,
z: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec4 {
x: f32,
y: f32,
z: f32,
w: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec2 {
x: bool,
y: bool,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec3 {
x: bool,
y: bool,
z: bool,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec4 {
x: bool,
y: bool,
z: bool,
w: bool,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec2 {
x: f64,
y: f64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec3 {
x: f64,
y: f64,
z: f64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec4 {
x: f64,
y: f64,
z: f64,
w: f64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat2 {
x_axis: Vec2,
y_axis: Vec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat3 {
x_axis: Vec3,
y_axis: Vec3,
z_axis: Vec3,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat3A {
x_axis: Vec3A,
y_axis: Vec3A,
z_axis: Vec3A,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat4 {
x_axis: Vec4,
y_axis: Vec4,
z_axis: Vec4,
w_axis: Vec4,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat2 {
x_axis: DVec2,
y_axis: DVec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat3 {
x_axis: DVec3,
y_axis: DVec3,
z_axis: DVec3,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat4 {
x_axis: DVec4,
y_axis: DVec4,
z_axis: DVec4,
w_axis: DVec4,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Affine2 {
matrix2: Mat2,
translation: Vec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Affine3A {
matrix3: Mat3A,
translation: Vec3A,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DAffine2 {
matrix2: DMat2,
translation: DVec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DAffine3 {
matrix3: DMat3,
translation: DVec3,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Quat {
x: f32,
y: f32,
z: f32,
w: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DQuat {
x: f64,
y: f64,
z: f64,
w: f64,
}
);
reflect_enum!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
enum EulerRot {
ZYX,
ZXY,
YXZ,
YZX,
XYZ,
XZY,
ZYZ,
ZXZ,
YXY,
YZY,
XYX,
XZX,
ZYXEx,
ZXYEx,
YXZEx,
YZXEx,
XYZEx,
XZYEx,
ZYZEx,
ZXZEx,
YXYEx,
YZYEx,
XYXEx,
XZXEx,
}
);
impl_reflect_opaque!(::glam::BVec3A(
Clone,
Debug,
Default,
Deserialize,
Serialize
));
impl_reflect_opaque!(::glam::BVec4A(
Clone,
Debug,
Default,
Deserialize,
Serialize
));
#[cfg(test)]
mod tests {
use alloc::{format, string::String};
use ron::{
ser::{to_string_pretty, PrettyConfig},
Deserializer,
};
use serde::de::DeserializeSeed;
use static_assertions::assert_impl_all;
use crate::{
prelude::*,
serde::{ReflectDeserializer, ReflectSerializer},
Enum, GetTypeRegistration, TypeRegistry,
};
use super::*;
assert_impl_all!(EulerRot: Enum);
#[test]
fn euler_rot_serialization() {
let v = EulerRot::YXZ;
let mut registry = TypeRegistry::default();
registry.register::<EulerRot>();
let ser = ReflectSerializer::new(&v, &registry);
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.indentor(String::from(" "));
let output = to_string_pretty(&ser, config).unwrap();
let expected = r#"
{
"glam::EulerRot": YXZ,
}"#;
assert_eq!(expected, format!("\n{output}"));
}
#[test]
fn euler_rot_deserialization() {
let data = r#"
{
"glam::EulerRot": XZY,
}"#;
let mut registry = TypeRegistry::default();
registry.add_registration(EulerRot::get_type_registration());
let de = ReflectDeserializer::new(&registry);
let mut deserializer =
Deserializer::from_str(data).expect("Failed to acquire deserializer");
let dynamic_struct = de
.deserialize(&mut deserializer)
.expect("Failed to deserialize");
let mut result = EulerRot::default();
result.apply(dynamic_struct.as_partial_reflect());
assert_eq!(result, EulerRot::XZY);
}
}

View File

@@ -0,0 +1,15 @@
use crate::{impl_reflect_opaque, prelude::ReflectDefault, ReflectDeserialize, ReflectSerialize};
impl_reflect_opaque!(::petgraph::graph::NodeIndex(
Clone,
Default,
PartialEq,
Hash,
Serialize,
Deserialize
));
impl_reflect_opaque!(::petgraph::graph::DiGraph<
N: ::core::clone::Clone,
E: ::core::clone::Clone,
Ix: ::petgraph::graph::IndexType
>(Clone));

View File

@@ -0,0 +1,238 @@
use crate::{
utility::GenericTypeInfoCell, ApplyError, FromReflect, FromType, Generics, GetTypeRegistration,
List, ListInfo, ListIter, MaybeTyped, PartialReflect, Reflect, ReflectFromPtr, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeParamInfo, TypePath, TypeRegistration,
Typed,
};
use alloc::{borrow::Cow, boxed::Box, string::ToString, vec::Vec};
use bevy_reflect::ReflectCloneError;
use bevy_reflect_derive::impl_type_path;
use core::any::Any;
use smallvec::{Array as SmallArray, SmallVec};
impl<T: SmallArray + TypePath + Send + Sync> List for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
if index < SmallVec::len(self) {
Some(&self[index] as &dyn PartialReflect)
} else {
None
}
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
if index < SmallVec::len(self) {
Some(&mut self[index] as &mut dyn PartialReflect)
} else {
None
}
}
fn insert(&mut self, index: usize, value: Box<dyn PartialReflect>) {
let value = value.try_take::<T::Item>().unwrap_or_else(|value| {
<T as SmallArray>::Item::from_reflect(&*value).unwrap_or_else(|| {
panic!(
"Attempted to insert invalid value of type {}.",
value.reflect_type_path()
)
})
});
SmallVec::insert(self, index, value);
}
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect> {
Box::new(self.remove(index))
}
fn push(&mut self, value: Box<dyn PartialReflect>) {
let value = value.try_take::<T::Item>().unwrap_or_else(|value| {
<T as SmallArray>::Item::from_reflect(&*value).unwrap_or_else(|| {
panic!(
"Attempted to push invalid value of type {}.",
value.reflect_type_path()
)
})
});
SmallVec::push(self, value);
}
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
self.pop()
.map(|value| Box::new(value) as Box<dyn PartialReflect>)
}
fn len(&self) -> usize {
<SmallVec<T>>::len(self)
}
fn iter(&self) -> ListIter {
ListIter::new(self)
}
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
self.drain(..)
.map(|value| Box::new(value) as Box<dyn PartialReflect>)
.collect()
}
}
impl<T: SmallArray + TypePath + Send + Sync> PartialReflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
Some(<Self as Typed>::type_info())
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Ok(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
Some(self)
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
Some(self)
}
fn apply(&mut self, value: &dyn PartialReflect) {
crate::list_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
crate::list_try_apply(self, value)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::List
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::List(self)
}
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new(
self.iter()
.map(|value| {
value
.reflect_clone()?
.take()
.map_err(|_| ReflectCloneError::FailedDowncast {
expected: Cow::Borrowed(<T::Item as TypePath>::type_path()),
received: Cow::Owned(value.reflect_type_path().to_string()),
})
})
.collect::<Result<Self, ReflectCloneError>>()?,
))
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
crate::list_partial_eq(self, value)
}
}
impl<T: SmallArray + TypePath + Send + Sync> Reflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
}
fn as_reflect(&self) -> &dyn Reflect {
self
}
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
}
impl<T: SmallArray + TypePath + Send + Sync + 'static> Typed for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn type_info() -> &'static TypeInfo {
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| {
TypeInfo::List(
ListInfo::new::<Self, T::Item>()
.with_generics(Generics::from_iter([TypeParamInfo::new::<T>("T")])),
)
})
}
}
impl_type_path!(::smallvec::SmallVec<T: SmallArray>);
impl<T: SmallArray + TypePath + Send + Sync> FromReflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
let ref_list = reflect.reflect_ref().as_list().ok()?;
let mut new_list = Self::with_capacity(ref_list.len());
for field in ref_list.iter() {
new_list.push(<T as SmallArray>::Item::from_reflect(field)?);
}
Some(new_list)
}
}
impl<T: SmallArray + TypePath + Send + Sync> GetTypeRegistration for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<SmallVec<T>>();
registration.insert::<ReflectFromPtr>(FromType::<SmallVec<T>>::from_type());
registration
}
}
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(SmallVec<T>; <T: SmallArray + TypePath + Send + Sync> where T::Item: FromReflect + MaybeTyped + TypePath);

View File

@@ -0,0 +1,34 @@
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use bevy_reflect_derive::impl_reflect_opaque;
impl_reflect_opaque!(::smol_str::SmolStr(
Clone,
Debug,
Hash,
PartialEq,
Default,
Serialize,
Deserialize,
));
#[cfg(test)]
mod tests {
use crate::{FromReflect, PartialReflect};
use smol_str::SmolStr;
#[test]
fn should_partial_eq_smolstr() {
let a: &dyn PartialReflect = &SmolStr::new("A");
let a2: &dyn PartialReflect = &SmolStr::new("A");
let b: &dyn PartialReflect = &SmolStr::new("B");
assert_eq!(Some(true), a.reflect_partial_eq(a2));
assert_eq!(Some(false), a.reflect_partial_eq(b));
}
#[test]
fn smolstr_should_from_reflect() {
let smolstr = SmolStr::new("hello_world.rs");
let output = <SmolStr as FromReflect>::from_reflect(&smolstr);
assert_eq!(Some(smolstr), output);
}
}

2888
vendor/bevy_reflect/src/impls/std.rs vendored Normal file

File diff suppressed because it is too large Load Diff

12
vendor/bevy_reflect/src/impls/uuid.rs vendored Normal file
View File

@@ -0,0 +1,12 @@
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use bevy_reflect_derive::impl_reflect_opaque;
impl_reflect_opaque!(::uuid::Uuid(
Serialize,
Deserialize,
Default,
Clone,
Debug,
PartialEq,
Hash
));

View File

@@ -0,0 +1,10 @@
use crate::{impl_reflect_opaque, ReflectDeserialize, ReflectSerialize};
impl_reflect_opaque!(::wgpu_types::TextureFormat(
Clone,
Debug,
Hash,
PartialEq,
Deserialize,
Serialize,
));

334
vendor/bevy_reflect/src/kind.rs vendored Normal file
View File

@@ -0,0 +1,334 @@
use alloc::boxed::Box;
use thiserror::Error;
#[cfg(feature = "functions")]
use crate::func::Function;
use crate::{Array, Enum, List, Map, PartialReflect, Set, Struct, Tuple, TupleStruct};
/// An enumeration of the "kinds" of a reflected type.
///
/// Each kind corresponds to a specific reflection trait,
/// such as [`Struct`] or [`List`],
/// which itself corresponds to the kind or structure of a type.
///
/// A [`ReflectKind`] is obtained via [`PartialReflect::reflect_kind`],
/// or via [`ReflectRef::kind`],[`ReflectMut::kind`] or [`ReflectOwned::kind`].
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ReflectKind {
/// A [struct-like] type.
///
/// [struct-like]: Struct
Struct,
/// A [tuple-struct-like] type.
///
/// [tuple-struct-like]: TupleStruct
TupleStruct,
/// A [tuple-like] type.
///
/// [tuple-like]: Tuple
Tuple,
/// A [list-like] type.
///
/// [list-like]: List
List,
/// An [array-like] type.
///
/// [array-like]: Array
Array,
/// A [map-like] type.
///
/// [map-like]: Map
Map,
/// A [set-like] type.
///
/// [set-like]: Set
Set,
/// An [enum-like] type.
///
/// [enum-like]: Enum
Enum,
/// A [function-like] type.
///
/// [function-like]: Function
#[cfg(feature = "functions")]
Function,
/// An opaque type.
///
/// This most often represents a type where it is either impossible, difficult,
/// or unuseful to reflect the type further.
///
/// This includes types like `String` and `Instant`.
///
/// Despite not technically being opaque types,
/// primitives like `u32` `i32` are considered opaque for the purposes of reflection.
///
/// Additionally, any type that [derives `Reflect`] with the `#[reflect(opaque)]` attribute
/// will be considered an opaque type.
///
/// [derives `Reflect`]: bevy_reflect_derive::Reflect
Opaque,
}
impl core::fmt::Display for ReflectKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ReflectKind::Struct => f.pad("struct"),
ReflectKind::TupleStruct => f.pad("tuple struct"),
ReflectKind::Tuple => f.pad("tuple"),
ReflectKind::List => f.pad("list"),
ReflectKind::Array => f.pad("array"),
ReflectKind::Map => f.pad("map"),
ReflectKind::Set => f.pad("set"),
ReflectKind::Enum => f.pad("enum"),
#[cfg(feature = "functions")]
ReflectKind::Function => f.pad("function"),
ReflectKind::Opaque => f.pad("opaque"),
}
}
}
macro_rules! impl_reflect_kind_conversions {
($name:ident$(<$lifetime:lifetime>)?) => {
impl $name$(<$lifetime>)? {
/// Returns the "kind" of this reflected type without any information.
pub fn kind(&self) -> ReflectKind {
match self {
Self::Struct(_) => ReflectKind::Struct,
Self::TupleStruct(_) => ReflectKind::TupleStruct,
Self::Tuple(_) => ReflectKind::Tuple,
Self::List(_) => ReflectKind::List,
Self::Array(_) => ReflectKind::Array,
Self::Map(_) => ReflectKind::Map,
Self::Set(_) => ReflectKind::Set,
Self::Enum(_) => ReflectKind::Enum,
#[cfg(feature = "functions")]
Self::Function(_) => ReflectKind::Function,
Self::Opaque(_) => ReflectKind::Opaque,
}
}
}
impl From<$name$(<$lifetime>)?> for ReflectKind {
fn from(value: $name) -> Self {
match value {
$name::Struct(_) => Self::Struct,
$name::TupleStruct(_) => Self::TupleStruct,
$name::Tuple(_) => Self::Tuple,
$name::List(_) => Self::List,
$name::Array(_) => Self::Array,
$name::Map(_) => Self::Map,
$name::Set(_) => Self::Set,
$name::Enum(_) => Self::Enum,
#[cfg(feature = "functions")]
$name::Function(_) => Self::Function,
$name::Opaque(_) => Self::Opaque,
}
}
}
};
}
/// Caused when a type was expected to be of a certain [kind], but was not.
///
/// [kind]: ReflectKind
#[derive(Debug, Error)]
#[error("kind mismatch: expected {expected:?}, received {received:?}")]
pub struct ReflectKindMismatchError {
pub expected: ReflectKind,
pub received: ReflectKind,
}
macro_rules! impl_cast_method {
($name:ident : Opaque => $retval:ty) => {
#[doc = "Attempts a cast to a [`PartialReflect`] trait object."]
#[doc = "\n\nReturns an error if `self` is not the [`Self::Opaque`] variant."]
pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
match self {
Self::Opaque(value) => Ok(value),
_ => Err(ReflectKindMismatchError {
expected: ReflectKind::Opaque,
received: self.kind(),
}),
}
}
};
($name:ident : $kind:ident => $retval:ty) => {
#[doc = concat!("Attempts a cast to a [`", stringify!($kind), "`] trait object.")]
#[doc = concat!("\n\nReturns an error if `self` is not the [`Self::", stringify!($kind), "`] variant.")]
pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
match self {
Self::$kind(value) => Ok(value),
_ => Err(ReflectKindMismatchError {
expected: ReflectKind::$kind,
received: self.kind(),
}),
}
}
};
}
/// An immutable enumeration of ["kinds"] of a reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectRef`] is obtained via [`PartialReflect::reflect_ref`].
///
/// ["kinds"]: ReflectKind
pub enum ReflectRef<'a> {
Struct(&'a dyn Struct),
TupleStruct(&'a dyn TupleStruct),
Tuple(&'a dyn Tuple),
List(&'a dyn List),
Array(&'a dyn Array),
Map(&'a dyn Map),
Set(&'a dyn Set),
Enum(&'a dyn Enum),
#[cfg(feature = "functions")]
Function(&'a dyn Function),
Opaque(&'a dyn PartialReflect),
}
impl_reflect_kind_conversions!(ReflectRef<'_>);
impl<'a> ReflectRef<'a> {
impl_cast_method!(as_struct: Struct => &'a dyn Struct);
impl_cast_method!(as_tuple_struct: TupleStruct => &'a dyn TupleStruct);
impl_cast_method!(as_tuple: Tuple => &'a dyn Tuple);
impl_cast_method!(as_list: List => &'a dyn List);
impl_cast_method!(as_array: Array => &'a dyn Array);
impl_cast_method!(as_map: Map => &'a dyn Map);
impl_cast_method!(as_set: Set => &'a dyn Set);
impl_cast_method!(as_enum: Enum => &'a dyn Enum);
impl_cast_method!(as_opaque: Opaque => &'a dyn PartialReflect);
}
/// A mutable enumeration of ["kinds"] of a reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectMut`] is obtained via [`PartialReflect::reflect_mut`].
///
/// ["kinds"]: ReflectKind
pub enum ReflectMut<'a> {
Struct(&'a mut dyn Struct),
TupleStruct(&'a mut dyn TupleStruct),
Tuple(&'a mut dyn Tuple),
List(&'a mut dyn List),
Array(&'a mut dyn Array),
Map(&'a mut dyn Map),
Set(&'a mut dyn Set),
Enum(&'a mut dyn Enum),
#[cfg(feature = "functions")]
Function(&'a mut dyn Function),
Opaque(&'a mut dyn PartialReflect),
}
impl_reflect_kind_conversions!(ReflectMut<'_>);
impl<'a> ReflectMut<'a> {
impl_cast_method!(as_struct: Struct => &'a mut dyn Struct);
impl_cast_method!(as_tuple_struct: TupleStruct => &'a mut dyn TupleStruct);
impl_cast_method!(as_tuple: Tuple => &'a mut dyn Tuple);
impl_cast_method!(as_list: List => &'a mut dyn List);
impl_cast_method!(as_array: Array => &'a mut dyn Array);
impl_cast_method!(as_map: Map => &'a mut dyn Map);
impl_cast_method!(as_set: Set => &'a mut dyn Set);
impl_cast_method!(as_enum: Enum => &'a mut dyn Enum);
impl_cast_method!(as_opaque: Opaque => &'a mut dyn PartialReflect);
}
/// An owned enumeration of ["kinds"] of a reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectOwned`] is obtained via [`PartialReflect::reflect_owned`].
///
/// ["kinds"]: ReflectKind
pub enum ReflectOwned {
Struct(Box<dyn Struct>),
TupleStruct(Box<dyn TupleStruct>),
Tuple(Box<dyn Tuple>),
List(Box<dyn List>),
Array(Box<dyn Array>),
Map(Box<dyn Map>),
Set(Box<dyn Set>),
Enum(Box<dyn Enum>),
#[cfg(feature = "functions")]
Function(Box<dyn Function>),
Opaque(Box<dyn PartialReflect>),
}
impl_reflect_kind_conversions!(ReflectOwned);
impl ReflectOwned {
impl_cast_method!(into_struct: Struct => Box<dyn Struct>);
impl_cast_method!(into_tuple_struct: TupleStruct => Box<dyn TupleStruct>);
impl_cast_method!(into_tuple: Tuple => Box<dyn Tuple>);
impl_cast_method!(into_list: List => Box<dyn List>);
impl_cast_method!(into_array: Array => Box<dyn Array>);
impl_cast_method!(into_map: Map => Box<dyn Map>);
impl_cast_method!(into_set: Set => Box<dyn Set>);
impl_cast_method!(into_enum: Enum => Box<dyn Enum>);
impl_cast_method!(into_value: Opaque => Box<dyn PartialReflect>);
}
#[cfg(test)]
mod tests {
use alloc::vec;
use std::collections::HashSet;
use super::*;
#[test]
fn should_cast_ref() {
let value = vec![1, 2, 3];
let result = value.reflect_ref().as_list();
assert!(result.is_ok());
let result = value.reflect_ref().as_array();
assert!(matches!(
result,
Err(ReflectKindMismatchError {
expected: ReflectKind::Array,
received: ReflectKind::List
})
));
}
#[test]
fn should_cast_mut() {
let mut value: HashSet<i32> = HashSet::default();
let result = value.reflect_mut().as_set();
assert!(result.is_ok());
let result = value.reflect_mut().as_map();
assert!(matches!(
result,
Err(ReflectKindMismatchError {
expected: ReflectKind::Map,
received: ReflectKind::Set
})
));
}
#[test]
fn should_cast_owned() {
let value = Box::new(Some(123));
let result = value.reflect_owned().into_enum();
assert!(result.is_ok());
let value = Box::new(Some(123));
let result = value.reflect_owned().into_struct();
assert!(matches!(
result,
Err(ReflectKindMismatchError {
expected: ReflectKind::Struct,
received: ReflectKind::Enum
})
));
}
}

3510
vendor/bevy_reflect/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

568
vendor/bevy_reflect/src/list.rs vendored Normal file
View File

@@ -0,0 +1,568 @@
use alloc::{boxed::Box, vec::Vec};
use core::{
any::Any,
fmt::{Debug, Formatter},
hash::{Hash, Hasher},
};
use bevy_reflect_derive::impl_type_path;
use crate::generics::impl_generic_info_methods;
use crate::{
type_info::impl_type_methods, utility::reflect_hasher, ApplyError, FromReflect, Generics,
MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
TypeInfo, TypePath,
};
/// A trait used to power [list-like] operations via [reflection].
///
/// This corresponds to types, like [`Vec`], which contain an ordered sequence
/// of elements that implement [`Reflect`].
///
/// Unlike the [`Array`](crate::Array) trait, implementors of this trait are not expected to
/// maintain a constant length.
/// Methods like [insertion](List::insert) and [removal](List::remove) explicitly allow for their
/// internal size to change.
///
/// [`push`](List::push) and [`pop`](List::pop) have default implementations,
/// however it will generally be more performant to implement them manually
/// as the default implementation uses a very naive approach to find the correct position.
///
/// This trait expects its elements to be ordered linearly from front to back.
/// The _front_ element starts at index 0 with the _back_ element ending at the largest index.
/// This contract above should be upheld by any manual implementors.
///
/// Due to the [type-erasing] nature of the reflection API as a whole,
/// this trait does not make any guarantees that the implementor's elements
/// are homogeneous (i.e. all the same type).
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Reflect, List};
///
/// let foo: &mut dyn List = &mut vec![123_u32, 456_u32, 789_u32];
/// assert_eq!(foo.len(), 3);
///
/// let last_field: Box<dyn PartialReflect> = foo.pop().unwrap();
/// assert_eq!(last_field.try_downcast_ref::<u32>(), Some(&789));
/// ```
///
/// [list-like]: https://doc.rust-lang.org/book/ch08-01-vectors.html
/// [reflection]: crate
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
pub trait List: PartialReflect {
/// Returns a reference to the element at `index`, or `None` if out of bounds.
fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Inserts an element at position `index` within the list,
/// shifting all elements after it towards the back of the list.
///
/// # Panics
/// Panics if `index > len`.
fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>);
/// Removes and returns the element at position `index` within the list,
/// shifting all elements before it towards the front of the list.
///
/// # Panics
/// Panics if `index` is out of bounds.
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect>;
/// Appends an element to the _back_ of the list.
fn push(&mut self, value: Box<dyn PartialReflect>) {
self.insert(self.len(), value);
}
/// Removes the _back_ element from the list and returns it, or [`None`] if it is empty.
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
if self.is_empty() {
None
} else {
Some(self.remove(self.len() - 1))
}
}
/// Returns the number of elements in the list.
fn len(&self) -> usize;
/// Returns `true` if the collection contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the list.
fn iter(&self) -> ListIter;
/// Drain the elements of this list to get a vector of owned values.
///
/// After calling this function, `self` will be empty. The order of items in the returned
/// [`Vec`] will match the order of items in `self`.
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>>;
/// Clones the list, producing a [`DynamicList`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_list` instead")]
fn clone_dynamic(&self) -> DynamicList {
self.to_dynamic_list()
}
/// Creates a new [`DynamicList`] from this list.
fn to_dynamic_list(&self) -> DynamicList {
DynamicList {
represented_type: self.get_represented_type_info(),
values: self.iter().map(PartialReflect::to_dynamic).collect(),
}
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_list_info(&self) -> Option<&'static ListInfo> {
self.get_represented_type_info()?.as_list().ok()
}
}
/// A container for compile-time list info.
#[derive(Clone, Debug)]
pub struct ListInfo {
ty: Type,
generics: Generics,
item_info: fn() -> Option<&'static TypeInfo>,
item_ty: Type,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl ListInfo {
/// Create a new [`ListInfo`].
pub fn new<TList: List + TypePath, TItem: FromReflect + MaybeTyped + TypePath>() -> Self {
Self {
ty: Type::of::<TList>(),
generics: Generics::new(),
item_info: TItem::maybe_type_info,
item_ty: Type::of::<TItem>(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this list.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
impl_type_methods!(ty);
/// The [`TypeInfo`] of the list item.
///
/// Returns `None` if the list item does not contain static type information,
/// such as for dynamic types.
pub fn item_info(&self) -> Option<&'static TypeInfo> {
(self.item_info)()
}
/// The [type] of the list item.
///
/// [type]: Type
pub fn item_ty(&self) -> Type {
self.item_ty
}
/// The docstring of this list, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// A list of reflected values.
#[derive(Default)]
pub struct DynamicList {
represented_type: Option<&'static TypeInfo>,
values: Vec<Box<dyn PartialReflect>>,
}
impl DynamicList {
/// Sets the [type] to be represented by this `DynamicList`.
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::List`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::List(_)),
"expected TypeInfo::List but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Appends a typed value to the list.
pub fn push<T: PartialReflect>(&mut self, value: T) {
self.values.push(Box::new(value));
}
/// Appends a [`Reflect`] trait object to the list.
pub fn push_box(&mut self, value: Box<dyn PartialReflect>) {
self.values.push(value);
}
}
impl List for DynamicList {
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
self.values.get(index).map(|value| &**value)
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.values.get_mut(index).map(|value| &mut **value)
}
fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>) {
self.values.insert(index, element);
}
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect> {
self.values.remove(index)
}
fn push(&mut self, value: Box<dyn PartialReflect>) {
DynamicList::push_box(self, value);
}
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
self.values.pop()
}
fn len(&self) -> usize {
self.values.len()
}
fn iter(&self) -> ListIter {
ListIter::new(self)
}
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
self.values.drain(..).collect()
}
}
impl PartialReflect for DynamicList {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
list_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
list_try_apply(self, value)
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::List
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::List(self)
}
#[inline]
fn reflect_hash(&self) -> Option<u64> {
list_hash(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
list_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicList(")?;
list_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicList);
impl Debug for DynamicList {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl FromIterator<Box<dyn PartialReflect>> for DynamicList {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect(),
}
}
}
impl<T: PartialReflect> FromIterator<T> for DynamicList {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|field| Box::new(field).into_partial_reflect())
.collect()
}
}
impl IntoIterator for DynamicList {
type Item = Box<dyn PartialReflect>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicList {
type Item = &'a dyn PartialReflect;
type IntoIter = ListIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// An iterator over an [`List`].
pub struct ListIter<'a> {
list: &'a dyn List,
index: usize,
}
impl ListIter<'_> {
/// Creates a new [`ListIter`].
#[inline]
pub const fn new(list: &dyn List) -> ListIter {
ListIter { list, index: 0 }
}
}
impl<'a> Iterator for ListIter<'a> {
type Item = &'a dyn PartialReflect;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let value = self.list.get(self.index);
self.index += value.is_some() as usize;
value
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.list.len();
(size, Some(size))
}
}
impl ExactSizeIterator for ListIter<'_> {}
/// Returns the `u64` hash of the given [list](List).
#[inline]
pub fn list_hash<L: List>(list: &L) -> Option<u64> {
let mut hasher = reflect_hasher();
Any::type_id(list).hash(&mut hasher);
list.len().hash(&mut hasher);
for value in list.iter() {
hasher.write_u64(value.reflect_hash()?);
}
Some(hasher.finish())
}
/// Applies the elements of `b` to the corresponding elements of `a`.
///
/// If the length of `b` is greater than that of `a`, the excess elements of `b`
/// are cloned and appended to `a`.
///
/// # Panics
///
/// This function panics if `b` is not a list.
#[inline]
pub fn list_apply<L: List>(a: &mut L, b: &dyn PartialReflect) {
if let Err(err) = list_try_apply(a, b) {
panic!("{err}");
}
}
/// Tries to apply the elements of `b` to the corresponding elements of `a` and
/// returns a Result.
///
/// If the length of `b` is greater than that of `a`, the excess elements of `b`
/// are cloned and appended to `a`.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a list or if
/// applying elements to each other fails.
#[inline]
pub fn list_try_apply<L: List>(a: &mut L, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let list_value = b.reflect_ref().as_list()?;
for (i, value) in list_value.iter().enumerate() {
if i < a.len() {
if let Some(v) = a.get_mut(i) {
v.try_apply(value)?;
}
} else {
List::push(a, value.to_dynamic());
}
}
Ok(())
}
/// Compares a [`List`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a list;
/// - `b` is the same length as `a`;
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn list_partial_eq<L: List + ?Sized>(a: &L, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::List(list) = b.reflect_ref() else {
return Some(false);
};
if a.len() != list.len() {
return Some(false);
}
for (a_value, b_value) in a.iter().zip(list.iter()) {
let eq_result = a_value.reflect_partial_eq(b_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}
Some(true)
}
/// The default debug formatter for [`List`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
///
/// let my_list: &dyn Reflect = &vec![1, 2, 3];
/// println!("{:#?}", my_list);
///
/// // Output:
///
/// // [
/// // 1,
/// // 2,
/// // 3,
/// // ]
/// ```
#[inline]
pub fn list_debug(dyn_list: &dyn List, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_list();
for item in dyn_list.iter() {
debug.entry(&item as &dyn Debug);
}
debug.finish()
}
#[cfg(test)]
mod tests {
use super::DynamicList;
use crate::Reflect;
use alloc::{boxed::Box, vec};
use core::assert_eq;
#[test]
fn test_into_iter() {
let mut list = DynamicList::default();
list.push(0usize);
list.push(1usize);
list.push(2usize);
let items = list.into_iter();
for (index, item) in items.into_iter().enumerate() {
let value = item
.try_take::<usize>()
.expect("couldn't downcast to usize");
assert_eq!(index, value);
}
}
#[test]
fn next_index_increment() {
const SIZE: usize = if cfg!(debug_assertions) {
4
} else {
// If compiled in release mode, verify we dont overflow
usize::MAX
};
let b = Box::new(vec![(); SIZE]).into_reflect();
let list = b.reflect_ref().as_list().unwrap();
let mut iter = list.iter();
iter.index = SIZE - 1;
assert!(iter.next().is_some());
// When None we should no longer increase index
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
}
}

751
vendor/bevy_reflect/src/map.rs vendored Normal file
View File

@@ -0,0 +1,751 @@
use core::fmt::{Debug, Formatter};
use bevy_platform::collections::HashTable;
use bevy_reflect_derive::impl_type_path;
use crate::{
generics::impl_generic_info_methods, type_info::impl_type_methods, ApplyError, Generics,
MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
TypeInfo, TypePath,
};
use alloc::{boxed::Box, format, vec::Vec};
/// A trait used to power [map-like] operations via [reflection].
///
/// Maps contain zero or more entries of a key and its associated value,
/// and correspond to types like [`HashMap`] and [`BTreeMap`].
/// The order of these entries is not guaranteed by this trait.
///
/// # Hashing and equality
///
/// All keys are expected to return a valid hash value from [`PartialReflect::reflect_hash`] and be
/// comparable using [`PartialReflect::reflect_partial_eq`].
/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding
/// `#[reflect(Hash, PartialEq)]` to the entire struct or enum.
/// The ordering is expected to be total, that is as if the reflected type implements the [`Eq`] trait.
/// This is true even for manual implementors who do not hash or compare values,
/// as it is still relied on by [`DynamicMap`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Reflect, Map};
/// use std::collections::HashMap;
///
///
/// let foo: &mut dyn Map = &mut HashMap::<u32, bool>::new();
/// foo.insert_boxed(Box::new(123_u32), Box::new(true));
/// assert_eq!(foo.len(), 1);
///
/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.try_downcast_ref::<bool>(), Some(&true));
/// ```
///
/// [`HashMap`]: std::collections::HashMap
/// [`BTreeMap`]: alloc::collections::BTreeMap
/// [map-like]: https://doc.rust-lang.org/book/ch08-03-hash-maps.html
/// [reflection]: crate
pub trait Map: PartialReflect {
/// Returns a reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect>;
/// Returns the key-value pair at `index` by reference, or `None` if out of bounds.
fn get_at(&self, index: usize) -> Option<(&dyn PartialReflect, &dyn PartialReflect)>;
/// Returns the key-value pair at `index` by reference where the value is a mutable reference, or `None` if out of bounds.
fn get_at_mut(
&mut self,
index: usize,
) -> Option<(&dyn PartialReflect, &mut dyn PartialReflect)>;
/// Returns the number of elements in the map.
fn len(&self) -> usize;
/// Returns `true` if the list contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the key-value pairs of the map.
fn iter(&self) -> MapIter;
/// Drain the key-value pairs of this map to get a vector of owned values.
///
/// After calling this function, `self` will be empty.
fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>;
/// Clones the map, producing a [`DynamicMap`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_map` instead")]
fn clone_dynamic(&self) -> DynamicMap {
self.to_dynamic_map()
}
/// Creates a new [`DynamicMap`] from this map.
fn to_dynamic_map(&self) -> DynamicMap {
let mut map = DynamicMap::default();
map.set_represented_type(self.get_represented_type_info());
for (key, value) in self.iter() {
map.insert_boxed(key.to_dynamic(), value.to_dynamic());
}
map
}
/// Inserts a key-value pair into the map.
///
/// If the map did not have this key present, `None` is returned.
/// If the map did have this key present, the value is updated, and the old value is returned.
fn insert_boxed(
&mut self,
key: Box<dyn PartialReflect>,
value: Box<dyn PartialReflect>,
) -> Option<Box<dyn PartialReflect>>;
/// Removes an entry from the map.
///
/// If the map did not have this key present, `None` is returned.
/// If the map did have this key present, the removed value is returned.
fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>>;
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_map_info(&self) -> Option<&'static MapInfo> {
self.get_represented_type_info()?.as_map().ok()
}
}
/// A container for compile-time map info.
#[derive(Clone, Debug)]
pub struct MapInfo {
ty: Type,
generics: Generics,
key_info: fn() -> Option<&'static TypeInfo>,
key_ty: Type,
value_info: fn() -> Option<&'static TypeInfo>,
value_ty: Type,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl MapInfo {
/// Create a new [`MapInfo`].
pub fn new<
TMap: Map + TypePath,
TKey: Reflect + MaybeTyped + TypePath,
TValue: Reflect + MaybeTyped + TypePath,
>() -> Self {
Self {
ty: Type::of::<TMap>(),
generics: Generics::new(),
key_info: TKey::maybe_type_info,
key_ty: Type::of::<TKey>(),
value_info: TValue::maybe_type_info,
value_ty: Type::of::<TValue>(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this map.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
impl_type_methods!(ty);
/// The [`TypeInfo`] of the key type.
///
/// Returns `None` if the key type does not contain static type information,
/// such as for dynamic types.
pub fn key_info(&self) -> Option<&'static TypeInfo> {
(self.key_info)()
}
/// The [type] of the key type.
///
/// [type]: Type
pub fn key_ty(&self) -> Type {
self.key_ty
}
/// The [`TypeInfo`] of the value type.
///
/// Returns `None` if the value type does not contain static type information,
/// such as for dynamic types.
pub fn value_info(&self) -> Option<&'static TypeInfo> {
(self.value_info)()
}
/// The [type] of the value type.
///
/// [type]: Type
pub fn value_ty(&self) -> Type {
self.value_ty
}
/// The docstring of this map, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
#[macro_export]
macro_rules! hash_error {
( $key:expr ) => {{
let type_path = (*$key).reflect_type_path();
if !$key.is_dynamic() {
format!(
"the given key of type `{}` does not support hashing",
type_path
)
} else {
match (*$key).get_represented_type_info() {
// Handle dynamic types that do not represent a type (i.e a plain `DynamicStruct`):
None => format!("the dynamic type `{}` does not support hashing", type_path),
// Handle dynamic types that do represent a type (i.e. a `DynamicStruct` proxying `Foo`):
Some(s) => format!(
"the dynamic type `{}` (representing `{}`) does not support hashing",
type_path,
s.type_path()
),
}
}
}}
}
/// An ordered mapping between reflected values.
#[derive(Default)]
pub struct DynamicMap {
represented_type: Option<&'static TypeInfo>,
values: Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>,
indices: HashTable<usize>,
}
impl DynamicMap {
/// Sets the [type] to be represented by this `DynamicMap`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Map`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Map(_)),
"expected TypeInfo::Map but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Inserts a typed key-value pair into the map.
pub fn insert<K: PartialReflect, V: PartialReflect>(&mut self, key: K, value: V) {
self.insert_boxed(Box::new(key), Box::new(value));
}
fn internal_hash(value: &dyn PartialReflect) -> u64 {
value.reflect_hash().expect(&hash_error!(value))
}
fn internal_eq<'a>(
value: &'a dyn PartialReflect,
values: &'a [(Box<dyn PartialReflect>, Box<dyn PartialReflect>)],
) -> impl FnMut(&usize) -> bool + 'a {
|&index| {
value
.reflect_partial_eq(&*values[index].0)
.expect("underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
}
}
}
impl Map for DynamicMap {
fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
let hash = Self::internal_hash(key);
let eq = Self::internal_eq(key, &self.values);
self.indices
.find(hash, eq)
.map(|&index| &*self.values[index].1)
}
fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect> {
let hash = Self::internal_hash(key);
let eq = Self::internal_eq(key, &self.values);
self.indices
.find(hash, eq)
.map(|&index| &mut *self.values[index].1)
}
fn get_at(&self, index: usize) -> Option<(&dyn PartialReflect, &dyn PartialReflect)> {
self.values
.get(index)
.map(|(key, value)| (&**key, &**value))
}
fn get_at_mut(
&mut self,
index: usize,
) -> Option<(&dyn PartialReflect, &mut dyn PartialReflect)> {
self.values
.get_mut(index)
.map(|(key, value)| (&**key, &mut **value))
}
fn len(&self) -> usize {
self.values.len()
}
fn iter(&self) -> MapIter {
MapIter::new(self)
}
fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> {
self.values.drain(..).collect()
}
fn insert_boxed(
&mut self,
key: Box<dyn PartialReflect>,
value: Box<dyn PartialReflect>,
) -> Option<Box<dyn PartialReflect>> {
assert_eq!(
key.reflect_partial_eq(&*key),
Some(true),
"keys inserted in `Map`-like types are expected to reflect `PartialEq`"
);
let hash = Self::internal_hash(&*key);
let eq = Self::internal_eq(&*key, &self.values);
match self.indices.find(hash, eq) {
Some(&index) => {
let (key_ref, value_ref) = &mut self.values[index];
*key_ref = key;
let old_value = core::mem::replace(value_ref, value);
Some(old_value)
}
None => {
let index = self.values.len();
self.values.push((key, value));
self.indices.insert_unique(hash, index, |&index| {
Self::internal_hash(&*self.values[index].0)
});
None
}
}
}
fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>> {
let hash = Self::internal_hash(key);
let eq = Self::internal_eq(key, &self.values);
match self.indices.find_entry(hash, eq) {
Ok(entry) => {
let (index, _) = entry.remove();
let (_, old_value) = self.values.swap_remove(index);
// The `swap_remove` might have moved the last element of `values`
// to `index`, so we might need to fix up its index in `indices`.
// If the removed element was also the last element there's nothing to
// fixup and this will return `None`, otherwise it returns the key
// whose index needs to be fixed up.
if let Some((moved_key, _)) = self.values.get(index) {
let hash = Self::internal_hash(&**moved_key);
let moved_index = self
.indices
.find_mut(hash, |&moved_index| moved_index == self.values.len())
.expect("key inserted in a `DynamicMap` is no longer present, this means its reflected `Hash` might be incorrect");
*moved_index = index;
}
Some(old_value)
}
Err(_) => None,
}
}
}
impl PartialReflect for DynamicMap {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
map_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
map_try_apply(self, value)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Map
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Map(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Map(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Map(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
map_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicMap(")?;
map_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicMap);
impl Debug for DynamicMap {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
/// An iterator over the key-value pairs of a [`Map`].
pub struct MapIter<'a> {
map: &'a dyn Map,
index: usize,
}
impl MapIter<'_> {
/// Creates a new [`MapIter`].
#[inline]
pub const fn new(map: &dyn Map) -> MapIter {
MapIter { map, index: 0 }
}
}
impl<'a> Iterator for MapIter<'a> {
type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
fn next(&mut self) -> Option<Self::Item> {
let value = self.map.get_at(self.index);
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.map.len();
(size, Some(size))
}
}
impl FromIterator<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>)>>(
items: I,
) -> Self {
let mut map = Self::default();
for (key, value) in items.into_iter() {
map.insert_boxed(key, value);
}
map
}
}
impl<K: Reflect, V: Reflect> FromIterator<(K, V)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (K, V)>>(items: I) -> Self {
let mut map = Self::default();
for (key, value) in items.into_iter() {
map.insert(key, value);
}
map
}
}
impl IntoIterator for DynamicMap {
type Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>);
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicMap {
type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
type IntoIter = MapIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> ExactSizeIterator for MapIter<'a> {}
/// Compares a [`Map`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a map;
/// - `b` is the same length as `a`;
/// - For each key-value pair in `a`, `b` contains a value for the given key,
/// and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn map_partial_eq<M: Map + ?Sized>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Map(map) = b.reflect_ref() else {
return Some(false);
};
if a.len() != map.len() {
return Some(false);
}
for (key, value) in a.iter() {
if let Some(map_value) = map.get(key) {
let eq_result = value.reflect_partial_eq(map_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
}
}
Some(true)
}
/// The default debug formatter for [`Map`] types.
///
/// # Example
/// ```
/// # use std::collections::HashMap;
/// use bevy_reflect::Reflect;
///
/// let mut my_map = HashMap::new();
/// my_map.insert(123, String::from("Hello"));
/// println!("{:#?}", &my_map as &dyn Reflect);
///
/// // Output:
///
/// // {
/// // 123: "Hello",
/// // }
/// ```
#[inline]
pub fn map_debug(dyn_map: &dyn Map, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_map();
for (key, value) in dyn_map.iter() {
debug.entry(&key as &dyn Debug, &value as &dyn Debug);
}
debug.finish()
}
/// Applies the elements of reflected map `b` to the corresponding elements of map `a`.
///
/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Panics
///
/// This function panics if `b` is not a reflected map.
#[inline]
pub fn map_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) {
if let Err(err) = map_try_apply(a, b) {
panic!("{err}");
}
}
/// Tries to apply the elements of reflected map `b` to the corresponding elements of map `a`
/// and returns a Result.
///
/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected map or if
/// applying elements to each other fails.
#[inline]
pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let map_value = b.reflect_ref().as_map()?;
for (key, b_value) in map_value.iter() {
if let Some(a_value) = a.get_mut(key) {
a_value.try_apply(b_value)?;
} else {
a.insert_boxed(key.to_dynamic(), b_value.to_dynamic());
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::{DynamicMap, Map};
use alloc::{
borrow::ToOwned,
string::{String, ToString},
};
#[test]
fn test_into_iter() {
let expected = ["foo", "bar", "baz"];
let mut map = DynamicMap::default();
map.insert(0usize, expected[0].to_string());
map.insert(1usize, expected[1].to_string());
map.insert(2usize, expected[2].to_string());
for (index, item) in map.into_iter().enumerate() {
let key = item
.0
.try_take::<usize>()
.expect("couldn't downcast to usize");
let value = item
.1
.try_take::<String>()
.expect("couldn't downcast to String");
assert_eq!(index, key);
assert_eq!(expected[index], value);
}
}
#[test]
fn test_map_get_at() {
let values = ["first", "second", "third"];
let mut map = DynamicMap::default();
map.insert(0usize, values[0].to_string());
map.insert(1usize, values[1].to_string());
map.insert(1usize, values[2].to_string());
let (key_r, value_r) = map.get_at(1).expect("Item wasn't found");
let value = value_r
.try_downcast_ref::<String>()
.expect("Couldn't downcast to String");
let key = key_r
.try_downcast_ref::<usize>()
.expect("Couldn't downcast to usize");
assert_eq!(key, &1usize);
assert_eq!(value, &values[2].to_owned());
assert!(map.get_at(2).is_none());
map.remove(&1usize);
assert!(map.get_at(1).is_none());
}
#[test]
fn test_map_get_at_mut() {
let values = ["first", "second", "third"];
let mut map = DynamicMap::default();
map.insert(0usize, values[0].to_string());
map.insert(1usize, values[1].to_string());
map.insert(1usize, values[2].to_string());
let (key_r, value_r) = map.get_at_mut(1).expect("Item wasn't found");
let value = value_r
.try_downcast_mut::<String>()
.expect("Couldn't downcast to String");
let key = key_r
.try_downcast_ref::<usize>()
.expect("Couldn't downcast to usize");
assert_eq!(key, &1usize);
assert_eq!(value, &mut values[2].to_owned());
value.clone_from(&values[0].to_owned());
assert_eq!(
map.get(&1usize)
.expect("Item wasn't found")
.try_downcast_ref::<String>()
.expect("Couldn't downcast to String"),
&values[0].to_owned()
);
assert!(map.get_at(2).is_none());
}
#[test]
fn next_index_increment() {
let values = ["first", "last"];
let mut map = DynamicMap::default();
map.insert(0usize, values[0]);
map.insert(1usize, values[1]);
let mut iter = map.iter();
let size = iter.len();
for _ in 0..2 {
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
}
// When None we should no longer increase index
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
}
#[test]
fn remove() {
let mut map = DynamicMap::default();
map.insert(0, 0);
map.insert(1, 1);
assert_eq!(map.remove(&0).unwrap().try_downcast_ref(), Some(&0));
assert!(map.get(&0).is_none());
assert_eq!(map.get(&1).unwrap().try_downcast_ref(), Some(&1));
assert_eq!(map.remove(&1).unwrap().try_downcast_ref(), Some(&1));
assert!(map.get(&1).is_none());
assert!(map.remove(&1).is_none());
assert!(map.get(&1).is_none());
}
}

184
vendor/bevy_reflect/src/path/access.rs vendored Normal file
View File

@@ -0,0 +1,184 @@
//! Representation for individual element accesses within a path.
use alloc::borrow::Cow;
use core::fmt;
use super::error::AccessErrorKind;
use crate::{AccessError, PartialReflect, ReflectKind, ReflectMut, ReflectRef, VariantType};
type InnerResult<T> = Result<T, AccessErrorKind>;
/// A singular element access within a path.
/// Multiple accesses can be combined into a [`ParsedPath`](super::ParsedPath).
///
/// Can be applied to a [`dyn Reflect`](crate::Reflect) to get a reference to the targeted element.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Access<'a> {
/// A name-based field access on a struct.
Field(Cow<'a, str>),
/// A index-based field access on a struct.
FieldIndex(usize),
/// An index-based access on a tuple.
TupleIndex(usize),
/// An index-based access on a list.
ListIndex(usize),
}
impl fmt::Display for Access<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Access::Field(field) => write!(f, ".{field}"),
Access::FieldIndex(index) => write!(f, "#{index}"),
Access::TupleIndex(index) => write!(f, ".{index}"),
Access::ListIndex(index) => write!(f, "[{index}]"),
}
}
}
impl<'a> Access<'a> {
/// Converts this into an "owned" value.
///
/// If the [`Access`] is of variant [`Field`](Access::Field),
/// the field's [`Cow<str>`] will be converted to its owned
/// counterpart, which doesn't require a reference.
pub fn into_owned(self) -> Access<'static> {
match self {
Self::Field(value) => Access::Field(Cow::Owned(value.into_owned())),
Self::FieldIndex(value) => Access::FieldIndex(value),
Self::TupleIndex(value) => Access::TupleIndex(value),
Self::ListIndex(value) => Access::ListIndex(value),
}
}
pub(super) fn element<'r>(
&self,
base: &'r dyn PartialReflect,
offset: Option<usize>,
) -> Result<&'r dyn PartialReflect, AccessError<'a>> {
self.element_inner(base)
.and_then(|opt| opt.ok_or(AccessErrorKind::MissingField(base.reflect_kind())))
.map_err(|err| err.with_access(self.clone(), offset))
}
fn element_inner<'r>(
&self,
base: &'r dyn PartialReflect,
) -> InnerResult<Option<&'r dyn PartialReflect>> {
use ReflectRef::*;
let invalid_variant =
|expected, actual| AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual };
match (self, base.reflect_ref()) {
(Self::Field(field), Struct(struct_ref)) => Ok(struct_ref.field(field.as_ref())),
(Self::Field(field), Enum(enum_ref)) => match enum_ref.variant_type() {
VariantType::Struct => Ok(enum_ref.field(field.as_ref())),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(&Self::FieldIndex(index), Struct(struct_ref)) => Ok(struct_ref.field_at(index)),
(&Self::FieldIndex(index), Enum(enum_ref)) => match enum_ref.variant_type() {
VariantType::Struct => Ok(enum_ref.field_at(index)),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(Self::Field(_) | Self::FieldIndex(_), actual) => {
Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Struct,
actual: actual.into(),
})
}
(&Self::TupleIndex(index), TupleStruct(tuple)) => Ok(tuple.field(index)),
(&Self::TupleIndex(index), Tuple(tuple)) => Ok(tuple.field(index)),
(&Self::TupleIndex(index), Enum(enum_ref)) => match enum_ref.variant_type() {
VariantType::Tuple => Ok(enum_ref.field_at(index)),
actual => Err(invalid_variant(VariantType::Tuple, actual)),
},
(Self::TupleIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Tuple,
actual: actual.into(),
}),
(&Self::ListIndex(index), List(list)) => Ok(list.get(index)),
(&Self::ListIndex(index), Array(list)) => Ok(list.get(index)),
(Self::ListIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::List,
actual: actual.into(),
}),
}
}
pub(super) fn element_mut<'r>(
&self,
base: &'r mut dyn PartialReflect,
offset: Option<usize>,
) -> Result<&'r mut dyn PartialReflect, AccessError<'a>> {
let kind = base.reflect_kind();
self.element_inner_mut(base)
.and_then(|maybe| maybe.ok_or(AccessErrorKind::MissingField(kind)))
.map_err(|err| err.with_access(self.clone(), offset))
}
fn element_inner_mut<'r>(
&self,
base: &'r mut dyn PartialReflect,
) -> InnerResult<Option<&'r mut dyn PartialReflect>> {
use ReflectMut::*;
let invalid_variant =
|expected, actual| AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual };
match (self, base.reflect_mut()) {
(Self::Field(field), Struct(struct_mut)) => Ok(struct_mut.field_mut(field.as_ref())),
(Self::Field(field), Enum(enum_mut)) => match enum_mut.variant_type() {
VariantType::Struct => Ok(enum_mut.field_mut(field.as_ref())),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(&Self::FieldIndex(index), Struct(struct_mut)) => Ok(struct_mut.field_at_mut(index)),
(&Self::FieldIndex(index), Enum(enum_mut)) => match enum_mut.variant_type() {
VariantType::Struct => Ok(enum_mut.field_at_mut(index)),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(Self::Field(_) | Self::FieldIndex(_), actual) => {
Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Struct,
actual: actual.into(),
})
}
(&Self::TupleIndex(index), TupleStruct(tuple)) => Ok(tuple.field_mut(index)),
(&Self::TupleIndex(index), Tuple(tuple)) => Ok(tuple.field_mut(index)),
(&Self::TupleIndex(index), Enum(enum_mut)) => match enum_mut.variant_type() {
VariantType::Tuple => Ok(enum_mut.field_at_mut(index)),
actual => Err(invalid_variant(VariantType::Tuple, actual)),
},
(Self::TupleIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Tuple,
actual: actual.into(),
}),
(&Self::ListIndex(index), List(list)) => Ok(list.get_mut(index)),
(&Self::ListIndex(index), Array(list)) => Ok(list.get_mut(index)),
(Self::ListIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::List,
actual: actual.into(),
}),
}
}
/// Returns a reference to this [`Access`]'s inner value as a [`&dyn Display`](fmt::Display).
pub fn display_value(&self) -> &dyn fmt::Display {
match self {
Self::Field(value) => value,
Self::FieldIndex(value) | Self::TupleIndex(value) | Self::ListIndex(value) => value,
}
}
pub(super) fn kind(&self) -> &'static str {
match self {
Self::Field(_) => "field",
Self::FieldIndex(_) => "field index",
Self::TupleIndex(_) | Self::ListIndex(_) => "index",
}
}
}

129
vendor/bevy_reflect/src/path/error.rs vendored Normal file
View File

@@ -0,0 +1,129 @@
use core::fmt;
use super::Access;
use crate::{ReflectKind, VariantType};
/// The kind of [`AccessError`], along with some kind-specific information.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AccessErrorKind {
/// An error that occurs when a certain type doesn't
/// contain the value referenced by the [`Access`].
MissingField(ReflectKind),
/// An error that occurs when using an [`Access`] on the wrong type.
/// (i.e. a [`ListIndex`](Access::ListIndex) on a struct, or a [`TupleIndex`](Access::TupleIndex) on a list)
IncompatibleTypes {
/// The [`ReflectKind`] that was expected based on the [`Access`].
expected: ReflectKind,
/// The actual [`ReflectKind`] that was found.
actual: ReflectKind,
},
/// An error that occurs when using an [`Access`] on the wrong enum variant.
/// (i.e. a [`ListIndex`](Access::ListIndex) on a struct variant, or a [`TupleIndex`](Access::TupleIndex) on a unit variant)
IncompatibleEnumVariantTypes {
/// The [`VariantType`] that was expected based on the [`Access`].
expected: VariantType,
/// The actual [`VariantType`] that was found.
actual: VariantType,
},
}
impl AccessErrorKind {
pub(super) fn with_access(self, access: Access, offset: Option<usize>) -> AccessError {
AccessError {
kind: self,
access,
offset,
}
}
}
/// An error originating from an [`Access`] of an element within a type.
///
/// Use the `Display` impl of this type to get information on the error.
///
/// Some sample messages:
///
/// ```text
/// Error accessing element with `.alpha` access (offset 14): The struct accessed doesn't have an "alpha" field
/// Error accessing element with '[0]' access: Expected index access to access a list, found a struct instead.
/// Error accessing element with '.4' access: Expected variant index access to access a Tuple variant, found a Unit variant instead.
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccessError<'a> {
pub(super) kind: AccessErrorKind,
pub(super) access: Access<'a>,
pub(super) offset: Option<usize>,
}
impl<'a> AccessError<'a> {
/// Returns the kind of [`AccessError`].
pub const fn kind(&self) -> &AccessErrorKind {
&self.kind
}
/// The returns the [`Access`] that this [`AccessError`] occurred in.
pub const fn access(&self) -> &Access {
&self.access
}
/// If the [`Access`] was created with a parser or an offset was manually provided,
/// returns the offset of the [`Access`] in its path string.
pub const fn offset(&self) -> Option<&usize> {
self.offset.as_ref()
}
}
impl fmt::Display for AccessError<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let AccessError {
kind,
access,
offset,
} = self;
write!(f, "Error accessing element with `{access}` access")?;
if let Some(offset) = offset {
write!(f, "(offset {offset})")?;
}
write!(f, ": ")?;
match kind {
AccessErrorKind::MissingField(type_accessed) => {
match access {
Access::Field(field) => write!(
f,
"The {type_accessed} accessed doesn't have {} `{}` field",
if let Some("a" | "e" | "i" | "o" | "u") = field.get(0..1) {
"an"
} else {
"a"
},
access.display_value()
),
Access::FieldIndex(_) => write!(
f,
"The {type_accessed} accessed doesn't have field index `{}`",
access.display_value(),
),
Access::TupleIndex(_) | Access::ListIndex(_) => write!(
f,
"The {type_accessed} accessed doesn't have index `{}`",
access.display_value()
)
}
}
AccessErrorKind::IncompatibleTypes { expected, actual } => write!(
f,
"Expected {} access to access a {expected}, found a {actual} instead.",
access.kind()
),
AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual } => write!(
f,
"Expected variant {} access to access a {expected:?} variant, found a {actual:?} variant instead.",
access.kind()
),
}
}
}
impl core::error::Error for AccessError<'_> {}

828
vendor/bevy_reflect/src/path/mod.rs vendored Normal file
View File

@@ -0,0 +1,828 @@
pub mod access;
pub use access::*;
mod error;
pub use error::*;
mod parse;
pub use parse::ParseError;
use parse::PathParser;
use crate::{PartialReflect, Reflect};
use alloc::vec::Vec;
use core::fmt;
use derive_more::derive::From;
use thiserror::Error;
type PathResult<'a, T> = Result<T, ReflectPathError<'a>>;
/// An error returned from a failed path string query.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum ReflectPathError<'a> {
/// An error caused by trying to access a path that's not able to be accessed,
/// see [`AccessError`] for details.
#[error(transparent)]
InvalidAccess(AccessError<'a>),
/// An error that occurs when a type cannot downcast to a given type.
#[error("Can't downcast result of access to the given type")]
InvalidDowncast,
/// An error caused by an invalid path string that couldn't be parsed.
#[error("Encountered an error at offset {offset} while parsing `{path}`: {error}")]
ParseError {
/// Position in `path`.
offset: usize,
/// The path that the error occurred in.
path: &'a str,
/// The underlying error.
error: ParseError<'a>,
},
}
impl<'a> From<AccessError<'a>> for ReflectPathError<'a> {
fn from(value: AccessError<'a>) -> Self {
ReflectPathError::InvalidAccess(value)
}
}
/// Something that can be interpreted as a reflection path in [`GetPath`].
pub trait ReflectPath<'a>: Sized {
/// Gets a reference to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::reflect_path`] for more details,
/// see [`element`](Self::element) if you want a typed return value.
fn reflect_element(self, root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect>;
/// Gets a mutable reference to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::reflect_path_mut`] for more details.
fn reflect_element_mut(
self,
root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect>;
/// Gets a `&T` to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::path`] for more details.
fn element<T: Reflect>(self, root: &dyn PartialReflect) -> PathResult<'a, &T> {
self.reflect_element(root).and_then(|p| {
p.try_downcast_ref::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
/// Gets a `&mut T` to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::path_mut`] for more details.
fn element_mut<T: Reflect>(self, root: &mut dyn PartialReflect) -> PathResult<'a, &mut T> {
self.reflect_element_mut(root).and_then(|p| {
p.try_downcast_mut::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
}
impl<'a> ReflectPath<'a> for &'a str {
fn reflect_element(self, mut root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect> {
for (access, offset) in PathParser::new(self) {
let a = access?;
root = a.element(root, Some(offset))?;
}
Ok(root)
}
fn reflect_element_mut(
self,
mut root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect> {
for (access, offset) in PathParser::new(self) {
root = access?.element_mut(root, Some(offset))?;
}
Ok(root)
}
}
/// A trait which allows nested [`Reflect`] values to be retrieved with path strings.
///
/// Using these functions repeatedly with the same string requires parsing the string every time.
/// To avoid this cost, it's recommended to construct a [`ParsedPath`] instead.
///
/// # Syntax
///
/// ## Structs
///
/// Field paths for [`Struct`] elements use the standard Rust field access syntax of
/// dot and field name: `.field_name`.
///
/// Additionally, struct fields may be accessed by their index within the struct's definition.
/// This is accomplished by using the hash symbol (`#`) in place of the standard dot: `#0`.
///
/// Accessing a struct's field by index can speed up fetches at runtime due to the removed
/// need for string matching.
/// And while this can be more performant, it's best to keep in mind the tradeoffs when
/// utilizing such optimizations.
/// For example, this can result in fairly fragile code as the string paths will need to be
/// kept in sync with the struct definitions since the order of fields could be easily changed.
/// Because of this, storing these kinds of paths in persistent storage (i.e. game assets)
/// is strongly discouraged.
///
/// Note that a leading dot (`.`) or hash (`#`) token is implied for the first item in a path,
/// and may therefore be omitted.
///
/// Additionally, an empty path may be used to get the struct itself.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect, PartialEq, Debug)]
/// struct MyStruct {
/// value: u32
/// }
///
/// let my_struct = MyStruct { value: 123 };
/// // Access via field name
/// assert_eq!(my_struct.path::<u32>(".value").unwrap(), &123);
/// // Access via field index
/// assert_eq!(my_struct.path::<u32>("#0").unwrap(), &123);
/// // Access self
/// assert_eq!(*my_struct.path::<MyStruct>("").unwrap(), my_struct);
/// ```
///
/// ## Tuples and Tuple Structs
///
/// [`Tuple`] and [`TupleStruct`] elements also follow a conventional Rust syntax.
/// Fields are accessed with a dot and the field index: `.0`.
///
/// Note that a leading dot (`.`) token is implied for the first item in a path,
/// and may therefore be omitted.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect)]
/// struct MyTupleStruct(u32);
///
/// let my_tuple_struct = MyTupleStruct(123);
/// assert_eq!(my_tuple_struct.path::<u32>(".0").unwrap(), &123);
/// ```
///
/// ## Lists and Arrays
///
/// [`List`] and [`Array`] elements are accessed with brackets: `[0]`.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath};
/// let my_list: Vec<u32> = vec![1, 2, 3];
/// assert_eq!(my_list.path::<u32>("[2]").unwrap(), &3);
/// ```
///
/// ## Enums
///
/// Pathing for [`Enum`] elements works a bit differently than in normal Rust.
/// Usually, you would need to pattern match an enum, branching off on the desired variants.
/// Paths used by this trait do not have any pattern matching capabilities;
/// instead, they assume the variant is already known ahead of time.
///
/// The syntax used, therefore, depends on the variant being accessed:
/// - Struct variants use the struct syntax (outlined above)
/// - Tuple variants use the tuple syntax (outlined above)
/// - Unit variants have no fields to access
///
/// If the variant cannot be known ahead of time, the path will need to be split up
/// and proper enum pattern matching will need to be handled manually.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect)]
/// enum MyEnum {
/// Unit,
/// Tuple(bool),
/// Struct {
/// value: u32
/// }
/// }
///
/// let tuple_variant = MyEnum::Tuple(true);
/// assert_eq!(tuple_variant.path::<bool>(".0").unwrap(), &true);
///
/// let struct_variant = MyEnum::Struct { value: 123 };
/// // Access via field name
/// assert_eq!(struct_variant.path::<u32>(".value").unwrap(), &123);
/// // Access via field index
/// assert_eq!(struct_variant.path::<u32>("#0").unwrap(), &123);
///
/// // Error: Expected struct variant
/// assert!(matches!(tuple_variant.path::<u32>(".value"), Err(_)));
/// ```
///
/// # Chaining
///
/// Using the aforementioned syntax, path items may be chained one after another
/// to create a full path to a nested element.
///
/// ## Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect)]
/// struct MyStruct {
/// value: Vec<Option<u32>>
/// }
///
/// let my_struct = MyStruct {
/// value: vec![None, None, Some(123)],
/// };
/// assert_eq!(
/// my_struct.path::<u32>(".value[2].0").unwrap(),
/// &123,
/// );
/// ```
///
/// [`Struct`]: crate::Struct
/// [`Tuple`]: crate::Tuple
/// [`TupleStruct`]: crate::TupleStruct
/// [`List`]: crate::List
/// [`Array`]: crate::Array
/// [`Enum`]: crate::Enum
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `GetPath` so cannot be accessed by reflection path",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait GetPath: PartialReflect {
/// Returns a reference to the value specified by `path`.
///
/// To retrieve a statically typed reference, use
/// [`path`][GetPath::path].
fn reflect_path<'p>(&self, path: impl ReflectPath<'p>) -> PathResult<'p, &dyn PartialReflect> {
path.reflect_element(self.as_partial_reflect())
}
/// Returns a mutable reference to the value specified by `path`.
///
/// To retrieve a statically typed mutable reference, use
/// [`path_mut`][GetPath::path_mut].
fn reflect_path_mut<'p>(
&mut self,
path: impl ReflectPath<'p>,
) -> PathResult<'p, &mut dyn PartialReflect> {
path.reflect_element_mut(self.as_partial_reflect_mut())
}
/// Returns a statically typed reference to the value specified by `path`.
///
/// This will automatically handle downcasting to type `T`.
/// The downcast will fail if this value is not of type `T`
/// (which may be the case when using dynamic types like [`DynamicStruct`]).
///
/// [`DynamicStruct`]: crate::DynamicStruct
fn path<'p, T: Reflect>(&self, path: impl ReflectPath<'p>) -> PathResult<'p, &T> {
path.element(self.as_partial_reflect())
}
/// Returns a statically typed mutable reference to the value specified by `path`.
///
/// This will automatically handle downcasting to type `T`.
/// The downcast will fail if this value is not of type `T`
/// (which may be the case when using dynamic types like [`DynamicStruct`]).
///
/// [`DynamicStruct`]: crate::DynamicStruct
fn path_mut<'p, T: Reflect>(&mut self, path: impl ReflectPath<'p>) -> PathResult<'p, &mut T> {
path.element_mut(self.as_partial_reflect_mut())
}
}
// Implement `GetPath` for `dyn Reflect`
impl<T: Reflect + ?Sized> GetPath for T {}
/// An [`Access`] combined with an `offset` for more helpful error reporting.
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct OffsetAccess {
/// The [`Access`] itself.
pub access: Access<'static>,
/// A character offset in the string the path was parsed from.
pub offset: Option<usize>,
}
impl From<Access<'static>> for OffsetAccess {
fn from(access: Access<'static>) -> Self {
OffsetAccess {
access,
offset: None,
}
}
}
/// A pre-parsed path to an element within a type.
///
/// This struct can be constructed manually from its [`Access`]es or with
/// the [parse](ParsedPath::parse) method.
///
/// This struct may be used like [`GetPath`] but removes the cost of parsing the path
/// string at each element access.
///
/// It's recommended to use this in place of [`GetPath`] when the path string is
/// unlikely to be changed and will be accessed repeatedly.
///
/// ## Examples
///
/// Parsing a [`&'static str`](str):
/// ```
/// # use bevy_reflect::ParsedPath;
/// let my_static_string: &'static str = "bar#0.1[2].0";
/// // Breakdown:
/// // "bar" - Access struct field named "bar"
/// // "#0" - Access struct field at index 0
/// // ".1" - Access tuple struct field at index 1
/// // "[2]" - Access list element at index 2
/// // ".0" - Access tuple variant field at index 0
/// let my_path = ParsedPath::parse_static(my_static_string);
/// ```
/// Parsing a non-static [`&str`](str):
/// ```
/// # use bevy_reflect::ParsedPath;
/// let my_string = String::from("bar#0.1[2].0");
/// // Breakdown:
/// // "bar" - Access struct field named "bar"
/// // "#0" - Access struct field at index 0
/// // ".1" - Access tuple struct field at index 1
/// // "[2]" - Access list element at index 2
/// // ".0" - Access tuple variant field at index 0
/// let my_path = ParsedPath::parse(&my_string);
/// ```
/// Manually constructing a [`ParsedPath`]:
/// ```
/// # use std::borrow::Cow;
/// # use bevy_reflect::access::Access;
/// # use bevy_reflect::ParsedPath;
/// let path_elements = [
/// Access::Field(Cow::Borrowed("bar")),
/// Access::FieldIndex(0),
/// Access::TupleIndex(1),
/// Access::ListIndex(2),
/// Access::TupleIndex(1),
/// ];
/// let my_path = ParsedPath::from(path_elements);
/// ```
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, From)]
pub struct ParsedPath(
/// This is a vector of pre-parsed [`OffsetAccess`]es.
pub Vec<OffsetAccess>,
);
impl ParsedPath {
/// Parses a [`ParsedPath`] from a string.
///
/// Returns an error if the string does not represent a valid path to an element.
///
/// The exact format for path strings can be found in the documentation for [`GetPath`].
/// In short, though, a path consists of one or more chained accessor strings.
/// These are:
/// - Named field access (`.field`)
/// - Unnamed field access (`.1`)
/// - Field index access (`#0`)
/// - Sequence access (`[2]`)
///
/// # Example
/// ```
/// # use bevy_reflect::{ParsedPath, Reflect, ReflectPath};
/// #[derive(Reflect)]
/// struct Foo {
/// bar: Bar,
/// }
///
/// #[derive(Reflect)]
/// struct Bar {
/// baz: Baz,
/// }
///
/// #[derive(Reflect)]
/// struct Baz(f32, Vec<Option<u32>>);
///
/// let foo = Foo {
/// bar: Bar {
/// baz: Baz(3.14, vec![None, None, Some(123)])
/// },
/// };
///
/// let parsed_path = ParsedPath::parse("bar#0.1[2].0").unwrap();
/// // Breakdown:
/// // "bar" - Access struct field named "bar"
/// // "#0" - Access struct field at index 0
/// // ".1" - Access tuple struct field at index 1
/// // "[2]" - Access list element at index 2
/// // ".0" - Access tuple variant field at index 0
///
/// assert_eq!(parsed_path.element::<u32>(&foo).unwrap(), &123);
/// ```
pub fn parse(string: &str) -> PathResult<Self> {
let mut parts = Vec::new();
for (access, offset) in PathParser::new(string) {
parts.push(OffsetAccess {
access: access?.into_owned(),
offset: Some(offset),
});
}
Ok(Self(parts))
}
/// Similar to [`Self::parse`] but only works on `&'static str`
/// and does not allocate per named field.
pub fn parse_static(string: &'static str) -> PathResult<'static, Self> {
let mut parts = Vec::new();
for (access, offset) in PathParser::new(string) {
parts.push(OffsetAccess {
access: access?,
offset: Some(offset),
});
}
Ok(Self(parts))
}
}
impl<'a> ReflectPath<'a> for &'a ParsedPath {
fn reflect_element(self, mut root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect> {
for OffsetAccess { access, offset } in &self.0 {
root = access.element(root, *offset)?;
}
Ok(root)
}
fn reflect_element_mut(
self,
mut root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect> {
for OffsetAccess { access, offset } in &self.0 {
root = access.element_mut(root, *offset)?;
}
Ok(root)
}
}
impl<const N: usize> From<[OffsetAccess; N]> for ParsedPath {
fn from(value: [OffsetAccess; N]) -> Self {
ParsedPath(value.to_vec())
}
}
impl From<Vec<Access<'static>>> for ParsedPath {
fn from(value: Vec<Access<'static>>) -> Self {
ParsedPath(
value
.into_iter()
.map(|access| OffsetAccess {
access,
offset: None,
})
.collect(),
)
}
}
impl<const N: usize> From<[Access<'static>; N]> for ParsedPath {
fn from(value: [Access<'static>; N]) -> Self {
value.to_vec().into()
}
}
impl<'a> TryFrom<&'a str> for ParsedPath {
type Error = ReflectPathError<'a>;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
ParsedPath::parse(value)
}
}
impl fmt::Display for ParsedPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for OffsetAccess { access, .. } in &self.0 {
write!(f, "{access}")?;
}
Ok(())
}
}
impl core::ops::Index<usize> for ParsedPath {
type Output = OffsetAccess;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl core::ops::IndexMut<usize> for ParsedPath {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
#[cfg(test)]
#[expect(
clippy::approx_constant,
reason = "We don't need the exact value of Pi here."
)]
mod tests {
use super::*;
use crate::*;
use alloc::vec;
#[derive(Reflect, PartialEq, Debug)]
struct A {
w: usize,
x: B,
y: Vec<C>,
z: D,
unit_variant: F,
tuple_variant: F,
struct_variant: F,
array: [i32; 3],
tuple: (bool, f32),
}
#[derive(Reflect, PartialEq, Debug)]
struct B {
foo: usize,
łø: C,
}
#[derive(Reflect, PartialEq, Debug)]
struct C {
mосква: f32,
}
#[derive(Reflect, PartialEq, Debug)]
struct D(E);
#[derive(Reflect, PartialEq, Debug)]
struct E(f32, usize);
#[derive(Reflect, PartialEq, Debug)]
enum F {
Unit,
Tuple(u32, u32),
Şķràźÿ { : char },
}
fn a_sample() -> A {
A {
w: 1,
x: B {
foo: 10,
łø: C { mосква: 3.14 },
},
y: vec![C { mосква: 1.0 }, C { mосква: 2.0 }],
z: D(E(10.0, 42)),
unit_variant: F::Unit,
tuple_variant: F::Tuple(123, 321),
struct_variant: F::Şķràźÿ { : 'm' },
array: [86, 75, 309],
tuple: (true, 1.23),
}
}
fn offset(access: Access<'static>, offset: usize) -> OffsetAccess {
OffsetAccess {
access,
offset: Some(offset),
}
}
fn access_field(field: &'static str) -> Access<'static> {
Access::Field(field.into())
}
type StaticError = ReflectPathError<'static>;
fn invalid_access(
offset: usize,
actual: ReflectKind,
expected: ReflectKind,
access: &'static str,
) -> StaticError {
ReflectPathError::InvalidAccess(AccessError {
kind: AccessErrorKind::IncompatibleTypes { actual, expected },
access: ParsedPath::parse_static(access).unwrap()[1].access.clone(),
offset: Some(offset),
})
}
#[test]
fn try_from() {
assert_eq!(
ParsedPath::try_from("w").unwrap().0,
&[offset(access_field("w"), 1)]
);
let r = ParsedPath::try_from("w[");
let matches = matches!(r, Err(ReflectPathError::ParseError { .. }));
assert!(
matches,
"ParsedPath::try_from did not return a ParseError for \"w[\""
);
}
#[test]
fn parsed_path_parse() {
assert_eq!(
ParsedPath::parse("w").unwrap().0,
&[offset(access_field("w"), 1)]
);
assert_eq!(
ParsedPath::parse("x.foo").unwrap().0,
&[offset(access_field("x"), 1), offset(access_field("foo"), 2)]
);
assert_eq!(
ParsedPath::parse("x.łørđ.mосква").unwrap().0,
&[
offset(access_field("x"), 1),
offset(access_field("łørđ"), 2),
offset(access_field("mосква"), 10)
]
);
assert_eq!(
ParsedPath::parse("y[1].mосква").unwrap().0,
&[
offset(access_field("y"), 1),
offset(Access::ListIndex(1), 2),
offset(access_field("mосква"), 5)
]
);
assert_eq!(
ParsedPath::parse("z.0.1").unwrap().0,
&[
offset(access_field("z"), 1),
offset(Access::TupleIndex(0), 2),
offset(Access::TupleIndex(1), 4),
]
);
assert_eq!(
ParsedPath::parse("x#0").unwrap().0,
&[
offset(access_field("x"), 1),
offset(Access::FieldIndex(0), 2)
]
);
assert_eq!(
ParsedPath::parse("x#0#1").unwrap().0,
&[
offset(access_field("x"), 1),
offset(Access::FieldIndex(0), 2),
offset(Access::FieldIndex(1), 4)
]
);
}
#[test]
fn parsed_path_get_field() {
let a = a_sample();
let b = ParsedPath::parse("w").unwrap();
let c = ParsedPath::parse("x.foo").unwrap();
let d = ParsedPath::parse("x.łørđ.mосква").unwrap();
let e = ParsedPath::parse("y[1].mосква").unwrap();
let f = ParsedPath::parse("z.0.1").unwrap();
let g = ParsedPath::parse("x#0").unwrap();
let h = ParsedPath::parse("x#1#0").unwrap();
let i = ParsedPath::parse("unit_variant").unwrap();
let j = ParsedPath::parse("tuple_variant.1").unwrap();
let k = ParsedPath::parse("struct_variant.東京").unwrap();
let l = ParsedPath::parse("struct_variant#0").unwrap();
let m = ParsedPath::parse("array[2]").unwrap();
let n = ParsedPath::parse("tuple.1").unwrap();
for _ in 0..30 {
assert_eq!(*b.element::<usize>(&a).unwrap(), 1);
assert_eq!(*c.element::<usize>(&a).unwrap(), 10);
assert_eq!(*d.element::<f32>(&a).unwrap(), 3.14);
assert_eq!(*e.element::<f32>(&a).unwrap(), 2.0);
assert_eq!(*f.element::<usize>(&a).unwrap(), 42);
assert_eq!(*g.element::<usize>(&a).unwrap(), 10);
assert_eq!(*h.element::<f32>(&a).unwrap(), 3.14);
assert_eq!(*i.element::<F>(&a).unwrap(), F::Unit);
assert_eq!(*j.element::<u32>(&a).unwrap(), 321);
assert_eq!(*k.element::<char>(&a).unwrap(), 'm');
assert_eq!(*l.element::<char>(&a).unwrap(), 'm');
assert_eq!(*m.element::<i32>(&a).unwrap(), 309);
assert_eq!(*n.element::<f32>(&a).unwrap(), 1.23);
}
}
#[test]
fn reflect_array_behaves_like_list() {
#[derive(Reflect)]
struct A {
list: Vec<u8>,
array: [u8; 10],
}
let a = A {
list: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
};
assert_eq!(*a.path::<u8>("list[5]").unwrap(), 5);
assert_eq!(*a.path::<u8>("array[5]").unwrap(), 5);
assert_eq!(*a.path::<u8>("list[0]").unwrap(), 0);
assert_eq!(*a.path::<u8>("array[0]").unwrap(), 0);
}
#[test]
fn reflect_array_behaves_like_list_mut() {
#[derive(Reflect)]
struct A {
list: Vec<u8>,
array: [u8; 10],
}
let mut a = A {
list: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
};
assert_eq!(*a.path_mut::<u8>("list[5]").unwrap(), 5);
assert_eq!(*a.path_mut::<u8>("array[5]").unwrap(), 5);
*a.path_mut::<u8>("list[5]").unwrap() = 10;
*a.path_mut::<u8>("array[5]").unwrap() = 10;
assert_eq!(*a.path_mut::<u8>("list[5]").unwrap(), 10);
assert_eq!(*a.path_mut::<u8>("array[5]").unwrap(), 10);
}
#[test]
fn reflect_path() {
let mut a = a_sample();
assert_eq!(*a.path::<A>("").unwrap(), a);
assert_eq!(*a.path::<usize>("w").unwrap(), 1);
assert_eq!(*a.path::<usize>("x.foo").unwrap(), 10);
assert_eq!(*a.path::<f32>("x.łørđ.mосква").unwrap(), 3.14);
assert_eq!(*a.path::<f32>("y[1].mосква").unwrap(), 2.0);
assert_eq!(*a.path::<usize>("z.0.1").unwrap(), 42);
assert_eq!(*a.path::<usize>("x#0").unwrap(), 10);
assert_eq!(*a.path::<f32>("x#1#0").unwrap(), 3.14);
assert_eq!(*a.path::<F>("unit_variant").unwrap(), F::Unit);
assert_eq!(*a.path::<u32>("tuple_variant.1").unwrap(), 321);
assert_eq!(*a.path::<char>("struct_variant.東京").unwrap(), 'm');
assert_eq!(*a.path::<char>("struct_variant#0").unwrap(), 'm');
assert_eq!(*a.path::<i32>("array[2]").unwrap(), 309);
assert_eq!(*a.path::<f32>("tuple.1").unwrap(), 1.23);
*a.path_mut::<f32>("tuple.1").unwrap() = 3.21;
assert_eq!(*a.path::<f32>("tuple.1").unwrap(), 3.21);
*a.path_mut::<f32>("y[1].mосква").unwrap() = 3.0;
assert_eq!(a.y[1].mосква, 3.0);
*a.path_mut::<u32>("tuple_variant.0").unwrap() = 1337;
assert_eq!(a.tuple_variant, F::Tuple(1337, 321));
assert_eq!(
a.reflect_path("x.notreal").err().unwrap(),
ReflectPathError::InvalidAccess(AccessError {
kind: AccessErrorKind::MissingField(ReflectKind::Struct),
access: access_field("notreal"),
offset: Some(2),
})
);
assert_eq!(
a.reflect_path("unit_variant.0").err().unwrap(),
ReflectPathError::InvalidAccess(AccessError {
kind: AccessErrorKind::IncompatibleEnumVariantTypes {
actual: VariantType::Unit,
expected: VariantType::Tuple,
},
access: ParsedPath::parse_static("unit_variant.0").unwrap()[1]
.access
.clone(),
offset: Some(13),
})
);
assert_eq!(
a.reflect_path("x[0]").err().unwrap(),
invalid_access(2, ReflectKind::Struct, ReflectKind::List, "x[0]")
);
assert_eq!(
a.reflect_path("y.x").err().unwrap(),
invalid_access(2, ReflectKind::List, ReflectKind::Struct, "y.x")
);
}
#[test]
fn accept_leading_tokens() {
assert_eq!(
ParsedPath::parse(".w").unwrap().0,
&[offset(access_field("w"), 1)]
);
assert_eq!(
ParsedPath::parse("#0.foo").unwrap().0,
&[
offset(Access::FieldIndex(0), 1),
offset(access_field("foo"), 3)
]
);
assert_eq!(
ParsedPath::parse(".5").unwrap().0,
&[offset(Access::TupleIndex(5), 1)]
);
assert_eq!(
ParsedPath::parse("[0].łørđ").unwrap().0,
&[
offset(Access::ListIndex(0), 1),
offset(access_field("łørđ"), 4)
]
);
}
}

200
vendor/bevy_reflect/src/path/parse.rs vendored Normal file
View File

@@ -0,0 +1,200 @@
use core::{
fmt::{self, Write},
num::ParseIntError,
str::from_utf8_unchecked,
};
use thiserror::Error;
use super::{Access, ReflectPathError};
/// An error that occurs when parsing reflect path strings.
#[derive(Debug, PartialEq, Eq, Error)]
#[error(transparent)]
pub struct ParseError<'a>(Error<'a>);
/// A parse error for a path string.
#[derive(Debug, PartialEq, Eq, Error)]
enum Error<'a> {
#[error("expected an identifier, but reached end of path string")]
NoIdent,
#[error("expected an identifier, got '{0}' instead")]
ExpectedIdent(Token<'a>),
#[error("failed to parse index as integer")]
InvalidIndex(#[from] ParseIntError),
#[error("a '[' wasn't closed, reached end of path string before finding a ']'")]
Unclosed,
#[error("a '[' wasn't closed properly, got '{0}' instead")]
BadClose(Token<'a>),
#[error("a ']' was found before an opening '['")]
CloseBeforeOpen,
}
pub(super) struct PathParser<'a> {
path: &'a str,
remaining: &'a [u8],
}
impl<'a> PathParser<'a> {
pub(super) fn new(path: &'a str) -> Self {
let remaining = path.as_bytes();
PathParser { path, remaining }
}
fn next_token(&mut self) -> Option<Token<'a>> {
let to_parse = self.remaining;
// Return with `None` if empty.
let (first_byte, remaining) = to_parse.split_first()?;
if let Some(token) = Token::symbol_from_byte(*first_byte) {
self.remaining = remaining; // NOTE: all symbols are ASCII
return Some(token);
}
// We are parsing either `0123` or `field`.
// If we do not find a subsequent token, we are at the end of the parse string.
let ident_len = to_parse.iter().position(|t| Token::SYMBOLS.contains(t));
let (ident, remaining) = to_parse.split_at(ident_len.unwrap_or(to_parse.len()));
// SAFETY: This relies on `self.remaining` always remaining valid UTF8:
// - self.remaining is a slice derived from self.path (valid &str)
// - The slice's end is either the same as the valid &str or
// the last byte before an ASCII utf-8 character (ie: it is a char
// boundary).
// - The slice always starts after a symbol ie: an ASCII character's boundary.
#[expect(
unsafe_code,
reason = "We have fulfilled the Safety requirements for `from_utf8_unchecked`."
)]
let ident = unsafe { from_utf8_unchecked(ident) };
self.remaining = remaining;
Some(Token::Ident(Ident(ident)))
}
fn next_ident(&mut self) -> Result<Ident<'a>, Error<'a>> {
match self.next_token() {
Some(Token::Ident(ident)) => Ok(ident),
Some(other) => Err(Error::ExpectedIdent(other)),
None => Err(Error::NoIdent),
}
}
fn access_following(&mut self, token: Token<'a>) -> Result<Access<'a>, Error<'a>> {
match token {
Token::Dot => Ok(self.next_ident()?.field()),
Token::Pound => self.next_ident()?.field_index(),
Token::Ident(ident) => Ok(ident.field()),
Token::CloseBracket => Err(Error::CloseBeforeOpen),
Token::OpenBracket => {
let index_ident = self.next_ident()?.list_index()?;
match self.next_token() {
Some(Token::CloseBracket) => Ok(index_ident),
Some(other) => Err(Error::BadClose(other)),
None => Err(Error::Unclosed),
}
}
}
}
fn offset(&self) -> usize {
self.path.len() - self.remaining.len()
}
}
impl<'a> Iterator for PathParser<'a> {
type Item = (Result<Access<'a>, ReflectPathError<'a>>, usize);
fn next(&mut self) -> Option<Self::Item> {
let token = self.next_token()?;
let offset = self.offset();
Some((
self.access_following(token)
.map_err(|error| ReflectPathError::ParseError {
offset,
path: self.path,
error: ParseError(error),
}),
offset,
))
}
}
#[derive(Debug, PartialEq, Eq)]
struct Ident<'a>(&'a str);
impl<'a> Ident<'a> {
fn field(self) -> Access<'a> {
let field = |_| Access::Field(self.0.into());
self.0.parse().map(Access::TupleIndex).unwrap_or_else(field)
}
fn field_index(self) -> Result<Access<'a>, Error<'a>> {
Ok(Access::FieldIndex(self.0.parse()?))
}
fn list_index(self) -> Result<Access<'a>, Error<'a>> {
Ok(Access::ListIndex(self.0.parse()?))
}
}
// NOTE: We use repr(u8) so that the `match byte` in `Token::symbol_from_byte`
// becomes a "check `byte` is one of SYMBOLS and forward its value" this makes
// the optimizer happy, and shaves off a few cycles.
#[derive(Debug, PartialEq, Eq)]
#[repr(u8)]
enum Token<'a> {
Dot = b'.',
Pound = b'#',
OpenBracket = b'[',
CloseBracket = b']',
Ident(Ident<'a>),
}
impl fmt::Display for Token<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Token::Dot => f.write_char('.'),
Token::Pound => f.write_char('#'),
Token::OpenBracket => f.write_char('['),
Token::CloseBracket => f.write_char(']'),
Token::Ident(ident) => f.write_str(ident.0),
}
}
}
impl<'a> Token<'a> {
const SYMBOLS: &'static [u8] = b".#[]";
fn symbol_from_byte(byte: u8) -> Option<Self> {
match byte {
b'.' => Some(Self::Dot),
b'#' => Some(Self::Pound),
b'[' => Some(Self::OpenBracket),
b']' => Some(Self::CloseBracket),
_ => None,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::path::ParsedPath;
#[test]
fn parse_invalid() {
assert_eq!(
ParsedPath::parse_static("x.."),
Err(ReflectPathError::ParseError {
error: ParseError(Error::ExpectedIdent(Token::Dot)),
offset: 2,
path: "x..",
}),
);
assert!(matches!(
ParsedPath::parse_static("y[badindex]"),
Err(ReflectPathError::ParseError {
error: ParseError(Error::InvalidIndex(_)),
offset: 2,
path: "y[badindex]",
}),
));
}
}

644
vendor/bevy_reflect/src/reflect.rs vendored Normal file
View File

@@ -0,0 +1,644 @@
use crate::{
array_debug, enum_debug, list_debug, map_debug, set_debug, struct_debug, tuple_debug,
tuple_struct_debug, DynamicTypePath, DynamicTyped, OpaqueInfo, ReflectCloneError, ReflectKind,
ReflectKindMismatchError, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, Typed,
};
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::string::ToString;
use core::{
any::{Any, TypeId},
fmt::Debug,
};
use thiserror::Error;
use crate::utility::NonGenericTypeInfoCell;
/// A enumeration of all error outcomes that might happen when running [`try_apply`](PartialReflect::try_apply).
#[derive(Error, Debug)]
pub enum ApplyError {
#[error("attempted to apply `{from_kind}` to `{to_kind}`")]
/// Attempted to apply the wrong [kind](ReflectKind) to a type, e.g. a struct to an enum.
MismatchedKinds {
from_kind: ReflectKind,
to_kind: ReflectKind,
},
#[error("enum variant `{variant_name}` doesn't have a field named `{field_name}`")]
/// Enum variant that we tried to apply to was missing a field.
MissingEnumField {
variant_name: Box<str>,
field_name: Box<str>,
},
#[error("`{from_type}` is not `{to_type}`")]
/// Tried to apply incompatible types.
MismatchedTypes {
from_type: Box<str>,
to_type: Box<str>,
},
#[error("attempted to apply type with {from_size} size to a type with {to_size} size")]
/// Attempted to apply to types with mismatched sizes, e.g. a [u8; 4] to [u8; 3].
DifferentSize { from_size: usize, to_size: usize },
#[error("variant with name `{variant_name}` does not exist on enum `{enum_name}`")]
/// The enum we tried to apply to didn't contain a variant with the give name.
UnknownVariant {
enum_name: Box<str>,
variant_name: Box<str>,
},
}
impl From<ReflectKindMismatchError> for ApplyError {
fn from(value: ReflectKindMismatchError) -> Self {
Self::MismatchedKinds {
from_kind: value.received,
to_kind: value.expected,
}
}
}
/// The foundational trait of [`bevy_reflect`], used for accessing and modifying data dynamically.
///
/// This is a supertrait of [`Reflect`],
/// meaning any type which implements `Reflect` implements `PartialReflect` by definition.
///
/// It's recommended to use [the derive macro for `Reflect`] rather than manually implementing this trait.
/// Doing so will automatically implement this trait as well as many other useful traits for reflection,
/// including one of the appropriate subtraits: [`Struct`], [`TupleStruct`] or [`Enum`].
///
/// See the [crate-level documentation] to see how this trait and its subtraits can be used.
///
/// [`bevy_reflect`]: crate
/// [the derive macro for `Reflect`]: bevy_reflect_derive::Reflect
/// [`Struct`]: crate::Struct
/// [`TupleStruct`]: crate::TupleStruct
/// [`Enum`]: crate::Enum
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `PartialReflect` so cannot be introspected",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait PartialReflect: DynamicTypePath + Send + Sync
where
// NB: we don't use `Self: Any` since for downcasting, `Reflect` should be used.
Self: 'static,
{
/// Returns the [`TypeInfo`] of the type _represented_ by this value.
///
/// For most types, this will simply return their own `TypeInfo`.
/// However, for dynamic types, such as [`DynamicStruct`] or [`DynamicList`],
/// this will return the type they represent
/// (or `None` if they don't represent any particular type).
///
/// This method is great if you have an instance of a type or a `dyn Reflect`,
/// and want to access its [`TypeInfo`]. However, if this method is to be called
/// frequently, consider using [`TypeRegistry::get_type_info`] as it can be more
/// performant for such use cases.
///
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicList`]: crate::DynamicList
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>;
/// Casts this type to a boxed, reflected value.
///
/// This is useful for coercing trait objects.
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect>;
/// Casts this type to a reflected value.
///
/// This is useful for coercing trait objects.
fn as_partial_reflect(&self) -> &dyn PartialReflect;
/// Casts this type to a mutable, reflected value.
///
/// This is useful for coercing trait objects.
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect;
/// Attempts to cast this type to a boxed, [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>;
/// Attempts to cast this type to a [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_as_reflect(&self) -> Option<&dyn Reflect>;
/// Attempts to cast this type to a mutable, [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect>;
/// Applies a reflected value to this value.
///
/// If a type implements an [introspection subtrait], then the semantics of this
/// method are as follows:
/// - If `T` is a [`Struct`], then the value of each named field of `value` is
/// applied to the corresponding named field of `self`. Fields which are
/// not present in both structs are ignored.
/// - If `T` is a [`TupleStruct`] or [`Tuple`], then the value of each
/// numbered field is applied to the corresponding numbered field of
/// `self.` Fields which are not present in both values are ignored.
/// - If `T` is an [`Enum`], then the variant of `self` is `updated` to match
/// the variant of `value`. The corresponding fields of that variant are
/// applied from `value` onto `self`. Fields which are not present in both
/// values are ignored.
/// - If `T` is a [`List`] or [`Array`], then each element of `value` is applied
/// to the corresponding element of `self`. Up to `self.len()` items are applied,
/// and excess elements in `value` are appended to `self`.
/// - If `T` is a [`Map`], then for each key in `value`, the associated
/// value is applied to the value associated with the same key in `self`.
/// Keys which are not present in `self` are inserted.
/// - If `T` is none of these, then `value` is downcast to `T`, cloned, and
/// assigned to `self`.
///
/// Note that `Reflect` must be implemented manually for [`List`]s and
/// [`Map`]s in order to achieve the correct semantics, as derived
/// implementations will have the semantics for [`Struct`], [`TupleStruct`], [`Enum`]
/// or none of the above depending on the kind of type. For lists and maps, use the
/// [`list_apply`] and [`map_apply`] helper functions when implementing this method.
///
/// [introspection subtrait]: crate#the-introspection-subtraits
/// [`Struct`]: crate::Struct
/// [`TupleStruct`]: crate::TupleStruct
/// [`Tuple`]: crate::Tuple
/// [`Enum`]: crate::Enum
/// [`List`]: crate::List
/// [`Array`]: crate::Array
/// [`Map`]: crate::Map
/// [`list_apply`]: crate::list_apply
/// [`map_apply`]: crate::map_apply
///
/// # Panics
///
/// Derived implementations of this method will panic:
/// - If the type of `value` is not of the same kind as `T` (e.g. if `T` is
/// a `List`, while `value` is a `Struct`).
/// - If `T` is any complex type and the corresponding fields or elements of
/// `self` and `value` are not of the same type.
/// - If `T` is an opaque type and `self` cannot be downcast to `T`
fn apply(&mut self, value: &dyn PartialReflect) {
PartialReflect::try_apply(self, value).unwrap();
}
/// Tries to [`apply`](PartialReflect::apply) a reflected value to this value.
///
/// Functions the same as the [`apply`](PartialReflect::apply) function but returns an error instead of
/// panicking.
///
/// # Handling Errors
///
/// This function may leave `self` in a partially mutated state if a error was encountered on the way.
/// consider maintaining a cloned instance of this data you can switch to if a error is encountered.
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError>;
/// Returns a zero-sized enumeration of "kinds" of type.
///
/// See [`ReflectKind`].
fn reflect_kind(&self) -> ReflectKind {
self.reflect_ref().kind()
}
/// Returns an immutable enumeration of "kinds" of type.
///
/// See [`ReflectRef`].
fn reflect_ref(&self) -> ReflectRef;
/// Returns a mutable enumeration of "kinds" of type.
///
/// See [`ReflectMut`].
fn reflect_mut(&mut self) -> ReflectMut;
/// Returns an owned enumeration of "kinds" of type.
///
/// See [`ReflectOwned`].
fn reflect_owned(self: Box<Self>) -> ReflectOwned;
/// Clones `Self` into its dynamic representation.
///
/// For value types or types marked with `#[reflect_value]`,
/// this will simply return a clone of `Self`.
///
/// Otherwise the associated dynamic type will be returned.
///
/// For example, a [`List`] type will invoke [`List::clone_dynamic`], returning [`DynamicList`].
/// A [`Struct`] type will invoke [`Struct::clone_dynamic`], returning [`DynamicStruct`].
/// And so on.
///
/// If the dynamic behavior is not desired, a concrete clone can be obtained using [`PartialReflect::reflect_clone`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::{PartialReflect};
/// let value = (1, true, 3.14);
/// let cloned = value.clone_value();
/// assert!(cloned.is_dynamic())
/// ```
///
/// [`List`]: crate::List
/// [`List::clone_dynamic`]: crate::List::clone_dynamic
/// [`DynamicList`]: crate::DynamicList
/// [`Struct`]: crate::Struct
/// [`Struct::clone_dynamic`]: crate::Struct::clone_dynamic
/// [`DynamicStruct`]: crate::DynamicStruct
#[deprecated(
since = "0.16.0",
note = "to clone reflected values, prefer using `reflect_clone`. To convert reflected values to dynamic ones, use `to_dynamic`."
)]
fn clone_value(&self) -> Box<dyn PartialReflect> {
self.to_dynamic()
}
/// Converts this reflected value into its dynamic representation based on its [kind].
///
/// For example, a [`List`] type will internally invoke [`List::to_dynamic_list`], returning [`DynamicList`].
/// A [`Struct`] type will invoke [`Struct::to_dynamic_struct`], returning [`DynamicStruct`].
/// And so on.
///
/// If the [kind] is [opaque], then the value will attempt to be cloned directly via [`reflect_clone`],
/// since opaque types do not have any standard dynamic representation.
///
/// To attempt to clone the value directly such that it returns a concrete instance of this type,
/// use [`reflect_clone`].
///
/// # Panics
///
/// This method will panic if the [kind] is [opaque] and the call to [`reflect_clone`] fails.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{PartialReflect};
/// let value = (1, true, 3.14);
/// let dynamic_value = value.to_dynamic();
/// assert!(dynamic_value.is_dynamic())
/// ```
///
/// [kind]: PartialReflect::reflect_kind
/// [`List`]: crate::List
/// [`List::to_dynamic_list`]: crate::List::to_dynamic_list
/// [`DynamicList`]: crate::DynamicList
/// [`Struct`]: crate::Struct
/// [`Struct::to_dynamic_struct`]: crate::Struct::to_dynamic_struct
/// [`DynamicStruct`]: crate::DynamicStruct
/// [opaque]: crate::ReflectKind::Opaque
/// [`reflect_clone`]: PartialReflect::reflect_clone
fn to_dynamic(&self) -> Box<dyn PartialReflect> {
match self.reflect_ref() {
ReflectRef::Struct(dyn_struct) => Box::new(dyn_struct.to_dynamic_struct()),
ReflectRef::TupleStruct(dyn_tuple_struct) => {
Box::new(dyn_tuple_struct.to_dynamic_tuple_struct())
}
ReflectRef::Tuple(dyn_tuple) => Box::new(dyn_tuple.to_dynamic_tuple()),
ReflectRef::List(dyn_list) => Box::new(dyn_list.to_dynamic_list()),
ReflectRef::Array(dyn_array) => Box::new(dyn_array.to_dynamic_array()),
ReflectRef::Map(dyn_map) => Box::new(dyn_map.to_dynamic_map()),
ReflectRef::Set(dyn_set) => Box::new(dyn_set.to_dynamic_set()),
ReflectRef::Enum(dyn_enum) => Box::new(dyn_enum.to_dynamic_enum()),
#[cfg(feature = "functions")]
ReflectRef::Function(dyn_function) => Box::new(dyn_function.to_dynamic_function()),
ReflectRef::Opaque(value) => value.reflect_clone().unwrap().into_partial_reflect(),
}
}
/// Attempts to clone `Self` using reflection.
///
/// Unlike [`to_dynamic`], which generally returns a dynamic representation of `Self`,
/// this method attempts create a clone of `Self` directly, if possible.
///
/// If the clone cannot be performed, an appropriate [`ReflectCloneError`] is returned.
///
/// # Example
///
/// ```
/// # use bevy_reflect::PartialReflect;
/// let value = (1, true, 3.14);
/// let cloned = value.reflect_clone().unwrap();
/// assert!(cloned.is::<(i32, bool, f64)>())
/// ```
///
/// [`to_dynamic`]: PartialReflect::to_dynamic
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Err(ReflectCloneError::NotImplemented {
type_path: Cow::Owned(self.reflect_type_path().to_string()),
})
}
/// Returns a hash of the value (which includes the type).
///
/// If the underlying type does not support hashing, returns `None`.
fn reflect_hash(&self) -> Option<u64> {
None
}
/// Returns a "partial equality" comparison result.
///
/// If the underlying type does not support equality testing, returns `None`.
fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {
None
}
/// Debug formatter for the value.
///
/// Any value that is not an implementor of other `Reflect` subtraits
/// (e.g. [`List`], [`Map`]), will default to the format: `"Reflect(type_path)"`,
/// where `type_path` is the [type path] of the underlying type.
///
/// [`List`]: crate::List
/// [`Map`]: crate::Map
/// [type path]: TypePath::type_path
fn debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.reflect_ref() {
ReflectRef::Struct(dyn_struct) => struct_debug(dyn_struct, f),
ReflectRef::TupleStruct(dyn_tuple_struct) => tuple_struct_debug(dyn_tuple_struct, f),
ReflectRef::Tuple(dyn_tuple) => tuple_debug(dyn_tuple, f),
ReflectRef::List(dyn_list) => list_debug(dyn_list, f),
ReflectRef::Array(dyn_array) => array_debug(dyn_array, f),
ReflectRef::Map(dyn_map) => map_debug(dyn_map, f),
ReflectRef::Set(dyn_set) => set_debug(dyn_set, f),
ReflectRef::Enum(dyn_enum) => enum_debug(dyn_enum, f),
#[cfg(feature = "functions")]
ReflectRef::Function(dyn_function) => dyn_function.fmt(f),
ReflectRef::Opaque(_) => write!(f, "Reflect({})", self.reflect_type_path()),
}
}
/// Indicates whether or not this type is a _dynamic_ type.
///
/// Dynamic types include the ones built-in to this [crate],
/// such as [`DynamicStruct`], [`DynamicList`], and [`DynamicTuple`].
/// However, they may be custom types used as proxies for other types
/// or to facilitate scripting capabilities.
///
/// By default, this method will return `false`.
///
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicList`]: crate::DynamicList
/// [`DynamicTuple`]: crate::DynamicTuple
fn is_dynamic(&self) -> bool {
false
}
}
/// A core trait of [`bevy_reflect`], used for downcasting to concrete types.
///
/// This is a subtrait of [`PartialReflect`],
/// meaning any type which implements `Reflect` implements `PartialReflect` by definition.
///
/// It's recommended to use [the derive macro] rather than manually implementing this trait.
/// Doing so will automatically implement this trait, [`PartialReflect`], and many other useful traits for reflection,
/// including one of the appropriate subtraits: [`Struct`], [`TupleStruct`] or [`Enum`].
///
/// If you need to use this trait as a generic bound along with other reflection traits,
/// for your convenience, consider using [`Reflectable`] instead.
///
/// See the [crate-level documentation] to see how this trait can be used.
///
/// [`bevy_reflect`]: crate
/// [the derive macro]: bevy_reflect_derive::Reflect
/// [`Struct`]: crate::Struct
/// [`TupleStruct`]: crate::TupleStruct
/// [`Enum`]: crate::Enum
/// [`Reflectable`]: crate::Reflectable
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `Reflect` so cannot be fully reflected",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait Reflect: PartialReflect + DynamicTyped + Any {
/// Returns the value as a [`Box<dyn Any>`][core::any::Any].
///
/// For remote wrapper types, this will return the remote type instead.
fn into_any(self: Box<Self>) -> Box<dyn Any>;
/// Returns the value as a [`&dyn Any`][core::any::Any].
///
/// For remote wrapper types, this will return the remote type instead.
fn as_any(&self) -> &dyn Any;
/// Returns the value as a [`&mut dyn Any`][core::any::Any].
///
/// For remote wrapper types, this will return the remote type instead.
fn as_any_mut(&mut self) -> &mut dyn Any;
/// Casts this type to a boxed, fully-reflected value.
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect>;
/// Casts this type to a fully-reflected value.
fn as_reflect(&self) -> &dyn Reflect;
/// Casts this type to a mutable, fully-reflected value.
fn as_reflect_mut(&mut self) -> &mut dyn Reflect;
/// Performs a type-checked assignment of a reflected value to this value.
///
/// If `value` does not contain a value of type `T`, returns an `Err`
/// containing the trait object.
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
}
impl dyn PartialReflect {
/// Returns `true` if the underlying value represents a value of type `T`, or `false`
/// otherwise.
///
/// Read `is` for more information on underlying values and represented types.
#[inline]
pub fn represents<T: Reflect + TypePath>(&self) -> bool {
self.get_represented_type_info()
.is_some_and(|t| t.type_path() == T::type_path())
}
/// Downcasts the value to type `T`, consuming the trait object.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn try_downcast<T: Any>(
self: Box<dyn PartialReflect>,
) -> Result<Box<T>, Box<dyn PartialReflect>> {
self.try_into_reflect()?
.downcast()
.map_err(PartialReflect::into_partial_reflect)
}
/// Downcasts the value to type `T`, unboxing and consuming the trait object.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn try_take<T: Any>(self: Box<dyn PartialReflect>) -> Result<T, Box<dyn PartialReflect>> {
self.try_downcast().map(|value| *value)
}
/// Downcasts the value to type `T` by reference.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns [`None`].
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn try_downcast_ref<T: Any>(&self) -> Option<&T> {
self.try_as_reflect()?.downcast_ref()
}
/// Downcasts the value to type `T` by mutable reference.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns [`None`].
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn try_downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
self.try_as_reflect_mut()?.downcast_mut()
}
}
impl Debug for dyn PartialReflect {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
// The following implementation never actually shadows the concrete TypePath implementation.
// See the comment on `dyn Reflect`'s `TypePath` implementation.
impl TypePath for dyn PartialReflect {
fn type_path() -> &'static str {
"dyn bevy_reflect::PartialReflect"
}
fn short_type_path() -> &'static str {
"dyn PartialReflect"
}
}
#[deny(rustdoc::broken_intra_doc_links)]
impl dyn Reflect {
/// Downcasts the value to type `T`, consuming the trait object.
///
/// If the underlying value is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn downcast<T: Any>(self: Box<dyn Reflect>) -> Result<Box<T>, Box<dyn Reflect>> {
if self.is::<T>() {
Ok(self.into_any().downcast().unwrap())
} else {
Err(self)
}
}
/// Downcasts the value to type `T`, unboxing and consuming the trait object.
///
/// If the underlying value is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn take<T: Any>(self: Box<dyn Reflect>) -> Result<T, Box<dyn Reflect>> {
self.downcast::<T>().map(|value| *value)
}
/// Returns `true` if the underlying value is of type `T`, or `false`
/// otherwise.
///
/// The underlying value is the concrete type that is stored in this `dyn` object;
/// it can be downcasted to. In the case that this underlying value "represents"
/// a different type, like the Dynamic\*\*\* types do, you can call `represents`
/// to determine what type they represent. Represented types cannot be downcasted
/// to, but you can use [`FromReflect`] to create a value of the represented type from them.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
///
/// [`FromReflect`]: crate::FromReflect
#[inline]
pub fn is<T: Any>(&self) -> bool {
self.as_any().type_id() == TypeId::of::<T>()
}
/// Downcasts the value to type `T` by reference.
///
/// If the underlying value is not of type `T`, returns `None`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.as_any().downcast_ref::<T>()
}
/// Downcasts the value to type `T` by mutable reference.
///
/// If the underlying value is not of type `T`, returns `None`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
#[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
self.as_any_mut().downcast_mut::<T>()
}
}
impl Debug for dyn Reflect {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl Typed for dyn Reflect {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Opaque(OpaqueInfo::new::<Self>()))
}
}
// The following implementation never actually shadows the concrete `TypePath` implementation.
// See this playground (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=589064053f27bc100d90da89c6a860aa).
impl TypePath for dyn Reflect {
fn type_path() -> &'static str {
"dyn bevy_reflect::Reflect"
}
fn short_type_path() -> &'static str {
"dyn Reflect"
}
}
macro_rules! impl_full_reflect {
($(<$($id:ident),* $(,)?>)? for $ty:ty $(where $($tt:tt)*)?) => {
impl $(<$($id),*>)? $crate::Reflect for $ty $(where $($tt)*)? {
fn into_any(self: Box<Self>) -> Box<dyn ::core::any::Any> {
self
}
fn as_any(&self) -> &dyn ::core::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
self
}
fn into_reflect(self: Box<Self>) -> Box<dyn $crate::Reflect> {
self
}
fn as_reflect(&self) -> &dyn $crate::Reflect {
self
}
fn as_reflect_mut(&mut self) -> &mut dyn $crate::Reflect {
self
}
fn set(
&mut self,
value: Box<dyn $crate::Reflect>,
) -> Result<(), Box<dyn $crate::Reflect>> {
*self = <dyn $crate::Reflect>::take(value)?;
Ok(())
}
}
};
}
pub(crate) use impl_full_reflect;

33
vendor/bevy_reflect/src/reflectable.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
use crate::{GetTypeRegistration, Reflect, TypePath, Typed};
/// A catch-all trait that is bound by the core reflection traits,
/// useful to simplify reflection-based generic type bounds.
///
/// You do _not_ need to implement this trait manually.
/// It is automatically implemented for all types that implement its supertraits.
/// And these supertraits are all automatically derived with the [`Reflect` derive macro].
///
/// This should namely be used to bound generic arguments to the necessary traits for reflection.
/// Doing this has the added benefit of reducing migration costs, as a change to the required traits
/// is automatically handled by this trait.
///
/// For now, the supertraits of this trait includes:
/// * [`Reflect`]
/// * [`GetTypeRegistration`]
/// * [`Typed`]
/// * [`TypePath`]
///
/// ## Example
///
/// ```
/// # use bevy_reflect::{Reflect, Reflectable};
/// #[derive(Reflect)]
/// struct MyStruct<T: Reflectable> {
/// value: T
/// }
/// ```
///
/// [`Reflect` derive macro]: bevy_reflect_derive::Reflect
pub trait Reflectable: Reflect + GetTypeRegistration + Typed + TypePath {}
impl<T: Reflect + GetTypeRegistration + Typed + TypePath> Reflectable for T {}

64
vendor/bevy_reflect/src/remote.rs vendored Normal file
View File

@@ -0,0 +1,64 @@
use crate::Reflect;
/// Marks a type as a [reflectable] wrapper for a remote type.
///
/// This allows types from external libraries (remote types) to be included in reflection.
///
/// # Safety
///
/// It is highly recommended to avoid implementing this trait manually and instead use the
/// [`#[reflect_remote]`](crate::reflect_remote) attribute macro.
/// This is because the trait tends to rely on [`transmute`], which is [very unsafe].
///
/// The macro will ensure that the following safety requirements are met:
/// - `Self` is a single-field tuple struct (i.e. a newtype) containing the remote type.
/// - `Self` is `#[repr(transparent)]` over the remote type.
///
/// Additionally, the macro will automatically generate [`Reflect`] and [`FromReflect`] implementations,
/// along with compile-time assertions to validate that the safety requirements have been met.
///
/// # Example
///
/// ```
/// use bevy_reflect_derive::{reflect_remote, Reflect};
///
/// mod some_lib {
/// pub struct TheirType {
/// pub value: u32
/// }
/// }
///
/// #[reflect_remote(some_lib::TheirType)]
/// struct MyType {
/// pub value: u32
/// }
///
/// #[derive(Reflect)]
/// struct MyStruct {
/// #[reflect(remote = MyType)]
/// data: some_lib::TheirType,
/// }
/// ```
///
/// [reflectable]: Reflect
/// [`transmute`]: core::mem::transmute
/// [very unsafe]: https://doc.rust-lang.org/1.71.0/nomicon/transmutes.html
/// [`FromReflect`]: crate::FromReflect
pub trait ReflectRemote: Reflect {
/// The remote type this type represents via reflection.
type Remote;
/// Converts a reference of this wrapper to a reference of its remote type.
fn as_remote(&self) -> &Self::Remote;
/// Converts a mutable reference of this wrapper to a mutable reference of its remote type.
fn as_remote_mut(&mut self) -> &mut Self::Remote;
/// Converts this wrapper into its remote type.
fn into_remote(self) -> Self::Remote;
/// Converts a reference of the remote type to a reference of this wrapper.
fn as_wrapper(remote: &Self::Remote) -> &Self;
/// Converts a mutable reference of the remote type to a mutable reference of this wrapper.
fn as_wrapper_mut(remote: &mut Self::Remote) -> &mut Self;
/// Converts the remote type into this wrapper.
fn into_wrapper(remote: Self::Remote) -> Self;
}

View File

@@ -0,0 +1,50 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
ArrayInfo, DynamicArray, TypeRegistry,
};
use alloc::{string::ToString, vec::Vec};
use core::{fmt, fmt::Formatter};
use serde::de::{Error, SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Array`] values.
///
/// [`Array`]: crate::Array
pub(super) struct ArrayVisitor<'a, P> {
pub array_info: &'static ArrayInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for ArrayVisitor<'_, P> {
type Value = DynamicArray;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected array value")
}
fn visit_seq<V>(mut self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or_default());
let registration = try_get_registration(self.array_info.item_ty(), self.registry)?;
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor.as_deref_mut(),
))? {
vec.push(value);
}
if vec.len() != self.array_info.capacity() {
return Err(Error::invalid_length(
vec.len(),
&self.array_info.capacity().to_string().as_str(),
));
}
Ok(DynamicArray::new(vec.into_boxed_slice()))
}
}

View File

@@ -0,0 +1,84 @@
use crate::serde::de::error_utils::make_custom_error;
use crate::{FromType, PartialReflect, TypeRegistry};
use alloc::boxed::Box;
use serde::Deserializer;
/// Trait used to provide finer control when deserializing a reflected type with one of
/// the reflection deserializers.
///
/// This trait is the reflection equivalent of `serde`'s [`Deserialize`] trait.
/// The main difference is that this trait provides access to the [`TypeRegistry`],
/// which means that we can use the registry and all its stored type information
/// to deserialize our type.
///
/// This can be useful when writing a custom reflection deserializer where we may
/// want to handle parts of the deserialization process, but temporarily pass control
/// to the standard reflection deserializer for other parts.
///
/// For the serialization equivalent of this trait, see [`SerializeWithRegistry`].
///
/// # Rationale
///
/// Without this trait and its associated [type data], such a deserializer would have to
/// write out all of the deserialization logic itself, possibly including
/// unnecessary code duplication and trivial implementations.
///
/// This is because a normal [`Deserialize`] implementation has no knowledge of the
/// [`TypeRegistry`] and therefore cannot create a reflection-based deserializer for
/// nested items.
///
/// # Implementors
///
/// In order for this to work with the reflection deserializers like [`TypedReflectDeserializer`]
/// and [`ReflectDeserializer`], implementors should be sure to register the
/// [`ReflectDeserializeWithRegistry`] type data.
/// This can be done [via the registry] or by adding `#[reflect(DeserializeWithRegistry)]` to
/// the type definition.
///
/// [`Deserialize`]: ::serde::Deserialize
/// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry
/// [type data]: ReflectDeserializeWithRegistry
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
/// [via the registry]: TypeRegistry::register_type_data
pub trait DeserializeWithRegistry<'de>: Sized {
fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
}
/// Type data used to deserialize a [`PartialReflect`] type with a custom [`DeserializeWithRegistry`] implementation.
#[derive(Clone)]
pub struct ReflectDeserializeWithRegistry {
deserialize: fn(
deserializer: &mut dyn erased_serde::Deserializer,
registry: &TypeRegistry,
) -> Result<Box<dyn PartialReflect>, erased_serde::Error>,
}
impl ReflectDeserializeWithRegistry {
/// Deserialize a [`PartialReflect`] type with this type data's custom [`DeserializeWithRegistry`] implementation.
pub fn deserialize<'de, D>(
&self,
deserializer: D,
registry: &TypeRegistry,
) -> Result<Box<dyn PartialReflect>, D::Error>
where
D: Deserializer<'de>,
{
let mut erased = <dyn erased_serde::Deserializer>::erase(deserializer);
(self.deserialize)(&mut erased, registry).map_err(make_custom_error)
}
}
impl<T: PartialReflect + for<'de> DeserializeWithRegistry<'de>> FromType<T>
for ReflectDeserializeWithRegistry
{
fn from_type() -> Self {
Self {
deserialize: |deserializer, registry| {
Ok(Box::new(T::deserialize(deserializer, registry)?))
},
}
}
}

View File

@@ -0,0 +1,531 @@
#[cfg(feature = "debug_stack")]
use crate::serde::de::error_utils::TYPE_INFO_STACK;
use crate::serde::{ReflectDeserializeWithRegistry, SerializationData};
use crate::{
serde::{
de::{
arrays::ArrayVisitor, enums::EnumVisitor, error_utils::make_custom_error,
lists::ListVisitor, maps::MapVisitor, options::OptionVisitor, sets::SetVisitor,
structs::StructVisitor, tuple_structs::TupleStructVisitor, tuples::TupleVisitor,
},
TypeRegistrationDeserializer,
},
PartialReflect, ReflectDeserialize, TypeInfo, TypePath, TypeRegistration, TypeRegistry,
};
use alloc::boxed::Box;
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, Error, IgnoredAny, MapAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A general purpose deserializer for reflected types.
///
/// This is the deserializer counterpart to [`ReflectSerializer`].
///
/// See [`TypedReflectDeserializer`] for a deserializer that expects a known type.
///
/// # Input
///
/// This deserializer expects a map with a single entry,
/// where the key is the _full_ [type path] of the reflected type
/// and the value is the serialized data.
///
/// # Output
///
/// This deserializer will return a [`Box<dyn Reflect>`] containing the deserialized data.
///
/// For opaque types (i.e. [`ReflectKind::Opaque`]) or types that register [`ReflectDeserialize`] type data,
/// this `Box` will contain the expected type.
/// For example, deserializing an `i32` will return a `Box<i32>` (as a `Box<dyn Reflect>`).
///
/// Otherwise, this `Box` will contain the dynamic equivalent.
/// For example, a deserialized struct might return a [`Box<DynamicStruct>`]
/// and a deserialized `Vec` might return a [`Box<DynamicList>`].
///
/// This means that if the actual type is needed, these dynamic representations will need to
/// be converted to the concrete type using [`FromReflect`] or [`ReflectFromReflect`].
///
/// If you want to override deserialization for a specific [`TypeRegistration`],
/// you can pass in a reference to a [`ReflectDeserializerProcessor`] which will
/// take priority over all other deserialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use serde::de::DeserializeSeed;
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{DynamicStruct, TypeRegistry, serde::ReflectDeserializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// #[type_path = "my_crate"]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = r#"{
/// "my_crate::MyStruct": (
/// value: 123
/// )
/// }"#;
///
/// let mut deserializer = ron::Deserializer::from_str(input).unwrap();
/// let reflect_deserializer = ReflectDeserializer::new(&registry);
///
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not an opaque type and does not register `ReflectDeserialize`,
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
///
/// // We can convert back to `MyStruct` using `FromReflect`.
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(output.as_partial_reflect()).unwrap();
/// assert_eq!(value, MyStruct { value: 123 });
///
/// // We can also do this dynamically with `ReflectFromReflect`.
/// let type_id = output.get_represented_type_info().unwrap().type_id();
/// let reflect_from_reflect = registry.get_type_data::<ReflectFromReflect>(type_id).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(output.as_partial_reflect()).unwrap();
/// assert!(value.is::<MyStruct>());
/// assert_eq!(value.take::<MyStruct>().unwrap(), MyStruct { value: 123 });
/// ```
///
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
/// [type path]: crate::TypePath::type_path
/// [`Box<dyn Reflect>`]: crate::Reflect
/// [`ReflectKind::Opaque`]: crate::ReflectKind::Opaque
/// [`ReflectDeserialize`]: crate::ReflectDeserialize
/// [`Box<DynamicStruct>`]: crate::DynamicStruct
/// [`Box<DynamicList>`]: crate::DynamicList
/// [`FromReflect`]: crate::FromReflect
/// [`ReflectFromReflect`]: crate::ReflectFromReflect
/// [`with_processor`]: Self::with_processor
pub struct ReflectDeserializer<'a, P: ReflectDeserializerProcessor = ()> {
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'a> ReflectDeserializer<'a, ()> {
/// Creates a deserializer with no processor.
///
/// If you want to add custom logic for deserializing certain types, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(registry: &'a TypeRegistry) -> Self {
Self {
registry,
processor: None,
}
}
}
impl<'a, P: ReflectDeserializerProcessor> ReflectDeserializer<'a, P> {
/// Creates a deserializer with a processor.
///
/// If you do not need any custom logic for handling certain types, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(registry: &'a TypeRegistry, processor: &'a mut P) -> Self {
Self {
registry,
processor: Some(processor),
}
}
}
impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de> for ReflectDeserializer<'_, P> {
type Value = Box<dyn PartialReflect>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
struct UntypedReflectDeserializerVisitor<'a, P> {
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de>
for UntypedReflectDeserializerVisitor<'_, P>
{
type Value = Box<dyn PartialReflect>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter
.write_str("map containing `type` and `value` entries for the reflected value")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let registration = map
.next_key_seed(TypeRegistrationDeserializer::new(self.registry))?
.ok_or_else(|| Error::invalid_length(0, &"a single entry"))?;
let value = map.next_value_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor,
))?;
if map.next_key::<IgnoredAny>()?.is_some() {
return Err(Error::invalid_length(2, &"a single entry"));
}
Ok(value)
}
}
deserializer.deserialize_map(UntypedReflectDeserializerVisitor {
registry: self.registry,
processor: self.processor,
})
}
}
/// A deserializer for reflected types whose [`TypeRegistration`] is known.
///
/// This is the deserializer counterpart to [`TypedReflectSerializer`].
///
/// See [`ReflectDeserializer`] for a deserializer that expects an unknown type.
///
/// # Input
///
/// Since the type is already known, the input is just the serialized data.
///
/// # Output
///
/// This deserializer will return a [`Box<dyn Reflect>`] containing the deserialized data.
///
/// For opaque types (i.e. [`ReflectKind::Opaque`]) or types that register [`ReflectDeserialize`] type data,
/// this `Box` will contain the expected type.
/// For example, deserializing an `i32` will return a `Box<i32>` (as a `Box<dyn Reflect>`).
///
/// Otherwise, this `Box` will contain the dynamic equivalent.
/// For example, a deserialized struct might return a [`Box<DynamicStruct>`]
/// and a deserialized `Vec` might return a [`Box<DynamicList>`].
///
/// This means that if the actual type is needed, these dynamic representations will need to
/// be converted to the concrete type using [`FromReflect`] or [`ReflectFromReflect`].
///
/// If you want to override deserialization for a specific [`TypeRegistration`],
/// you can pass in a reference to a [`ReflectDeserializerProcessor`] which will
/// take priority over all other deserialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use core::any::TypeId;
/// # use serde::de::DeserializeSeed;
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{DynamicStruct, TypeRegistry, serde::TypedReflectDeserializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = r#"(
/// value: 123
/// )"#;
///
/// let registration = registry.get(TypeId::of::<MyStruct>()).unwrap();
///
/// let mut deserializer = ron::Deserializer::from_str(input).unwrap();
/// let reflect_deserializer = TypedReflectDeserializer::new(registration, &registry);
///
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not an opaque type and does not register `ReflectDeserialize`,
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
///
/// // We can convert back to `MyStruct` using `FromReflect`.
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(output.as_partial_reflect()).unwrap();
/// assert_eq!(value, MyStruct { value: 123 });
///
/// // We can also do this dynamically with `ReflectFromReflect`.
/// let type_id = output.get_represented_type_info().unwrap().type_id();
/// let reflect_from_reflect = registry.get_type_data::<ReflectFromReflect>(type_id).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(output.as_partial_reflect()).unwrap();
/// assert!(value.is::<MyStruct>());
/// assert_eq!(value.take::<MyStruct>().unwrap(), MyStruct { value: 123 });
/// ```
///
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`Box<dyn Reflect>`]: crate::Reflect
/// [`ReflectKind::Opaque`]: crate::ReflectKind::Opaque
/// [`ReflectDeserialize`]: crate::ReflectDeserialize
/// [`Box<DynamicStruct>`]: crate::DynamicStruct
/// [`Box<DynamicList>`]: crate::DynamicList
/// [`FromReflect`]: crate::FromReflect
/// [`ReflectFromReflect`]: crate::ReflectFromReflect
/// [`with_processor`]: Self::with_processor
pub struct TypedReflectDeserializer<'a, P: ReflectDeserializerProcessor = ()> {
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'a> TypedReflectDeserializer<'a, ()> {
/// Creates a typed deserializer with no processor.
///
/// If you want to add custom logic for deserializing certain types, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(registration: &'a TypeRegistration, registry: &'a TypeRegistry) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
registration,
registry,
processor: None,
}
}
/// Creates a new [`TypedReflectDeserializer`] for the given type `T`
/// without a processor.
///
/// # Panics
///
/// Panics if `T` is not registered in the given [`TypeRegistry`].
pub fn of<T: TypePath>(registry: &'a TypeRegistry) -> Self {
let registration = registry
.get(core::any::TypeId::of::<T>())
.unwrap_or_else(|| panic!("no registration found for type `{}`", T::type_path()));
Self {
registration,
registry,
processor: None,
}
}
}
impl<'a, P: ReflectDeserializerProcessor> TypedReflectDeserializer<'a, P> {
/// Creates a typed deserializer with a processor.
///
/// If you do not need any custom logic for handling certain types, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: &'a mut P,
) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
registration,
registry,
processor: Some(processor),
}
}
/// An internal constructor for creating a deserializer without resetting the type info stack.
pub(super) fn new_internal(
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
) -> Self {
Self {
registration,
registry,
processor,
}
}
}
impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de>
for TypedReflectDeserializer<'_, P>
{
type Value = Box<dyn PartialReflect>;
fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let deserialize_internal = || -> Result<Self::Value, D::Error> {
// First, check if our processor wants to deserialize this type
// This takes priority over any other deserialization operations
let deserializer = if let Some(processor) = self.processor.as_deref_mut() {
match processor.try_deserialize(self.registration, self.registry, deserializer) {
Ok(Ok(value)) => {
return Ok(value);
}
Err(err) => {
return Err(make_custom_error(err));
}
Ok(Err(deserializer)) => deserializer,
}
} else {
deserializer
};
let type_path = self.registration.type_info().type_path();
// Handle both Value case and types that have a custom `ReflectDeserialize`
if let Some(deserialize_reflect) = self.registration.data::<ReflectDeserialize>() {
let value = deserialize_reflect.deserialize(deserializer)?;
return Ok(value.into_partial_reflect());
}
if let Some(deserialize_reflect) =
self.registration.data::<ReflectDeserializeWithRegistry>()
{
let value = deserialize_reflect.deserialize(deserializer, self.registry)?;
return Ok(value);
}
match self.registration.type_info() {
TypeInfo::Struct(struct_info) => {
let mut dynamic_struct = deserializer.deserialize_struct(
struct_info.type_path_table().ident().unwrap(),
struct_info.field_names(),
StructVisitor {
struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?;
dynamic_struct.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_struct))
}
TypeInfo::TupleStruct(tuple_struct_info) => {
let mut dynamic_tuple_struct = if tuple_struct_info.field_len() == 1
&& self.registration.data::<SerializationData>().is_none()
{
deserializer.deserialize_newtype_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
TupleStructVisitor {
tuple_struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
} else {
deserializer.deserialize_tuple_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
tuple_struct_info.field_len(),
TupleStructVisitor {
tuple_struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
};
dynamic_tuple_struct.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_tuple_struct))
}
TypeInfo::List(list_info) => {
let mut dynamic_list = deserializer.deserialize_seq(ListVisitor {
list_info,
registry: self.registry,
processor: self.processor,
})?;
dynamic_list.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_list))
}
TypeInfo::Array(array_info) => {
let mut dynamic_array = deserializer.deserialize_tuple(
array_info.capacity(),
ArrayVisitor {
array_info,
registry: self.registry,
processor: self.processor,
},
)?;
dynamic_array.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_array))
}
TypeInfo::Map(map_info) => {
let mut dynamic_map = deserializer.deserialize_map(MapVisitor {
map_info,
registry: self.registry,
processor: self.processor,
})?;
dynamic_map.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_map))
}
TypeInfo::Set(set_info) => {
let mut dynamic_set = deserializer.deserialize_seq(SetVisitor {
set_info,
registry: self.registry,
processor: self.processor,
})?;
dynamic_set.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_set))
}
TypeInfo::Tuple(tuple_info) => {
let mut dynamic_tuple = deserializer.deserialize_tuple(
tuple_info.field_len(),
TupleVisitor {
tuple_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?;
dynamic_tuple.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_tuple))
}
TypeInfo::Enum(enum_info) => {
let mut dynamic_enum = if enum_info.type_path_table().module_path()
== Some("core::option")
&& enum_info.type_path_table().ident() == Some("Option")
{
deserializer.deserialize_option(OptionVisitor {
enum_info,
registry: self.registry,
processor: self.processor,
})?
} else {
deserializer.deserialize_enum(
enum_info.type_path_table().ident().unwrap(),
enum_info.variant_names(),
EnumVisitor {
enum_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
};
dynamic_enum.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_enum))
}
TypeInfo::Opaque(_) => {
// This case should already be handled
Err(make_custom_error(format_args!(
"type `{type_path}` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`",
)))
}
}
};
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(|stack| stack.push(self.registration.type_info()));
let output = deserialize_internal();
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
output
}
}

View File

@@ -0,0 +1,215 @@
use crate::{
serde::{
de::{
error_utils::make_custom_error,
helpers::ExpectedValues,
registration_utils::try_get_registration,
struct_utils::{visit_struct, visit_struct_seq},
tuple_utils::{visit_tuple, TupleLikeInfo},
},
TypedReflectDeserializer,
},
DynamicEnum, DynamicStruct, DynamicTuple, DynamicVariant, EnumInfo, StructVariantInfo,
TupleVariantInfo, TypeRegistration, TypeRegistry, VariantInfo,
};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Enum`] values.
///
/// [`Enum`]: crate::Enum
pub(super) struct EnumVisitor<'a, P> {
pub enum_info: &'static EnumInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for EnumVisitor<'_, P> {
type Value = DynamicEnum;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected enum value")
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let mut dynamic_enum = DynamicEnum::default();
let (variant_info, variant) = data.variant_seed(VariantDeserializer {
enum_info: self.enum_info,
})?;
let value: DynamicVariant = match variant_info {
VariantInfo::Unit(..) => variant.unit_variant()?.into(),
VariantInfo::Struct(struct_info) => variant
.struct_variant(
struct_info.field_names(),
StructVariantVisitor {
struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
.into(),
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
let registration = try_get_registration(
*TupleLikeInfo::field_at(tuple_info, 0)?.ty(),
self.registry,
)?;
let value =
variant.newtype_variant_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor,
))?;
let mut dynamic_tuple = DynamicTuple::default();
dynamic_tuple.insert_boxed(value);
dynamic_tuple.into()
}
VariantInfo::Tuple(tuple_info) => variant
.tuple_variant(
tuple_info.field_len(),
TupleVariantVisitor {
tuple_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
.into(),
};
let variant_name = variant_info.name();
let variant_index = self
.enum_info
.index_of(variant_name)
.expect("variant should exist");
dynamic_enum.set_variant_with_index(variant_index, variant_name, value);
Ok(dynamic_enum)
}
}
struct VariantDeserializer {
enum_info: &'static EnumInfo,
}
impl<'de> DeserializeSeed<'de> for VariantDeserializer {
type Value = &'static VariantInfo;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
struct VariantVisitor(&'static EnumInfo);
impl<'de> Visitor<'de> for VariantVisitor {
type Value = &'static VariantInfo;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("expected either a variant index or variant name")
}
fn visit_u32<E>(self, variant_index: u32) -> Result<Self::Value, E>
where
E: Error,
{
self.0.variant_at(variant_index as usize).ok_or_else(|| {
make_custom_error(format_args!(
"no variant found at index `{}` on enum `{}`",
variant_index,
self.0.type_path()
))
})
}
fn visit_str<E>(self, variant_name: &str) -> Result<Self::Value, E>
where
E: Error,
{
self.0.variant(variant_name).ok_or_else(|| {
let names = self.0.iter().map(VariantInfo::name);
make_custom_error(format_args!(
"unknown variant `{}`, expected one of {:?}",
variant_name,
ExpectedValues::from_iter(names)
))
})
}
}
deserializer.deserialize_identifier(VariantVisitor(self.enum_info))
}
}
struct StructVariantVisitor<'a, P> {
struct_info: &'static StructVariantInfo,
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVariantVisitor<'_, P> {
type Value = DynamicStruct;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected struct variant value")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
visit_struct_seq(
&mut seq,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
visit_struct(
&mut map,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
}
struct TupleVariantVisitor<'a, P> {
tuple_info: &'static TupleVariantInfo,
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleVariantVisitor<'_, P> {
type Value = DynamicTuple;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected tuple variant value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
visit_tuple(
&mut seq,
self.tuple_info,
self.registration,
self.registry,
self.processor,
)
}
}

View File

@@ -0,0 +1,29 @@
use core::fmt::Display;
use serde::de::Error;
#[cfg(feature = "debug_stack")]
use std::thread_local;
#[cfg(feature = "debug_stack")]
thread_local! {
/// The thread-local [`TypeInfoStack`] used for debugging.
///
/// [`TypeInfoStack`]: crate::type_info_stack::TypeInfoStack
pub(super) static TYPE_INFO_STACK: core::cell::RefCell<crate::type_info_stack::TypeInfoStack> = const { core::cell::RefCell::new(
crate::type_info_stack::TypeInfoStack::new()
) };
}
/// A helper function for generating a custom deserialization error message.
///
/// This function should be preferred over [`Error::custom`] as it will include
/// other useful information, such as the [type info stack].
///
/// [type info stack]: crate::type_info_stack::TypeInfoStack
pub(super) fn make_custom_error<E: Error>(msg: impl Display) -> E {
#[cfg(feature = "debug_stack")]
return TYPE_INFO_STACK
.with_borrow(|stack| E::custom(format_args!("{} (stack: {:?})", msg, stack)));
#[cfg(not(feature = "debug_stack"))]
return E::custom(msg);
}

View File

@@ -0,0 +1,78 @@
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{
fmt,
fmt::{Debug, Display, Formatter},
};
use serde::{
de::{Error, Visitor},
Deserialize,
};
/// A debug struct used for error messages that displays a list of expected values.
///
/// # Example
///
/// ```ignore (Can't import private struct from doctest)
/// let expected = vec!["foo", "bar", "baz"];
/// assert_eq!("`foo`, `bar`, `baz`", format!("{}", ExpectedValues(expected)));
/// ```
pub(super) struct ExpectedValues<T: Display>(pub Vec<T>);
impl<T: Display> FromIterator<T> for ExpectedValues<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl<T: Display> Debug for ExpectedValues<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let len = self.0.len();
for (index, item) in self.0.iter().enumerate() {
write!(f, "`{item}`")?;
if index < len - 1 {
write!(f, ", ")?;
}
}
Ok(())
}
}
/// Represents a simple reflected identifier.
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) struct Ident(pub String);
impl<'de> Deserialize<'de> for Ident {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct IdentVisitor;
impl<'de> Visitor<'de> for IdentVisitor {
type Value = Ident;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Ident(value.to_string()))
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Ident(value))
}
}
deserializer.deserialize_identifier(IdentVisitor)
}
}

View File

@@ -0,0 +1,41 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
DynamicList, ListInfo, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`List`] values.
///
/// [`List`]: crate::List
pub(super) struct ListVisitor<'a, P> {
pub list_info: &'static ListInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for ListVisitor<'_, P> {
type Value = DynamicList;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected list value")
}
fn visit_seq<V>(mut self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut list = DynamicList::default();
let registration = try_get_registration(self.list_info.item_ty(), self.registry)?;
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor.as_deref_mut(),
))? {
list.push_box(value);
}
Ok(list)
}
}

View File

@@ -0,0 +1,48 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
DynamicMap, Map, MapInfo, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{MapAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Map`] values.
///
/// [`Map`]: crate::Map
pub(super) struct MapVisitor<'a, P> {
pub map_info: &'static MapInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for MapVisitor<'_, P> {
type Value = DynamicMap;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected map value")
}
fn visit_map<V>(mut self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut dynamic_map = DynamicMap::default();
let key_registration = try_get_registration(self.map_info.key_ty(), self.registry)?;
let value_registration = try_get_registration(self.map_info.value_ty(), self.registry)?;
while let Some(key) = map.next_key_seed(TypedReflectDeserializer::new_internal(
key_registration,
self.registry,
self.processor.as_deref_mut(),
))? {
let value = map.next_value_seed(TypedReflectDeserializer::new_internal(
value_registration,
self.registry,
self.processor.as_deref_mut(),
))?;
dynamic_map.insert_boxed(key, value);
}
Ok(dynamic_map)
}
}

855
vendor/bevy_reflect/src/serde/de/mod.rs vendored Normal file
View File

@@ -0,0 +1,855 @@
pub use deserialize_with_registry::*;
pub use deserializer::*;
pub use processor::*;
pub use registrations::*;
mod arrays;
mod deserialize_with_registry;
mod deserializer;
mod enums;
mod error_utils;
mod helpers;
mod lists;
mod maps;
mod options;
mod processor;
mod registration_utils;
mod registrations;
mod sets;
mod struct_utils;
mod structs;
mod tuple_structs;
mod tuple_utils;
mod tuples;
#[cfg(test)]
mod tests {
use alloc::{
boxed::Box,
string::{String, ToString},
vec,
vec::Vec,
};
use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive};
use serde::{de::DeserializeSeed, Deserialize};
use serde::{de::IgnoredAny, Deserializer};
use bevy_platform::collections::{HashMap, HashSet};
use crate::{
serde::{
ReflectDeserializer, ReflectDeserializerProcessor, ReflectSerializer,
TypedReflectDeserializer,
},
DynamicEnum, FromReflect, PartialReflect, Reflect, ReflectDeserialize, TypeRegistration,
TypeRegistry,
};
#[derive(Reflect, Debug, PartialEq)]
struct MyStruct {
primitive_value: i8,
option_value: Option<String>,
option_value_complex: Option<SomeStruct>,
tuple_value: (f32, usize),
list_value: Vec<i32>,
array_value: [i32; 5],
map_value: HashMap<u8, usize>,
set_value: HashSet<u8>,
struct_value: SomeStruct,
tuple_struct_value: SomeTupleStruct,
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum,
newtype_enum: SomeEnum,
tuple_enum: SomeEnum,
struct_enum: SomeEnum,
ignored_struct: SomeIgnoredStruct,
ignored_tuple_struct: SomeIgnoredTupleStruct,
ignored_struct_variant: SomeIgnoredEnum,
ignored_tuple_variant: SomeIgnoredEnum,
custom_deserialize: CustomDeserialize,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeStruct {
foo: i64,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeTupleStruct(String);
#[derive(Reflect, Debug, PartialEq)]
struct SomeUnitStruct;
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredStruct {
#[reflect(ignore)]
ignored: i32,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredTupleStruct(#[reflect(ignore)] i32);
#[derive(Reflect, Debug, PartialEq, Deserialize)]
struct SomeDeserializableStruct {
foo: i64,
}
/// Implements a custom deserialize using `#[reflect(Deserialize)]`.
///
/// For testing purposes, this is just the auto-generated one from deriving.
#[derive(Reflect, Debug, PartialEq, Deserialize)]
#[reflect(Deserialize)]
struct CustomDeserialize {
value: usize,
#[serde(alias = "renamed")]
inner_struct: SomeDeserializableStruct,
}
#[derive(Reflect, Debug, PartialEq)]
enum SomeEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { foo: String },
}
#[derive(Reflect, Debug, PartialEq)]
enum SomeIgnoredEnum {
Tuple(#[reflect(ignore)] f32, #[reflect(ignore)] f32),
Struct {
#[reflect(ignore)]
foo: String,
},
}
fn get_registry() -> TypeRegistry {
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
registry.register::<SomeStruct>();
registry.register::<SomeTupleStruct>();
registry.register::<SomeUnitStruct>();
registry.register::<SomeIgnoredStruct>();
registry.register::<SomeIgnoredTupleStruct>();
registry.register::<CustomDeserialize>();
registry.register::<SomeDeserializableStruct>();
registry.register::<SomeEnum>();
registry.register::<SomeIgnoredEnum>();
registry.register::<i8>();
registry.register::<String>();
registry.register::<i64>();
registry.register::<f32>();
registry.register::<usize>();
registry.register::<i32>();
registry.register::<u8>();
registry.register::<(f32, usize)>();
registry.register::<[i32; 5]>();
registry.register::<Vec<i32>>();
registry.register::<HashMap<u8, usize>>();
registry.register::<HashSet<u8>>();
registry.register::<Option<SomeStruct>>();
registry.register::<Option<String>>();
registry.register_type_data::<Option<String>, ReflectDeserialize>();
registry
}
fn get_my_struct() -> MyStruct {
let mut map = <HashMap<_, _>>::default();
map.insert(64, 32);
let mut set = <HashSet<_>>::default();
set.insert(64);
MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
set_value: set,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 0 },
ignored_tuple_struct: SomeIgnoredTupleStruct(0),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::default(),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(0.0, 0.0),
custom_deserialize: CustomDeserialize {
value: 100,
inner_struct: SomeDeserializableStruct { foo: 101 },
},
}
}
#[test]
fn should_deserialize() {
let expected = get_my_struct();
let registry = get_registry();
let input = r#"{
"bevy_reflect::serde::de::tests::MyStruct": (
primitive_value: 123,
option_value: Some("Hello world!"),
option_value_complex: Some((
foo: 123,
)),
tuple_value: (3.1415927, 1337),
list_value: [
-2,
-1,
0,
1,
2,
],
array_value: (-2, -1, 0, 1, 2),
map_value: {
64: 32,
},
set_value: [
64,
],
struct_value: (
foo: 999999999,
),
tuple_struct_value: ("Tuple Struct"),
unit_struct: (),
unit_enum: Unit,
newtype_enum: NewType(123),
tuple_enum: Tuple(1.23, 3.21),
struct_enum: Struct(
foo: "Struct variant value",
),
ignored_struct: (),
ignored_tuple_struct: (),
ignored_struct_variant: Struct(),
ignored_tuple_variant: Tuple(),
custom_deserialize: (
value: 100,
renamed: (
foo: 101,
),
),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = <MyStruct as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_deserialize_value() {
let input = r#"{
"f32": 1.23,
}"#;
let registry = get_registry();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = dynamic_output
.try_take::<f32>()
.expect("underlying type should be f32");
assert_eq!(1.23, output);
}
#[test]
fn should_deserialized_typed() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
}
let expected = Foo { bar: 123 };
let input = r#"(
bar: 123
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let reflect_deserializer = TypedReflectDeserializer::new(registration, &registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output =
<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_deserialize_option() {
#[derive(Reflect, Debug, PartialEq)]
struct OptionTest {
none: Option<()>,
simple: Option<String>,
complex: Option<SomeStruct>,
}
let expected = OptionTest {
none: None,
simple: Some(String::from("Hello world!")),
complex: Some(SomeStruct { foo: 123 }),
};
let mut registry = get_registry();
registry.register::<OptionTest>();
registry.register::<Option<()>>();
// === Normal === //
let input = r#"{
"bevy_reflect::serde::de::tests::OptionTest": (
none: None,
simple: Some("Hello world!"),
complex: Some((
foo: 123,
)),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = <OptionTest as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output, "failed to deserialize Options");
// === Implicit Some === //
let input = r#"
#![enable(implicit_some)]
{
"bevy_reflect::serde::de::tests::OptionTest": (
none: None,
simple: "Hello world!",
complex: (
foo: 123,
),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = <OptionTest as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(
expected, output,
"failed to deserialize Options with implicit Some"
);
}
#[test]
fn enum_should_deserialize() {
#[derive(Reflect)]
enum MyEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { value: String },
}
let mut registry = get_registry();
registry.register::<MyEnum>();
// === Unit Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": Unit,
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::Unit);
assert!(expected.reflect_partial_eq(output.as_ref()).unwrap());
// === NewType Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": NewType(123),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::NewType(123));
assert!(expected.reflect_partial_eq(output.as_ref()).unwrap());
// === Tuple Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": Tuple(1.23, 3.21),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::Tuple(1.23, 3.21));
assert!(expected
.reflect_partial_eq(output.as_partial_reflect())
.unwrap());
// === Struct Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": Struct(
value: "I <3 Enums",
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::Struct {
value: String::from("I <3 Enums"),
});
assert!(expected
.reflect_partial_eq(output.as_partial_reflect())
.unwrap());
}
// Regression test for https://github.com/bevyengine/bevy/issues/12462
#[test]
fn should_reserialize() {
let registry = get_registry();
let input1 = get_my_struct();
let serializer1 = ReflectSerializer::new(&input1, &registry);
let serialized1 = ron::ser::to_string(&serializer1).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized1).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let input2 = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let serializer2 = ReflectSerializer::new(input2.as_partial_reflect(), &registry);
let serialized2 = ron::ser::to_string(&serializer2).unwrap();
assert_eq!(serialized1, serialized2);
}
#[test]
fn should_deserialize_non_self_describing_binary() {
let expected = get_my_struct();
let registry = get_registry();
let input = vec![
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 98, 101, 118, 121, 95, 114, 101, 102,
108, 101, 99, 116, 58, 58, 115, 101, 114, 100, 101, 58, 58, 100, 101, 58, 58, 116, 101,
115, 116, 115, 58, 58, 77, 121, 83, 116, 114, 117, 99, 116, 123, 1, 12, 0, 0, 0, 0, 0,
0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 1, 123, 0, 0, 0, 0, 0,
0, 0, 219, 15, 73, 64, 57, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255,
255, 255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 254, 255, 255, 255, 255,
255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 32, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 255, 201, 154, 59, 0, 0, 0, 0, 12, 0, 0,
0, 0, 0, 0, 0, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 0, 0, 0, 0, 1,
0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 164, 112, 157, 63, 164, 112, 77, 64, 3,
0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105,
97, 110, 116, 32, 118, 97, 108, 117, 101, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0,
0, 0, 101, 0, 0, 0, 0, 0, 0, 0,
];
let deserializer = ReflectDeserializer::new(&registry);
let config = bincode::config::standard().with_fixed_int_encoding();
let (dynamic_output, _read_bytes) =
bincode::serde::seed_decode_from_slice(deserializer, &input, config).unwrap();
let output = <MyStruct as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_deserialize_self_describing_binary() {
let expected = get_my_struct();
let registry = get_registry();
let input = vec![
129, 217, 40, 98, 101, 118, 121, 95, 114, 101, 102, 108, 101, 99, 116, 58, 58, 115,
101, 114, 100, 101, 58, 58, 100, 101, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77, 121,
83, 116, 114, 117, 99, 116, 220, 0, 20, 123, 172, 72, 101, 108, 108, 111, 32, 119, 111,
114, 108, 100, 33, 145, 123, 146, 202, 64, 73, 15, 219, 205, 5, 57, 149, 254, 255, 0,
1, 2, 149, 254, 255, 0, 1, 2, 129, 64, 32, 145, 64, 145, 206, 59, 154, 201, 255, 172,
84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 144, 164, 85, 110, 105, 116,
129, 167, 78, 101, 119, 84, 121, 112, 101, 123, 129, 165, 84, 117, 112, 108, 101, 146,
202, 63, 157, 112, 164, 202, 64, 77, 112, 164, 129, 166, 83, 116, 114, 117, 99, 116,
145, 180, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105, 97, 110, 116, 32, 118, 97,
108, 117, 101, 144, 144, 129, 166, 83, 116, 114, 117, 99, 116, 144, 129, 165, 84, 117,
112, 108, 101, 144, 146, 100, 145, 101,
];
let mut reader = std::io::BufReader::new(input.as_slice());
let deserializer = ReflectDeserializer::new(&registry);
let dynamic_output = deserializer
.deserialize(&mut rmp_serde::Deserializer::new(&mut reader))
.unwrap();
let output = <MyStruct as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_return_error_if_missing_type_data() {
let mut registry = TypeRegistry::new();
registry.register::<RangeInclusive<f32>>();
let input = r#"{"core::ops::RangeInclusive<f32>":(start:0.0,end:1.0)}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let error = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(error, ron::Error::Message("type `core::ops::RangeInclusive<f32>` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `core::ops::RangeInclusive<f32>`)".to_string()));
#[cfg(not(feature = "debug_stack"))]
assert_eq!(error, ron::Error::Message("type `core::ops::RangeInclusive<f32>` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string()));
}
#[test]
fn should_use_processor_for_custom_deserialization() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct FooProcessor;
impl ReflectDeserializerProcessor for FooProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i64>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(456_i64)))
} else {
Ok(Err(deserializer))
}
}
}
let expected = Foo { bar: 123, qux: 456 };
let input = r#"(
bar: 123,
qux: 123,
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let mut processor = FooProcessor;
let reflect_deserializer =
TypedReflectDeserializer::with_processor(registration, &registry, &mut processor);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output =
<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_use_processor_for_multiple_registrations() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct FooProcessor;
impl ReflectDeserializerProcessor for FooProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i32>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(123_i32)))
} else if registration.type_id() == TypeId::of::<i64>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(456_i64)))
} else {
Ok(Err(deserializer))
}
}
}
let expected = Foo { bar: 123, qux: 456 };
let input = r#"(
bar: 0,
qux: 0,
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let mut processor = FooProcessor;
let reflect_deserializer =
TypedReflectDeserializer::with_processor(registration, &registry, &mut processor);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output =
<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_propagate_processor_deserialize_error() {
struct ErroringProcessor;
impl ReflectDeserializerProcessor for ErroringProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i32>() {
Err(serde::de::Error::custom("my custom deserialize error"))
} else {
Ok(Err(deserializer))
}
}
}
let registry = get_registry();
let input = r#"{"i32":123}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let mut processor = ErroringProcessor;
let reflect_deserializer = ReflectDeserializer::with_processor(&registry, &mut processor);
let error = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message("my custom deserialize error (stack: `i32`)".to_string())
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message("my custom deserialize error".to_string())
);
}
#[test]
fn should_access_local_scope_in_processor() {
struct ValueCountingProcessor<'a> {
values_found: &'a mut usize,
}
impl ReflectDeserializerProcessor for ValueCountingProcessor<'_> {
fn try_deserialize<'de, D>(
&mut self,
_: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
let _ = deserializer.deserialize_ignored_any(IgnoredAny)?;
*self.values_found += 1;
Ok(Ok(Box::new(123_i32)))
}
}
let registry = get_registry();
let input = r#"{"i32":0}"#;
let mut values_found = 0_usize;
let mut deserializer_processor = ValueCountingProcessor {
values_found: &mut values_found,
};
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer =
ReflectDeserializer::with_processor(&registry, &mut deserializer_processor);
reflect_deserializer.deserialize(&mut deserializer).unwrap();
assert_eq!(1, values_found);
}
#[test]
fn should_fail_from_reflect_if_processor_returns_wrong_typed_value() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct WrongTypeProcessor;
impl ReflectDeserializerProcessor for WrongTypeProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i32>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(42_i64)))
} else {
Ok(Err(deserializer))
}
}
}
let input = r#"(
bar: 123,
qux: 123,
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let mut processor = WrongTypeProcessor;
let reflect_deserializer =
TypedReflectDeserializer::with_processor(registration, &registry, &mut processor);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
assert!(<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).is_none());
}
#[cfg(feature = "functions")]
mod functions {
use super::*;
use crate::func::DynamicFunction;
#[test]
fn should_not_deserialize_function() {
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct MyStruct {
func: DynamicFunction<'static>,
}
let mut registry = TypeRegistry::new();
registry.register::<MyStruct>();
let input = r#"{
"bevy_reflect::serde::de::tests::functions::MyStruct": (
func: (),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let error = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message(
"no registration found for type `bevy_reflect::DynamicFunction` (stack: `bevy_reflect::serde::de::tests::functions::MyStruct`)"
.to_string()
)
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message(
"no registration found for type `bevy_reflect::DynamicFunction`".to_string()
)
);
}
}
#[cfg(feature = "debug_stack")]
mod debug_stack {
use super::*;
#[test]
fn should_report_context_in_errors() {
#[derive(Reflect)]
struct Foo {
bar: Bar,
}
#[derive(Reflect)]
struct Bar {
some_other_field: Option<u32>,
baz: Baz,
}
#[derive(Reflect)]
struct Baz {
value: Vec<RangeInclusive<f32>>,
}
let mut registry = TypeRegistry::new();
registry.register::<Foo>();
registry.register::<Bar>();
registry.register::<Baz>();
registry.register::<RangeInclusive<f32>>();
let input = r#"{"bevy_reflect::serde::de::tests::debug_stack::Foo":(bar:(some_other_field:Some(123),baz:(value:[(start:0.0,end:1.0)])))}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let error = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap_err();
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `bevy_reflect::serde::de::tests::debug_stack::Foo` -> `bevy_reflect::serde::de::tests::debug_stack::Bar` -> `bevy_reflect::serde::de::tests::debug_stack::Baz` -> `alloc::vec::Vec<core::ops::RangeInclusive<f32>>` -> `core::ops::RangeInclusive<f32>`)".to_string()
)
);
}
}
}

View File

@@ -0,0 +1,63 @@
use crate::{
serde::{
de::{error_utils::make_custom_error, registration_utils::try_get_registration},
TypedReflectDeserializer,
},
DynamicEnum, DynamicTuple, EnumInfo, TypeRegistry, VariantInfo,
};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, Error, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Option`] values.
pub(super) struct OptionVisitor<'a, P> {
pub enum_info: &'static EnumInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for OptionVisitor<'_, P> {
type Value = DynamicEnum;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected option value of type ")?;
formatter.write_str(self.enum_info.type_path())
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
let mut option = DynamicEnum::default();
option.set_variant("None", ());
Ok(option)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let variant_info = self.enum_info.variant("Some").unwrap();
match variant_info {
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
let field = tuple_info.field_at(0).unwrap();
let registration = try_get_registration(*field.ty(), self.registry)?;
let de = TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor,
);
let mut value = DynamicTuple::default();
value.insert_boxed(de.deserialize(deserializer)?);
let mut option = DynamicEnum::default();
option.set_variant("Some", value);
Ok(option)
}
info => Err(make_custom_error(format_args!(
"invalid variant, expected `Some` but got `{}`",
info.name()
))),
}
}
}

View File

@@ -0,0 +1,217 @@
use crate::{PartialReflect, TypeRegistration, TypeRegistry};
use alloc::boxed::Box;
/// Allows overriding the default deserialization behavior of
/// [`ReflectDeserializer`] and [`TypedReflectDeserializer`] for specific
/// [`TypeRegistration`]s.
///
/// When deserializing a reflected value, you may want to override the default
/// behavior and use your own logic for deserialization. This logic may also
/// be context-dependent, and only apply for a single use of your
/// [`ReflectDeserializer`]. To achieve this, you can create a processor and
/// pass it in to your deserializer.
///
/// Whenever the deserializer attempts to deserialize a value, it will first
/// call [`try_deserialize`] on your processor, which may take ownership of the
/// deserializer and give back a [`Box<dyn PartialReflect>`], or return
/// ownership of the deserializer back, and continue with the default logic.
///
/// The serialization equivalent of this is [`ReflectSerializerProcessor`].
///
/// # Compared to [`DeserializeWithRegistry`]
///
/// [`DeserializeWithRegistry`] allows you to define how your type will be
/// deserialized by a [`TypedReflectDeserializer`], given the extra context of
/// the [`TypeRegistry`]. If your type can be deserialized entirely from that,
/// then you should prefer implementing that trait instead of using a processor.
///
/// However, you may need more context-dependent data which is only present in
/// the scope where you create the [`TypedReflectDeserializer`]. For example, in
/// an asset loader, the `&mut LoadContext` you get is only valid from within
/// the `load` function. This is where a processor is useful, as the processor
/// can capture local variables.
///
/// A [`ReflectDeserializerProcessor`] always takes priority over a
/// [`DeserializeWithRegistry`] implementation, so this is also useful for
/// overriding deserialization behavior if you need to do something custom.
///
/// # Examples
///
/// Deserializing a reflected value in an asset loader, and replacing asset
/// handles with a loaded equivalent:
///
/// ```
/// # use bevy_reflect::serde::{ReflectDeserializer, ReflectDeserializerProcessor};
/// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistration, TypeRegistry};
/// # use serde::de::{DeserializeSeed, Deserializer, Visitor};
/// # use std::marker::PhantomData;
/// #
/// # #[derive(Debug, Clone, Reflect)]
/// # struct LoadedUntypedAsset;
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Handle<T: Reflect>(T);
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Mesh;
/// #
/// # struct LoadContext;
/// # impl LoadContext {
/// # fn load(&mut self) -> &mut Self { unimplemented!() }
/// # fn with_asset_type_id(&mut self, (): ()) -> &mut Self { unimplemented!() }
/// # fn untyped(&mut self) -> &mut Self { unimplemented!() }
/// # fn load_asset(&mut self, (): ()) -> Handle<LoadedUntypedAsset> { unimplemented!() }
/// # }
/// #
/// # struct ReflectHandle;
/// # impl TypeData for ReflectHandle {
/// # fn clone_type_data(&self) -> Box<dyn TypeData> {
/// # unimplemented!()
/// # }
/// # }
/// # impl ReflectHandle {
/// # fn asset_type_id(&self) {
/// # unimplemented!()
/// # }
/// # }
/// #
/// # struct AssetPathVisitor;
/// # impl<'de> Visitor<'de> for AssetPathVisitor {
/// # type Value = ();
/// # fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { unimplemented!() }
/// # }
/// # type AssetError = Box<dyn core::error::Error>;
/// #[derive(Debug, Clone, Reflect)]
/// struct MyAsset {
/// name: String,
/// mesh: Handle<Mesh>,
/// }
///
/// fn load(
/// asset_bytes: &[u8],
/// type_registry: &TypeRegistry,
/// load_context: &mut LoadContext,
/// ) -> Result<MyAsset, AssetError> {
/// struct HandleProcessor<'a> {
/// load_context: &'a mut LoadContext,
/// }
///
/// impl ReflectDeserializerProcessor for HandleProcessor<'_> {
/// fn try_deserialize<'de, D>(
/// &mut self,
/// registration: &TypeRegistration,
/// _registry: &TypeRegistry,
/// deserializer: D,
/// ) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
/// where
/// D: Deserializer<'de>,
/// {
/// let Some(reflect_handle) = registration.data::<ReflectHandle>() else {
/// // we don't want to deserialize this - give the deserializer back
/// return Ok(Err(deserializer));
/// };
///
/// let asset_type_id = reflect_handle.asset_type_id();
/// let asset_path = deserializer.deserialize_str(AssetPathVisitor)?;
///
/// let handle: Handle<LoadedUntypedAsset> = self.load_context
/// .load()
/// .with_asset_type_id(asset_type_id)
/// .untyped()
/// .load_asset(asset_path);
/// # let _: Result<_, ()> = {
/// Ok(Box::new(handle))
/// # };
/// # unimplemented!()
/// }
/// }
///
/// let mut ron_deserializer = ron::Deserializer::from_bytes(asset_bytes)?;
/// let mut processor = HandleProcessor { load_context };
/// let reflect_deserializer =
/// ReflectDeserializer::with_processor(type_registry, &mut processor);
/// let asset = reflect_deserializer.deserialize(&mut ron_deserializer)?;
/// # unimplemented!()
/// }
/// ```
///
/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [`try_deserialize`]: Self::try_deserialize
/// [`DeserializeWithRegistry`]: crate::serde::DeserializeWithRegistry
/// [`ReflectSerializerProcessor`]: crate::serde::ReflectSerializerProcessor
pub trait ReflectDeserializerProcessor {
/// Attempts to deserialize the value which a [`TypedReflectDeserializer`]
/// is currently looking at, and knows the type of.
///
/// If you've read the `registration` and want to override the default
/// deserialization, return `Ok(Ok(value))` with the boxed reflected value
/// that you want to assign this value to. The type inside the box must
/// be the same one as the `registration` is for, otherwise future
/// reflection operations (such as using [`FromReflect`] to convert the
/// resulting [`Box<dyn PartialReflect>`] into a concrete type) will fail.
///
/// If you don't want to override the deserialization, return ownership of
/// the deserializer back via `Ok(Err(deserializer))`.
///
/// Note that, if you do want to return a value, you *must* read from the
/// deserializer passed to this function (you are free to ignore the result
/// though). Otherwise, the deserializer will be in an inconsistent state,
/// and future value parsing will fail.
///
/// # Examples
///
/// Correct way to return a constant value (not using any output from the
/// deserializer):
///
/// ```
/// # use bevy_reflect::{TypeRegistration, PartialReflect, TypeRegistry};
/// # use bevy_reflect::serde::ReflectDeserializerProcessor;
/// # use core::any::TypeId;
/// use serde::de::IgnoredAny;
///
/// struct ConstantI32Processor;
///
/// impl ReflectDeserializerProcessor for ConstantI32Processor {
/// fn try_deserialize<'de, D>(
/// &mut self,
/// registration: &TypeRegistration,
/// _registry: &TypeRegistry,
/// deserializer: D,
/// ) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
/// where
/// D: serde::Deserializer<'de>
/// {
/// if registration.type_id() == TypeId::of::<i32>() {
/// _ = deserializer.deserialize_ignored_any(IgnoredAny);
/// Ok(Ok(Box::new(42_i32)))
/// } else {
/// Ok(Err(deserializer))
/// }
/// }
/// }
/// ```
///
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [`FromReflect`]: crate::FromReflect
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: serde::Deserializer<'de>;
}
impl ReflectDeserializerProcessor for () {
fn try_deserialize<'de, D>(
&mut self,
_registration: &TypeRegistration,
_registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Err(deserializer))
}
}

View File

@@ -0,0 +1,15 @@
use crate::{serde::de::error_utils::make_custom_error, Type, TypeRegistration, TypeRegistry};
use serde::de::Error;
/// Attempts to find the [`TypeRegistration`] for a given [type].
///
/// [type]: Type
pub(super) fn try_get_registration<E: Error>(
ty: Type,
registry: &TypeRegistry,
) -> Result<&TypeRegistration, E> {
let registration = registry.get(ty.id()).ok_or_else(|| {
make_custom_error(format_args!("no registration found for type `{ty:?}`"))
})?;
Ok(registration)
}

View File

@@ -0,0 +1,51 @@
use crate::{serde::de::error_utils::make_custom_error, TypeRegistration, TypeRegistry};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, Error, Visitor};
/// A deserializer for type registrations.
///
/// This will return a [`&TypeRegistration`] corresponding to the given type.
/// This deserializer expects a string containing the _full_ [type path] of the
/// type to find the `TypeRegistration` of.
///
/// [`&TypeRegistration`]: TypeRegistration
/// [type path]: crate::TypePath::type_path
pub struct TypeRegistrationDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a> TypeRegistrationDeserializer<'a> {
pub fn new(registry: &'a TypeRegistry) -> Self {
Self { registry }
}
}
impl<'a, 'de> DeserializeSeed<'de> for TypeRegistrationDeserializer<'a> {
type Value = &'a TypeRegistration;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
struct TypeRegistrationVisitor<'a>(&'a TypeRegistry);
impl<'de, 'a> Visitor<'de> for TypeRegistrationVisitor<'a> {
type Value = &'a TypeRegistration;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("string containing `type` entry for the reflected value")
}
fn visit_str<E>(self, type_path: &str) -> Result<Self::Value, E>
where
E: Error,
{
self.0.get_with_type_path(type_path).ok_or_else(|| {
make_custom_error(format_args!("no registration found for `{type_path}`"))
})
}
}
deserializer.deserialize_str(TypeRegistrationVisitor(self.registry))
}
}

View File

@@ -0,0 +1,42 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
DynamicSet, Set, SetInfo, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Set`] values.
///
/// [`Set`]: crate::Set
pub(super) struct SetVisitor<'a, P> {
pub set_info: &'static SetInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for SetVisitor<'_, P> {
type Value = DynamicSet;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected set value")
}
fn visit_seq<V>(mut self, mut set: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut dynamic_set = DynamicSet::default();
let value_registration = try_get_registration(self.set_info.value_ty(), self.registry)?;
while let Some(value) = set.next_element_seed(TypedReflectDeserializer::new_internal(
value_registration,
self.registry,
self.processor.as_deref_mut(),
))? {
dynamic_set.insert_boxed(value);
}
Ok(dynamic_set)
}
}

View File

@@ -0,0 +1,185 @@
use crate::{
serde::{
de::{
error_utils::make_custom_error,
helpers::{ExpectedValues, Ident},
registration_utils::try_get_registration,
},
SerializationData, TypedReflectDeserializer,
},
DynamicStruct, NamedField, StructInfo, StructVariantInfo, TypeRegistration, TypeRegistry,
};
use alloc::string::ToString;
use core::slice::Iter;
use serde::de::{Error, MapAccess, SeqAccess};
use super::ReflectDeserializerProcessor;
/// A helper trait for accessing type information from struct-like types.
pub(super) trait StructLikeInfo {
fn field<E: Error>(&self, name: &str) -> Result<&NamedField, E>;
fn field_at<E: Error>(&self, index: usize) -> Result<&NamedField, E>;
fn field_len(&self) -> usize;
fn iter_fields(&self) -> Iter<'_, NamedField>;
}
impl StructLikeInfo for StructInfo {
fn field<E: Error>(&self, name: &str) -> Result<&NamedField, E> {
Self::field(self, name).ok_or_else(|| {
make_custom_error(format_args!(
"no field named `{}` on struct `{}`",
name,
self.type_path(),
))
})
}
fn field_at<E: Error>(&self, index: usize) -> Result<&NamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on struct `{}`",
index,
self.type_path(),
))
})
}
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn iter_fields(&self) -> Iter<'_, NamedField> {
self.iter()
}
}
impl StructLikeInfo for StructVariantInfo {
fn field<E: Error>(&self, name: &str) -> Result<&NamedField, E> {
Self::field(self, name).ok_or_else(|| {
make_custom_error(format_args!(
"no field named `{}` on variant `{}`",
name,
self.name(),
))
})
}
fn field_at<E: Error>(&self, index: usize) -> Result<&NamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on variant `{}`",
index,
self.name(),
))
})
}
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn iter_fields(&self) -> Iter<'_, NamedField> {
self.iter()
}
}
/// Deserializes a [struct-like] type from a mapping of fields, returning a [`DynamicStruct`].
///
/// [struct-like]: StructLikeInfo
pub(super) fn visit_struct<'de, T, V, P>(
map: &mut V,
info: &'static T,
registration: &TypeRegistration,
registry: &TypeRegistry,
mut processor: Option<&mut P>,
) -> Result<DynamicStruct, V::Error>
where
T: StructLikeInfo,
V: MapAccess<'de>,
P: ReflectDeserializerProcessor,
{
let mut dynamic_struct = DynamicStruct::default();
while let Some(Ident(key)) = map.next_key::<Ident>()? {
let field = info.field::<V::Error>(&key).map_err(|_| {
let fields = info.iter_fields().map(NamedField::name);
make_custom_error(format_args!(
"unknown field `{}`, expected one of {:?}",
key,
ExpectedValues::from_iter(fields)
))
})?;
let registration = try_get_registration(*field.ty(), registry)?;
let value = map.next_value_seed(TypedReflectDeserializer::new_internal(
registration,
registry,
processor.as_deref_mut(),
))?;
dynamic_struct.insert_boxed(&key, value);
}
if let Some(serialization_data) = registration.data::<SerializationData>() {
for (skipped_index, skipped_field) in serialization_data.iter_skipped() {
let Ok(field) = info.field_at::<V::Error>(*skipped_index) else {
continue;
};
dynamic_struct.insert_boxed(
field.name(),
skipped_field.generate_default().into_partial_reflect(),
);
}
}
Ok(dynamic_struct)
}
/// Deserializes a [struct-like] type from a sequence of fields, returning a [`DynamicStruct`].
///
/// [struct-like]: StructLikeInfo
pub(super) fn visit_struct_seq<'de, T, V, P>(
seq: &mut V,
info: &T,
registration: &TypeRegistration,
registry: &TypeRegistry,
mut processor: Option<&mut P>,
) -> Result<DynamicStruct, V::Error>
where
T: StructLikeInfo,
V: SeqAccess<'de>,
P: ReflectDeserializerProcessor,
{
let mut dynamic_struct = DynamicStruct::default();
let len = info.field_len();
if len == 0 {
// Handle unit structs
return Ok(dynamic_struct);
}
let serialization_data = registration.data::<SerializationData>();
for index in 0..len {
let name = info.field_at::<V::Error>(index)?.name();
if serialization_data
.map(|data| data.is_field_skipped(index))
.unwrap_or_default()
{
if let Some(value) = serialization_data.unwrap().generate_default(index) {
dynamic_struct.insert_boxed(name, value.into_partial_reflect());
}
continue;
}
let value = seq
.next_element_seed(TypedReflectDeserializer::new_internal(
try_get_registration(*info.field_at(index)?.ty(), registry)?,
registry,
processor.as_deref_mut(),
))?
.ok_or_else(|| Error::invalid_length(index, &len.to_string().as_str()))?;
dynamic_struct.insert_boxed(name, value);
}
Ok(dynamic_struct)
}

View File

@@ -0,0 +1,52 @@
use crate::{
serde::de::struct_utils::{visit_struct, visit_struct_seq},
DynamicStruct, StructInfo, TypeRegistration, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{MapAccess, SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Struct`] values.
///
/// [`Struct`]: crate::Struct
pub(super) struct StructVisitor<'a, P> {
pub struct_info: &'static StructInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVisitor<'_, P> {
type Value = DynamicStruct;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected struct value")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
visit_struct_seq(
&mut seq,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
visit_struct(
&mut map,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
}

View File

@@ -0,0 +1,71 @@
use crate::{
serde::{de::tuple_utils::visit_tuple, SerializationData},
DynamicTupleStruct, TupleStructInfo, TypeRegistration, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, SeqAccess, Visitor};
use super::{registration_utils::try_get_registration, TypedReflectDeserializer};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`TupleStruct`] values.
///
/// [`TupleStruct`]: crate::TupleStruct
pub(super) struct TupleStructVisitor<'a, P> {
pub tuple_struct_info: &'static TupleStructInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleStructVisitor<'_, P> {
type Value = DynamicTupleStruct;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected tuple struct value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
visit_tuple(
&mut seq,
self.tuple_struct_info,
self.registration,
self.registry,
self.processor,
)
.map(DynamicTupleStruct::from)
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut tuple = DynamicTupleStruct::default();
let serialization_data = self.registration.data::<SerializationData>();
if let Some(value) = serialization_data.and_then(|data| data.generate_default(0)) {
tuple.insert_boxed(value.into_partial_reflect());
return Ok(tuple);
}
let registration = try_get_registration(
*self
.tuple_struct_info
.field_at(0)
.ok_or(serde::de::Error::custom("Field at index 0 not found"))?
.ty(),
self.registry,
)?;
let reflect_deserializer =
TypedReflectDeserializer::new_internal(registration, self.registry, self.processor);
let value = reflect_deserializer.deserialize(deserializer)?;
tuple.insert_boxed(value.into_partial_reflect());
Ok(tuple)
}
}

View File

@@ -0,0 +1,110 @@
use crate::{
serde::{
de::{error_utils::make_custom_error, registration_utils::try_get_registration},
SerializationData, TypedReflectDeserializer,
},
DynamicTuple, TupleInfo, TupleStructInfo, TupleVariantInfo, TypeRegistration, TypeRegistry,
UnnamedField,
};
use alloc::string::ToString;
use serde::de::{Error, SeqAccess};
use super::ReflectDeserializerProcessor;
pub(super) trait TupleLikeInfo {
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E>;
fn field_len(&self) -> usize;
}
impl TupleLikeInfo for TupleInfo {
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on tuple `{}`",
index,
self.type_path(),
))
})
}
}
impl TupleLikeInfo for TupleStructInfo {
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on tuple struct `{}`",
index,
self.type_path(),
))
})
}
}
impl TupleLikeInfo for TupleVariantInfo {
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on tuple variant `{}`",
index,
self.name(),
))
})
}
}
/// Deserializes a [tuple-like] type from a sequence of elements, returning a [`DynamicTuple`].
///
/// [tuple-like]: TupleLikeInfo
pub(super) fn visit_tuple<'de, T, V, P>(
seq: &mut V,
info: &T,
registration: &TypeRegistration,
registry: &TypeRegistry,
mut processor: Option<&mut P>,
) -> Result<DynamicTuple, V::Error>
where
T: TupleLikeInfo,
V: SeqAccess<'de>,
P: ReflectDeserializerProcessor,
{
let mut tuple = DynamicTuple::default();
let len = info.field_len();
if len == 0 {
// Handle empty tuple/tuple struct
return Ok(tuple);
}
let serialization_data = registration.data::<SerializationData>();
for index in 0..len {
if let Some(value) = serialization_data.and_then(|data| data.generate_default(index)) {
tuple.insert_boxed(value.into_partial_reflect());
continue;
}
let value = seq
.next_element_seed(TypedReflectDeserializer::new_internal(
try_get_registration(*info.field_at(index)?.ty(), registry)?,
registry,
processor.as_deref_mut(),
))?
.ok_or_else(|| Error::invalid_length(index, &len.to_string().as_str()))?;
tuple.insert_boxed(value);
}
Ok(tuple)
}

View File

@@ -0,0 +1,38 @@
use crate::{
serde::de::tuple_utils::visit_tuple, DynamicTuple, TupleInfo, TypeRegistration, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Tuple`] values.
///
/// [`Tuple`]: crate::Tuple
pub(super) struct TupleVisitor<'a, P> {
pub tuple_info: &'static TupleInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleVisitor<'_, P> {
type Value = DynamicTuple;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected tuple value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
visit_tuple(
&mut seq,
self.tuple_info,
self.registration,
self.registry,
self.processor,
)
}
}

476
vendor/bevy_reflect/src/serde/mod.rs vendored Normal file
View File

@@ -0,0 +1,476 @@
mod de;
mod ser;
mod type_data;
pub use de::*;
pub use ser::*;
pub use type_data::*;
#[cfg(test)]
mod tests {
use super::*;
use crate::{
type_registry::TypeRegistry, DynamicStruct, DynamicTupleStruct, FromReflect,
PartialReflect, Reflect, Struct,
};
use serde::de::DeserializeSeed;
#[test]
fn test_serialization_struct() {
#[derive(Debug, Reflect, PartialEq)]
#[reflect(PartialEq)]
struct TestStruct {
a: i32,
#[reflect(ignore)]
b: i32,
#[reflect(skip_serializing)]
c: i32,
#[reflect(skip_serializing)]
#[reflect(default = "custom_default")]
d: i32,
e: i32,
}
fn custom_default() -> i32 {
-1
}
let mut registry = TypeRegistry::default();
registry.register::<TestStruct>();
let test_struct = TestStruct {
a: 3,
b: 4,
c: 5,
d: 6,
e: 7,
};
let serializer = ReflectSerializer::new(&test_struct, &registry);
let serialized =
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let mut expected = DynamicStruct::default();
expected.insert("a", 3);
// Ignored: expected.insert("b", 0);
expected.insert("c", 0);
expected.insert("d", -1);
expected.insert("e", 7);
assert!(
expected
.reflect_partial_eq(deserialized.as_partial_reflect())
.unwrap(),
"Deserialization failed: expected {expected:?} found {deserialized:?}"
);
let expected = TestStruct {
a: 3,
b: 0,
c: 0,
d: -1,
e: 7,
};
let received =
<TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
assert_eq!(
expected, received,
"FromReflect failed: expected {expected:?} found {received:?}"
);
}
#[test]
fn test_serialization_tuple_struct() {
#[derive(Debug, Reflect, PartialEq)]
#[reflect(PartialEq)]
struct TestStruct(
i32,
#[reflect(ignore)] i32,
#[reflect(skip_serializing)] i32,
#[reflect(skip_serializing)]
#[reflect(default = "custom_default")]
i32,
i32,
);
fn custom_default() -> i32 {
-1
}
let mut registry = TypeRegistry::default();
registry.register::<TestStruct>();
let test_struct = TestStruct(3, 4, 5, 6, 7);
let serializer = ReflectSerializer::new(&test_struct, &registry);
let serialized =
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let mut expected = DynamicTupleStruct::default();
expected.insert(3);
// Ignored: expected.insert(0);
expected.insert(0);
expected.insert(-1);
expected.insert(7);
assert!(
expected
.reflect_partial_eq(deserialized.as_partial_reflect())
.unwrap(),
"Deserialization failed: expected {expected:?} found {deserialized:?}"
);
let expected = TestStruct(3, 0, 0, -1, 7);
let received =
<TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
assert_eq!(
expected, received,
"FromReflect failed: expected {expected:?} found {received:?}"
);
}
#[test]
#[should_panic(
expected = "cannot serialize dynamic value without represented type: `bevy_reflect::DynamicStruct`"
)]
fn should_not_serialize_unproxied_dynamic() {
let registry = TypeRegistry::default();
let mut value = DynamicStruct::default();
value.insert("foo", 123_u32);
let serializer = ReflectSerializer::new(&value, &registry);
ron::ser::to_string(&serializer).unwrap();
}
#[test]
fn should_roundtrip_proxied_dynamic() {
#[derive(Reflect)]
struct TestStruct {
a: i32,
b: i32,
}
let mut registry = TypeRegistry::default();
registry.register::<TestStruct>();
let value: DynamicStruct = TestStruct { a: 123, b: 456 }.to_dynamic_struct();
let serializer = ReflectSerializer::new(&value, &registry);
let expected = r#"{"bevy_reflect::serde::tests::TestStruct":(a:123,b:456)}"#;
let result = ron::ser::to_string(&serializer).unwrap();
assert_eq!(expected, result);
let mut deserializer = ron::de::Deserializer::from_str(&result).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let expected = value.to_dynamic();
let result = reflect_deserializer.deserialize(&mut deserializer).unwrap();
assert!(expected
.reflect_partial_eq(result.as_partial_reflect())
.unwrap());
}
mod type_data {
use super::*;
use crate::from_reflect::FromReflect;
use crate::serde::{DeserializeWithRegistry, ReflectDeserializeWithRegistry};
use crate::serde::{ReflectSerializeWithRegistry, SerializeWithRegistry};
use crate::{ReflectFromReflect, TypePath};
use alloc::{format, string::String, vec, vec::Vec};
use bevy_platform::sync::Arc;
use bevy_reflect_derive::reflect_trait;
use core::any::TypeId;
use core::fmt::{Debug, Formatter};
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserializer, Serialize, Serializer};
#[reflect_trait]
trait Enemy: Reflect + Debug {
#[expect(dead_code, reason = "this method is purely for testing purposes")]
fn hp(&self) -> u8;
}
// This is needed to support Arc<dyn Enemy>
impl TypePath for dyn Enemy {
fn type_path() -> &'static str {
"dyn bevy_reflect::serde::tests::type_data::Enemy"
}
fn short_type_path() -> &'static str {
"dyn Enemy"
}
}
#[derive(Reflect, Debug)]
#[reflect(Enemy)]
struct Skeleton(u8);
impl Enemy for Skeleton {
fn hp(&self) -> u8 {
self.0
}
}
#[derive(Reflect, Debug)]
#[reflect(Enemy)]
struct Zombie {
health: u8,
walk_speed: f32,
}
impl Enemy for Zombie {
fn hp(&self) -> u8 {
self.health
}
}
#[derive(Reflect, Debug)]
struct Level {
name: String,
enemies: EnemyList,
}
#[derive(Reflect, Debug)]
#[reflect(SerializeWithRegistry, DeserializeWithRegistry)]
// Note that we have to use `Arc` instead of `Box` here due to the
// former being the only one between the two to implement `Reflect`.
struct EnemyList(Vec<Arc<dyn Enemy>>);
impl SerializeWithRegistry for EnemyList {
fn serialize<S>(
&self,
serializer: S,
registry: &TypeRegistry,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_seq(Some(self.0.len()))?;
for enemy in &self.0 {
state.serialize_element(&ReflectSerializer::new(
(**enemy).as_partial_reflect(),
registry,
))?;
}
state.end()
}
}
impl<'de> DeserializeWithRegistry<'de> for EnemyList {
fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct EnemyListVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for EnemyListVisitor<'a> {
type Value = Vec<Arc<dyn Enemy>>;
fn expecting(&self, formatter: &mut Formatter) -> core::fmt::Result {
write!(formatter, "a list of enemies")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut enemies = Vec::new();
while let Some(enemy) =
seq.next_element_seed(ReflectDeserializer::new(self.registry))?
{
let registration = self
.registry
.get_with_type_path(
enemy.get_represented_type_info().unwrap().type_path(),
)
.unwrap();
// 1. Convert any possible dynamic values to concrete ones
let enemy = registration
.data::<ReflectFromReflect>()
.unwrap()
.from_reflect(&*enemy)
.unwrap();
// 2. Convert the concrete value to a boxed trait object
let enemy = registration
.data::<ReflectEnemy>()
.unwrap()
.get_boxed(enemy)
.unwrap();
enemies.push(enemy.into());
}
Ok(enemies)
}
}
deserializer
.deserialize_seq(EnemyListVisitor { registry })
.map(EnemyList)
}
}
fn create_registry() -> TypeRegistry {
let mut registry = TypeRegistry::default();
registry.register::<Level>();
registry.register::<EnemyList>();
registry.register::<Skeleton>();
registry.register::<Zombie>();
registry
}
fn create_arc_dyn_enemy<T: Enemy>(enemy: T) -> Arc<dyn Enemy> {
let arc = Arc::new(enemy);
#[cfg(not(target_has_atomic = "ptr"))]
#[expect(
unsafe_code,
reason = "unsized coercion is an unstable feature for non-std types"
)]
// SAFETY:
// - Coercion from `T` to `dyn Enemy` is valid as `T: Enemy + 'static`
// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
let arc = unsafe { Arc::from_raw(Arc::into_raw(arc) as *const dyn Enemy) };
arc
}
#[test]
fn should_serialize_with_serialize_with_registry() {
let registry = create_registry();
let level = Level {
name: String::from("Level 1"),
enemies: EnemyList(vec![
create_arc_dyn_enemy(Skeleton(10)),
create_arc_dyn_enemy(Zombie {
health: 20,
walk_speed: 0.5,
}),
]),
};
let serializer = ReflectSerializer::new(&level, &registry);
let serialized = ron::ser::to_string(&serializer).unwrap();
let expected = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#;
assert_eq!(expected, serialized);
}
#[test]
fn should_deserialize_with_deserialize_with_registry() {
let registry = create_registry();
let input = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let output = Level::from_reflect(&*value).unwrap();
let expected = Level {
name: String::from("Level 1"),
enemies: EnemyList(vec![
create_arc_dyn_enemy(Skeleton(10)),
create_arc_dyn_enemy(Zombie {
health: 20,
walk_speed: 0.5,
}),
]),
};
// Poor man's comparison since we can't derive PartialEq for Arc<dyn Enemy>
assert_eq!(format!("{:?}", expected), format!("{:?}", output));
let unexpected = Level {
name: String::from("Level 1"),
enemies: EnemyList(vec![
create_arc_dyn_enemy(Skeleton(20)),
create_arc_dyn_enemy(Zombie {
health: 20,
walk_speed: 5.0,
}),
]),
};
// Poor man's comparison since we can't derive PartialEq for Arc<dyn Enemy>
assert_ne!(format!("{:?}", unexpected), format!("{:?}", output));
}
#[test]
fn should_serialize_single_tuple_struct_as_newtype() {
#[derive(Reflect, Serialize, PartialEq, Debug)]
struct TupleStruct(u32);
#[derive(Reflect, Serialize, PartialEq, Debug)]
struct TupleStructWithSkip(
u32,
#[reflect(skip_serializing)]
#[serde(skip)]
u32,
);
#[derive(Reflect, Serialize, PartialEq, Debug)]
enum Enum {
TupleStruct(usize),
NestedTupleStruct(TupleStruct),
NestedTupleStructWithSkip(TupleStructWithSkip),
}
let mut registry = TypeRegistry::default();
registry.register::<TupleStruct>();
registry.register::<TupleStructWithSkip>();
registry.register::<Enum>();
let tuple_struct = TupleStruct(1);
let tuple_struct_with_skip = TupleStructWithSkip(2, 3);
let tuple_struct_enum = Enum::TupleStruct(4);
let nested_tuple_struct = Enum::NestedTupleStruct(TupleStruct(5));
let nested_tuple_struct_with_skip =
Enum::NestedTupleStructWithSkip(TupleStructWithSkip(6, 7));
fn assert_serialize<T: Reflect + FromReflect + Serialize + PartialEq + Debug>(
value: &T,
registry: &TypeRegistry,
) {
let serializer = TypedReflectSerializer::new(value, registry);
let reflect_serialize = serde_json::to_string(&serializer).unwrap();
let serde_serialize = serde_json::to_string(value).unwrap();
assert_eq!(reflect_serialize, serde_serialize);
let registration = registry.get(TypeId::of::<T>()).unwrap();
let reflect_deserializer = TypedReflectDeserializer::new(registration, registry);
let mut deserializer = serde_json::Deserializer::from_str(&serde_serialize);
let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let _ = T::from_reflect(&*reflect_value).unwrap();
}
assert_serialize(&tuple_struct, &registry);
assert_serialize(&tuple_struct_with_skip, &registry);
assert_serialize(&tuple_struct_enum, &registry);
assert_serialize(&nested_tuple_struct, &registry);
assert_serialize(&nested_tuple_struct_with_skip, &registry);
}
}
}

View File

@@ -0,0 +1,28 @@
use crate::{serde::TypedReflectSerializer, Array, TypeRegistry};
use serde::{ser::SerializeTuple, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Array`] values.
pub(super) struct ArraySerializer<'a, P> {
pub array: &'a dyn Array,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for ArraySerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_tuple(self.array.len())?;
for value in self.array.iter() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,62 @@
use crate::serde::ser::error_utils::make_custom_error;
#[cfg(feature = "debug_stack")]
use crate::serde::ser::error_utils::TYPE_INFO_STACK;
use crate::serde::ReflectSerializeWithRegistry;
use crate::{PartialReflect, ReflectSerialize, TypeRegistry};
use core::borrow::Borrow;
use serde::{Serialize, Serializer};
/// Attempts to serialize a [`PartialReflect`] value with custom [`ReflectSerialize`]
/// or [`ReflectSerializeWithRegistry`] type data.
///
/// On success, returns the result of the serialization.
/// On failure, returns the original serializer and the error that occurred.
pub(super) fn try_custom_serialize<S: Serializer>(
value: &dyn PartialReflect,
type_registry: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S::Error>, (S, S::Error)> {
let Some(value) = value.try_as_reflect() else {
return Err((
serializer,
make_custom_error(format_args!(
"type `{}` does not implement `Reflect`",
value.reflect_type_path()
)),
));
};
let info = value.reflect_type_info();
let Some(registration) = type_registry.get(info.type_id()) else {
return Err((
serializer,
make_custom_error(format_args!(
"type `{}` is not registered in the type registry",
info.type_path(),
)),
));
};
if let Some(reflect_serialize) = registration.data::<ReflectSerialize>() {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
Ok(reflect_serialize
.get_serializable(value)
.borrow()
.serialize(serializer))
} else if let Some(reflect_serialize_with_registry) =
registration.data::<ReflectSerializeWithRegistry>()
{
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
Ok(reflect_serialize_with_registry.serialize(value, serializer, type_registry))
} else {
Err((serializer, make_custom_error(format_args!(
"type `{}` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. For certain types, this may need to be registered manually using `register_type_data`",
info.type_path(),
))))
}
}

View File

@@ -0,0 +1,130 @@
use crate::{
serde::{ser::error_utils::make_custom_error, TypedReflectSerializer},
Enum, TypeInfo, TypeRegistry, VariantInfo, VariantType,
};
use serde::{
ser::{SerializeStructVariant, SerializeTupleVariant},
Serialize,
};
use super::ReflectSerializerProcessor;
/// A serializer for [`Enum`] values.
pub(super) struct EnumSerializer<'a, P> {
pub enum_value: &'a dyn Enum,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for EnumSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let type_info = self.enum_value.get_represented_type_info().ok_or_else(|| {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.enum_value.reflect_type_path()
))
})?;
let enum_info = match type_info {
TypeInfo::Enum(enum_info) => enum_info,
info => {
return Err(make_custom_error(format_args!(
"expected enum type but received {info:?}"
)));
}
};
let enum_name = enum_info.type_path_table().ident().unwrap();
let variant_index = self.enum_value.variant_index() as u32;
let variant_info = enum_info
.variant_at(variant_index as usize)
.ok_or_else(|| {
make_custom_error(format_args!(
"variant at index `{variant_index}` does not exist",
))
})?;
let variant_name = variant_info.name();
let variant_type = self.enum_value.variant_type();
let field_len = self.enum_value.field_len();
match variant_type {
VariantType::Unit => {
if type_info.type_path_table().module_path() == Some("core::option")
&& type_info.type_path_table().ident() == Some("Option")
{
serializer.serialize_none()
} else {
serializer.serialize_unit_variant(enum_name, variant_index, variant_name)
}
}
VariantType::Struct => {
let struct_info = match variant_info {
VariantInfo::Struct(struct_info) => struct_info,
info => {
return Err(make_custom_error(format_args!(
"expected struct variant type but received {info:?}",
)));
}
};
let mut state = serializer.serialize_struct_variant(
enum_name,
variant_index,
variant_name,
field_len,
)?;
for (index, field) in self.enum_value.iter_fields().enumerate() {
let field_info = struct_info.field_at(index).unwrap();
state.serialize_field(
field_info.name(),
&TypedReflectSerializer::new_internal(
field.value(),
self.registry,
self.processor,
),
)?;
}
state.end()
}
VariantType::Tuple if field_len == 1 => {
let field = self.enum_value.field_at(0).unwrap();
if type_info.type_path_table().module_path() == Some("core::option")
&& type_info.type_path_table().ident() == Some("Option")
{
serializer.serialize_some(&TypedReflectSerializer::new_internal(
field,
self.registry,
self.processor,
))
} else {
serializer.serialize_newtype_variant(
enum_name,
variant_index,
variant_name,
&TypedReflectSerializer::new_internal(field, self.registry, self.processor),
)
}
}
VariantType::Tuple => {
let mut state = serializer.serialize_tuple_variant(
enum_name,
variant_index,
variant_name,
field_len,
)?;
for field in self.enum_value.iter_fields() {
state.serialize_field(&TypedReflectSerializer::new_internal(
field.value(),
self.registry,
self.processor,
))?;
}
state.end()
}
}
}
}

View File

@@ -0,0 +1,29 @@
use core::fmt::Display;
use serde::ser::Error;
#[cfg(feature = "debug_stack")]
use std::thread_local;
#[cfg(feature = "debug_stack")]
thread_local! {
/// The thread-local [`TypeInfoStack`] used for debugging.
///
/// [`TypeInfoStack`]: crate::type_info_stack::TypeInfoStack
pub(super) static TYPE_INFO_STACK: core::cell::RefCell<crate::type_info_stack::TypeInfoStack> = const { core::cell::RefCell::new(
crate::type_info_stack::TypeInfoStack::new()
) };
}
/// A helper function for generating a custom serialization error message.
///
/// This function should be preferred over [`Error::custom`] as it will include
/// other useful information, such as the [type info stack].
///
/// [type info stack]: crate::type_info_stack::TypeInfoStack
pub(super) fn make_custom_error<E: Error>(msg: impl Display) -> E {
#[cfg(feature = "debug_stack")]
return TYPE_INFO_STACK
.with_borrow(|stack| E::custom(format_args!("{} (stack: {:?})", msg, stack)));
#[cfg(not(feature = "debug_stack"))]
return E::custom(msg);
}

View File

@@ -0,0 +1,28 @@
use crate::{serde::TypedReflectSerializer, List, TypeRegistry};
use serde::{ser::SerializeSeq, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`List`] values.
pub(super) struct ListSerializer<'a, P> {
pub list: &'a dyn List,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for ListSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_seq(Some(self.list.len()))?;
for value in self.list.iter() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,27 @@
use crate::{serde::TypedReflectSerializer, Map, TypeRegistry};
use serde::{ser::SerializeMap, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Map`] values.
pub(super) struct MapSerializer<'a, P> {
pub map: &'a dyn Map,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for MapSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(self.map.len()))?;
for (key, value) in self.map.iter() {
state.serialize_entry(
&TypedReflectSerializer::new_internal(key, self.registry, self.processor),
&TypedReflectSerializer::new_internal(value, self.registry, self.processor),
)?;
}
state.end()
}
}

733
vendor/bevy_reflect/src/serde/ser/mod.rs vendored Normal file
View File

@@ -0,0 +1,733 @@
pub use processor::*;
pub use serializable::*;
pub use serialize_with_registry::*;
pub use serializer::*;
mod arrays;
mod custom_serialization;
mod enums;
mod error_utils;
mod lists;
mod maps;
mod processor;
mod serializable;
mod serialize_with_registry;
mod serializer;
mod sets;
mod structs;
mod tuple_structs;
mod tuples;
#[cfg(test)]
mod tests {
use crate::{
serde::{ReflectSerializer, ReflectSerializerProcessor},
PartialReflect, Reflect, ReflectSerialize, Struct, TypeRegistry,
};
#[cfg(feature = "functions")]
use alloc::boxed::Box;
use alloc::{
string::{String, ToString},
vec,
vec::Vec,
};
use bevy_platform::collections::{HashMap, HashSet};
use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive};
use ron::{extensions::Extensions, ser::PrettyConfig};
use serde::{Serialize, Serializer};
#[derive(Reflect, Debug, PartialEq)]
struct MyStruct {
primitive_value: i8,
option_value: Option<String>,
option_value_complex: Option<SomeStruct>,
tuple_value: (f32, usize),
list_value: Vec<i32>,
array_value: [i32; 5],
map_value: HashMap<u8, usize>,
set_value: HashSet<u8>,
struct_value: SomeStruct,
tuple_struct_value: SomeTupleStruct,
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum,
newtype_enum: SomeEnum,
tuple_enum: SomeEnum,
struct_enum: SomeEnum,
ignored_struct: SomeIgnoredStruct,
ignored_tuple_struct: SomeIgnoredTupleStruct,
ignored_struct_variant: SomeIgnoredEnum,
ignored_tuple_variant: SomeIgnoredEnum,
custom_serialize: CustomSerialize,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeStruct {
foo: i64,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeTupleStruct(String);
#[derive(Reflect, Debug, PartialEq)]
struct SomeUnitStruct;
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredStruct {
#[reflect(ignore)]
ignored: i32,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredTupleStruct(#[reflect(ignore)] i32);
#[derive(Reflect, Debug, PartialEq)]
enum SomeEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { foo: String },
}
#[derive(Reflect, Debug, PartialEq)]
enum SomeIgnoredEnum {
Tuple(#[reflect(ignore)] f32, #[reflect(ignore)] f32),
Struct {
#[reflect(ignore)]
foo: String,
},
}
#[derive(Reflect, Debug, PartialEq, Serialize)]
struct SomeSerializableStruct {
foo: i64,
}
/// Implements a custom serialize using `#[reflect(Serialize)]`.
///
/// For testing purposes, this just uses the generated one from deriving Serialize.
#[derive(Reflect, Debug, PartialEq, Serialize)]
#[reflect(Serialize)]
struct CustomSerialize {
value: usize,
#[serde(rename = "renamed")]
inner_struct: SomeSerializableStruct,
}
fn get_registry() -> TypeRegistry {
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
registry.register::<SomeStruct>();
registry.register::<SomeTupleStruct>();
registry.register::<SomeUnitStruct>();
registry.register::<SomeIgnoredStruct>();
registry.register::<SomeIgnoredTupleStruct>();
registry.register::<SomeIgnoredEnum>();
registry.register::<CustomSerialize>();
registry.register::<SomeEnum>();
registry.register::<SomeSerializableStruct>();
registry.register_type_data::<SomeSerializableStruct, ReflectSerialize>();
registry.register::<String>();
registry.register::<Option<String>>();
registry.register_type_data::<Option<String>, ReflectSerialize>();
registry
}
fn get_my_struct() -> MyStruct {
let mut map = <HashMap<_, _>>::default();
map.insert(64, 32);
let mut set = <HashSet<_>>::default();
set.insert(64);
MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
set_value: set,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 123 },
ignored_tuple_struct: SomeIgnoredTupleStruct(123),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::from("Struct Variant"),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(1.23, 3.45),
custom_serialize: CustomSerialize {
value: 100,
inner_struct: SomeSerializableStruct { foo: 101 },
},
}
}
#[test]
fn should_serialize() {
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.indentor(String::from(" "));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyStruct": (
primitive_value: 123,
option_value: Some("Hello world!"),
option_value_complex: Some((
foo: 123,
)),
tuple_value: (3.1415927, 1337),
list_value: [
-2,
-1,
0,
1,
2,
],
array_value: (-2, -1, 0, 1, 2),
map_value: {
64: 32,
},
set_value: [
64,
],
struct_value: (
foo: 999999999,
),
tuple_struct_value: ("Tuple Struct"),
unit_struct: (),
unit_enum: Unit,
newtype_enum: NewType(123),
tuple_enum: Tuple(1.23, 3.21),
struct_enum: Struct(
foo: "Struct variant value",
),
ignored_struct: (),
ignored_tuple_struct: (),
ignored_struct_variant: Struct(),
ignored_tuple_variant: Tuple(),
custom_serialize: (
value: 100,
renamed: (
foo: 101,
),
),
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_serialize_option() {
#[derive(Reflect, Debug, PartialEq)]
struct OptionTest {
none: Option<()>,
simple: Option<String>,
complex: Option<SomeStruct>,
}
let value = OptionTest {
none: None,
simple: Some(String::from("Hello world!")),
complex: Some(SomeStruct { foo: 123 }),
};
let registry = get_registry();
let serializer = ReflectSerializer::new(&value, &registry);
// === Normal === //
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.indentor(String::from(" "));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::OptionTest": (
none: None,
simple: Some("Hello world!"),
complex: Some((
foo: 123,
)),
),
}"#;
assert_eq!(expected, output);
// === Implicit Some === //
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.extensions(Extensions::IMPLICIT_SOME)
.indentor(String::from(" "));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"#![enable(implicit_some)]
{
"bevy_reflect::serde::ser::tests::OptionTest": (
none: None,
simple: "Hello world!",
complex: (
foo: 123,
),
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn enum_should_serialize() {
#[derive(Reflect)]
enum MyEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { value: String },
}
let mut registry = get_registry();
registry.register::<MyEnum>();
let config = PrettyConfig::default().new_line(String::from("\n"));
// === Unit Variant === //
let value = MyEnum::Unit;
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": Unit,
}"#;
assert_eq!(expected, output);
// === NewType Variant === //
let value = MyEnum::NewType(123);
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": NewType(123),
}"#;
assert_eq!(expected, output);
// === Tuple Variant === //
let value = MyEnum::Tuple(1.23, 3.21);
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": Tuple(1.23, 3.21),
}"#;
assert_eq!(expected, output);
// === Struct Variant === //
let value = MyEnum::Struct {
value: String::from("I <3 Enums"),
};
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": Struct(
value: "I <3 Enums",
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_serialize_non_self_describing_binary() {
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
let config = bincode::config::standard().with_fixed_int_encoding();
let bytes = bincode::serde::encode_to_vec(&serializer, config).unwrap();
let expected: Vec<u8> = vec![
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 98, 101, 118, 121, 95, 114, 101, 102,
108, 101, 99, 116, 58, 58, 115, 101, 114, 100, 101, 58, 58, 115, 101, 114, 58, 58, 116,
101, 115, 116, 115, 58, 58, 77, 121, 83, 116, 114, 117, 99, 116, 123, 1, 12, 0, 0, 0,
0, 0, 0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 1, 123, 0, 0, 0,
0, 0, 0, 0, 219, 15, 73, 64, 57, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 254, 255,
255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 254, 255, 255, 255,
255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 32,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 255, 201, 154, 59, 0, 0, 0, 0, 12, 0,
0, 0, 0, 0, 0, 0, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 0, 0, 0, 0,
1, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 164, 112, 157, 63, 164, 112, 77, 64,
3, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105,
97, 110, 116, 32, 118, 97, 108, 117, 101, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0,
0, 0, 101, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(expected, bytes);
}
#[test]
fn should_serialize_self_describing_binary() {
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
let bytes: Vec<u8> = rmp_serde::to_vec(&serializer).unwrap();
let expected: Vec<u8> = vec![
129, 217, 41, 98, 101, 118, 121, 95, 114, 101, 102, 108, 101, 99, 116, 58, 58, 115,
101, 114, 100, 101, 58, 58, 115, 101, 114, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77,
121, 83, 116, 114, 117, 99, 116, 220, 0, 20, 123, 172, 72, 101, 108, 108, 111, 32, 119,
111, 114, 108, 100, 33, 145, 123, 146, 202, 64, 73, 15, 219, 205, 5, 57, 149, 254, 255,
0, 1, 2, 149, 254, 255, 0, 1, 2, 129, 64, 32, 145, 64, 145, 206, 59, 154, 201, 255,
172, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 144, 164, 85, 110, 105,
116, 129, 167, 78, 101, 119, 84, 121, 112, 101, 123, 129, 165, 84, 117, 112, 108, 101,
146, 202, 63, 157, 112, 164, 202, 64, 77, 112, 164, 129, 166, 83, 116, 114, 117, 99,
116, 145, 180, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105, 97, 110, 116, 32,
118, 97, 108, 117, 101, 144, 144, 129, 166, 83, 116, 114, 117, 99, 116, 144, 129, 165,
84, 117, 112, 108, 101, 144, 146, 100, 145, 101,
];
assert_eq!(expected, bytes);
}
#[test]
fn should_serialize_dynamic_option() {
#[derive(Default, Reflect)]
struct OtherStruct {
some: Option<SomeStruct>,
none: Option<SomeStruct>,
}
let value = OtherStruct {
some: Some(SomeStruct { foo: 999999999 }),
none: None,
};
let dynamic = value.to_dynamic_struct();
let reflect = dynamic.as_partial_reflect();
let registry = get_registry();
let serializer = ReflectSerializer::new(reflect, &registry);
let mut buf = Vec::new();
let format = serde_json::ser::PrettyFormatter::with_indent(b" ");
let mut ser = serde_json::Serializer::with_formatter(&mut buf, format);
serializer.serialize(&mut ser).unwrap();
let output = core::str::from_utf8(&buf).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::OtherStruct": {
"some": {
"foo": 999999999
},
"none": null
}
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_return_error_if_missing_registration() {
let value = RangeInclusive::<f32>::new(0.0, 1.0);
let registry = TypeRegistry::new();
let serializer = ReflectSerializer::new(&value, &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` is not registered in the type registry (stack: `core::ops::RangeInclusive<f32>`)"
.to_string(),
)
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` is not registered in the type registry"
.to_string(),
)
);
}
#[test]
fn should_return_error_if_missing_type_data() {
let value = RangeInclusive::<f32>::new(0.0, 1.0);
let mut registry = TypeRegistry::new();
registry.register::<RangeInclusive<f32>>();
let serializer = ReflectSerializer::new(&value, &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `core::ops::RangeInclusive<f32>`)".to_string()
)
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string()
)
);
}
#[test]
fn should_use_processor_for_custom_serialization() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct FooProcessor;
impl ReflectSerializerProcessor for FooProcessor {
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
_: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
let Some(value) = value.try_as_reflect() else {
return Ok(Err(serializer));
};
let type_id = value.reflect_type_info().type_id();
if type_id == TypeId::of::<i64>() {
Ok(Ok(serializer.serialize_str("custom!")?))
} else {
Ok(Err(serializer))
}
}
}
let value = Foo { bar: 123, qux: 456 };
let mut registry = TypeRegistry::new();
registry.register::<Foo>();
let processor = FooProcessor;
let serializer = ReflectSerializer::with_processor(&value, &registry, &processor);
let config = PrettyConfig::default().new_line(String::from("\n"));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::Foo": (
bar: 123,
qux: "custom!",
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_use_processor_for_multiple_registrations() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
sub: SubFoo,
}
#[derive(Reflect, Debug, PartialEq)]
struct SubFoo {
val: i32,
}
struct FooProcessor;
impl ReflectSerializerProcessor for FooProcessor {
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
_: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
let Some(value) = value.try_as_reflect() else {
return Ok(Err(serializer));
};
let type_id = value.reflect_type_info().type_id();
if type_id == TypeId::of::<i32>() {
Ok(Ok(serializer.serialize_str("an i32")?))
} else if type_id == TypeId::of::<SubFoo>() {
Ok(Ok(serializer.serialize_str("a SubFoo")?))
} else {
Ok(Err(serializer))
}
}
}
let value = Foo {
bar: 123,
sub: SubFoo { val: 456 },
};
let mut registry = TypeRegistry::new();
registry.register::<Foo>();
registry.register::<SubFoo>();
let processor = FooProcessor;
let serializer = ReflectSerializer::with_processor(&value, &registry, &processor);
let config = PrettyConfig::default().new_line(String::from("\n"));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::Foo": (
bar: "an i32",
sub: "a SubFoo",
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_propagate_processor_serialize_error() {
struct ErroringProcessor;
impl ReflectSerializerProcessor for ErroringProcessor {
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
_: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
let Some(value) = value.try_as_reflect() else {
return Ok(Err(serializer));
};
let type_id = value.reflect_type_info().type_id();
if type_id == TypeId::of::<i32>() {
Err(serde::ser::Error::custom("my custom serialize error"))
} else {
Ok(Err(serializer))
}
}
}
let value = 123_i32;
let registry = TypeRegistry::new();
let processor = ErroringProcessor;
let serializer = ReflectSerializer::with_processor(&value, &registry, &processor);
let error = ron::ser::to_string_pretty(&serializer, PrettyConfig::default()).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message("my custom serialize error (stack: `i32`)".to_string())
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message("my custom serialize error".to_string())
);
}
#[cfg(feature = "functions")]
mod functions {
use super::*;
use crate::func::{DynamicFunction, IntoFunction};
use alloc::string::ToString;
#[test]
fn should_not_serialize_function() {
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct MyStruct {
func: DynamicFunction<'static>,
}
let value: Box<dyn Reflect> = Box::new(MyStruct {
func: String::new.into_function(),
});
let registry = TypeRegistry::new();
let serializer = ReflectSerializer::new(value.as_partial_reflect(), &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message("functions cannot be serialized (stack: `bevy_reflect::serde::ser::tests::functions::MyStruct`)".to_string())
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message("functions cannot be serialized".to_string())
);
}
}
#[cfg(feature = "debug_stack")]
mod debug_stack {
use super::*;
#[test]
fn should_report_context_in_errors() {
#[derive(Reflect)]
struct Foo {
bar: Bar,
}
#[derive(Reflect)]
struct Bar {
some_other_field: Option<u32>,
baz: Baz,
}
#[derive(Reflect)]
struct Baz {
value: Vec<RangeInclusive<f32>>,
}
let value = Foo {
bar: Bar {
some_other_field: Some(123),
baz: Baz {
value: vec![0.0..=1.0],
},
},
};
let registry = TypeRegistry::new();
let serializer = ReflectSerializer::new(&value, &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` is not registered in the type registry (stack: `bevy_reflect::serde::ser::tests::debug_stack::Foo` -> `bevy_reflect::serde::ser::tests::debug_stack::Bar` -> `bevy_reflect::serde::ser::tests::debug_stack::Baz` -> `alloc::vec::Vec<core::ops::RangeInclusive<f32>>` -> `core::ops::RangeInclusive<f32>`)".to_string()
)
);
}
}
}

View File

@@ -0,0 +1,196 @@
use serde::Serializer;
use crate::{PartialReflect, TypeRegistry};
/// Allows overriding the default serialization behavior of
/// [`ReflectSerializer`] and [`TypedReflectSerializer`] for specific values.
///
/// When serializing a reflected value, you may want to override the default
/// behavior and use your own logic for serialization. This logic may also be
/// context-dependent, and only apply for a single use of your
/// [`ReflectSerializer`]. To achieve this, you can create a processor and pass
/// it into your serializer.
///
/// Whenever the serializer attempts to serialize a value, it will first call
/// [`try_serialize`] on your processor, which may take ownership of the
/// serializer and write into the serializer (successfully or not), or return
/// ownership of the serializer back, and continue with the default logic.
///
/// The deserialization equivalent of this is [`ReflectDeserializerProcessor`].
///
/// # Compared to [`SerializeWithRegistry`]
///
/// [`SerializeWithRegistry`] allows you to define how your type will be
/// serialized by a [`TypedReflectSerializer`], given the extra context of the
/// [`TypeRegistry`]. If your type can be serialized entirely using that, then
/// you should prefer implementing that trait instead of using a processor.
///
/// However, you may need more context-dependent data which is only present in
/// the scope where you create the [`TypedReflectSerializer`]. For example, if
/// you need to use a reference to a value while serializing, then there is no
/// way to do this with [`SerializeWithRegistry`] as you can't pass that
/// reference into anywhere. This is where a processor is useful, as the
/// processor can capture local variables.
///
/// A [`ReflectSerializerProcessor`] always takes priority over a
/// [`SerializeWithRegistry`] implementation, so this is also useful for
/// overriding serialization behavior if you need to do something custom.
///
/// # Examples
///
/// Serializing a reflected value when saving an asset to disk, and replacing
/// asset handles with the handle path (if it has one):
///
/// ```
/// # use core::any::Any;
/// # use serde::Serialize;
/// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistry};
/// # use bevy_reflect::serde::{ReflectSerializer, ReflectSerializerProcessor};
/// #
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Handle<T>(T);
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Mesh;
/// #
/// # struct ReflectHandle;
/// # impl TypeData for ReflectHandle {
/// # fn clone_type_data(&self) -> Box<dyn TypeData> {
/// # unimplemented!()
/// # }
/// # }
/// # impl ReflectHandle {
/// # fn downcast_handle_untyped(&self, handle: &(dyn Any + 'static)) -> Option<UntypedHandle> {
/// # unimplemented!()
/// # }
/// # }
/// #
/// # #[derive(Debug, Clone)]
/// # struct UntypedHandle;
/// # impl UntypedHandle {
/// # fn path(&self) -> Option<&str> {
/// # unimplemented!()
/// # }
/// # }
/// # type AssetError = Box<dyn core::error::Error>;
/// #
/// #[derive(Debug, Clone, Reflect)]
/// struct MyAsset {
/// name: String,
/// mesh: Handle<Mesh>,
/// }
///
/// struct HandleProcessor;
///
/// impl ReflectSerializerProcessor for HandleProcessor {
/// fn try_serialize<S>(
/// &self,
/// value: &dyn PartialReflect,
/// registry: &TypeRegistry,
/// serializer: S,
/// ) -> Result<Result<S::Ok, S>, S::Error>
/// where
/// S: serde::Serializer,
/// {
/// let Some(value) = value.try_as_reflect() else {
/// // we don't have any info on this type; do the default serialization logic
/// return Ok(Err(serializer));
/// };
/// let type_id = value.reflect_type_info().type_id();
/// let Some(reflect_handle) = registry.get_type_data::<ReflectHandle>(type_id) else {
/// // this isn't a `Handle<T>`
/// return Ok(Err(serializer));
/// };
///
/// let untyped_handle = reflect_handle
/// .downcast_handle_untyped(value.as_any())
/// .unwrap();
/// if let Some(path) = untyped_handle.path() {
/// Ok(Ok(serializer.serialize_str(path)?))
/// } else {
/// Ok(Ok(serializer.serialize_unit()?))
/// }
/// }
/// }
///
/// fn save(type_registry: &TypeRegistry, asset: &MyAsset) -> Result<Vec<u8>, AssetError> {
/// let mut asset_bytes = Vec::new();
///
/// let processor = HandleProcessor;
/// let serializer = ReflectSerializer::with_processor(asset, type_registry, &processor);
/// let mut ron_serializer = ron::Serializer::new(&mut asset_bytes, None)?;
///
/// serializer.serialize(&mut ron_serializer)?;
/// Ok(asset_bytes)
/// }
/// ```
///
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`try_serialize`]: Self::try_serialize
/// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry
/// [`ReflectDeserializerProcessor`]: crate::serde::ReflectDeserializerProcessor
pub trait ReflectSerializerProcessor {
/// Attempts to serialize the value which a [`TypedReflectSerializer`] is
/// currently looking at.
///
/// If you want to override the default serialization, return
/// `Ok(Ok(value))` with an `Ok` output from the serializer.
///
/// If you don't want to override the serialization, return ownership of
/// the serializer back via `Ok(Err(serializer))`.
///
/// You can use the type registry to read info about the type you're
/// serializing, or just try to downcast the value directly:
///
/// ```
/// # use bevy_reflect::{TypeRegistration, TypeRegistry, PartialReflect};
/// # use bevy_reflect::serde::ReflectSerializerProcessor;
/// # use core::any::TypeId;
/// struct I32AsStringProcessor;
///
/// impl ReflectSerializerProcessor for I32AsStringProcessor {
/// fn try_serialize<S>(
/// &self,
/// value: &dyn PartialReflect,
/// registry: &TypeRegistry,
/// serializer: S,
/// ) -> Result<Result<S::Ok, S>, S::Error>
/// where
/// S: serde::Serializer
/// {
/// if let Some(value) = value.try_downcast_ref::<i32>() {
/// let value_as_string = format!("{value:?}");
/// Ok(Ok(serializer.serialize_str(&value_as_string)?))
/// } else {
/// // Not an `i32`, just do the default serialization
/// Ok(Err(serializer))
/// }
/// }
/// }
/// ```
///
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`Reflect`]: crate::Reflect
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
registry: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer;
}
impl ReflectSerializerProcessor for () {
fn try_serialize<S>(
&self,
_value: &dyn PartialReflect,
_registry: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
Ok(Err(serializer))
}
}

View File

@@ -0,0 +1,19 @@
use alloc::boxed::Box;
use core::ops::Deref;
/// A type-erased serializable value.
pub enum Serializable<'a> {
Owned(Box<dyn erased_serde::Serialize + 'a>),
Borrowed(&'a dyn erased_serde::Serialize),
}
impl<'a> Deref for Serializable<'a> {
type Target = dyn erased_serde::Serialize + 'a;
fn deref(&self) -> &Self::Target {
match self {
Serializable::Borrowed(serialize) => serialize,
Serializable::Owned(serialize) => serialize,
}
}
}

View File

@@ -0,0 +1,101 @@
use crate::{FromType, Reflect, TypeRegistry};
use alloc::boxed::Box;
use serde::{Serialize, Serializer};
/// Trait used to provide finer control when serializing a reflected type with one of
/// the reflection serializers.
///
/// This trait is the reflection equivalent of `serde`'s [`Serialize`] trait.
/// The main difference is that this trait provides access to the [`TypeRegistry`],
/// which means that we can use the registry and all its stored type information
/// to serialize our type.
///
/// This can be useful when writing a custom reflection serializer where we may
/// want to handle parts of the serialization process, but temporarily pass control
/// to the standard reflection serializer for other parts.
///
/// For the deserialization equivalent of this trait, see [`DeserializeWithRegistry`].
///
/// # Rationale
///
/// Without this trait and its associated [type data], such a serializer would have to
/// write out all of the serialization logic itself, possibly including
/// unnecessary code duplication and trivial implementations.
///
/// This is because a normal [`Serialize`] implementation has no knowledge of the
/// [`TypeRegistry`] and therefore cannot create a reflection-based serializer for
/// nested items.
///
/// # Implementors
///
/// In order for this to work with the reflection serializers like [`TypedReflectSerializer`]
/// and [`ReflectSerializer`], implementors should be sure to register the
/// [`ReflectSerializeWithRegistry`] type data.
/// This can be done [via the registry] or by adding `#[reflect(SerializeWithRegistry)]` to
/// the type definition.
///
/// [`DeserializeWithRegistry`]: crate::serde::DeserializeWithRegistry
/// [type data]: ReflectSerializeWithRegistry
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
/// [via the registry]: TypeRegistry::register_type_data
pub trait SerializeWithRegistry {
fn serialize<S>(&self, serializer: S, registry: &TypeRegistry) -> Result<S::Ok, S::Error>
where
S: Serializer;
}
/// Type data used to serialize a [`Reflect`] type with a custom [`SerializeWithRegistry`] implementation.
#[derive(Clone)]
pub struct ReflectSerializeWithRegistry {
serialize: for<'a> fn(
value: &'a dyn Reflect,
registry: &'a TypeRegistry,
) -> Box<dyn erased_serde::Serialize + 'a>,
}
impl ReflectSerializeWithRegistry {
/// Serialize a [`Reflect`] type with this type data's custom [`SerializeWithRegistry`] implementation.
pub fn serialize<S>(
&self,
value: &dyn Reflect,
serializer: S,
registry: &TypeRegistry,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
((self.serialize)(value, registry)).serialize(serializer)
}
}
impl<T: Reflect + SerializeWithRegistry> FromType<T> for ReflectSerializeWithRegistry {
fn from_type() -> Self {
Self {
serialize: |value: &dyn Reflect, registry| {
let value = value.downcast_ref::<T>().unwrap_or_else(|| {
panic!(
"Expected value to be of type {} but received {}",
core::any::type_name::<T>(),
value.reflect_type_path()
)
});
Box::new(SerializableWithRegistry { value, registry })
},
}
}
}
struct SerializableWithRegistry<'a, T: SerializeWithRegistry> {
value: &'a T,
registry: &'a TypeRegistry,
}
impl<'a, T: SerializeWithRegistry> Serialize for SerializableWithRegistry<'a, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.value.serialize(serializer, self.registry)
}
}

View File

@@ -0,0 +1,326 @@
#[cfg(feature = "debug_stack")]
use crate::serde::ser::error_utils::TYPE_INFO_STACK;
use crate::{
serde::ser::{
arrays::ArraySerializer, custom_serialization::try_custom_serialize, enums::EnumSerializer,
error_utils::make_custom_error, lists::ListSerializer, maps::MapSerializer,
sets::SetSerializer, structs::StructSerializer, tuple_structs::TupleStructSerializer,
tuples::TupleSerializer,
},
PartialReflect, ReflectRef, TypeRegistry,
};
use serde::{ser::SerializeMap, Serialize, Serializer};
use super::ReflectSerializerProcessor;
/// A general purpose serializer for reflected types.
///
/// This is the serializer counterpart to [`ReflectDeserializer`].
///
/// See [`TypedReflectSerializer`] for a serializer that serializes a known type.
///
/// # Output
///
/// This serializer will output a map with a single entry,
/// where the key is the _full_ [type path] of the reflected type
/// and the value is the serialized data.
///
/// If you want to override serialization for specific values, you can pass in
/// a reference to a [`ReflectSerializerProcessor`] which will take priority
/// over all other serialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{TypeRegistry, serde::ReflectSerializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// #[type_path = "my_crate"]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = MyStruct { value: 123 };
///
/// let reflect_serializer = ReflectSerializer::new(&input, &registry);
/// let output = ron::to_string(&reflect_serializer).unwrap();
///
/// assert_eq!(output, r#"{"my_crate::MyStruct":(value:123)}"#);
/// ```
///
/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
/// [type path]: crate::TypePath::type_path
/// [`with_processor`]: Self::with_processor
pub struct ReflectSerializer<'a, P = ()> {
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: Option<&'a P>,
}
impl<'a> ReflectSerializer<'a, ()> {
/// Creates a serializer with no processor.
///
/// If you want to add custom logic for serializing certain values, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(value: &'a dyn PartialReflect, registry: &'a TypeRegistry) -> Self {
Self {
value,
registry,
processor: None,
}
}
}
impl<'a, P: ReflectSerializerProcessor> ReflectSerializer<'a, P> {
/// Creates a serializer with a processor.
///
/// If you do not need any custom logic for handling certain values, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: &'a P,
) -> Self {
Self {
value,
registry,
processor: Some(processor),
}
}
}
impl<P: ReflectSerializerProcessor> Serialize for ReflectSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_map(Some(1))?;
state.serialize_entry(
self.value
.get_represented_type_info()
.ok_or_else(|| {
if self.value.is_dynamic() {
make_custom_error(format_args!(
"cannot serialize dynamic value without represented type: `{}`",
self.value.reflect_type_path()
))
} else {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.value.reflect_type_path()
))
}
})?
.type_path(),
&TypedReflectSerializer::new_internal(self.value, self.registry, self.processor),
)?;
state.end()
}
}
/// A serializer for reflected types whose type will be known during deserialization.
///
/// This is the serializer counterpart to [`TypedReflectDeserializer`].
///
/// See [`ReflectSerializer`] for a serializer that serializes an unknown type.
///
/// # Output
///
/// Since the type is expected to be known during deserialization,
/// this serializer will not output any additional type information,
/// such as the [type path].
///
/// Instead, it will output just the serialized data.
///
/// If you want to override serialization for specific values, you can pass in
/// a reference to a [`ReflectSerializerProcessor`] which will take priority
/// over all other serialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{TypeRegistry, serde::TypedReflectSerializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// #[type_path = "my_crate"]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = MyStruct { value: 123 };
///
/// let reflect_serializer = TypedReflectSerializer::new(&input, &registry);
/// let output = ron::to_string(&reflect_serializer).unwrap();
///
/// assert_eq!(output, r#"(value:123)"#);
/// ```
///
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [type path]: crate::TypePath::type_path
/// [`with_processor`]: Self::with_processor
pub struct TypedReflectSerializer<'a, P = ()> {
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: Option<&'a P>,
}
impl<'a> TypedReflectSerializer<'a, ()> {
/// Creates a serializer with no processor.
///
/// If you want to add custom logic for serializing certain values, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(value: &'a dyn PartialReflect, registry: &'a TypeRegistry) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
value,
registry,
processor: None,
}
}
}
impl<'a, P> TypedReflectSerializer<'a, P> {
/// Creates a serializer with a processor.
///
/// If you do not need any custom logic for handling certain values, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: &'a P,
) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
value,
registry,
processor: Some(processor),
}
}
/// An internal constructor for creating a serializer without resetting the type info stack.
pub(super) fn new_internal(
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: Option<&'a P>,
) -> Self {
Self {
value,
registry,
processor,
}
}
}
impl<P: ReflectSerializerProcessor> Serialize for TypedReflectSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[cfg(feature = "debug_stack")]
{
if let Some(info) = self.value.get_represented_type_info() {
TYPE_INFO_STACK.with_borrow_mut(|stack| stack.push(info));
}
}
// First, check if our processor wants to serialize this type
// This takes priority over any other serialization operations
let serializer = if let Some(processor) = self.processor {
match processor.try_serialize(self.value, self.registry, serializer) {
Ok(Ok(value)) => {
return Ok(value);
}
Err(err) => {
return Err(make_custom_error(err));
}
Ok(Err(serializer)) => serializer,
}
} else {
serializer
};
// Handle both Value case and types that have a custom `Serialize`
let (serializer, error) = match try_custom_serialize(self.value, self.registry, serializer)
{
Ok(result) => return result,
Err(value) => value,
};
let output = match self.value.reflect_ref() {
ReflectRef::Struct(struct_value) => StructSerializer {
struct_value,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::TupleStruct(tuple_struct) => TupleStructSerializer {
tuple_struct,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Tuple(tuple) => TupleSerializer {
tuple,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::List(list) => ListSerializer {
list,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Array(array) => ArraySerializer {
array,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Map(map) => MapSerializer {
map,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Set(set) => SetSerializer {
set,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Enum(enum_value) => EnumSerializer {
enum_value,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
#[cfg(feature = "functions")]
ReflectRef::Function(_) => Err(make_custom_error("functions cannot be serialized")),
ReflectRef::Opaque(_) => Err(error),
};
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
output
}
}

View File

@@ -0,0 +1,28 @@
use crate::{serde::TypedReflectSerializer, Set, TypeRegistry};
use serde::{ser::SerializeSeq, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Set`] values.
pub(super) struct SetSerializer<'a, P> {
pub set: &'a dyn Set,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for SetSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_seq(Some(self.set.len()))?;
for value in self.set.iter() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,62 @@
use crate::{
serde::{ser::error_utils::make_custom_error, SerializationData, TypedReflectSerializer},
Struct, TypeInfo, TypeRegistry,
};
use serde::{ser::SerializeStruct, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Struct`] values.
pub(super) struct StructSerializer<'a, P> {
pub struct_value: &'a dyn Struct,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for StructSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let type_info = self
.struct_value
.get_represented_type_info()
.ok_or_else(|| {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.struct_value.reflect_type_path()
))
})?;
let struct_info = match type_info {
TypeInfo::Struct(struct_info) => struct_info,
info => {
return Err(make_custom_error(format_args!(
"expected struct type but received {info:?}"
)));
}
};
let serialization_data = self
.registry
.get(type_info.type_id())
.and_then(|registration| registration.data::<SerializationData>());
let ignored_len = serialization_data.map(SerializationData::len).unwrap_or(0);
let mut state = serializer.serialize_struct(
struct_info.type_path_table().ident().unwrap(),
self.struct_value.field_len() - ignored_len,
)?;
for (index, value) in self.struct_value.iter_fields().enumerate() {
if serialization_data.is_some_and(|data| data.is_field_skipped(index)) {
continue;
}
let key = struct_info.field_at(index).unwrap().name();
state.serialize_field(
key,
&TypedReflectSerializer::new_internal(value, self.registry, self.processor),
)?;
}
state.end()
}
}

View File

@@ -0,0 +1,71 @@
use crate::{
serde::{ser::error_utils::make_custom_error, SerializationData, TypedReflectSerializer},
TupleStruct, TypeInfo, TypeRegistry,
};
use serde::{ser::SerializeTupleStruct, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`TupleStruct`] values.
pub(super) struct TupleStructSerializer<'a, P> {
pub tuple_struct: &'a dyn TupleStruct,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for TupleStructSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let type_info = self
.tuple_struct
.get_represented_type_info()
.ok_or_else(|| {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.tuple_struct.reflect_type_path()
))
})?;
let tuple_struct_info = match type_info {
TypeInfo::TupleStruct(tuple_struct_info) => tuple_struct_info,
info => {
return Err(make_custom_error(format_args!(
"expected tuple struct type but received {info:?}"
)));
}
};
let serialization_data = self
.registry
.get(type_info.type_id())
.and_then(|registration| registration.data::<SerializationData>());
let ignored_len = serialization_data.map(SerializationData::len).unwrap_or(0);
if self.tuple_struct.field_len() == 1 && serialization_data.is_none() {
let field = self.tuple_struct.field(0).unwrap();
return serializer.serialize_newtype_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
&TypedReflectSerializer::new_internal(field, self.registry, self.processor),
);
}
let mut state = serializer.serialize_tuple_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
self.tuple_struct.field_len() - ignored_len,
)?;
for (index, value) in self.tuple_struct.iter_fields().enumerate() {
if serialization_data.is_some_and(|data| data.is_field_skipped(index)) {
continue;
}
state.serialize_field(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,29 @@
use crate::{serde::TypedReflectSerializer, Tuple, TypeRegistry};
use serde::{ser::SerializeTuple, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Tuple`] values.
pub(super) struct TupleSerializer<'a, P> {
pub tuple: &'a dyn Tuple,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for TupleSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_tuple(self.tuple.field_len())?;
for value in self.tuple.iter_fields() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,136 @@
use crate::Reflect;
use alloc::boxed::Box;
use bevy_platform::collections::{hash_map::Iter, HashMap};
/// Contains data relevant to the automatic reflect powered (de)serialization of a type.
#[derive(Debug, Clone)]
pub struct SerializationData {
skipped_fields: HashMap<usize, SkippedField>,
}
impl SerializationData {
/// Creates a new `SerializationData` instance with the given skipped fields.
///
/// # Arguments
///
/// * `skipped_iter`: The iterator of field indices to be skipped during (de)serialization.
/// Indices are assigned only to reflected fields.
/// Ignored fields (i.e. those marked `#[reflect(ignore)]`) are implicitly skipped
/// and do not need to be included in this iterator.
pub fn new<I: Iterator<Item = (usize, SkippedField)>>(skipped_iter: I) -> Self {
Self {
skipped_fields: skipped_iter.collect(),
}
}
/// Returns true if the given index corresponds to a field meant to be skipped during (de)serialization.
///
/// # Example
///
/// ```
/// # use core::any::TypeId;
/// # use bevy_reflect::{Reflect, Struct, TypeRegistry, serde::SerializationData};
/// #[derive(Reflect)]
/// struct MyStruct {
/// serialize_me: i32,
/// #[reflect(skip_serializing)]
/// skip_me: i32
/// }
///
/// let mut registry = TypeRegistry::new();
/// registry.register::<MyStruct>();
///
/// let my_struct = MyStruct {
/// serialize_me: 123,
/// skip_me: 321,
/// };
///
/// let serialization_data = registry.get_type_data::<SerializationData>(TypeId::of::<MyStruct>()).unwrap();
///
/// for (idx, field) in my_struct.iter_fields().enumerate(){
/// if serialization_data.is_field_skipped(idx) {
/// // Skipped!
/// assert_eq!(1, idx);
/// } else {
/// // Not Skipped!
/// assert_eq!(0, idx);
/// }
/// }
/// ```
pub fn is_field_skipped(&self, index: usize) -> bool {
self.skipped_fields.contains_key(&index)
}
/// Generates a default instance of the skipped field at the given index.
///
/// Returns `None` if the field is not skipped.
///
/// # Example
///
/// ```
/// # use core::any::TypeId;
/// # use bevy_reflect::{Reflect, Struct, TypeRegistry, serde::SerializationData};
/// #[derive(Reflect)]
/// struct MyStruct {
/// serialize_me: i32,
/// #[reflect(skip_serializing)]
/// #[reflect(default = "skip_me_default")]
/// skip_me: i32
/// }
///
/// fn skip_me_default() -> i32 {
/// 789
/// }
///
/// let mut registry = TypeRegistry::new();
/// registry.register::<MyStruct>();
///
/// let serialization_data = registry.get_type_data::<SerializationData>(TypeId::of::<MyStruct>()).unwrap();
/// assert_eq!(789, serialization_data.generate_default(1).unwrap().take::<i32>().unwrap());
/// ```
pub fn generate_default(&self, index: usize) -> Option<Box<dyn Reflect>> {
self.skipped_fields
.get(&index)
.map(SkippedField::generate_default)
}
/// Returns the number of skipped fields.
pub fn len(&self) -> usize {
self.skipped_fields.len()
}
/// Returns true if there are no skipped fields.
pub fn is_empty(&self) -> bool {
self.skipped_fields.is_empty()
}
/// Returns an iterator over the skipped fields.
///
/// Each item in the iterator is a tuple containing:
/// 1. The reflected index of the field
/// 2. The (de)serialization metadata of the field
pub fn iter_skipped(&self) -> Iter<'_, usize, SkippedField> {
self.skipped_fields.iter()
}
}
/// Data needed for (de)serialization of a skipped field.
#[derive(Debug, Clone)]
pub struct SkippedField {
default_fn: fn() -> Box<dyn Reflect>,
}
impl SkippedField {
/// Create a new `SkippedField`.
///
/// # Arguments
///
/// * `default_fn`: A function pointer used to generate a default instance of the field.
pub fn new(default_fn: fn() -> Box<dyn Reflect>) -> Self {
Self { default_fn }
}
/// Generates a default instance of the field.
pub fn generate_default(&self) -> Box<dyn Reflect> {
(self.default_fn)()
}
}

515
vendor/bevy_reflect/src/set.rs vendored Normal file
View File

@@ -0,0 +1,515 @@
use alloc::{boxed::Box, format, vec::Vec};
use core::fmt::{Debug, Formatter};
use bevy_platform::collections::{hash_table::OccupiedEntry as HashTableOccupiedEntry, HashTable};
use bevy_reflect_derive::impl_type_path;
use crate::{
generics::impl_generic_info_methods, hash_error, type_info::impl_type_methods, ApplyError,
Generics, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
TypeInfo, TypePath,
};
/// A trait used to power [set-like] operations via [reflection].
///
/// Sets contain zero or more entries of a fixed type, and correspond to types
/// like [`HashSet`] and [`BTreeSet`].
/// The order of these entries is not guaranteed by this trait.
///
/// # Hashing and equality
///
/// All values are expected to return a valid hash value from [`PartialReflect::reflect_hash`] and be
/// comparable using [`PartialReflect::reflect_partial_eq`].
/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding
/// `#[reflect(Hash, PartialEq)]` to the entire struct or enum.
/// The ordering is expected to be total, that is as if the reflected type implements the [`Eq`] trait.
/// This is true even for manual implementors who do not hash or compare values,
/// as it is still relied on by [`DynamicSet`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Set};
/// use std::collections::HashSet;
///
///
/// let foo: &mut dyn Set = &mut HashSet::<u32>::new();
/// foo.insert_boxed(Box::new(123_u32));
/// assert_eq!(foo.len(), 1);
///
/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123_u32));
/// ```
///
/// [`HashSet`]: std::collections::HashSet
/// [`BTreeSet`]: alloc::collections::BTreeSet
/// [set-like]: https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html
/// [reflection]: crate
pub trait Set: PartialReflect {
/// Returns a reference to the value.
///
/// If no value is contained, returns `None`.
fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
/// Returns the number of elements in the set.
fn len(&self) -> usize;
/// Returns `true` if the list contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the values of the set.
fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_>;
/// Drain the values of this set to get a vector of owned values.
///
/// After calling this function, `self` will be empty.
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>>;
/// Clones the set, producing a [`DynamicSet`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_set` instead")]
fn clone_dynamic(&self) -> DynamicSet {
self.to_dynamic_set()
}
/// Creates a new [`DynamicSet`] from this set.
fn to_dynamic_set(&self) -> DynamicSet {
let mut set = DynamicSet::default();
set.set_represented_type(self.get_represented_type_info());
for value in self.iter() {
set.insert_boxed(value.to_dynamic());
}
set
}
/// Inserts a value into the set.
///
/// If the set did not have this value present, `true` is returned.
/// If the set did have this value present, `false` is returned.
fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool;
/// Removes a value from the set.
///
/// If the set did not have this value present, `true` is returned.
/// If the set did have this value present, `false` is returned.
fn remove(&mut self, value: &dyn PartialReflect) -> bool;
/// Checks if the given value is contained in the set
fn contains(&self, value: &dyn PartialReflect) -> bool;
}
/// A container for compile-time set info.
#[derive(Clone, Debug)]
pub struct SetInfo {
ty: Type,
generics: Generics,
value_ty: Type,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl SetInfo {
/// Create a new [`SetInfo`].
pub fn new<TSet: Set + TypePath, TValue: Reflect + TypePath>() -> Self {
Self {
ty: Type::of::<TSet>(),
generics: Generics::new(),
value_ty: Type::of::<TValue>(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this set.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
impl_type_methods!(ty);
/// The [type] of the value.
///
/// [type]: Type
pub fn value_ty(&self) -> Type {
self.value_ty
}
/// The docstring of this set, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// An ordered set of reflected values.
#[derive(Default)]
pub struct DynamicSet {
represented_type: Option<&'static TypeInfo>,
hash_table: HashTable<Box<dyn PartialReflect>>,
}
impl DynamicSet {
/// Sets the [type] to be represented by this `DynamicSet`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Set`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Set(_)),
"expected TypeInfo::Set but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Inserts a typed value into the set.
pub fn insert<V: Reflect>(&mut self, value: V) {
self.insert_boxed(Box::new(value));
}
fn internal_hash(value: &dyn PartialReflect) -> u64 {
value.reflect_hash().expect(&hash_error!(value))
}
fn internal_eq(
value: &dyn PartialReflect,
) -> impl FnMut(&Box<dyn PartialReflect>) -> bool + '_ {
|other| {
value
.reflect_partial_eq(&**other)
.expect("Underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
}
}
}
impl Set for DynamicSet {
fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
self.hash_table
.find(Self::internal_hash(value), Self::internal_eq(value))
.map(|value| &**value)
}
fn len(&self) -> usize {
self.hash_table.len()
}
fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_> {
let iter = self.hash_table.iter().map(|v| &**v);
Box::new(iter)
}
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
self.hash_table.drain().collect::<Vec<_>>()
}
fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool {
assert_eq!(
value.reflect_partial_eq(&*value),
Some(true),
"Values inserted in `Set` like types are expected to reflect `PartialEq`"
);
match self
.hash_table
.find_mut(Self::internal_hash(&*value), Self::internal_eq(&*value))
{
Some(old) => {
*old = value;
false
}
None => {
self.hash_table.insert_unique(
Self::internal_hash(value.as_ref()),
value,
|boxed| Self::internal_hash(boxed.as_ref()),
);
true
}
}
}
fn remove(&mut self, value: &dyn PartialReflect) -> bool {
self.hash_table
.find_entry(Self::internal_hash(value), Self::internal_eq(value))
.map(HashTableOccupiedEntry::remove)
.is_ok()
}
fn contains(&self, value: &dyn PartialReflect) -> bool {
self.hash_table
.find(Self::internal_hash(value), Self::internal_eq(value))
.is_some()
}
}
impl PartialReflect for DynamicSet {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
#[inline]
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
#[inline]
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
set_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
set_try_apply(self, value)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Set
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Set(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Set(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Set(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
set_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicSet(")?;
set_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicSet);
impl Debug for DynamicSet {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl FromIterator<Box<dyn PartialReflect>> for DynamicSet {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
let mut this = Self {
represented_type: None,
hash_table: HashTable::new(),
};
for value in values {
this.insert_boxed(value);
}
this
}
}
impl<T: Reflect> FromIterator<T> for DynamicSet {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
let mut this = Self {
represented_type: None,
hash_table: HashTable::new(),
};
for value in values {
this.insert(value);
}
this
}
}
impl IntoIterator for DynamicSet {
type Item = Box<dyn PartialReflect>;
type IntoIter = bevy_platform::collections::hash_table::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.hash_table.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicSet {
type Item = &'a dyn PartialReflect;
type IntoIter = core::iter::Map<
bevy_platform::collections::hash_table::Iter<'a, Box<dyn PartialReflect>>,
fn(&'a Box<dyn PartialReflect>) -> Self::Item,
>;
fn into_iter(self) -> Self::IntoIter {
self.hash_table.iter().map(|v| v.as_ref())
}
}
/// Compares a [`Set`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a set;
/// - `b` is the same length as `a`;
/// - For each value pair in `a`, `b` contains the value too,
/// and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn set_partial_eq<M: Set>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Set(set) = b.reflect_ref() else {
return Some(false);
};
if a.len() != set.len() {
return Some(false);
}
for value in a.iter() {
if let Some(set_value) = set.get(value) {
let eq_result = value.reflect_partial_eq(set_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
}
}
Some(true)
}
/// The default debug formatter for [`Set`] types.
///
/// # Example
/// ```
/// # use std::collections::HashSet;
/// use bevy_reflect::Reflect;
///
/// let mut my_set = HashSet::new();
/// my_set.insert(String::from("Hello"));
/// println!("{:#?}", &my_set as &dyn Reflect);
///
/// // Output:
///
/// // {
/// // "Hello",
/// // }
/// ```
#[inline]
pub fn set_debug(dyn_set: &dyn Set, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_set();
for value in dyn_set.iter() {
debug.entry(&value as &dyn Debug);
}
debug.finish()
}
/// Applies the elements of reflected set `b` to the corresponding elements of set `a`.
///
/// If a value from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Panics
///
/// This function panics if `b` is not a reflected set.
#[inline]
pub fn set_apply<M: Set>(a: &mut M, b: &dyn PartialReflect) {
if let ReflectRef::Set(set_value) = b.reflect_ref() {
for b_value in set_value.iter() {
if a.get(b_value).is_none() {
a.insert_boxed(b_value.to_dynamic());
}
}
} else {
panic!("Attempted to apply a non-set type to a set type.");
}
}
/// Tries to apply the elements of reflected set `b` to the corresponding elements of set `a`
/// and returns a Result.
///
/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected set or if
/// applying elements to each other fails.
#[inline]
pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let set_value = b.reflect_ref().as_set()?;
for b_value in set_value.iter() {
if a.get(b_value).is_none() {
a.insert_boxed(b_value.to_dynamic());
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::DynamicSet;
use alloc::string::{String, ToString};
#[test]
fn test_into_iter() {
let expected = ["foo", "bar", "baz"];
let mut set = DynamicSet::default();
set.insert(expected[0].to_string());
set.insert(expected[1].to_string());
set.insert(expected[2].to_string());
for item in set.into_iter() {
let value = item
.try_take::<String>()
.expect("couldn't downcast to String");
let index = expected
.iter()
.position(|i| *i == value.as_str())
.expect("Element found in expected array");
assert_eq!(expected[index], value);
}
}
}

24
vendor/bevy_reflect/src/std_traits.rs vendored Normal file
View File

@@ -0,0 +1,24 @@
use crate::{FromType, Reflect};
use alloc::boxed::Box;
/// A struct used to provide the default value of a type.
///
/// A [`ReflectDefault`] for type `T` can be obtained via [`FromType::from_type`].
#[derive(Clone)]
pub struct ReflectDefault {
default: fn() -> Box<dyn Reflect>,
}
impl ReflectDefault {
pub fn default(&self) -> Box<dyn Reflect> {
(self.default)()
}
}
impl<T: Reflect + Default> FromType<T> for ReflectDefault {
fn from_type() -> Self {
ReflectDefault {
default: || Box::<T>::default(),
}
}
}

604
vendor/bevy_reflect/src/struct_trait.rs vendored Normal file
View File

@@ -0,0 +1,604 @@
use crate::generics::impl_generic_info_methods;
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
type_info::impl_type_methods,
ApplyError, Generics, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
};
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
use bevy_platform::collections::HashMap;
use bevy_platform::sync::Arc;
use bevy_reflect_derive::impl_type_path;
use core::{
fmt::{Debug, Formatter},
slice::Iter,
};
/// A trait used to power [struct-like] operations via [reflection].
///
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
/// be dynamically addressed by both name and index.
///
/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a standard struct,
/// this trait will be automatically implemented.
/// This goes for [unit structs] as well.
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Reflect, Struct};
///
/// #[derive(Reflect)]
/// struct Foo {
/// bar: u32,
/// }
///
/// let foo = Foo { bar: 123 };
///
/// assert_eq!(foo.field_len(), 1);
/// assert_eq!(foo.name_at(0), Some("bar"));
///
/// let field: &dyn PartialReflect = foo.field("bar").unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html
/// [reflection]: crate
/// [unit structs]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
pub trait Struct: PartialReflect {
/// Returns a reference to the value of the field named `name` as a `&dyn
/// PartialReflect`.
fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field named `name` as a
/// `&mut dyn PartialReflect`.
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn PartialReflect`.
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn PartialReflect`.
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the name of the field with index `index`.
fn name_at(&self, index: usize) -> Option<&str>;
/// Returns the number of fields in the struct.
fn field_len(&self) -> usize;
/// Returns an iterator over the values of the reflectable fields for this struct.
fn iter_fields(&self) -> FieldIter;
/// Clones the struct into a [`DynamicStruct`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_struct` instead")]
fn clone_dynamic(&self) -> DynamicStruct {
self.to_dynamic_struct()
}
fn to_dynamic_struct(&self) -> DynamicStruct {
let mut dynamic_struct = DynamicStruct::default();
dynamic_struct.set_represented_type(self.get_represented_type_info());
for (i, value) in self.iter_fields().enumerate() {
dynamic_struct.insert_boxed(self.name_at(i).unwrap(), value.to_dynamic());
}
dynamic_struct
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_struct_info(&self) -> Option<&'static StructInfo> {
self.get_represented_type_info()?.as_struct().ok()
}
}
/// A container for compile-time named struct info.
#[derive(Clone, Debug)]
pub struct StructInfo {
ty: Type,
generics: Generics,
fields: Box<[NamedField]>,
field_names: Box<[&'static str]>,
field_indices: HashMap<&'static str, usize>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl StructInfo {
/// Create a new [`StructInfo`].
///
/// # Arguments
///
/// * `fields`: The fields of this struct in the order they are defined
pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
let field_indices = fields
.iter()
.enumerate()
.map(|(index, field)| (field.name(), index))
.collect::<HashMap<_, _>>();
let field_names = fields.iter().map(NamedField::name).collect();
Self {
ty: Type::of::<T>(),
generics: Generics::new(),
fields: fields.to_vec().into_boxed_slice(),
field_names,
field_indices,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this struct.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this struct.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// A slice containing the names of all fields in order.
pub fn field_names(&self) -> &[&'static str] {
&self.field_names
}
/// Get the field with the given name.
pub fn field(&self, name: &str) -> Option<&NamedField> {
self.field_indices
.get(name)
.map(|index| &self.fields[*index])
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&NamedField> {
self.fields.get(index)
}
/// Get the index of the field with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.field_indices.get(name).copied()
}
/// Iterate over the fields of this struct.
pub fn iter(&self) -> Iter<'_, NamedField> {
self.fields.iter()
}
/// The total number of fields in this struct.
pub fn field_len(&self) -> usize {
self.fields.len()
}
impl_type_methods!(ty);
/// The docstring of this struct, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "struct");
impl_generic_info_methods!(generics);
}
/// An iterator over the field values of a struct.
pub struct FieldIter<'a> {
pub(crate) struct_val: &'a dyn Struct,
pub(crate) index: usize,
}
impl<'a> FieldIter<'a> {
pub fn new(value: &'a dyn Struct) -> Self {
FieldIter {
struct_val: value,
index: 0,
}
}
}
impl<'a> Iterator for FieldIter<'a> {
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.struct_val.field_at(self.index);
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.struct_val.field_len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for FieldIter<'a> {}
/// A convenience trait which combines fetching and downcasting of struct
/// fields.
///
/// # Example
///
/// ```
/// use bevy_reflect::{GetField, Reflect};
///
/// #[derive(Reflect)]
/// struct Foo {
/// bar: String,
/// }
///
/// # fn main() {
/// let mut foo = Foo { bar: "Hello, world!".to_string() };
///
/// foo.get_field_mut::<String>("bar").unwrap().truncate(5);
/// assert_eq!(foo.get_field::<String>("bar"), Some(&"Hello".to_string()));
/// # }
/// ```
pub trait GetField {
/// Returns a reference to the value of the field named `name`, downcast to
/// `T`.
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
/// Returns a mutable reference to the value of the field named `name`,
/// downcast to `T`.
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
}
impl<S: Struct> GetField for S {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetField for dyn Struct {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
/// A struct type which allows fields to be added at runtime.
#[derive(Default)]
pub struct DynamicStruct {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn PartialReflect>>,
field_names: Vec<Cow<'static, str>>,
field_indices: HashMap<Cow<'static, str>, usize>,
}
impl DynamicStruct {
/// Sets the [type] to be represented by this `DynamicStruct`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Struct`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Struct(_)),
"expected TypeInfo::Struct but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Inserts a field named `name` with value `value` into the struct.
///
/// If the field already exists, it is overwritten.
pub fn insert_boxed<'a>(
&mut self,
name: impl Into<Cow<'a, str>>,
value: Box<dyn PartialReflect>,
) {
let name: Cow<str> = name.into();
if let Some(index) = self.field_indices.get(&name) {
self.fields[*index] = value;
} else {
self.fields.push(value);
self.field_indices
.insert(Cow::Owned(name.clone().into_owned()), self.fields.len() - 1);
self.field_names.push(Cow::Owned(name.into_owned()));
}
}
/// Inserts a field named `name` with the typed value `value` into the struct.
///
/// If the field already exists, it is overwritten.
pub fn insert<'a, T: PartialReflect>(&mut self, name: impl Into<Cow<'a, str>>, value: T) {
self.insert_boxed(name, Box::new(value));
}
/// Gets the index of the field with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.field_indices.get(name).copied()
}
}
impl Struct for DynamicStruct {
#[inline]
fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
self.field_indices
.get(name)
.map(|index| &*self.fields[*index])
}
#[inline]
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
if let Some(index) = self.field_indices.get(name) {
Some(&mut *self.fields[*index])
} else {
None
}
}
#[inline]
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|value| &**value)
}
#[inline]
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|value| &mut **value)
}
#[inline]
fn name_at(&self, index: usize) -> Option<&str> {
self.field_names.get(index).map(AsRef::as_ref)
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> FieldIter {
FieldIter {
struct_val: self,
index: 0,
}
}
}
impl PartialReflect for DynamicStruct {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
let struct_value = value.reflect_ref().as_struct()?;
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
if let Some(v) = self.field_mut(name) {
v.try_apply(value)?;
}
}
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Struct(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
struct_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicStruct(")?;
struct_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicStruct);
impl Debug for DynamicStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl<'a, N> FromIterator<(N, Box<dyn PartialReflect>)> for DynamicStruct
where
N: Into<Cow<'a, str>>,
{
/// Create a dynamic struct that doesn't represent a type from the
/// field name, field value pairs.
fn from_iter<I: IntoIterator<Item = (N, Box<dyn PartialReflect>)>>(fields: I) -> Self {
let mut dynamic_struct = Self::default();
for (name, value) in fields.into_iter() {
dynamic_struct.insert_boxed(name, value);
}
dynamic_struct
}
}
impl IntoIterator for DynamicStruct {
type Item = Box<dyn PartialReflect>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicStruct {
type Item = &'a dyn PartialReflect;
type IntoIter = FieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Compares a [`Struct`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a struct;
/// - For each field in `a`, `b` contains a field with the same name and
/// [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn struct_partial_eq<S: Struct + ?Sized>(a: &S, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
return Some(false);
};
if a.field_len() != struct_value.field_len() {
return Some(false);
}
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
if let Some(field_value) = a.field(name) {
let eq_result = field_value.reflect_partial_eq(value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
}
}
Some(true)
}
/// The default debug formatter for [`Struct`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
/// #[derive(Reflect)]
/// struct MyStruct {
/// foo: usize
/// }
///
/// let my_struct: &dyn Reflect = &MyStruct { foo: 123 };
/// println!("{:#?}", my_struct);
///
/// // Output:
///
/// // MyStruct {
/// // foo: 123,
/// // }
/// ```
#[inline]
pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_struct(
dyn_struct
.get_represented_type_info()
.map(TypeInfo::type_path)
.unwrap_or("_"),
);
for field_index in 0..dyn_struct.field_len() {
let field = dyn_struct.field_at(field_index).unwrap();
debug.field(
dyn_struct.name_at(field_index).unwrap(),
&field as &dyn Debug,
);
}
debug.finish()
}
#[cfg(test)]
mod tests {
use crate::*;
#[derive(Reflect, Default)]
struct MyStruct {
a: (),
b: (),
c: (),
}
#[test]
fn next_index_increment() {
let my_struct = MyStruct::default();
let mut iter = my_struct.iter_fields();
iter.index = iter.len() - 1;
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
// When None we should no longer increase index
let prev_index = iter.index;
assert!(iter.next().is_none());
assert_eq!(prev_index, iter.index);
assert!(iter.next().is_none());
assert_eq!(prev_index, iter.index);
}
}

804
vendor/bevy_reflect/src/tuple.rs vendored Normal file
View File

@@ -0,0 +1,804 @@
use bevy_reflect_derive::impl_type_path;
use variadics_please::all_tuples;
use crate::generics::impl_generic_info_methods;
use crate::{
type_info::impl_type_methods, utility::GenericTypePathCell, ApplyError, FromReflect, Generics,
GetTypeRegistration, MaybeTyped, PartialReflect, Reflect, ReflectCloneError, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath, TypeRegistration, TypeRegistry,
Typed, UnnamedField,
};
use alloc::{boxed::Box, vec, vec::Vec};
use core::{
any::Any,
fmt::{Debug, Formatter},
slice::Iter,
};
/// A trait used to power [tuple-like] operations via [reflection].
///
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
/// be dynamically addressed by index.
///
/// This trait is automatically implemented for arbitrary tuples of up to 12
/// elements, provided that each element implements [`Reflect`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Tuple};
///
/// let foo = (123_u32, true);
/// assert_eq!(foo.field_len(), 2);
///
/// let field: &dyn PartialReflect = foo.field(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [tuple-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
/// [reflection]: crate
pub trait Tuple: PartialReflect {
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn Reflect`.
fn field(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn Reflect`.
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of fields in the tuple.
fn field_len(&self) -> usize;
/// Returns an iterator over the values of the tuple's fields.
fn iter_fields(&self) -> TupleFieldIter;
/// Drain the fields of this tuple to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the tuple into a [`DynamicTuple`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_tuple` instead")]
fn clone_dynamic(&self) -> DynamicTuple {
self.to_dynamic_tuple()
}
/// Creates a new [`DynamicTuple`] from this tuple.
fn to_dynamic_tuple(&self) -> DynamicTuple {
DynamicTuple {
represented_type: self.get_represented_type_info(),
fields: self.iter_fields().map(PartialReflect::to_dynamic).collect(),
}
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_tuple_info(&self) -> Option<&'static TupleInfo> {
self.get_represented_type_info()?.as_tuple().ok()
}
}
/// An iterator over the field values of a tuple.
pub struct TupleFieldIter<'a> {
pub(crate) tuple: &'a dyn Tuple,
pub(crate) index: usize,
}
impl<'a> TupleFieldIter<'a> {
pub fn new(value: &'a dyn Tuple) -> Self {
TupleFieldIter {
tuple: value,
index: 0,
}
}
}
impl<'a> Iterator for TupleFieldIter<'a> {
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple.field(self.index);
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.tuple.field_len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for TupleFieldIter<'a> {}
/// A convenience trait which combines fetching and downcasting of tuple
/// fields.
///
/// # Example
///
/// ```
/// use bevy_reflect::GetTupleField;
///
/// # fn main() {
/// let foo = ("blue".to_string(), 42_i32);
///
/// assert_eq!(foo.get_field::<String>(0), Some(&"blue".to_string()));
/// assert_eq!(foo.get_field::<i32>(1), Some(&42));
/// # }
/// ```
pub trait GetTupleField {
/// Returns a reference to the value of the field with index `index`,
/// downcast to `T`.
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
/// Returns a mutable reference to the value of the field with index
/// `index`, downcast to `T`.
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
}
impl<S: Tuple> GetTupleField for S {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetTupleField for dyn Tuple {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
/// A container for compile-time tuple info.
#[derive(Clone, Debug)]
pub struct TupleInfo {
ty: Type,
generics: Generics,
fields: Box<[UnnamedField]>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl TupleInfo {
/// Create a new [`TupleInfo`].
///
/// # Arguments
///
/// * `fields`: The fields of this tuple in the order they are defined
pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
Self {
ty: Type::of::<T>(),
generics: Generics::new(),
fields: fields.to_vec().into_boxed_slice(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this tuple.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&UnnamedField> {
self.fields.get(index)
}
/// Iterate over the fields of this tuple.
pub fn iter(&self) -> Iter<'_, UnnamedField> {
self.fields.iter()
}
/// The total number of fields in this tuple.
pub fn field_len(&self) -> usize {
self.fields.len()
}
impl_type_methods!(ty);
/// The docstring of this tuple, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// A tuple which allows fields to be added at runtime.
#[derive(Default, Debug)]
pub struct DynamicTuple {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn PartialReflect>>,
}
impl DynamicTuple {
/// Sets the [type] to be represented by this `DynamicTuple`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Tuple`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Tuple(_)),
"expected TypeInfo::Tuple but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Appends an element with value `value` to the tuple.
pub fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) {
self.represented_type = None;
self.fields.push(value);
}
/// Appends a typed element with value `value` to the tuple.
pub fn insert<T: PartialReflect>(&mut self, value: T) {
self.represented_type = None;
self.insert_boxed(Box::new(value));
}
}
impl Tuple for DynamicTuple {
#[inline]
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|field| &**field)
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|field| &mut **field)
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> TupleFieldIter {
TupleFieldIter {
tuple: self,
index: 0,
}
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.fields
}
}
impl PartialReflect for DynamicTuple {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
tuple_apply(self, value);
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Tuple
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Tuple(self)
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
tuple_try_apply(self, value)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
tuple_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicTuple(")?;
tuple_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicTuple);
impl FromIterator<Box<dyn PartialReflect>> for DynamicTuple {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(fields: I) -> Self {
Self {
represented_type: None,
fields: fields.into_iter().collect(),
}
}
}
impl IntoIterator for DynamicTuple {
type Item = Box<dyn PartialReflect>;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicTuple {
type Item = &'a dyn PartialReflect;
type IntoIter = TupleFieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Applies the elements of `b` to the corresponding elements of `a`.
///
/// # Panics
///
/// This function panics if `b` is not a tuple.
#[inline]
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) {
if let Err(err) = tuple_try_apply(a, b) {
panic!("{err}");
}
}
/// Tries to apply the elements of `b` to the corresponding elements of `a` and
/// returns a Result.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a tuple or if
/// applying elements to each other fails.
#[inline]
pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let tuple = b.reflect_ref().as_tuple()?;
for (i, value) in tuple.iter_fields().enumerate() {
if let Some(v) = a.field_mut(i) {
v.try_apply(value)?;
}
}
Ok(())
}
/// Compares a [`Tuple`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a tuple;
/// - `b` has the same number of elements as `a`;
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn tuple_partial_eq<T: Tuple + ?Sized>(a: &T, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Tuple(b) = b.reflect_ref() else {
return Some(false);
};
if a.field_len() != b.field_len() {
return Some(false);
}
for (a_field, b_field) in a.iter_fields().zip(b.iter_fields()) {
let eq_result = a_field.reflect_partial_eq(b_field);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}
Some(true)
}
/// The default debug formatter for [`Tuple`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
///
/// let my_tuple: &dyn Reflect = &(1, 2, 3);
/// println!("{:#?}", my_tuple);
///
/// // Output:
///
/// // (
/// // 1,
/// // 2,
/// // 3,
/// // )
/// ```
#[inline]
pub fn tuple_debug(dyn_tuple: &dyn Tuple, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_tuple("");
for field in dyn_tuple.iter_fields() {
debug.field(&field as &dyn Debug);
}
debug.finish()
}
macro_rules! impl_reflect_tuple {
{$($index:tt : $name:tt),*} => {
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Tuple for ($($name,)*) {
#[inline]
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
match index {
$($index => Some(&self.$index as &dyn PartialReflect),)*
_ => None,
}
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
match index {
$($index => Some(&mut self.$index as &mut dyn PartialReflect),)*
_ => None,
}
}
#[inline]
fn field_len(&self) -> usize {
let indices: &[usize] = &[$($index as usize),*];
indices.len()
}
#[inline]
fn iter_fields(&self) -> TupleFieldIter {
TupleFieldIter {
tuple: self,
index: 0,
}
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
vec![
$(Box::new(self.$index),)*
]
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> PartialReflect for ($($name,)*) {
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
Some(<Self as Typed>::type_info())
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Ok(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
Some(self)
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
Some(self)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Tuple
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Tuple(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
crate::tuple_partial_eq(self, value)
}
fn apply(&mut self, value: &dyn PartialReflect) {
crate::tuple_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
crate::tuple_try_apply(self, value)
}
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new((
$(
self.$index.reflect_clone()?
.take::<$name>()
.expect("`Reflect::reflect_clone` should return the same type"),
)*
)))
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Reflect for ($($name,)*) {
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
}
fn as_reflect(&self) -> &dyn Reflect {
self
}
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
}
impl <$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Typed for ($($name,)*) {
fn type_info() -> &'static TypeInfo {
static CELL: $crate::utility::GenericTypeInfoCell = $crate::utility::GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| {
let fields = [
$(UnnamedField::new::<$name>($index),)*
];
let info = TupleInfo::new::<Self>(&fields);
TypeInfo::Tuple(info)
})
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> GetTypeRegistration for ($($name,)*) {
fn get_type_registration() -> TypeRegistration {
TypeRegistration::of::<($($name,)*)>()
}
fn register_type_dependencies(_registry: &mut TypeRegistry) {
$(_registry.register::<$name>();)*
}
}
impl<$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*> FromReflect for ($($name,)*)
{
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
let _ref_tuple = reflect.reflect_ref().as_tuple().ok()?;
Some(
(
$(
<$name as FromReflect>::from_reflect(_ref_tuple.field($index)?)?,
)*
)
)
}
}
}
}
impl_reflect_tuple! {}
impl_reflect_tuple! {0: A}
impl_reflect_tuple! {0: A, 1: B}
impl_reflect_tuple! {0: A, 1: B, 2: C}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L}
macro_rules! impl_type_path_tuple {
($(#[$meta:meta])*) => {
$(#[$meta])*
impl TypePath for () {
fn type_path() -> &'static str {
"()"
}
fn short_type_path() -> &'static str {
"()"
}
}
};
($(#[$meta:meta])* $param:ident) => {
$(#[$meta])*
impl <$param: TypePath> TypePath for ($param,) {
fn type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() + $param::type_path() + ",)"
})
}
fn short_type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() + $param::short_type_path() + ",)"
})
}
}
};
($(#[$meta:meta])* $last:ident $(,$param:ident)*) => {
$(#[$meta])*
impl <$($param: TypePath,)* $last: TypePath> TypePath for ($($param,)* $last) {
fn type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() $(+ $param::type_path() + ", ")* + $last::type_path() + ")"
})
}
fn short_type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() $(+ $param::short_type_path() + ", ")* + $last::short_type_path() + ")"
})
}
}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_type_path_tuple,
0,
12,
P
);
#[cfg(feature = "functions")]
const _: () = {
macro_rules! impl_get_ownership_tuple {
($(#[$meta:meta])* $($name: ident),*) => {
$(#[$meta])*
$crate::func::args::impl_get_ownership!(($($name,)*); <$($name),*>);
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_get_ownership_tuple,
0,
12,
P
);
macro_rules! impl_from_arg_tuple {
($(#[$meta:meta])* $($name: ident),*) => {
$(#[$meta])*
$crate::func::args::impl_from_arg!(($($name,)*); <$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*>);
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_from_arg_tuple,
0,
12,
P
);
macro_rules! impl_into_return_tuple {
($(#[$meta:meta])* $($name: ident),+) => {
$(#[$meta])*
$crate::func::impl_into_return!(($($name,)*); <$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*>);
};
}
// The unit type (i.e. `()`) is special-cased, so we skip implementing it here.
all_tuples!(
#[doc(fake_variadic)]
impl_into_return_tuple,
1,
12,
P
);
};
#[cfg(test)]
mod tests {
use super::Tuple;
#[test]
fn next_index_increment() {
let mut iter = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).iter_fields();
let size = iter.len();
iter.index = size - 1;
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
// When None we should no longer increase index
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
}

Some files were not shown because too many files have changed in this diff Show More