summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ron
diff options
context:
space:
mode:
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.md211
-rw-r--r--third_party/rust/ron/Cargo.lock163
-rw-r--r--third_party/rust/ron/Cargo.toml63
-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.md171
-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.md140
-rw-r--r--third_party/rust/ron/examples/decode.rs67
-rw-r--r--third_party/rust/ron/examples/decode_file.rs36
-rw-r--r--third_party/rust/ron/examples/encode.rs49
-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.rs807
-rw-r--r--third_party/rust/ron/src/de/tag.rs251
-rw-r--r--third_party/rust/ron/src/de/tests.rs362
-rw-r--r--third_party/rust/ron/src/de/value.rs335
-rw-r--r--third_party/rust/ron/src/error.rs404
-rw-r--r--third_party/rust/ron/src/extensions.rs28
-rw-r--r--third_party/rust/ron/src/lib.rs20
-rw-r--r--third_party/rust/ron/src/options.rs183
-rw-r--r--third_party/rust/ron/src/parse.rs978
-rw-r--r--third_party/rust/ron/src/ser/mod.rs996
-rw-r--r--third_party/rust/ron/src/ser/tests.rs146
-rw-r--r--third_party/rust/ron/src/ser/value.rs23
-rw-r--r--third_party/rust/ron/src/value.rs553
-rw-r--r--third_party/rust/ron/tests/117_untagged_tuple_variant.rs59
-rw-r--r--third_party/rust/ron/tests/123_enum_representation.rs273
-rw-r--r--third_party/rust/ron/tests/129_indexmap.rs76
-rw-r--r--third_party/rust/ron/tests/147_empty_sets_serialisation.rs62
-rw-r--r--third_party/rust/ron/tests/152_bitflags.rs80
-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/240_array_pretty.rs52
-rw-r--r--third_party/rust/ron/tests/250_variant_newtypes.rs407
-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/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/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.rs59
-rw-r--r--third_party/rust/ron/tests/escape.rs77
-rw-r--r--third_party/rust/ron/tests/extensions.rs91
-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/numbers.rs111
-rw-r--r--third_party/rust/ron/tests/options.rs53
-rw-r--r--third_party/rust/ron/tests/preserve_sequence.rs47
-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.rs21
-rw-r--r--third_party/rust/ron/tests/unicode.rs13
-rw-r--r--third_party/rust/ron/tests/value.rs131
67 files changed, 9593 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..47a21172be
--- /dev/null
+++ b/third_party/rust/ron/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"5560ffa7d7db7d15d03fd15bfa210bcf694762efc0327cd981293a849395d1c6","Cargo.lock":"c96c96146e827f66ecd91443a0a2aa84ef1f5499f4affd6d1cbf6068905fb304","Cargo.toml":"6c18303873768e123aa7b1ff2967d1354835aad5b16431e920e9609d40b1aba1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"fa0598d520497731445a5bc89a2b3d47896d95568bd2be255b7bc43d771b9994","README.md":"3842cc540b99051013dc72b89cc7575c3b2ea6468c4945bb040b752d9cee6ac1","clippy.toml":"12e7ca8f0fcbd33bc8ebb1babf6e967073019df81a175b0b1bb2cae931c2865d","docs/extensions.md":"47cb367dbef73952065fe1c0b1186603b108dc70b5d8abbf3eff3b75c1024912","docs/grammar.md":"b0dfbe6850629cea3515c2892ca1103929dee2b04bde1ad431a820422baf493e","examples/decode.rs":"2a11b77bc06679657fb10f6d908f89fe217bb3c31209b4cbca82cfbb06ea88cb","examples/decode_file.rs":"195b3c8fd2a87587014f0286bcb0590fa84050aabd9851b879985ab1a7971138","examples/encode.rs":"0ed5ae13562a10c740c816e3bed5e4c1538b737412a86a074cdd2adb5d293263","examples/example.ron":"aebd2baff31a62c3aed1ba568b7a7c1165b197d526a1e2c9eb7adb211de8292e","examples/transcode.rs":"7a1e281684243b263d28f90f2836d6098239ae8ab2a0cb9d97ee0b7521ba960e","rustfmt.toml":"56a01ff6240c06eb9a198c938c72fe9cf49dd62a79cd693bb50d63dcb1a415eb","src/de/id.rs":"608b7bcc400f126007166da1455fb77dac34e42918c1f94717bb3d5e8127170b","src/de/mod.rs":"622d39480d3a518ec7d516e183ab403ead7cd147d8b905c0117504ce1cae7ebd","src/de/tag.rs":"527c3ea01886612c17440608daa11a3e1b3aa3b11b8c3f06f68d6ba1fc70ba27","src/de/tests.rs":"3c1dc1098a25ce268572b8ffdd91f414e3a2183377d2474f91c4e0e326215102","src/de/value.rs":"2a3cdbeb878243f6594f9aef403922df3cb6095b98a5c6ca38749a560216c31e","src/error.rs":"cfc6236a29e3a119997a42f51dfcbc44437e1f4bd8a6da4f58bfaad82e36e682","src/extensions.rs":"cc2d7baa95b0195a16b734e8022379f3666aa61de8f36db3f68d47ce67129bf1","src/lib.rs":"380e6d2def6c62630a99b5df3dd9a9a0cee2df35312f9ea5d970531bed093d03","src/options.rs":"25b544cef454d2be379a7e5b3c9f7532b56aa2d992da2b0e88fa60ac8f0a63de","src/parse.rs":"b8cbf2cad1e3199d7acc44c0a59a64e699ff551d2fe612d2d3ca42cf2e321063","src/ser/mod.rs":"fcc80cca04b2c8d6c08e00345f581cad322197019e4fa20b65b0cce2a4c40057","src/ser/tests.rs":"342d6b67fd757d2c12ed2cc16bddbcd35ca2d64623831b77ff121cbbfe23118b","src/ser/value.rs":"0c099c6c3c73062048c989dc8f70c3e67cfd3989a286da79a45323830c4a277b","src/value.rs":"1abcdf19d5ebb1617ff66f560b637ddea1a92308473a58b594301a45a6f568a2","tests/117_untagged_tuple_variant.rs":"1ce8d384d84ff21a28dafef0f0ea4be9e6cbf9bd7c2ed4aa37e8d820c7b594b8","tests/123_enum_representation.rs":"aeae57321e4f674b8d469a59c4ea8d5c3c908ce89c9812de99936a6095d52739","tests/129_indexmap.rs":"a55ed888407dce347035893afa6a5e60d3e2f92672287c93cf5e21bb19218a40","tests/147_empty_sets_serialisation.rs":"017a0c0d734b862ad9b9286376a07d80bb48af7a3753ee982ec27d1dcef61c7c","tests/152_bitflags.rs":"0fec781bf91fe8a6743ab1aaada8287220e1238a4f1d07452fe5004177833cd5","tests/203_error_positions.rs":"a78b5232a686950befc2c2139aa1a120cbdfad2cc7b5ac5ab4bc8622adf31fa1","tests/207_adjacently_tagged_enum.rs":"a1ba4e08d95f9a241e450bc0655eea08a0fd776d6118373de031231e090a9f29","tests/240_array_pretty.rs":"5187f3d50aa94db60d6fb42162921e9d94c7573c61767ded898a6ca50929f18b","tests/250_variant_newtypes.rs":"649eeef56ffe1d8119efbc1e40b6eedf46a8f255c5e79b40b46d60a3217c56d2","tests/256_comma_error.rs":"c2e2d7b37d4810e0eb12af2c47dfd47fa64adf14a350a745c575ff02caaf6d41","tests/289_enumerate_arrays.rs":"0e1e9bd624b756714c6d79b79c388972c4b443c331d08098d585a85cba519bb5","tests/301_struct_name_mismatch.rs":"b980a004edadc4829479e96f897290de25c34c4efb364e5a7d8bd695fdfb78c0","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":"f1b585e9e590285da2757f032aafbf0c218d9ca1732cd9ec9b67f1969fc03920","tests/big_struct.rs":"9c7b41233ae7d0c4fec0727aabd4cea1cd95844c85c0beb5e688b3c79eb43c14","tests/borrowed_str.rs":"24390ee6076ce3896b7cf1b2e202cb3a705c61129a4f62f6c39a2412ca68405f","tests/comments.rs":"d88ba142978b5536f6891d839c89c420196f8927fd059eb25c087b555f235109","tests/depth_limit.rs":"6b2675b271229f495d93d9b555b69c8cbc66be0e6a2b3d41aa1d097c9b92ddd4","tests/escape.rs":"d401d9026ff9168d6973894ee4dd086bbe31aeec72e5d465da1b00f33e4cfe67","tests/extensions.rs":"1c6f030fdcba63d8e9b645661e9f9b1fdf7e98fc73c06586c1ee116cf1e65187","tests/floats.rs":"367a22cca7d3a3ce6bdffc30df8712aae348ad29a1adbe9a47bc98e0a51b614d","tests/large_number.rs":"415ad0374b22553b0cf7926b6d7a64505f8b6021d46b6a93587024449f60b353","tests/min_max.rs":"4529513a4cf1e5c25f7697ba258fdbae258617cf8f3374080843aef048c2bde3","tests/numbers.rs":"2b6f4f706f247ae1d2f0457157a882f3279e20d4f52f250ca78e33693ac1024e","tests/options.rs":"e62ffcb23d9fc5a44a3d452256109a8e084f07a92dd36f17b6fb56393e600820","tests/preserve_sequence.rs":"d11dd6a67c83e930848d07fbfea04a75a0f157f8f11cd50835d5b36793d08902","tests/preserve_sequence_ex1.ron":"47bdf8da637b6e99701b5a4b8c100b4c9d45440c357aef8d368a406a05394ea9","tests/preserve_sequence_ex2.ron":"9ba759300324f8978469ce616f20eb0cfc134f0a8a1afff884fff5315b32e0d0","tests/roundtrip.rs":"61275cab0b2769225c3a4a029a308135594dd873002e13dea584e8939eeb681e","tests/struct_integers.rs":"10f06e4d0845c8319236122047e6bda2765082fdf93b8d9c3770c29fb941086d","tests/to_string_pretty.rs":"54a503e2a34b04122b085e69852078a3b0aaa1ac8afe52ac65b349479e36eb50","tests/unicode.rs":"ac3944bf448f8cd5986bad5e7c4eca60302230c13378b213415dafc1d3ae2428","tests/value.rs":"3e4e9904456b4d2a2e720bd9420c4a4ace26ac832777f0e655148875ccf2d7f5"},"package":"300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff"} \ 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..be5160e99f
--- /dev/null
+++ b/third_party/rust/ron/CHANGELOG.md
@@ -0,0 +1,211 @@
+# 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.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..aa3bd822fb
--- /dev/null
+++ b/third_party/rust/ron/Cargo.lock
@@ -0,0 +1,163 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+ "serde",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+
+[[package]]
+name = "option_set"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c83b2d96bdcfa87852ffdc8e77e5fb544ffe2f85ed60568f5b62c98a05ec9a9b"
+dependencies = [
+ "heck",
+ "serde",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ron"
+version = "0.8.0"
+dependencies = [
+ "base64",
+ "bitflags",
+ "indexmap",
+ "option_set",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+
+[[package]]
+name = "serde"
+version = "1.0.143"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.143"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
diff --git a/third_party/rust/ron/Cargo.toml b/third_party/rust/ron/Cargo.toml
new file mode 100644
index 0000000000..c44d06a521
--- /dev/null
+++ b/third_party/rust/ron/Cargo.toml
@@ -0,0 +1,63 @@
+# 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.56.0"
+name = "ron"
+version = "0.8.0"
+authors = [
+ "Christopher Durham <cad97@cad97.com>",
+ "Dzmitry Malyshau <kvarkus@gmail.com>",
+ "Thomas Schaller <torkleyy@gmail.com>",
+ "Juniper Langenstein <juniper.langenstein@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"
+resolver = "2"
+
+[dependencies.base64]
+version = "0.13"
+
+[dependencies.bitflags]
+version = "1.3.2"
+
+[dependencies.indexmap]
+version = "1.9.1"
+features = ["serde-1"]
+optional = true
+
+[dependencies.serde]
+version = "1.0.60"
+features = ["serde_derive"]
+
+[dev-dependencies.option_set]
+version = "0.1"
+
+[dev-dependencies.serde_bytes]
+version = "0.11"
+
+[dev-dependencies.serde_json]
+version = "1"
+
+[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..6ed5908232
--- /dev/null
+++ b/third_party/rust/ron/README.md
@@ -0,0 +1,171 @@
+# 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.56.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,
+ "A": Down,
+ "S": 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)
+
+## 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());
+}
+```
+
+## 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..9e89f43f4a
--- /dev/null
+++ b/third_party/rust/ron/clippy.toml
@@ -0,0 +1,2 @@
+msrv = "1.56.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..5c88107e76
--- /dev/null
+++ b/third_party/rust/ron/docs/grammar.md
@@ -0,0 +1,140 @@
+# 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"] | ["/*", { ? any character ? }, "*/"];
+```
+
+## 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]], ")";
+```
diff --git a/third_party/rust/ron/examples/decode.rs b/third_party/rust/ron/examples/decode.rs
new file mode 100644
index 0000000000..56a9f30074
--- /dev/null
+++ b/third_party/rust/ron/examples/decode.rs
@@ -0,0 +1,67 @@
+#![allow(dead_code)]
+
+use ron::de::from_str;
+use serde::Deserialize;
+use std::collections::HashMap;
+
+#[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..691e9367e3
--- /dev/null
+++ b/third_party/rust/ron/examples/decode_file.rs
@@ -0,0 +1,36 @@
+#![allow(dead_code)]
+
+use ron::de::from_reader;
+use serde::Deserialize;
+use std::{collections::HashMap, fs::File};
+
+#[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..ad1a237ba5
--- /dev/null
+++ b/third_party/rust/ron/examples/encode.rs
@@ -0,0 +1,49 @@
+use ron::ser::{to_string_pretty, PrettyConfig};
+use serde::Serialize;
+use std::{collections::HashMap, iter::FromIterator};
+
+#[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..ff03191910
--- /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 = "2018"
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..537ce5690a
--- /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>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_i8<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_i16<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_i32<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_i64<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_i128<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_u8<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_u16<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_u32<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_u64<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ #[cfg(feature = "integer128")]
+ fn deserialize_u128<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_f32<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_f64<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_char<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_string<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_bytes<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_option<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_unit<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_unit_struct<V>(self, _: &'static str, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_newtype_struct<V>(self, _: &'static str, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_seq<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_tuple<V>(self, _: usize, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_tuple_struct<V>(self, _: &'static str, _: usize, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_map<V>(self, _: V) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ _: &'static str,
+ _: &'static [&'static str],
+ _: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _: &'static str,
+ _: &'static [&'static str],
+ _: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'b>,
+ {
+ unimplemented!("IdDeserializer may only be used for identifiers")
+ }
+
+ 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..0920a67b43
--- /dev/null
+++ b/third_party/rust/ron/src/de/mod.rs
@@ -0,0 +1,807 @@
+/// Deserialization module.
+pub use crate::error::{Error, Position, SpannedError};
+
+use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
+use std::{borrow::Cow, io, str};
+
+use self::{id::IdDeserializer, tag::TagDeserializer};
+use crate::{
+ error::{Result, SpannedResult},
+ extensions::Extensions,
+ options::Options,
+ parse::{AnyNum, Bytes, ParsedStr},
+};
+
+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>,
+}
+
+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,
+ };
+
+ 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)
+}
+
+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` 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 {
+ // first two arguments are technically incorrect, but ignored anyway
+ self.deserialize_struct("", &[], visitor)
+ }
+ } else {
+ visitor.visit_unit()
+ }
+ }
+}
+
+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>,
+ {
+ let res = {
+ let string = self.bytes.string()?;
+ let base64_str = match string {
+ ParsedStr::Allocated(ref s) => s.as_str(),
+ ParsedStr::Slice(s) => s,
+ };
+ base64::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 = visitor.visit_some(&mut *self)?;
+
+ self.bytes.skip_ws()?;
+
+ if self.bytes.consume(")") {
+ Ok(v)
+ } else {
+ Err(Error::ExpectedOptionEnd)
+ }
+ } else if self.bytes.exts.contains(Extensions::IMPLICIT_SOME) {
+ 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 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 = 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>(mut self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.newtype_variant = false;
+
+ if self.bytes.consume("[") {
+ let value = visitor.visit_seq(CommaSeparated::new(b']', self))?;
+ self.bytes.comma()?;
+
+ if self.bytes.consume("]") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedArrayEnd)
+ }
+ } else {
+ Err(Error::ExpectedArray)
+ }
+ }
+
+ fn deserialize_tuple<V>(mut 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 = visitor.visit_seq(CommaSeparated::new(b')', self))?;
+ self.bytes.comma()?;
+
+ 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>(mut self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.newtype_variant = false;
+
+ if self.bytes.consume("{") {
+ let value = visitor.visit_map(CommaSeparated::new(b'}', self))?;
+ self.bytes.comma()?;
+
+ if self.bytes.consume("}") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedMapEnd)
+ }
+ } else {
+ Err(Error::ExpectedMap)
+ }
+ }
+
+ fn deserialize_struct<V>(
+ mut 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()?;
+
+ if self.newtype_variant || self.bytes.consume("(") {
+ let old_newtype_variant = self.newtype_variant;
+ self.newtype_variant = false;
+
+ let value = visitor
+ .visit_map(CommaSeparated::new(b')', self))
+ .map_err(|err| {
+ struct_error_name(
+ err,
+ if !old_newtype_variant && !name.is_empty() {
+ Some(name)
+ } else {
+ None
+ },
+ )
+ })?;
+
+ self.bytes.comma()?;
+
+ if old_newtype_variant || self.bytes.consume(")") {
+ Ok(value)
+ } else {
+ Err(Error::ExpectedStructLikeEnd)
+ }
+ } else if name.is_empty() {
+ Err(Error::ExpectedStructLike)
+ } else {
+ Err(Error::ExpectedNamedStructLike(name))
+ }
+ }
+
+ 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 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_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 = 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')' {
+ seed.deserialize(&mut IdDeserializer::new(&mut *self.de))
+ .map(Some)
+ } else {
+ 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 = 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 = 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 = 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
+ .deserialize_struct("", fields, 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..3e37e4e9db
--- /dev/null
+++ b/third_party/rust/ron/src/de/tests.rs
@@ -0,0 +1,362 @@
+use serde::Deserialize;
+use serde_bytes;
+
+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 self::Error::*;
+ use std::collections::HashMap;
+
+ 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..544ee05e37
--- /dev/null
+++ b/third_party/rust/ron/src/de/value.rs
@@ -0,0 +1,335 @@
+use std::fmt;
+
+use serde::{
+ de::{Error, MapAccess, SeqAccess, Visitor},
+ Deserialize, Deserializer,
+};
+
+use crate::error::SpannedResult;
+use crate::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 super::*;
+ use std::str::FromStr;
+
+ 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..7f7cc9b93e
--- /dev/null
+++ b/third_party/rust/ron/src/error.rs
@@ -0,0 +1,404 @@
+use serde::{de, ser};
+use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
+
+/// 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>,
+ },
+}
+
+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 `{}`", expected, found),
+ Error::ExpectedStructLike => f.write_str("Expected opening `(`"),
+ Error::ExpectedNamedStructLike(name) => {
+ write!(f, "Expected opening `(` for struct `{}`", 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 `{}`", 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 `{}`", found)?;
+
+ if let Some(outer) = outer {
+ write!(f, "in enum `{}`", outer)?;
+ }
+
+ write!(
+ f,
+ ", {}",
+ OneOf {
+ alts: expected,
+ none: "variants"
+ }
+ )
+ }
+ Error::NoSuchStructField {
+ expected,
+ ref found,
+ ref outer,
+ } => {
+ write!(f, "Unexpected field named `{}`", found)?;
+
+ if let Some(outer) = outer {
+ write!(f, "in `{}`", outer)?;
+ }
+
+ write!(
+ f,
+ ", {}",
+ OneOf {
+ alts: expected,
+ none: "fields"
+ }
+ )
+ }
+ Error::MissingStructField { field, ref outer } => {
+ write!(f, "Unexpected missing field `{}`", field)?;
+
+ match outer {
+ Some(outer) => write!(f, " in `{}`", outer),
+ None => Ok(()),
+ }
+ }
+ Error::DuplicateStructField { field, ref outer } => {
+ write!(f, "Unexpected duplicate field `{}`", field)?;
+
+ match outer {
+ Some(outer) => write!(f, " in `{}`", outer),
+ None => Ok(()),
+ }
+ }
+ }
+ }
+}
+
+#[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) => {
+ f.write_str("the bytes b\"")?;
+
+ for b in b {
+ write!(f, "\\x{:02x}", b)?;
+ }
+
+ f.write_str("\"")
+ }
+ 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", a1),
+ [a1, a2] => write!(f, "expected either `{}` or `{}` instead", a1, a2),
+ [a1, ref alts @ ..] => {
+ write!(f, "expected one of `{}`", a1)?;
+
+ for alt in alts {
+ write!(f, ", `{}`", alt)?;
+ }
+
+ f.write_str(" instead")
+ }
+ }
+ }
+}
diff --git a/third_party/rust/ron/src/extensions.rs b/third_party/rust/ron/src/extensions.rs
new file mode 100644
index 0000000000..39357ac7df
--- /dev/null
+++ b/third_party/rust/ron/src/extensions.rs
@@ -0,0 +1,28 @@
+use serde::{Deserialize, Serialize};
+
+bitflags::bitflags! {
+ #[derive(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()
+ }
+}
diff --git a/third_party/rust/ron/src/lib.rs b/third_party/rust/ron/src/lib.rs
new file mode 100644
index 0000000000..af7b06bcc5
--- /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.0")]
+
+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..1e35118122
--- /dev/null
+++ b/third_party/rust/ron/src/options.rs
@@ -0,0 +1,183 @@
+//! Roundtrip serde Options module.
+
+use std::io;
+
+use serde::{de, ser, Deserialize, Serialize};
+
+use crate::de::Deserializer;
+use crate::error::{Result, SpannedResult};
+use crate::extensions::Extensions;
+use crate::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,
+}
+
+impl Default for Options {
+ fn default() -> Self {
+ Self {
+ default_extensions: Extensions::empty(),
+ }
+ }
+}
+
+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
+ }
+}
+
+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`
+ 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` 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..b0cc632f30
--- /dev/null
+++ b/third_party/rust/ron/src/parse.rs
@@ -0,0 +1,978 @@
+#![allow(clippy::identity_op)]
+
+use std::{
+ char::from_u32 as char_from_u32,
+ str::{from_utf8, from_utf8_unchecked, FromStr},
+};
+
+use crate::{
+ error::{Error, Position, Result, SpannedError, SpannedResult},
+ extensions::Extensions,
+};
+
+// 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
+}
+
+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).cloned() {
+ 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("") {
+ Ok(false)
+ } else if ident.is_empty() {
+ Err(Error::ExpectedStructLike)
+ } else if self.check_ident(ident) {
+ let _ = self.advance(ident.len());
+
+ Ok(true)
+ } else {
+ // If the following is not even an identifier, then a missing
+ // opening `(` seems more likely
+ let maybe_ident = self
+ .identifier()
+ .map_err(|_| Error::ExpectedNamedStructLike(ident))?;
+
+ let found = std::str::from_utf8(maybe_ident).map_err(Error::from)?;
+
+ Err(Error::ExpectedDifferentStructName {
+ expected: ident,
+ found: String::from(found),
+ })
+ }
+ }
+
+ 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) {
+ 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).cloned().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)
+ }
+ _ => self.next_bytes_contained_in(is_ident_other_char),
+ }
+ } else {
+ self.next_bytes_contained_in(is_ident_other_char)
+ };
+
+ 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().cloned()
+ }
+
+ pub fn peek_or_eof(&self) -> Result<u8> {
+ self.bytes.first().cloned().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..f723d15e09
--- /dev/null
+++ b/third_party/rust/ron/src/ser/mod.rs
@@ -0,0 +1,996 @@
+use serde::{ser, Deserialize, Serialize};
+use std::io;
+
+use crate::{
+ error::{Error, Result},
+ extensions::Extensions,
+ options::Options,
+ parse::{is_ident_first_char, is_ident_other_char, LargeSInt, LargeUInt},
+};
+
+#[cfg(test)]
+mod tests;
+mod value;
+
+/// Serializes `value` into `writer`
+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: [std::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: !0,
+ 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 the `pretty` module.
+pub struct Serializer<W: io::Write> {
+ output: W,
+ pretty: Option<(PrettyConfig, Pretty)>,
+ default_extensions: Extensions,
+ is_empty: Option<bool>,
+ newtype_variant: bool,
+}
+
+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,
+ })
+ }
+
+ 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) -> io::Result<()> {
+ let mut bytes = name.as_bytes().iter().cloned();
+ 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)
+ }
+}
+
+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::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(")?;
+ }
+ 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 value.serialize(&mut *self);
+ }
+
+ if self.struct_names() {
+ self.write_identifier(name)?;
+ }
+
+ self.output.write_all(b"(")?;
+ 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);
+
+ 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);
+ }
+
+ Ok(Compound {
+ ser: self,
+ state: State::First,
+ newtype_variant: 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()?;
+ }
+
+ Ok(Compound {
+ ser: self,
+ state: State::First,
+ newtype_variant: 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()?;
+ }
+
+ Ok(Compound {
+ ser: self,
+ state: State::First,
+ newtype_variant: 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()?;
+
+ Ok(Compound {
+ ser: self,
+ state: State::First,
+ newtype_variant: 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()?;
+
+ Ok(Compound {
+ ser: self,
+ state: State::First,
+ newtype_variant: 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()?;
+
+ Ok(Compound {
+ ser: self,
+ state: State::First,
+ newtype_variant: 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> 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;
+ }
+ }
+
+ 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()?;
+ }
+
+ 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()?;
+ 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())?;
+ }
+
+ 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())?;
+ }
+
+ 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..f1056e6575
--- /dev/null
+++ b/third_party/rust/ron/src/ser/tests.rs
@@ -0,0 +1,146 @@
+use super::to_string;
+use serde::Serialize;
+
+#[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..565bfa05e3
--- /dev/null
+++ b/third_party/rust/ron/src/value.rs
@@ -0,0 +1,553 @@
+//! 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, Deserialize, Serialize,
+};
+
+use crate::de::Error;
+use crate::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()
+ }
+}
+
+impl FromIterator<(Value, Value)> for Map {
+ fn from_iter<T: IntoIterator<Item = (Value, Value)>>(iter: T) -> Self {
+ Map(MapInner::from_iter(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 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 equals 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 equals 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 equals 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 equals 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` doesn't 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) => visitor.visit_map(MapAccessor {
+ keys: m.keys().cloned().rev().collect(),
+ values: m.values().cloned().rev().collect(),
+ }),
+ 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) => {
+ seq.reverse();
+ visitor.visit_seq(Seq { seq })
+ }
+ 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 {
+ keys: Vec<Value>,
+ values: Vec<Value>,
+}
+
+impl<'de> MapAccess<'de> for MapAccessor {
+ 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
+ self.keys
+ .pop()
+ .map_or(Ok(None), |v| seed.deserialize(v).map(Some))
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ // The `Vec` is reversed, so we can pop to get the originally first element
+ self.values
+ .pop()
+ .map(|v| seed.deserialize(v))
+ .expect("Contract violation")
+ }
+}
+
+struct Seq {
+ seq: Vec<Value>,
+}
+
+impl<'de> SeqAccess<'de> for Seq {
+ 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))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use serde::Deserialize;
+ use std::{collections::BTreeMap, fmt::Debug};
+
+ 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..3f82b08cd5
--- /dev/null
+++ b/third_party/rust/ron/tests/123_enum_representation.rs
@@ -0,0 +1,273 @@
+use ron::{de::from_str, ser::to_string};
+use serde::{Deserialize, Serialize};
+use std::{cmp::PartialEq, fmt::Debug};
+
+#[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..81cabf64fc
--- /dev/null
+++ b/third_party/rust/ron/tests/147_empty_sets_serialisation.rs
@@ -0,0 +1,62 @@
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+
+#[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..b51fd55102
--- /dev/null
+++ b/third_party/rust/ron/tests/152_bitflags.rs
@@ -0,0 +1,80 @@
+use bitflags::*;
+use option_set::option_set;
+
+#[macro_use]
+extern crate bitflags_serial;
+
+bitflags! {
+ #[derive(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;
+ }
+}
+
+bitflags_serial! {
+ struct TestBadTWO: 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, "{\"bits\":3}");
+ assert_eq!(ron_ser_good, "(bits:3)");
+
+ 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);
+
+ // bitflags_serial
+ let flag_bad_two = TestBadTWO::ONE | TestBadTWO::TWO;
+
+ let json_ser_bad_two = serde_json::ser::to_string(&flag_bad_two).unwrap();
+ let ron_ser_bad_two = ron::ser::to_string(&flag_bad_two).unwrap();
+
+ assert_eq!(json_ser_bad_two, "[\"ONE\",\"TWO\"]");
+ assert_eq!(ron_ser_bad_two, "[ONE,TWO]");
+
+ let json_de_bad_two: TestBadTWO = serde_json::de::from_str(json_ser_bad_two.as_str()).unwrap();
+ let ron_de_bad_two: TestBadTWO = ron::de::from_str(ron_ser_bad_two.as_str()).unwrap();
+
+ assert_eq!(json_de_bad_two, flag_bad_two);
+ assert_eq!(ron_de_bad_two, flag_bad_two);
+}
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..0ef486a179
--- /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)]
+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..46fda5c648
--- /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/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..f4c76606c6
--- /dev/null
+++ b/third_party/rust/ron/tests/250_variant_newtypes.rs
@@ -0,0 +1,407 @@
+use std::collections::HashMap;
+
+use ron::{
+ de::from_str, error::Error, extensions::Extensions, ser::to_string_pretty, ser::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/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..f57532bf67
--- /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: 39 },
+ })
+ );
+}
+
+#[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/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..6d197bde93
--- /dev/null
+++ b/third_party/rust/ron/tests/depth_limit.rs
@@ -0,0 +1,59 @@
+use serde::Serialize;
+use std::collections::HashMap;
+
+#[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..48f5fdaa1d
--- /dev/null
+++ b/third_party/rust/ron/tests/escape.rs
@@ -0,0 +1,77 @@
+use ron::{de::from_str, ser::to_string};
+use serde::{Deserialize, Serialize};
+use std::{char::from_u32, fmt::Debug};
+
+#[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..6161d90b43
--- /dev/null
+++ b/third_party/rust/ron/tests/extensions.rs
@@ -0,0 +1,91 @@
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+
+#[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/numbers.rs b/third_party/rust/ron/tests/numbers.rs
new file mode 100644
index 0000000000..4717ddb9f2
--- /dev/null
+++ b/third_party/rust/ron/tests/numbers.rs
@@ -0,0 +1,111 @@
+use ron::de::from_str;
+use ron::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..89a122af8a
--- /dev/null
+++ b/third_party/rust/ron/tests/options.rs
@@ -0,0 +1,53 @@
+use serde::{Deserialize, Serialize};
+
+use ron::{extensions::Extensions, ser::PrettyConfig, Options};
+
+#[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..8ffb20d86f
--- /dev/null
+++ b/third_party/rust/ron/tests/preserve_sequence.rs
@@ -0,0 +1,47 @@
+use ron::{
+ de::from_str,
+ ser::{to_string_pretty, PrettyConfig},
+};
+use serde::{Deserialize, Serialize};
+use std::collections::BTreeMap;
+
+#[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..7ca5bd8ad7
--- /dev/null
+++ b/third_party/rust/ron/tests/roundtrip.rs
@@ -0,0 +1,121 @@
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+
+use ron::extensions::Extensions;
+
+#[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..0e1f93d1aa
--- /dev/null
+++ b/third_party/rust/ron/tests/to_string_pretty.rs
@@ -0,0 +1,21 @@
+use ron::ser::{to_string_pretty, PrettyConfig};
+use ron::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..8256d3cf95
--- /dev/null
+++ b/third_party/rust/ron/tests/value.rs
@@ -0,0 +1,131 @@
+use ron::value::{Map, Number, Value};
+use serde::Serialize;
+use std::f64;
+
+#[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)));
+}
+
+#[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);
+}