summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ron
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/ron
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/ron')
-rw-r--r--third_party/rust/ron/.cargo-checksum.json1
-rw-r--r--third_party/rust/ron/CHANGELOG.md225
-rw-r--r--third_party/rust/ron/Cargo.lock158
-rw-r--r--third_party/rust/ron/Cargo.toml69
-rw-r--r--third_party/rust/ron/LICENSE-APACHE201
-rw-r--r--third_party/rust/ron/LICENSE-MIT25
-rw-r--r--third_party/rust/ron/README.md182
-rw-r--r--third_party/rust/ron/clippy.toml2
-rw-r--r--third_party/rust/ron/docs/extensions.md116
-rw-r--r--third_party/rust/ron/docs/grammar.md152
-rw-r--r--third_party/rust/ron/examples/decode.rs68
-rw-r--r--third_party/rust/ron/examples/decode_file.rs37
-rw-r--r--third_party/rust/ron/examples/encode.rs50
-rw-r--r--third_party/rust/ron/examples/example.ron22
-rw-r--r--third_party/rust/ron/examples/transcode.rs31
-rw-r--r--third_party/rust/ron/rustfmt.toml4
-rw-r--r--third_party/rust/ron/src/de/id.rs246
-rw-r--r--third_party/rust/ron/src/de/mod.rs869
-rw-r--r--third_party/rust/ron/src/de/tag.rs251
-rw-r--r--third_party/rust/ron/src/de/tests.rs363
-rw-r--r--third_party/rust/ron/src/de/value.rs338
-rw-r--r--third_party/rust/ron/src/error.rs445
-rw-r--r--third_party/rust/ron/src/extensions.rs55
-rw-r--r--third_party/rust/ron/src/lib.rs20
-rw-r--r--third_party/rust/ron/src/options.rs215
-rw-r--r--third_party/rust/ron/src/parse.rs1008
-rw-r--r--third_party/rust/ron/src/ser/mod.rs1041
-rw-r--r--third_party/rust/ron/src/ser/tests.rs147
-rw-r--r--third_party/rust/ron/src/ser/value.rs23
-rw-r--r--third_party/rust/ron/src/value.rs619
-rw-r--r--third_party/rust/ron/tests/117_untagged_tuple_variant.rs59
-rw-r--r--third_party/rust/ron/tests/123_enum_representation.rs274
-rw-r--r--third_party/rust/ron/tests/129_indexmap.rs76
-rw-r--r--third_party/rust/ron/tests/147_empty_sets_serialisation.rs63
-rw-r--r--third_party/rust/ron/tests/152_bitflags.rs57
-rw-r--r--third_party/rust/ron/tests/203_error_positions.rs105
-rw-r--r--third_party/rust/ron/tests/207_adjacently_tagged_enum.rs22
-rw-r--r--third_party/rust/ron/tests/238_array.rs51
-rw-r--r--third_party/rust/ron/tests/240_array_pretty.rs52
-rw-r--r--third_party/rust/ron/tests/250_variant_newtypes.rs410
-rw-r--r--third_party/rust/ron/tests/256_comma_error.rs72
-rw-r--r--third_party/rust/ron/tests/289_enumerate_arrays.rs47
-rw-r--r--third_party/rust/ron/tests/301_struct_name_mismatch.rs130
-rw-r--r--third_party/rust/ron/tests/307_stack_overflow.rsbin0 -> 7646 bytes
-rw-r--r--third_party/rust/ron/tests/322_escape_idents.rs34
-rw-r--r--third_party/rust/ron/tests/337_value_float_roundtrip.rs29
-rw-r--r--third_party/rust/ron/tests/359_deserialize_seed.rs57
-rw-r--r--third_party/rust/ron/tests/367_implicit_some.rs108
-rw-r--r--third_party/rust/ron/tests/370_float_parsing.rs66
-rw-r--r--third_party/rust/ron/tests/393_serde_errors.rs215
-rw-r--r--third_party/rust/ron/tests/401_raw_identifier.rs177
-rw-r--r--third_party/rust/ron/tests/410_trailing_comma.rs95
-rw-r--r--third_party/rust/ron/tests/423_de_borrowed_identifier.rs45
-rw-r--r--third_party/rust/ron/tests/462_bytes.rs22
-rw-r--r--third_party/rust/ron/tests/big_struct.rs79
-rw-r--r--third_party/rust/ron/tests/borrowed_str.rs16
-rw-r--r--third_party/rust/ron/tests/comments.rs52
-rw-r--r--third_party/rust/ron/tests/depth_limit.rs60
-rw-r--r--third_party/rust/ron/tests/escape.rs78
-rw-r--r--third_party/rust/ron/tests/extensions.rs92
-rw-r--r--third_party/rust/ron/tests/floats.rs23
-rw-r--r--third_party/rust/ron/tests/large_number.rs28
-rw-r--r--third_party/rust/ron/tests/min_max.rs69
-rw-r--r--third_party/rust/ron/tests/non_identifier_identifier.rs94
-rw-r--r--third_party/rust/ron/tests/numbers.rs113
-rw-r--r--third_party/rust/ron/tests/options.rs52
-rw-r--r--third_party/rust/ron/tests/preserve_sequence.rs48
-rw-r--r--third_party/rust/ron/tests/preserve_sequence_ex1.ron20
-rw-r--r--third_party/rust/ron/tests/preserve_sequence_ex2.ron15
-rw-r--r--third_party/rust/ron/tests/roundtrip.rs121
-rw-r--r--third_party/rust/ron/tests/struct_integers.rs39
-rw-r--r--third_party/rust/ron/tests/to_string_pretty.rs23
-rw-r--r--third_party/rust/ron/tests/unicode.rs13
-rw-r--r--third_party/rust/ron/tests/value.rs163
74 files changed, 10447 insertions, 0 deletions
diff --git a/third_party/rust/ron/.cargo-checksum.json b/third_party/rust/ron/.cargo-checksum.json
new file mode 100644
index 0000000000..5004a77fbd
--- /dev/null
+++ b/third_party/rust/ron/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"bdd87c85a3688ec08650dbd953df54fe0b2e8caa9df134e6f0d27e85a36735ca","Cargo.lock":"8509283147e687d6a4395ba465e763ce99c958ccb1e91289dc71f13db9c56ada","Cargo.toml":"ba9098bc92f15da67dcdc3264663a741ff78cef33824346350ad31ea13be0c62","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"fa0598d520497731445a5bc89a2b3d47896d95568bd2be255b7bc43d771b9994","README.md":"eb0da6ac295ea48163cc58683ca18caa554303c730aef4ef0ea259dfc04f3f14","clippy.toml":"53dcbaa544dd4d34fefe8aef4d287720223385c47f7b27cc1d6983c72843a9ca","docs/extensions.md":"47cb367dbef73952065fe1c0b1186603b108dc70b5d8abbf3eff3b75c1024912","docs/grammar.md":"18b0c90828b4d7089f7adced614ab4910935a1f927446367a23a9f2ee31dd54c","examples/decode.rs":"b8e2db901f0a25070daa0294794da7c95f9a7d61934e9b5b1cbcb131ca70a7d7","examples/decode_file.rs":"113bec048bae541618fdacd22b55052852cdf6f1a93b1f32e02a59d53a718e8b","examples/encode.rs":"cfded2357414e2ea68580bf8f2333a62c1ae9d9fa70775c56a23dfe158e297be","examples/example.ron":"aebd2baff31a62c3aed1ba568b7a7c1165b197d526a1e2c9eb7adb211de8292e","examples/transcode.rs":"7a1e281684243b263d28f90f2836d6098239ae8ab2a0cb9d97ee0b7521ba960e","rustfmt.toml":"10f292ebd4c21ef67c36b6edb79eed7fada8f021c527948dfbeb3a54a5591e59","src/de/id.rs":"6bf18960a4cc99e7d2408a94d5d47e78105b3912290a33c799291b7b2ff994d1","src/de/mod.rs":"45d44b02f7440648b2e3169d3023ad68cd02b6192c3c8524c04aebf4b0677f2d","src/de/tag.rs":"527c3ea01886612c17440608daa11a3e1b3aa3b11b8c3f06f68d6ba1fc70ba27","src/de/tests.rs":"41b62078e6837db673454a709e438901c5b52f8baa77e6b16881a1bfc1247791","src/de/value.rs":"f86a4eba21b31f4f700acd035009d4c426d04969f4762391112100471c4eaabb","src/error.rs":"a63d644181f088275332b147a0a4c3d5d1cf03602a7e8a58250ce5ddcb0ef159","src/extensions.rs":"58ae01101553d1a0758bcdc652bfd5c2f5123f2807e18270c6f35a4e95d1f44c","src/lib.rs":"63af8224ca12b95eaa548266243eb6b3de456b02a166071ea2b7ade2695ad9f7","src/options.rs":"cc05dc580794a8766824e7e034ee98e796590ea605f4575a529f5ef5c757f8ee","src/parse.rs":"497f44abb50535d72b6adfb8ba4e6bbde9665c08aaebb49ff88af1e2d2165c5d","src/ser/mod.rs":"582969f19cf8f53ec48143d3c3cd8eacae4733703e28434009df5b0ba971bd66","src/ser/tests.rs":"3dca7c683c3ede146bf17138f6445c38ee6f37c5a8afe08d76bb2921688f3981","src/ser/value.rs":"0c099c6c3c73062048c989dc8f70c3e67cfd3989a286da79a45323830c4a277b","src/value.rs":"14a6d9a69676d6fdda8216336ec35af3f0a0b2d4bbdd1725e07d172fa4d6b780","tests/117_untagged_tuple_variant.rs":"1ce8d384d84ff21a28dafef0f0ea4be9e6cbf9bd7c2ed4aa37e8d820c7b594b8","tests/123_enum_representation.rs":"776c666a4d388504bde9f2e27838d6cb389fcb6d705dfa077a1de7cdea1f26d6","tests/129_indexmap.rs":"a55ed888407dce347035893afa6a5e60d3e2f92672287c93cf5e21bb19218a40","tests/147_empty_sets_serialisation.rs":"1782934f9b19d56460d3e94c78698c1220d38bca801d46dd8474bb76bc00a21c","tests/152_bitflags.rs":"7e2cd4a62799f4b435924ed0909d391c3a680893bbeb84ca46fc5232ffd69886","tests/203_error_positions.rs":"9c5654a7dbde482040dc11521dd7db0f71dc42e5782d1df9908911c42ce4ff7e","tests/207_adjacently_tagged_enum.rs":"f2ebdf4268eeb6be95fd249c10930e4ea8f4fd4e3452d1ae8799334db2a3b96e","tests/238_array.rs":"30873e63e475b48df88dc8cc169569b6495ee24b27c37838ae27bf834b8d7ee7","tests/240_array_pretty.rs":"5187f3d50aa94db60d6fb42162921e9d94c7573c61767ded898a6ca50929f18b","tests/250_variant_newtypes.rs":"c3b4ffdd33163299f47d14f78137fc1496d7ad133717b85b3be195846a8c2fc2","tests/256_comma_error.rs":"c2e2d7b37d4810e0eb12af2c47dfd47fa64adf14a350a745c575ff02caaf6d41","tests/289_enumerate_arrays.rs":"0e1e9bd624b756714c6d79b79c388972c4b443c331d08098d585a85cba519bb5","tests/301_struct_name_mismatch.rs":"b980a004edadc4829479e96f897290de25c34c4efb364e5a7d8bd695fdfb78c0","tests/307_stack_overflow.rs":"b8affab09acdb6594242e7142e2fc9f6cd0f3bf36337129dc42b11f8d72060f5","tests/322_escape_idents.rs":"4f8912aeb24655a378049919ffc8b270519849abcb34ef9d7c34af5be1ec72f3","tests/337_value_float_roundtrip.rs":"d4fc07c7fd8c588ae46f8c1fd24caa29e044bf593c8a6754dc3353ddd44157ac","tests/359_deserialize_seed.rs":"be8d0ce834f68496cc90d05b2a0688c105c51883318e3eb362ce7c646d4dc5fe","tests/367_implicit_some.rs":"e222c356e8af4e5e3bd7b936daafa2519630d83dfddc784e07599fe3bfd92797","tests/370_float_parsing.rs":"23bd0e59e5fa5b51d1575d6fe620b04773c555428ec461849e04028f1d22be69","tests/393_serde_errors.rs":"0f9471ea1f5117df6916d0100f3cdb1073c7e9e0ba2da28caa7dfe7e1c63ab13","tests/401_raw_identifier.rs":"d073a92dd49b712fc6385aafa9a4b2f53bcc1d9ef88942fbc206232dc9bc6c2b","tests/410_trailing_comma.rs":"c8755b2805f26f0d9b748f4277a8d8eea85227af06788ae533cf7b96a8b9e724","tests/423_de_borrowed_identifier.rs":"b3adbdf97d7082d7fea2b2649bb6d50e3e7b320049671dad6d803c003a15586f","tests/462_bytes.rs":"7394a118a1bd1336301289b6d93a390fb5a46b2fbd13bccf68d4a6fab400b58b","tests/big_struct.rs":"9c7b41233ae7d0c4fec0727aabd4cea1cd95844c85c0beb5e688b3c79eb43c14","tests/borrowed_str.rs":"24390ee6076ce3896b7cf1b2e202cb3a705c61129a4f62f6c39a2412ca68405f","tests/comments.rs":"d88ba142978b5536f6891d839c89c420196f8927fd059eb25c087b555f235109","tests/depth_limit.rs":"775f872038c127abeb2e4474df67ad483f82d23fdb535060da14e498d05119f8","tests/escape.rs":"b43702a042b7078e9007fd4c90bb9b2d770565178946e95438e92981ea2ffc2d","tests/extensions.rs":"4058b5da64c3f9591026790e044d19cf30c744a30cd3e9af79acd70f76ec0d40","tests/floats.rs":"367a22cca7d3a3ce6bdffc30df8712aae348ad29a1adbe9a47bc98e0a51b614d","tests/large_number.rs":"415ad0374b22553b0cf7926b6d7a64505f8b6021d46b6a93587024449f60b353","tests/min_max.rs":"4529513a4cf1e5c25f7697ba258fdbae258617cf8f3374080843aef048c2bde3","tests/non_identifier_identifier.rs":"ba759adf7e0e93a9989b3e08155d424868f6b060ff8d2d7ef8fdd45433497990","tests/numbers.rs":"d28656afd5123df5cec3b8fe01cda8f14b6b3065900b7adbf352776a164dd29b","tests/options.rs":"8ff7bbc62503a5f6675a89a10059ec48c437da1c57000f5310e0d4b09fb3d5e2","tests/preserve_sequence.rs":"ade33555951c08eceaf38ff62b0d043f7e6a426496527dc4b94ceadf2a99344b","tests/preserve_sequence_ex1.ron":"47bdf8da637b6e99701b5a4b8c100b4c9d45440c357aef8d368a406a05394ea9","tests/preserve_sequence_ex2.ron":"9ba759300324f8978469ce616f20eb0cfc134f0a8a1afff884fff5315b32e0d0","tests/roundtrip.rs":"4af0accc1129850537f2e04fcf9c9c1d4ecf25fdd05e79179de8fb7f8596a910","tests/struct_integers.rs":"10f06e4d0845c8319236122047e6bda2765082fdf93b8d9c3770c29fb941086d","tests/to_string_pretty.rs":"96b3aaba638f90b66a16693714139ef57ecd8daefd8f87b771ae2bf37b15e985","tests/unicode.rs":"ac3944bf448f8cd5986bad5e7c4eca60302230c13378b213415dafc1d3ae2428","tests/value.rs":"71b12b8ff43b5e27efeba30e9d303156410d38a1f59d8bf680e450d5c379fdf3"},"package":"b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"} \ No newline at end of file
diff --git a/third_party/rust/ron/CHANGELOG.md b/third_party/rust/ron/CHANGELOG.md
new file mode 100644
index 0000000000..fd9ec5977d
--- /dev/null
+++ b/third_party/rust/ron/CHANGELOG.md
@@ -0,0 +1,225 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## Unreleased
+
+## [0.8.1] - 2023-08-17
+- Fix issues [#277](https://github.com/ron-rs/ron/issues/277) and [#405](https://github.com/ron-rs/ron/issues/405) with `Value::Map` `IntoIter` and extraneous item check for `Value::Seq` ([#406](https://github.com/ron-rs/ron/pull/406))
+- Fix issue [#401](https://github.com/ron-rs/ron/issues/401) with correct raw struct name identifier parsing ([#402](https://github.com/ron-rs/ron/pull/402))
+- Fix issue [#410](https://github.com/ron-rs/ron/issues/410) trailing comma parsing in tuples and `Some` ([#412](https://github.com/ron-rs/ron/pull/412))
+- Error instead of panic when deserializing non-identifiers as field names ([#415](https://github.com/ron-rs/ron/pull/415))
+- [Non-API] Breaking: Fix issue [#307](https://github.com/ron-rs/ron/issues/307) stack overflow with explicit recursion limits in serialising and deserialising ([#420](https://github.com/ron-rs/ron/pull/420))
+- Fix issue [#423](https://github.com/ron-rs/ron/issues/423) deserialising an identifier into a borrowed str ([#424](https://github.com/ron-rs/ron/pull/424))
+- Bump MSRV to 1.57.0 and bump dependency: `base64` to 0.20 ([#431](https://github.com/ron-rs/ron/pull/431))
+- Bump dependency `base64` to 0.21 ([#433](https://github.com/ron-rs/ron/pull/433))
+- Depend on `serde_derive` directly to potentially enable more compilation parallelism ([#441](https://github.com/ron-rs/ron/pull/441))
+- [Non-API] Breaking: Bump `bitflags` dependency to 2.0, changes `serde` impls of `Extensions` ([#443](https://github.com/ron-rs/ron/pull/443))
+- Add `Map::retain` method ([#460](https://github.com/ron-rs/ron/pull/460))
+- Bump MSRV to 1.64.0 and bump dependency: `indexmap` to 2.0 ([#459](https://github.com/ron-rs/ron/pull/459))
+
+## [0.8.0] - 2022-08-17
+
+- Bump dependencies: `bitflags` to 1.3, `indexmap` to 1.9 ([#399](https://github.com/ron-rs/ron/pull/399))
+- Add `integer128` feature that guards `i128` and `u128` ([#304](https://github.com/ron-rs/ron/pull/304), [#351](https://github.com/ron-rs/ron/pull/351))
+- Fix issue [#265](https://github.com/ron-rs/ron/issues/265) with better missing comma error ([#353](https://github.com/ron-rs/ron/pull/353))
+- Fix issue [#301](https://github.com/ron-rs/ron/issues/301) with better error messages ([#354](https://github.com/ron-rs/ron/pull/354))
+- Fix issue [#337](https://github.com/ron-rs/ron/issues/337) by removing `decimal_floats` PrettyConfig option and unconditional decimals in floats ([#363](https://github.com/ron-rs/ron/pull/363))
+- Fix issue [#203](https://github.com/ron-rs/ron/issues/203) with full de error positioning ([#356](https://github.com/ron-rs/ron/pull/356))
+- Expand the `ron::Error` enum to distinguish `serde` errors like `NoSuchEnumVariant` and `MissingStructField` with error positioning ([#394](https://github.com/ron-rs/ron/pull/394))
+- Bump MSRV to 1.56.0 ([#396](https://github.com/ron-rs/ron/pull/396))
+
+## [0.7.1] - 2022-06-15
+
+- Add `struct_names` option to `PrettyConfig` ([#329](https://github.com/ron-rs/ron/pull/329))
+- Fix newtype variant unwrapping around enum, seq and map ([#331](https://github.com/ron-rs/ron/pull/331))
+- Implement `unwrap_newtypes` extension during serialization ([#333](https://github.com/ron-rs/ron/pull/333))
+- Implement `unwrap_variant_newtypes` extension during serialization ([#336](https://github.com/ron-rs/ron/pull/336))
+- Add `compact_arrays` ([#299](https://github.com/ron-rs/ron/pull/299)) and `separator` options to `PrettyConfig` ([#349](https://github.com/ron-rs/ron/pull/349))
+- Fix issue [#338](https://github.com/ron-rs/ron/issues/338) value map roundtrip ([#341](https://github.com/ron-rs/ron/pull/341))
+- Fix issue [#289](https://github.com/ron-rs/ron/issues/289) enumerate_arrays comments ([#344](https://github.com/ron-rs/ron/pull/344))
+- Report struct name in expected struct error ([#342](https://github.com/ron-rs/ron/pull/342))
+- Add `Options` builder to configure the RON serde roundtrip ([#343](https://github.com/ron-rs/ron/pull/343))
+- Fix issue [#367](https://github.com/ron-rs/ron/issues/367) with eager implicit some ([#368](https://github.com/ron-rs/ron/pull/368))
+- Fix issue [#359](https://github.com/ron-rs/ron/issues/359) with `DeserializeSeed` support ([#360](https://github.com/ron-rs/ron/pull/360))
+- Fix issue [#370](https://github.com/ron-rs/ron/issues/370) with `FromStr`-equivalent float EBNF and `Error::FloatUnderscore` ([#371](https://github.com/ron-rs/ron/pull/371))
+- Fix issue [#374](https://github.com/ron-rs/ron/issues/374) extraneous .0 for small floats ([#372](https://github.com/ron-rs/ron/pull/372))
+- Deprecate `Serializer::new` ([#382](https://github.com/ron-rs/ron/issues/382))
+
+## [0.7.0] - 2021-10-22
+
+- Add `unwrap_variant_newtypes` extension ([#319](https://github.com/ron-rs/ron/pull/319))
+- Change MSRV to 1.36
+
+## [0.6.6] - 2021-10-21
+
+- Fix serialization of raw identifiers ([#323](https://github.com/ron-rs/ron/pull/323))
+
+## [0.6.5] - 2021-09-09
+- support serde renames that start with a digit
+
+## [0.6.3] - 2020-12-18
+- bump `base64` dependency to 0.13
+
+## [0.6.2] - 2020-09-09
+
+- Added `decimal_floats` PrettyConfig option, which always includes decimals in floats (`1.0` vs `1`) ([#237](https://github.com/ron-rs/ron/pull/237))
+- Fixed EBNF grammar for raw strings ([#236](https://github.com/ron-rs/ron/pull/236), unsigned integers ([#248](https://github.com/ron-rs/ron/pull/248)), and nested comments ([#272](https://github.com/ron-rs/ron/pull/272))
+- Added `ser::to_writer_pretty` ([#269](https://github.com/ron-rs/ron/pull/269))
+- Sped up parsing using table predicates ([#276](https://github.com/ron-rs/ron/pull/276))
+
+## [0.6.1] - 2020-07-14
+
+### Fixes
+
+- Fix array formatting regression ([#260](https://github.com/ron-rs/ron/pull/260))
+
+## [0.6.0] - 2020-05-21
+
+### Additions
+- Implement integer support in Numbers ([#210](https://github.com/ron-rs/ron/pull/210))
+- Port `ser::Serializer` to `io::Write` ([#206](https://github.com/ron-rs/ron/pull/206))
+- Support i128 and u128 ([#219](https://github.com/ron-rs/ron/pull/219))
+- Allow pretty ser to work with implicit-some extension ([#182](https://github.com/ron-rs/ron/pull/182))
+- Make PrettyConfig future-proof ([#173](https://github.com/ron-rs/ron/pull/173))
+- Use indexmap to preserve order (optional) ([#172](https://github.com/ron-rs/ron/pull/172))
+- Add tests for different enum representations ([#166](https://github.com/ron-rs/ron/pull/166))
+- Implement inf, -inf and NaN handling ([#163](https://github.com/ron-rs/ron/pull/163))
+- Add VS code language tooling ([#160](https://github.com/ron-rs/ron/pull/160))
+- Be smarter about integer deserialization ([#157](https://github.com/ron-rs/ron/pull/157))
+
+### Fixes
+- Fix parsing of borrowed strings ([#228](https://github.com/ron-rs/ron/pull/228))
+- Fix depth limit test for off-by-one fix ([#225](https://github.com/ron-rs/ron/pull/225))
+- Remove deprecated uses of `Error::description` ([#208](https://github.com/ron-rs/ron/pull/208))
+- Preserve ordering of map sequences ([#197](https://github.com/ron-rs/ron/pull/197))
+- Remove unneeded Neg requirement for signed_integer ([#193](https://github.com/ron-rs/ron/pull/193))
+- Ensure "Untagged tuple-like enum variants not deserializing correctly……" is fixed ([#170](https://github.com/ron-rs/ron/pull/170))
+
+### Changes
+- Update `serde` requirement to 1.0.60 ([#226](https://github.com/ron-rs/ron/pull/226))
+- Replace Travis with GitHub actions ([#223](https://github.com/ron-rs/ron/pull/223))
+- Rename `format_doc_comments` to `format_code_in_doc_comment`
+- Update base64 requirement from 0.11 to 0.12 ([#204](https://github.com/ron-rs/ron/pull/204))
+- Update base64 requirement from 0.10 to 0.11 ([#195](https://github.com/ron-rs/ron/pull/195))
+- Update `serde_bytes` to 0.11 ([#164](https://github.com/ron-rs/ron/pull/164))
+
+## [0.5.1] - 2019-04-05
+### Fixes
+- Increase source compability from Rust `1.34.0` to `1.31.0` by not relying on `as _` imports ([#156](https://github.com/ron-rs/ron/pull/156))
+
+## [0.5.0] - 2019-03-31
+### Additions
+- Don't insert new lines in empty arrays or maps ([#150](https://github.com/ron-rs/ron/pull/150))
+### Changes
+- Transition to Rust 2018 ([#149](https://github.com/ron-rs/ron/pull/149))
+
+## [0.4.2] - 2019-03-01
+### Additions
+- Add integer check for deserializer ([#148](https://github.com/ron-rs/ron/pull/148))
+- Implement `Value::into_rust` ([#146](https://github.com/ron-rs/ron/pull/146))
+
+## [0.4.1] - 2019-01-09
+### Additions
+- Allow underscores in integers ([#135](https://github.com/ron-rs/ron/pull/135))
+- Added extension documentation ([#130](https://github.com/ron-rs/ron/pull/130))
+### Changes
+- Move sublime text syntax to separate repo ([#138](https://github.com/ron-rs/ron/pull/138))
+- Update `base64` crate dependency to 0.10 ([#137](https://github.com/ron-rs/ron/pull/137))
+
+## [0.4.0] - 2018-08-11
+### Fixes
+- Handle tuple deserialization in deserialize_any properly ([#124](https://github.com/ron-rs/ron/pull/124))
+### Changes
+- Add raw string syntax to grammar ([#125](https://github.com/ron-rs/ron/pull/125))
+- Reexport `Value` at root ([#120](https://github.com/ron-rs/ron/pull/120))
+
+## [0.3.0] - 2018-06-15
+### Additions
+- `serde_bytes` fields to be encoded using base64. ([#109](https://github.com/ron-rs/ron/pull/109))
+### Fixes
+- Allow raw string literals ([#114](https://github.com/ron-rs/ron/pull/114))
+### Changes
+- Now depends on `base64` 0.9.2.
+
+## [0.2.2] - 2018-05-19
+### Fixes
+- Allow whitespace in newtype variants ([#104](https://github.com/ron-rs/ron/pull/104))
+
+## [0.2.1] - 2018-05-04
+### Additions
+- Add multi-line comments ([#98](https://github.com/ron-rs/ron/pull/98))
+### Fixes
+- Allow more whitespace inside newtypes ([#103](https://github.com/ron-rs/ron/pull/103))
+
+## [0.2.0] - 2018-02-14
+### Additions
+- Limit the pretty depth ([#93](https://github.com/ron-rs/ron/pull/93))
+- Add support for `\x??` and improve unicode escapes ([#84](https://github.com/ron-rs/ron/pull/84))
+
+## [0.1.7] - 2018-01-24
+### Additions
+- Deep array indexing ([#88](https://github.com/ron-rs/ron/pull/88))
+- Pretty sequence indexing ([#86](https://github.com/ron-rs/ron/pull/86))
+- Add unicode support for chars ([#80](https://github.com/ron-rs/ron/pull/80))
+- Add support for hex, oct and bin numbers ([#78](https://github.com/ron-rs/ron/pull/78))
+- Allow implicit Some ([#75](https://github.com/ron-rs/ron/pull/75))
+- Add grammar specification ([#73](https://github.com/ron-rs/ron/pull/73))
+- Add extension support and first extension, unwrap_newtypes ([#72](https://github.com/ron-rs/ron/pull/72))
+### Fixes
+- Directly serialize `f32` ([#81](https://github.com/ron-rs/ron/pull/81))
+
+## [0.1.6] - 2018-01-24
+### Additions
+- Implement sequence indexing ([#87](https://github.com/ron-rs/ron/pull/87))
+### Fixes
+- Remove ident variable from Sublime syntax ([#71](https://github.com/ron-rs/ron/pull/71))
+
+## [0.1.5] - 2017-12-27
+### Additions
+- Allow creating a new serializer ([#70](https://github.com/ron-rs/ron/pull/70))
+- Sublime syntax highlighter ([#67](https://github.com/ron-rs/ron/pull/67))
+- Add support for integers ([#65](https://github.com/ron-rs/ron/pull/65))
+- Implement `Deserializer` for `Value` ([#64](https://github.com/ron-rs/ron/pull/64))
+
+## [0.1.4] - 2017-10-12
+### Additions
+- Add `PrettyConfig` ([#61](https://github.com/ron-rs/ron/pull/61))
+- impl `deserialize_ignored_any` for `id` ([#60](https://github.com/ron-rs/ron/pull/60))
+### Fixes
+- Fix deserializing of ignored fields ([#62](https://github.com/ron-rs/ron/pull/62))
+
+## [0.1.3] - 2017-10-06
+### Fixes
+- Removed indentation from tuple variant pretty encoder ([#57](https://github.com/ron-rs/ron/pull/57))
+
+## [0.1.2] - 2017-10-06
+### Fixes
+- Fix decoding of string literals ([#56](https://github.com/ron-rs/ron/pull/56))
+- Add `Value` and implement `deserialize_any` ([#53](https://github.com/ron-rs/ron/pull/53))
+
+## [0.1.1] - 2017-08-07
+### Fixes
+- Be more permissive wrt whitespace decoding ([#41](https://github.com/ron-rs/ron/pull/41))
+### Additions
+- Add utility function to deserialize from `std::io::Read` ([#42](https://github.com/ron-rs/ron/pull/42))
+
+## [0.1.0] - 2015-08-04
+### Changes
+- Reorganize deserialization modules ([#30](https://github.com/ron-rs/ron/pull/30))
+- Rework deserializer not to require `pom` crate [#27](https://github.com/ron-rs/ron/pull/27), ([#38](https://github.com/ron-rs/ron/pull/38))
+- Dual license under Apache 2.0 and MIT ([#26](https://github.com/ron-rs/ron/pull/26))
+### Fixes
+- Use CRLF for serializatio on Windows ([#32](https://github.com/ron-rs/ron/pull/32))
+- Fix bors-ng to work with travis ([#31](https://github.com/ron-rs/ron/pull/31))
+- Handle escapes ([#23](https://github.com/ron-rs/ron/pull/23))
+### Additions
+- Improve error reporting ([#29](https://github.com/ron-rs/ron/pull/29))
+- Allow decoding of comments ([#28](https://github.com/ron-rs/ron/pull/28))
+- Add `pretty` option to serializer ([#25](https://github.com/ron-rs/ron/pull/25))
+- Add roundtrip tests ([#24](https://github.com/ron-rs/ron/pull/24))
+
+## [0.0.1] - 2015-07-30
+Initial release
diff --git a/third_party/rust/ron/Cargo.lock b/third_party/rust/ron/Cargo.lock
new file mode 100644
index 0000000000..f0b6bf1bc0
--- /dev/null
+++ b/third_party/rust/ron/Cargo.lock
@@ -0,0 +1,158 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "base64"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+
+[[package]]
+name = "bitflags"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "indexmap"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+ "serde",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+
+[[package]]
+name = "option_set"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6086504539517779cabafa311a1092e743ef0e8e8aad859db384f06ceb1ada44"
+dependencies = [
+ "heck",
+ "serde",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ron"
+version = "0.8.1"
+dependencies = [
+ "base64",
+ "bitflags",
+ "indexmap",
+ "option_set",
+ "serde",
+ "serde_bytes",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+
+[[package]]
+name = "serde"
+version = "1.0.183"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.183"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
diff --git a/third_party/rust/ron/Cargo.toml b/third_party/rust/ron/Cargo.toml
new file mode 100644
index 0000000000..5879d23a5d
--- /dev/null
+++ b/third_party/rust/ron/Cargo.toml
@@ -0,0 +1,69 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.64.0"
+name = "ron"
+version = "0.8.1"
+authors = [
+ "Christopher Durham <cad97@cad97.com>",
+ "Dzmitry Malyshau <kvarkus@gmail.com>",
+ "Thomas Schaller <torkleyy@gmail.com>",
+ "Juniper Tyree <juniper.tyree@helsinki.fi>",
+]
+description = "Rusty Object Notation"
+homepage = "https://github.com/ron-rs/ron"
+documentation = "https://docs.rs/ron/"
+readme = "README.md"
+keywords = [
+ "parser",
+ "serde",
+ "serialization",
+]
+categories = ["encoding"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/ron-rs/ron"
+
+[dependencies.base64]
+version = "0.21"
+
+[dependencies.bitflags]
+version = "2.0"
+features = ["serde"]
+
+[dependencies.indexmap]
+version = "2.0"
+features = ["serde"]
+optional = true
+
+[dependencies.serde]
+version = "1.0.60"
+
+[dependencies.serde_derive]
+version = "1.0"
+
+[dev-dependencies.option_set]
+version = "0.2"
+
+[dev-dependencies.serde]
+version = "1.0"
+features = ["derive"]
+
+[dev-dependencies.serde_bytes]
+version = "0.11"
+
+[dev-dependencies.serde_json]
+version = "1.0"
+
+[features]
+default = []
+integer128 = []
diff --git a/third_party/rust/ron/LICENSE-APACHE b/third_party/rust/ron/LICENSE-APACHE
new file mode 100644
index 0000000000..16fe87b06e
--- /dev/null
+++ b/third_party/rust/ron/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/ron/LICENSE-MIT b/third_party/rust/ron/LICENSE-MIT
new file mode 100644
index 0000000000..620b0130cc
--- /dev/null
+++ b/third_party/rust/ron/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017 RON developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/ron/README.md b/third_party/rust/ron/README.md
new file mode 100644
index 0000000000..b784222626
--- /dev/null
+++ b/third_party/rust/ron/README.md
@@ -0,0 +1,182 @@
+# Rusty Object Notation
+
+[![CI](https://github.com/ron-rs/ron/actions/workflows/ci.yaml/badge.svg)](https://github.com/ron-rs/ron/actions/workflows/ci.yaml)
+[![codecov](https://img.shields.io/codecov/c/github/ron-rs/ron/codecov?token=x4Q5KA51Ul)](https://codecov.io/gh/ron-rs/ron)
+[![Crates.io](https://img.shields.io/crates/v/ron.svg)](https://crates.io/crates/ron)
+[![MSRV](https://img.shields.io/badge/MSRV-1.64.0-orange)](https://github.com/ron-rs/ron)
+[![Docs](https://docs.rs/ron/badge.svg)](https://docs.rs/ron)
+[![Matrix](https://img.shields.io/matrix/ron-rs:matrix.org.svg)](https://matrix.to/#/#ron-rs:matrix.org)
+
+RON is a simple readable data serialization format that looks similar to Rust syntax.
+It's designed to support all of [Serde's data model](https://serde.rs/data-model.html), so
+structs, enums, tuples, arrays, generic maps, and primitive values.
+
+## Example
+
+```rust,ignore
+GameConfig( // optional struct name
+ window_size: (800, 600),
+ window_title: "PAC-MAN",
+ fullscreen: false,
+
+ mouse_sensitivity: 1.4,
+ key_bindings: {
+ "up": Up,
+ "down": Down,
+ "left": Left,
+ "right": Right,
+
+ // Uncomment to enable WASD controls
+ /*
+ "W": Up,
+ "S": Down,
+ "A": Left,
+ "D": Right,
+ */
+ },
+
+ difficulty_options: (
+ start_difficulty: Easy,
+ adaptive: false,
+ ),
+)
+```
+
+## Why RON?
+
+### Example in JSON
+
+```json
+{
+ "materials": {
+ "metal": {
+ "reflectivity": 1.0
+ },
+ "plastic": {
+ "reflectivity": 0.5
+ }
+ },
+ "entities": [
+ {
+ "name": "hero",
+ "material": "metal"
+ },
+ {
+ "name": "monster",
+ "material": "plastic"
+ }
+ ]
+}
+```
+
+### Same example in RON
+
+```rust,ignore
+Scene( // class name is optional
+ materials: { // this is a map
+ "metal": (
+ reflectivity: 1.0,
+ ),
+ "plastic": (
+ reflectivity: 0.5,
+ ),
+ },
+ entities: [ // this is an array
+ (
+ name: "hero",
+ material: "metal",
+ ),
+ (
+ name: "monster",
+ material: "plastic",
+ ),
+ ],
+)
+```
+
+Note the following advantages of RON over JSON:
+
+* trailing commas allowed
+* single- and multi-line comments
+* field names aren't quoted, so it's less verbose
+* optional struct names improve readability
+* enums are supported (and less verbose than their JSON representation)
+
+## Limitations
+
+RON is not designed to be a fully self-describing format (unlike JSON) and is thus not guaranteed to work when [`deserialize_any`](https://docs.rs/serde/latest/serde/trait.Deserializer.html#tymethod.deserialize_any) is used instead of its typed alternatives. In particular, the following Serde attributes are not yet supported:
+- `#[serde(tag = "type")]`, i.e. internally tagged enums
+- `#[serde(untagged)]`, i.e. untagged enums
+- `#[serde(flatten)]`, i.e. flattening an inner struct into its outer container
+
+## RON syntax overview
+
+* Numbers: `42`, `3.14`, `0xFF`, `0b0110`
+* Strings: `"Hello"`, `"with\\escapes\n"`, `r#"raw string, great for regex\."#`
+* Booleans: `true`, `false`
+* Chars: `'e'`, `'\n'`
+* Optionals: `Some("string")`, `Some(Some(1.34))`, `None`
+* Tuples: `("abc", 1.23, true)`, `()`
+* Lists: `["abc", "def"]`
+* Structs: `( foo: 1.0, bar: ( baz: "I'm nested" ) )`
+* Maps: `{ "arbitrary": "keys", "are": "allowed" }`
+
+> **Note:** Serde's data model represents fixed-size Rust arrays as tuple (instead of as list)
+
+## Quickstart
+
+### `Cargo.toml`
+
+```toml
+[dependencies]
+ron = "0.8"
+serde = { version = "1", features = ["derive"] }
+```
+
+### `main.rs`
+
+```rust
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Deserialize, Serialize)]
+struct MyStruct {
+ boolean: bool,
+ float: f32,
+}
+
+fn main() {
+ let x: MyStruct = ron::from_str("(boolean: true, float: 1.23)").unwrap();
+
+ println!("RON: {}", ron::to_string(&x).unwrap());
+
+ println!("Pretty RON: {}", ron::ser::to_string_pretty(
+ &x, ron::ser::PrettyConfig::default()).unwrap(),
+ );
+}
+```
+
+## Tooling
+
+| Editor | Plugin |
+| ------------ | ----------------------------------------------------------- |
+| IntelliJ | [intellij-ron](https://github.com/ron-rs/intellij-ron) |
+| VS Code | [a5huynh/vscode-ron](https://github.com/a5huynh/vscode-ron) |
+| Sublime Text | [RON](https://packagecontrol.io/packages/RON) |
+| Atom | [language-ron](https://atom.io/packages/language-ron) |
+| Vim | [ron-rs/ron.vim](https://github.com/ron-rs/ron.vim) |
+| EMACS | [emacs-ron] |
+
+[emacs-ron]: https://chiselapp.com/user/Hutzdog/repository/ron-mode/home
+
+## Specification
+
+There is a very basic, work in progress specification available on
+[the wiki page](https://github.com/ron-rs/ron/wiki/Specification).
+A more formal and complete grammar is available [here](docs/grammar.md).
+
+
+## License
+
+RON is dual-licensed under Apache-2.0 and MIT.
+
+Any contribution intentionally submitted for inclusion in the work must be provided under the same dual-license terms.
diff --git a/third_party/rust/ron/clippy.toml b/third_party/rust/ron/clippy.toml
new file mode 100644
index 0000000000..cb8cfcd1c7
--- /dev/null
+++ b/third_party/rust/ron/clippy.toml
@@ -0,0 +1,2 @@
+msrv = "1.64.0"
+blacklisted-names = []
diff --git a/third_party/rust/ron/docs/extensions.md b/third_party/rust/ron/docs/extensions.md
new file mode 100644
index 0000000000..a849220222
--- /dev/null
+++ b/third_party/rust/ron/docs/extensions.md
@@ -0,0 +1,116 @@
+## RON extensions
+
+RON has extensions that can be enabled by adding the following attribute at the top of your RON document:
+
+`#![enable(...)]`
+
+# unwrap_newtypes
+
+You can add this extension by adding the following attribute at the top of your RON document:
+
+`#![enable(unwrap_newtypes)]`
+
+This feature enables RON to automatically unwrap simple tuples.
+
+```rust
+struct NewType(u32);
+struct Object {
+ pub new_type: NewType,
+}
+```
+
+Without `unwrap_newtypes`, because the value `5` can not be saved into `NewType(u32)`, your RON document would look like this:
+
+``` ron
+(
+ new_type: (5),
+)
+```
+
+With the `unwrap_newtypes` extension, this coercion is done automatically. So `5` will be interpreted as `(5)`.
+
+``` ron
+#![enable(unwrap_newtypes)]
+(
+ new_type: 5,
+)
+```
+
+# implicit_some
+
+You can add this extension by adding the following attribute at the top of your RON document:
+
+`#![enable(implicit_some)]`
+
+This feature enables RON to automatically convert any value to `Some(value)` if the deserialized type requires it.
+
+```rust
+struct Object {
+ pub value: Option<u32>,
+}
+```
+
+Without this feature, you would have to write this RON document.
+
+```ron
+(
+ value: Some(5),
+)
+```
+
+Enabling the feature would automatically infer `Some(x)` if `x` is given. In this case, RON automatically casts this `5` into a `Some(5)`.
+
+```ron
+(
+ value: 5,
+)
+```
+
+With this extension enabled, explicitly given `None` and `Some(..)` will be matched eagerly on `Option<Option<Option<u32>>>`, i.e.
+* `5` -> `Some(Some(Some(5)))`
+* `None` -> `None`
+* `Some(5)` -> `Some(Some(Some(5)))`
+* `Some(None)` -> `Some(None)`
+* `Some(Some(5))` -> `Some(Some(Some(5)))`
+* `Some(Some(None))` -> `Some(Some(None))`
+* `Some(Some(Some(5)))` -> `Some(Some(Some(5)))`
+
+# unwrap_variant_newtypes
+
+You can add this extension by adding the following attribute at the top of your RON document:
+
+`#![enable(unwrap_variant_newtypes)]`
+
+This feature enables RON to automatically unwrap newtype enum variants.
+
+```rust
+#[derive(Deserialize)]
+struct Inner {
+ pub a: u8,
+ pub b: bool,
+}
+#[derive(Deserialize)]
+pub enum Enum {
+ A(Inner),
+ B,
+}
+```
+
+Without `unwrap_variant_newtypes`, your RON document would look like this:
+
+``` ron
+(
+ variant: A(Inner(a: 4, b: true)),
+)
+```
+
+With the `unwrap_variant_newtypes` extension, the first structural layer inside a newtype variant will be unwrapped automatically:
+
+``` ron
+#![enable(unwrap_newtypes)]
+(
+ variant: A(a: 4, b: true),
+)
+```
+
+Note that when the `unwrap_variant_newtypes` extension is enabled, the first layer inside a newtype variant will **always** be unwrapped, i.e. it is no longer possible to write `A(Inner(a: 4, b: true))` or `A((a: 4, b: true))`.
diff --git a/third_party/rust/ron/docs/grammar.md b/third_party/rust/ron/docs/grammar.md
new file mode 100644
index 0000000000..3ef2b7f7e1
--- /dev/null
+++ b/third_party/rust/ron/docs/grammar.md
@@ -0,0 +1,152 @@
+# RON grammar
+
+This file describes the structure of a RON file in [EBNF notation][ebnf].
+If extensions are enabled, some rules will be replaced. For that, see the
+[extensions document][exts] which describes all extensions and what they override.
+
+[ebnf]: https://en.wikipedia.org/wiki/Extended_Backus–Naur_form
+[exts]: ./extensions.md
+
+## RON file
+
+```ebnf
+RON = [extensions], ws, value, ws;
+```
+
+## Whitespace and comments
+
+```ebnf
+ws = { ws_single | comment };
+ws_single = "\n" | "\t" | "\r" | " ";
+comment = ["//", { no_newline }, "\n"] | ["/*", nested_block_comment, "*/"];
+nested_block_comment = { ? any characters except "/*" or "*/" ? }, [ "/*", nested_block_comment, "*/", nested_block_comment ];
+```
+
+## Commas
+
+```ebnf
+comma = ws, ",", ws;
+```
+
+## Extensions
+
+```ebnf
+extensions = { "#", ws, "!", ws, "[", ws, extensions_inner, ws, "]", ws };
+extensions_inner = "enable", ws, "(", extension_name, { comma, extension_name }, [comma], ws, ")";
+```
+
+For the extension names see the [`extensions.md`][exts] document.
+
+## Value
+
+```ebnf
+value = unsigned | signed | float | string | char | bool | option | list | map | tuple | struct | enum_variant;
+```
+
+## Numbers
+
+```ebnf
+digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
+hex_digit = "A" | "a" | "B" | "b" | "C" | "c" | "D" | "d" | "E" | "e" | "F" | "f";
+unsigned = (["0", ("b" | "o")], digit, { digit | '_' } |
+ "0x", (digit | hex_digit), { digit | hex_digit | '_' });
+signed = ["+" | "-"], unsigned;
+float = ["+" | "-"], ("inf" | "NaN" | float_num);
+float_num = (float_int | float_std | float_frac), [float_exp];
+float_int = digit, { digit };
+float_std = digit, { digit }, ".", {digit};
+float_frac = ".", digit, {digit};
+float_exp = ("e" | "E"), ["+" | "-"], digit, {digit};
+```
+
+## String
+
+```ebnf
+string = string_std | string_raw;
+string_std = "\"", { no_double_quotation_marks | string_escape }, "\"";
+string_escape = "\\", ("\"" | "\\" | "b" | "f" | "n" | "r" | "t" | ("u", unicode_hex));
+string_raw = "r" string_raw_content;
+string_raw_content = ("#", string_raw_content, "#") | "\"", { unicode_non_greedy }, "\"";
+```
+
+> Note: Raw strings start with an `r`, followed by n `#`s and a quotation mark
+ `"`. They may contain any characters or escapes (except the end sequence).
+ A raw string ends with a quotation mark (`"`), followed by n `#`s. n may be
+ any number, including zero.
+ Example:
+ ```rust
+r##"This is a "raw string". It can contain quotations or
+backslashes (\)!"##
+ ```
+Raw strings cannot be written in EBNF, as they are context-sensitive.
+Also see [the Rust document] about context-sensitivity of raw strings.
+
+[the Rust document]: https://github.com/rust-lang/rust/blob/d046ffddc4bd50e04ffc3ff9f766e2ac71f74d50/src/grammar/raw-string-literal-ambiguity.md
+
+## Char
+
+```ebnf
+char = "'", (no_apostrophe | "\\\\" | "\\'"), "'";
+```
+
+## Boolean
+
+```ebnf
+bool = "true" | "false";
+```
+
+## Optional
+
+```ebnf
+option = "None" | option_some;
+option_some = "Some", ws, "(", ws, value, ws, ")";
+```
+
+## List
+
+```ebnf
+list = "[", [value, { comma, value }, [comma]], "]";
+```
+
+## Map
+
+```ebnf
+map = "{", [map_entry, { comma, map_entry }, [comma]], "}";
+map_entry = value, ws, ":", ws, value;
+```
+
+## Tuple
+
+```ebnf
+tuple = "(", [value, { comma, value }, [comma]], ")";
+```
+
+## Struct
+
+```ebnf
+struct = unit_struct | tuple_struct | named_struct;
+unit_struct = ident | "()";
+tuple_struct = [ident], ws, tuple;
+named_struct = [ident], ws, "(", ws, [named_field, { comma, named_field }, [comma]], ")";
+named_field = ident, ws, ":", ws, value;
+```
+
+## Enum
+
+```ebnf
+enum_variant = enum_variant_unit | enum_variant_tuple | enum_variant_named;
+enum_variant_unit = ident;
+enum_variant_tuple = ident, ws, tuple;
+enum_variant_named = ident, ws, "(", [named_field, { comma, named_field }, [comma]], ")";
+```
+
+## Identifier
+
+```ebnf
+ident = ident_std | ident_raw;
+ident_std = ident_std_first, { ident_std_rest };
+ident_std_first = "A" | ... | "Z" | "a" | ... | "z" | "_";
+ident_std_rest = ident_std_first | digit;
+ident_raw = "r", "#", ident_raw_rest, { ident_raw_rest };
+ident_raw_rest = ident_std_rest | "." | "+" | "-";
+```
diff --git a/third_party/rust/ron/examples/decode.rs b/third_party/rust/ron/examples/decode.rs
new file mode 100644
index 0000000000..5aa2042fa7
--- /dev/null
+++ b/third_party/rust/ron/examples/decode.rs
@@ -0,0 +1,68 @@
+#![allow(dead_code)]
+
+use std::collections::HashMap;
+
+use ron::de::from_str;
+use serde::Deserialize;
+
+#[derive(Debug, Deserialize)]
+struct Config {
+ boolean: bool,
+ float: f32,
+ map: HashMap<u8, char>,
+ nested: Nested,
+ option: Option<String>,
+ tuple: (u32, u32),
+}
+
+#[derive(Debug, Deserialize)]
+struct Nested {
+ a: String,
+ b: char,
+}
+
+const CONFIG: &str = "
+/*
+ * RON now has multi-line (C-style) block comments!
+ * They can be freely nested:
+ * /* This is a nested comment */
+ * If you just want a single-line comment,
+ * do it like here:
+// Just put two slashes before the comment and the rest of the line
+// can be used freely!
+*/
+
+// Note that block comments can not be started in a line comment
+// (Putting a /* here will have no effect)
+
+(
+ boolean: true,
+ float: 8.2,
+ map: {
+ 1: '1',
+ 2: '4',
+ 3: '9',
+ 4: '1',
+ 5: '2',
+ 6: '3',
+ },
+ nested: Nested(
+ a: \"Decode me!\",
+ b: 'z',
+ ),
+ option: Some(\t \"Weird formatting!\" \n\n ),
+ tuple: (3 /*(2 + 1)*/, 7 /*(2 * 5 - 3)*/),
+)";
+
+fn main() {
+ let config: Config = match from_str(CONFIG) {
+ Ok(x) => x,
+ Err(e) => {
+ println!("Failed to load config: {}", e);
+
+ std::process::exit(1);
+ }
+ };
+
+ println!("Config: {:?}", &config);
+}
diff --git a/third_party/rust/ron/examples/decode_file.rs b/third_party/rust/ron/examples/decode_file.rs
new file mode 100644
index 0000000000..72ca8a05f3
--- /dev/null
+++ b/third_party/rust/ron/examples/decode_file.rs
@@ -0,0 +1,37 @@
+#![allow(dead_code)]
+
+use std::{collections::HashMap, fs::File};
+
+use ron::de::from_reader;
+use serde::Deserialize;
+
+#[derive(Debug, Deserialize)]
+struct Config {
+ boolean: bool,
+ float: f32,
+ map: HashMap<u8, char>,
+ nested: Nested,
+ tuple: (u32, u32),
+ vec: Vec<Nested>,
+}
+
+#[derive(Debug, Deserialize)]
+struct Nested {
+ a: String,
+ b: char,
+}
+
+fn main() {
+ let input_path = format!("{}/examples/example.ron", env!("CARGO_MANIFEST_DIR"));
+ let f = File::open(&input_path).expect("Failed opening file");
+ let config: Config = match from_reader(f) {
+ Ok(x) => x,
+ Err(e) => {
+ println!("Failed to load config: {}", e);
+
+ std::process::exit(1);
+ }
+ };
+
+ println!("Config: {:?}", &config);
+}
diff --git a/third_party/rust/ron/examples/encode.rs b/third_party/rust/ron/examples/encode.rs
new file mode 100644
index 0000000000..30e9688951
--- /dev/null
+++ b/third_party/rust/ron/examples/encode.rs
@@ -0,0 +1,50 @@
+use std::{collections::HashMap, iter::FromIterator};
+
+use ron::ser::{to_string_pretty, PrettyConfig};
+use serde::Serialize;
+
+#[derive(Serialize)]
+struct Config {
+ float: (f32, f64),
+ tuple: TupleStruct,
+ map: HashMap<u8, char>,
+ nested: Nested,
+ var: Variant,
+ array: Vec<()>,
+}
+
+#[derive(Serialize)]
+struct TupleStruct((), bool);
+
+#[derive(Serialize)]
+enum Variant {
+ A(u8, &'static str),
+}
+
+#[derive(Serialize)]
+struct Nested {
+ a: String,
+ b: char,
+}
+
+fn main() {
+ let data = Config {
+ float: (2.18, -1.1),
+ tuple: TupleStruct((), false),
+ map: HashMap::from_iter(vec![(0, '1'), (1, '2'), (3, '5'), (8, '1')]),
+ nested: Nested {
+ a: "Hello from \"RON\"".to_string(),
+ b: 'b',
+ },
+ var: Variant::A(!0, ""),
+ array: vec![(); 3],
+ };
+
+ let pretty = PrettyConfig::new()
+ .depth_limit(2)
+ .separate_tuple_members(true)
+ .enumerate_arrays(true);
+ let s = to_string_pretty(&data, pretty).expect("Serialization failed");
+
+ println!("{}", s);
+}
diff --git a/third_party/rust/ron/examples/example.ron b/third_party/rust/ron/examples/example.ron
new file mode 100644
index 0000000000..011ac5782d
--- /dev/null
+++ b/third_party/rust/ron/examples/example.ron
@@ -0,0 +1,22 @@
+(
+ boolean: true,
+ float: 8.2,
+ map: {
+ 1: '1',
+ 2: '4',
+ 3: '9',
+ 4: '1',
+ 5: '2',
+ 6: '3',
+ },
+ nested: Nested(
+ a: "Decode me!",
+ b: 'z',
+ ),
+ tuple: (3, 7),
+ vec: [
+ (a: "Nested 1", b: 'x'),
+ (a: "Nested 2", b: 'y'),
+ (a: "Nested 3", b: 'z'),
+ ],
+) \ No newline at end of file
diff --git a/third_party/rust/ron/examples/transcode.rs b/third_party/rust/ron/examples/transcode.rs
new file mode 100644
index 0000000000..115ac469d1
--- /dev/null
+++ b/third_party/rust/ron/examples/transcode.rs
@@ -0,0 +1,31 @@
+use ron::value::Value;
+use serde::Serialize;
+
+fn main() {
+ let data = r#"
+ Scene( // class name is optional
+ materials: { // this is a map
+ "metal": (
+ reflectivity: 1.0,
+ ),
+ "plastic": (
+ reflectivity: 0.5,
+ ),
+ },
+ entities: [ // this is an array
+ (
+ name: "hero",
+ material: "metal",
+ ),
+ (
+ name: "monster",
+ material: "plastic",
+ ),
+ ],
+ )
+ "#;
+
+ let value: Value = data.parse().expect("Failed to deserialize");
+ let mut ser = serde_json::Serializer::pretty(std::io::stdout());
+ value.serialize(&mut ser).expect("Failed to serialize");
+}
diff --git a/third_party/rust/ron/rustfmt.toml b/third_party/rust/ron/rustfmt.toml
new file mode 100644
index 0000000000..95127ec82c
--- /dev/null
+++ b/third_party/rust/ron/rustfmt.toml
@@ -0,0 +1,4 @@
+hard_tabs = false
+use_field_init_shorthand = true
+use_try_shorthand = true
+edition = "2021"
diff --git a/third_party/rust/ron/src/de/id.rs b/third_party/rust/ron/src/de/id.rs
new file mode 100644
index 0000000000..e7230da5fc
--- /dev/null
+++ b/third_party/rust/ron/src/de/id.rs
@@ -0,0 +1,246 @@
+use serde::de::{self, Visitor};
+
+use super::{Deserializer, Error, Result};
+
+pub struct IdDeserializer<'a, 'b: 'a> {
+ d: &'a mut Deserializer<'b>,
+}
+
+impl<'a, 'b: 'a> IdDeserializer<'a, 'b> {
+ pub fn new(d: &'a mut Deserializer<'b>) -> Self {
+ IdDeserializer { d }
+ }
+}
+
+impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
+ type Error = Error;
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_identifier(visitor)
+ }
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.deserialize_identifier(visitor)
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.deserialize_identifier(visitor)
+ }
+
+ fn deserialize_bool<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_i8<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_i16<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_i32<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_i64<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_i128<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_u8<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_u16<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_u32<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_u64<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_u128<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_f32<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_f64<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_char<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_string<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_bytes<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_option<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_unit<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_unit_struct<V>(self, _: &'static str, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_newtype_struct<V>(self, _: &'static str, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_seq<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_tuple<V>(self, _: usize, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_tuple_struct<V>(self, _: &'static str, _: usize, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_map<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ _: &'static str,
+ _: &'static [&'static str],
+ _: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _: &'static str,
+ _: &'static [&'static str],
+ _: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ Err(Error::ExpectedIdentifier)
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.deserialize_any(visitor)
+ }
+}
diff --git a/third_party/rust/ron/src/de/mod.rs b/third_party/rust/ron/src/de/mod.rs
new file mode 100644
index 0000000000..c0e62494be
--- /dev/null
+++ b/third_party/rust/ron/src/de/mod.rs
@@ -0,0 +1,869 @@
+/// Deserialization module.
+use std::{borrow::Cow, io, str};
+
+use base64::Engine;
+use serde::{
+ de::{self, DeserializeSeed, Deserializer as _, Visitor},
+ Deserialize,
+};
+
+use self::{id::IdDeserializer, tag::TagDeserializer};
+pub use crate::error::{Error, Position, SpannedError};
+use crate::{
+ error::{Result, SpannedResult},
+ extensions::Extensions,
+ options::Options,
+ parse::{AnyNum, Bytes, ParsedStr, BASE64_ENGINE},
+};
+
+mod id;
+mod tag;
+#[cfg(test)]
+mod tests;
+mod value;
+
+/// The RON deserializer.
+///
+/// If you just want to simply deserialize a value,
+/// you can use the [`from_str`] convenience function.
+pub struct Deserializer<'de> {
+ bytes: Bytes<'de>,
+ newtype_variant: bool,
+ last_identifier: Option<&'de str>,
+ recursion_limit: Option<usize>,
+}
+
+impl<'de> Deserializer<'de> {
+ // Cannot implement trait here since output is tied to input lifetime 'de.
+ #[allow(clippy::should_implement_trait)]
+ pub fn from_str(input: &'de str) -> SpannedResult<Self> {
+ Self::from_str_with_options(input, Options::default())
+ }
+
+ pub fn from_bytes(input: &'de [u8]) -> SpannedResult<Self> {
+ Self::from_bytes_with_options(input, Options::default())
+ }
+
+ pub fn from_str_with_options(input: &'de str, options: Options) -> SpannedResult<Self> {
+ Self::from_bytes_with_options(input.as_bytes(), options)
+ }
+
+ pub fn from_bytes_with_options(input: &'de [u8], options: Options) -> SpannedResult<Self> {
+ let mut deserializer = Deserializer {
+ bytes: Bytes::new(input)?,
+ newtype_variant: false,
+ last_identifier: None,
+ recursion_limit: options.recursion_limit,
+ };
+
+ deserializer.bytes.exts |= options.default_extensions;
+
+ Ok(deserializer)
+ }
+
+ pub fn remainder(&self) -> Cow<'_, str> {
+ String::from_utf8_lossy(self.bytes.bytes())
+ }
+
+ pub fn span_error(&self, code: Error) -> SpannedError {
+ self.bytes.span_error(code)
+ }
+}
+
+/// A convenience function for building a deserializer
+/// and deserializing a value of type `T` from a reader.
+pub fn from_reader<R, T>(rdr: R) -> SpannedResult<T>
+where
+ R: io::Read,
+ T: de::DeserializeOwned,
+{
+ Options::default().from_reader(rdr)
+}
+
+/// A convenience function for building a deserializer
+/// and deserializing a value of type `T` from a string.
+pub fn from_str<'a, T>(s: &'a str) -> SpannedResult<T>
+where
+ T: de::Deserialize<'a>,
+{
+ Options::default().from_str(s)
+}
+
+/// A convenience function for building a deserializer
+/// and deserializing a value of type `T` from bytes.
+pub fn from_bytes<'a, T>(s: &'a [u8]) -> SpannedResult<T>
+where
+ T: de::Deserialize<'a>,
+{
+ Options::default().from_bytes(s)
+}
+
+macro_rules! guard_recursion {
+ ($self:expr => $expr:expr) => {{
+ if let Some(limit) = &mut $self.recursion_limit {
+ if let Some(new_limit) = limit.checked_sub(1) {
+ *limit = new_limit;
+ } else {
+ return Err(Error::ExceededRecursionLimit);
+ }
+ }
+
+ let result = $expr;
+
+ if let Some(limit) = &mut $self.recursion_limit {
+ *limit = limit.saturating_add(1);
+ }
+
+ result
+ }};
+}
+
+impl<'de> Deserializer<'de> {
+ /// Check if the remaining bytes are whitespace only,
+ /// otherwise return an error.
+ pub fn end(&mut self) -> Result<()> {
+ self.bytes.skip_ws()?;
+
+ if self.bytes.bytes().is_empty() {
+ Ok(())
+ } else {
+ Err(Error::TrailingCharacters)
+ }
+ }
+
+ /// Called from [`deserialize_any`][serde::Deserializer::deserialize_any]
+ /// when a struct was detected. Decides if there is a unit, tuple or usual
+ /// struct and deserializes it accordingly.
+ ///
+ /// This method assumes there is no identifier left.
+ fn handle_any_struct<V>(&mut self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ // Create a working copy
+ let mut bytes = self.bytes;
+
+ if bytes.consume("(") {
+ bytes.skip_ws()?;
+
+ if bytes.check_tuple_struct()? {
+ // first argument is technically incorrect, but ignored anyway
+ self.deserialize_tuple(0, visitor)
+ } else {
+ // giving no name results in worse errors but is necessary here
+ self.handle_struct_after_name("", visitor)
+ }
+ } else {
+ visitor.visit_unit()
+ }
+ }
+
+ /// Called from
+ /// [`deserialize_struct`][serde::Deserializer::deserialize_struct],
+ /// [`struct_variant`][serde::de::VariantAccess::struct_variant], and
+ /// [`handle_any_struct`][Self::handle_any_struct]. Handles
+ /// deserialising the enclosing parentheses and everything in between.
+ ///
+ /// This method assumes there is no struct name identifier left.
+ fn handle_struct_after_name<V>(
+ &mut self,
+ name_for_pretty_errors_only: &'static str,
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.newtype_variant || self.bytes.consume("(") {
+ let old_newtype_variant = self.newtype_variant;
+ self.newtype_variant = false;
+
+ let value = guard_recursion! { self =>
+ visitor
+ .visit_map(CommaSeparated::new(b')', self))
+ .map_err(|err| {
+ struct_error_name(
+ err,
+ if !old_newtype_variant && !name_for_pretty_errors_only.is_empty() {
+ Some(name_for_pretty_errors_only)
+ } else {
+ None
+ },
+ )
+ })?
+ };
+
+ self.bytes.skip_ws()?;
+
+ if old_newtype_variant || self.bytes.consume(")") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedStructLikeEnd)
+ }
+ } else if name_for_pretty_errors_only.is_empty() {
+ Err(Error::ExpectedStructLike)
+ } else {
+ Err(Error::ExpectedNamedStructLike(name_for_pretty_errors_only))
+ }
+ }
+}
+
+impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ // Newtype variants can only be unwrapped if we receive information
+ // about the wrapped type - with `deserialize_any` we don't
+ self.newtype_variant = false;
+
+ if self.bytes.consume_ident("true") {
+ return visitor.visit_bool(true);
+ } else if self.bytes.consume_ident("false") {
+ return visitor.visit_bool(false);
+ } else if self.bytes.check_ident("Some") {
+ return self.deserialize_option(visitor);
+ } else if self.bytes.consume_ident("None") {
+ return visitor.visit_none();
+ } else if self.bytes.consume("()") {
+ return visitor.visit_unit();
+ } else if self.bytes.consume_ident("inf") {
+ return visitor.visit_f64(std::f64::INFINITY);
+ } else if self.bytes.consume_ident("-inf") {
+ return visitor.visit_f64(std::f64::NEG_INFINITY);
+ } else if self.bytes.consume_ident("NaN") {
+ return visitor.visit_f64(std::f64::NAN);
+ }
+
+ // `identifier` does not change state if it fails
+ let ident = self.bytes.identifier().ok();
+
+ if ident.is_some() {
+ self.bytes.skip_ws()?;
+
+ return self.handle_any_struct(visitor);
+ }
+
+ match self.bytes.peek_or_eof()? {
+ b'(' => self.handle_any_struct(visitor),
+ b'[' => self.deserialize_seq(visitor),
+ b'{' => self.deserialize_map(visitor),
+ b'0'..=b'9' | b'+' | b'-' => {
+ let any_num: AnyNum = self.bytes.any_num()?;
+
+ match any_num {
+ AnyNum::F32(x) => visitor.visit_f32(x),
+ AnyNum::F64(x) => visitor.visit_f64(x),
+ AnyNum::I8(x) => visitor.visit_i8(x),
+ AnyNum::U8(x) => visitor.visit_u8(x),
+ AnyNum::I16(x) => visitor.visit_i16(x),
+ AnyNum::U16(x) => visitor.visit_u16(x),
+ AnyNum::I32(x) => visitor.visit_i32(x),
+ AnyNum::U32(x) => visitor.visit_u32(x),
+ AnyNum::I64(x) => visitor.visit_i64(x),
+ AnyNum::U64(x) => visitor.visit_u64(x),
+ #[cfg(feature = "integer128")]
+ AnyNum::I128(x) => visitor.visit_i128(x),
+ #[cfg(feature = "integer128")]
+ AnyNum::U128(x) => visitor.visit_u128(x),
+ }
+ }
+ b'.' => self.deserialize_f64(visitor),
+ b'"' | b'r' => self.deserialize_string(visitor),
+ b'\'' => self.deserialize_char(visitor),
+ other => Err(Error::UnexpectedByte(other as char)),
+ }
+ }
+
+ fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_bool(self.bytes.bool()?)
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i8(self.bytes.signed_integer()?)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i16(self.bytes.signed_integer()?)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i32(self.bytes.signed_integer()?)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i64(self.bytes.signed_integer()?)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i128(self.bytes.signed_integer()?)
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_u8(self.bytes.unsigned_integer()?)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_u16(self.bytes.unsigned_integer()?)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_u32(self.bytes.unsigned_integer()?)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_u64(self.bytes.unsigned_integer()?)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_u128(self.bytes.unsigned_integer()?)
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_f32(self.bytes.float()?)
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_f64(self.bytes.float()?)
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_char(self.bytes.char()?)
+ }
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ match self.bytes.string()? {
+ ParsedStr::Allocated(s) => visitor.visit_string(s),
+ ParsedStr::Slice(s) => visitor.visit_borrowed_str(s),
+ }
+ }
+
+ fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_str(visitor)
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_byte_buf(visitor)
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if let Some(b'[') = self.bytes.peek() {
+ let bytes = Vec::<u8>::deserialize(self)?;
+ return visitor.visit_byte_buf(bytes);
+ }
+
+ let res = {
+ let string = self.bytes.string()?;
+ let base64_str = match string {
+ ParsedStr::Allocated(ref s) => s.as_str(),
+ ParsedStr::Slice(s) => s,
+ };
+ BASE64_ENGINE.decode(base64_str)
+ };
+
+ match res {
+ Ok(byte_buf) => visitor.visit_byte_buf(byte_buf),
+ Err(err) => Err(Error::Base64Error(err)),
+ }
+ }
+
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.bytes.consume("None") {
+ visitor.visit_none()
+ } else if self.bytes.consume("Some") && {
+ self.bytes.skip_ws()?;
+ self.bytes.consume("(")
+ } {
+ self.bytes.skip_ws()?;
+
+ let v = guard_recursion! { self => visitor.visit_some(&mut *self)? };
+
+ self.bytes.comma()?;
+
+ if self.bytes.consume(")") {
+ Ok(v)
+ } else {
+ Err(Error::ExpectedOptionEnd)
+ }
+ } else if self.bytes.exts.contains(Extensions::IMPLICIT_SOME) {
+ guard_recursion! { self => visitor.visit_some(&mut *self) }
+ } else {
+ Err(Error::ExpectedOption)
+ }
+ }
+
+ // In Serde, unit means an anonymous value containing no data.
+ fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.newtype_variant || self.bytes.consume("()") {
+ self.newtype_variant = false;
+
+ visitor.visit_unit()
+ } else {
+ Err(Error::ExpectedUnit)
+ }
+ }
+
+ fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.newtype_variant || self.bytes.consume_struct_name(name)? {
+ self.newtype_variant = false;
+
+ visitor.visit_unit()
+ } else {
+ self.deserialize_unit(visitor)
+ }
+ }
+
+ fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.bytes.exts.contains(Extensions::UNWRAP_NEWTYPES) || self.newtype_variant {
+ self.newtype_variant = false;
+
+ return guard_recursion! { self => visitor.visit_newtype_struct(&mut *self) };
+ }
+
+ self.bytes.consume_struct_name(name)?;
+
+ self.bytes.skip_ws()?;
+
+ if self.bytes.consume("(") {
+ self.bytes.skip_ws()?;
+ let value = guard_recursion! { self => visitor.visit_newtype_struct(&mut *self)? };
+ self.bytes.comma()?;
+
+ if self.bytes.consume(")") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedStructLikeEnd)
+ }
+ } else if name.is_empty() {
+ Err(Error::ExpectedStructLike)
+ } else {
+ Err(Error::ExpectedNamedStructLike(name))
+ }
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.newtype_variant = false;
+
+ if self.bytes.consume("[") {
+ let value = guard_recursion! { self =>
+ visitor.visit_seq(CommaSeparated::new(b']', self))?
+ };
+ self.bytes.skip_ws()?;
+
+ if self.bytes.consume("]") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedArrayEnd)
+ }
+ } else {
+ Err(Error::ExpectedArray)
+ }
+ }
+
+ fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.newtype_variant || self.bytes.consume("(") {
+ let old_newtype_variant = self.newtype_variant;
+ self.newtype_variant = false;
+
+ let value = guard_recursion! { self =>
+ visitor.visit_seq(CommaSeparated::new(b')', self))?
+ };
+ self.bytes.skip_ws()?;
+
+ if old_newtype_variant || self.bytes.consume(")") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedStructLikeEnd)
+ }
+ } else {
+ Err(Error::ExpectedStructLike)
+ }
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ name: &'static str,
+ len: usize,
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if !self.newtype_variant {
+ self.bytes.consume_struct_name(name)?;
+ }
+
+ self.deserialize_tuple(len, visitor).map_err(|e| match e {
+ Error::ExpectedStructLike if !name.is_empty() => Error::ExpectedNamedStructLike(name),
+ e => e,
+ })
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.newtype_variant = false;
+
+ if self.bytes.consume("{") {
+ let value = guard_recursion! { self =>
+ visitor.visit_map(CommaSeparated::new(b'}', self))?
+ };
+ self.bytes.skip_ws()?;
+
+ if self.bytes.consume("}") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedMapEnd)
+ }
+ } else {
+ Err(Error::ExpectedMap)
+ }
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ name: &'static str,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if !self.newtype_variant {
+ self.bytes.consume_struct_name(name)?;
+ }
+
+ self.bytes.skip_ws()?;
+
+ self.handle_struct_after_name(name, visitor)
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ name: &'static str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.newtype_variant = false;
+
+ match guard_recursion! { self => visitor.visit_enum(Enum::new(self)) } {
+ Ok(value) => Ok(value),
+ Err(Error::NoSuchEnumVariant {
+ expected,
+ found,
+ outer: None,
+ }) if !name.is_empty() => Err(Error::NoSuchEnumVariant {
+ expected,
+ found,
+ outer: Some(String::from(name)),
+ }),
+ Err(e) => Err(e),
+ }
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ let identifier = str::from_utf8(self.bytes.identifier()?).map_err(Error::from)?;
+
+ self.last_identifier = Some(identifier);
+
+ visitor.visit_borrowed_str(identifier)
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_any(visitor)
+ }
+}
+
+struct CommaSeparated<'a, 'de: 'a> {
+ de: &'a mut Deserializer<'de>,
+ terminator: u8,
+ had_comma: bool,
+}
+
+impl<'a, 'de> CommaSeparated<'a, 'de> {
+ fn new(terminator: u8, de: &'a mut Deserializer<'de>) -> Self {
+ CommaSeparated {
+ de,
+ terminator,
+ had_comma: true,
+ }
+ }
+
+ fn has_element(&mut self) -> Result<bool> {
+ self.de.bytes.skip_ws()?;
+
+ match (
+ self.had_comma,
+ self.de.bytes.peek_or_eof()? != self.terminator,
+ ) {
+ // Trailing comma, maybe has a next element
+ (true, has_element) => Ok(has_element),
+ // No trailing comma but terminator
+ (false, false) => Ok(false),
+ // No trailing comma or terminator
+ (false, true) => Err(Error::ExpectedComma),
+ }
+ }
+}
+
+impl<'de, 'a> de::SeqAccess<'de> for CommaSeparated<'a, 'de> {
+ type Error = Error;
+
+ fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ if self.has_element()? {
+ let res = guard_recursion! { self.de => seed.deserialize(&mut *self.de)? };
+
+ self.had_comma = self.de.bytes.comma()?;
+
+ Ok(Some(res))
+ } else {
+ Ok(None)
+ }
+ }
+}
+
+impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
+ type Error = Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
+ where
+ K: DeserializeSeed<'de>,
+ {
+ if self.has_element()? {
+ if self.terminator == b')' {
+ guard_recursion! { self.de =>
+ seed.deserialize(&mut IdDeserializer::new(&mut *self.de)).map(Some)
+ }
+ } else {
+ guard_recursion! { self.de => seed.deserialize(&mut *self.de).map(Some) }
+ }
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ self.de.bytes.skip_ws()?;
+
+ if self.de.bytes.consume(":") {
+ self.de.bytes.skip_ws()?;
+
+ let res = guard_recursion! { self.de =>
+ seed.deserialize(&mut TagDeserializer::new(&mut *self.de))?
+ };
+
+ self.had_comma = self.de.bytes.comma()?;
+
+ Ok(res)
+ } else {
+ Err(Error::ExpectedMapColon)
+ }
+ }
+}
+
+struct Enum<'a, 'de: 'a> {
+ de: &'a mut Deserializer<'de>,
+}
+
+impl<'a, 'de> Enum<'a, 'de> {
+ fn new(de: &'a mut Deserializer<'de>) -> Self {
+ Enum { de }
+ }
+}
+
+impl<'de, 'a> de::EnumAccess<'de> for Enum<'a, 'de> {
+ type Error = Error;
+ type Variant = Self;
+
+ fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ self.de.bytes.skip_ws()?;
+
+ let value = guard_recursion! { self.de => seed.deserialize(&mut *self.de)? };
+
+ Ok((value, self))
+ }
+}
+
+impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
+ type Error = Error;
+
+ fn unit_variant(self) -> Result<()> {
+ Ok(())
+ }
+
+ fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ let newtype_variant = self.de.last_identifier;
+
+ self.de.bytes.skip_ws()?;
+
+ if self.de.bytes.consume("(") {
+ self.de.bytes.skip_ws()?;
+
+ self.de.newtype_variant = self
+ .de
+ .bytes
+ .exts
+ .contains(Extensions::UNWRAP_VARIANT_NEWTYPES);
+
+ let val = guard_recursion! { self.de =>
+ seed
+ .deserialize(&mut *self.de)
+ .map_err(|err| struct_error_name(err, newtype_variant))?
+ };
+
+ self.de.newtype_variant = false;
+
+ self.de.bytes.comma()?;
+
+ if self.de.bytes.consume(")") {
+ Ok(val)
+ } else {
+ Err(Error::ExpectedStructLikeEnd)
+ }
+ } else {
+ Err(Error::ExpectedStructLike)
+ }
+ }
+
+ fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de.bytes.skip_ws()?;
+
+ self.de.deserialize_tuple(len, visitor)
+ }
+
+ fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ let struct_variant = self.de.last_identifier;
+
+ self.de.bytes.skip_ws()?;
+
+ self.de
+ .handle_struct_after_name("", visitor)
+ .map_err(|err| struct_error_name(err, struct_variant))
+ }
+}
+
+fn struct_error_name(error: Error, name: Option<&str>) -> Error {
+ match error {
+ Error::NoSuchStructField {
+ expected,
+ found,
+ outer: None,
+ } => Error::NoSuchStructField {
+ expected,
+ found,
+ outer: name.map(ToOwned::to_owned),
+ },
+ Error::MissingStructField { field, outer: None } => Error::MissingStructField {
+ field,
+ outer: name.map(ToOwned::to_owned),
+ },
+ Error::DuplicateStructField { field, outer: None } => Error::DuplicateStructField {
+ field,
+ outer: name.map(ToOwned::to_owned),
+ },
+ e => e,
+ }
+}
diff --git a/third_party/rust/ron/src/de/tag.rs b/third_party/rust/ron/src/de/tag.rs
new file mode 100644
index 0000000000..9e204ff847
--- /dev/null
+++ b/third_party/rust/ron/src/de/tag.rs
@@ -0,0 +1,251 @@
+use serde::de::{self, Visitor};
+
+use super::{Deserializer, Error, Result};
+
+pub struct TagDeserializer<'a, 'b: 'a> {
+ d: &'a mut Deserializer<'b>,
+}
+
+impl<'a, 'b: 'a> TagDeserializer<'a, 'b> {
+ pub fn new(d: &'a mut Deserializer<'b>) -> Self {
+ TagDeserializer { d }
+ }
+}
+
+impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut TagDeserializer<'a, 'b> {
+ type Error = Error;
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_str(visitor)
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.deserialize_str(visitor)
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_any(visitor)
+ }
+
+ fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_bool(visitor)
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_i8(visitor)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_i16(visitor)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_i32(visitor)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_i64(visitor)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_i128(visitor)
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_u8(visitor)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_u16(visitor)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_u32(visitor)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_u64(visitor)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_u128(visitor)
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_f32(visitor)
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_f64(visitor)
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_char(visitor)
+ }
+
+ fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_string(visitor)
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_bytes(visitor)
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_byte_buf(visitor)
+ }
+
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_option(visitor)
+ }
+
+ fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_unit(visitor)
+ }
+
+ fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_unit_struct(name, visitor)
+ }
+
+ fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_newtype_struct(name, visitor)
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_seq(visitor)
+ }
+
+ fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_tuple(len, visitor)
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ name: &'static str,
+ len: usize,
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_tuple_struct(name, len, visitor)
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_map(visitor)
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_struct(name, fields, visitor)
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ name: &'static str,
+ variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_enum(name, variants, visitor)
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ self.d.deserialize_ignored_any(visitor)
+ }
+}
diff --git a/third_party/rust/ron/src/de/tests.rs b/third_party/rust/ron/src/de/tests.rs
new file mode 100644
index 0000000000..2c46eb68f9
--- /dev/null
+++ b/third_party/rust/ron/src/de/tests.rs
@@ -0,0 +1,363 @@
+use serde_bytes;
+use serde_derive::Deserialize;
+
+use crate::{
+ de::from_str,
+ error::{Error, Position, SpannedError, SpannedResult},
+ parse::{AnyNum, Bytes},
+};
+
+#[derive(Debug, PartialEq, Deserialize)]
+struct EmptyStruct1;
+
+#[derive(Debug, PartialEq, Deserialize)]
+struct EmptyStruct2 {}
+
+#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
+struct MyStruct {
+ x: f32,
+ y: f32,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
+enum MyEnum {
+ A,
+ B(bool),
+ C(bool, f32),
+ D { a: i32, b: i32 },
+}
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct BytesStruct {
+ small: Vec<u8>,
+ #[serde(with = "serde_bytes")]
+ large: Vec<u8>,
+}
+
+#[test]
+fn test_empty_struct() {
+ assert_eq!(Ok(EmptyStruct1), from_str("EmptyStruct1"));
+ assert_eq!(Ok(EmptyStruct2 {}), from_str("EmptyStruct2()"));
+}
+
+#[test]
+fn test_struct() {
+ let my_struct = MyStruct { x: 4.0, y: 7.0 };
+
+ assert_eq!(Ok(my_struct), from_str("MyStruct(x:4,y:7,)"));
+ assert_eq!(Ok(my_struct), from_str("(x:4,y:7)"));
+
+ #[derive(Debug, PartialEq, Deserialize)]
+ struct NewType(i32);
+
+ assert_eq!(Ok(NewType(42)), from_str("NewType(42)"));
+ assert_eq!(Ok(NewType(33)), from_str("(33)"));
+
+ #[derive(Debug, PartialEq, Deserialize)]
+ struct TupleStruct(f32, f32);
+
+ assert_eq!(Ok(TupleStruct(2.0, 5.0)), from_str("TupleStruct(2,5,)"));
+ assert_eq!(Ok(TupleStruct(3.0, 4.0)), from_str("(3,4)"));
+}
+
+#[test]
+fn test_option() {
+ assert_eq!(Ok(Some(1u8)), from_str("Some(1)"));
+ assert_eq!(Ok(None::<u8>), from_str("None"));
+}
+
+#[test]
+fn test_enum() {
+ assert_eq!(Ok(MyEnum::A), from_str("A"));
+ assert_eq!(Ok(MyEnum::B(true)), from_str("B(true,)"));
+ assert_eq!(Ok(MyEnum::C(true, 3.5)), from_str("C(true,3.5,)"));
+ assert_eq!(Ok(MyEnum::D { a: 2, b: 3 }), from_str("D(a:2,b:3,)"));
+}
+
+#[test]
+fn test_array() {
+ let empty: [i32; 0] = [];
+ assert_eq!(Ok(empty), from_str("()"));
+ let empty_array = empty.to_vec();
+ assert_eq!(Ok(empty_array), from_str("[]"));
+
+ assert_eq!(Ok([2, 3, 4i32]), from_str("(2,3,4,)"));
+ assert_eq!(Ok([2, 3, 4i32].to_vec()), from_str("[2,3,4,]"));
+}
+
+#[test]
+fn test_map() {
+ use std::collections::HashMap;
+
+ let mut map = HashMap::new();
+ map.insert((true, false), 4);
+ map.insert((false, false), 123);
+
+ assert_eq!(
+ Ok(map),
+ from_str(
+ "{
+ (true,false,):4,
+ (false,false,):123,
+ }"
+ )
+ );
+}
+
+#[test]
+fn test_string() {
+ let s: String = from_str("\"String\"").unwrap();
+ assert_eq!("String", s);
+
+ let raw: String = from_str("r\"String\"").unwrap();
+ assert_eq!("String", raw);
+
+ let raw_hashes: String = from_str("r#\"String\"#").unwrap();
+ assert_eq!("String", raw_hashes);
+
+ let raw_hashes_multiline: String = from_str("r#\"String with\nmultiple\nlines\n\"#").unwrap();
+ assert_eq!("String with\nmultiple\nlines\n", raw_hashes_multiline);
+
+ let raw_hashes_quote: String = from_str("r##\"String with \"#\"##").unwrap();
+ assert_eq!("String with \"#", raw_hashes_quote);
+}
+
+#[test]
+fn test_char() {
+ assert_eq!(Ok('c'), from_str("'c'"));
+}
+
+#[test]
+fn test_escape_char() {
+ assert_eq!('\'', from_str::<char>("'\\''").unwrap());
+}
+
+#[test]
+fn test_escape() {
+ assert_eq!("\"Quoted\"", from_str::<String>(r#""\"Quoted\"""#).unwrap());
+}
+
+#[test]
+fn test_comment() {
+ assert_eq!(
+ MyStruct { x: 1.0, y: 2.0 },
+ from_str(
+ "(
+x: 1.0, // x is just 1
+// There is another comment in the very next line..
+// And y is indeed
+y: 2.0 // 2!
+ )"
+ )
+ .unwrap()
+ );
+}
+
+fn err<T>(kind: Error, line: usize, col: usize) -> SpannedResult<T> {
+ Err(SpannedError {
+ code: kind,
+ position: Position { line, col },
+ })
+}
+
+#[test]
+fn test_err_wrong_value() {
+ use std::collections::HashMap;
+
+ use self::Error::*;
+
+ assert_eq!(from_str::<f32>("'c'"), err(ExpectedFloat, 1, 1));
+ assert_eq!(from_str::<String>("'c'"), err(ExpectedString, 1, 1));
+ assert_eq!(from_str::<HashMap<u32, u32>>("'c'"), err(ExpectedMap, 1, 1));
+ assert_eq!(from_str::<[u8; 5]>("'c'"), err(ExpectedStructLike, 1, 1));
+ assert_eq!(from_str::<Vec<u32>>("'c'"), err(ExpectedArray, 1, 1));
+ assert_eq!(from_str::<MyEnum>("'c'"), err(ExpectedIdentifier, 1, 1));
+ assert_eq!(
+ from_str::<MyStruct>("'c'"),
+ err(ExpectedNamedStructLike("MyStruct"), 1, 1)
+ );
+ assert_eq!(
+ from_str::<MyStruct>("NotMyStruct(x: 4, y: 2)"),
+ err(
+ ExpectedDifferentStructName {
+ expected: "MyStruct",
+ found: String::from("NotMyStruct")
+ },
+ 1,
+ 12
+ )
+ );
+ assert_eq!(from_str::<(u8, bool)>("'c'"), err(ExpectedStructLike, 1, 1));
+ assert_eq!(from_str::<bool>("notabool"), err(ExpectedBoolean, 1, 1));
+
+ assert_eq!(
+ from_str::<MyStruct>("MyStruct(\n x: true)"),
+ err(ExpectedFloat, 2, 8)
+ );
+ assert_eq!(
+ from_str::<MyStruct>("MyStruct(\n x: 3.5, \n y:)"),
+ err(ExpectedFloat, 3, 7)
+ );
+}
+
+#[test]
+fn test_perm_ws() {
+ assert_eq!(
+ from_str::<MyStruct>("\nMyStruct \t ( \n x : 3.5 , \t y\n: 4.5 \n ) \t\n"),
+ Ok(MyStruct { x: 3.5, y: 4.5 })
+ );
+}
+
+#[test]
+fn untagged() {
+ #[derive(Deserialize, Debug, PartialEq)]
+ #[serde(untagged)]
+ enum Untagged {
+ U8(u8),
+ Bool(bool),
+ }
+
+ assert_eq!(from_str::<Untagged>("true").unwrap(), Untagged::Bool(true));
+ assert_eq!(from_str::<Untagged>("8").unwrap(), Untagged::U8(8));
+}
+
+#[test]
+fn rename() {
+ #[derive(Deserialize, Debug, PartialEq)]
+ enum Foo {
+ #[serde(rename = "2d")]
+ D2,
+ #[serde(rename = "triangle-list")]
+ TriangleList,
+ }
+ assert_eq!(from_str::<Foo>("r#2d").unwrap(), Foo::D2);
+ assert_eq!(
+ from_str::<Foo>("r#triangle-list").unwrap(),
+ Foo::TriangleList
+ );
+}
+
+#[test]
+fn forgot_apostrophes() {
+ let de: SpannedResult<(i32, String)> = from_str("(4, \"Hello)");
+
+ assert!(matches!(
+ de,
+ Err(SpannedError {
+ code: Error::ExpectedStringEnd,
+ position: _,
+ })
+ ));
+}
+
+#[test]
+fn expected_attribute() {
+ let de: SpannedResult<String> = from_str("#\"Hello\"");
+
+ assert_eq!(de, err(Error::ExpectedAttribute, 1, 2));
+}
+
+#[test]
+fn expected_attribute_end() {
+ let de: SpannedResult<String> = from_str("#![enable(unwrap_newtypes) \"Hello\"");
+
+ assert_eq!(de, err(Error::ExpectedAttributeEnd, 1, 28));
+}
+
+#[test]
+fn invalid_attribute() {
+ let de: SpannedResult<String> = from_str("#![enable(invalid)] \"Hello\"");
+
+ assert_eq!(
+ de,
+ err(Error::NoSuchExtension("invalid".to_string()), 1, 18)
+ );
+}
+
+#[test]
+fn multiple_attributes() {
+ #[derive(Debug, Deserialize, PartialEq)]
+ struct New(String);
+ let de: SpannedResult<New> =
+ from_str("#![enable(unwrap_newtypes)] #![enable(unwrap_newtypes)] \"Hello\"");
+
+ assert_eq!(de, Ok(New("Hello".to_owned())));
+}
+
+#[test]
+fn uglified_attribute() {
+ let de: SpannedResult<()> = from_str(
+ "# !\
+ // We definitely want to add a comment here
+ [\t\tenable( // best style ever
+ unwrap_newtypes ) ] ()",
+ );
+
+ assert_eq!(de, Ok(()));
+}
+
+#[test]
+fn implicit_some() {
+ use serde::de::DeserializeOwned;
+
+ fn de<T: DeserializeOwned>(s: &str) -> Option<T> {
+ let enable = "#![enable(implicit_some)]\n".to_string();
+
+ from_str::<Option<T>>(&(enable + s)).unwrap()
+ }
+
+ assert_eq!(de("'c'"), Some('c'));
+ assert_eq!(de("5"), Some(5));
+ assert_eq!(de("\"Hello\""), Some("Hello".to_owned()));
+ assert_eq!(de("false"), Some(false));
+ assert_eq!(
+ de("MyStruct(x: .4, y: .5)"),
+ Some(MyStruct { x: 0.4, y: 0.5 })
+ );
+
+ assert_eq!(de::<char>("None"), None);
+
+ // Not concise
+ assert_eq!(de::<Option<Option<char>>>("None"), None);
+}
+
+#[test]
+fn ws_tuple_newtype_variant() {
+ assert_eq!(Ok(MyEnum::B(true)), from_str("B ( \n true \n ) "));
+}
+
+#[test]
+fn test_byte_stream() {
+ assert_eq!(
+ Ok(BytesStruct {
+ small: vec![1, 2],
+ large: vec![1, 2, 3, 4]
+ }),
+ from_str("BytesStruct( small:[1, 2], large:\"AQIDBA==\" )"),
+ );
+}
+
+#[test]
+fn test_numbers() {
+ assert_eq!(
+ Ok(vec![1234, 12345, 123456, 1234567, 555_555]),
+ from_str("[1_234, 12_345, 1_2_3_4_5_6, 1_234_567, 5_55_55_5]"),
+ );
+}
+
+fn de_any_number(s: &str) -> AnyNum {
+ let mut bytes = Bytes::new(s.as_bytes()).unwrap();
+
+ bytes.any_num().unwrap()
+}
+
+#[test]
+fn test_any_number_precision() {
+ assert_eq!(de_any_number("1"), AnyNum::U8(1));
+ assert_eq!(de_any_number("+1"), AnyNum::I8(1));
+ assert_eq!(de_any_number("-1"), AnyNum::I8(-1));
+ assert_eq!(de_any_number("-1.0"), AnyNum::F32(-1.0));
+ assert_eq!(de_any_number("1."), AnyNum::F32(1.));
+ assert_eq!(de_any_number("-1."), AnyNum::F32(-1.));
+ assert_eq!(de_any_number("0.3"), AnyNum::F64(0.3));
+}
diff --git a/third_party/rust/ron/src/de/value.rs b/third_party/rust/ron/src/de/value.rs
new file mode 100644
index 0000000000..5883a37adc
--- /dev/null
+++ b/third_party/rust/ron/src/de/value.rs
@@ -0,0 +1,338 @@
+use std::fmt;
+
+use serde::{
+ de::{Error, MapAccess, SeqAccess, Visitor},
+ Deserialize, Deserializer,
+};
+
+use crate::{
+ error::SpannedResult,
+ value::{Map, Number, Value},
+};
+
+impl std::str::FromStr for Value {
+ type Err = crate::error::SpannedError;
+
+ /// Creates a value from a string reference.
+ fn from_str(s: &str) -> SpannedResult<Self> {
+ let mut de = super::Deserializer::from_str(s)?;
+
+ let val = Value::deserialize(&mut de).map_err(|e| de.span_error(e))?;
+ de.end().map_err(|e| de.span_error(e))?;
+
+ Ok(val)
+ }
+}
+
+impl<'de> Deserialize<'de> for Value {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_any(ValueVisitor)
+ }
+}
+
+struct ValueVisitor;
+
+impl<'de> Visitor<'de> for ValueVisitor {
+ type Value = Value;
+
+ fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "a RON value")
+ }
+
+ fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::Bool(v))
+ }
+
+ fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::Number(Number::new(v)))
+ }
+
+ #[cfg(feature = "integer128")]
+ fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ self.visit_f64(v as f64)
+ }
+
+ fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::Number(Number::new(v)))
+ }
+
+ #[cfg(feature = "integer128")]
+ fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ self.visit_f64(v as f64)
+ }
+
+ fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::Number(Number::new(v)))
+ }
+
+ fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::Char(v))
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ self.visit_string(v.to_owned())
+ }
+
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::String(v))
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ self.visit_byte_buf(v.to_vec())
+ }
+
+ fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ self.visit_string(String::from_utf8(v).map_err(|e| Error::custom(format!("{}", e)))?)
+ }
+
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::Option(None))
+ }
+
+ fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(Value::Option(Some(Box::new(
+ deserializer.deserialize_any(ValueVisitor)?,
+ ))))
+ }
+
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(Value::Unit)
+ }
+
+ fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_any(ValueVisitor)
+ }
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut vec = Vec::new();
+ if let Some(cap) = seq.size_hint() {
+ vec.reserve_exact(cap);
+ }
+
+ while let Some(x) = seq.next_element()? {
+ vec.push(x);
+ }
+
+ Ok(Value::Seq(vec))
+ }
+
+ fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ let mut res: Map = Map::new();
+
+ while let Some(entry) = map.next_entry()? {
+ res.insert(entry.0, entry.1);
+ }
+
+ Ok(Value::Map(res))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::str::FromStr;
+
+ use super::*;
+
+ fn eval(s: &str) -> Value {
+ s.parse().expect("Failed to parse")
+ }
+
+ #[test]
+ fn test_none() {
+ assert_eq!(eval("None"), Value::Option(None));
+ }
+
+ #[test]
+ fn test_some() {
+ assert_eq!(eval("Some(())"), Value::Option(Some(Box::new(Value::Unit))));
+ assert_eq!(
+ eval("Some ( () )"),
+ Value::Option(Some(Box::new(Value::Unit)))
+ );
+ }
+
+ #[test]
+ fn test_tuples_basic() {
+ assert_eq!(
+ eval("(3, 4.0, 5.0)"),
+ Value::Seq(vec![
+ Value::Number(Number::new(3)),
+ Value::Number(Number::new(4.0)),
+ Value::Number(Number::new(5.0)),
+ ],),
+ );
+ }
+
+ #[test]
+ fn test_tuples_ident() {
+ assert_eq!(
+ eval("(true, 3, 4, 5.0)"),
+ Value::Seq(vec![
+ Value::Bool(true),
+ Value::Number(Number::new(3)),
+ Value::Number(Number::new(4)),
+ Value::Number(Number::new(5.0)),
+ ]),
+ );
+ }
+
+ #[test]
+ fn test_tuples_error() {
+ use crate::de::{Error, Position, SpannedError};
+
+ assert_eq!(
+ Value::from_str("Foo:").unwrap_err(),
+ SpannedError {
+ code: Error::TrailingCharacters,
+ position: Position { col: 4, line: 1 }
+ },
+ );
+ }
+
+ #[test]
+ fn test_floats() {
+ assert_eq!(
+ eval("(inf, -inf, NaN)"),
+ Value::Seq(vec![
+ Value::Number(Number::new(std::f64::INFINITY)),
+ Value::Number(Number::new(std::f64::NEG_INFINITY)),
+ Value::Number(Number::new(std::f64::NAN)),
+ ]),
+ );
+ }
+
+ #[test]
+ fn test_complex() {
+ assert_eq!(
+ eval(
+ "Some([
+ Room ( width: 20, height: 5, name: \"The Room\" ),
+
+ (
+ width: 10.0,
+ height: 10.0,
+ name: \"Another room\",
+ enemy_levels: {
+ \"Enemy1\": 3,
+ \"Enemy2\": 5,
+ \"Enemy3\": 7,
+ },
+ ),
+])"
+ ),
+ Value::Option(Some(Box::new(Value::Seq(vec![
+ Value::Map(
+ vec![
+ (
+ Value::String("width".to_owned()),
+ Value::Number(Number::new(20)),
+ ),
+ (
+ Value::String("height".to_owned()),
+ Value::Number(Number::new(5)),
+ ),
+ (
+ Value::String("name".to_owned()),
+ Value::String("The Room".to_owned()),
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ ),
+ Value::Map(
+ vec![
+ (
+ Value::String("width".to_owned()),
+ Value::Number(Number::new(10.0)),
+ ),
+ (
+ Value::String("height".to_owned()),
+ Value::Number(Number::new(10.0)),
+ ),
+ (
+ Value::String("name".to_owned()),
+ Value::String("Another room".to_owned()),
+ ),
+ (
+ Value::String("enemy_levels".to_owned()),
+ Value::Map(
+ vec![
+ (
+ Value::String("Enemy1".to_owned()),
+ Value::Number(Number::new(3)),
+ ),
+ (
+ Value::String("Enemy2".to_owned()),
+ Value::Number(Number::new(5)),
+ ),
+ (
+ Value::String("Enemy3".to_owned()),
+ Value::Number(Number::new(7)),
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ ),
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ ),
+ ]))))
+ );
+ }
+}
diff --git a/third_party/rust/ron/src/error.rs b/third_party/rust/ron/src/error.rs
new file mode 100644
index 0000000000..406fb058c3
--- /dev/null
+++ b/third_party/rust/ron/src/error.rs
@@ -0,0 +1,445 @@
+use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
+
+use serde::{de, ser};
+
+use crate::parse::{is_ident_first_char, is_ident_other_char, is_ident_raw_char, BASE64_ENGINE};
+
+/// This type represents all possible errors that can occur when
+/// serializing or deserializing RON data.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct SpannedError {
+ pub code: Error,
+ pub position: Position,
+}
+
+pub type Result<T, E = Error> = std::result::Result<T, E>;
+pub type SpannedResult<T> = std::result::Result<T, SpannedError>;
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum Error {
+ Io(String),
+ Message(String),
+ Base64Error(base64::DecodeError),
+ Eof,
+ ExpectedArray,
+ ExpectedArrayEnd,
+ ExpectedAttribute,
+ ExpectedAttributeEnd,
+ ExpectedBoolean,
+ ExpectedComma,
+ ExpectedChar,
+ ExpectedFloat,
+ FloatUnderscore,
+ ExpectedInteger,
+ ExpectedOption,
+ ExpectedOptionEnd,
+ ExpectedMap,
+ ExpectedMapColon,
+ ExpectedMapEnd,
+ ExpectedDifferentStructName {
+ expected: &'static str,
+ found: String,
+ },
+ ExpectedStructLike,
+ ExpectedNamedStructLike(&'static str),
+ ExpectedStructLikeEnd,
+ ExpectedUnit,
+ ExpectedString,
+ ExpectedStringEnd,
+ ExpectedIdentifier,
+
+ InvalidEscape(&'static str),
+
+ IntegerOutOfBounds,
+
+ NoSuchExtension(String),
+
+ UnclosedBlockComment,
+ UnderscoreAtBeginning,
+ UnexpectedByte(char),
+
+ Utf8Error(Utf8Error),
+ TrailingCharacters,
+
+ InvalidValueForType {
+ expected: String,
+ found: String,
+ },
+ ExpectedDifferentLength {
+ expected: String,
+ found: usize,
+ },
+ NoSuchEnumVariant {
+ expected: &'static [&'static str],
+ found: String,
+ outer: Option<String>,
+ },
+ NoSuchStructField {
+ expected: &'static [&'static str],
+ found: String,
+ outer: Option<String>,
+ },
+ MissingStructField {
+ field: &'static str,
+ outer: Option<String>,
+ },
+ DuplicateStructField {
+ field: &'static str,
+ outer: Option<String>,
+ },
+ InvalidIdentifier(String),
+ SuggestRawIdentifier(String),
+ ExceededRecursionLimit,
+}
+
+impl fmt::Display for SpannedError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if (self.position == Position { line: 0, col: 0 }) {
+ write!(f, "{}", self.code)
+ } else {
+ write!(f, "{}: {}", self.position, self.code)
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Error::Io(ref s) => f.write_str(s),
+ Error::Message(ref s) => f.write_str(s),
+ Error::Base64Error(ref e) => fmt::Display::fmt(e, f),
+ Error::Eof => f.write_str("Unexpected end of RON"),
+ Error::ExpectedArray => f.write_str("Expected opening `[`"),
+ Error::ExpectedArrayEnd => f.write_str("Expected closing `]`"),
+ Error::ExpectedAttribute => f.write_str("Expected an `#![enable(...)]` attribute"),
+ Error::ExpectedAttributeEnd => {
+ f.write_str("Expected closing `)]` after the enable attribute")
+ }
+ Error::ExpectedBoolean => f.write_str("Expected boolean"),
+ Error::ExpectedComma => f.write_str("Expected comma"),
+ Error::ExpectedChar => f.write_str("Expected char"),
+ Error::ExpectedFloat => f.write_str("Expected float"),
+ Error::FloatUnderscore => f.write_str("Unexpected underscore in float"),
+ Error::ExpectedInteger => f.write_str("Expected integer"),
+ Error::ExpectedOption => f.write_str("Expected option"),
+ Error::ExpectedOptionEnd => f.write_str("Expected closing `)`"),
+ Error::ExpectedMap => f.write_str("Expected opening `{`"),
+ Error::ExpectedMapColon => f.write_str("Expected colon"),
+ Error::ExpectedMapEnd => f.write_str("Expected closing `}`"),
+ Error::ExpectedDifferentStructName {
+ expected,
+ ref found,
+ } => write!(
+ f,
+ "Expected struct {} but found {}",
+ Identifier(expected),
+ Identifier(found)
+ ),
+ Error::ExpectedStructLike => f.write_str("Expected opening `(`"),
+ Error::ExpectedNamedStructLike(name) => {
+ if name.is_empty() {
+ f.write_str("Expected only opening `(`, no name, for un-nameable struct")
+ } else {
+ write!(f, "Expected opening `(` for struct {}", Identifier(name))
+ }
+ }
+ Error::ExpectedStructLikeEnd => f.write_str("Expected closing `)`"),
+ Error::ExpectedUnit => f.write_str("Expected unit"),
+ Error::ExpectedString => f.write_str("Expected string"),
+ Error::ExpectedStringEnd => f.write_str("Expected end of string"),
+ Error::ExpectedIdentifier => f.write_str("Expected identifier"),
+ Error::InvalidEscape(s) => f.write_str(s),
+ Error::IntegerOutOfBounds => f.write_str("Integer is out of bounds"),
+ Error::NoSuchExtension(ref name) => {
+ write!(f, "No RON extension named {}", Identifier(name))
+ }
+ Error::Utf8Error(ref e) => fmt::Display::fmt(e, f),
+ Error::UnclosedBlockComment => f.write_str("Unclosed block comment"),
+ Error::UnderscoreAtBeginning => {
+ f.write_str("Unexpected leading underscore in an integer")
+ }
+ Error::UnexpectedByte(ref byte) => write!(f, "Unexpected byte {:?}", byte),
+ Error::TrailingCharacters => f.write_str("Non-whitespace trailing characters"),
+ Error::InvalidValueForType {
+ ref expected,
+ ref found,
+ } => {
+ write!(f, "Expected {} but found {} instead", expected, found)
+ }
+ Error::ExpectedDifferentLength {
+ ref expected,
+ found,
+ } => {
+ write!(f, "Expected {} but found ", expected)?;
+
+ match found {
+ 0 => f.write_str("zero elements")?,
+ 1 => f.write_str("one element")?,
+ n => write!(f, "{} elements", n)?,
+ }
+
+ f.write_str(" instead")
+ }
+ Error::NoSuchEnumVariant {
+ expected,
+ ref found,
+ ref outer,
+ } => {
+ f.write_str("Unexpected ")?;
+
+ if outer.is_none() {
+ f.write_str("enum ")?;
+ }
+
+ write!(f, "variant named {}", Identifier(found))?;
+
+ if let Some(outer) = outer {
+ write!(f, "in enum {}", Identifier(outer))?;
+ }
+
+ write!(
+ f,
+ ", {}",
+ OneOf {
+ alts: expected,
+ none: "variants"
+ }
+ )
+ }
+ Error::NoSuchStructField {
+ expected,
+ ref found,
+ ref outer,
+ } => {
+ write!(f, "Unexpected field named {}", Identifier(found))?;
+
+ if let Some(outer) = outer {
+ write!(f, "in {}", Identifier(outer))?;
+ }
+
+ write!(
+ f,
+ ", {}",
+ OneOf {
+ alts: expected,
+ none: "fields"
+ }
+ )
+ }
+ Error::MissingStructField { field, ref outer } => {
+ write!(f, "Unexpected missing field {}", Identifier(field))?;
+
+ match outer {
+ Some(outer) => write!(f, " in {}", Identifier(outer)),
+ None => Ok(()),
+ }
+ }
+ Error::DuplicateStructField { field, ref outer } => {
+ write!(f, "Unexpected duplicate field {}", Identifier(field))?;
+
+ match outer {
+ Some(outer) => write!(f, " in {}", Identifier(outer)),
+ None => Ok(()),
+ }
+ }
+ Error::InvalidIdentifier(ref invalid) => write!(f, "Invalid identifier {:?}", invalid),
+ Error::SuggestRawIdentifier(ref identifier) => write!(
+ f,
+ "Found invalid std identifier `{}`, try the raw identifier `r#{}` instead",
+ identifier, identifier
+ ),
+ Error::ExceededRecursionLimit => f.write_str("Exceeded recursion limit, try increasing the limit and using `serde_stacker` to protect against a stack overflow"),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct Position {
+ pub line: usize,
+ pub col: usize,
+}
+
+impl fmt::Display for Position {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}:{}", self.line, self.col)
+ }
+}
+
+impl ser::Error for Error {
+ #[cold]
+ fn custom<T: fmt::Display>(msg: T) -> Self {
+ Error::Message(msg.to_string())
+ }
+}
+
+impl de::Error for Error {
+ #[cold]
+ fn custom<T: fmt::Display>(msg: T) -> Self {
+ Error::Message(msg.to_string())
+ }
+
+ #[cold]
+ fn invalid_type(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self {
+ // Invalid type and invalid value are merged given their similarity in ron
+ Self::invalid_value(unexp, exp)
+ }
+
+ #[cold]
+ fn invalid_value(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self {
+ struct UnexpectedSerdeTypeValue<'a>(de::Unexpected<'a>);
+
+ impl<'a> fmt::Display for UnexpectedSerdeTypeValue<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use de::Unexpected::*;
+
+ match self.0 {
+ Bool(b) => write!(f, "the boolean `{}`", b),
+ Unsigned(i) => write!(f, "the unsigned integer `{}`", i),
+ Signed(i) => write!(f, "the signed integer `{}`", i),
+ Float(n) => write!(f, "the floating point number `{}`", n),
+ Char(c) => write!(f, "the UTF-8 character `{}`", c),
+ Str(s) => write!(f, "the string {:?}", s),
+ Bytes(b) => write!(f, "the bytes \"{}\"", {
+ base64::display::Base64Display::new(b, &BASE64_ENGINE)
+ }),
+ Unit => write!(f, "a unit value"),
+ Option => write!(f, "an optional value"),
+ NewtypeStruct => write!(f, "a newtype struct"),
+ Seq => write!(f, "a sequence"),
+ Map => write!(f, "a map"),
+ Enum => write!(f, "an enum"),
+ UnitVariant => write!(f, "a unit variant"),
+ NewtypeVariant => write!(f, "a newtype variant"),
+ TupleVariant => write!(f, "a tuple variant"),
+ StructVariant => write!(f, "a struct variant"),
+ Other(other) => f.write_str(other),
+ }
+ }
+ }
+
+ Error::InvalidValueForType {
+ expected: exp.to_string(),
+ found: UnexpectedSerdeTypeValue(unexp).to_string(),
+ }
+ }
+
+ #[cold]
+ fn invalid_length(len: usize, exp: &dyn de::Expected) -> Self {
+ Error::ExpectedDifferentLength {
+ expected: exp.to_string(),
+ found: len,
+ }
+ }
+
+ #[cold]
+ fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
+ Error::NoSuchEnumVariant {
+ expected,
+ found: variant.to_string(),
+ outer: None,
+ }
+ }
+
+ #[cold]
+ fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
+ Error::NoSuchStructField {
+ expected,
+ found: field.to_string(),
+ outer: None,
+ }
+ }
+
+ #[cold]
+ fn missing_field(field: &'static str) -> Self {
+ Error::MissingStructField { field, outer: None }
+ }
+
+ #[cold]
+ fn duplicate_field(field: &'static str) -> Self {
+ Error::DuplicateStructField { field, outer: None }
+ }
+}
+
+impl StdError for SpannedError {}
+impl StdError for Error {}
+
+impl From<Utf8Error> for Error {
+ fn from(e: Utf8Error) -> Self {
+ Error::Utf8Error(e)
+ }
+}
+
+impl From<FromUtf8Error> for Error {
+ fn from(e: FromUtf8Error) -> Self {
+ Error::Utf8Error(e.utf8_error())
+ }
+}
+
+impl From<io::Error> for Error {
+ fn from(e: io::Error) -> Self {
+ Error::Io(e.to_string())
+ }
+}
+
+impl From<io::Error> for SpannedError {
+ fn from(e: io::Error) -> Self {
+ SpannedError {
+ code: e.into(),
+ position: Position { line: 0, col: 0 },
+ }
+ }
+}
+
+impl From<SpannedError> for Error {
+ fn from(e: SpannedError) -> Self {
+ e.code
+ }
+}
+
+struct OneOf {
+ alts: &'static [&'static str],
+ none: &'static str,
+}
+
+impl fmt::Display for OneOf {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.alts {
+ [] => write!(f, "there are no {}", self.none),
+ [a1] => write!(f, "expected {} instead", Identifier(a1)),
+ [a1, a2] => write!(
+ f,
+ "expected either {} or {} instead",
+ Identifier(a1),
+ Identifier(a2)
+ ),
+ [a1, ref alts @ ..] => {
+ write!(f, "expected one of {}", Identifier(a1))?;
+
+ for alt in alts {
+ write!(f, ", {}", Identifier(alt))?;
+ }
+
+ f.write_str(" instead")
+ }
+ }
+ }
+}
+
+struct Identifier<'a>(&'a str);
+
+impl<'a> fmt::Display for Identifier<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.0.is_empty() || !self.0.as_bytes().iter().copied().all(is_ident_raw_char) {
+ return write!(f, "{:?}_[invalid identifier]", self.0);
+ }
+
+ let mut bytes = self.0.as_bytes().iter().copied();
+
+ if !bytes.next().map_or(false, is_ident_first_char) || !bytes.all(is_ident_other_char) {
+ write!(f, "`r#{}`", self.0)
+ } else {
+ write!(f, "`{}`", self.0)
+ }
+ }
+}
diff --git a/third_party/rust/ron/src/extensions.rs b/third_party/rust/ron/src/extensions.rs
new file mode 100644
index 0000000000..0455a34dd3
--- /dev/null
+++ b/third_party/rust/ron/src/extensions.rs
@@ -0,0 +1,55 @@
+use serde_derive::{Deserialize, Serialize};
+
+bitflags::bitflags! {
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
+ pub struct Extensions: usize {
+ const UNWRAP_NEWTYPES = 0x1;
+ const IMPLICIT_SOME = 0x2;
+ const UNWRAP_VARIANT_NEWTYPES = 0x4;
+ }
+}
+
+impl Extensions {
+ /// Creates an extension flag from an ident.
+ pub fn from_ident(ident: &[u8]) -> Option<Extensions> {
+ match ident {
+ b"unwrap_newtypes" => Some(Extensions::UNWRAP_NEWTYPES),
+ b"implicit_some" => Some(Extensions::IMPLICIT_SOME),
+ b"unwrap_variant_newtypes" => Some(Extensions::UNWRAP_VARIANT_NEWTYPES),
+ _ => None,
+ }
+ }
+}
+
+impl Default for Extensions {
+ fn default() -> Self {
+ Extensions::empty()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Extensions;
+
+ fn roundtrip_extensions(ext: Extensions) {
+ let ron = crate::to_string(&ext).unwrap();
+ let ext2: Extensions = crate::from_str(&ron).unwrap();
+ assert_eq!(ext, ext2);
+ }
+
+ #[test]
+ fn test_extension_serde() {
+ roundtrip_extensions(Extensions::default());
+ roundtrip_extensions(Extensions::UNWRAP_NEWTYPES);
+ roundtrip_extensions(Extensions::IMPLICIT_SOME);
+ roundtrip_extensions(Extensions::UNWRAP_VARIANT_NEWTYPES);
+ roundtrip_extensions(Extensions::UNWRAP_NEWTYPES | Extensions::IMPLICIT_SOME);
+ roundtrip_extensions(Extensions::UNWRAP_NEWTYPES | Extensions::UNWRAP_VARIANT_NEWTYPES);
+ roundtrip_extensions(Extensions::IMPLICIT_SOME | Extensions::UNWRAP_VARIANT_NEWTYPES);
+ roundtrip_extensions(
+ Extensions::UNWRAP_NEWTYPES
+ | Extensions::IMPLICIT_SOME
+ | Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ }
+}
diff --git a/third_party/rust/ron/src/lib.rs b/third_party/rust/ron/src/lib.rs
new file mode 100644
index 0000000000..638af2cb07
--- /dev/null
+++ b/third_party/rust/ron/src/lib.rs
@@ -0,0 +1,20 @@
+#![doc = include_str!("../README.md")]
+#![doc(html_root_url = "https://docs.rs/ron/0.8.1")]
+
+pub mod de;
+pub mod ser;
+
+pub mod error;
+pub mod value;
+
+pub mod extensions;
+
+pub mod options;
+
+pub use de::{from_str, Deserializer};
+pub use error::{Error, Result};
+pub use options::Options;
+pub use ser::{to_string, Serializer};
+pub use value::{Map, Number, Value};
+
+mod parse;
diff --git a/third_party/rust/ron/src/options.rs b/third_party/rust/ron/src/options.rs
new file mode 100644
index 0000000000..b0c5816bd4
--- /dev/null
+++ b/third_party/rust/ron/src/options.rs
@@ -0,0 +1,215 @@
+//! Roundtrip serde Options module.
+
+use std::io;
+
+use serde::{de, ser};
+use serde_derive::{Deserialize, Serialize};
+
+use crate::{
+ de::Deserializer,
+ error::{Result, SpannedResult},
+ extensions::Extensions,
+ ser::{PrettyConfig, Serializer},
+};
+
+/// Roundtrip serde options.
+///
+/// # Examples
+///
+/// ```
+/// use ron::{Options, extensions::Extensions};
+///
+/// let ron = Options::default()
+/// .with_default_extension(Extensions::IMPLICIT_SOME);
+///
+/// let de: Option<i32> = ron.from_str("42").unwrap();
+/// let ser = ron.to_string(&de).unwrap();
+///
+/// assert_eq!(ser, "42");
+/// ```
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(default)]
+#[non_exhaustive]
+pub struct Options {
+ /// Extensions that are enabled by default during serialization and
+ /// deserialization.
+ /// During serialization, these extensions do NOT have to be explicitly
+ /// enabled in the parsed RON.
+ /// During deserialization, these extensions are used, but their explicit
+ /// activation is NOT included in the output RON.
+ /// No extensions are enabled by default.
+ pub default_extensions: Extensions,
+ /// Default recursion limit that is checked during serialization and
+ /// deserialization.
+ /// If set to `None`, infinite recursion is allowed and stack overflow
+ /// errors can crash the serialization or deserialization process.
+ /// Defaults to `Some(128)`, i.e. 128 recursive calls are allowed.
+ pub recursion_limit: Option<usize>,
+}
+
+impl Default for Options {
+ fn default() -> Self {
+ Self {
+ default_extensions: Extensions::empty(),
+ recursion_limit: Some(128),
+ }
+ }
+}
+
+impl Options {
+ #[must_use]
+ /// Enable `default_extension` by default during serialization and deserialization.
+ pub fn with_default_extension(mut self, default_extension: Extensions) -> Self {
+ self.default_extensions |= default_extension;
+ self
+ }
+
+ #[must_use]
+ /// Do NOT enable `default_extension` by default during serialization and deserialization.
+ pub fn without_default_extension(mut self, default_extension: Extensions) -> Self {
+ self.default_extensions &= !default_extension;
+ self
+ }
+
+ #[must_use]
+ /// Set a maximum recursion limit during serialization and deserialization.
+ pub fn with_recursion_limit(mut self, recursion_limit: usize) -> Self {
+ self.recursion_limit = Some(recursion_limit);
+ self
+ }
+
+ #[must_use]
+ /// Disable the recursion limit during serialization and deserialization.
+ ///
+ /// If you expect to handle highly recursive datastructures, consider wrapping
+ /// `ron` with [`serde_stacker`](https://docs.rs/serde_stacker/latest/serde_stacker/).
+ pub fn without_recursion_limit(mut self) -> Self {
+ self.recursion_limit = None;
+ self
+ }
+}
+
+impl Options {
+ /// A convenience function for building a deserializer
+ /// and deserializing a value of type `T` from a reader.
+ pub fn from_reader<R, T>(&self, mut rdr: R) -> SpannedResult<T>
+ where
+ R: io::Read,
+ T: de::DeserializeOwned,
+ {
+ let mut bytes = Vec::new();
+ rdr.read_to_end(&mut bytes)?;
+
+ self.from_bytes(&bytes)
+ }
+
+ /// A convenience function for building a deserializer
+ /// and deserializing a value of type `T` from a string.
+ pub fn from_str<'a, T>(&self, s: &'a str) -> SpannedResult<T>
+ where
+ T: de::Deserialize<'a>,
+ {
+ self.from_bytes(s.as_bytes())
+ }
+
+ /// A convenience function for building a deserializer
+ /// and deserializing a value of type `T` from bytes.
+ pub fn from_bytes<'a, T>(&self, s: &'a [u8]) -> SpannedResult<T>
+ where
+ T: de::Deserialize<'a>,
+ {
+ self.from_bytes_seed(s, std::marker::PhantomData)
+ }
+
+ /// A convenience function for building a deserializer
+ /// and deserializing a value of type `T` from a reader
+ /// and a seed.
+ pub fn from_reader_seed<R, S, T>(&self, mut rdr: R, seed: S) -> SpannedResult<T>
+ where
+ R: io::Read,
+ S: for<'a> de::DeserializeSeed<'a, Value = T>,
+ {
+ let mut bytes = Vec::new();
+ rdr.read_to_end(&mut bytes)?;
+
+ self.from_bytes_seed(&bytes, seed)
+ }
+
+ /// A convenience function for building a deserializer
+ /// and deserializing a value of type `T` from a string
+ /// and a seed.
+ pub fn from_str_seed<'a, S, T>(&self, s: &'a str, seed: S) -> SpannedResult<T>
+ where
+ S: de::DeserializeSeed<'a, Value = T>,
+ {
+ self.from_bytes_seed(s.as_bytes(), seed)
+ }
+
+ /// A convenience function for building a deserializer
+ /// and deserializing a value of type `T` from bytes
+ /// and a seed.
+ pub fn from_bytes_seed<'a, S, T>(&self, s: &'a [u8], seed: S) -> SpannedResult<T>
+ where
+ S: de::DeserializeSeed<'a, Value = T>,
+ {
+ let mut deserializer = Deserializer::from_bytes_with_options(s, self.clone())?;
+
+ let value = seed
+ .deserialize(&mut deserializer)
+ .map_err(|e| deserializer.span_error(e))?;
+
+ deserializer.end().map_err(|e| deserializer.span_error(e))?;
+
+ Ok(value)
+ }
+
+ /// Serializes `value` into `writer`.
+ ///
+ /// This function does not generate any newlines or nice formatting;
+ /// if you want that, you can use
+ /// [`to_writer_pretty`][Self::to_writer_pretty] instead.
+ pub fn to_writer<W, T>(&self, writer: W, value: &T) -> Result<()>
+ where
+ W: io::Write,
+ T: ?Sized + ser::Serialize,
+ {
+ let mut s = Serializer::with_options(writer, None, self.clone())?;
+ value.serialize(&mut s)
+ }
+
+ /// Serializes `value` into `writer` in a pretty way.
+ pub fn to_writer_pretty<W, T>(&self, writer: W, value: &T, config: PrettyConfig) -> Result<()>
+ where
+ W: io::Write,
+ T: ?Sized + ser::Serialize,
+ {
+ let mut s = Serializer::with_options(writer, Some(config), self.clone())?;
+ value.serialize(&mut s)
+ }
+
+ /// Serializes `value` and returns it as string.
+ ///
+ /// This function does not generate any newlines or nice formatting;
+ /// if you want that, you can use
+ /// [`to_string_pretty`][Self::to_string_pretty] instead.
+ pub fn to_string<T>(&self, value: &T) -> Result<String>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ let mut output = Vec::new();
+ let mut s = Serializer::with_options(&mut output, None, self.clone())?;
+ value.serialize(&mut s)?;
+ Ok(String::from_utf8(output).expect("Ron should be utf-8"))
+ }
+
+ /// Serializes `value` in the recommended RON layout in a pretty way.
+ pub fn to_string_pretty<T>(&self, value: &T, config: PrettyConfig) -> Result<String>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ let mut output = Vec::new();
+ let mut s = Serializer::with_options(&mut output, Some(config), self.clone())?;
+ value.serialize(&mut s)?;
+ Ok(String::from_utf8(output).expect("Ron should be utf-8"))
+ }
+}
diff --git a/third_party/rust/ron/src/parse.rs b/third_party/rust/ron/src/parse.rs
new file mode 100644
index 0000000000..bed7f44916
--- /dev/null
+++ b/third_party/rust/ron/src/parse.rs
@@ -0,0 +1,1008 @@
+#![allow(clippy::identity_op)]
+
+use std::{
+ char::from_u32 as char_from_u32,
+ str::{from_utf8, from_utf8_unchecked, FromStr},
+};
+
+use base64::engine::general_purpose::{GeneralPurpose, STANDARD};
+
+use crate::{
+ error::{Error, Position, Result, SpannedError, SpannedResult},
+ extensions::Extensions,
+};
+
+pub const BASE64_ENGINE: GeneralPurpose = STANDARD;
+
+// We have the following char categories.
+const INT_CHAR: u8 = 1 << 0; // [0-9A-Fa-f_]
+const FLOAT_CHAR: u8 = 1 << 1; // [0-9\.Ee+-_]
+const IDENT_FIRST_CHAR: u8 = 1 << 2; // [A-Za-z_]
+const IDENT_OTHER_CHAR: u8 = 1 << 3; // [A-Za-z_0-9]
+const IDENT_RAW_CHAR: u8 = 1 << 4; // [A-Za-z_0-9\.+-]
+const WHITESPACE_CHAR: u8 = 1 << 5; // [\n\t\r ]
+
+// We encode each char as belonging to some number of these categories.
+const DIGIT: u8 = INT_CHAR | FLOAT_CHAR | IDENT_OTHER_CHAR | IDENT_RAW_CHAR; // [0-9]
+const ABCDF: u8 = INT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR | IDENT_RAW_CHAR; // [ABCDFabcdf]
+const UNDER: u8 = INT_CHAR | FLOAT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR | IDENT_RAW_CHAR; // [_]
+const E____: u8 = INT_CHAR | FLOAT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR | IDENT_RAW_CHAR; // [Ee]
+const G2Z__: u8 = IDENT_FIRST_CHAR | IDENT_OTHER_CHAR | IDENT_RAW_CHAR; // [G-Zg-z]
+const PUNCT: u8 = FLOAT_CHAR | IDENT_RAW_CHAR; // [\.+-]
+const WS___: u8 = WHITESPACE_CHAR; // [\t\n\r ]
+const _____: u8 = 0; // everything else
+
+// Table of encodings, for fast predicates. (Non-ASCII and special chars are
+// shown with '·' in the comment.)
+#[rustfmt::skip]
+const ENCODINGS: [u8; 256] = [
+/* 0 1 2 3 4 5 6 7 8 9 */
+/* 0+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, WS___,
+/* 10+: ·········· */ WS___, _____, _____, WS___, _____, _____, _____, _____, _____, _____,
+/* 20+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 30+: ·· !"#$%&' */ _____, _____, WS___, _____, _____, _____, _____, _____, _____, _____,
+/* 40+: ()*+,-./01 */ _____, _____, _____, PUNCT, _____, PUNCT, PUNCT, _____, DIGIT, DIGIT,
+/* 50+: 23456789:; */ DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, _____, _____,
+/* 60+: <=>?@ABCDE */ _____, _____, _____, _____, _____, ABCDF, ABCDF, ABCDF, ABCDF, E____,
+/* 70+: FGHIJKLMNO */ ABCDF, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
+/* 80+: PQRSTUVWZY */ G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
+/* 90+: Z[\]^_`abc */ G2Z__, _____, _____, _____, _____, UNDER, _____, ABCDF, ABCDF, ABCDF,
+/* 100+: defghijklm */ ABCDF, E____, ABCDF, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
+/* 110+: nopqrstuvw */ G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
+/* 120+: xyz{|}~··· */ G2Z__, G2Z__, G2Z__, _____, _____, _____, _____, _____, _____, _____,
+/* 130+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 140+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 150+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 160+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 170+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 180+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 190+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 200+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 210+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 220+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 230+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 240+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
+/* 250+: ·········· */ _____, _____, _____, _____, _____, _____
+];
+
+const fn is_int_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & INT_CHAR != 0
+}
+
+const fn is_float_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & FLOAT_CHAR != 0
+}
+
+pub const fn is_ident_first_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & IDENT_FIRST_CHAR != 0
+}
+
+pub const fn is_ident_other_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & IDENT_OTHER_CHAR != 0
+}
+
+pub const fn is_ident_raw_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & IDENT_RAW_CHAR != 0
+}
+
+const fn is_whitespace_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & WHITESPACE_CHAR != 0
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum AnyNum {
+ F32(f32),
+ F64(f64),
+ I8(i8),
+ U8(u8),
+ I16(i16),
+ U16(u16),
+ I32(i32),
+ U32(u32),
+ I64(i64),
+ U64(u64),
+ #[cfg(feature = "integer128")]
+ I128(i128),
+ #[cfg(feature = "integer128")]
+ U128(u128),
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct Bytes<'a> {
+ /// Bits set according to the [`Extensions`] enum.
+ pub exts: Extensions,
+ bytes: &'a [u8],
+ cursor: Position,
+}
+
+#[cfg(feature = "integer128")]
+pub(crate) type LargeUInt = u128;
+#[cfg(not(feature = "integer128"))]
+pub(crate) type LargeUInt = u64;
+#[cfg(feature = "integer128")]
+pub(crate) type LargeSInt = i128;
+#[cfg(not(feature = "integer128"))]
+pub(crate) type LargeSInt = i64;
+
+impl<'a> Bytes<'a> {
+ pub fn new(bytes: &'a [u8]) -> SpannedResult<Self> {
+ let mut b = Bytes {
+ exts: Extensions::empty(),
+ bytes,
+ cursor: Position { line: 1, col: 1 },
+ };
+
+ b.skip_ws().map_err(|e| b.span_error(e))?;
+
+ // Loop over all extensions attributes
+ loop {
+ let attribute = b.extensions().map_err(|e| b.span_error(e))?;
+
+ if attribute.is_empty() {
+ break;
+ }
+
+ b.exts |= attribute;
+ b.skip_ws().map_err(|e| b.span_error(e))?;
+ }
+
+ Ok(b)
+ }
+
+ pub fn span_error(&self, code: Error) -> SpannedError {
+ SpannedError {
+ code,
+ position: self.cursor,
+ }
+ }
+
+ pub fn advance(&mut self, bytes: usize) -> Result<()> {
+ for _ in 0..bytes {
+ self.advance_single()?;
+ }
+
+ Ok(())
+ }
+
+ pub fn advance_single(&mut self) -> Result<()> {
+ if self.peek_or_eof()? == b'\n' {
+ self.cursor.line += 1;
+ self.cursor.col = 1;
+ } else {
+ self.cursor.col += 1;
+ }
+
+ self.bytes = &self.bytes[1..];
+
+ Ok(())
+ }
+
+ fn any_integer<T: Num>(&mut self, sign: i8) -> Result<T> {
+ let base = if self.peek() == Some(b'0') {
+ match self.bytes.get(1).copied() {
+ Some(b'x') => 16,
+ Some(b'b') => 2,
+ Some(b'o') => 8,
+ _ => 10,
+ }
+ } else {
+ 10
+ };
+
+ if base != 10 {
+ // If we have `0x45A` for example,
+ // cut it to `45A`.
+ let _ = self.advance(2);
+ }
+
+ let num_bytes = self.next_bytes_contained_in(is_int_char);
+
+ if num_bytes == 0 {
+ return Err(Error::ExpectedInteger);
+ }
+
+ let s = unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) };
+
+ if s.as_bytes()[0] == b'_' {
+ return Err(Error::UnderscoreAtBeginning);
+ }
+
+ fn calc_num<T: Num>(
+ bytes: &Bytes,
+ s: &str,
+ base: u8,
+ mut f: impl FnMut(&mut T, u8) -> bool,
+ ) -> Result<T> {
+ let mut num_acc = T::from_u8(0);
+
+ for &byte in s.as_bytes() {
+ if byte == b'_' {
+ continue;
+ }
+
+ if num_acc.checked_mul_ext(base) {
+ return Err(Error::IntegerOutOfBounds);
+ }
+
+ let digit = bytes.decode_hex(byte)?;
+
+ if digit >= base {
+ return Err(Error::ExpectedInteger);
+ }
+
+ if f(&mut num_acc, digit) {
+ return Err(Error::IntegerOutOfBounds);
+ }
+ }
+
+ Ok(num_acc)
+ }
+
+ let res = if sign > 0 {
+ calc_num(self, s, base, T::checked_add_ext)
+ } else {
+ calc_num(self, s, base, T::checked_sub_ext)
+ };
+
+ let _ = self.advance(num_bytes);
+
+ res
+ }
+
+ pub fn any_num(&mut self) -> Result<AnyNum> {
+ // We are not doing float comparisons here in the traditional sense.
+ // Instead, this code checks if a f64 fits inside an f32.
+ #[allow(clippy::float_cmp)]
+ fn any_float(f: f64) -> Result<AnyNum> {
+ if f == f64::from(f as f32) {
+ Ok(AnyNum::F32(f as f32))
+ } else {
+ Ok(AnyNum::F64(f))
+ }
+ }
+
+ let bytes_backup = self.bytes;
+
+ let first_byte = self.peek_or_eof()?;
+ let is_signed = first_byte == b'-' || first_byte == b'+';
+ let is_float = self.next_bytes_is_float();
+
+ if is_float {
+ let f = self.float::<f64>()?;
+
+ any_float(f)
+ } else {
+ let max_u8 = LargeUInt::from(std::u8::MAX);
+ let max_u16 = LargeUInt::from(std::u16::MAX);
+ let max_u32 = LargeUInt::from(std::u32::MAX);
+ #[cfg_attr(not(feature = "integer128"), allow(clippy::useless_conversion))]
+ let max_u64 = LargeUInt::from(std::u64::MAX);
+
+ let min_i8 = LargeSInt::from(std::i8::MIN);
+ let max_i8 = LargeSInt::from(std::i8::MAX);
+ let min_i16 = LargeSInt::from(std::i16::MIN);
+ let max_i16 = LargeSInt::from(std::i16::MAX);
+ let min_i32 = LargeSInt::from(std::i32::MIN);
+ let max_i32 = LargeSInt::from(std::i32::MAX);
+ #[cfg_attr(not(feature = "integer128"), allow(clippy::useless_conversion))]
+ let min_i64 = LargeSInt::from(std::i64::MIN);
+ #[cfg_attr(not(feature = "integer128"), allow(clippy::useless_conversion))]
+ let max_i64 = LargeSInt::from(std::i64::MAX);
+
+ if is_signed {
+ match self.signed_integer::<LargeSInt>() {
+ Ok(x) => {
+ if x >= min_i8 && x <= max_i8 {
+ Ok(AnyNum::I8(x as i8))
+ } else if x >= min_i16 && x <= max_i16 {
+ Ok(AnyNum::I16(x as i16))
+ } else if x >= min_i32 && x <= max_i32 {
+ Ok(AnyNum::I32(x as i32))
+ } else if x >= min_i64 && x <= max_i64 {
+ Ok(AnyNum::I64(x as i64))
+ } else {
+ #[cfg(feature = "integer128")]
+ {
+ Ok(AnyNum::I128(x))
+ }
+ #[cfg(not(feature = "integer128"))]
+ {
+ Ok(AnyNum::I64(x))
+ }
+ }
+ }
+ Err(_) => {
+ self.bytes = bytes_backup;
+
+ any_float(self.float::<f64>()?)
+ }
+ }
+ } else {
+ match self.unsigned_integer::<LargeUInt>() {
+ Ok(x) => {
+ if x <= max_u8 {
+ Ok(AnyNum::U8(x as u8))
+ } else if x <= max_u16 {
+ Ok(AnyNum::U16(x as u16))
+ } else if x <= max_u32 {
+ Ok(AnyNum::U32(x as u32))
+ } else if x <= max_u64 {
+ Ok(AnyNum::U64(x as u64))
+ } else {
+ #[cfg(feature = "integer128")]
+ {
+ Ok(AnyNum::U128(x))
+ }
+ #[cfg(not(feature = "integer128"))]
+ {
+ Ok(AnyNum::U64(x))
+ }
+ }
+ }
+ Err(_) => {
+ self.bytes = bytes_backup;
+
+ any_float(self.float::<f64>()?)
+ }
+ }
+ }
+ }
+ }
+
+ pub fn bool(&mut self) -> Result<bool> {
+ if self.consume("true") {
+ Ok(true)
+ } else if self.consume("false") {
+ Ok(false)
+ } else {
+ Err(Error::ExpectedBoolean)
+ }
+ }
+
+ pub fn bytes(&self) -> &[u8] {
+ self.bytes
+ }
+
+ pub fn char(&mut self) -> Result<char> {
+ if !self.consume("'") {
+ return Err(Error::ExpectedChar);
+ }
+
+ let c = self.peek_or_eof()?;
+
+ let c = if c == b'\\' {
+ let _ = self.advance(1);
+
+ self.parse_escape()?
+ } else {
+ // Check where the end of the char (') is and try to
+ // interpret the rest as UTF-8
+
+ let max = self.bytes.len().min(5);
+ let pos: usize = self.bytes[..max]
+ .iter()
+ .position(|&x| x == b'\'')
+ .ok_or(Error::ExpectedChar)?;
+ let s = from_utf8(&self.bytes[0..pos]).map_err(Error::from)?;
+ let mut chars = s.chars();
+
+ let first = chars.next().ok_or(Error::ExpectedChar)?;
+ if chars.next().is_some() {
+ return Err(Error::ExpectedChar);
+ }
+
+ let _ = self.advance(pos);
+
+ first
+ };
+
+ if !self.consume("'") {
+ return Err(Error::ExpectedChar);
+ }
+
+ Ok(c)
+ }
+
+ pub fn comma(&mut self) -> Result<bool> {
+ self.skip_ws()?;
+
+ if self.consume(",") {
+ self.skip_ws()?;
+
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+
+ /// Only returns true if the char after `ident` cannot belong
+ /// to an identifier.
+ pub fn check_ident(&mut self, ident: &str) -> bool {
+ self.test_for(ident) && !self.check_ident_other_char(ident.len())
+ }
+
+ fn check_ident_other_char(&self, index: usize) -> bool {
+ self.bytes
+ .get(index)
+ .map_or(false, |&b| is_ident_other_char(b))
+ }
+
+ /// Should only be used on a working copy
+ pub fn check_tuple_struct(mut self) -> Result<bool> {
+ if self.identifier().is_err() {
+ // if there's no field ident, this is a tuple struct
+ return Ok(true);
+ }
+
+ self.skip_ws()?;
+
+ // if there is no colon after the ident, this can only be a unit struct
+ self.eat_byte().map(|c| c != b':')
+ }
+
+ /// Only returns true if the char after `ident` cannot belong
+ /// to an identifier.
+ pub fn consume_ident(&mut self, ident: &str) -> bool {
+ if self.check_ident(ident) {
+ let _ = self.advance(ident.len());
+
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn consume_struct_name(&mut self, ident: &'static str) -> Result<bool> {
+ if self.check_ident("") {
+ return Ok(false);
+ }
+
+ let found_ident = match self.identifier() {
+ Ok(maybe_ident) => std::str::from_utf8(maybe_ident)?,
+ Err(Error::SuggestRawIdentifier(found_ident)) if found_ident == ident => {
+ return Err(Error::SuggestRawIdentifier(found_ident))
+ }
+ Err(_) => return Err(Error::ExpectedNamedStructLike(ident)),
+ };
+
+ if found_ident != ident {
+ return Err(Error::ExpectedDifferentStructName {
+ expected: ident,
+ found: String::from(found_ident),
+ });
+ }
+
+ Ok(true)
+ }
+
+ pub fn consume(&mut self, s: &str) -> bool {
+ if self.test_for(s) {
+ let _ = self.advance(s.len());
+
+ true
+ } else {
+ false
+ }
+ }
+
+ fn consume_all(&mut self, all: &[&str]) -> Result<bool> {
+ all.iter()
+ .map(|elem| {
+ if self.consume(elem) {
+ self.skip_ws()?;
+
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ })
+ .fold(Ok(true), |acc, x| acc.and_then(|val| x.map(|x| x && val)))
+ }
+
+ pub fn eat_byte(&mut self) -> Result<u8> {
+ let peek = self.peek_or_eof()?;
+ let _ = self.advance_single();
+
+ Ok(peek)
+ }
+
+ pub fn expect_byte(&mut self, byte: u8, error: Error) -> Result<()> {
+ self.eat_byte()
+ .and_then(|b| if b == byte { Ok(()) } else { Err(error) })
+ }
+
+ /// Returns the extensions bit mask.
+ fn extensions(&mut self) -> Result<Extensions> {
+ if self.peek() != Some(b'#') {
+ return Ok(Extensions::empty());
+ }
+
+ if !self.consume_all(&["#", "!", "[", "enable", "("])? {
+ return Err(Error::ExpectedAttribute);
+ }
+
+ self.skip_ws()?;
+ let mut extensions = Extensions::empty();
+
+ loop {
+ let ident = self.identifier()?;
+ let extension = Extensions::from_ident(ident).ok_or_else(|| {
+ Error::NoSuchExtension(String::from_utf8_lossy(ident).into_owned())
+ })?;
+
+ extensions |= extension;
+
+ let comma = self.comma()?;
+
+ // If we have no comma but another item, return an error
+ if !comma && self.check_ident_other_char(0) {
+ return Err(Error::ExpectedComma);
+ }
+
+ // If there's no comma, assume the list ended.
+ // If there is, it might be a trailing one, thus we only
+ // continue the loop if we get an ident char.
+ if !comma || !self.check_ident_other_char(0) {
+ break;
+ }
+ }
+
+ self.skip_ws()?;
+
+ if self.consume_all(&[")", "]"])? {
+ Ok(extensions)
+ } else {
+ Err(Error::ExpectedAttributeEnd)
+ }
+ }
+
+ pub fn float<T>(&mut self) -> Result<T>
+ where
+ T: FromStr,
+ {
+ for literal in &["inf", "+inf", "-inf", "NaN", "+NaN", "-NaN"] {
+ if self.consume_ident(literal) {
+ return FromStr::from_str(literal).map_err(|_| unreachable!()); // must not fail
+ }
+ }
+
+ let num_bytes = self.next_bytes_contained_in(is_float_char);
+
+ // Since `rustc` allows `1_0.0_1`, lint against underscores in floats
+ if let Some(err_bytes) = self.bytes[0..num_bytes].iter().position(|b| *b == b'_') {
+ let _ = self.advance(err_bytes);
+
+ return Err(Error::FloatUnderscore);
+ }
+
+ let s = unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) };
+ let res = FromStr::from_str(s).map_err(|_| Error::ExpectedFloat);
+
+ let _ = self.advance(num_bytes);
+
+ res
+ }
+
+ pub fn identifier(&mut self) -> Result<&'a [u8]> {
+ let next = self.peek_or_eof()?;
+ if !is_ident_first_char(next) {
+ if is_ident_raw_char(next) {
+ let ident_bytes = &self.bytes[..self.next_bytes_contained_in(is_ident_raw_char)];
+
+ if let Ok(ident) = std::str::from_utf8(ident_bytes) {
+ return Err(Error::SuggestRawIdentifier(String::from(ident)));
+ }
+ }
+
+ return Err(Error::ExpectedIdentifier);
+ }
+
+ // If the next two bytes signify the start of a raw string literal,
+ // return an error.
+ let length = if next == b'r' {
+ match self.bytes.get(1).ok_or(Error::Eof)? {
+ b'"' => return Err(Error::ExpectedIdentifier),
+ b'#' => {
+ let after_next = self.bytes.get(2).copied().unwrap_or_default();
+ // Note: it's important to check this before advancing forward, so that
+ // the value-type deserializer can fall back to parsing it differently.
+ if !is_ident_raw_char(after_next) {
+ return Err(Error::ExpectedIdentifier);
+ }
+ // skip "r#"
+ let _ = self.advance(2);
+ self.next_bytes_contained_in(is_ident_raw_char)
+ }
+ _ => {
+ let std_ident_length = self.next_bytes_contained_in(is_ident_other_char);
+ let raw_ident_length = self.next_bytes_contained_in(is_ident_raw_char);
+
+ if raw_ident_length > std_ident_length {
+ if let Ok(ident) = std::str::from_utf8(&self.bytes[..raw_ident_length]) {
+ return Err(Error::SuggestRawIdentifier(String::from(ident)));
+ }
+ }
+
+ std_ident_length
+ }
+ }
+ } else {
+ let std_ident_length = self.next_bytes_contained_in(is_ident_other_char);
+ let raw_ident_length = self.next_bytes_contained_in(is_ident_raw_char);
+
+ if raw_ident_length > std_ident_length {
+ if let Ok(ident) = std::str::from_utf8(&self.bytes[..raw_ident_length]) {
+ return Err(Error::SuggestRawIdentifier(String::from(ident)));
+ }
+ }
+
+ std_ident_length
+ };
+
+ let ident = &self.bytes[..length];
+ let _ = self.advance(length);
+
+ Ok(ident)
+ }
+
+ pub fn next_bytes_contained_in(&self, allowed: fn(u8) -> bool) -> usize {
+ self.bytes.iter().take_while(|&&b| allowed(b)).count()
+ }
+
+ pub fn next_bytes_is_float(&self) -> bool {
+ if let Some(byte) = self.peek() {
+ let skip = match byte {
+ b'+' | b'-' => 1,
+ _ => 0,
+ };
+ let flen = self
+ .bytes
+ .iter()
+ .skip(skip)
+ .take_while(|&&b| is_float_char(b))
+ .count();
+ let ilen = self
+ .bytes
+ .iter()
+ .skip(skip)
+ .take_while(|&&b| is_int_char(b))
+ .count();
+ flen > ilen
+ } else {
+ false
+ }
+ }
+
+ pub fn skip_ws(&mut self) -> Result<()> {
+ loop {
+ while self.peek().map_or(false, is_whitespace_char) {
+ let _ = self.advance_single();
+ }
+
+ if !self.skip_comment()? {
+ return Ok(());
+ }
+ }
+ }
+
+ pub fn peek(&self) -> Option<u8> {
+ self.bytes.first().copied()
+ }
+
+ pub fn peek_or_eof(&self) -> Result<u8> {
+ self.bytes.first().copied().ok_or(Error::Eof)
+ }
+
+ pub fn signed_integer<T>(&mut self) -> Result<T>
+ where
+ T: Num,
+ {
+ match self.peek_or_eof()? {
+ b'+' => {
+ let _ = self.advance_single();
+
+ self.any_integer(1)
+ }
+ b'-' => {
+ let _ = self.advance_single();
+
+ self.any_integer(-1)
+ }
+ _ => self.any_integer(1),
+ }
+ }
+
+ pub fn string(&mut self) -> Result<ParsedStr<'a>> {
+ if self.consume("\"") {
+ self.escaped_string()
+ } else if self.consume("r") {
+ self.raw_string()
+ } else {
+ Err(Error::ExpectedString)
+ }
+ }
+
+ fn escaped_string(&mut self) -> Result<ParsedStr<'a>> {
+ use std::iter::repeat;
+
+ let (i, end_or_escape) = self
+ .bytes
+ .iter()
+ .enumerate()
+ .find(|&(_, &b)| b == b'\\' || b == b'"')
+ .ok_or(Error::ExpectedStringEnd)?;
+
+ if *end_or_escape == b'"' {
+ let s = from_utf8(&self.bytes[..i]).map_err(Error::from)?;
+
+ // Advance by the number of bytes of the string
+ // + 1 for the `"`.
+ let _ = self.advance(i + 1);
+
+ Ok(ParsedStr::Slice(s))
+ } else {
+ let mut i = i;
+ let mut s: Vec<_> = self.bytes[..i].to_vec();
+
+ loop {
+ let _ = self.advance(i + 1);
+ let character = self.parse_escape()?;
+ match character.len_utf8() {
+ 1 => s.push(character as u8),
+ len => {
+ let start = s.len();
+ s.extend(repeat(0).take(len));
+ character.encode_utf8(&mut s[start..]);
+ }
+ }
+
+ let (new_i, end_or_escape) = self
+ .bytes
+ .iter()
+ .enumerate()
+ .find(|&(_, &b)| b == b'\\' || b == b'"')
+ .ok_or(Error::ExpectedStringEnd)?;
+
+ i = new_i;
+ s.extend_from_slice(&self.bytes[..i]);
+
+ if *end_or_escape == b'"' {
+ let _ = self.advance(i + 1);
+
+ let s = String::from_utf8(s).map_err(Error::from)?;
+ break Ok(ParsedStr::Allocated(s));
+ }
+ }
+ }
+ }
+
+ fn raw_string(&mut self) -> Result<ParsedStr<'a>> {
+ let num_hashes = self.bytes.iter().take_while(|&&b| b == b'#').count();
+ let hashes = &self.bytes[..num_hashes];
+ let _ = self.advance(num_hashes);
+
+ if !self.consume("\"") {
+ return Err(Error::ExpectedString);
+ }
+
+ let ending = [&[b'"'], hashes].concat();
+ let i = self
+ .bytes
+ .windows(num_hashes + 1)
+ .position(|window| window == ending.as_slice())
+ .ok_or(Error::ExpectedStringEnd)?;
+
+ let s = from_utf8(&self.bytes[..i]).map_err(Error::from)?;
+
+ // Advance by the number of bytes of the string
+ // + `num_hashes` + 1 for the `"`.
+ let _ = self.advance(i + num_hashes + 1);
+
+ Ok(ParsedStr::Slice(s))
+ }
+
+ fn test_for(&self, s: &str) -> bool {
+ s.bytes()
+ .enumerate()
+ .all(|(i, b)| self.bytes.get(i).map_or(false, |t| *t == b))
+ }
+
+ pub fn unsigned_integer<T: Num>(&mut self) -> Result<T> {
+ self.any_integer(1)
+ }
+
+ fn decode_ascii_escape(&mut self) -> Result<u8> {
+ let mut n = 0;
+ for _ in 0..2 {
+ n <<= 4;
+ let byte = self.eat_byte()?;
+ let decoded = self.decode_hex(byte)?;
+ n |= decoded;
+ }
+
+ Ok(n)
+ }
+
+ #[inline]
+ fn decode_hex(&self, c: u8) -> Result<u8> {
+ match c {
+ c @ b'0'..=b'9' => Ok(c - b'0'),
+ c @ b'a'..=b'f' => Ok(10 + c - b'a'),
+ c @ b'A'..=b'F' => Ok(10 + c - b'A'),
+ _ => Err(Error::InvalidEscape("Non-hex digit found")),
+ }
+ }
+
+ fn parse_escape(&mut self) -> Result<char> {
+ let c = match self.eat_byte()? {
+ b'\'' => '\'',
+ b'"' => '"',
+ b'\\' => '\\',
+ b'n' => '\n',
+ b'r' => '\r',
+ b't' => '\t',
+ b'0' => '\0',
+ b'x' => self.decode_ascii_escape()? as char,
+ b'u' => {
+ self.expect_byte(b'{', Error::InvalidEscape("Missing { in Unicode escape"))?;
+
+ let mut bytes: u32 = 0;
+ let mut num_digits = 0;
+
+ while num_digits < 6 {
+ let byte = self.peek_or_eof()?;
+
+ if byte == b'}' {
+ break;
+ } else {
+ self.advance_single()?;
+ }
+
+ let byte = self.decode_hex(byte)?;
+ bytes <<= 4;
+ bytes |= u32::from(byte);
+
+ num_digits += 1;
+ }
+
+ if num_digits == 0 {
+ return Err(Error::InvalidEscape(
+ "Expected 1-6 digits, got 0 digits in Unicode escape",
+ ));
+ }
+
+ self.expect_byte(
+ b'}',
+ Error::InvalidEscape("No } at the end of Unicode escape"),
+ )?;
+ char_from_u32(bytes).ok_or(Error::InvalidEscape("Not a valid char"))?
+ }
+ _ => {
+ return Err(Error::InvalidEscape("Unknown escape character"));
+ }
+ };
+
+ Ok(c)
+ }
+
+ fn skip_comment(&mut self) -> Result<bool> {
+ if self.consume("/") {
+ match self.eat_byte()? {
+ b'/' => {
+ let bytes = self.bytes.iter().take_while(|&&b| b != b'\n').count();
+
+ let _ = self.advance(bytes);
+ }
+ b'*' => {
+ let mut level = 1;
+
+ while level > 0 {
+ let bytes = self
+ .bytes
+ .iter()
+ .take_while(|&&b| b != b'/' && b != b'*')
+ .count();
+
+ if self.bytes.is_empty() {
+ return Err(Error::UnclosedBlockComment);
+ }
+
+ let _ = self.advance(bytes);
+
+ // check whether / or * and take action
+ if self.consume("/*") {
+ level += 1;
+ } else if self.consume("*/") {
+ level -= 1;
+ } else {
+ self.eat_byte().map_err(|_| Error::UnclosedBlockComment)?;
+ }
+ }
+ }
+ b => return Err(Error::UnexpectedByte(b as char)),
+ }
+
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+}
+
+pub trait Num {
+ fn from_u8(x: u8) -> Self;
+
+ /// Returns `true` on overflow
+ fn checked_mul_ext(&mut self, x: u8) -> bool;
+
+ /// Returns `true` on overflow
+ fn checked_add_ext(&mut self, x: u8) -> bool;
+
+ /// Returns `true` on overflow
+ fn checked_sub_ext(&mut self, x: u8) -> bool;
+}
+
+macro_rules! impl_num {
+ ($ty:ident) => {
+ impl Num for $ty {
+ fn from_u8(x: u8) -> Self {
+ x as $ty
+ }
+
+ fn checked_mul_ext(&mut self, x: u8) -> bool {
+ match self.checked_mul(Self::from_u8(x)) {
+ Some(n) => {
+ *self = n;
+ false
+ }
+ None => true,
+ }
+ }
+
+ fn checked_add_ext(&mut self, x: u8) -> bool {
+ match self.checked_add(Self::from_u8(x)) {
+ Some(n) => {
+ *self = n;
+ false
+ }
+ None => true,
+ }
+ }
+
+ fn checked_sub_ext(&mut self, x: u8) -> bool {
+ match self.checked_sub(Self::from_u8(x)) {
+ Some(n) => {
+ *self = n;
+ false
+ }
+ None => true,
+ }
+ }
+ }
+ };
+ ($($tys:ident)*) => {
+ $( impl_num!($tys); )*
+ };
+}
+
+#[cfg(feature = "integer128")]
+impl_num!(u8 u16 u32 u64 u128 i8 i16 i32 i64 i128);
+#[cfg(not(feature = "integer128"))]
+impl_num!(u8 u16 u32 u64 i8 i16 i32 i64);
+
+#[derive(Clone, Debug)]
+pub enum ParsedStr<'a> {
+ Allocated(String),
+ Slice(&'a str),
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn decode_x10() {
+ let mut bytes = Bytes::new(b"10").unwrap();
+ assert_eq!(bytes.decode_ascii_escape(), Ok(0x10));
+ }
+}
diff --git a/third_party/rust/ron/src/ser/mod.rs b/third_party/rust/ron/src/ser/mod.rs
new file mode 100644
index 0000000000..b1aefbcba4
--- /dev/null
+++ b/third_party/rust/ron/src/ser/mod.rs
@@ -0,0 +1,1041 @@
+use std::io;
+
+use base64::Engine;
+use serde::{ser, ser::Serialize};
+use serde_derive::{Deserialize, Serialize};
+
+use crate::{
+ error::{Error, Result},
+ extensions::Extensions,
+ options::Options,
+ parse::{
+ is_ident_first_char, is_ident_other_char, is_ident_raw_char, LargeSInt, LargeUInt,
+ BASE64_ENGINE,
+ },
+};
+
+#[cfg(test)]
+mod tests;
+mod value;
+
+/// Serializes `value` into `writer`.
+///
+/// This function does not generate any newlines or nice formatting;
+/// if you want that, you can use [`to_writer_pretty`] instead.
+pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()>
+where
+ W: io::Write,
+ T: ?Sized + Serialize,
+{
+ Options::default().to_writer(writer, value)
+}
+
+/// Serializes `value` into `writer` in a pretty way.
+pub fn to_writer_pretty<W, T>(writer: W, value: &T, config: PrettyConfig) -> Result<()>
+where
+ W: io::Write,
+ T: ?Sized + Serialize,
+{
+ Options::default().to_writer_pretty(writer, value, config)
+}
+
+/// Serializes `value` and returns it as string.
+///
+/// This function does not generate any newlines or nice formatting;
+/// if you want that, you can use [`to_string_pretty`] instead.
+pub fn to_string<T>(value: &T) -> Result<String>
+where
+ T: ?Sized + Serialize,
+{
+ Options::default().to_string(value)
+}
+
+/// Serializes `value` in the recommended RON layout in a pretty way.
+pub fn to_string_pretty<T>(value: &T, config: PrettyConfig) -> Result<String>
+where
+ T: ?Sized + Serialize,
+{
+ Options::default().to_string_pretty(value, config)
+}
+
+/// Pretty serializer state
+struct Pretty {
+ indent: usize,
+ sequence_index: Vec<usize>,
+}
+
+/// Pretty serializer configuration.
+///
+/// # Examples
+///
+/// ```
+/// use ron::ser::PrettyConfig;
+///
+/// let my_config = PrettyConfig::new()
+/// .depth_limit(4)
+/// // definitely superior (okay, just joking)
+/// .indentor("\t".to_owned());
+/// ```
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(default)]
+#[non_exhaustive]
+pub struct PrettyConfig {
+ /// Limit the pretty-ness up to the given depth.
+ pub depth_limit: usize,
+ /// New line string
+ pub new_line: String,
+ /// Indentation string
+ pub indentor: String,
+ /// Separator string
+ pub separator: String,
+ // Whether to emit struct names
+ pub struct_names: bool,
+ /// Separate tuple members with indentation
+ pub separate_tuple_members: bool,
+ /// Enumerate array items in comments
+ pub enumerate_arrays: bool,
+ /// Enable extensions. Only configures 'implicit_some',
+ /// 'unwrap_newtypes', and 'unwrap_variant_newtypes' for now.
+ pub extensions: Extensions,
+ /// Enable compact arrays
+ pub compact_arrays: bool,
+}
+
+impl PrettyConfig {
+ /// Creates a default [`PrettyConfig`].
+ pub fn new() -> Self {
+ Default::default()
+ }
+
+ /// Limits the pretty-formatting based on the number of indentations.
+ /// I.e., with a depth limit of 5, starting with an element of depth
+ /// (indentation level) 6, everything will be put into the same line,
+ /// without pretty formatting.
+ ///
+ /// Default: [usize::MAX]
+ pub fn depth_limit(mut self, depth_limit: usize) -> Self {
+ self.depth_limit = depth_limit;
+
+ self
+ }
+
+ /// Configures the newlines used for serialization.
+ ///
+ /// Default: `\r\n` on Windows, `\n` otherwise
+ pub fn new_line(mut self, new_line: String) -> Self {
+ self.new_line = new_line;
+
+ self
+ }
+
+ /// Configures the string sequence used for indentation.
+ ///
+ /// Default: 4 spaces
+ pub fn indentor(mut self, indentor: String) -> Self {
+ self.indentor = indentor;
+
+ self
+ }
+
+ /// Configures the string sequence used to separate items inline.
+ ///
+ /// Default: 1 space
+ pub fn separator(mut self, separator: String) -> Self {
+ self.separator = separator;
+
+ self
+ }
+
+ /// Configures whether to emit struct names.
+ ///
+ /// Default: `false`
+ pub fn struct_names(mut self, struct_names: bool) -> Self {
+ self.struct_names = struct_names;
+
+ self
+ }
+
+ /// Configures whether tuples are single- or multi-line.
+ /// If set to `true`, tuples will have their fields indented and in new
+ /// lines. If set to `false`, tuples will be serialized without any
+ /// newlines or indentations.
+ ///
+ /// Default: `false`
+ pub fn separate_tuple_members(mut self, separate_tuple_members: bool) -> Self {
+ self.separate_tuple_members = separate_tuple_members;
+
+ self
+ }
+
+ /// Configures whether a comment shall be added to every array element,
+ /// indicating the index.
+ ///
+ /// Default: `false`
+ pub fn enumerate_arrays(mut self, enumerate_arrays: bool) -> Self {
+ self.enumerate_arrays = enumerate_arrays;
+
+ self
+ }
+
+ /// Configures whether every array should be a single line (`true`)
+ /// or a multi line one (`false`).
+ ///
+ /// When `false`, `["a","b"]` (as well as any array) will serialize to
+ /// ```
+ /// [
+ /// "a",
+ /// "b",
+ /// ]
+ /// # ;
+ /// ```
+ /// When `true`, `["a","b"]` (as well as any array) will serialize to
+ /// ```
+ /// ["a","b"]
+ /// # ;
+ /// ```
+ ///
+ /// Default: `false`
+ pub fn compact_arrays(mut self, compact_arrays: bool) -> Self {
+ self.compact_arrays = compact_arrays;
+
+ self
+ }
+
+ /// Configures extensions
+ ///
+ /// Default: [Extensions::empty()]
+ pub fn extensions(mut self, extensions: Extensions) -> Self {
+ self.extensions = extensions;
+
+ self
+ }
+}
+
+impl Default for PrettyConfig {
+ fn default() -> Self {
+ PrettyConfig {
+ depth_limit: usize::MAX,
+ new_line: if cfg!(not(target_os = "windows")) {
+ String::from("\n")
+ } else {
+ String::from("\r\n")
+ },
+ indentor: String::from(" "),
+ separator: String::from(" "),
+ struct_names: false,
+ separate_tuple_members: false,
+ enumerate_arrays: false,
+ extensions: Extensions::empty(),
+ compact_arrays: false,
+ }
+ }
+}
+
+/// The RON serializer.
+///
+/// You can just use [`to_string`] for deserializing a value.
+/// If you want it pretty-printed, take a look at [`to_string_pretty`].
+pub struct Serializer<W: io::Write> {
+ output: W,
+ pretty: Option<(PrettyConfig, Pretty)>,
+ default_extensions: Extensions,
+ is_empty: Option<bool>,
+ newtype_variant: bool,
+ recursion_limit: Option<usize>,
+}
+
+impl<W: io::Write> Serializer<W> {
+ /// Creates a new [`Serializer`].
+ ///
+ /// Most of the time you can just use [`to_string`] or
+ /// [`to_string_pretty`].
+ pub fn new(writer: W, config: Option<PrettyConfig>) -> Result<Self> {
+ Self::with_options(writer, config, Options::default())
+ }
+
+ /// Creates a new [`Serializer`].
+ ///
+ /// Most of the time you can just use [`to_string`] or
+ /// [`to_string_pretty`].
+ pub fn with_options(
+ mut writer: W,
+ config: Option<PrettyConfig>,
+ options: Options,
+ ) -> Result<Self> {
+ if let Some(conf) = &config {
+ let non_default_extensions = !options.default_extensions;
+
+ if (non_default_extensions & conf.extensions).contains(Extensions::IMPLICIT_SOME) {
+ writer.write_all(b"#![enable(implicit_some)]")?;
+ writer.write_all(conf.new_line.as_bytes())?;
+ };
+ if (non_default_extensions & conf.extensions).contains(Extensions::UNWRAP_NEWTYPES) {
+ writer.write_all(b"#![enable(unwrap_newtypes)]")?;
+ writer.write_all(conf.new_line.as_bytes())?;
+ };
+ if (non_default_extensions & conf.extensions)
+ .contains(Extensions::UNWRAP_VARIANT_NEWTYPES)
+ {
+ writer.write_all(b"#![enable(unwrap_variant_newtypes)]")?;
+ writer.write_all(conf.new_line.as_bytes())?;
+ };
+ };
+ Ok(Serializer {
+ output: writer,
+ pretty: config.map(|conf| {
+ (
+ conf,
+ Pretty {
+ indent: 0,
+ sequence_index: Vec::new(),
+ },
+ )
+ }),
+ default_extensions: options.default_extensions,
+ is_empty: None,
+ newtype_variant: false,
+ recursion_limit: options.recursion_limit,
+ })
+ }
+
+ fn separate_tuple_members(&self) -> bool {
+ self.pretty
+ .as_ref()
+ .map_or(false, |&(ref config, _)| config.separate_tuple_members)
+ }
+
+ fn compact_arrays(&self) -> bool {
+ self.pretty
+ .as_ref()
+ .map_or(false, |&(ref config, _)| config.compact_arrays)
+ }
+
+ fn extensions(&self) -> Extensions {
+ self.default_extensions
+ | self
+ .pretty
+ .as_ref()
+ .map_or(Extensions::empty(), |&(ref config, _)| config.extensions)
+ }
+
+ fn start_indent(&mut self) -> Result<()> {
+ if let Some((ref config, ref mut pretty)) = self.pretty {
+ pretty.indent += 1;
+ if pretty.indent <= config.depth_limit {
+ let is_empty = self.is_empty.unwrap_or(false);
+
+ if !is_empty {
+ self.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn indent(&mut self) -> io::Result<()> {
+ if let Some((ref config, ref pretty)) = self.pretty {
+ if pretty.indent <= config.depth_limit {
+ for _ in 0..pretty.indent {
+ self.output.write_all(config.indentor.as_bytes())?;
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn end_indent(&mut self) -> io::Result<()> {
+ if let Some((ref config, ref mut pretty)) = self.pretty {
+ if pretty.indent <= config.depth_limit {
+ let is_empty = self.is_empty.unwrap_or(false);
+
+ if !is_empty {
+ for _ in 1..pretty.indent {
+ self.output.write_all(config.indentor.as_bytes())?;
+ }
+ }
+ }
+ pretty.indent -= 1;
+
+ self.is_empty = None;
+ }
+ Ok(())
+ }
+
+ fn serialize_escaped_str(&mut self, value: &str) -> io::Result<()> {
+ self.output.write_all(b"\"")?;
+ let mut scalar = [0u8; 4];
+ for c in value.chars().flat_map(|c| c.escape_debug()) {
+ self.output
+ .write_all(c.encode_utf8(&mut scalar).as_bytes())?;
+ }
+ self.output.write_all(b"\"")?;
+ Ok(())
+ }
+
+ fn serialize_sint(&mut self, value: impl Into<LargeSInt>) -> Result<()> {
+ // TODO optimize
+ write!(self.output, "{}", value.into())?;
+
+ Ok(())
+ }
+
+ fn serialize_uint(&mut self, value: impl Into<LargeUInt>) -> Result<()> {
+ // TODO optimize
+ write!(self.output, "{}", value.into())?;
+
+ Ok(())
+ }
+
+ fn write_identifier(&mut self, name: &str) -> Result<()> {
+ if name.is_empty() || !name.as_bytes().iter().copied().all(is_ident_raw_char) {
+ return Err(Error::InvalidIdentifier(name.into()));
+ }
+ let mut bytes = name.as_bytes().iter().copied();
+ if !bytes.next().map_or(false, is_ident_first_char) || !bytes.all(is_ident_other_char) {
+ self.output.write_all(b"r#")?;
+ }
+ self.output.write_all(name.as_bytes())?;
+ Ok(())
+ }
+
+ fn struct_names(&self) -> bool {
+ self.pretty
+ .as_ref()
+ .map(|(pc, _)| pc.struct_names)
+ .unwrap_or(false)
+ }
+}
+
+macro_rules! guard_recursion {
+ ($self:expr => $expr:expr) => {{
+ if let Some(limit) = &mut $self.recursion_limit {
+ if let Some(new_limit) = limit.checked_sub(1) {
+ *limit = new_limit;
+ } else {
+ return Err(Error::ExceededRecursionLimit);
+ }
+ }
+
+ let result = $expr;
+
+ if let Some(limit) = &mut $self.recursion_limit {
+ *limit = limit.saturating_add(1);
+ }
+
+ result
+ }};
+}
+
+impl<'a, W: io::Write> ser::Serializer for &'a mut Serializer<W> {
+ type Error = Error;
+ type Ok = ();
+ type SerializeMap = Compound<'a, W>;
+ type SerializeSeq = Compound<'a, W>;
+ type SerializeStruct = Compound<'a, W>;
+ type SerializeStructVariant = Compound<'a, W>;
+ type SerializeTuple = Compound<'a, W>;
+ type SerializeTupleStruct = Compound<'a, W>;
+ type SerializeTupleVariant = Compound<'a, W>;
+
+ fn serialize_bool(self, v: bool) -> Result<()> {
+ self.output.write_all(if v { b"true" } else { b"false" })?;
+ Ok(())
+ }
+
+ fn serialize_i8(self, v: i8) -> Result<()> {
+ self.serialize_sint(v)
+ }
+
+ fn serialize_i16(self, v: i16) -> Result<()> {
+ self.serialize_sint(v)
+ }
+
+ fn serialize_i32(self, v: i32) -> Result<()> {
+ self.serialize_sint(v)
+ }
+
+ fn serialize_i64(self, v: i64) -> Result<()> {
+ self.serialize_sint(v)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn serialize_i128(self, v: i128) -> Result<()> {
+ self.serialize_sint(v)
+ }
+
+ fn serialize_u8(self, v: u8) -> Result<()> {
+ self.serialize_uint(v)
+ }
+
+ fn serialize_u16(self, v: u16) -> Result<()> {
+ self.serialize_uint(v)
+ }
+
+ fn serialize_u32(self, v: u32) -> Result<()> {
+ self.serialize_uint(v)
+ }
+
+ fn serialize_u64(self, v: u64) -> Result<()> {
+ self.serialize_uint(v)
+ }
+
+ #[cfg(feature = "integer128")]
+ fn serialize_u128(self, v: u128) -> Result<()> {
+ self.serialize_uint(v)
+ }
+
+ fn serialize_f32(self, v: f32) -> Result<()> {
+ write!(self.output, "{}", v)?;
+ if v.fract() == 0.0 {
+ write!(self.output, ".0")?;
+ }
+ Ok(())
+ }
+
+ fn serialize_f64(self, v: f64) -> Result<()> {
+ write!(self.output, "{}", v)?;
+ if v.fract() == 0.0 {
+ write!(self.output, ".0")?;
+ }
+ Ok(())
+ }
+
+ fn serialize_char(self, v: char) -> Result<()> {
+ self.output.write_all(b"'")?;
+ if v == '\\' || v == '\'' {
+ self.output.write_all(b"\\")?;
+ }
+ write!(self.output, "{}", v)?;
+ self.output.write_all(b"'")?;
+ Ok(())
+ }
+
+ fn serialize_str(self, v: &str) -> Result<()> {
+ self.serialize_escaped_str(v)?;
+
+ Ok(())
+ }
+
+ fn serialize_bytes(self, v: &[u8]) -> Result<()> {
+ self.serialize_str(BASE64_ENGINE.encode(v).as_str())
+ }
+
+ fn serialize_none(self) -> Result<()> {
+ self.output.write_all(b"None")?;
+
+ Ok(())
+ }
+
+ fn serialize_some<T>(self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ let implicit_some = self.extensions().contains(Extensions::IMPLICIT_SOME);
+ if !implicit_some {
+ self.output.write_all(b"Some(")?;
+ }
+ guard_recursion! { self => value.serialize(&mut *self)? };
+ if !implicit_some {
+ self.output.write_all(b")")?;
+ }
+
+ Ok(())
+ }
+
+ fn serialize_unit(self) -> Result<()> {
+ if !self.newtype_variant {
+ self.output.write_all(b"()")?;
+ }
+
+ self.newtype_variant = false;
+
+ Ok(())
+ }
+
+ fn serialize_unit_struct(self, name: &'static str) -> Result<()> {
+ if self.struct_names() && !self.newtype_variant {
+ self.write_identifier(name)?;
+
+ Ok(())
+ } else {
+ self.serialize_unit()
+ }
+ }
+
+ fn serialize_unit_variant(self, _: &'static str, _: u32, variant: &'static str) -> Result<()> {
+ self.write_identifier(variant)?;
+
+ Ok(())
+ }
+
+ fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if self.extensions().contains(Extensions::UNWRAP_NEWTYPES) || self.newtype_variant {
+ self.newtype_variant = false;
+
+ return guard_recursion! { self => value.serialize(&mut *self) };
+ }
+
+ if self.struct_names() {
+ self.write_identifier(name)?;
+ }
+
+ self.output.write_all(b"(")?;
+ guard_recursion! { self => value.serialize(&mut *self)? };
+ self.output.write_all(b")")?;
+ Ok(())
+ }
+
+ fn serialize_newtype_variant<T>(
+ self,
+ _: &'static str,
+ _: u32,
+ variant: &'static str,
+ value: &T,
+ ) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.write_identifier(variant)?;
+ self.output.write_all(b"(")?;
+
+ self.newtype_variant = self
+ .extensions()
+ .contains(Extensions::UNWRAP_VARIANT_NEWTYPES);
+
+ guard_recursion! { self => value.serialize(&mut *self)? };
+
+ self.newtype_variant = false;
+
+ self.output.write_all(b")")?;
+ Ok(())
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
+ self.newtype_variant = false;
+
+ self.output.write_all(b"[")?;
+
+ if let Some(len) = len {
+ self.is_empty = Some(len == 0);
+ }
+
+ if !self.compact_arrays() {
+ self.start_indent()?;
+ }
+
+ if let Some((_, ref mut pretty)) = self.pretty {
+ pretty.sequence_index.push(0);
+ }
+
+ Compound::try_new(self, false)
+ }
+
+ fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
+ let old_newtype_variant = self.newtype_variant;
+ self.newtype_variant = false;
+
+ if !old_newtype_variant {
+ self.output.write_all(b"(")?;
+ }
+
+ if self.separate_tuple_members() {
+ self.is_empty = Some(len == 0);
+
+ self.start_indent()?;
+ }
+
+ Compound::try_new(self, old_newtype_variant)
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ name: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleStruct> {
+ if self.struct_names() && !self.newtype_variant {
+ self.write_identifier(name)?;
+ }
+
+ self.serialize_tuple(len)
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _: &'static str,
+ _: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleVariant> {
+ self.newtype_variant = false;
+
+ self.write_identifier(variant)?;
+ self.output.write_all(b"(")?;
+
+ if self.separate_tuple_members() {
+ self.is_empty = Some(len == 0);
+
+ self.start_indent()?;
+ }
+
+ Compound::try_new(self, false)
+ }
+
+ fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
+ self.newtype_variant = false;
+
+ self.output.write_all(b"{")?;
+
+ if let Some(len) = len {
+ self.is_empty = Some(len == 0);
+ }
+
+ self.start_indent()?;
+
+ Compound::try_new(self, false)
+ }
+
+ fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
+ let old_newtype_variant = self.newtype_variant;
+ self.newtype_variant = false;
+
+ if !old_newtype_variant {
+ if self.struct_names() {
+ self.write_identifier(name)?;
+ }
+ self.output.write_all(b"(")?;
+ }
+
+ self.is_empty = Some(len == 0);
+ self.start_indent()?;
+
+ Compound::try_new(self, old_newtype_variant)
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _: &'static str,
+ _: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeStructVariant> {
+ self.newtype_variant = false;
+
+ self.write_identifier(variant)?;
+ self.output.write_all(b"(")?;
+
+ self.is_empty = Some(len == 0);
+ self.start_indent()?;
+
+ Compound::try_new(self, false)
+ }
+}
+
+enum State {
+ First,
+ Rest,
+}
+
+#[doc(hidden)]
+pub struct Compound<'a, W: io::Write> {
+ ser: &'a mut Serializer<W>,
+ state: State,
+ newtype_variant: bool,
+}
+
+impl<'a, W: io::Write> Compound<'a, W> {
+ fn try_new(ser: &'a mut Serializer<W>, newtype_variant: bool) -> Result<Self> {
+ if let Some(limit) = &mut ser.recursion_limit {
+ if let Some(new_limit) = limit.checked_sub(1) {
+ *limit = new_limit;
+ } else {
+ return Err(Error::ExceededRecursionLimit);
+ }
+ }
+
+ Ok(Compound {
+ ser,
+ state: State::First,
+ newtype_variant,
+ })
+ }
+}
+
+impl<'a, W: io::Write> Drop for Compound<'a, W> {
+ fn drop(&mut self) {
+ if let Some(limit) = &mut self.ser.recursion_limit {
+ *limit = limit.saturating_add(1);
+ }
+ }
+}
+
+impl<'a, W: io::Write> ser::SerializeSeq for Compound<'a, W> {
+ type Error = Error;
+ type Ok = ();
+
+ fn serialize_element<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if let State::First = self.state {
+ self.state = State::Rest;
+ } else {
+ self.ser.output.write_all(b",")?;
+ if let Some((ref config, ref mut pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit && !config.compact_arrays {
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ } else {
+ self.ser.output.write_all(config.separator.as_bytes())?;
+ }
+ }
+ }
+
+ if !self.ser.compact_arrays() {
+ self.ser.indent()?;
+ }
+
+ if let Some((ref mut config, ref mut pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit && config.enumerate_arrays {
+ let index = pretty.sequence_index.last_mut().unwrap();
+ write!(self.ser.output, "/*[{}]*/ ", index)?;
+ *index += 1;
+ }
+ }
+
+ guard_recursion! { self.ser => value.serialize(&mut *self.ser)? };
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ if let State::Rest = self.state {
+ if let Some((ref config, ref mut pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit && !config.compact_arrays {
+ self.ser.output.write_all(b",")?;
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ }
+
+ if !self.ser.compact_arrays() {
+ self.ser.end_indent()?;
+ }
+
+ if let Some((_, ref mut pretty)) = self.ser.pretty {
+ pretty.sequence_index.pop();
+ }
+
+ // seq always disables `self.newtype_variant`
+ self.ser.output.write_all(b"]")?;
+ Ok(())
+ }
+}
+
+impl<'a, W: io::Write> ser::SerializeTuple for Compound<'a, W> {
+ type Error = Error;
+ type Ok = ();
+
+ fn serialize_element<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if let State::First = self.state {
+ self.state = State::Rest;
+ } else {
+ self.ser.output.write_all(b",")?;
+ if let Some((ref config, ref pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit && self.ser.separate_tuple_members() {
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ } else {
+ self.ser.output.write_all(config.separator.as_bytes())?;
+ }
+ }
+ }
+
+ if self.ser.separate_tuple_members() {
+ self.ser.indent()?;
+ }
+
+ guard_recursion! { self.ser => value.serialize(&mut *self.ser)? };
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ if let State::Rest = self.state {
+ if let Some((ref config, ref pretty)) = self.ser.pretty {
+ if self.ser.separate_tuple_members() && pretty.indent <= config.depth_limit {
+ self.ser.output.write_all(b",")?;
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ }
+ if self.ser.separate_tuple_members() {
+ self.ser.end_indent()?;
+ }
+
+ if !self.newtype_variant {
+ self.ser.output.write_all(b")")?;
+ }
+
+ Ok(())
+ }
+}
+
+// Same thing but for tuple structs.
+impl<'a, W: io::Write> ser::SerializeTupleStruct for Compound<'a, W> {
+ type Error = Error;
+ type Ok = ();
+
+ fn serialize_field<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ ser::SerializeTuple::serialize_element(self, value)
+ }
+
+ fn end(self) -> Result<()> {
+ ser::SerializeTuple::end(self)
+ }
+}
+
+impl<'a, W: io::Write> ser::SerializeTupleVariant for Compound<'a, W> {
+ type Error = Error;
+ type Ok = ();
+
+ fn serialize_field<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ ser::SerializeTuple::serialize_element(self, value)
+ }
+
+ fn end(self) -> Result<()> {
+ ser::SerializeTuple::end(self)
+ }
+}
+
+impl<'a, W: io::Write> ser::SerializeMap for Compound<'a, W> {
+ type Error = Error;
+ type Ok = ();
+
+ fn serialize_key<T>(&mut self, key: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if let State::First = self.state {
+ self.state = State::Rest;
+ } else {
+ self.ser.output.write_all(b",")?;
+
+ if let Some((ref config, ref pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ } else {
+ self.ser.output.write_all(config.separator.as_bytes())?;
+ }
+ }
+ }
+ self.ser.indent()?;
+ guard_recursion! { self.ser => key.serialize(&mut *self.ser) }
+ }
+
+ fn serialize_value<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.ser.output.write_all(b":")?;
+
+ if let Some((ref config, _)) = self.ser.pretty {
+ self.ser.output.write_all(config.separator.as_bytes())?;
+ }
+
+ guard_recursion! { self.ser => value.serialize(&mut *self.ser)? };
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ if let State::Rest = self.state {
+ if let Some((ref config, ref pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ self.ser.output.write_all(b",")?;
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ }
+ self.ser.end_indent()?;
+ // map always disables `self.newtype_variant`
+ self.ser.output.write_all(b"}")?;
+ Ok(())
+ }
+}
+
+impl<'a, W: io::Write> ser::SerializeStruct for Compound<'a, W> {
+ type Error = Error;
+ type Ok = ();
+
+ fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if let State::First = self.state {
+ self.state = State::Rest;
+ } else {
+ self.ser.output.write_all(b",")?;
+
+ if let Some((ref config, ref pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ } else {
+ self.ser.output.write_all(config.separator.as_bytes())?;
+ }
+ }
+ }
+ self.ser.indent()?;
+ self.ser.write_identifier(key)?;
+ self.ser.output.write_all(b":")?;
+
+ if let Some((ref config, _)) = self.ser.pretty {
+ self.ser.output.write_all(config.separator.as_bytes())?;
+ }
+
+ guard_recursion! { self.ser => value.serialize(&mut *self.ser)? };
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ if let State::Rest = self.state {
+ if let Some((ref config, ref pretty)) = self.ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ self.ser.output.write_all(b",")?;
+ self.ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ }
+ self.ser.end_indent()?;
+ if !self.newtype_variant {
+ self.ser.output.write_all(b")")?;
+ }
+ Ok(())
+ }
+}
+
+impl<'a, W: io::Write> ser::SerializeStructVariant for Compound<'a, W> {
+ type Error = Error;
+ type Ok = ();
+
+ fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ ser::SerializeStruct::serialize_field(self, key, value)
+ }
+
+ fn end(self) -> Result<()> {
+ ser::SerializeStruct::end(self)
+ }
+}
diff --git a/third_party/rust/ron/src/ser/tests.rs b/third_party/rust/ron/src/ser/tests.rs
new file mode 100644
index 0000000000..fce7f00710
--- /dev/null
+++ b/third_party/rust/ron/src/ser/tests.rs
@@ -0,0 +1,147 @@
+use serde_derive::Serialize;
+
+use super::to_string;
+
+#[derive(Serialize)]
+struct EmptyStruct1;
+
+#[derive(Serialize)]
+struct EmptyStruct2 {}
+
+#[derive(Serialize)]
+struct MyStruct {
+ x: f32,
+ y: f32,
+}
+
+#[derive(Serialize)]
+enum MyEnum {
+ A,
+ B(bool),
+ C(bool, f32),
+ D { a: i32, b: i32 },
+}
+
+#[test]
+fn test_empty_struct() {
+ assert_eq!(to_string(&EmptyStruct1).unwrap(), "()");
+ assert_eq!(to_string(&EmptyStruct2 {}).unwrap(), "()");
+}
+
+#[test]
+fn test_struct() {
+ let my_struct = MyStruct { x: 4.0, y: 7.0 };
+
+ assert_eq!(to_string(&my_struct).unwrap(), "(x:4.0,y:7.0)");
+
+ #[derive(Serialize)]
+ struct NewType(i32);
+
+ assert_eq!(to_string(&NewType(42)).unwrap(), "(42)");
+
+ #[derive(Serialize)]
+ struct TupleStruct(f32, f32);
+
+ assert_eq!(to_string(&TupleStruct(2.0, 5.0)).unwrap(), "(2.0,5.0)");
+}
+
+#[test]
+fn test_option() {
+ assert_eq!(to_string(&Some(1u8)).unwrap(), "Some(1)");
+ assert_eq!(to_string(&None::<u8>).unwrap(), "None");
+}
+
+#[test]
+fn test_enum() {
+ assert_eq!(to_string(&MyEnum::A).unwrap(), "A");
+ assert_eq!(to_string(&MyEnum::B(true)).unwrap(), "B(true)");
+ assert_eq!(to_string(&MyEnum::C(true, 3.5)).unwrap(), "C(true,3.5)");
+ assert_eq!(to_string(&MyEnum::D { a: 2, b: 3 }).unwrap(), "D(a:2,b:3)");
+}
+
+#[test]
+fn test_array() {
+ let empty: [i32; 0] = [];
+ assert_eq!(to_string(&empty).unwrap(), "()");
+ let empty_ref: &[i32] = &empty;
+ assert_eq!(to_string(&empty_ref).unwrap(), "[]");
+
+ assert_eq!(to_string(&[2, 3, 4i32]).unwrap(), "(2,3,4)");
+ assert_eq!(to_string(&(&[2, 3, 4i32] as &[i32])).unwrap(), "[2,3,4]");
+}
+
+#[test]
+fn test_slice() {
+ assert_eq!(to_string(&[0, 1, 2, 3, 4, 5][..]).unwrap(), "[0,1,2,3,4,5]");
+ assert_eq!(to_string(&[0, 1, 2, 3, 4, 5][1..4]).unwrap(), "[1,2,3]");
+}
+
+#[test]
+fn test_vec() {
+ assert_eq!(to_string(&vec![0, 1, 2, 3, 4, 5]).unwrap(), "[0,1,2,3,4,5]");
+}
+
+#[test]
+fn test_map() {
+ use std::collections::HashMap;
+
+ let mut map = HashMap::new();
+ map.insert((true, false), 4);
+ map.insert((false, false), 123);
+
+ let s = to_string(&map).unwrap();
+ s.starts_with('{');
+ s.contains("(true,false):4");
+ s.contains("(false,false):123");
+ s.ends_with('}');
+}
+
+#[test]
+fn test_string() {
+ assert_eq!(to_string(&"Some string").unwrap(), "\"Some string\"");
+}
+
+#[test]
+fn test_char() {
+ assert_eq!(to_string(&'c').unwrap(), "'c'");
+}
+
+#[test]
+fn test_escape() {
+ assert_eq!(to_string(&r#""Quoted""#).unwrap(), r#""\"Quoted\"""#);
+}
+
+#[test]
+fn test_byte_stream() {
+ use serde_bytes;
+
+ let small: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+ assert_eq!(
+ to_string(&small).unwrap(),
+ "(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)"
+ );
+
+ let large = vec![255u8; 64];
+ let large = serde_bytes::Bytes::new(&large);
+ assert_eq!(
+ to_string(&large).unwrap(),
+ concat!(
+ "\"/////////////////////////////////////////",
+ "////////////////////////////////////////////w==\""
+ )
+ );
+}
+
+#[test]
+fn rename() {
+ #[derive(Serialize, Debug, PartialEq)]
+ enum Foo {
+ #[serde(rename = "2d")]
+ D2,
+ #[serde(rename = "triangle-list")]
+ TriangleList,
+ }
+
+ assert_eq!(to_string(&Foo::D2).unwrap(), "r#2d");
+ assert_eq!(to_string(&Foo::TriangleList).unwrap(), "r#triangle-list");
+}
diff --git a/third_party/rust/ron/src/ser/value.rs b/third_party/rust/ron/src/ser/value.rs
new file mode 100644
index 0000000000..1a47758986
--- /dev/null
+++ b/third_party/rust/ron/src/ser/value.rs
@@ -0,0 +1,23 @@
+use serde::ser::{Serialize, Serializer};
+
+use crate::value::{Number, Value};
+
+impl Serialize for Value {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match *self {
+ Value::Bool(b) => serializer.serialize_bool(b),
+ Value::Char(c) => serializer.serialize_char(c),
+ Value::Map(ref m) => Serialize::serialize(m, serializer),
+ Value::Number(Number::Float(ref f)) => serializer.serialize_f64(f.get()),
+ Value::Number(Number::Integer(i)) => serializer.serialize_i64(i),
+ Value::Option(Some(ref o)) => serializer.serialize_some(o.as_ref()),
+ Value::Option(None) => serializer.serialize_none(),
+ Value::String(ref s) => serializer.serialize_str(s),
+ Value::Seq(ref s) => Serialize::serialize(s, serializer),
+ Value::Unit => serializer.serialize_unit(),
+ }
+ }
+}
diff --git a/third_party/rust/ron/src/value.rs b/third_party/rust/ron/src/value.rs
new file mode 100644
index 0000000000..ba843bc16a
--- /dev/null
+++ b/third_party/rust/ron/src/value.rs
@@ -0,0 +1,619 @@
+//! Value module.
+
+use std::{
+ cmp::{Eq, Ordering},
+ hash::{Hash, Hasher},
+ iter::FromIterator,
+ ops::{Index, IndexMut},
+};
+
+use serde::{
+ de::{DeserializeOwned, DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor},
+ forward_to_deserialize_any,
+};
+use serde_derive::{Deserialize, Serialize};
+
+use crate::{de::Error, error::Result};
+
+/// A [`Value`] to [`Value`] map.
+///
+/// This structure either uses a [BTreeMap](std::collections::BTreeMap) or the
+/// [IndexMap](indexmap::IndexMap) internally.
+/// The latter can be used by enabling the `indexmap` feature. This can be used
+/// to preserve the order of the parsed map.
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
+#[serde(transparent)]
+pub struct Map(MapInner);
+
+impl Map {
+ /// Creates a new, empty [`Map`].
+ pub fn new() -> Map {
+ Default::default()
+ }
+
+ /// Returns the number of elements in the map.
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ /// Returns `true` if `self.len() == 0`, `false` otherwise.
+ pub fn is_empty(&self) -> bool {
+ self.0.len() == 0
+ }
+
+ /// Inserts a new element, returning the previous element with this `key` if
+ /// there was any.
+ pub fn insert(&mut self, key: Value, value: Value) -> Option<Value> {
+ self.0.insert(key, value)
+ }
+
+ /// Removes an element by its `key`.
+ pub fn remove(&mut self, key: &Value) -> Option<Value> {
+ self.0.remove(key)
+ }
+
+ /// Iterate all key-value pairs.
+ pub fn iter(&self) -> impl Iterator<Item = (&Value, &Value)> + DoubleEndedIterator {
+ self.0.iter()
+ }
+
+ /// Iterate all key-value pairs mutably.
+ pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Value, &mut Value)> + DoubleEndedIterator {
+ self.0.iter_mut()
+ }
+
+ /// Iterate all keys.
+ pub fn keys(&self) -> impl Iterator<Item = &Value> + DoubleEndedIterator {
+ self.0.keys()
+ }
+
+ /// Iterate all values.
+ pub fn values(&self) -> impl Iterator<Item = &Value> + DoubleEndedIterator {
+ self.0.values()
+ }
+
+ /// Iterate all values mutably.
+ pub fn values_mut(&mut self) -> impl Iterator<Item = &mut Value> + DoubleEndedIterator {
+ self.0.values_mut()
+ }
+
+ /// Retains only the elements specified by the `keep` predicate.
+ ///
+ /// In other words, remove all pairs `(k, v)` for which `keep(&k, &mut v)`
+ /// returns `false`.
+ ///
+ /// The elements are visited in iteration order.
+ pub fn retain<F>(&mut self, keep: F)
+ where
+ F: FnMut(&Value, &mut Value) -> bool,
+ {
+ self.0.retain(keep);
+ }
+}
+
+impl FromIterator<(Value, Value)> for Map {
+ fn from_iter<T: IntoIterator<Item = (Value, Value)>>(iter: T) -> Self {
+ Map(MapInner::from_iter(iter))
+ }
+}
+
+impl IntoIterator for Map {
+ type Item = (Value, Value);
+
+ type IntoIter = <MapInner as IntoIterator>::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.0.into_iter()
+ }
+}
+
+/// Note: equality is only given if both values and order of values match
+impl Eq for Map {}
+
+impl Hash for Map {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.iter().for_each(|x| x.hash(state));
+ }
+}
+
+impl Index<&Value> for Map {
+ type Output = Value;
+
+ fn index(&self, index: &Value) -> &Self::Output {
+ &self.0[index]
+ }
+}
+
+impl IndexMut<&Value> for Map {
+ fn index_mut(&mut self, index: &Value) -> &mut Self::Output {
+ self.0.get_mut(index).expect("no entry found for key")
+ }
+}
+
+impl Ord for Map {
+ fn cmp(&self, other: &Map) -> Ordering {
+ self.iter().cmp(other.iter())
+ }
+}
+
+/// Note: equality is only given if both values and order of values match
+impl PartialEq for Map {
+ fn eq(&self, other: &Map) -> bool {
+ self.iter().zip(other.iter()).all(|(a, b)| a == b)
+ }
+}
+
+impl PartialOrd for Map {
+ fn partial_cmp(&self, other: &Map) -> Option<Ordering> {
+ self.iter().partial_cmp(other.iter())
+ }
+}
+
+#[cfg(not(feature = "indexmap"))]
+type MapInner = std::collections::BTreeMap<Value, Value>;
+#[cfg(feature = "indexmap")]
+type MapInner = indexmap::IndexMap<Value, Value>;
+
+/// A wrapper for a number, which can be either [`f64`] or [`i64`].
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
+pub enum Number {
+ Integer(i64),
+ Float(Float),
+}
+
+/// A wrapper for [`f64`], which guarantees that the inner value
+/// is finite and thus implements [`Eq`], [`Hash`] and [`Ord`].
+#[derive(Copy, Clone, Debug)]
+pub struct Float(f64);
+
+impl Float {
+ /// Construct a new [`Float`].
+ pub fn new(v: f64) -> Self {
+ Float(v)
+ }
+
+ /// Returns the wrapped float.
+ pub fn get(self) -> f64 {
+ self.0
+ }
+}
+
+impl Number {
+ /// Construct a new number.
+ pub fn new(v: impl Into<Number>) -> Self {
+ v.into()
+ }
+
+ /// Returns the [`f64`] representation of the [`Number`] regardless of
+ /// whether the number is stored as a float or integer.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use ron::value::Number;
+ /// let i = Number::new(5);
+ /// let f = Number::new(2.0);
+ /// assert_eq!(i.into_f64(), 5.0);
+ /// assert_eq!(f.into_f64(), 2.0);
+ /// ```
+ pub fn into_f64(self) -> f64 {
+ self.map_to(|i| i as f64, |f| f)
+ }
+
+ /// If the [`Number`] is a float, return it. Otherwise return [`None`].
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use ron::value::Number;
+ /// let i = Number::new(5);
+ /// let f = Number::new(2.0);
+ /// assert_eq!(i.as_f64(), None);
+ /// assert_eq!(f.as_f64(), Some(2.0));
+ /// ```
+ pub fn as_f64(self) -> Option<f64> {
+ self.map_to(|_| None, Some)
+ }
+
+ /// If the [`Number`] is an integer, return it. Otherwise return [`None`].
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use ron::value::Number;
+ /// let i = Number::new(5);
+ /// let f = Number::new(2.0);
+ /// assert_eq!(i.as_i64(), Some(5));
+ /// assert_eq!(f.as_i64(), None);
+ /// ```
+ pub fn as_i64(self) -> Option<i64> {
+ self.map_to(Some, |_| None)
+ }
+
+ /// Map this number to a single type using the appropriate closure.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use ron::value::Number;
+ /// let i = Number::new(5);
+ /// let f = Number::new(2.0);
+ /// assert!(i.map_to(|i| i > 3, |f| f > 3.0));
+ /// assert!(!f.map_to(|i| i > 3, |f| f > 3.0));
+ /// ```
+ pub fn map_to<T>(
+ self,
+ integer_fn: impl FnOnce(i64) -> T,
+ float_fn: impl FnOnce(f64) -> T,
+ ) -> T {
+ match self {
+ Number::Integer(i) => integer_fn(i),
+ Number::Float(Float(f)) => float_fn(f),
+ }
+ }
+}
+
+impl From<f64> for Number {
+ fn from(f: f64) -> Number {
+ Number::Float(Float(f))
+ }
+}
+
+impl From<i64> for Number {
+ fn from(i: i64) -> Number {
+ Number::Integer(i)
+ }
+}
+
+impl From<i32> for Number {
+ fn from(i: i32) -> Number {
+ Number::Integer(i64::from(i))
+ }
+}
+
+/// The following [`Number`] conversion checks if the integer fits losslessly
+/// into an [`i64`], before constructing a [`Number::Integer`] variant.
+/// If not, the conversion defaults to [`Number::Float`].
+
+impl From<u64> for Number {
+ fn from(i: u64) -> Number {
+ if i <= std::i64::MAX as u64 {
+ Number::Integer(i as i64)
+ } else {
+ Number::new(i as f64)
+ }
+ }
+}
+
+/// Partial equality comparison
+/// In order to be able to use [`Number`] as a mapping key, NaN floating values
+/// wrapped in [`Float`] are equal to each other. It is not the case for
+/// underlying [`f64`] values itself.
+impl PartialEq for Float {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.is_nan() && other.0.is_nan() || self.0 == other.0
+ }
+}
+
+/// Equality comparison
+/// In order to be able to use [`Float`] as a mapping key, NaN floating values
+/// wrapped in [`Float`] are equal to each other. It is not the case for
+/// underlying [`f64`] values itself.
+impl Eq for Float {}
+
+impl Hash for Float {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ state.write_u64(self.0.to_bits());
+ }
+}
+
+/// Partial ordering comparison
+/// In order to be able to use [`Number`] as a mapping key, NaN floating values
+/// wrapped in [`Number`] are equal to each other and are less then any other
+/// floating value. It is not the case for the underlying [`f64`] values
+/// themselves.
+///
+/// ```
+/// use ron::value::Number;
+/// assert!(Number::new(std::f64::NAN) < Number::new(std::f64::NEG_INFINITY));
+/// assert_eq!(Number::new(std::f64::NAN), Number::new(std::f64::NAN));
+/// ```
+impl PartialOrd for Float {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ match (self.0.is_nan(), other.0.is_nan()) {
+ (true, true) => Some(Ordering::Equal),
+ (true, false) => Some(Ordering::Less),
+ (false, true) => Some(Ordering::Greater),
+ _ => self.0.partial_cmp(&other.0),
+ }
+ }
+}
+
+/// Ordering comparison
+/// In order to be able to use [`Float`] as a mapping key, NaN floating values
+/// wrapped in [`Float`] are equal to each other and are less then any other
+/// floating value. It is not the case for underlying [`f64`] values itself.
+/// See the [`PartialEq`] implementation.
+impl Ord for Float {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.partial_cmp(other).expect("Bug: Contract violation")
+ }
+}
+
+#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum Value {
+ Bool(bool),
+ Char(char),
+ Map(Map),
+ Number(Number),
+ Option(Option<Box<Value>>),
+ String(String),
+ Seq(Vec<Value>),
+ Unit,
+}
+
+impl Value {
+ /// Tries to deserialize this [`Value`] into `T`.
+ pub fn into_rust<T>(self) -> Result<T>
+ where
+ T: DeserializeOwned,
+ {
+ T::deserialize(self)
+ }
+}
+
+/// Deserializer implementation for RON [`Value`].
+/// This does not support enums (because [`Value`] does not store them).
+impl<'de> Deserializer<'de> for Value {
+ type Error = Error;
+
+ forward_to_deserialize_any! {
+ bool f32 f64 char str string bytes
+ byte_buf option unit unit_struct newtype_struct seq tuple
+ tuple_struct map struct enum identifier ignored_any
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Bool(b) => visitor.visit_bool(b),
+ Value::Char(c) => visitor.visit_char(c),
+ Value::Map(m) => {
+ let old_len = m.len();
+
+ let mut items: Vec<(Value, Value)> = m.into_iter().collect();
+ items.reverse();
+
+ let value = visitor.visit_map(MapAccessor {
+ items: &mut items,
+ value: None,
+ })?;
+
+ if items.is_empty() {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedDifferentLength {
+ expected: format!("a map of length {}", old_len - items.len()),
+ found: old_len,
+ })
+ }
+ }
+ Value::Number(Number::Float(ref f)) => visitor.visit_f64(f.get()),
+ Value::Number(Number::Integer(i)) => visitor.visit_i64(i),
+ Value::Option(Some(o)) => visitor.visit_some(*o),
+ Value::Option(None) => visitor.visit_none(),
+ Value::String(s) => visitor.visit_string(s),
+ Value::Seq(mut seq) => {
+ let old_len = seq.len();
+
+ seq.reverse();
+ let value = visitor.visit_seq(Seq { seq: &mut seq })?;
+
+ if seq.is_empty() {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedDifferentLength {
+ expected: format!("a sequence of length {}", old_len - seq.len()),
+ found: old_len,
+ })
+ }
+ }
+ Value::Unit => visitor.visit_unit(),
+ }
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_i64(visitor)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_i64(visitor)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_i64(visitor)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Number(Number::Integer(i)) => visitor.visit_i64(i),
+ v => Err(Error::Message(format!("Expected a number, got {:?}", v))),
+ }
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_u64(visitor)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_u64(visitor)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_u64(visitor)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Number(Number::Integer(i)) => visitor.visit_u64(i as u64),
+ v => Err(Error::Message(format!("Expected a number, got {:?}", v))),
+ }
+ }
+}
+
+struct MapAccessor<'a> {
+ items: &'a mut Vec<(Value, Value)>,
+ value: Option<Value>,
+}
+
+impl<'a, 'de> MapAccess<'de> for MapAccessor<'a> {
+ type Error = Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
+ where
+ K: DeserializeSeed<'de>,
+ {
+ // The `Vec` is reversed, so we can pop to get the originally first element
+ match self.items.pop() {
+ Some((key, value)) => {
+ self.value = Some(value);
+ seed.deserialize(key).map(Some)
+ }
+ None => Ok(None),
+ }
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ match self.value.take() {
+ Some(value) => seed.deserialize(value),
+ None => panic!("Contract violation: value before key"),
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ Some(self.items.len())
+ }
+}
+
+struct Seq<'a> {
+ seq: &'a mut Vec<Value>,
+}
+
+impl<'a, 'de> SeqAccess<'de> for Seq<'a> {
+ type Error = Error;
+
+ fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ // The `Vec` is reversed, so we can pop to get the originally first element
+ self.seq
+ .pop()
+ .map_or(Ok(None), |v| seed.deserialize(v).map(Some))
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ Some(self.seq.len())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::{collections::BTreeMap, fmt::Debug};
+
+ use serde::Deserialize;
+
+ use super::*;
+
+ fn assert_same<'de, T>(s: &'de str)
+ where
+ T: Debug + Deserialize<'de> + PartialEq,
+ {
+ use crate::de::from_str;
+
+ let direct: T = from_str(s).unwrap();
+ let value: Value = from_str(s).unwrap();
+ let value = T::deserialize(value).unwrap();
+
+ assert_eq!(direct, value, "Deserialization for {:?} is not the same", s);
+ }
+
+ #[test]
+ fn boolean() {
+ assert_same::<bool>("true");
+ assert_same::<bool>("false");
+ }
+
+ #[test]
+ fn float() {
+ assert_same::<f64>("0.123");
+ assert_same::<f64>("-4.19");
+ }
+
+ #[test]
+ fn int() {
+ assert_same::<u32>("626");
+ assert_same::<i32>("-50");
+ }
+
+ #[test]
+ fn char() {
+ assert_same::<char>("'4'");
+ assert_same::<char>("'c'");
+ }
+
+ #[test]
+ fn map() {
+ assert_same::<BTreeMap<char, String>>(
+ "{
+'a': \"Hello\",
+'b': \"Bye\",
+ }",
+ );
+ }
+
+ #[test]
+ fn option() {
+ assert_same::<Option<char>>("Some('a')");
+ assert_same::<Option<char>>("None");
+ }
+
+ #[test]
+ fn seq() {
+ assert_same::<Vec<f64>>("[1.0, 2.0, 3.0, 4.0]");
+ }
+
+ #[test]
+ fn unit() {
+ assert_same::<()>("()");
+ }
+}
diff --git a/third_party/rust/ron/tests/117_untagged_tuple_variant.rs b/third_party/rust/ron/tests/117_untagged_tuple_variant.rs
new file mode 100644
index 0000000000..6d98deb65c
--- /dev/null
+++ b/third_party/rust/ron/tests/117_untagged_tuple_variant.rs
@@ -0,0 +1,59 @@
+use std::borrow::Cow;
+
+use ron::{de::from_str, ser::to_string};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
+pub struct BuildSystem<'m> {
+ version: Cow<'m, str>,
+ flags: Vec<Flag<'m>>,
+}
+
+#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
+#[serde(untagged)]
+pub enum Flag<'m> {
+ Value(Cow<'m, str>),
+ If(Cow<'m, str>, Vec<Cow<'m, str>>),
+}
+
+#[test]
+fn test_ebkalderon_case() {
+ let file = r#"BuildSystem(
+ version: "1.0.0",
+ flags: [
+ "--enable-thing",
+ "--enable-other-thing",
+ If("some-conditional", ["--enable-third-thing"]),
+ ]
+)
+"#;
+
+ assert_eq!(
+ from_str::<BuildSystem>(file).unwrap(),
+ BuildSystem {
+ version: "1.0.0".into(),
+ flags: vec![
+ Flag::Value("--enable-thing".into()),
+ Flag::Value("--enable-other-thing".into()),
+ Flag::If(
+ "some-conditional".into(),
+ vec!["--enable-third-thing".into()]
+ )
+ ]
+ },
+ );
+}
+
+#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
+#[serde(untagged)]
+enum Foo {
+ Bar(usize),
+}
+
+#[test]
+fn test_vessd_case() {
+ let foo_vec = vec![Foo::Bar(0); 5];
+ let foo_str = to_string(&foo_vec).unwrap();
+ assert_eq!(foo_str.as_str(), "[0,0,0,0,0]");
+ assert_eq!(from_str::<Vec<Foo>>(&foo_str).unwrap(), foo_vec);
+}
diff --git a/third_party/rust/ron/tests/123_enum_representation.rs b/third_party/rust/ron/tests/123_enum_representation.rs
new file mode 100644
index 0000000000..414350f694
--- /dev/null
+++ b/third_party/rust/ron/tests/123_enum_representation.rs
@@ -0,0 +1,274 @@
+use std::{cmp::PartialEq, fmt::Debug};
+
+use ron::{de::from_str, ser::to_string};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+enum Inner {
+ Foo,
+ Bar,
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+enum EnumStructExternally {
+ VariantA { foo: u32, bar: u32, different: u32 },
+ VariantB { foo: u32, bar: u32 },
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(tag = "type")]
+enum EnumStructInternally {
+ VariantA { foo: u32, bar: u32, different: u32 },
+ VariantB { foo: u32, bar: u32 },
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(tag = "type", content = "content")]
+enum EnumStructAdjacently {
+ VariantA {
+ foo: u32,
+ bar: u32,
+ different: Inner,
+ },
+ VariantB {
+ foo: u32,
+ bar: u32,
+ },
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(untagged)]
+enum EnumStructUntagged {
+ VariantA { foo: u32, bar: u32, different: u32 },
+ VariantB { foo: u32, bar: u32 },
+}
+
+fn test_ser<T: Serialize>(value: &T, expected: &str) {
+ let actual = to_string(value).expect("Failed to serialize");
+ assert_eq!(actual, expected);
+}
+
+fn test_de<T>(s: &str, expected: T)
+where
+ T: for<'a> Deserialize<'a> + Debug + PartialEq,
+{
+ let actual: Result<T, _> = from_str(s);
+ assert_eq!(actual, Ok(expected));
+}
+
+fn test_roundtrip<T>(value: T)
+where
+ T: Serialize + for<'a> Deserialize<'a> + Debug + PartialEq,
+{
+ let s = to_string(&value).expect("Failed to serialize");
+ let actual: Result<T, _> = from_str(&s);
+ assert_eq!(actual, Ok(value));
+}
+
+#[test]
+fn test_externally_a_ser() {
+ let v = EnumStructExternally::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ let e = "VariantA(foo:1,bar:2,different:3)";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_externally_b_ser() {
+ let v = EnumStructExternally::VariantB { foo: 1, bar: 2 };
+ let e = "VariantB(foo:1,bar:2)";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_internally_a_ser() {
+ let v = EnumStructInternally::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ let e = "(type:\"VariantA\",foo:1,bar:2,different:3)";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_internally_b_ser() {
+ let v = EnumStructInternally::VariantB { foo: 1, bar: 2 };
+ let e = "(type:\"VariantB\",foo:1,bar:2)";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_adjacently_a_ser() {
+ let v = EnumStructAdjacently::VariantA {
+ foo: 1,
+ bar: 2,
+ different: Inner::Foo,
+ };
+ let e = "(type:VariantA,content:(foo:1,bar:2,different:Foo))";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_adjacently_b_ser() {
+ let v = EnumStructAdjacently::VariantB { foo: 1, bar: 2 };
+ let e = "(type:VariantB,content:(foo:1,bar:2))";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_untagged_a_ser() {
+ let v = EnumStructUntagged::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ let e = "(foo:1,bar:2,different:3)";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_untagged_b_ser() {
+ let v = EnumStructUntagged::VariantB { foo: 1, bar: 2 };
+ let e = "(foo:1,bar:2)";
+ test_ser(&v, e);
+}
+
+#[test]
+fn test_externally_a_de() {
+ let s = "VariantA(foo:1,bar:2,different:3)";
+ let e = EnumStructExternally::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ test_de(s, e);
+}
+
+#[test]
+fn test_externally_b_de() {
+ let s = "VariantB(foo:1,bar:2)";
+ let e = EnumStructExternally::VariantB { foo: 1, bar: 2 };
+ test_de(s, e);
+}
+
+#[test]
+fn test_internally_a_de() {
+ let s = "(type:\"VariantA\",foo:1,bar:2,different:3)";
+ let e = EnumStructInternally::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ test_de(s, e);
+}
+
+#[test]
+fn test_internally_b_de() {
+ let s = "(type:\"VariantB\",foo:1,bar:2)";
+ let e = EnumStructInternally::VariantB { foo: 1, bar: 2 };
+ test_de(s, e);
+}
+
+#[test]
+fn test_adjacently_a_de() {
+ let s = "(type:VariantA,content:(foo:1,bar:2,different:Foo))";
+ let e = EnumStructAdjacently::VariantA {
+ foo: 1,
+ bar: 2,
+ different: Inner::Foo,
+ };
+ test_de(s, e);
+}
+
+#[test]
+fn test_adjacently_b_de() {
+ let s = "(type:VariantB,content:(foo:1,bar:2))";
+ let e = EnumStructAdjacently::VariantB { foo: 1, bar: 2 };
+ test_de(s, e);
+}
+
+#[test]
+fn test_untagged_a_de() {
+ let s = "(foo:1,bar:2,different:3)";
+ let e = EnumStructUntagged::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ test_de(s, e);
+}
+
+#[test]
+fn test_untagged_b_de() {
+ let s = "(foo:1,bar:2)";
+ let e = EnumStructUntagged::VariantB { foo: 1, bar: 2 };
+ test_de(s, e);
+}
+
+#[test]
+fn test_externally_a_roundtrip() {
+ let v = EnumStructExternally::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ test_roundtrip(v);
+}
+
+#[test]
+fn test_externally_b_roundtrip() {
+ let v = EnumStructExternally::VariantB { foo: 1, bar: 2 };
+ test_roundtrip(v);
+}
+
+#[test]
+fn test_internally_a_roundtrip() {
+ let v = EnumStructInternally::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ test_roundtrip(v);
+}
+
+#[test]
+fn test_internally_b_roundtrip() {
+ let v = EnumStructInternally::VariantB { foo: 1, bar: 2 };
+ test_roundtrip(v);
+}
+
+#[test]
+fn test_adjacently_a_roundtrip() {
+ let v = EnumStructAdjacently::VariantA {
+ foo: 1,
+ bar: 2,
+ different: Inner::Foo,
+ };
+ test_roundtrip(v);
+}
+
+#[test]
+fn test_adjacently_b_roundtrip() {
+ let v = EnumStructAdjacently::VariantB { foo: 1, bar: 2 };
+ test_roundtrip(v);
+}
+
+#[test]
+fn test_untagged_a_roundtrip() {
+ let v = EnumStructUntagged::VariantA {
+ foo: 1,
+ bar: 2,
+ different: 3,
+ };
+ test_roundtrip(v);
+}
+
+#[test]
+fn test_untagged_b_roundtrip() {
+ let v = EnumStructUntagged::VariantB { foo: 1, bar: 2 };
+ test_roundtrip(v);
+}
diff --git a/third_party/rust/ron/tests/129_indexmap.rs b/third_party/rust/ron/tests/129_indexmap.rs
new file mode 100644
index 0000000000..7fae993548
--- /dev/null
+++ b/third_party/rust/ron/tests/129_indexmap.rs
@@ -0,0 +1,76 @@
+#[cfg(feature = "indexmap")]
+use ron::{de::from_str, Value};
+
+#[test]
+#[cfg(feature = "indexmap")]
+fn test_order_preserved() {
+ let file = r#"(
+tasks: {
+ "debug message": Dbg(
+ msg: "test message. some text after it."
+ ),
+ "shell command": Shell(
+ command: "ls",
+ args: Some([
+ "-l",
+ "-h",
+ ]),
+ ch_dir: Some("/"),
+ ),
+},
+)
+"#;
+
+ let value: Value = from_str(file).unwrap();
+ match value {
+ Value::Map(map) => match &map[&Value::String("tasks".to_owned())] {
+ Value::Map(map) => {
+ assert_eq!(
+ *map.keys().next().unwrap(),
+ Value::String("debug message".to_string())
+ );
+ assert_eq!(
+ *map.keys().nth(1).unwrap(),
+ Value::String("shell command".to_string())
+ );
+ }
+ _ => panic!(), // GRCOV_EXCL_LINE
+ },
+ _ => panic!(), // GRCOV_EXCL_LINE
+ }
+
+ let file = r#"(
+tasks: {
+ "shell command": Shell(
+ command: "ls",
+ args: Some([
+ "-l",
+ "-h",
+ ]),
+ ch_dir: Some("/")
+ ),
+ "debug message": Dbg(
+ msg: "test message. some text after it."
+ ),
+}
+)
+"#;
+
+ let value: Value = from_str(file).unwrap();
+ match value {
+ Value::Map(map) => match &map[&Value::String("tasks".to_owned())] {
+ Value::Map(map) => {
+ assert_eq!(
+ *map.keys().next().unwrap(),
+ Value::String("shell command".to_string())
+ );
+ assert_eq!(
+ *map.keys().nth(1).unwrap(),
+ Value::String("debug message".to_string())
+ );
+ }
+ _ => panic!(), // GRCOV_EXCL_LINE
+ },
+ _ => panic!(), // GRCOV_EXCL_LINE
+ }
+}
diff --git a/third_party/rust/ron/tests/147_empty_sets_serialisation.rs b/third_party/rust/ron/tests/147_empty_sets_serialisation.rs
new file mode 100644
index 0000000000..d93f9dd118
--- /dev/null
+++ b/third_party/rust/ron/tests/147_empty_sets_serialisation.rs
@@ -0,0 +1,63 @@
+use std::collections::HashMap;
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct UnitStruct;
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct NewType(f32);
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct TupleStruct(UnitStruct, i8);
+
+#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
+struct Key(u32);
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct Struct {
+ tuple: ((), NewType, TupleStruct),
+ vec: Vec<Option<UnitStruct>>,
+ map: HashMap<Key, i32>,
+ deep_vec: HashMap<Key, Vec<()>>,
+ deep_map: HashMap<Key, HashMap<Key, i32>>,
+}
+
+#[test]
+fn empty_sets_arrays() {
+ let value = Struct {
+ tuple: ((), NewType(0.5), TupleStruct(UnitStruct, -5)),
+ vec: vec![],
+ map: vec![].into_iter().collect(),
+ deep_vec: vec![(Key(0), vec![])].into_iter().collect(),
+ deep_map: vec![(Key(0), vec![].into_iter().collect())]
+ .into_iter()
+ .collect(),
+ };
+
+ let pretty = ron::ser::PrettyConfig::new()
+ .enumerate_arrays(true)
+ .new_line("\n".to_string());
+ let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
+
+ println!("Serialized: {}", serial);
+
+ assert_eq!(
+ "(
+ tuple: ((), (0.5), ((), -5)),
+ vec: [],
+ map: {},
+ deep_vec: {
+ (0): [],
+ },
+ deep_map: {
+ (0): {},
+ },
+)",
+ serial
+ );
+
+ let deserial = ron::de::from_str(&serial);
+
+ assert_eq!(Ok(value), deserial);
+}
diff --git a/third_party/rust/ron/tests/152_bitflags.rs b/third_party/rust/ron/tests/152_bitflags.rs
new file mode 100644
index 0000000000..b4085b93d2
--- /dev/null
+++ b/third_party/rust/ron/tests/152_bitflags.rs
@@ -0,0 +1,57 @@
+use bitflags::bitflags;
+use option_set::option_set;
+
+bitflags! {
+ #[derive(
+ Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
+ serde::Serialize, serde::Deserialize,
+ )]
+ struct TestGood: u8 {
+ const ONE = 1;
+ const TWO = 1 << 1;
+ const THREE = 1 << 2;
+ }
+}
+
+option_set! {
+ struct TestBad: UpperCamel + u8 {
+ const ONE = 1;
+ const TWO = 1 << 1;
+ const THREE = 1 << 2;
+ }
+}
+
+#[test]
+fn test_bitflags() {
+ // Test case provided by jaynus in
+ // https://github.com/ron-rs/ron/issues/152#issue-421298302
+
+ let flag_good = TestGood::ONE | TestGood::TWO;
+
+ let json_ser_good = serde_json::ser::to_string(&flag_good).unwrap();
+ let ron_ser_good = ron::ser::to_string(&flag_good).unwrap();
+
+ assert_eq!(json_ser_good, "\"ONE | TWO\"");
+ assert_eq!(ron_ser_good, "(\"ONE | TWO\")");
+
+ let json_de_good: TestGood = serde_json::de::from_str(json_ser_good.as_str()).unwrap();
+ let ron_de_good: TestGood = ron::de::from_str(ron_ser_good.as_str()).unwrap();
+
+ assert_eq!(json_de_good, flag_good);
+ assert_eq!(ron_de_good, flag_good);
+
+ // option_set
+ let flag_bad = TestBad::ONE | TestBad::TWO;
+
+ let json_ser_bad = serde_json::ser::to_string(&flag_bad).unwrap();
+ let ron_ser_bad = ron::ser::to_string(&flag_bad).unwrap();
+
+ assert_eq!(json_ser_bad, "[\"One\",\"Two\"]");
+ assert_eq!(ron_ser_bad, "[\"One\",\"Two\"]");
+
+ let json_de_bad: TestBad = serde_json::de::from_str(json_ser_bad.as_str()).unwrap();
+ let ron_de_bad: TestBad = ron::de::from_str(ron_ser_bad.as_str()).unwrap();
+
+ assert_eq!(json_de_bad, flag_bad);
+ assert_eq!(ron_de_bad, flag_bad);
+}
diff --git a/third_party/rust/ron/tests/203_error_positions.rs b/third_party/rust/ron/tests/203_error_positions.rs
new file mode 100644
index 0000000000..153e3f5ba2
--- /dev/null
+++ b/third_party/rust/ron/tests/203_error_positions.rs
@@ -0,0 +1,105 @@
+use std::num::NonZeroU32;
+
+use ron::error::{Error, Position, SpannedError};
+use serde::{
+ de::{Deserialize, Error as DeError, Unexpected},
+ Deserializer,
+};
+
+#[derive(Debug, serde::Deserialize, PartialEq)]
+#[serde(deny_unknown_fields)]
+enum Test {
+ TupleVariant(i32, String),
+ StructVariant { a: bool, b: NonZeroU32, c: i32 },
+}
+
+#[derive(Debug, PartialEq)] // GRCOV_EXCL_LINE
+struct TypeError;
+
+impl<'de> Deserialize<'de> for TypeError {
+ fn deserialize<D: Deserializer<'de>>(_deserializer: D) -> Result<Self, D::Error> {
+ Err(D::Error::invalid_type(Unexpected::Unit, &"impossible"))
+ }
+}
+
+#[test]
+fn test_error_positions() {
+ assert_eq!(
+ ron::from_str::<TypeError>(" ()"),
+ Err(SpannedError {
+ code: Error::InvalidValueForType {
+ expected: String::from("impossible"),
+ found: String::from("a unit value"),
+ },
+ position: Position { line: 1, col: 3 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<Test>("StructVariant(a: true, b: 0, c: -42)"),
+ Err(SpannedError {
+ code: Error::InvalidValueForType {
+ expected: String::from("a nonzero u32"),
+ found: String::from("the unsigned integer `0`"),
+ },
+ position: Position { line: 1, col: 28 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<Test>("TupleVariant(42)"),
+ Err(SpannedError {
+ code: Error::ExpectedDifferentLength {
+ expected: String::from("tuple variant Test::TupleVariant with 2 elements"),
+ found: 1,
+ },
+ position: Position { line: 1, col: 16 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<Test>("NotAVariant"),
+ Err(SpannedError {
+ code: Error::NoSuchEnumVariant {
+ expected: &["TupleVariant", "StructVariant"],
+ found: String::from("NotAVariant"),
+ outer: Some(String::from("Test")),
+ },
+ position: Position { line: 1, col: 12 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<Test>("StructVariant(a: true, b: 1, c: -42, d: \"gotcha\")"),
+ Err(SpannedError {
+ code: Error::NoSuchStructField {
+ expected: &["a", "b", "c"],
+ found: String::from("d"),
+ outer: Some(String::from("StructVariant")),
+ },
+ position: Position { line: 1, col: 39 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<Test>("StructVariant(a: true, c: -42)"),
+ Err(SpannedError {
+ code: Error::MissingStructField {
+ field: "b",
+ outer: Some(String::from("StructVariant")),
+ },
+ position: Position { line: 1, col: 30 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<Test>("StructVariant(a: true, b: 1, a: false, c: -42)"),
+ Err(SpannedError {
+ code: Error::DuplicateStructField {
+ field: "a",
+ outer: Some(String::from("StructVariant")),
+ },
+ position: Position { line: 1, col: 31 },
+ })
+ );
+}
diff --git a/third_party/rust/ron/tests/207_adjacently_tagged_enum.rs b/third_party/rust/ron/tests/207_adjacently_tagged_enum.rs
new file mode 100644
index 0000000000..8a81d753ed
--- /dev/null
+++ b/third_party/rust/ron/tests/207_adjacently_tagged_enum.rs
@@ -0,0 +1,22 @@
+use ron::{de::from_str, ser::to_string};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(tag = "type", content = "data")]
+enum TestEnum {
+ Name(String),
+ Index(u32),
+}
+
+#[test]
+fn test_adjacently_tagged() {
+ let source = TestEnum::Index(1);
+
+ let ron_string = to_string(&source).unwrap();
+
+ assert_eq!(ron_string, "(type:Index,data:1)");
+
+ let deserialized = from_str::<TestEnum>(&ron_string).unwrap();
+
+ assert_eq!(deserialized, source);
+}
diff --git a/third_party/rust/ron/tests/238_array.rs b/third_party/rust/ron/tests/238_array.rs
new file mode 100644
index 0000000000..8429f804ce
--- /dev/null
+++ b/third_party/rust/ron/tests/238_array.rs
@@ -0,0 +1,51 @@
+use ron::{
+ error::{Error, Position, SpannedError},
+ value::{Number, Value},
+};
+
+#[test]
+fn test_array() {
+ let array: [i32; 3] = [1, 2, 3];
+
+ let ser = ron::to_string(&array).unwrap();
+ assert_eq!(ser, "(1,2,3)");
+
+ let de: [i32; 3] = ron::from_str(&ser).unwrap();
+ assert_eq!(de, array);
+
+ let value: Value = ron::from_str(&ser).unwrap();
+ assert_eq!(
+ value,
+ Value::Seq(vec![
+ Value::Number(Number::from(1)),
+ Value::Number(Number::from(2)),
+ Value::Number(Number::from(3)),
+ ])
+ );
+
+ let ser = ron::to_string(&value).unwrap();
+ assert_eq!(ser, "[1,2,3]");
+
+ let de: [i32; 3] = value.into_rust().unwrap();
+ assert_eq!(de, array);
+
+ // FIXME: fails and hence arrays do not roundtrip
+ let de: SpannedError = ron::from_str::<[i32; 3]>(&ser).unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::ExpectedStructLike,
+ position: Position { line: 1, col: 1 },
+ }
+ );
+
+ let value: Value = ron::from_str(&ser).unwrap();
+ assert_eq!(
+ value,
+ Value::Seq(vec![
+ Value::Number(Number::from(1)),
+ Value::Number(Number::from(2)),
+ Value::Number(Number::from(3)),
+ ])
+ );
+}
diff --git a/third_party/rust/ron/tests/240_array_pretty.rs b/third_party/rust/ron/tests/240_array_pretty.rs
new file mode 100644
index 0000000000..db49f57677
--- /dev/null
+++ b/third_party/rust/ron/tests/240_array_pretty.rs
@@ -0,0 +1,52 @@
+use ron::ser::{to_string_pretty, PrettyConfig};
+
+#[test]
+fn small_array() {
+ let arr = &[(), (), ()][..];
+ assert_eq!(
+ to_string_pretty(&arr, PrettyConfig::new().new_line("\n".to_string())).unwrap(),
+ "[
+ (),
+ (),
+ (),
+]"
+ );
+ assert_eq!(
+ to_string_pretty(
+ &arr,
+ PrettyConfig::new()
+ .new_line("\n".to_string())
+ .compact_arrays(true)
+ )
+ .unwrap(),
+ "[(), (), ()]"
+ );
+ assert_eq!(
+ to_string_pretty(
+ &arr,
+ PrettyConfig::new()
+ .new_line("\n".to_string())
+ .compact_arrays(true)
+ .separator("".to_string())
+ )
+ .unwrap(),
+ "[(),(),()]"
+ );
+ assert_eq!(
+ to_string_pretty(
+ &vec![(1, 2), (3, 4)],
+ PrettyConfig::new()
+ .new_line("\n".to_string())
+ .separate_tuple_members(true)
+ .compact_arrays(true)
+ )
+ .unwrap(),
+ "[(
+ 1,
+ 2,
+), (
+ 3,
+ 4,
+)]"
+ );
+}
diff --git a/third_party/rust/ron/tests/250_variant_newtypes.rs b/third_party/rust/ron/tests/250_variant_newtypes.rs
new file mode 100644
index 0000000000..55673e92b9
--- /dev/null
+++ b/third_party/rust/ron/tests/250_variant_newtypes.rs
@@ -0,0 +1,410 @@
+use std::collections::HashMap;
+
+use ron::{
+ de::from_str,
+ error::Error,
+ extensions::Extensions,
+ ser::{to_string_pretty, PrettyConfig},
+};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
+enum TestEnum {
+ Unit,
+ PrimitiveNewtype(String),
+ Tuple(u32, bool),
+ Struct { a: u32, b: bool },
+ TupleNewtypeUnit(Unit),
+ TupleNewtypeNewtype(Newtype),
+ TupleNewtypeTuple((u32, bool)),
+ TupleNewtypeTupleStruct(TupleStruct),
+ TupleNewtypeStruct(Struct),
+ TupleNewtypeEnum(Enum),
+ TupleNewtypeOption(Option<Struct>),
+ TupleNewtypeSeq(Vec<Struct>),
+ TupleNewtypeMap(HashMap<u32, Struct>),
+}
+
+#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
+struct Unit;
+
+#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
+struct Newtype(i32);
+
+#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
+struct TupleStruct(u32, bool);
+
+#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
+struct Struct {
+ a: u32,
+ b: bool,
+}
+
+#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
+enum Enum {
+ A,
+ B(Struct),
+ C(u32, bool),
+ D { a: u32, b: bool },
+}
+
+#[test]
+fn test_deserialise_non_newtypes() {
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] Unit"#).unwrap(),
+ TestEnum::Unit,
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] PrimitiveNewtype("hi")"#)
+ .unwrap(),
+ TestEnum::PrimitiveNewtype(String::from("hi")),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] Tuple(4, false)"#).unwrap(),
+ TestEnum::Tuple(4, false),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] Struct(a: 4, b: false)"#)
+ .unwrap(),
+ TestEnum::Struct { a: 4, b: false },
+ );
+}
+
+#[test]
+fn test_deserialise_tuple_newtypes() {
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeUnit(Unit)"#)
+ .unwrap_err()
+ .code,
+ Error::ExpectedStructLikeEnd,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeUnit(())"#)
+ .unwrap_err()
+ .code,
+ Error::ExpectedStructLikeEnd,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeUnit()"#).unwrap(),
+ TestEnum::TupleNewtypeUnit(Unit),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeNewtype(Newtype(4))"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedInteger,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeNewtype((4))"#)
+ .unwrap_err()
+ .code,
+ Error::ExpectedInteger,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeNewtype(4)"#)
+ .unwrap(),
+ TestEnum::TupleNewtypeNewtype(Newtype(4)),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_newtypes)] TupleNewtypeNewtype(4)"#).unwrap(),
+ TestEnum::TupleNewtypeNewtype(Newtype(4)),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_newtypes)] #![enable(unwrap_variant_newtypes)] TupleNewtypeNewtype(4)"#).unwrap(),
+ TestEnum::TupleNewtypeNewtype(Newtype(4)),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeTuple((4, false))"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedInteger,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeTuple(4, false)"#)
+ .unwrap(),
+ TestEnum::TupleNewtypeTuple((4, false)),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeTupleStruct(TupleStruct(4, false))"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedInteger,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeTupleStruct((4, false))"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedInteger,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeTupleStruct(4, false)"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeTupleStruct(TupleStruct(4, false)),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeStruct(Struct(a: 4, b: false))"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedMapColon,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeStruct((a: 4, b: false))"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedIdentifier,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeStruct(a: 4, b: false)"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeStruct(Struct { a: 4, b: false }),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeEnum(A)"#).unwrap(),
+ TestEnum::TupleNewtypeEnum(Enum::A),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeEnum(B(a: 4, b: false))"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeEnum(Enum::B(Struct { a: 4, b: false })),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeEnum(C 4, false)"#)
+ .unwrap_err()
+ .code,
+ Error::ExpectedStructLike,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeEnum(C(4, false))"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeEnum(Enum::C(4, false)),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeEnum(D a: 4, b: false)"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedStructLike,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeEnum(D(a: 4, b: false))"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeEnum(Enum::D { a: 4, b: false }),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeOption(None)"#)
+ .unwrap(),
+ TestEnum::TupleNewtypeOption(None),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeOption(Some(a: 4, b: false))"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeOption(Some(Struct { a: 4, b: false })),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeOption(a: 4, b: false)"#
+ )
+ .unwrap_err()
+ .code,
+ Error::ExpectedOption,
+ );
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes, implicit_some)] TupleNewtypeOption(a: 4, b: false)"#).unwrap(),
+ TestEnum::TupleNewtypeOption(Some(Struct { a: 4, b: false })),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeSeq([])"#).unwrap(),
+ TestEnum::TupleNewtypeSeq(vec![]),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeSeq([(a: 4, b: false)])"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeSeq(vec![Struct { a: 4, b: false }]),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeSeq([Struct(a: 4, b: false)])"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeSeq(vec![Struct { a: 4, b: false }]),
+ );
+
+ assert_eq!(
+ from_str::<TestEnum>(r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeMap({})"#).unwrap(),
+ TestEnum::TupleNewtypeMap(vec![].into_iter().collect()),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeMap({2: (a: 4, b: false)})"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeMap(vec![(2, Struct { a: 4, b: false })].into_iter().collect()),
+ );
+ assert_eq!(
+ from_str::<TestEnum>(
+ r#"#![enable(unwrap_variant_newtypes)] TupleNewtypeMap({8: Struct(a: 4, b: false)})"#
+ )
+ .unwrap(),
+ TestEnum::TupleNewtypeMap(vec![(8, Struct { a: 4, b: false })].into_iter().collect()),
+ );
+}
+
+#[test]
+fn test_serialise_non_newtypes() {
+ assert_eq_serialize_roundtrip(TestEnum::Unit, Extensions::UNWRAP_VARIANT_NEWTYPES);
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::PrimitiveNewtype(String::from("hi")),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::Tuple(4, false),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::Struct { a: 4, b: false },
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+}
+
+#[test]
+fn test_serialise_tuple_newtypes() {
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeUnit(Unit),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeNewtype(Newtype(4)),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeNewtype(Newtype(4)),
+ Extensions::UNWRAP_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeNewtype(Newtype(4)),
+ Extensions::UNWRAP_VARIANT_NEWTYPES | Extensions::UNWRAP_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeTuple((4, false)),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeTupleStruct(TupleStruct(4, false)),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeStruct(Struct { a: 4, b: false }),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeEnum(Enum::A),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeEnum(Enum::B(Struct { a: 4, b: false })),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeEnum(Enum::C(4, false)),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeEnum(Enum::D { a: 4, b: false }),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeOption(None),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeOption(Some(Struct { a: 4, b: false })),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeOption(Some(Struct { a: 4, b: false })),
+ Extensions::IMPLICIT_SOME,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeOption(Some(Struct { a: 4, b: false })),
+ Extensions::UNWRAP_VARIANT_NEWTYPES | Extensions::IMPLICIT_SOME,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeSeq(vec![]),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeSeq(vec![Struct { a: 4, b: false }]),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeMap(vec![].into_iter().collect()),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+ assert_eq_serialize_roundtrip(
+ TestEnum::TupleNewtypeMap(vec![(2, Struct { a: 4, b: false })].into_iter().collect()),
+ Extensions::UNWRAP_VARIANT_NEWTYPES,
+ );
+}
+
+fn assert_eq_serialize_roundtrip<
+ S: Serialize + serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
+>(
+ value: S,
+ extensions: Extensions,
+) {
+ assert_eq!(
+ from_str::<S>(
+ &to_string_pretty(&value, PrettyConfig::default().extensions(extensions)).unwrap()
+ )
+ .unwrap(),
+ value,
+ );
+}
diff --git a/third_party/rust/ron/tests/256_comma_error.rs b/third_party/rust/ron/tests/256_comma_error.rs
new file mode 100644
index 0000000000..4a873e4762
--- /dev/null
+++ b/third_party/rust/ron/tests/256_comma_error.rs
@@ -0,0 +1,72 @@
+#![allow(dead_code)]
+
+use ron::error::{Error, Position, SpannedError};
+
+#[derive(Debug, serde::Deserialize)]
+struct Test {
+ a: i32,
+ b: i32,
+}
+
+#[test]
+fn test_missing_comma_error() {
+ let tuple_string = r#"(
+ 1 // <-- forgotten comma here
+ 2
+ )"#;
+
+ assert_eq!(
+ ron::from_str::<(i32, i32)>(tuple_string).unwrap_err(),
+ SpannedError {
+ code: Error::ExpectedComma,
+ position: Position { line: 3, col: 9 }
+ }
+ );
+
+ let list_string = r#"[
+ 0,
+ 1 // <-- forgotten comma here
+ 2
+ ]"#;
+
+ assert_eq!(
+ ron::from_str::<Vec<i32>>(list_string).unwrap_err(),
+ SpannedError {
+ code: Error::ExpectedComma,
+ position: Position { line: 4, col: 9 }
+ }
+ );
+
+ let struct_string = r#"Test(
+ a: 1 // <-- forgotten comma here
+ b: 2
+ )"#;
+
+ assert_eq!(
+ ron::from_str::<Test>(struct_string).unwrap_err(),
+ SpannedError {
+ code: Error::ExpectedComma,
+ position: Position { line: 3, col: 9 }
+ }
+ );
+
+ let map_string = r#"{
+ "a": 1 // <-- forgotten comma here
+ "b": 2
+ }"#;
+
+ assert_eq!(
+ ron::from_str::<std::collections::HashMap<String, i32>>(map_string).unwrap_err(),
+ SpannedError {
+ code: Error::ExpectedComma,
+ position: Position { line: 3, col: 9 }
+ }
+ );
+}
+
+#[test]
+fn test_comma_end() {
+ assert_eq!(ron::from_str::<(i32, i32)>("(0, 1)").unwrap(), (0, 1));
+ assert_eq!(ron::from_str::<(i32, i32)>("(0, 1,)").unwrap(), (0, 1));
+ assert_eq!(ron::from_str::<()>("()"), Ok(()));
+}
diff --git a/third_party/rust/ron/tests/289_enumerate_arrays.rs b/third_party/rust/ron/tests/289_enumerate_arrays.rs
new file mode 100644
index 0000000000..6e0d5c3071
--- /dev/null
+++ b/third_party/rust/ron/tests/289_enumerate_arrays.rs
@@ -0,0 +1,47 @@
+const EXPTECTED: &str = "[
+ /*[0]*/ None,
+ /*[1]*/ Some([]),
+ /*[2]*/ Some([
+ /*[0]*/ 42,
+ ]),
+ /*[3]*/ Some([
+ /*[0]*/ 4,
+ /*[1]*/ 2,
+ ]),
+ /*[4]*/ None,
+]";
+
+const EXPTECTED_COMPACT: &str = "[/*[0]*/ None, /*[1]*/ Some([]), /*[2]*/ Some([/*[0]*/ 42]), \
+/*[3]*/ Some([/*[0]*/ 4, /*[1]*/ 2]), /*[4]*/ None]";
+
+#[test]
+fn enumerate_arrays() {
+ let v: Vec<Option<Vec<u8>>> = vec![None, Some(vec![]), Some(vec![42]), Some(vec![4, 2]), None];
+
+ let pretty = ron::ser::PrettyConfig::new().enumerate_arrays(true);
+
+ let ser = ron::ser::to_string_pretty(&v, pretty).unwrap();
+
+ assert_eq!(ser, EXPTECTED);
+
+ let de: Vec<Option<Vec<u8>>> = ron::from_str(&ser).unwrap();
+
+ assert_eq!(v, de)
+}
+
+#[test]
+fn enumerate_compact_arrays() {
+ let v: Vec<Option<Vec<u8>>> = vec![None, Some(vec![]), Some(vec![42]), Some(vec![4, 2]), None];
+
+ let pretty = ron::ser::PrettyConfig::new()
+ .enumerate_arrays(true)
+ .compact_arrays(true);
+
+ let ser = ron::ser::to_string_pretty(&v, pretty).unwrap();
+
+ assert_eq!(ser, EXPTECTED_COMPACT);
+
+ let de: Vec<Option<Vec<u8>>> = ron::from_str(&ser).unwrap();
+
+ assert_eq!(v, de)
+}
diff --git a/third_party/rust/ron/tests/301_struct_name_mismatch.rs b/third_party/rust/ron/tests/301_struct_name_mismatch.rs
new file mode 100644
index 0000000000..063cdac364
--- /dev/null
+++ b/third_party/rust/ron/tests/301_struct_name_mismatch.rs
@@ -0,0 +1,130 @@
+use ron::error::{Error, Position, SpannedError};
+use serde::Deserialize;
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct MyUnitStruct;
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct MyTupleStruct(bool, i32);
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct MyNewtypeStruct(MyTupleStruct);
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct MyStruct {
+ a: bool,
+ b: i32,
+}
+
+#[test]
+fn test_unit_struct_name_mismatch() {
+ assert_eq!(ron::from_str::<MyUnitStruct>("()"), Ok(MyUnitStruct),);
+ assert_eq!(
+ ron::from_str::<MyUnitStruct>("MyUnitStruct"),
+ Ok(MyUnitStruct),
+ );
+ assert_eq!(
+ ron::from_str::<MyUnitStruct>("MyUnit Struct"),
+ Err(SpannedError {
+ code: Error::ExpectedDifferentStructName {
+ expected: "MyUnitStruct",
+ found: String::from("MyUnit")
+ },
+ position: Position { line: 1, col: 7 }
+ }),
+ );
+ assert_eq!(
+ ron::from_str::<MyUnitStruct>("42"),
+ Err(SpannedError {
+ code: Error::ExpectedNamedStructLike("MyUnitStruct"),
+ position: Position { line: 1, col: 1 }
+ }),
+ );
+}
+
+#[test]
+fn test_tuple_struct_name_mismatch() {
+ assert_eq!(
+ ron::from_str::<MyTupleStruct>("(true, 42)"),
+ Ok(MyTupleStruct(true, 42)),
+ );
+ assert_eq!(
+ ron::from_str::<MyTupleStruct>("MyTupleStruct(true, 42)"),
+ Ok(MyTupleStruct(true, 42)),
+ );
+ assert_eq!(
+ ron::from_str::<MyTupleStruct>("MyTypleStruct(true, 42)"),
+ Err(SpannedError {
+ code: Error::ExpectedDifferentStructName {
+ expected: "MyTupleStruct",
+ found: String::from("MyTypleStruct")
+ },
+ position: Position { line: 1, col: 14 }
+ }),
+ );
+ assert_eq!(
+ ron::from_str::<MyTupleStruct>("42"),
+ Err(SpannedError {
+ code: Error::ExpectedNamedStructLike("MyTupleStruct"),
+ position: Position { line: 1, col: 1 }
+ }),
+ );
+}
+
+#[test]
+fn test_newtype_struct_name_mismatch() {
+ assert_eq!(
+ ron::from_str::<MyNewtypeStruct>("((true, 42))"),
+ Ok(MyNewtypeStruct(MyTupleStruct(true, 42))),
+ );
+ assert_eq!(
+ ron::from_str::<MyNewtypeStruct>("MyNewtypeStruct((true, 42))"),
+ Ok(MyNewtypeStruct(MyTupleStruct(true, 42))),
+ );
+ assert_eq!(
+ ron::from_str::<MyNewtypeStruct>("MyNewtypeStrucl((true, 42))"),
+ Err(SpannedError {
+ code: Error::ExpectedDifferentStructName {
+ expected: "MyNewtypeStruct",
+ found: String::from("MyNewtypeStrucl")
+ },
+ position: Position { line: 1, col: 16 }
+ }),
+ );
+ assert_eq!(
+ ron::from_str::<MyNewtypeStruct>("42"),
+ Err(SpannedError {
+ code: Error::ExpectedNamedStructLike("MyNewtypeStruct"),
+ position: Position { line: 1, col: 1 }
+ }),
+ );
+}
+
+#[test]
+fn test_struct_name_mismatch() {
+ assert_eq!(
+ ron::from_str::<MyStruct>("(a: true, b: 42)"),
+ Ok(MyStruct { a: true, b: 42 }),
+ );
+ assert_eq!(
+ ron::from_str::<MyStruct>("MyStruct(a: true, b: 42)"),
+ Ok(MyStruct { a: true, b: 42 }),
+ );
+ assert_eq!(
+ ron::from_str::<MyStruct>("MuStryct(a: true, b: 42)"),
+ Err(SpannedError {
+ code: Error::ExpectedDifferentStructName {
+ expected: "MyStruct",
+ found: String::from("MuStryct")
+ },
+ position: Position { line: 1, col: 9 }
+ }),
+ );
+ assert_eq!(
+ ron::from_str::<MyStruct>("42"),
+ Err(SpannedError {
+ code: Error::ExpectedNamedStructLike("MyStruct"),
+ position: Position { line: 1, col: 1 }
+ }),
+ );
+}
diff --git a/third_party/rust/ron/tests/307_stack_overflow.rs b/third_party/rust/ron/tests/307_stack_overflow.rs
new file mode 100644
index 0000000000..7076e6e13e
--- /dev/null
+++ b/third_party/rust/ron/tests/307_stack_overflow.rs
Binary files differ
diff --git a/third_party/rust/ron/tests/322_escape_idents.rs b/third_party/rust/ron/tests/322_escape_idents.rs
new file mode 100644
index 0000000000..f236369f31
--- /dev/null
+++ b/third_party/rust/ron/tests/322_escape_idents.rs
@@ -0,0 +1,34 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Deserialize, PartialEq, Serialize)]
+#[serde(rename_all = "kebab-case")]
+enum MyEnumWithDashes {
+ ThisIsMyUnitVariant,
+ ThisIsMyTupleVariant(bool, i32),
+}
+
+#[derive(Debug, Deserialize, PartialEq, Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct MyStructWithDashes {
+ my_enum: MyEnumWithDashes,
+ #[serde(rename = "2nd")]
+ my_enum2: MyEnumWithDashes,
+ will_be_renamed: u32,
+}
+
+#[test]
+fn roundtrip_ident_with_dash() {
+ let value = MyStructWithDashes {
+ my_enum: MyEnumWithDashes::ThisIsMyUnitVariant,
+ my_enum2: MyEnumWithDashes::ThisIsMyTupleVariant(false, -3),
+ will_be_renamed: 32,
+ };
+
+ let serial = ron::ser::to_string(&value).unwrap();
+
+ println!("Serialized: {}", serial);
+
+ let deserial = ron::de::from_str(&serial);
+
+ assert_eq!(Ok(value), deserial);
+}
diff --git a/third_party/rust/ron/tests/337_value_float_roundtrip.rs b/third_party/rust/ron/tests/337_value_float_roundtrip.rs
new file mode 100644
index 0000000000..66873eaeab
--- /dev/null
+++ b/third_party/rust/ron/tests/337_value_float_roundtrip.rs
@@ -0,0 +1,29 @@
+#[test]
+fn roundtrip_value_float_with_decimals() {
+ let v: ron::Value = ron::from_str("1.0").unwrap();
+
+ assert_eq!(v, ron::Value::Number(1.0_f64.into()));
+
+ let ser = ron::ser::to_string(&v).unwrap();
+
+ let roundtrip = ron::from_str(&ser).unwrap();
+
+ assert_eq!(v, roundtrip);
+}
+
+#[test]
+#[allow(clippy::float_cmp)]
+fn roundtrip_value_float_into() {
+ let v: ron::Value = ron::from_str("1.0").unwrap();
+ assert_eq!(v, ron::Value::Number(1.0_f64.into()));
+
+ let ser = ron::ser::to_string(&v).unwrap();
+
+ let f1: f64 = ron::from_str(&ser).unwrap();
+ assert_eq!(f1, 1.0_f64);
+
+ let roundtrip: ron::Value = ron::from_str(&ser).unwrap();
+
+ let f2: f64 = roundtrip.into_rust().unwrap();
+ assert_eq!(f2, 1.0_f64);
+}
diff --git a/third_party/rust/ron/tests/359_deserialize_seed.rs b/third_party/rust/ron/tests/359_deserialize_seed.rs
new file mode 100644
index 0000000000..4bca6c438b
--- /dev/null
+++ b/third_party/rust/ron/tests/359_deserialize_seed.rs
@@ -0,0 +1,57 @@
+#[test]
+fn test_deserialize_seed() {
+ // Test adapted from David Tolnay's serde-yaml:
+ // https://github.com/dtolnay/serde-yaml/blob/8a806e316302fd2e6541dccee6d166dd51b689d6/tests/test_de.rs#L357-L392
+
+ struct Seed(i64);
+
+ impl<'de> serde::de::DeserializeSeed<'de> for Seed {
+ type Value = i64;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<i64, D::Error>
+ where
+ D: serde::de::Deserializer<'de>,
+ {
+ struct Visitor(i64);
+
+ impl<'de> serde::de::Visitor<'de> for Visitor {
+ type Value = i64;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(formatter, "an integer")
+ }
+
+ fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<i64, E> {
+ Ok(v * self.0)
+ }
+
+ fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<i64, E> {
+ Ok(v as i64 * self.0)
+ }
+ }
+
+ deserializer.deserialize_any(Visitor(self.0))
+ }
+ }
+
+ let cases = [("3", 5, 15), ("6", 7, 42), ("-5", 9, -45)];
+
+ for &(ron, seed, expected) in &cases {
+ let deserialized = ron::Options::default()
+ .from_str_seed(ron, Seed(seed))
+ .unwrap();
+
+ assert_eq!(expected, deserialized);
+ }
+
+ assert_eq!(
+ ron::Options::default().from_str_seed("'a'", Seed(42)),
+ Err(ron::error::SpannedError {
+ code: ron::Error::InvalidValueForType {
+ expected: String::from("an integer"),
+ found: String::from("the string \"a\""),
+ },
+ position: ron::error::Position { line: 1, col: 4 },
+ })
+ );
+}
diff --git a/third_party/rust/ron/tests/367_implicit_some.rs b/third_party/rust/ron/tests/367_implicit_some.rs
new file mode 100644
index 0000000000..4eeac4df35
--- /dev/null
+++ b/third_party/rust/ron/tests/367_implicit_some.rs
@@ -0,0 +1,108 @@
+#[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
+struct MaybeFields {
+ f1: i64,
+ f2: Option<i64>,
+ f3: Option<Option<i64>>,
+}
+
+#[test]
+fn test_recursive_implicit_some() {
+ // Test case provided by d86leader in
+ // https://github.com/ron-rs/ron/issues/367#issue-1147920589
+
+ let x1: std::result::Result<MaybeFields, _> =
+ ron::from_str("#![enable(implicit_some)]\n(f1: 1)");
+ let x2: std::result::Result<MaybeFields, _> =
+ ron::from_str("#![enable(implicit_some)]\n(f1: 1, f2: None, f3: None)");
+ let x3: std::result::Result<MaybeFields, _> =
+ ron::from_str("#![enable(implicit_some)]\n(f1: 1, f2: 2, f3: 3)");
+ let x4: std::result::Result<MaybeFields, _> =
+ ron::from_str("#![enable(implicit_some)]\n(f1: 1, f2: 2, f3: Some(3))");
+ let x5: std::result::Result<MaybeFields, _> =
+ ron::from_str("#![enable(implicit_some)]\n(f1: 1, f2: 2, f3: Some(Some(3)))");
+ let x6: std::result::Result<MaybeFields, _> =
+ ron::from_str("#![enable(implicit_some)]\n(f1: 1, f2: 2, f3: Some(None))");
+
+ assert_eq!(
+ x1,
+ Ok(MaybeFields {
+ f1: 1,
+ f2: None,
+ f3: None
+ })
+ );
+ assert_eq!(
+ x2,
+ Ok(MaybeFields {
+ f1: 1,
+ f2: None,
+ f3: None
+ })
+ );
+ assert_eq!(
+ x3,
+ Ok(MaybeFields {
+ f1: 1,
+ f2: Some(2),
+ f3: Some(Some(3))
+ })
+ );
+ assert_eq!(
+ x4,
+ Ok(MaybeFields {
+ f1: 1,
+ f2: Some(2),
+ f3: Some(Some(3))
+ })
+ );
+ assert_eq!(
+ x5,
+ Ok(MaybeFields {
+ f1: 1,
+ f2: Some(2),
+ f3: Some(Some(3))
+ })
+ );
+ assert_eq!(
+ x6,
+ Ok(MaybeFields {
+ f1: 1,
+ f2: Some(2),
+ f3: Some(None)
+ })
+ );
+}
+
+#[test]
+fn test_nested_implicit_some() {
+ assert_eq!(
+ ron::from_str::<Option<Option<Option<u32>>>>("#![enable(implicit_some)]\n5"),
+ Ok(Some(Some(Some(5))))
+ );
+ assert_eq!(
+ ron::from_str::<Option<Option<Option<u32>>>>("#![enable(implicit_some)]\nNone"),
+ Ok(None)
+ );
+ assert_eq!(
+ ron::from_str::<Option<Option<Option<u32>>>>("#![enable(implicit_some)]\nSome(5)"),
+ Ok(Some(Some(Some(5))))
+ );
+ assert_eq!(
+ ron::from_str::<Option<Option<Option<u32>>>>("#![enable(implicit_some)]\nSome(None)"),
+ Ok(Some(None))
+ );
+ assert_eq!(
+ ron::from_str::<Option<Option<Option<u32>>>>("#![enable(implicit_some)]\nSome(Some(5))"),
+ Ok(Some(Some(Some(5))))
+ );
+ assert_eq!(
+ ron::from_str::<Option<Option<Option<u32>>>>("#![enable(implicit_some)]\nSome(Some(None))"),
+ Ok(Some(Some(None)))
+ );
+ assert_eq!(
+ ron::from_str::<Option<Option<Option<u32>>>>(
+ "#![enable(implicit_some)]\nSome(Some(Some(5)))"
+ ),
+ Ok(Some(Some(Some(5))))
+ );
+}
diff --git a/third_party/rust/ron/tests/370_float_parsing.rs b/third_party/rust/ron/tests/370_float_parsing.rs
new file mode 100644
index 0000000000..786d5ae331
--- /dev/null
+++ b/third_party/rust/ron/tests/370_float_parsing.rs
@@ -0,0 +1,66 @@
+use ron::{
+ de::{Position, SpannedError},
+ Error,
+};
+
+#[test]
+fn test_float_literal_parsing() {
+ assert_eq!(ron::from_str("inf"), Ok(f64::INFINITY));
+ assert_eq!(ron::from_str("+inf"), Ok(f64::INFINITY));
+ assert_eq!(ron::from_str("-inf"), Ok(f64::NEG_INFINITY));
+
+ assert!(ron::from_str::<f64>("NaN").unwrap().is_nan());
+ assert!(ron::from_str::<f64>("+NaN").unwrap().is_nan());
+ assert!(ron::from_str::<f64>("-NaN").unwrap().is_nan());
+
+ assert_eq!(ron::from_str("1"), Ok(1.0_f64));
+ assert_eq!(ron::from_str("+1"), Ok(1.0_f64));
+ assert_eq!(ron::from_str("-1"), Ok(-1.0_f64));
+ assert_eq!(ron::from_str("1e3"), Ok(1000.0_f64));
+ assert_eq!(ron::from_str("1e+1"), Ok(10.0_f64));
+ assert_eq!(ron::from_str("7E-1"), Ok(0.7_f64));
+
+ assert_eq!(ron::from_str("1."), Ok(1.0_f64));
+ assert_eq!(ron::from_str("+1.1"), Ok(1.1_f64));
+ assert_eq!(ron::from_str("-1.42"), Ok(-1.42_f64));
+ assert_eq!(ron::from_str("-1.5e3"), Ok(-1500.0_f64));
+ assert_eq!(ron::from_str("1.e+1"), Ok(10.0_f64));
+ assert_eq!(ron::from_str("7.4E-1"), Ok(0.74_f64));
+
+ assert_eq!(ron::from_str(".1"), Ok(0.1_f64));
+ assert_eq!(ron::from_str("+.1"), Ok(0.1_f64));
+ assert_eq!(ron::from_str("-.42"), Ok(-0.42_f64));
+ assert_eq!(ron::from_str("-.5e3"), Ok(-500.0_f64));
+ assert_eq!(ron::from_str(".3e+1"), Ok(3.0_f64));
+ assert_eq!(ron::from_str(".4E-1"), Ok(0.04_f64));
+
+ assert_eq!(
+ ron::from_str::<f64>("1_0.1_0"),
+ Err(SpannedError {
+ code: Error::FloatUnderscore,
+ position: Position { line: 1, col: 2 },
+ })
+ );
+ assert_eq!(
+ ron::from_str::<f64>("1_0.10"),
+ Err(SpannedError {
+ code: Error::FloatUnderscore,
+ position: Position { line: 1, col: 2 },
+ })
+ );
+ assert_eq!(
+ ron::from_str::<f64>("10.1_0"),
+ Err(SpannedError {
+ code: Error::FloatUnderscore,
+ position: Position { line: 1, col: 5 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<f64>("1.0e1.0"),
+ Err(SpannedError {
+ code: Error::ExpectedFloat,
+ position: Position { line: 1, col: 8 },
+ })
+ );
+}
diff --git a/third_party/rust/ron/tests/393_serde_errors.rs b/third_party/rust/ron/tests/393_serde_errors.rs
new file mode 100644
index 0000000000..9246e6633f
--- /dev/null
+++ b/third_party/rust/ron/tests/393_serde_errors.rs
@@ -0,0 +1,215 @@
+use ron::error::{Error, Position, SpannedError};
+
+#[derive(Debug, serde::Deserialize, PartialEq)]
+#[serde(deny_unknown_fields)]
+enum TestEnum {
+ StructVariant { a: bool, b: char, c: i32 },
+ NewtypeVariant(TestStruct),
+}
+
+#[derive(Debug, serde::Deserialize, PartialEq)]
+#[serde(tag = "type")]
+enum TestEnumInternal {
+ StructVariant { a: bool },
+}
+
+#[derive(Debug, serde::Deserialize, PartialEq)]
+#[serde(tag = "type", content = "content")]
+enum TestEnumAdjacent {
+ StructVariant { a: bool },
+}
+
+#[derive(Debug, serde::Deserialize, PartialEq)]
+#[serde(untagged)]
+enum TestEnumUntagged {
+ StructVariant { a: bool },
+}
+
+#[derive(Debug, serde::Deserialize, PartialEq)]
+#[serde(deny_unknown_fields)]
+struct TestStruct {
+ a: bool,
+ b: char,
+ c: i32,
+}
+
+#[test]
+fn test_unknown_enum_variant() {
+ assert_eq!(
+ ron::from_str::<TestEnum>("NotAVariant"),
+ Err(SpannedError {
+ code: Error::NoSuchEnumVariant {
+ expected: &["StructVariant", "NewtypeVariant"],
+ found: String::from("NotAVariant"),
+ outer: Some(String::from("TestEnum")),
+ },
+ position: Position { line: 1, col: 12 },
+ })
+ );
+}
+
+#[test]
+fn test_struct_enum_fields() {
+ assert_eq!(
+ ron::from_str::<TestEnum>("StructVariant(a: true, b: 'b', c: -42, d: \"gotcha\")"),
+ Err(SpannedError {
+ code: Error::NoSuchStructField {
+ expected: &["a", "b", "c"],
+ found: String::from("d"),
+ outer: Some(String::from("StructVariant")),
+ },
+ position: Position { line: 1, col: 41 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<TestEnum>("StructVariant(a: true, c: -42)"),
+ Err(SpannedError {
+ code: Error::MissingStructField {
+ field: "b",
+ outer: Some(String::from("StructVariant")),
+ },
+ position: Position { line: 1, col: 30 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<TestEnum>("StructVariant(a: true, b: 'b', a: false, c: -42)"),
+ Err(SpannedError {
+ code: Error::DuplicateStructField {
+ field: "a",
+ outer: Some(String::from("StructVariant")),
+ },
+ position: Position { line: 1, col: 33 },
+ })
+ );
+}
+
+#[test]
+fn test_newtype_enum_fields() {
+ assert_eq!(
+ ron::from_str::<TestEnum>("#![enable(unwrap_variant_newtypes)] NewtypeVariant(a: true, b: 'b', c: -42, d: \"gotcha\")"),
+ Err(SpannedError {
+ code: Error::NoSuchStructField {
+ expected: &["a", "b", "c"],
+ found: String::from("d"),
+ outer: Some(String::from("NewtypeVariant")),
+ },
+ position: Position { line: 1, col: 78 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<TestEnum>(
+ "#![enable(unwrap_variant_newtypes)] NewtypeVariant(a: true, c: -42)"
+ ),
+ Err(SpannedError {
+ code: Error::MissingStructField {
+ field: "b",
+ outer: Some(String::from("NewtypeVariant")),
+ },
+ position: Position { line: 1, col: 67 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<TestEnum>(
+ "#![enable(unwrap_variant_newtypes)] NewtypeVariant(a: true, b: 'b', a: false, c: -42)"
+ ),
+ Err(SpannedError {
+ code: Error::DuplicateStructField {
+ field: "a",
+ outer: Some(String::from("NewtypeVariant")),
+ },
+ position: Position { line: 1, col: 70 },
+ })
+ );
+}
+
+#[test]
+fn test_struct_fields() {
+ assert_eq!(
+ ron::from_str::<TestStruct>("TestStruct(a: true, b: 'b', c: -42, d: \"gotcha\")"),
+ Err(SpannedError {
+ code: Error::NoSuchStructField {
+ expected: &["a", "b", "c"],
+ found: String::from("d"),
+ outer: Some(String::from("TestStruct")),
+ },
+ position: Position { line: 1, col: 38 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<TestStruct>("TestStruct(a: true, c: -42)"),
+ Err(SpannedError {
+ code: Error::MissingStructField {
+ field: "b",
+ outer: Some(String::from("TestStruct")),
+ },
+ position: Position { line: 1, col: 27 },
+ })
+ );
+
+ assert_eq!(
+ ron::from_str::<TestStruct>("TestStruct(a: true, b: 'b', a: false, c: -42)"),
+ Err(SpannedError {
+ code: Error::DuplicateStructField {
+ field: "a",
+ outer: Some(String::from("TestStruct")),
+ },
+ position: Position { line: 1, col: 30 },
+ })
+ );
+}
+
+#[test]
+fn test_internally_tagged_enum() {
+ // Note: Not extracting the variant type is not great,
+ // but at least not wrong either
+ // Since the error occurs in serde-generated user code,
+ // after successfully deserialising, we cannot annotate
+
+ assert_eq!(
+ ron::from_str::<TestEnumInternal>("(type: \"StructVariant\")"),
+ Err(SpannedError {
+ code: Error::MissingStructField {
+ field: "a",
+ outer: None,
+ },
+ position: Position { line: 1, col: 24 },
+ })
+ );
+}
+
+#[test]
+fn test_adjacently_tagged_enum() {
+ // Note: TestEnumAdjacent makes sense here since we are now treating
+ // the enum as a struct
+
+ assert_eq!(
+ ron::from_str::<TestEnumAdjacent>("(type: StructVariant, content: (d: 4))"),
+ Err(SpannedError {
+ code: Error::MissingStructField {
+ field: "a",
+ outer: Some(String::from("TestEnumAdjacent")),
+ },
+ position: Position { line: 1, col: 37 },
+ })
+ );
+}
+
+#[test]
+fn test_untagged_enum() {
+ // Note: Errors inside untagged enums are not bubbled up
+
+ assert_eq!(
+ ron::from_str::<TestEnumUntagged>("(a: true, a: false)"),
+ Err(SpannedError {
+ code: Error::Message(String::from(
+ "data did not match any variant of untagged enum TestEnumUntagged"
+ )),
+ position: Position { line: 1, col: 20 },
+ })
+ );
+}
diff --git a/third_party/rust/ron/tests/401_raw_identifier.rs b/third_party/rust/ron/tests/401_raw_identifier.rs
new file mode 100644
index 0000000000..23e6ecabd2
--- /dev/null
+++ b/third_party/rust/ron/tests/401_raw_identifier.rs
@@ -0,0 +1,177 @@
+use ron::error::{Error, Position, SpannedError};
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename = "Hello World")]
+struct InvalidStruct;
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename = "")]
+struct EmptyStruct;
+
+#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
+#[serde(rename = "Hello+World")]
+#[serde(deny_unknown_fields)]
+struct RawStruct {
+ #[serde(rename = "ab.cd-ef")]
+ field: bool,
+}
+
+#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
+enum RawEnum {
+ #[serde(rename = "Hello-World")]
+ RawVariant,
+}
+
+#[test]
+fn test_invalid_identifiers() {
+ let ser = ron::ser::to_string_pretty(
+ &InvalidStruct,
+ ron::ser::PrettyConfig::default().struct_names(true),
+ );
+ assert_eq!(
+ ser,
+ Err(Error::InvalidIdentifier(String::from("Hello World")))
+ );
+
+ let ser = ron::ser::to_string_pretty(
+ &EmptyStruct,
+ ron::ser::PrettyConfig::default().struct_names(true),
+ );
+ assert_eq!(ser, Err(Error::InvalidIdentifier(String::from(""))));
+
+ let de = ron::from_str::<InvalidStruct>("Hello World").unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::ExpectedDifferentStructName {
+ expected: "Hello World",
+ found: String::from("Hello"),
+ },
+ position: Position { line: 1, col: 6 },
+ }
+ );
+
+ let de = ron::from_str::<EmptyStruct>("").unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::ExpectedUnit,
+ position: Position { line: 1, col: 1 },
+ }
+ );
+
+ let de = ron::from_str::<EmptyStruct>("r#").unwrap_err();
+ assert_eq!(
+ format!("{}", de),
+ "1:1: Expected only opening `(`, no name, for un-nameable struct"
+ );
+
+ let de = ron::from_str::<RawStruct>("").unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::ExpectedNamedStructLike("Hello+World"),
+ position: Position { line: 1, col: 1 },
+ },
+ );
+
+ let de = ron::from_str::<RawStruct>("r#").unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::ExpectedNamedStructLike("Hello+World"),
+ position: Position { line: 1, col: 1 },
+ },
+ );
+
+ let de = ron::from_str::<RawStruct>("Hello+World").unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::SuggestRawIdentifier(String::from("Hello+World")),
+ position: Position { line: 1, col: 1 },
+ }
+ );
+
+ let de = ron::from_str::<RawStruct>(
+ "r#Hello+World(
+ ab.cd-ef: true,
+ )",
+ )
+ .unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::SuggestRawIdentifier(String::from("ab.cd-ef")),
+ position: Position { line: 2, col: 9 },
+ }
+ );
+
+ let de = ron::from_str::<RawStruct>(
+ "r#Hello+World(
+ r#ab.cd+ef: true,
+ )",
+ )
+ .unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::NoSuchStructField {
+ expected: &["ab.cd-ef"],
+ found: String::from("ab.cd+ef"),
+ outer: Some(String::from("Hello+World")),
+ },
+ position: Position { line: 2, col: 19 },
+ }
+ );
+
+ let de = ron::from_str::<RawEnum>("Hello-World").unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::SuggestRawIdentifier(String::from("Hello-World")),
+ position: Position { line: 1, col: 1 },
+ }
+ );
+
+ let de = ron::from_str::<RawEnum>("r#Hello+World").unwrap_err();
+ assert_eq!(
+ de,
+ SpannedError {
+ code: Error::NoSuchEnumVariant {
+ expected: &["Hello-World"],
+ found: String::from("Hello+World"),
+ outer: Some(String::from("RawEnum")),
+ },
+ position: Position { line: 1, col: 14 },
+ }
+ );
+
+ let de = ron::from_str::<EmptyStruct>("r#+").unwrap_err();
+ assert_eq!(
+ format!("{}", de),
+ r#"1:4: Expected struct ""_[invalid identifier] but found `r#+`"#,
+ );
+}
+
+#[test]
+fn test_raw_identifier_roundtrip() {
+ let val = RawStruct { field: true };
+
+ let ser =
+ ron::ser::to_string_pretty(&val, ron::ser::PrettyConfig::default().struct_names(true))
+ .unwrap();
+ assert_eq!(ser, "r#Hello+World(\n r#ab.cd-ef: true,\n)");
+
+ let de: RawStruct = ron::from_str(&ser).unwrap();
+ assert_eq!(de, val);
+
+ let val = RawEnum::RawVariant;
+
+ let ser = ron::ser::to_string(&val).unwrap();
+ assert_eq!(ser, "r#Hello-World");
+
+ let de: RawEnum = ron::from_str(&ser).unwrap();
+ assert_eq!(de, val);
+}
diff --git a/third_party/rust/ron/tests/410_trailing_comma.rs b/third_party/rust/ron/tests/410_trailing_comma.rs
new file mode 100644
index 0000000000..91018a3efb
--- /dev/null
+++ b/third_party/rust/ron/tests/410_trailing_comma.rs
@@ -0,0 +1,95 @@
+use std::collections::HashMap;
+
+use ron::from_str;
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+struct Newtype(i32);
+
+#[derive(Deserialize)]
+struct Tuple(i32, i32);
+
+#[derive(Deserialize)]
+#[allow(dead_code)]
+struct Struct {
+ a: i32,
+ b: i32,
+}
+
+#[derive(Deserialize)]
+#[allow(dead_code)]
+enum Enum {
+ Newtype(i32),
+ Tuple(i32, i32),
+ Struct { a: i32, b: i32 },
+}
+
+#[test]
+fn test_trailing_comma_some() {
+ assert!(from_str::<Option<i32>>("Some(1)").is_ok());
+ assert!(from_str::<Option<i32>>("Some(1,)").is_ok());
+ assert!(from_str::<Option<i32>>("Some(1,,)").is_err());
+}
+
+#[test]
+fn test_trailing_comma_tuple() {
+ assert!(from_str::<(i32, i32)>("(1,2)").is_ok());
+ assert!(from_str::<(i32, i32)>("(1,2,)").is_ok());
+ assert!(from_str::<(i32, i32)>("(1,2,,)").is_err());
+}
+
+#[test]
+fn test_trailing_comma_list() {
+ assert!(from_str::<Vec<i32>>("[1,2]").is_ok());
+ assert!(from_str::<Vec<i32>>("[1,2,]").is_ok());
+ assert!(from_str::<Vec<i32>>("[1,2,,]").is_err());
+}
+
+#[test]
+fn test_trailing_comma_map() {
+ assert!(from_str::<HashMap<i32, bool>>("{1:false,2:true}").is_ok());
+ assert!(from_str::<HashMap<i32, bool>>("{1:false,2:true,}").is_ok());
+ assert!(from_str::<HashMap<i32, bool>>("{1:false,2:true,,}").is_err());
+}
+
+#[test]
+fn test_trailing_comma_newtype_struct() {
+ assert!(from_str::<Newtype>("(1)").is_ok());
+ assert!(from_str::<Newtype>("(1,)").is_ok());
+ assert!(from_str::<Newtype>("(1,,)").is_err());
+}
+
+#[test]
+fn test_trailing_comma_tuple_struct() {
+ assert!(from_str::<Tuple>("(1,2)").is_ok());
+ assert!(from_str::<Tuple>("(1,2,)").is_ok());
+ assert!(from_str::<Tuple>("(1,2,,)").is_err());
+}
+
+#[test]
+fn test_trailing_comma_struct() {
+ assert!(from_str::<Struct>("(a:1,b:2)").is_ok());
+ assert!(from_str::<Struct>("(a:1,b:2,)").is_ok());
+ assert!(from_str::<Struct>("(a:1,b:2,,)").is_err());
+}
+
+#[test]
+fn test_trailing_comma_enum_newtype_variant() {
+ assert!(from_str::<Enum>("Newtype(1)").is_ok());
+ assert!(from_str::<Enum>("Newtype(1,)").is_ok());
+ assert!(from_str::<Enum>("Newtype(1,,)").is_err());
+}
+
+#[test]
+fn test_trailing_comma_enum_tuple_variant() {
+ assert!(from_str::<Enum>("Tuple(1,2)").is_ok());
+ assert!(from_str::<Enum>("Tuple(1,2,)").is_ok());
+ assert!(from_str::<Enum>("Tuple(1,2,,)").is_err());
+}
+
+#[test]
+fn test_trailing_comma_enum_struct_variant() {
+ assert!(from_str::<Enum>("Struct(a:1,b:2)").is_ok());
+ assert!(from_str::<Enum>("Struct(a:1,b:2,)").is_ok());
+ assert!(from_str::<Enum>("Struct(a:1,b:2,,)").is_err());
+}
diff --git a/third_party/rust/ron/tests/423_de_borrowed_identifier.rs b/third_party/rust/ron/tests/423_de_borrowed_identifier.rs
new file mode 100644
index 0000000000..d29a0050f7
--- /dev/null
+++ b/third_party/rust/ron/tests/423_de_borrowed_identifier.rs
@@ -0,0 +1,45 @@
+use std::any::Any;
+
+use serde::{
+ de::{MapAccess, Visitor},
+ Deserializer,
+};
+
+#[test]
+fn manually_deserialize_dyn() {
+ let ron = r#"SerializeDyn(
+ type: "engine_utils::types::registry::tests::Player",
+ )"#;
+
+ let mut de = ron::Deserializer::from_bytes(ron.as_bytes()).unwrap();
+
+ let result = de
+ .deserialize_struct("SerializeDyn", &["type"], SerializeDynVisitor)
+ .unwrap();
+
+ assert_eq!(
+ *result.downcast::<Option<(String, String)>>().unwrap(),
+ Some((
+ String::from("type"),
+ String::from("engine_utils::types::registry::tests::Player")
+ ))
+ );
+}
+
+struct SerializeDynVisitor;
+
+impl<'de> Visitor<'de> for SerializeDynVisitor {
+ type Value = Box<dyn Any>;
+
+ // GRCOV_EXCL_START
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(formatter, "a serialize dyn struct")
+ }
+ // GRCOV_EXCL_STOP
+
+ fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
+ let entry = map.next_entry::<&str, String>()?;
+
+ Ok(Box::new(entry.map(|(k, v)| (String::from(k), v))))
+ }
+}
diff --git a/third_party/rust/ron/tests/462_bytes.rs b/third_party/rust/ron/tests/462_bytes.rs
new file mode 100644
index 0000000000..ac91890397
--- /dev/null
+++ b/third_party/rust/ron/tests/462_bytes.rs
@@ -0,0 +1,22 @@
+#[test]
+fn test_deserialise_byte_slice() {
+ let val: &[u8] = &[0_u8, 1_u8, 2_u8, 3_u8];
+ let ron = ron::to_string(val).unwrap();
+ assert_eq!(ron, "[0,1,2,3]");
+
+ // deserialising a byte slice from a byte sequence should fail
+ // with the error that a borrowed slice was expected but a byte
+ // buffer was provided
+ // NOT with an expected string error, since the byte slice
+ // serialisation never serialises to a string
+ assert_eq!(
+ ron::from_str::<&[u8]>(&ron),
+ Err(ron::error::SpannedError {
+ code: ron::error::Error::InvalidValueForType {
+ expected: String::from("a borrowed byte array"),
+ found: String::from("the bytes \"AAECAw==\""),
+ },
+ position: ron::error::Position { line: 1, col: 10 },
+ })
+ );
+}
diff --git a/third_party/rust/ron/tests/big_struct.rs b/third_party/rust/ron/tests/big_struct.rs
new file mode 100644
index 0000000000..40583606f1
--- /dev/null
+++ b/third_party/rust/ron/tests/big_struct.rs
@@ -0,0 +1,79 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize)]
+pub struct ImVec2 {
+ pub x: f32,
+ pub y: f32,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct ImColorsSave {
+ pub text: f32,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct ImGuiStyleSave {
+ pub alpha: f32,
+ pub window_padding: ImVec2,
+ pub window_min_size: ImVec2,
+ pub window_rounding: f32,
+ pub window_title_align: ImVec2,
+ pub child_window_rounding: f32,
+ pub frame_padding: ImVec2,
+ pub frame_rounding: f32,
+ pub item_spacing: ImVec2,
+ pub item_inner_spacing: ImVec2,
+ pub touch_extra_padding: ImVec2,
+ pub indent_spacing: f32,
+ pub columns_min_spacing: f32,
+ pub scrollbar_size: f32,
+ pub scrollbar_rounding: f32,
+ pub grab_min_size: f32,
+ pub grab_rounding: f32,
+ pub button_text_align: ImVec2,
+ pub display_window_padding: ImVec2,
+ pub display_safe_area_padding: ImVec2,
+ pub anti_aliased_lines: bool,
+ pub anti_aliased_shapes: bool,
+ pub curve_tessellation_tol: f32,
+ pub colors: ImColorsSave,
+ pub new_type: NewType,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct NewType(i32);
+
+const CONFIG: &str = "(
+ alpha: 1.0,
+ window_padding: (x: 8, y: 8),
+ window_min_size: (x: 32, y: 32),
+ window_rounding: 9.0,
+ window_title_align: (x: 0.0, y: 0.5),
+ child_window_rounding: 0.0,
+ frame_padding: (x: 4, y: 3),
+ frame_rounding: 0.0,
+ item_spacing: (x: 8, y: 4),
+ item_inner_spacing: (x: 4, y: 4),
+ touch_extra_padding: (x: 0, y: 0),
+ indent_spacing: 21.0,
+ columns_min_spacing: 6.0,
+ scrollbar_size: 16,
+ scrollbar_rounding: 9,
+ grab_min_size: 10,
+ grab_rounding: 0,
+ button_text_align: (x: 0.5, y: 0.5),
+ display_window_padding: (x: 22, y: 22),
+ display_safe_area_padding: (x: 4, y: 4),
+ anti_aliased_lines: true,
+ anti_aliased_shapes: true,
+ curve_tessellation_tol: 1.25,
+ colors: (text: 4),
+ new_type: NewType( 1 ),
+
+ ignored_field: \"Totally ignored, not causing a panic. Hopefully.\",
+)";
+
+#[test]
+fn deserialize_big_struct() {
+ ron::de::from_str::<ImGuiStyleSave>(CONFIG).unwrap();
+}
diff --git a/third_party/rust/ron/tests/borrowed_str.rs b/third_party/rust/ron/tests/borrowed_str.rs
new file mode 100644
index 0000000000..f01eeb141f
--- /dev/null
+++ b/third_party/rust/ron/tests/borrowed_str.rs
@@ -0,0 +1,16 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+struct Borrowed<'a> {
+ value: &'a str,
+}
+
+const BORROWED: &str = "Borrowed(value: \"test\")";
+
+#[test]
+fn borrowed_str() {
+ assert_eq!(
+ ron::de::from_str(BORROWED).ok(),
+ Some(Borrowed { value: "test" })
+ );
+}
diff --git a/third_party/rust/ron/tests/comments.rs b/third_party/rust/ron/tests/comments.rs
new file mode 100644
index 0000000000..2b77de6187
--- /dev/null
+++ b/third_party/rust/ron/tests/comments.rs
@@ -0,0 +1,52 @@
+use ron::de::{from_str, Error, Position, SpannedError as RonErr};
+
+#[test]
+fn test_simple() {
+ assert_eq!(
+ from_str(
+ "/*
+ * We got a hexadecimal number here!
+ *
+ */0x507"
+ ),
+ Ok(0x507)
+ );
+}
+
+#[test]
+fn test_nested() {
+ assert_eq!(
+ from_str(
+ "/*
+ /* quite * some * nesting * going * on * /* here /* (yeah, maybe a bit too much) */ */ */
+ */
+ // The actual value comes.. /*
+ // very soon, these are just checks that */
+ // multi-line comments don't trigger in line comments /*
+\"THE VALUE\" /* This is the value /* :) */ */
+ "
+ ),
+ Ok("THE VALUE".to_owned())
+ );
+}
+
+#[test]
+fn test_unclosed() {
+ assert_eq!(
+ from_str::<String>(
+ "/*
+ /* quite * some * nesting * going * on * /* here /* (yeah, maybe a bit too much) */ */ */
+ */
+ // The actual value comes.. /*
+ // very soon, these are just checks that */
+ // multi-line comments don't trigger in line comments /*
+/* Unfortunately, this comment won't get closed :(
+\"THE VALUE (which is invalid)\"
+"
+ ),
+ Err(RonErr {
+ code: Error::UnclosedBlockComment,
+ position: Position { col: 1, line: 9 }
+ })
+ );
+}
diff --git a/third_party/rust/ron/tests/depth_limit.rs b/third_party/rust/ron/tests/depth_limit.rs
new file mode 100644
index 0000000000..ee61a09c89
--- /dev/null
+++ b/third_party/rust/ron/tests/depth_limit.rs
@@ -0,0 +1,60 @@
+use std::collections::HashMap;
+
+use serde::Serialize;
+
+#[derive(Serialize)]
+struct Config {
+ float: (f32, f64),
+ tuple: TupleStruct,
+ map: HashMap<u8, char>,
+ nested: Nested,
+ var: Variant,
+ array: Vec<()>,
+}
+
+#[derive(Serialize)]
+struct TupleStruct((), bool);
+
+#[derive(Serialize)]
+enum Variant {
+ A(u8, &'static str),
+}
+
+#[derive(Serialize)]
+struct Nested {
+ a: String,
+ b: char,
+}
+
+const EXPECTED: &str = "(
+ float: (2.18, -1.1),
+ tuple: ((), false),
+ map: {8: '1'},
+ nested: (a: \"a\", b: 'b'),
+ var: A(255, \"\"),
+ array: [(), (), ()],
+)";
+
+#[test]
+fn depth_limit() {
+ let data = Config {
+ float: (2.18, -1.1),
+ tuple: TupleStruct((), false),
+ map: vec![(8, '1')].into_iter().collect(),
+ nested: Nested {
+ a: "a".to_owned(),
+ b: 'b',
+ },
+ var: Variant::A(!0, ""),
+ array: vec![(); 3],
+ };
+
+ let pretty = ron::ser::PrettyConfig::new()
+ .depth_limit(1)
+ .separate_tuple_members(true)
+ .enumerate_arrays(true)
+ .new_line("\n".to_string());
+ let s = ron::ser::to_string_pretty(&data, pretty);
+
+ assert_eq!(s, Ok(EXPECTED.to_string()));
+}
diff --git a/third_party/rust/ron/tests/escape.rs b/third_party/rust/ron/tests/escape.rs
new file mode 100644
index 0000000000..2874c3f4fa
--- /dev/null
+++ b/third_party/rust/ron/tests/escape.rs
@@ -0,0 +1,78 @@
+use std::{char::from_u32, fmt::Debug};
+
+use ron::{de::from_str, ser::to_string};
+use serde::{Deserialize, Serialize};
+
+#[test]
+fn test_escape_basic() {
+ assert_eq!(to_string(&"\x07").unwrap(), "\"\\u{7}\"");
+
+ assert_eq!(from_str::<String>("\"\\x07\"").unwrap(), "\x07");
+ assert_eq!(from_str::<String>("\"\\u{7}\"").unwrap(), "\x07");
+
+ assert_eq!(from_str::<char>("\'\\x07\'").unwrap(), '\x07');
+ assert_eq!(from_str::<char>("\'\\u{7}\'").unwrap(), '\x07');
+}
+
+fn check_same<T>(t: T)
+where
+ T: Debug + for<'a> Deserialize<'a> + PartialEq + Serialize,
+{
+ let s: String = to_string(&t).unwrap();
+
+ println!("Serialized: \n\n{}\n\n", s);
+
+ assert_eq!(from_str(&s), Ok(t));
+}
+
+#[test]
+fn test_ascii_10() {
+ check_same("\u{10}".to_owned());
+}
+
+#[test]
+fn test_ascii_chars() {
+ (1..128).into_iter().flat_map(from_u32).for_each(check_same)
+}
+
+#[test]
+fn test_ascii_string() {
+ let s: String = (1..128).into_iter().flat_map(from_u32).collect();
+
+ check_same(s);
+}
+
+#[test]
+fn test_non_ascii() {
+ assert_eq!(to_string(&"♠").unwrap(), "\"♠\"");
+ assert_eq!(to_string(&"ß").unwrap(), "\"ß\"");
+ assert_eq!(to_string(&"ä").unwrap(), "\"ä\"");
+ assert_eq!(to_string(&"ö").unwrap(), "\"ö\"");
+ assert_eq!(to_string(&"ü").unwrap(), "\"ü\"");
+}
+
+#[test]
+fn test_chars() {
+ assert_eq!(to_string(&'♠').unwrap(), "'♠'");
+ assert_eq!(to_string(&'ß').unwrap(), "'ß'");
+ assert_eq!(to_string(&'ä').unwrap(), "'ä'");
+ assert_eq!(to_string(&'ö').unwrap(), "'ö'");
+ assert_eq!(to_string(&'ü').unwrap(), "'ü'");
+ assert_eq!(to_string(&'\u{715}').unwrap(), "'\u{715}'");
+ assert_eq!(
+ from_str::<char>("'\u{715}'").unwrap(),
+ from_str("'\\u{715}'").unwrap()
+ );
+}
+
+#[test]
+fn test_nul_in_string() {
+ assert_eq!(
+ from_str("\"Hello\0World!\""),
+ Ok(String::from("Hello\0World!"))
+ );
+
+ check_same("Hello\0World!".to_owned());
+ check_same("Hello\x00World!".to_owned());
+ check_same("Hello\u{0}World!".to_owned());
+}
diff --git a/third_party/rust/ron/tests/extensions.rs b/third_party/rust/ron/tests/extensions.rs
new file mode 100644
index 0000000000..6b3ade87ae
--- /dev/null
+++ b/third_party/rust/ron/tests/extensions.rs
@@ -0,0 +1,92 @@
+use std::collections::HashMap;
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct UnitStruct;
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct NewType(f32);
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct TupleStruct(UnitStruct, i8);
+
+#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
+struct Key(u32);
+
+#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
+enum Enum {
+ Unit,
+ Bool(bool),
+ Chars(char, String),
+}
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct Struct {
+ tuple: ((), NewType, TupleStruct),
+ vec: Vec<Option<UnitStruct>>,
+ map: HashMap<Key, Enum>,
+}
+
+const CONFIG_U_NT: &str = "
+#![enable(unwrap_newtypes)]
+
+(
+ tuple: ((), 0.5, ((), -5)),
+ vec: [
+ None,
+ Some(()),
+ ],
+ map: {
+ 7: Bool(true),
+ 9: Chars('x', \"\"),
+ 6: Bool(false),
+ 5: Unit,
+ },
+)
+";
+
+#[test]
+fn unwrap_newtypes() {
+ let d: Struct = ron::de::from_str(CONFIG_U_NT).expect("Failed to deserialize");
+
+ println!("unwrap_newtypes: {:#?}", d);
+
+ let s = ron::ser::to_string_pretty(
+ &d,
+ ron::ser::PrettyConfig::default().extensions(ron::extensions::Extensions::UNWRAP_NEWTYPES),
+ )
+ .expect("Failed to serialize");
+
+ let d2: Struct = ron::de::from_str(&s).expect("Failed to deserialize");
+
+ assert_eq!(d, d2);
+}
+
+const CONFIG_I_S: &str = "
+#![enable(implicit_some)]
+
+(
+ tuple: ((), (0.5), ((), -5)),
+ vec: [
+ None,
+ (),
+ UnitStruct,
+ None,
+ (),
+ ],
+ map: {
+ (7): Bool(true),
+ (9): Chars('x', \"\"),
+ (6): Bool(false),
+ (5): Unit,
+ },
+)
+";
+
+#[test]
+fn implicit_some() {
+ let d: Struct = ron::de::from_str(CONFIG_I_S).expect("Failed to deserialize");
+
+ println!("implicit_some: {:#?}", d);
+}
diff --git a/third_party/rust/ron/tests/floats.rs b/third_party/rust/ron/tests/floats.rs
new file mode 100644
index 0000000000..9a5474fa68
--- /dev/null
+++ b/third_party/rust/ron/tests/floats.rs
@@ -0,0 +1,23 @@
+use ron::{
+ de::from_str,
+ ser::{to_string, to_string_pretty, PrettyConfig},
+};
+
+#[test]
+fn test_inf_and_nan() {
+ assert_eq!(from_str("inf"), Ok(std::f64::INFINITY));
+ assert_eq!(from_str("-inf"), Ok(std::f64::NEG_INFINITY));
+ assert_eq!(from_str::<f64>("NaN").map(|n| n.is_nan()), Ok(true))
+}
+
+#[test]
+fn decimal_floats() {
+ let non_pretty = to_string(&1.0).unwrap();
+ assert_eq!(non_pretty, "1.0");
+
+ let with_pretty = to_string_pretty(&1.0, PrettyConfig::new()).unwrap();
+ assert_eq!(with_pretty, "1.0");
+
+ let tiny_pretty = to_string_pretty(&0.00000000000000005, PrettyConfig::new()).unwrap();
+ assert_eq!(tiny_pretty, "0.00000000000000005");
+}
diff --git a/third_party/rust/ron/tests/large_number.rs b/third_party/rust/ron/tests/large_number.rs
new file mode 100644
index 0000000000..c8ae49f0b4
--- /dev/null
+++ b/third_party/rust/ron/tests/large_number.rs
@@ -0,0 +1,28 @@
+use ron::value::{Number, Value};
+
+#[test]
+fn test_large_number() {
+ let test_var = Value::Number(Number::new(10000000000000000000000.0f64));
+ let test_ser = ron::ser::to_string(&test_var).unwrap();
+ let test_deser = ron::de::from_str::<Value>(&test_ser);
+
+ assert_eq!(
+ test_deser.unwrap(),
+ Value::Number(Number::new(10000000000000000000000.0))
+ );
+}
+
+#[test]
+fn test_large_integer_to_float() {
+ use ron::value::Float;
+ let test_var = std::i64::MAX as u64 + 1;
+ let expected = test_var as f64; // Is exactly representable by f64
+ let test_ser = ron::ser::to_string(&test_var).unwrap();
+ assert_eq!(test_ser, test_var.to_string());
+ let test_deser = ron::de::from_str::<Value>(&test_ser);
+
+ assert_eq!(
+ test_deser.unwrap(),
+ Value::Number(Number::Float(Float::new(expected))),
+ );
+}
diff --git a/third_party/rust/ron/tests/min_max.rs b/third_party/rust/ron/tests/min_max.rs
new file mode 100644
index 0000000000..cbe6c0298b
--- /dev/null
+++ b/third_party/rust/ron/tests/min_max.rs
@@ -0,0 +1,69 @@
+use ron::{de::*, ser::*};
+
+#[test]
+fn test_i32_min() {
+ assert_eq!(
+ std::i32::MIN,
+ from_str(&to_string(&std::i32::MIN).unwrap()).unwrap()
+ );
+}
+
+#[test]
+fn test_i32_max() {
+ assert_eq!(
+ std::i32::MAX,
+ from_str(&to_string(&std::i32::MAX).unwrap()).unwrap()
+ );
+}
+
+#[test]
+fn test_i64_min() {
+ assert_eq!(
+ std::i64::MIN,
+ from_str(&to_string(&std::i64::MIN).unwrap()).unwrap()
+ );
+}
+
+#[test]
+fn test_i64_max() {
+ assert_eq!(
+ std::i64::MAX,
+ from_str(&to_string(&std::i64::MAX).unwrap()).unwrap()
+ );
+}
+
+#[cfg(feature = "integer128")]
+#[test]
+fn test_i128_min() {
+ assert_eq!(
+ std::i128::MIN,
+ from_str(&to_string(&std::i128::MIN).unwrap()).unwrap()
+ );
+}
+
+#[cfg(feature = "integer128")]
+#[test]
+fn test_i128_max() {
+ assert_eq!(
+ std::i128::MAX,
+ from_str(&to_string(&std::i128::MAX).unwrap()).unwrap()
+ );
+}
+
+#[cfg(feature = "integer128")]
+#[test]
+fn test_u128_min() {
+ assert_eq!(
+ std::u128::MIN,
+ from_str(&to_string(&std::u128::MIN).unwrap()).unwrap()
+ );
+}
+
+#[cfg(feature = "integer128")]
+#[test]
+fn test_u128_max() {
+ assert_eq!(
+ std::u128::MAX,
+ from_str(&to_string(&std::u128::MAX).unwrap()).unwrap()
+ );
+}
diff --git a/third_party/rust/ron/tests/non_identifier_identifier.rs b/third_party/rust/ron/tests/non_identifier_identifier.rs
new file mode 100644
index 0000000000..81b6c2cdc6
--- /dev/null
+++ b/third_party/rust/ron/tests/non_identifier_identifier.rs
@@ -0,0 +1,94 @@
+macro_rules! test_non_identifier {
+ ($test_name:ident => $deserialize_method:ident($($deserialize_param:expr),*)) => {
+ #[test]
+ fn $test_name() {
+ use serde::{Deserialize, Deserializer, de::Visitor, de::MapAccess};
+
+ struct FieldVisitor;
+
+ impl<'de> Visitor<'de> for FieldVisitor {
+ type Value = FieldName;
+
+ // GRCOV_EXCL_START
+ fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ fmt.write_str("an error")
+ }
+ // GRCOV_EXCL_STOP
+ }
+
+ struct FieldName;
+
+ impl<'de> Deserialize<'de> for FieldName {
+ fn deserialize<D: Deserializer<'de>>(deserializer: D)
+ -> Result<Self, D::Error>
+ {
+ deserializer.$deserialize_method($($deserialize_param,)* FieldVisitor)
+ }
+ }
+
+ struct StructVisitor;
+
+ impl<'de> Visitor<'de> for StructVisitor {
+ type Value = Struct;
+
+ // GRCOV_EXCL_START
+ fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ fmt.write_str("a struct")
+ }
+ // GRCOV_EXCL_STOP
+
+ fn visit_map<A: MapAccess<'de>>(self, mut map: A)
+ -> Result<Self::Value, A::Error>
+ {
+ map.next_key::<FieldName>().map(|_| Struct)
+ }
+ }
+
+ #[derive(Debug)]
+ struct Struct;
+
+ impl<'de> Deserialize<'de> for Struct {
+ fn deserialize<D: Deserializer<'de>>(deserializer: D)
+ -> Result<Self, D::Error>
+ {
+ deserializer.deserialize_struct("Struct", &[], StructVisitor)
+ }
+ }
+
+ assert_eq!(
+ ron::from_str::<Struct>("(true: 4)").unwrap_err().code,
+ ron::Error::ExpectedIdentifier
+ )
+ }
+ };
+}
+
+test_non_identifier! { test_bool => deserialize_bool() }
+test_non_identifier! { test_i8 => deserialize_i8() }
+test_non_identifier! { test_i16 => deserialize_i16() }
+test_non_identifier! { test_i32 => deserialize_i32() }
+test_non_identifier! { test_i64 => deserialize_i64() }
+#[cfg(feature = "integer128")]
+test_non_identifier! { test_i128 => deserialize_i128() }
+test_non_identifier! { test_u8 => deserialize_u8() }
+test_non_identifier! { test_u16 => deserialize_u16() }
+test_non_identifier! { test_u32 => deserialize_u32() }
+test_non_identifier! { test_u64 => deserialize_u64() }
+#[cfg(feature = "integer128")]
+test_non_identifier! { test_u128 => deserialize_u128() }
+test_non_identifier! { test_f32 => deserialize_f32() }
+test_non_identifier! { test_f64 => deserialize_f64() }
+test_non_identifier! { test_char => deserialize_char() }
+test_non_identifier! { test_string => deserialize_string() }
+test_non_identifier! { test_bytes => deserialize_bytes() }
+test_non_identifier! { test_byte_buf => deserialize_byte_buf() }
+test_non_identifier! { test_option => deserialize_option() }
+test_non_identifier! { test_unit => deserialize_unit() }
+test_non_identifier! { test_unit_struct => deserialize_unit_struct("") }
+test_non_identifier! { test_newtype_struct => deserialize_newtype_struct("") }
+test_non_identifier! { test_seq => deserialize_seq() }
+test_non_identifier! { test_tuple => deserialize_tuple(0) }
+test_non_identifier! { test_tuple_struct => deserialize_tuple_struct("", 0) }
+test_non_identifier! { test_map => deserialize_map() }
+test_non_identifier! { test_struct => deserialize_struct("", &[]) }
+test_non_identifier! { test_enum => deserialize_enum("", &[]) }
diff --git a/third_party/rust/ron/tests/numbers.rs b/third_party/rust/ron/tests/numbers.rs
new file mode 100644
index 0000000000..bdd357478d
--- /dev/null
+++ b/third_party/rust/ron/tests/numbers.rs
@@ -0,0 +1,113 @@
+use ron::{
+ de::from_str,
+ error::{Error, Position, SpannedError},
+};
+
+#[test]
+fn test_hex() {
+ assert_eq!(from_str("0x507"), Ok(0x507));
+ assert_eq!(from_str("0x1A5"), Ok(0x1A5));
+ assert_eq!(from_str("0x53C537"), Ok(0x53C537));
+
+ assert_eq!(
+ from_str::<u8>("0x"),
+ Err(SpannedError {
+ code: Error::ExpectedInteger,
+ position: Position { line: 1, col: 3 },
+ })
+ );
+ assert_eq!(
+ from_str::<u8>("0x_1"),
+ Err(SpannedError {
+ code: Error::UnderscoreAtBeginning,
+ position: Position { line: 1, col: 3 },
+ })
+ );
+ assert_eq!(
+ from_str::<u8>("0xFFF"),
+ Err(SpannedError {
+ code: Error::IntegerOutOfBounds,
+ position: Position { line: 1, col: 6 },
+ })
+ );
+}
+
+#[test]
+fn test_bin() {
+ assert_eq!(from_str("0b101"), Ok(0b101));
+ assert_eq!(from_str("0b001"), Ok(0b001));
+ assert_eq!(from_str("0b100100"), Ok(0b100100));
+
+ assert_eq!(
+ from_str::<u8>("0b"),
+ Err(SpannedError {
+ code: Error::ExpectedInteger,
+ position: Position { line: 1, col: 3 },
+ })
+ );
+ assert_eq!(
+ from_str::<u8>("0b_1"),
+ Err(SpannedError {
+ code: Error::UnderscoreAtBeginning,
+ position: Position { line: 1, col: 3 },
+ })
+ );
+ assert_eq!(
+ from_str::<u8>("0b111111111"),
+ Err(SpannedError {
+ code: Error::IntegerOutOfBounds,
+ position: Position { line: 1, col: 12 },
+ })
+ );
+}
+
+#[test]
+fn test_oct() {
+ assert_eq!(from_str("0o1461"), Ok(0o1461));
+ assert_eq!(from_str("0o051"), Ok(0o051));
+ assert_eq!(from_str("0o150700"), Ok(0o150700));
+
+ assert_eq!(
+ from_str::<u8>("0o"),
+ Err(SpannedError {
+ code: Error::ExpectedInteger,
+ position: Position { line: 1, col: 3 },
+ })
+ );
+ assert_eq!(
+ from_str::<u8>("0o_1"),
+ Err(SpannedError {
+ code: Error::UnderscoreAtBeginning,
+ position: Position { line: 1, col: 3 },
+ })
+ );
+ assert_eq!(
+ from_str::<u8>("0o77777"),
+ Err(SpannedError {
+ code: Error::IntegerOutOfBounds,
+ position: Position { line: 1, col: 8 },
+ })
+ );
+}
+
+#[test]
+fn test_dec() {
+ assert_eq!(from_str("1461"), Ok(1461));
+ assert_eq!(from_str("51"), Ok(51));
+ assert_eq!(from_str("150700"), Ok(150700));
+
+ assert_eq!(
+ from_str::<i8>("-_1"),
+ Err(SpannedError {
+ code: Error::UnderscoreAtBeginning,
+ position: Position { line: 1, col: 2 },
+ })
+ );
+ assert_eq!(
+ from_str::<u8>("256"),
+ Err(SpannedError {
+ code: Error::IntegerOutOfBounds,
+ position: Position { line: 1, col: 4 },
+ })
+ );
+}
diff --git a/third_party/rust/ron/tests/options.rs b/third_party/rust/ron/tests/options.rs
new file mode 100644
index 0000000000..0f60924688
--- /dev/null
+++ b/third_party/rust/ron/tests/options.rs
@@ -0,0 +1,52 @@
+use ron::{extensions::Extensions, ser::PrettyConfig, Options};
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize)]
+struct Newtype(f64);
+
+#[derive(Serialize, Deserialize)]
+struct Struct(Option<u32>, Newtype);
+
+#[test]
+fn default_options() {
+ let ron = Options::default();
+
+ let de: Struct = ron.from_str("(Some(42),(4.2))").unwrap();
+ let ser = ron.to_string(&de).unwrap();
+
+ assert_eq!(ser, "(Some(42),(4.2))")
+}
+
+#[test]
+fn single_default_extension() {
+ let ron = Options::default().with_default_extension(Extensions::IMPLICIT_SOME);
+
+ let de: Struct = ron.from_str("(42,(4.2))").unwrap();
+ let ser = ron.to_string(&de).unwrap();
+
+ assert_eq!(ser, "(42,(4.2))");
+
+ let de: Struct = ron.from_str("#![enable(implicit_some)](42,(4.2))").unwrap();
+ let ser = ron.to_string(&de).unwrap();
+
+ assert_eq!(ser, "(42,(4.2))");
+
+ let de: Struct = ron
+ .from_str("#![enable(implicit_some)]#![enable(unwrap_newtypes)](42,4.2)")
+ .unwrap();
+ let ser = ron.to_string(&de).unwrap();
+
+ assert_eq!(ser, "(42,(4.2))");
+
+ let de: Struct = ron
+ .from_str("#![enable(implicit_some)]#![enable(unwrap_newtypes)](42,4.2)")
+ .unwrap();
+ let ser = ron
+ .to_string_pretty(
+ &de,
+ PrettyConfig::default().extensions(Extensions::UNWRAP_NEWTYPES),
+ )
+ .unwrap();
+
+ assert_eq!(ser, "#![enable(unwrap_newtypes)]\n(42, 4.2)");
+}
diff --git a/third_party/rust/ron/tests/preserve_sequence.rs b/third_party/rust/ron/tests/preserve_sequence.rs
new file mode 100644
index 0000000000..bdfe3575e9
--- /dev/null
+++ b/third_party/rust/ron/tests/preserve_sequence.rs
@@ -0,0 +1,48 @@
+use std::collections::BTreeMap;
+
+use ron::{
+ de::from_str,
+ ser::{to_string_pretty, PrettyConfig},
+};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Deserialize, Serialize)]
+struct Config {
+ boolean: bool,
+ float: f32,
+ map: BTreeMap<u8, char>,
+ nested: Nested,
+ tuple: (u32, u32),
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+struct Nested {
+ a: String,
+ b: char,
+}
+
+fn read_original(source: &str) -> String {
+ source.to_string().replace("\r\n", "\n")
+}
+
+fn make_roundtrip(source: &str) -> String {
+ let config: Config = from_str(source).unwrap();
+ let pretty = PrettyConfig::new()
+ .depth_limit(3)
+ .separate_tuple_members(true)
+ .enumerate_arrays(true)
+ .new_line("\n".into());
+ to_string_pretty(&config, pretty).expect("Serialization failed")
+}
+
+#[test]
+fn test_sequence_ex1() {
+ let file = include_str!("preserve_sequence_ex1.ron");
+ assert_eq!(read_original(file), make_roundtrip(file));
+}
+
+#[test]
+fn test_sequence_ex2() {
+ let file = include_str!("preserve_sequence_ex2.ron");
+ assert_eq!(read_original(file), make_roundtrip(file));
+}
diff --git a/third_party/rust/ron/tests/preserve_sequence_ex1.ron b/third_party/rust/ron/tests/preserve_sequence_ex1.ron
new file mode 100644
index 0000000000..8373cfd379
--- /dev/null
+++ b/third_party/rust/ron/tests/preserve_sequence_ex1.ron
@@ -0,0 +1,20 @@
+(
+ boolean: true,
+ float: 8.2,
+ map: {
+ 1: '1',
+ 2: '4',
+ 3: '9',
+ 4: '1',
+ 5: '2',
+ 6: '3',
+ },
+ nested: (
+ a: "Decode me!",
+ b: 'z',
+ ),
+ tuple: (
+ 3,
+ 7,
+ ),
+) \ No newline at end of file
diff --git a/third_party/rust/ron/tests/preserve_sequence_ex2.ron b/third_party/rust/ron/tests/preserve_sequence_ex2.ron
new file mode 100644
index 0000000000..42c0e5a190
--- /dev/null
+++ b/third_party/rust/ron/tests/preserve_sequence_ex2.ron
@@ -0,0 +1,15 @@
+(
+ boolean: true,
+ float: 8.2,
+ map: {
+ 1: '1',
+ },
+ nested: (
+ a: "Decode me!",
+ b: 'z',
+ ),
+ tuple: (
+ 3,
+ 7,
+ ),
+) \ No newline at end of file
diff --git a/third_party/rust/ron/tests/roundtrip.rs b/third_party/rust/ron/tests/roundtrip.rs
new file mode 100644
index 0000000000..cc168f024e
--- /dev/null
+++ b/third_party/rust/ron/tests/roundtrip.rs
@@ -0,0 +1,121 @@
+use std::collections::HashMap;
+
+use ron::extensions::Extensions;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct UnitStruct;
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct NewType(f32);
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct TupleStruct(UnitStruct, i8);
+
+#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
+struct Key(u32);
+
+#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
+enum Enum {
+ Unit,
+ Bool(bool),
+ Chars(char, String),
+}
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct Struct {
+ tuple: ((), NewType, TupleStruct),
+ vec: Vec<Option<UnitStruct>>,
+ map: HashMap<Key, Enum>,
+}
+
+#[test]
+fn roundtrip() {
+ let value = Struct {
+ tuple: ((), NewType(0.5), TupleStruct(UnitStruct, -5)),
+ vec: vec![None, Some(UnitStruct)],
+ map: vec![
+ (Key(5), Enum::Unit),
+ (Key(6), Enum::Bool(false)),
+ (Key(7), Enum::Bool(true)),
+ (Key(9), Enum::Chars('x', "".to_string())),
+ ]
+ .into_iter()
+ .collect(),
+ };
+
+ let serial = ron::ser::to_string(&value).unwrap();
+
+ println!("Serialized: {}", serial);
+
+ let deserial = ron::de::from_str(&serial);
+
+ assert_eq!(Ok(value), deserial);
+}
+
+#[test]
+fn roundtrip_pretty() {
+ let value = Struct {
+ tuple: ((), NewType(0.5), TupleStruct(UnitStruct, -5)),
+ vec: vec![None, Some(UnitStruct)],
+ map: vec![
+ (Key(5), Enum::Unit),
+ (Key(6), Enum::Bool(false)),
+ (Key(7), Enum::Bool(true)),
+ (Key(9), Enum::Chars('x', "".to_string())),
+ ]
+ .into_iter()
+ .collect(),
+ };
+
+ let pretty = ron::ser::PrettyConfig::new()
+ .enumerate_arrays(true)
+ .extensions(Extensions::IMPLICIT_SOME);
+ let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
+
+ println!("Serialized: {}", serial);
+
+ let deserial = ron::de::from_str(&serial);
+
+ assert_eq!(Ok(value), deserial);
+}
+
+#[test]
+fn roundtrip_sep_tuple_members() {
+ #[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
+ pub enum FileOrMem {
+ File(String),
+ Memory,
+ }
+
+ #[derive(Debug, Deserialize, PartialEq, Serialize)]
+ struct Both {
+ a: Struct,
+ b: FileOrMem,
+ }
+
+ let a = Struct {
+ tuple: ((), NewType(0.5), TupleStruct(UnitStruct, -5)),
+ vec: vec![None, Some(UnitStruct)],
+ map: vec![
+ (Key(5), Enum::Unit),
+ (Key(6), Enum::Bool(false)),
+ (Key(7), Enum::Bool(true)),
+ (Key(9), Enum::Chars('x', "".to_string())),
+ ]
+ .into_iter()
+ .collect(),
+ };
+ let b = FileOrMem::File("foo".to_owned());
+
+ let value = Both { a, b };
+
+ let pretty = ron::ser::PrettyConfig::new().separate_tuple_members(true);
+ let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
+
+ println!("Serialized: {}", serial);
+
+ let deserial = ron::de::from_str(&serial);
+
+ assert_eq!(Ok(value), deserial);
+}
diff --git a/third_party/rust/ron/tests/struct_integers.rs b/third_party/rust/ron/tests/struct_integers.rs
new file mode 100644
index 0000000000..385d53dab3
--- /dev/null
+++ b/third_party/rust/ron/tests/struct_integers.rs
@@ -0,0 +1,39 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct S {
+ a: i8,
+ b: i16,
+ c: i32,
+ d: i64,
+ #[cfg(feature = "integer128")]
+ e: i128,
+ f: u8,
+ g: u16,
+ h: u32,
+ i: u64,
+ #[cfg(feature = "integer128")]
+ j: u128,
+}
+
+#[test]
+fn roundtrip() {
+ let s = S {
+ a: std::i8::MIN,
+ b: std::i16::MIN,
+ c: std::i32::MIN,
+ d: std::i64::MIN,
+ #[cfg(feature = "integer128")]
+ e: std::i128::MIN,
+ f: std::u8::MAX,
+ g: std::u16::MAX,
+ h: std::u32::MAX,
+ i: std::u64::MAX,
+ #[cfg(feature = "integer128")]
+ j: std::u128::MAX,
+ };
+ let serialized = ron::ser::to_string(&s).unwrap();
+ dbg!(&serialized);
+ let deserialized = ron::de::from_str(&serialized).unwrap();
+ assert_eq!(s, deserialized,);
+}
diff --git a/third_party/rust/ron/tests/to_string_pretty.rs b/third_party/rust/ron/tests/to_string_pretty.rs
new file mode 100644
index 0000000000..ad5c7ed261
--- /dev/null
+++ b/third_party/rust/ron/tests/to_string_pretty.rs
@@ -0,0 +1,23 @@
+use ron::{
+ ser::{to_string_pretty, PrettyConfig},
+ to_string,
+};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Deserialize, Serialize)]
+struct Point {
+ x: f64,
+ y: f64,
+}
+
+#[test]
+fn test_struct_names() {
+ let value = Point { x: 1.0, y: 2.0 };
+ let struct_name = to_string_pretty(&value, PrettyConfig::default().struct_names(true));
+ assert_eq!(
+ struct_name,
+ Ok("Point(\n x: 1.0,\n y: 2.0,\n)".to_string())
+ );
+ let no_struct_name = to_string(&value);
+ assert_eq!(no_struct_name, Ok("(x:1.0,y:2.0)".to_string()));
+}
diff --git a/third_party/rust/ron/tests/unicode.rs b/third_party/rust/ron/tests/unicode.rs
new file mode 100644
index 0000000000..0617eeed14
--- /dev/null
+++ b/third_party/rust/ron/tests/unicode.rs
@@ -0,0 +1,13 @@
+use ron::de::from_str;
+
+#[test]
+fn test_char() {
+ let de: char = from_str("'Փ'").unwrap();
+ assert_eq!(de, 'Փ');
+}
+
+#[test]
+fn test_string() {
+ let de: String = from_str("\"My string: ऄ\"").unwrap();
+ assert_eq!(de, "My string: ऄ");
+}
diff --git a/third_party/rust/ron/tests/value.rs b/third_party/rust/ron/tests/value.rs
new file mode 100644
index 0000000000..3919058c04
--- /dev/null
+++ b/third_party/rust/ron/tests/value.rs
@@ -0,0 +1,163 @@
+use std::f64;
+
+use ron::{
+ error::Error,
+ value::{Map, Number, Value},
+};
+use serde::Serialize;
+
+#[test]
+fn bool() {
+ assert_eq!("true".parse(), Ok(Value::Bool(true)));
+ assert_eq!("false".parse(), Ok(Value::Bool(false)));
+}
+
+#[test]
+fn char() {
+ assert_eq!("'a'".parse(), Ok(Value::Char('a')));
+}
+
+#[test]
+fn map() {
+ let mut map = Map::new();
+ map.insert(Value::Char('a'), Value::Number(Number::new(1)));
+ map.insert(Value::Char('b'), Value::Number(Number::new(2f64)));
+ assert_eq!("{ 'a': 1, 'b': 2.0 }".parse(), Ok(Value::Map(map)));
+}
+
+#[test]
+fn number() {
+ assert_eq!("42".parse(), Ok(Value::Number(Number::new(42))));
+ assert_eq!(
+ "3.141592653589793".parse(),
+ Ok(Value::Number(Number::new(f64::consts::PI)))
+ );
+}
+
+#[test]
+fn option() {
+ let opt = Some(Box::new(Value::Char('c')));
+ assert_eq!("Some('c')".parse(), Ok(Value::Option(opt)));
+}
+
+#[test]
+fn string() {
+ let normal = "\"String\"";
+ assert_eq!(normal.parse(), Ok(Value::String("String".into())));
+
+ let raw = "r\"Raw String\"";
+ assert_eq!(raw.parse(), Ok(Value::String("Raw String".into())));
+
+ let raw_hashes = "r#\"Raw String\"#";
+ assert_eq!(raw_hashes.parse(), Ok(Value::String("Raw String".into())));
+
+ let raw_escaped = "r##\"Contains \"#\"##";
+ assert_eq!(
+ raw_escaped.parse(),
+ Ok(Value::String("Contains \"#".into()))
+ );
+
+ let raw_multi_line = "r\"Multi\nLine\"";
+ assert_eq!(
+ raw_multi_line.parse(),
+ Ok(Value::String("Multi\nLine".into()))
+ );
+}
+
+#[test]
+fn seq() {
+ let seq = vec![
+ Value::Number(Number::new(1)),
+ Value::Number(Number::new(2f64)),
+ ];
+ assert_eq!("[1, 2.0]".parse(), Ok(Value::Seq(seq)));
+
+ let err = Value::Seq(vec![Value::Number(Number::new(1))])
+ .into_rust::<[i32; 2]>()
+ .unwrap_err();
+
+ assert_eq!(
+ err,
+ Error::ExpectedDifferentLength {
+ expected: String::from("an array of length 2"),
+ found: 1,
+ }
+ );
+
+ let err = Value::Seq(vec![
+ Value::Number(Number::new(1)),
+ Value::Number(Number::new(2)),
+ Value::Number(Number::new(3)),
+ ])
+ .into_rust::<[i32; 2]>()
+ .unwrap_err();
+
+ assert_eq!(
+ err,
+ Error::ExpectedDifferentLength {
+ expected: String::from("a sequence of length 2"),
+ found: 3,
+ }
+ );
+}
+
+#[test]
+fn unit() {
+ use ron::error::{Error, Position, SpannedError};
+
+ assert_eq!("()".parse(), Ok(Value::Unit));
+ assert_eq!("Foo".parse(), Ok(Value::Unit));
+
+ assert_eq!(
+ "".parse::<Value>(),
+ Err(SpannedError {
+ code: Error::Eof,
+ position: Position { col: 1, line: 1 }
+ })
+ );
+}
+
+#[derive(Serialize)]
+struct Scene(Option<(u32, u32)>);
+
+#[derive(Serialize)]
+struct Scene2 {
+ foo: Option<(u32, u32)>,
+}
+
+#[test]
+fn roundtrip() {
+ use ron::{de::from_str, ser::to_string};
+
+ {
+ let s = to_string(&Scene2 {
+ foo: Some((122, 13)),
+ })
+ .unwrap();
+ println!("{}", s);
+ let scene: Value = from_str(&s).unwrap();
+ println!("{:?}", scene);
+ }
+ {
+ let s = to_string(&Scene(Some((13, 122)))).unwrap();
+ println!("{}", s);
+ let scene: Value = from_str(&s).unwrap();
+ println!("{:?}", scene);
+ }
+}
+
+#[test]
+fn map_roundtrip_338() {
+ // https://github.com/ron-rs/ron/issues/338
+
+ let v: Value = ron::from_str("{}").unwrap();
+ println!("{:?}", v);
+
+ let ser = ron::to_string(&v).unwrap();
+ println!("{:?}", ser);
+
+ let roundtrip = ron::from_str(&ser).unwrap();
+ println!("{:?}", roundtrip);
+
+ assert_eq!(v, roundtrip);
+}