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