summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ron
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/ron
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/ron')
-rw-r--r--third_party/rust/ron/.cargo-checksum.json1
-rw-r--r--third_party/rust/ron/CHANGELOG.md163
-rw-r--r--third_party/rust/ron/Cargo.lock130
-rw-r--r--third_party/rust/ron/Cargo.toml48
-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.md157
-rw-r--r--third_party/rust/ron/docs/extensions.md67
-rw-r--r--third_party/rust/ron/docs/grammar.md137
-rw-r--r--third_party/rust/ron/examples/decode.rs65
-rw-r--r--third_party/rust/ron/examples/decode_file.rs33
-rw-r--r--third_party/rust/ron/examples/encode.rs49
-rw-r--r--third_party/rust/ron/examples/example.ron17
-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.rs244
-rw-r--r--third_party/rust/ron/src/de/mod.rs685
-rw-r--r--third_party/rust/ron/src/de/tag.rs249
-rw-r--r--third_party/rust/ron/src/de/tests.rs328
-rw-r--r--third_party/rust/ron/src/de/value.rs335
-rw-r--r--third_party/rust/ron/src/error.rs164
-rw-r--r--third_party/rust/ron/src/extensions.rs26
-rw-r--r--third_party/rust/ron/src/lib.rs75
-rw-r--r--third_party/rust/ron/src/parse.rs932
-rw-r--r--third_party/rust/ron/src/ser/mod.rs1089
-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.rs69
-rw-r--r--third_party/rust/ron/tests/240_array_pretty.rs14
-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.rs67
-rw-r--r--third_party/rust/ron/tests/extensions.rs81
-rw-r--r--third_party/rust/ron/tests/floats.rs30
-rw-r--r--third_party/rust/ron/tests/large_number.rs14
-rw-r--r--third_party/rust/ron/tests/min_max.rs65
-rw-r--r--third_party/rust/ron/tests/numbers.rs22
-rw-r--r--third_party/rust/ron/tests/preserve_sequence.rs53
-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.rs35
-rw-r--r--third_party/rust/ron/tests/unicode.rs13
-rw-r--r--third_party/rust/ron/tests/value.rs111
49 files changed, 7175 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..9e516c882e
--- /dev/null
+++ b/third_party/rust/ron/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"0b74ab0c36ab2db7a8bfd566caf3c0f0f46c9177fbbad2aa682f8e34ec634f14","Cargo.lock":"7f2d751146ab17d12f4e414c3cb6fca2f0197ca08a02043e618b019e7fbf98cf","Cargo.toml":"d41f57286ebb4911e14eab98e7b08f168056eb320e9c526cc21633ff85da1485","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"fa0598d520497731445a5bc89a2b3d47896d95568bd2be255b7bc43d771b9994","README.md":"19222dfbca1e5d06df69058870b2a84fb94cdfd61ca67f0a28c4aedd02912522","docs/extensions.md":"b5013a854c1fd90fad40dbb37d35a50f1afc8eafe481133f6e36345091c4c3ef","docs/grammar.md":"9c0eaf92bd6221235e5a00e7a237242e8f44c7b0cb51268af4368a7bf9492043","examples/decode.rs":"ebf3348ce23c3b4cca04da745f8cabfd866b087982d459bb589b2f2f26be0d81","examples/decode_file.rs":"b52cc91894fe10ca5b964327ac5cc633a30da6f646846838a6d4c606369bffb5","examples/encode.rs":"3ec6c5fa1922e60aa1d8d6ec43d126e0340e13414344e4cb65b221ecc9bd5f9f","examples/example.ron":"c3355fcb6ee48f32da62ff56040dc69a69730c24f55e7744e235a28aa66a560e","examples/transcode.rs":"7a1e281684243b263d28f90f2836d6098239ae8ab2a0cb9d97ee0b7521ba960e","rustfmt.toml":"56a01ff6240c06eb9a198c938c72fe9cf49dd62a79cd693bb50d63dcb1a415eb","src/de/id.rs":"8cab9d75b2d0cb45c69cfd20b912b00c2c931ad08728f14c94f7f58fb8e6401d","src/de/mod.rs":"b10e28cd1bbe999f500a1df524564d2430eed8540ac8b815bea52680d330e601","src/de/tag.rs":"b84814358041c0784f0202d181bd2f8871df2024c1e461ffd874273f5e9192aa","src/de/tests.rs":"5b51663f518514374e533da1c3ad843b0109f1ded5ccf6c38193347916042205","src/de/value.rs":"a0f48ada281c650221ee6b075deaa386e19fedf6880b57e01d88c027e66c4117","src/error.rs":"30ffdb6aaa5849dcebb3bdc735f040cd265d17608555fc27bcf3f218c1e6fffa","src/extensions.rs":"b29a4459474809be25f4e5f5afce12ceb555e2c65b72e49186c910cd37d2034d","src/lib.rs":"0aadbf1267c29c6bc9b213326622693f6f8722d762136345d72e046d56fe4ae3","src/parse.rs":"5deb005ee297f28c466b2e6677d66e6dfa472fae9cecafba4d7171e385c23aa2","src/ser/mod.rs":"58225ac31bc67919423977fa4bb2d864236370c6fcc7cdd8819e8a69c33453fe","src/ser/value.rs":"0c099c6c3c73062048c989dc8f70c3e67cfd3989a286da79a45323830c4a277b","src/value.rs":"7a75e23932194e015bfe020f9187ae4c1307dd9c81f8759d6dac8841c7d5a23d","tests/117_untagged_tuple_variant.rs":"1ce8d384d84ff21a28dafef0f0ea4be9e6cbf9bd7c2ed4aa37e8d820c7b594b8","tests/123_enum_representation.rs":"aeae57321e4f674b8d469a59c4ea8d5c3c908ce89c9812de99936a6095d52739","tests/129_indexmap.rs":"49740c05c1ff66963e78dca8a0eb06e5fad69b67e395fd8f8c72162fda94ab40","tests/147_empty_sets_serialisation.rs":"525ec0846b221209c6a2e2cf3f2f31088cd231867af0bed7e2df43f3067be282","tests/240_array_pretty.rs":"a1ee6f8f9d145bb1d25e6206770f2c4a42e5447bc9680a1156b03d8138916908","tests/big_struct.rs":"9c7b41233ae7d0c4fec0727aabd4cea1cd95844c85c0beb5e688b3c79eb43c14","tests/borrowed_str.rs":"24390ee6076ce3896b7cf1b2e202cb3a705c61129a4f62f6c39a2412ca68405f","tests/comments.rs":"ec325babc23c0f2c248ea24935d7e0835e4c247d6f69283fcbc498233dd8d622","tests/depth_limit.rs":"bf69d82d36f84ff4643f22350fe7cd32f5497476f9b0f4a364c1e22cd87ecaa6","tests/escape.rs":"e53c92cd9ea1fbe115ffdbd8778939a481febc451cce7ab64a3dcb126df3a53b","tests/extensions.rs":"3978323185285a7bfb046402400a5ba70147d9c055a03f42e2d4be18d5568254","tests/floats.rs":"a5ff92bad76cff5e48257b0d656c953620e9b2b4c5ed7036b3d5c5d588346a4a","tests/large_number.rs":"951e97c64a234b90c0834161ea792c531a7097ade5f599cc6e6160120292488b","tests/min_max.rs":"701b5a156df7de69c02409832913d10b72cc1219b4393157c4af60c30ef7e6c2","tests/numbers.rs":"0ac1745b821fd08c759c5e665c00fecceb23077d41f9f237488989f8d89d32a5","tests/preserve_sequence.rs":"73fefa2e4bae31ff921b37589b999b6d11a23c2dd496c29ed8cde895a71ab501","tests/preserve_sequence_ex1.ron":"47bdf8da637b6e99701b5a4b8c100b4c9d45440c357aef8d368a406a05394ea9","tests/preserve_sequence_ex2.ron":"9ba759300324f8978469ce616f20eb0cfc134f0a8a1afff884fff5315b32e0d0","tests/roundtrip.rs":"861e558559e8ce71adb39817488fcad00212eca314adc4a3744cb1a95f3948ef","tests/struct_integers.rs":"cd33618d90fbf0dc082e050a7717f330978ab3858687a532961835d57014e295","tests/unicode.rs":"ac3944bf448f8cd5986bad5e7c4eca60302230c13378b213415dafc1d3ae2428","tests/value.rs":"eccef728d0ad3e06da5d0ab72e36d2ee4090e736732c4a9ae092ade55e18710c"},"package":"f8a58080b7bb83b2ea28c3b7a9a994fd5e310330b7c8ca5258d99b98128ecfe4"} \ 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..af31413848
--- /dev/null
+++ b/third_party/rust/ron/CHANGELOG.md
@@ -0,0 +1,163 @@
+# 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).
+
+## [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 \ No newline at end of file
diff --git a/third_party/rust/ron/Cargo.lock b/third_party/rust/ron/Cargo.lock
new file mode 100644
index 0000000000..de702bd60b
--- /dev/null
+++ b/third_party/rust/ron/Cargo.lock
@@ -0,0 +1,130 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "autocfg"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "base64"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "dtoa"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "indexmap"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ron"
+version = "0.6.2"
+dependencies = [
+ "base64 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_bytes 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+"checksum base64 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3"
+"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
+"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
+"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
+"checksum proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
+"checksum quote 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4c1f4b0efa5fc5e8ceb705136bfee52cfdb6a4e3509f770b478cd6ed434232a7"
+"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
+"checksum serde_bytes 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3bf487fbf5c6239d7ea2ff8b10cb6b811cd4b5080d1c2aeed1dec18753c06e10"
+"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
+"checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1"
+"checksum syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
diff --git a/third_party/rust/ron/Cargo.toml b/third_party/rust/ron/Cargo.toml
new file mode 100644
index 0000000000..a5092d0c54
--- /dev/null
+++ b/third_party/rust/ron/Cargo.toml
@@ -0,0 +1,48 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "ron"
+version = "0.6.2"
+authors = ["Christopher Durham <cad97@cad97.com>", "Dzmitry Malyshau <kvarkus@gmail.com>", "Thomas Schaller <torkleyy@gmail.com>"]
+exclude = ["bors.toml", ".travis.yml"]
+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/Apache-2.0"
+repository = "https://github.com/ron-rs/ron"
+
+[lib]
+name = "ron"
+[dependencies.base64]
+version = "0.12"
+
+[dependencies.bitflags]
+version = "1.0.4"
+
+[dependencies.indexmap]
+version = "1.0.2"
+features = ["serde-1"]
+optional = true
+
+[dependencies.serde]
+version = "1.0.60"
+features = ["serde_derive"]
+[dev-dependencies.serde_bytes]
+version = "0.11"
+
+[dev-dependencies.serde_json]
+version = "1"
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..26b3e60b02
--- /dev/null
+++ b/third_party/rust/ron/README.md
@@ -0,0 +1,157 @@
+# Rusty Object Notation
+
+[![Build Status](https://travis-ci.org/ron-rs/ron.svg?branch=master)](https://travis-ci.org/ron-rs/ron)
+[![Crates.io](https://img.shields.io/crates/v/ron.svg)](https://crates.io/crates/ron)
+[![Docs](https://docs.rs/ron/badge.svg)](https://docs.rs/ron)
+[![Gitter](https://badges.gitter.im/ron-rs/ron.svg)](https://gitter.im/ron-rs/ron)
+
+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
+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"
+ }
+ ]
+}
+```
+
+Notice these issues:
+ 1. Struct and maps are the same
+ - random order of exported fields
+ - annoying and inconvenient for reading
+ - doesn't work well with version control
+ - quoted field names
+ - too verbose
+ - no support for enums
+ 2. No trailing comma allowed
+ 3. No comments allowed
+
+### Same example in RON
+
+```rust
+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",
+ ),
+ ],
+)
+```
+
+The new format uses `(`..`)` brackets for *heterogeneous* structures (classes),
+while preserving the `{`..`}` for maps, and `[`..`]` for *homogeneous* structures (arrays).
+This distinction allows us to solve the biggest problem with JSON.
+
+Here are the general rules to parse the heterogeneous structures:
+
+| class is named? | fields are named? | what is it? | example |
+| --------------- | ------------------| ------------------------- | ------------------- |
+| no | no | tuple | `(a, b)` |
+| yes/no | no | tuple struct | `Name(a, b)` |
+| yes | no | enum value | `Variant(a, b)` |
+| yes/no | yes | struct | `(f1: a, f2: b,)` |
+
+### 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).
+
+### Appendix
+
+Why not XML?
+ - too verbose
+ - unclear how to treat attributes vs contents
+
+Why not YAML?
+ - significant white-space
+ - specification is too big
+
+Why not TOML?
+ - alien syntax
+ - absolute paths are not scalable
+
+Why not XXX?
+ - if you know a better format, tell me!
+
+## Tooling
+
+IntelliJ: https://vultix.github.io/intellij-ron-plugin/
+
+VS Code: https://github.com/a5huynh/vscode-ron
+
+Sublime Text: https://packagecontrol.io/packages/RON
+
+Atom: https://atom.io/packages/language-ron
+
+Vim: https://github.com/ron-rs/ron.vim
+
+## License
+
+RON is dual-licensed under Apache-2.0 and MIT.
+
diff --git a/third_party/rust/ron/docs/extensions.md b/third_party/rust/ron/docs/extensions.md
new file mode 100644
index 0000000000..ae648d778a
--- /dev/null
+++ b/third_party/rust/ron/docs/extensions.md
@@ -0,0 +1,67 @@
+## 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 struct 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,
+)
+```
diff --git a/third_party/rust/ron/docs/grammar.md b/third_party/rust/ron/docs/grammar.md
new file mode 100644
index 0000000000..be64b8ba35
--- /dev/null
+++ b/third_party/rust/ron/docs/grammar.md
@@ -0,0 +1,137 @@
+# 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 = float_std | float_frac;
+float_std = ["+" | "-"], digit, { digit }, ".", {digit}, [float_exp];
+float_frac = ".", digit, {digit}, [float_exp];
+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 = "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, "(", [named_field, { comma, named_field }, [comma]], ")";
+named_field = ident, 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..366f69b2ec
--- /dev/null
+++ b/third_party/rust/ron/examples/decode.rs
@@ -0,0 +1,65 @@
+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..cd88ffc5a0
--- /dev/null
+++ b/third_party/rust/ron/examples/decode_file.rs
@@ -0,0 +1,33 @@
+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),
+}
+
+#[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..3d3dc2533a
--- /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()
+ .with_depth_limit(2)
+ .with_separate_tuple_members(true)
+ .with_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..3ef0b4a06f
--- /dev/null
+++ b/third_party/rust/ron/examples/example.ron
@@ -0,0 +1,17 @@
+(
+ 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),
+) \ 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..b8d7d59f87
--- /dev/null
+++ b/third_party/rust/ron/src/de/id.rs
@@ -0,0 +1,244 @@
+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")
+ }
+
+ 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")
+ }
+
+ 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..8c01d42a98
--- /dev/null
+++ b/third_party/rust/ron/src/de/mod.rs
@@ -0,0 +1,685 @@
+/// Deserialization module.
+pub use crate::error::{Error, ErrorCode, Result};
+pub use crate::parse::Position;
+
+use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
+use std::{borrow::Cow, io, str};
+
+use self::{id::IdDeserializer, tag::TagDeserializer};
+use crate::{
+ extensions::Extensions,
+ 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>,
+}
+
+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) -> Result<Self> {
+ Deserializer::from_bytes(input.as_bytes())
+ }
+
+ pub fn from_bytes(input: &'de [u8]) -> Result<Self> {
+ Ok(Deserializer {
+ bytes: Bytes::new(input)?,
+ })
+ }
+
+ pub fn remainder(&self) -> Cow<'_, str> {
+ String::from_utf8_lossy(&self.bytes.bytes())
+ }
+}
+
+/// A convenience function for reading data from a reader
+/// and feeding into a deserializer.
+pub fn from_reader<R, T>(mut rdr: R) -> Result<T>
+where
+ R: io::Read,
+ T: de::DeserializeOwned,
+{
+ let mut bytes = Vec::new();
+ rdr.read_to_end(&mut bytes)?;
+
+ 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>(s: &'a str) -> Result<T>
+where
+ T: de::Deserialize<'a>,
+{
+ 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>(s: &'a [u8]) -> Result<T>
+where
+ T: de::Deserialize<'a>,
+{
+ let mut deserializer = Deserializer::from_bytes(s)?;
+ let t = T::deserialize(&mut deserializer)?;
+
+ deserializer.end()?;
+
+ Ok(t)
+}
+
+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 {
+ self.bytes.err(ErrorCode::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>,
+ {
+ 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),
+ AnyNum::I128(x) => visitor.visit_i128(x),
+ 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 => self.bytes.err(ErrorCode::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()?)
+ }
+
+ 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()?)
+ }
+
+ 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(ref s) => s,
+ };
+ base64::decode(base64_str)
+ };
+
+ match res {
+ Ok(byte_buf) => visitor.visit_byte_buf(byte_buf),
+ Err(err) => self.bytes.err(ErrorCode::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.exts.contains(Extensions::IMPLICIT_SOME) {
+ visitor.visit_some(&mut *self)
+ } 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 {
+ self.bytes.err(ErrorCode::ExpectedOptionEnd)
+ }
+ } else {
+ self.bytes.err(ErrorCode::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.bytes.consume("()") {
+ visitor.visit_unit()
+ } else {
+ self.bytes.err(ErrorCode::ExpectedUnit)
+ }
+ }
+
+ fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.bytes.consume(name) {
+ 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) {
+ return visitor.visit_newtype_struct(&mut *self);
+ }
+
+ self.bytes.consume(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 {
+ self.bytes.err(ErrorCode::ExpectedStructEnd)
+ }
+ } else {
+ self.bytes.err(ErrorCode::ExpectedStruct)
+ }
+ }
+
+ fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.bytes.consume("[") {
+ let value = visitor.visit_seq(CommaSeparated::new(b']', &mut self))?;
+ self.bytes.comma()?;
+
+ if self.bytes.consume("]") {
+ Ok(value)
+ } else {
+ self.bytes.err(ErrorCode::ExpectedArrayEnd)
+ }
+ } else {
+ self.bytes.err(ErrorCode::ExpectedArray)
+ }
+ }
+
+ fn deserialize_tuple<V>(mut self, _len: usize, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.bytes.consume("(") {
+ let value = visitor.visit_seq(CommaSeparated::new(b')', &mut self))?;
+ self.bytes.comma()?;
+
+ if self.bytes.consume(")") {
+ Ok(value)
+ } else {
+ self.bytes.err(ErrorCode::ExpectedArrayEnd)
+ }
+ } else {
+ self.bytes.err(ErrorCode::ExpectedArray)
+ }
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ name: &'static str,
+ len: usize,
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.bytes.consume(name);
+ self.deserialize_tuple(len, visitor)
+ }
+
+ fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ if self.bytes.consume("{") {
+ let value = visitor.visit_map(CommaSeparated::new(b'}', &mut self))?;
+ self.bytes.comma()?;
+
+ if self.bytes.consume("}") {
+ Ok(value)
+ } else {
+ self.bytes.err(ErrorCode::ExpectedMapEnd)
+ }
+ } else {
+ self.bytes.err(ErrorCode::ExpectedMap)
+ }
+ }
+
+ fn deserialize_struct<V>(
+ mut self,
+ name: &'static str,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.bytes.consume(name);
+
+ self.bytes.skip_ws()?;
+
+ if self.bytes.consume("(") {
+ let value = visitor.visit_map(CommaSeparated::new(b')', &mut self))?;
+ self.bytes.comma()?;
+
+ if self.bytes.consume(")") {
+ Ok(value)
+ } else {
+ self.bytes.err(ErrorCode::ExpectedStructEnd)
+ }
+ } else {
+ self.bytes.err(ErrorCode::ExpectedStruct)
+ }
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _name: &'static str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_enum(Enum::new(self))
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_str(
+ str::from_utf8(self.bytes.identifier()?).map_err(|e| self.bytes.error(e.into()))?,
+ )
+ }
+
+ 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 err<T>(&self, kind: ErrorCode) -> Result<T> {
+ self.de.bytes.err(kind)
+ }
+
+ fn has_element(&mut self) -> Result<bool> {
+ self.de.bytes.skip_ws()?;
+
+ Ok(self.had_comma && self.de.bytes.peek_or_eof()? != self.terminator)
+ }
+}
+
+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 {
+ self.err(ErrorCode::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>,
+ {
+ self.de.bytes.skip_ws()?;
+
+ if self.de.bytes.consume("(") {
+ self.de.bytes.skip_ws()?;
+
+ let val = seed.deserialize(&mut *self.de)?;
+
+ self.de.bytes.comma()?;
+
+ if self.de.bytes.consume(")") {
+ Ok(val)
+ } else {
+ self.de.bytes.err(ErrorCode::ExpectedStructEnd)
+ }
+ } else {
+ self.de.bytes.err(ErrorCode::ExpectedStruct)
+ }
+ }
+
+ 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>,
+ {
+ self.de.bytes.skip_ws()?;
+
+ self.de.deserialize_struct("", fields, visitor)
+ }
+}
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..76a8bb7973
--- /dev/null
+++ b/third_party/rust/ron/src/de/tag.rs
@@ -0,0 +1,249 @@
+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)
+ }
+
+ 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)
+ }
+
+ 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..f74b87b658
--- /dev/null
+++ b/third_party/rust/ron/src/de/tests.rs
@@ -0,0 +1,328 @@
+use serde::Deserialize;
+use serde_bytes;
+
+use super::*;
+
+#[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: ErrorCode, line: usize, col: usize) -> Result<T> {
+ Err(Error {
+ code: kind,
+ position: Position { line, col },
+ })
+}
+
+#[test]
+fn test_err_wrong_value() {
+ use self::ErrorCode::*;
+ 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(ExpectedArray, 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(ExpectedStruct, 1, 1));
+ assert_eq!(from_str::<(u8, bool)>("'c'"), err(ExpectedArray, 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 forgot_apostrophes() {
+ let de: Result<(i32, String)> = from_str("(4, \"Hello)");
+
+ assert!(match de {
+ Err(Error {
+ code: ErrorCode::ExpectedStringEnd,
+ position: _,
+ }) => true,
+ _ => false,
+ });
+}
+
+#[test]
+fn expected_attribute() {
+ let de: Result<String> = from_str("#\"Hello\"");
+
+ assert_eq!(de, err(ErrorCode::ExpectedAttribute, 1, 2));
+}
+
+#[test]
+fn expected_attribute_end() {
+ let de: Result<String> = from_str("#![enable(unwrap_newtypes) \"Hello\"");
+
+ assert_eq!(de, err(ErrorCode::ExpectedAttributeEnd, 1, 28));
+}
+
+#[test]
+fn invalid_attribute() {
+ let de: Result<String> = from_str("#![enable(invalid)] \"Hello\"");
+
+ assert_eq!(
+ de,
+ err(ErrorCode::NoSuchExtension("invalid".to_string()), 1, 18)
+ );
+}
+
+#[test]
+fn multiple_attributes() {
+ #[derive(Debug, Deserialize, PartialEq)]
+ struct New(String);
+ let de: Result<New> =
+ from_str("#![enable(unwrap_newtypes)] #![enable(unwrap_newtypes)] \"Hello\"");
+
+ assert_eq!(de, Ok(New("Hello".to_owned())));
+}
+
+#[test]
+fn uglified_attribute() {
+ let de: Result<()> = 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..92acca2068
--- /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::{
+ de,
+ value::{Map, Number, Value},
+};
+
+impl std::str::FromStr for Value {
+ type Err = de::Error;
+
+ /// Creates a value from a string reference.
+ fn from_str(s: &str) -> de::Result<Self> {
+ let mut de = super::Deserializer::from_str(s)?;
+
+ let val = Value::deserialize(&mut de)?;
+ de.end()?;
+
+ 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)))
+ }
+
+ 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)))
+ }
+
+ 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, ErrorCode, Position};
+
+ assert_eq!(
+ Value::from_str("Foo:").unwrap_err(),
+ Error {
+ code: ErrorCode::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..2a5052159a
--- /dev/null
+++ b/third_party/rust/ron/src/error.rs
@@ -0,0 +1,164 @@
+use serde::{de, ser};
+use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
+
+pub use crate::parse::Position;
+
+/// This type represents all possible errors that can occur when
+/// serializing or deserializing RON data.
+#[derive(Clone, Debug, PartialEq)]
+pub struct Error {
+ pub code: ErrorCode,
+ pub position: Position,
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum ErrorCode {
+ Io(String),
+ Message(String),
+ Base64Error(base64::DecodeError),
+ Eof,
+ ExpectedArray,
+ ExpectedArrayEnd,
+ ExpectedAttribute,
+ ExpectedAttributeEnd,
+ ExpectedBoolean,
+ ExpectedComma,
+ // ExpectedEnum,
+ ExpectedChar,
+ ExpectedFloat,
+ ExpectedInteger,
+ ExpectedOption,
+ ExpectedOptionEnd,
+ ExpectedMap,
+ ExpectedMapColon,
+ ExpectedMapEnd,
+ ExpectedStruct,
+ ExpectedStructEnd,
+ ExpectedUnit,
+ // ExpectedStructName,
+ ExpectedString,
+ ExpectedStringEnd,
+ ExpectedIdentifier,
+
+ InvalidEscape(&'static str),
+
+ IntegerOutOfBounds,
+
+ NoSuchExtension(String),
+
+ UnclosedBlockComment,
+ UnderscoreAtBeginning,
+ UnexpectedByte(char),
+
+ Utf8Error(Utf8Error),
+ TrailingCharacters,
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+}
+
+impl fmt::Display for Error {
+ 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 ErrorCode {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ ErrorCode::Io(ref s) => f.write_str(s),
+ ErrorCode::Message(ref s) => f.write_str(s),
+ ErrorCode::Base64Error(ref e) => fmt::Display::fmt(e, f),
+ ErrorCode::Eof => f.write_str("Unexpected end of file"),
+ ErrorCode::ExpectedArray => f.write_str("Expected array"),
+ ErrorCode::ExpectedArrayEnd => f.write_str("Expected end of array"),
+ ErrorCode::ExpectedAttribute => f.write_str("Expected an enable attribute"),
+ ErrorCode::ExpectedAttributeEnd => {
+ f.write_str("Expected closing `)` and `]` after the attribute")
+ }
+ ErrorCode::ExpectedBoolean => f.write_str("Expected boolean"),
+ ErrorCode::ExpectedComma => f.write_str("Expected comma"),
+ // ErrorCode::ExpectedEnum => f.write_str("Expected enum"),
+ ErrorCode::ExpectedChar => f.write_str("Expected char"),
+ ErrorCode::ExpectedFloat => f.write_str("Expected float"),
+ ErrorCode::ExpectedInteger => f.write_str("Expected integer"),
+ ErrorCode::ExpectedOption => f.write_str("Expected option"),
+ ErrorCode::ExpectedOptionEnd => f.write_str("Expected end of option"),
+ ErrorCode::ExpectedMap => f.write_str("Expected map"),
+ ErrorCode::ExpectedMapColon => f.write_str("Expected colon"),
+ ErrorCode::ExpectedMapEnd => f.write_str("Expected end of map"),
+ ErrorCode::ExpectedStruct => f.write_str("Expected struct"),
+ ErrorCode::ExpectedStructEnd => f.write_str("Expected end of struct"),
+ ErrorCode::ExpectedUnit => f.write_str("Expected unit"),
+ // ErrorCode::ExpectedStructName => f.write_str("Expected struct name"),
+ ErrorCode::ExpectedString => f.write_str("Expected string"),
+ ErrorCode::ExpectedStringEnd => f.write_str("Expected string end"),
+ ErrorCode::ExpectedIdentifier => f.write_str("Expected identifier"),
+ ErrorCode::InvalidEscape(_) => f.write_str("Invalid escape sequence"),
+ ErrorCode::IntegerOutOfBounds => f.write_str("Integer is out of bounds"),
+ ErrorCode::NoSuchExtension(_) => f.write_str("No such RON extension"),
+ ErrorCode::Utf8Error(ref e) => fmt::Display::fmt(e, f),
+ ErrorCode::UnclosedBlockComment => f.write_str("Unclosed block comment"),
+ ErrorCode::UnderscoreAtBeginning => f.write_str("Found underscore at the beginning"),
+ ErrorCode::UnexpectedByte(_) => f.write_str("Unexpected byte"),
+ ErrorCode::TrailingCharacters => f.write_str("Non-whitespace trailing characters"),
+ _ => f.write_str("Unknown ErrorCode"),
+ }
+ }
+}
+
+impl de::Error for Error {
+ fn custom<T: fmt::Display>(msg: T) -> Self {
+ Error {
+ code: ErrorCode::Message(msg.to_string()),
+ position: Position { line: 0, col: 0 },
+ }
+ }
+}
+
+impl ser::Error for Error {
+ fn custom<T: fmt::Display>(msg: T) -> Self {
+ Error {
+ code: ErrorCode::Message(msg.to_string()),
+ position: Position { line: 0, col: 0 },
+ }
+ }
+}
+
+impl StdError for Error {}
+
+impl From<Utf8Error> for ErrorCode {
+ fn from(e: Utf8Error) -> Self {
+ ErrorCode::Utf8Error(e)
+ }
+}
+
+impl From<FromUtf8Error> for ErrorCode {
+ fn from(e: FromUtf8Error) -> Self {
+ ErrorCode::Utf8Error(e.utf8_error())
+ }
+}
+
+impl From<Utf8Error> for Error {
+ fn from(e: Utf8Error) -> Self {
+ Error {
+ code: ErrorCode::Utf8Error(e),
+ position: Position { line: 0, col: 0 },
+ }
+ }
+}
+
+impl From<io::Error> for Error {
+ fn from(e: io::Error) -> Self {
+ Error {
+ code: ErrorCode::Io(e.to_string()),
+ position: Position { line: 0, col: 0 },
+ }
+ }
+}
diff --git a/third_party/rust/ron/src/extensions.rs b/third_party/rust/ron/src/extensions.rs
new file mode 100644
index 0000000000..5f3906c67d
--- /dev/null
+++ b/third_party/rust/ron/src/extensions.rs
@@ -0,0 +1,26 @@
+use serde::{Deserialize, Serialize};
+
+bitflags::bitflags! {
+ #[derive(Serialize, Deserialize)]
+ pub struct Extensions: usize {
+ const UNWRAP_NEWTYPES = 0x1;
+ const IMPLICIT_SOME = 0x2;
+ }
+}
+
+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),
+ _ => 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..d9bf34ae5a
--- /dev/null
+++ b/third_party/rust/ron/src/lib.rs
@@ -0,0 +1,75 @@
+/*!
+RON is a simple config format which looks similar to Rust syntax.
+
+## Features
+
+* Data types
+ * Structs, typename optional
+ * Tuples
+ * Enums
+ * Lists
+ * Maps
+ * Units (`()`)
+ * Optionals
+ * Primitives: booleans, numbers, string, char
+* Allows nested layout (similar to JSON)
+* Supports comments
+* Trailing commas
+* Pretty serialization
+
+## Syntax example
+
+```rust,ignore
+Game(
+ title: "Hello, RON!",
+ level: Level( // We could just leave the `Level` out
+ buildings: [
+ (
+ size: (10, 20),
+ color: Yellow, // This as an enum variant
+ owner: None,
+ ),
+ (
+ size: (20, 25),
+ color: Custom(0.1, 0.8, 1.0),
+ owner: Some("guy"),
+ ),
+ ],
+ characters: {
+ "guy": (
+ friendly: true,
+ ),
+ },
+ ),
+)
+```
+
+## Usage
+
+Just add it to your `Cargo.toml`:
+
+```toml
+[dependencies]
+ron = "*"
+```
+
+Serializing / Deserializing is as simple as calling `to_string` / `from_str`.
+
+!*/
+
+#![doc(html_root_url = "https://docs.rs/ron/0.6.0")]
+
+pub mod de;
+pub mod ser;
+
+pub mod error;
+pub mod value;
+
+pub mod extensions;
+
+pub use de::{from_str, Deserializer};
+pub use error::{Error, Result};
+pub use ser::{to_string, Serializer};
+pub use value::{Map, Number, Value};
+
+mod parse;
diff --git a/third_party/rust/ron/src/parse.rs b/third_party/rust/ron/src/parse.rs
new file mode 100644
index 0000000000..d592e44942
--- /dev/null
+++ b/third_party/rust/ron/src/parse.rs
@@ -0,0 +1,932 @@
+use std::{
+ char::from_u32 as char_from_u32,
+ fmt::{Display, Formatter, Result as FmtResult},
+ str::{from_utf8, from_utf8_unchecked, FromStr},
+};
+
+use crate::{
+ error::{Error, ErrorCode, Result},
+ 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 WHITESPACE_CHAR: u8 = 1 << 4; // [\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; // [0-9]
+const ABCDF: u8 = INT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [ABCDFabcdf]
+const UNDER: u8 = INT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [_]
+const E____: u8 = INT_CHAR | FLOAT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [Ee]
+const G2Z__: u8 = IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [G-Zg-z]
+const PUNCT: u8 = FLOAT_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
+}
+
+const fn is_ident_first_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & IDENT_FIRST_CHAR != 0
+}
+
+const fn is_ident_other_char(c: u8) -> bool {
+ ENCODINGS[c as usize] & IDENT_OTHER_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),
+ I128(i128),
+ U128(u128),
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct Bytes<'a> {
+ /// Bits set according to `Extension` enum.
+ pub exts: Extensions,
+ bytes: &'a [u8],
+ column: usize,
+ line: usize,
+}
+
+impl<'a> Bytes<'a> {
+ pub fn new(bytes: &'a [u8]) -> Result<Self> {
+ let mut b = Bytes {
+ bytes,
+ column: 1,
+ exts: Extensions::empty(),
+ line: 1,
+ };
+
+ b.skip_ws()?;
+ // Loop over all extensions attributes
+ loop {
+ let attribute = b.extensions()?;
+
+ if attribute.is_empty() {
+ break;
+ }
+
+ b.exts |= attribute;
+ b.skip_ws()?;
+ }
+
+ Ok(b)
+ }
+
+ 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.line += 1;
+ self.column = 1;
+ } else {
+ self.column += 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 self.err(ErrorCode::ExpectedInteger);
+ }
+
+ let s = unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) };
+
+ if s.as_bytes()[0] == b'_' {
+ return self.err(ErrorCode::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 bytes.err(ErrorCode::IntegerOutOfBounds);
+ }
+
+ let digit = bytes.decode_hex(byte)?;
+
+ if digit >= base {
+ return bytes.err(ErrorCode::ExpectedInteger);
+ }
+
+ if f(&mut num_acc, digit) {
+ return bytes.err(ErrorCode::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 == f as f32 as f64 {
+ 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 = std::u8::MAX as u128;
+ let max_u16 = std::u16::MAX as u128;
+ let max_u32 = std::u32::MAX as u128;
+ let max_u64 = std::u64::MAX as u128;
+
+ let min_i8 = std::i8::MIN as i128;
+ let max_i8 = std::i8::MAX as i128;
+ let min_i16 = std::i16::MIN as i128;
+ let max_i16 = std::i16::MAX as i128;
+ let min_i32 = std::i32::MIN as i128;
+ let max_i32 = std::i32::MAX as i128;
+ let min_i64 = std::i64::MIN as i128;
+ let max_i64 = std::i64::MAX as i128;
+
+ if is_signed {
+ match self.signed_integer::<i128>() {
+ 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 {
+ Ok(AnyNum::I128(x))
+ }
+ }
+ Err(_) => {
+ self.bytes = bytes_backup;
+
+ any_float(self.float::<f64>()?)
+ }
+ }
+ } else {
+ match self.unsigned_integer::<u128>() {
+ 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 {
+ Ok(AnyNum::U128(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 {
+ self.err(ErrorCode::ExpectedBoolean)
+ }
+ }
+
+ pub fn bytes(&self) -> &[u8] {
+ &self.bytes
+ }
+
+ pub fn char(&mut self) -> Result<char> {
+ if !self.consume("'") {
+ return self.err(ErrorCode::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_else(|| self.error(ErrorCode::ExpectedChar))?;
+ let s = from_utf8(&self.bytes[0..pos]).map_err(|e| self.error(e.into()))?;
+ let mut chars = s.chars();
+
+ let first = chars
+ .next()
+ .ok_or_else(|| self.error(ErrorCode::ExpectedChar))?;
+ if chars.next().is_some() {
+ return self.err(ErrorCode::ExpectedChar);
+ }
+
+ let _ = self.advance(pos);
+
+ first
+ };
+
+ if !self.consume("'") {
+ return self.err(ErrorCode::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(&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 err<T>(&self, kind: ErrorCode) -> Result<T> {
+ Err(self.error(kind))
+ }
+
+ pub fn error(&self, kind: ErrorCode) -> Error {
+ Error {
+ code: kind,
+ position: Position {
+ line: self.line,
+ col: self.column,
+ },
+ }
+ }
+
+ pub fn expect_byte(&mut self, byte: u8, error: ErrorCode) -> Result<()> {
+ self.eat_byte()
+ .and_then(|b| if b == byte { Ok(()) } else { self.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 self.err(ErrorCode::ExpectedAttribute);
+ }
+
+ self.skip_ws()?;
+ let mut extensions = Extensions::empty();
+
+ loop {
+ let ident = self.identifier()?;
+ let extension = Extensions::from_ident(ident).ok_or_else(|| {
+ self.error(ErrorCode::NoSuchExtension(
+ from_utf8(ident).unwrap().to_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 self.err(ErrorCode::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(self.error(ErrorCode::ExpectedAttributeEnd))
+ }
+ }
+
+ pub fn float<T>(&mut self) -> Result<T>
+ where
+ T: FromStr,
+ {
+ for literal in &["inf", "-inf", "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);
+
+ let s = unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) };
+ let res = FromStr::from_str(s).map_err(|_| self.error(ErrorCode::ExpectedFloat));
+
+ let _ = self.advance(num_bytes);
+
+ res
+ }
+
+ pub fn identifier(&mut self) -> Result<&'a [u8]> {
+ let bytes = self.identifier_len()?;
+ let ident = &self.bytes[..bytes];
+ let _ = self.advance(bytes);
+
+ Ok(ident)
+ }
+
+ pub fn identifier_len(&self) -> Result<usize> {
+ let next = self.peek_or_eof()?;
+ if is_ident_first_char(next) {
+ // If the next two bytes signify the start of a raw string literal,
+ // return an error.
+ if next == b'r' {
+ let second = self
+ .bytes
+ .get(1)
+ .ok_or_else(|| self.error(ErrorCode::Eof))?;
+ if *second == b'"' || *second == b'#' {
+ return self.err(ErrorCode::ExpectedIdentifier);
+ }
+ }
+
+ let bytes = self.next_bytes_contained_in(is_ident_other_char);
+
+ Ok(bytes)
+ } else {
+ self.err(ErrorCode::ExpectedIdentifier)
+ }
+ }
+
+ 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<()> {
+ while self.peek().map_or(false, |c| is_whitespace_char(c)) {
+ let _ = self.advance_single();
+ }
+
+ if self.skip_comment()? {
+ self.skip_ws()?;
+ }
+
+ Ok(())
+ }
+
+ pub fn peek(&self) -> Option<u8> {
+ self.bytes.get(0).cloned()
+ }
+
+ pub fn peek_or_eof(&self) -> Result<u8> {
+ self.bytes
+ .get(0)
+ .cloned()
+ .ok_or_else(|| self.error(ErrorCode::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 {
+ self.err(ErrorCode::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_else(|| self.error(ErrorCode::ExpectedStringEnd))?;
+
+ if *end_or_escape == b'"' {
+ let s = from_utf8(&self.bytes[..i]).map_err(|e| self.error(e.into()))?;
+
+ // 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(ErrorCode::Eof)
+ .map_err(|e| self.error(e))?;
+
+ 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(|e| self.error(e.into()))?;
+ 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 self.err(ErrorCode::ExpectedString);
+ }
+
+ let ending = [&[b'"'], hashes].concat();
+ let i = self
+ .bytes
+ .windows(num_hashes + 1)
+ .position(|window| window == ending.as_slice())
+ .ok_or_else(|| self.error(ErrorCode::ExpectedStringEnd))?;
+
+ let s = from_utf8(&self.bytes[..i]).map_err(|e| self.error(e.into()))?;
+
+ // 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'),
+ _ => self.err(ErrorCode::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'x' => self.decode_ascii_escape()? as char,
+ b'u' => {
+ self.expect_byte(b'{', ErrorCode::InvalidEscape("Missing {"))?;
+
+ 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 |= byte as u32;
+
+ num_digits += 1;
+ }
+
+ if num_digits == 0 {
+ return self.err(ErrorCode::InvalidEscape(
+ "Expected 1-6 digits, got 0 digits",
+ ));
+ }
+
+ self.expect_byte(b'}', ErrorCode::InvalidEscape("No } at the end"))?;
+ char_from_u32(bytes)
+ .ok_or_else(|| self.error(ErrorCode::InvalidEscape("Not a valid char")))?
+ }
+ _ => {
+ return self.err(ErrorCode::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 self.err(ErrorCode::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(|_| self.error(ErrorCode::UnclosedBlockComment))?;
+ }
+ }
+ }
+ b => return self.err(ErrorCode::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); )*
+ };
+}
+
+impl_num!(u8 u16 u32 u64 u128 i8 i16 i32 i64 i128);
+
+#[derive(Clone, Debug)]
+pub enum ParsedStr<'a> {
+ Allocated(String),
+ Slice(&'a str),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Position {
+ pub line: usize,
+ pub col: usize,
+}
+
+impl Display for Position {
+ fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
+ write!(f, "{}:{}", self.line, self.col)
+ }
+}
+
+#[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..ca1cea3dad
--- /dev/null
+++ b/third_party/rust/ron/src/ser/mod.rs
@@ -0,0 +1,1089 @@
+use serde::{ser, Deserialize, Serialize};
+use std::io;
+
+use crate::error::{Error, Result};
+use crate::extensions::Extensions;
+
+mod value;
+
+/// Serializes `value` into `writer`
+pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()>
+where
+ W: io::Write,
+ T: Serialize,
+{
+ let mut s = Serializer::new(writer, None, false)?;
+ value.serialize(&mut s)
+}
+
+/// 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: Serialize,
+{
+ let mut s = Serializer::new(writer, Some(config), false)?;
+ 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>(value: &T) -> Result<String>
+where
+ T: Serialize,
+{
+ let buf = Vec::new();
+ let mut s = Serializer::new(buf, None, false)?;
+ value.serialize(&mut s)?;
+ Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
+}
+
+/// 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: Serialize,
+{
+ let buf = Vec::new();
+ let mut s = Serializer::new(buf, Some(config), false)?;
+ value.serialize(&mut s)?;
+ Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
+}
+
+/// Pretty serializer state
+struct Pretty {
+ indent: usize,
+ sequence_index: Vec<usize>,
+}
+
+/// Pretty serializer configuration.
+///
+/// # Examples
+///
+/// ```
+/// use ron::ser::PrettyConfig;
+///
+/// let my_config = PrettyConfig::new()
+/// .with_depth_limit(4)
+/// // definitely superior (okay, just joking)
+/// .with_indentor("\t".to_owned());
+/// ```
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct PrettyConfig {
+ /// Limit the pretty-ness up to the given depth.
+ #[serde(default = "default_depth_limit")]
+ pub depth_limit: usize,
+ /// New line string
+ #[serde(default = "default_new_line")]
+ pub new_line: String,
+ /// Indentation string
+ #[serde(default = "default_indentor")]
+ pub indentor: String,
+ /// Separate tuple members with indentation
+ #[serde(default = "default_separate_tuple_members")]
+ pub separate_tuple_members: bool,
+ /// Enumerate array items in comments
+ #[serde(default = "default_enumerate_arrays")]
+ pub enumerate_arrays: bool,
+ /// Always include the decimal in floats
+ #[serde(default = "default_decimal_floats")]
+ pub decimal_floats: bool,
+ /// Enable extensions. Only configures 'implicit_some' for now.
+ pub extensions: Extensions,
+ /// Private field to ensure adding a field is non-breaking.
+ #[serde(skip)]
+ _future_proof: (),
+}
+
+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 with_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 with_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 with_indentor(mut self, indentor: String) -> Self {
+ self.indentor = indentor;
+
+ 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 with_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 with_enumerate_arrays(mut self, enumerate_arrays: bool) -> Self {
+ self.enumerate_arrays = enumerate_arrays;
+
+ self
+ }
+
+ /// Configures whether floats should always include a decimal.
+ /// When false `1.0` will serialize as `1`
+ /// When true `1.0` will serialize as `1.0`
+ ///
+ /// Default: `false`
+ pub fn with_decimal_floats(mut self, decimal_floats: bool) -> Self {
+ self.decimal_floats = decimal_floats;
+
+ self
+ }
+
+ /// Configures extensions
+ ///
+ /// Default: Extensions::empty()
+ pub fn with_extensions(mut self, extensions: Extensions) -> Self {
+ self.extensions = extensions;
+
+ self
+ }
+}
+
+fn default_depth_limit() -> usize {
+ !0
+}
+
+fn default_new_line() -> String {
+ #[cfg(not(target_os = "windows"))]
+ let new_line = "\n".to_string();
+ #[cfg(target_os = "windows")]
+ let new_line = "\r\n".to_string();
+
+ new_line
+}
+
+fn default_decimal_floats() -> bool {
+ false
+}
+
+fn default_indentor() -> String {
+ " ".to_string()
+}
+
+fn default_separate_tuple_members() -> bool {
+ false
+}
+
+fn default_enumerate_arrays() -> bool {
+ false
+}
+
+impl Default for PrettyConfig {
+ fn default() -> Self {
+ PrettyConfig {
+ depth_limit: default_depth_limit(),
+ new_line: default_new_line(),
+ indentor: default_indentor(),
+ separate_tuple_members: default_separate_tuple_members(),
+ enumerate_arrays: default_enumerate_arrays(),
+ extensions: Extensions::default(),
+ decimal_floats: default_decimal_floats(),
+ _future_proof: (),
+ }
+ }
+}
+
+/// 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)>,
+ struct_names: bool,
+ is_empty: Option<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(mut writer: W, config: Option<PrettyConfig>, struct_names: bool) -> Result<Self> {
+ if let Some(conf) = &config {
+ if conf.extensions.contains(Extensions::IMPLICIT_SOME) {
+ writer.write_all(b"#![enable(implicit_some)]")?;
+ writer.write_all(conf.new_line.as_bytes())?;
+ };
+ };
+ Ok(Serializer {
+ output: writer,
+ pretty: config.map(|conf| {
+ (
+ conf,
+ Pretty {
+ indent: 0,
+ sequence_index: Vec::new(),
+ },
+ )
+ }),
+ struct_names,
+ is_empty: None,
+ })
+ }
+
+ fn is_pretty(&self) -> bool {
+ match self.pretty {
+ Some((ref config, ref pretty)) => pretty.indent <= config.depth_limit,
+ None => false,
+ }
+ }
+
+ fn separate_tuple_members(&self) -> bool {
+ self.pretty
+ .as_ref()
+ .map_or(false, |&(ref config, _)| config.separate_tuple_members)
+ }
+
+ fn decimal_floats(&self) -> bool {
+ self.pretty
+ .as_ref()
+ .map_or(false, |&(ref config, _)| config.decimal_floats)
+ }
+
+ fn extensions(&self) -> 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(())
+ }
+}
+
+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_i128(v as i128)
+ }
+
+ fn serialize_i16(self, v: i16) -> Result<()> {
+ self.serialize_i128(v as i128)
+ }
+
+ fn serialize_i32(self, v: i32) -> Result<()> {
+ self.serialize_i128(v as i128)
+ }
+
+ fn serialize_i64(self, v: i64) -> Result<()> {
+ self.serialize_i128(v as i128)
+ }
+
+ fn serialize_i128(self, v: i128) -> Result<()> {
+ // TODO optimize
+ write!(self.output, "{}", v)?;
+ Ok(())
+ }
+
+ fn serialize_u8(self, v: u8) -> Result<()> {
+ self.serialize_u128(v as u128)
+ }
+
+ fn serialize_u16(self, v: u16) -> Result<()> {
+ self.serialize_u128(v as u128)
+ }
+
+ fn serialize_u32(self, v: u32) -> Result<()> {
+ self.serialize_u128(v as u128)
+ }
+
+ fn serialize_u64(self, v: u64) -> Result<()> {
+ self.serialize_u128(v as u128)
+ }
+
+ fn serialize_u128(self, v: u128) -> Result<()> {
+ write!(self.output, "{}", v)?;
+ Ok(())
+ }
+
+ fn serialize_f32(self, v: f32) -> Result<()> {
+ write!(self.output, "{}", v)?;
+ // TODO: use f32::EPSILON when minimum supported rust version is 1.43
+ pub const EPSILON: f32 = 1.19209290e-07_f32;
+ if self.decimal_floats() && (v - v.floor()).abs() < EPSILON {
+ write!(self.output, ".0")?;
+ }
+ Ok(())
+ }
+
+ fn serialize_f64(self, v: f64) -> Result<()> {
+ write!(self.output, "{}", v)?;
+ // TODO: use f64::EPSILON when minimum supported rust version is 1.43
+ pub const EPSILON: f64 = 2.2204460492503131e-16_f64;
+ if self.decimal_floats() && (v - v.floor()).abs() < EPSILON {
+ 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<()> {
+ self.output.write_all(b"()")?;
+
+ Ok(())
+ }
+
+ fn serialize_unit_struct(self, name: &'static str) -> Result<()> {
+ if self.struct_names {
+ self.output.write_all(name.as_bytes())?;
+
+ Ok(())
+ } else {
+ self.serialize_unit()
+ }
+ }
+
+ fn serialize_unit_variant(self, _: &'static str, _: u32, variant: &'static str) -> Result<()> {
+ self.output.write_all(variant.as_bytes())?;
+
+ Ok(())
+ }
+
+ fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if self.struct_names {
+ self.output.write_all(name.as_bytes())?;
+ }
+
+ 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.output.write_all(variant.as_bytes())?;
+ self.output.write_all(b"(")?;
+
+ value.serialize(&mut *self)?;
+
+ self.output.write_all(b")")?;
+ Ok(())
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
+ self.output.write_all(b"[")?;
+
+ if let Some(len) = len {
+ self.is_empty = Some(len == 0);
+ }
+
+ self.start_indent()?;
+
+ if let Some((_, ref mut pretty)) = self.pretty {
+ pretty.sequence_index.push(0);
+ }
+
+ Ok(Compound::Map {
+ ser: self,
+ state: State::First,
+ })
+ }
+
+ fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
+ self.output.write_all(b"(")?;
+
+ if self.separate_tuple_members() {
+ self.is_empty = Some(len == 0);
+
+ self.start_indent()?;
+ }
+
+ Ok(Compound::Map {
+ ser: self,
+ state: State::First,
+ })
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ name: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleStruct> {
+ if self.struct_names {
+ self.output.write_all(name.as_bytes())?;
+ }
+
+ self.serialize_tuple(len)
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _: &'static str,
+ _: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleVariant> {
+ self.output.write_all(variant.as_bytes())?;
+ self.output.write_all(b"(")?;
+
+ if self.separate_tuple_members() {
+ self.is_empty = Some(len == 0);
+
+ self.start_indent()?;
+ }
+
+ Ok(Compound::Map {
+ ser: self,
+ state: State::First,
+ })
+ }
+
+ fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
+ self.output.write_all(b"{")?;
+
+ if let Some(len) = len {
+ self.is_empty = Some(len == 0);
+ }
+
+ self.start_indent()?;
+
+ Ok(Compound::Map {
+ ser: self,
+ state: State::First,
+ })
+ }
+
+ fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
+ if self.struct_names {
+ self.output.write_all(name.as_bytes())?;
+ }
+ self.output.write_all(b"(")?;
+
+ self.is_empty = Some(len == 0);
+ self.start_indent()?;
+
+ Ok(Compound::Map {
+ ser: self,
+ state: State::First,
+ })
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _: &'static str,
+ _: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeStructVariant> {
+ self.output.write_all(variant.as_bytes())?;
+ self.output.write_all(b"(")?;
+
+ self.is_empty = Some(len == 0);
+ self.start_indent()?;
+
+ Ok(Compound::Map {
+ ser: self,
+ state: State::First,
+ })
+ }
+}
+
+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,
+ {
+ let ser = match self {
+ Compound::Map {
+ state: ref mut s @ State::First,
+ ser,
+ } => {
+ *s = State::Rest;
+ ser
+ }
+ Compound::Map {
+ state: State::Rest,
+ ser,
+ } => {
+ ser.output.write_all(b",")?;
+ if let Some((ref config, ref mut pretty)) = ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ if config.enumerate_arrays {
+ assert!(config.new_line.contains('\n'));
+ let index = pretty.sequence_index.last_mut().unwrap();
+ //TODO: when /**/ comments are supported, prepend the index
+ // to an element instead of appending it.
+ write!(ser.output, "// [{}]", index).unwrap();
+ *index += 1;
+ }
+ ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ ser
+ }
+ };
+ ser.indent()?;
+
+ value.serialize(&mut **ser)?;
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ let ser = match self {
+ Compound::Map {
+ ser,
+ state: State::Rest,
+ } => {
+ if let Some((ref config, ref mut pretty)) = ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ ser.output.write_all(b",")?;
+ ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ ser
+ }
+ Compound::Map { ser, .. } => ser,
+ };
+ ser.end_indent()?;
+
+ if let Some((_, ref mut pretty)) = ser.pretty {
+ pretty.sequence_index.pop();
+ }
+
+ ser.output.write_all(b"]")?;
+ Ok(())
+ }
+}
+pub enum State {
+ First,
+ Rest,
+}
+pub enum Compound<'a, W: io::Write> {
+ Map {
+ ser: &'a mut Serializer<W>,
+ state: State,
+ },
+}
+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,
+ {
+ let ser = match self {
+ Compound::Map {
+ ser,
+ state: ref mut s @ State::First,
+ } => {
+ *s = State::Rest;
+ ser
+ }
+ Compound::Map { ser, .. } => {
+ ser.output.write_all(b",")?;
+ if let Some((ref config, ref pretty)) = ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ ser.output.write_all(if ser.separate_tuple_members() {
+ config.new_line.as_bytes()
+ } else {
+ b" "
+ })?;
+ }
+ }
+ ser
+ }
+ };
+
+ if ser.separate_tuple_members() {
+ ser.indent()?;
+ }
+
+ value.serialize(&mut **ser)?;
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ let ser = match self {
+ Compound::Map {
+ ser,
+ state: State::Rest,
+ } => {
+ if let Some((ref config, ref pretty)) = ser.pretty {
+ if ser.separate_tuple_members() && pretty.indent <= config.depth_limit {
+ ser.output.write_all(b",")?;
+ ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ ser
+ }
+ Compound::Map { ser, .. } => ser,
+ };
+ if ser.separate_tuple_members() {
+ ser.end_indent()?;
+ }
+
+ 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,
+ {
+ let ser = match self {
+ Compound::Map {
+ ser,
+ state: ref mut s @ State::First,
+ } => {
+ *s = State::Rest;
+ ser
+ }
+ Compound::Map {
+ ser,
+ state: State::Rest,
+ } => {
+ ser.output.write_all(b",")?;
+
+ if let Some((ref config, ref pretty)) = ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ ser
+ }
+ };
+ ser.indent()?;
+ key.serialize(&mut **ser)
+ }
+
+ fn serialize_value<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ match self {
+ Compound::Map { ser, .. } => {
+ ser.output.write_all(b":")?;
+
+ if ser.is_pretty() {
+ ser.output.write_all(b" ")?;
+ }
+
+ value.serialize(&mut **ser)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ let ser = match self {
+ Compound::Map {
+ ser,
+ state: State::Rest,
+ } => {
+ if let Some((ref config, ref pretty)) = ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ ser.output.write_all(b",")?;
+ ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+
+ ser
+ }
+ Compound::Map { ser, .. } => ser,
+ };
+ ser.end_indent()?;
+ 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,
+ {
+ let ser = match self {
+ Compound::Map {
+ ser,
+ state: ref mut s @ State::First,
+ } => {
+ *s = State::Rest;
+ ser
+ }
+ Compound::Map { ser, .. } => {
+ ser.output.write_all(b",")?;
+
+ if let Some((ref config, ref pretty)) = ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ ser
+ }
+ };
+ ser.indent()?;
+ ser.output.write_all(key.as_bytes())?;
+ ser.output.write_all(b":")?;
+
+ if ser.is_pretty() {
+ ser.output.write_all(b" ")?;
+ }
+
+ value.serialize(&mut **ser)?;
+
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ let ser = match self {
+ Compound::Map {
+ ser,
+ state: State::Rest,
+ } => {
+ if let Some((ref config, ref pretty)) = ser.pretty {
+ if pretty.indent <= config.depth_limit {
+ ser.output.write_all(b",")?;
+ ser.output.write_all(config.new_line.as_bytes())?;
+ }
+ }
+ ser
+ }
+ Compound::Map { ser, .. } => ser,
+ };
+ ser.end_indent()?;
+ 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)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[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,y:7)");
+
+ #[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,5)");
+ }
+
+ #[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_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==\""
+ )
+ );
+ }
+}
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..e5387df022
--- /dev/null
+++ b/third_party/rust/ron/src/value.rs
@@ -0,0 +1,553 @@
+//! Value module.
+
+use serde::{
+ de::{
+ DeserializeOwned, DeserializeSeed, Deserializer, Error as SerdeError, MapAccess, SeqAccess,
+ Visitor,
+ },
+ forward_to_deserialize_any, Deserialize, Serialize,
+};
+use std::{
+ cmp::{Eq, Ordering},
+ hash::{Hash, Hasher},
+ iter::FromIterator,
+ ops::{Index, IndexMut},
+};
+
+use crate::de::{Error as RonError, 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)]
+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) -> usize {
+ self.0.len()
+ }
+
+ /// 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(i as i64)
+ }
+}
+
+// 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 as i64 as u64 == i {
+ 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 as u64);
+ }
+}
+
+/// 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 = RonError;
+
+ 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(RonError::custom(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(RonError::custom(format!("Expected a number, got {:?}", v))),
+ }
+ }
+}
+
+struct MapAccessor {
+ keys: Vec<Value>,
+ values: Vec<Value>,
+}
+
+impl<'de> MapAccess<'de> for MapAccessor {
+ type Error = RonError;
+
+ 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 = RonError;
+
+ 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..a10a11e27e
--- /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().skip(1).next().unwrap(),
+ Value::String("shell command".to_string())
+ );
+ }
+ _ => panic!(),
+ },
+ _ => panic!(),
+ }
+
+ 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().skip(1).next().unwrap(),
+ Value::String("debug message".to_string())
+ );
+ }
+ _ => panic!(),
+ },
+ _ => panic!(),
+ }
+}
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..827ed8e498
--- /dev/null
+++ b/third_party/rust/ron/tests/147_empty_sets_serialisation.rs
@@ -0,0 +1,69 @@
+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>,
+ deep_vec: HashMap<Key, Vec<()>>,
+ deep_map: HashMap<Key, HashMap<Key, Enum>>,
+}
+
+#[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()
+ .with_enumerate_arrays(true)
+ .with_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/240_array_pretty.rs b/third_party/rust/ron/tests/240_array_pretty.rs
new file mode 100644
index 0000000000..957be1572c
--- /dev/null
+++ b/third_party/rust/ron/tests/240_array_pretty.rs
@@ -0,0 +1,14 @@
+use ron::ser::{to_string_pretty, PrettyConfig};
+
+#[test]
+fn small_array() {
+ let arr = &[(), (), ()][..];
+ assert_eq!(
+ to_string_pretty(&arr, PrettyConfig::new().with_new_line("\n".to_string())).unwrap(),
+ "[
+ (),
+ (),
+ (),
+]"
+ );
+}
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..f5d6f73c12
--- /dev/null
+++ b/third_party/rust/ron/tests/comments.rs
@@ -0,0 +1,52 @@
+use ron::de::{from_str, Error as RonErr, ErrorCode, Position};
+
+#[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: ErrorCode::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..5c74f28299
--- /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()
+ .with_depth_limit(1)
+ .with_separate_tuple_members(true)
+ .with_enumerate_arrays(true)
+ .with_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..20cc87ee1e
--- /dev/null
+++ b/third_party/rust/ron/tests/escape.rs
@@ -0,0 +1,67 @@
+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");
+}
+
+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() {
+ check_same("Hello\0World!".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..81157257ab
--- /dev/null
+++ b/third_party/rust/ron/tests/extensions.rs
@@ -0,0 +1,81 @@
+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);
+}
+
+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..e19726b1ba
--- /dev/null
+++ b/third_party/rust/ron/tests/floats.rs
@@ -0,0 +1,30 @@
+use ron::{
+ de::from_str,
+ ser::{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 pretty = PrettyConfig::new().with_decimal_floats(false);
+ let without_decimal = to_string_pretty(&1.0, pretty).unwrap();
+ assert_eq!(without_decimal, "1");
+
+ let pretty = PrettyConfig::new().with_decimal_floats(false);
+ let without_decimal = to_string_pretty(&1.1, pretty).unwrap();
+ assert_eq!(without_decimal, "1.1");
+
+ let pretty = PrettyConfig::new().with_decimal_floats(true);
+ let with_decimal = to_string_pretty(&1.0, pretty).unwrap();
+ assert_eq!(with_decimal, "1.0");
+
+ let pretty = PrettyConfig::new().with_decimal_floats(true);
+ let with_decimal = to_string_pretty(&1.1, pretty).unwrap();
+ assert_eq!(with_decimal, "1.1");
+}
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..4e8b5e4b47
--- /dev/null
+++ b/third_party/rust/ron/tests/large_number.rs
@@ -0,0 +1,14 @@
+use ron::value::Number;
+
+#[test]
+fn test_large_number() {
+ use ron::value::Value;
+ 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))
+ );
+}
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..f53bcb2cf3
--- /dev/null
+++ b/third_party/rust/ron/tests/min_max.rs
@@ -0,0 +1,65 @@
+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()
+ );
+}
+
+#[test]
+fn test_i128_min() {
+ assert_eq!(
+ std::i128::MIN,
+ from_str(&to_string(&std::i128::MIN).unwrap()).unwrap()
+ );
+}
+
+#[test]
+fn test_i128_max() {
+ assert_eq!(
+ std::i128::MAX,
+ from_str(&to_string(&std::i128::MAX).unwrap()).unwrap()
+ );
+}
+
+#[test]
+fn test_u128_min() {
+ assert_eq!(
+ std::u128::MIN,
+ from_str(&to_string(&std::u128::MIN).unwrap()).unwrap()
+ );
+}
+
+#[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..26b97a53de
--- /dev/null
+++ b/third_party/rust/ron/tests/numbers.rs
@@ -0,0 +1,22 @@
+use ron::de::from_str;
+
+#[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));
+}
+
+#[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));
+}
+
+#[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));
+}
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..db34a1d397
--- /dev/null
+++ b/third_party/rust/ron/tests/preserve_sequence.rs
@@ -0,0 +1,53 @@
+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 = match from_str(source) {
+ Ok(x) => x,
+ Err(e) => {
+ println!("Failed to load config: {}", e);
+ std::process::exit(1);
+ }
+ };
+ let pretty = PrettyConfig::new()
+ .with_depth_limit(3)
+ .with_separate_tuple_members(true)
+ .with_enumerate_arrays(true)
+ .with_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..08022f0fbe
--- /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()
+ .with_enumerate_arrays(true)
+ .with_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, 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().with_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..c7f80a0a5a
--- /dev/null
+++ b/third_party/rust/ron/tests/struct_integers.rs
@@ -0,0 +1,35 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct S {
+ a: i8,
+ b: i16,
+ c: i32,
+ d: i64,
+ e: i128,
+ f: u8,
+ g: u16,
+ h: u32,
+ i: u64,
+ j: u128,
+}
+
+#[test]
+fn roundtrip() {
+ let s = S {
+ a: std::i8::MIN,
+ b: std::i16::MIN,
+ c: std::i32::MIN,
+ d: std::i64::MIN,
+ e: std::i128::MIN,
+ f: std::u8::MAX,
+ g: std::u16::MAX,
+ h: std::u32::MAX,
+ i: std::u64::MAX,
+ 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/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..1e1ff5b991
--- /dev/null
+++ b/third_party/rust/ron/tests/value.rs
@@ -0,0 +1,111 @@
+use ron::value::{Map, Number, Value};
+use serde::Serialize;
+
+#[test]
+fn bool() {
+ assert_eq!("true".parse(), Ok(Value::Bool(true)));
+ assert_eq!("false".parse(), Ok(Value::Bool(false)));
+}
+
+#[test]
+fn char() {
+ assert_eq!("'a'".parse(), Ok(Value::Char('a')));
+}
+
+#[test]
+fn map() {
+ let mut map = Map::new();
+ map.insert(Value::Char('a'), Value::Number(Number::new(1)));
+ map.insert(Value::Char('b'), Value::Number(Number::new(2f64)));
+ assert_eq!("{ 'a': 1, 'b': 2.0 }".parse(), Ok(Value::Map(map)));
+}
+
+#[test]
+fn number() {
+ assert_eq!("42".parse(), Ok(Value::Number(Number::new(42))));
+ assert_eq!("3.1415".parse(), Ok(Value::Number(Number::new(3.1415f64))));
+}
+
+#[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, ErrorCode, Position};
+
+ assert_eq!("()".parse(), Ok(Value::Unit));
+ assert_eq!("Foo".parse(), Ok(Value::Unit));
+
+ assert_eq!(
+ "".parse::<Value>(),
+ Err(Error {
+ code: ErrorCode::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);
+ }
+}