зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1664105 - Upgrade `ron` to 0.6.2. r=kvark
Differential Revision: https://phabricator.services.mozilla.com/D89698
This commit is contained in:
Родитель
0b80ebcbcb
Коммит
cc286890ec
|
@ -4184,11 +4184,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.5.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
|
||||
checksum = "f8a58080b7bb83b2ea28c3b7a9a994fd5e310330b7c8ca5258d99b98128ecfe4"
|
||||
dependencies = [
|
||||
"base64 0.10.1",
|
||||
"base64 0.12.0",
|
||||
"bitflags",
|
||||
"serde",
|
||||
]
|
||||
|
|
|
@ -78,12 +78,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
|||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.10.1"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "battery"
|
||||
|
@ -1022,9 +1019,9 @@ checksum = "60d4a9058849c3e765fe2fa68b72c1416b1766f27eac3c52d7bac8712ea0d390"
|
|||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.5.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
|
||||
checksum = "f8a58080b7bb83b2ea28c3b7a9a994fd5e310330b7c8ca5258d99b98128ecfe4"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitflags",
|
||||
|
|
|
@ -19,7 +19,7 @@ env_logger = "0.7"
|
|||
log = "0.4"
|
||||
raw-window-handle = "0.3"
|
||||
renderdoc = { version = "0.8", optional = true, default_features = false }
|
||||
ron = "0.5"
|
||||
ron = "0.6.2"
|
||||
winit = { version = "0.22", optional = true }
|
||||
|
||||
[dependencies.wgt]
|
||||
|
|
|
@ -34,7 +34,7 @@ gfx-memory = "0.1"
|
|||
parking_lot = "0.10"
|
||||
peek-poke = "0.2"
|
||||
raw-window-handle = { version = "0.3", optional = true }
|
||||
ron = { version = "0.5", optional = true }
|
||||
ron = { version = "0.6.2", optional = true }
|
||||
serde = { version = "1.0", features = ["serde_derive"], optional = true }
|
||||
smallvec = "1"
|
||||
spirv_headers = { version = "1.4.2" }
|
||||
|
|
|
@ -99,6 +99,11 @@ dependencies = [
|
|||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "binary-space-partition"
|
||||
version = "0.1.2"
|
||||
|
@ -1368,10 +1373,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.5.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1628,7 +1633,7 @@ name = "tileview"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ron 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender 0.61.0",
|
||||
"webrender_api 0.61.0",
|
||||
|
@ -1822,7 +1827,7 @@ dependencies = [
|
|||
"png 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ron 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2062,6 +2067,7 @@ dependencies = [
|
|||
"checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
||||
"checksum backtrace-sys 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
|
||||
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||
"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
"checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
|
||||
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
@ -2206,7 +2212,7 @@ dependencies = [
|
|||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
||||
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||
"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
|
||||
"checksum ron 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8a58080b7bb83b2ea28c3b7a9a994fd5e310330b7c8ca5258d99b98128ecfe4"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum rusttype 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5"
|
||||
|
|
|
@ -8,7 +8,7 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
ron = "0.5"
|
||||
ron = "0.6.2"
|
||||
serde = {version = "1.0.88", features = ["derive"] }
|
||||
webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler","no_static_freetype", "leak_checks"]}
|
||||
webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]}
|
||||
|
|
|
@ -43,7 +43,7 @@ num-traits = "0.2"
|
|||
plane-split = "0.17"
|
||||
png = { optional = true, version = "0.16" }
|
||||
rayon = "1"
|
||||
ron = { optional = true, version = "0.5" }
|
||||
ron = { optional = true, version = "0.6.2" }
|
||||
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
|
||||
serde_json = { optional = true, version = "1.0" }
|
||||
smallvec = "1"
|
||||
|
|
|
@ -42,11 +42,9 @@ impl CaptureConfig {
|
|||
frame_id: 0,
|
||||
resource_id: 0,
|
||||
#[cfg(feature = "capture")]
|
||||
pretty: ron::ser::PrettyConfig {
|
||||
enumerate_arrays: true,
|
||||
indentor: " ".to_string(),
|
||||
.. ron::ser::PrettyConfig::default()
|
||||
},
|
||||
pretty: ron::ser::PrettyConfig::new()
|
||||
.with_enumerate_arrays(true)
|
||||
.with_indentor(" ".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"cbff1b8a1ed9f2757045ddfa291ca54050f528caeb28af00275232b73f635ac7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"fa0598d520497731445a5bc89a2b3d47896d95568bd2be255b7bc43d771b9994","README.md":"64b6f569099a35c13f6028d01ac9b9c314b2aa4a40f0309de7e8e580f90754cb","docs/extensions.md":"b5013a854c1fd90fad40dbb37d35a50f1afc8eafe481133f6e36345091c4c3ef","docs/grammar.md":"e7dbfeae7cc705bd7df5f5132675da7703ba412a64b806b12df15ff50cfb35b3","examples/decode.rs":"ebf3348ce23c3b4cca04da745f8cabfd866b087982d459bb589b2f2f26be0d81","examples/decode_file.rs":"b52cc91894fe10ca5b964327ac5cc633a30da6f646846838a6d4c606369bffb5","examples/encode.rs":"8a7c225036bdd3b9e5ccc1668d608990d0b7b830ebcdf03aadea43cd0dffd67b","examples/example.ron":"c3355fcb6ee48f32da62ff56040dc69a69730c24f55e7744e235a28aa66a560e","examples/transcode.rs":"a01ebe61331fcd1935f5c7885b7825e9155053466ace35f81338c628ea1af2ec","rustfmt.toml":"4f90eed39c472a472c46a9e1273f2e77de3071ba674af7fe57a9e29b6b9bb0c2","src/de/error.rs":"f4581524eaa808ea1307a38cca2dfd0c268953d4c6ab296cd776de057f350345","src/de/id.rs":"4deb0d0c5ad83ca7b287a87b76d19247e43228e85698dd5efb6f7c168433aa79","src/de/mod.rs":"cb435e23590b7bba3394d7592dc8e3749297da64bec90f2cdaf6f6dadc2f0393","src/de/tests.rs":"ac17dcd0573b23fe883d3210bda0550f8d4a7d92fd83611ed72c10e1a5b038b9","src/de/value.rs":"80d32104ea7b4370aa0b4bc8fe9f4ad671886b28ceea37d84a75183f225cc800","src/lib.rs":"39a260e4c97d6b305c1c93c27a12569db4533dc6087981400555c3649630ebb6","src/parse.rs":"f35ef5b3328da6cb836fac6222046c865bc20a11a806944a61af1659b467af76","src/ser/mod.rs":"4cda213bb6163c91b3a3cd7fc1dcfa69d34dff6776ede93bc426533ada2de355","src/ser/value.rs":"4ce34d4b405d6279a24500db0bda4b8b2978dc5aaeb4a34d100a5ee41af7bf05","src/value.rs":"d36369ee4907b1ceda9f4117a78d56a2109357e6b16c8acec989511df60b63e6","tests/147_empty_sets_serialisation.rs":"8e9e71b879d6fe834c110c79939db0a010e75eedb4d117a2147adb6b5136faf5","tests/big_struct.rs":"9c7b41233ae7d0c4fec0727aabd4cea1cd95844c85c0beb5e688b3c79eb43c14","tests/comments.rs":"fff605e703449f211f737e36fb33d6f56f2213d18fec85ca72aea5b3032a287e","tests/depth_limit.rs":"ddf6a45137c78dc283d052556b5b719045f40bffe6f4a454f25de13ef8da6f81","tests/escape.rs":"e53c92cd9ea1fbe115ffdbd8778939a481febc451cce7ab64a3dcb126df3a53b","tests/extensions.rs":"3978323185285a7bfb046402400a5ba70147d9c055a03f42e2d4be18d5568254","tests/numbers.rs":"0ac1745b821fd08c759c5e665c00fecceb23077d41f9f237488989f8d89d32a5","tests/roundtrip.rs":"4267fb6286d3c866d2b3fc16bd67da8a740f709bf685e5cc0d06913007d15dda","tests/unicode.rs":"ac3944bf448f8cd5986bad5e7c4eca60302230c13378b213415dafc1d3ae2428","tests/value.rs":"aec359fc3786e3e150a87ede2ec2fd3185602fe469da9c0598ba443517245fd3"},"package":"2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"}
|
||||
{"files":{"CHANGELOG.md":"0b74ab0c36ab2db7a8bfd566caf3c0f0f46c9177fbbad2aa682f8e34ec634f14","Cargo.lock":"7f2d751146ab17d12f4e414c3cb6fca2f0197ca08a02043e618b019e7fbf98cf","Cargo.toml":"d41f57286ebb4911e14eab98e7b08f168056eb320e9c526cc21633ff85da1485","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"fa0598d520497731445a5bc89a2b3d47896d95568bd2be255b7bc43d771b9994","README.md":"19222dfbca1e5d06df69058870b2a84fb94cdfd61ca67f0a28c4aedd02912522","docs/extensions.md":"b5013a854c1fd90fad40dbb37d35a50f1afc8eafe481133f6e36345091c4c3ef","docs/grammar.md":"9c0eaf92bd6221235e5a00e7a237242e8f44c7b0cb51268af4368a7bf9492043","examples/decode.rs":"ebf3348ce23c3b4cca04da745f8cabfd866b087982d459bb589b2f2f26be0d81","examples/decode_file.rs":"b52cc91894fe10ca5b964327ac5cc633a30da6f646846838a6d4c606369bffb5","examples/encode.rs":"3ec6c5fa1922e60aa1d8d6ec43d126e0340e13414344e4cb65b221ecc9bd5f9f","examples/example.ron":"c3355fcb6ee48f32da62ff56040dc69a69730c24f55e7744e235a28aa66a560e","examples/transcode.rs":"7a1e281684243b263d28f90f2836d6098239ae8ab2a0cb9d97ee0b7521ba960e","rustfmt.toml":"56a01ff6240c06eb9a198c938c72fe9cf49dd62a79cd693bb50d63dcb1a415eb","src/de/id.rs":"8cab9d75b2d0cb45c69cfd20b912b00c2c931ad08728f14c94f7f58fb8e6401d","src/de/mod.rs":"b10e28cd1bbe999f500a1df524564d2430eed8540ac8b815bea52680d330e601","src/de/tag.rs":"b84814358041c0784f0202d181bd2f8871df2024c1e461ffd874273f5e9192aa","src/de/tests.rs":"5b51663f518514374e533da1c3ad843b0109f1ded5ccf6c38193347916042205","src/de/value.rs":"a0f48ada281c650221ee6b075deaa386e19fedf6880b57e01d88c027e66c4117","src/error.rs":"30ffdb6aaa5849dcebb3bdc735f040cd265d17608555fc27bcf3f218c1e6fffa","src/extensions.rs":"b29a4459474809be25f4e5f5afce12ceb555e2c65b72e49186c910cd37d2034d","src/lib.rs":"0aadbf1267c29c6bc9b213326622693f6f8722d762136345d72e046d56fe4ae3","src/parse.rs":"5deb005ee297f28c466b2e6677d66e6dfa472fae9cecafba4d7171e385c23aa2","src/ser/mod.rs":"58225ac31bc67919423977fa4bb2d864236370c6fcc7cdd8819e8a69c33453fe","src/ser/value.rs":"0c099c6c3c73062048c989dc8f70c3e67cfd3989a286da79a45323830c4a277b","src/value.rs":"7a75e23932194e015bfe020f9187ae4c1307dd9c81f8759d6dac8841c7d5a23d","tests/117_untagged_tuple_variant.rs":"1ce8d384d84ff21a28dafef0f0ea4be9e6cbf9bd7c2ed4aa37e8d820c7b594b8","tests/123_enum_representation.rs":"aeae57321e4f674b8d469a59c4ea8d5c3c908ce89c9812de99936a6095d52739","tests/129_indexmap.rs":"49740c05c1ff66963e78dca8a0eb06e5fad69b67e395fd8f8c72162fda94ab40","tests/147_empty_sets_serialisation.rs":"525ec0846b221209c6a2e2cf3f2f31088cd231867af0bed7e2df43f3067be282","tests/240_array_pretty.rs":"a1ee6f8f9d145bb1d25e6206770f2c4a42e5447bc9680a1156b03d8138916908","tests/big_struct.rs":"9c7b41233ae7d0c4fec0727aabd4cea1cd95844c85c0beb5e688b3c79eb43c14","tests/borrowed_str.rs":"24390ee6076ce3896b7cf1b2e202cb3a705c61129a4f62f6c39a2412ca68405f","tests/comments.rs":"ec325babc23c0f2c248ea24935d7e0835e4c247d6f69283fcbc498233dd8d622","tests/depth_limit.rs":"bf69d82d36f84ff4643f22350fe7cd32f5497476f9b0f4a364c1e22cd87ecaa6","tests/escape.rs":"e53c92cd9ea1fbe115ffdbd8778939a481febc451cce7ab64a3dcb126df3a53b","tests/extensions.rs":"3978323185285a7bfb046402400a5ba70147d9c055a03f42e2d4be18d5568254","tests/floats.rs":"a5ff92bad76cff5e48257b0d656c953620e9b2b4c5ed7036b3d5c5d588346a4a","tests/large_number.rs":"951e97c64a234b90c0834161ea792c531a7097ade5f599cc6e6160120292488b","tests/min_max.rs":"701b5a156df7de69c02409832913d10b72cc1219b4393157c4af60c30ef7e6c2","tests/numbers.rs":"0ac1745b821fd08c759c5e665c00fecceb23077d41f9f237488989f8d89d32a5","tests/preserve_sequence.rs":"73fefa2e4bae31ff921b37589b999b6d11a23c2dd496c29ed8cde895a71ab501","tests/preserve_sequence_ex1.ron":"47bdf8da637b6e99701b5a4b8c100b4c9d45440c357aef8d368a406a05394ea9","tests/preserve_sequence_ex2.ron":"9ba759300324f8978469ce616f20eb0cfc134f0a8a1afff884fff5315b32e0d0","tests/roundtrip.rs":"861e558559e8ce71adb39817488fcad00212eca314adc4a3744cb1a95f3948ef","tests/struct_integers.rs":"cd33618d90fbf0dc082e050a7717f330978ab3858687a532961835d57014e295","tests/unicode.rs":"ac3944bf448f8cd5986bad5e7c4eca60302230c13378b213415dafc1d3ae2428","tests/value.rs":"eccef728d0ad3e06da5d0ab72e36d2ee4090e736732c4a9ae092ade55e18710c"},"package":"f8a58080b7bb83b2ea28c3b7a9a994fd5e310330b7c8ca5258d99b98128ecfe4"}
|
|
@ -0,0 +1,163 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.6.2] - 2020-09-09
|
||||
- Added `decimal_floats` PrettyConfig option, which always includes decimals in floats (`1.0` vs `1`) ([#237](https://github.com/ron-rs/ron/pull/237))
|
||||
- Fixed EBNF grammar for raw strings ([#236](https://github.com/ron-rs/ron/pull/236), unsigned integers ([#248](https://github.com/ron-rs/ron/pull/248)), and nested comments ([#272](https://github.com/ron-rs/ron/pull/272))
|
||||
- Added `ser::to_writer_pretty` ([#269](https://github.com/ron-rs/ron/pull/269))
|
||||
- Sped up parsing using table predicates ([#276](https://github.com/ron-rs/ron/pull/276))
|
||||
|
||||
## [0.6.1] - 2020-07-14
|
||||
|
||||
### Fixes
|
||||
- Fix array formatting regression ([#260](https://github.com/ron-rs/ron/pull/260))
|
||||
|
||||
## [0.6.0] - 2020-05-21
|
||||
### Additions
|
||||
- Implement integer support in Numbers ([#210](https://github.com/ron-rs/ron/pull/210))
|
||||
- Port `ser::Serializer` to `io::Write` ([#206](https://github.com/ron-rs/ron/pull/206))
|
||||
- Support i128 and u128 ([#219](https://github.com/ron-rs/ron/pull/219))
|
||||
- Allow pretty ser to work with implicit-some extension ([#182](https://github.com/ron-rs/ron/pull/182))
|
||||
- Make PrettyConfig future-proof ([#173](https://github.com/ron-rs/ron/pull/173))
|
||||
- Use indexmap to preserve order (optional) ([#172](https://github.com/ron-rs/ron/pull/172))
|
||||
- Add tests for different enum representations ([#166](https://github.com/ron-rs/ron/pull/166))
|
||||
- Implement inf, -inf and NaN handling ([#163](https://github.com/ron-rs/ron/pull/163))
|
||||
- Add VS code language tooling ([#160](https://github.com/ron-rs/ron/pull/160))
|
||||
- Be smarter about integer deserialization ([#157](https://github.com/ron-rs/ron/pull/157))
|
||||
|
||||
### Fixes
|
||||
- Fix parsing of borrowed strings ([#228](https://github.com/ron-rs/ron/pull/228))
|
||||
- Fix depth limit test for off-by-one fix ([#225](https://github.com/ron-rs/ron/pull/225))
|
||||
- Remove deprecated uses of `Error::description` ([#208](https://github.com/ron-rs/ron/pull/208))
|
||||
- Preserve ordering of map sequences ([#197](https://github.com/ron-rs/ron/pull/197))
|
||||
- Remove unneeded Neg requirement for signed_integer ([#193](https://github.com/ron-rs/ron/pull/193))
|
||||
- Ensure "Untagged tuple-like enum variants not deserializing correctly……" is fixed ([#170](https://github.com/ron-rs/ron/pull/170))
|
||||
|
||||
### Changes
|
||||
- Update `serde` requirement to 1.0.60 ([#226](https://github.com/ron-rs/ron/pull/226))
|
||||
- Replace Travis with GitHub actions ([#223](https://github.com/ron-rs/ron/pull/223))
|
||||
- Rename `format_doc_comments` to `format_code_in_doc_comment`
|
||||
- Update base64 requirement from 0.11 to 0.12 ([#204](https://github.com/ron-rs/ron/pull/204))
|
||||
- Update base64 requirement from 0.10 to 0.11 ([#195](https://github.com/ron-rs/ron/pull/195))
|
||||
- Update `serde_bytes` to 0.11 ([#164](https://github.com/ron-rs/ron/pull/164))
|
||||
|
||||
## [0.5.1] - 2019-04-05
|
||||
### Fixes
|
||||
- Increase source compability from Rust `1.34.0` to `1.31.0` by not relying on `as _` imports ([#156](https://github.com/ron-rs/ron/pull/156))
|
||||
|
||||
## [0.5.0] - 2019-03-31
|
||||
### Additions
|
||||
- Don't insert new lines in empty arrays or maps ([#150](https://github.com/ron-rs/ron/pull/150))
|
||||
### Changes
|
||||
- Transition to Rust 2018 ([#149](https://github.com/ron-rs/ron/pull/149))
|
||||
|
||||
## [0.4.2] - 2019-03-01
|
||||
### Additions
|
||||
- Add integer check for deserializer ([#148](https://github.com/ron-rs/ron/pull/148))
|
||||
- Implement `Value::into_rust` ([#146](https://github.com/ron-rs/ron/pull/146))
|
||||
|
||||
## [0.4.1] - 2019-01-09
|
||||
### Additions
|
||||
- Allow underscores in integers ([#135](https://github.com/ron-rs/ron/pull/135))
|
||||
- Added extension documentation ([#130](https://github.com/ron-rs/ron/pull/130))
|
||||
### Changes
|
||||
- Move sublime text syntax to separate repo ([#138](https://github.com/ron-rs/ron/pull/138))
|
||||
- Update `base64` crate dependency to 0.10 ([#137](https://github.com/ron-rs/ron/pull/137))
|
||||
|
||||
## [0.4.0] - 2018-08-11
|
||||
### Fixes
|
||||
- Handle tuple deserialization in deserialize_any properly ([#124](https://github.com/ron-rs/ron/pull/124))
|
||||
### Changes
|
||||
- Add raw string syntax to grammar ([#125](https://github.com/ron-rs/ron/pull/125))
|
||||
- Reexport `Value` at root ([#120](https://github.com/ron-rs/ron/pull/120))
|
||||
|
||||
## [0.3.0] - 2018-06-15
|
||||
### Additions
|
||||
- `serde_bytes` fields to be encoded using base64. ([#109](https://github.com/ron-rs/ron/pull/109))
|
||||
### Fixes
|
||||
- Allow raw string literals ([#114](https://github.com/ron-rs/ron/pull/114))
|
||||
### Changes
|
||||
- Now depends on `base64` 0.9.2.
|
||||
|
||||
## [0.2.2] - 2018-05-19
|
||||
### Fixes
|
||||
- Allow whitespace in newtype variants ([#104](https://github.com/ron-rs/ron/pull/104))
|
||||
|
||||
## [0.2.1] - 2018-05-04
|
||||
### Additions
|
||||
- Add multi-line comments ([#98](https://github.com/ron-rs/ron/pull/98))
|
||||
### Fixes
|
||||
- Allow more whitespace inside newtypes ([#103](https://github.com/ron-rs/ron/pull/103))
|
||||
|
||||
## [0.2.0] - 2018-02-14
|
||||
### Additions
|
||||
- Limit the pretty depth ([#93](https://github.com/ron-rs/ron/pull/93))
|
||||
- Add support for `\x??` and improve unicode escapes ([#84](https://github.com/ron-rs/ron/pull/84))
|
||||
|
||||
## [0.1.7] - 2018-01-24
|
||||
### Additions
|
||||
- Deep array indexing ([#88](https://github.com/ron-rs/ron/pull/88))
|
||||
- Pretty sequence indexing ([#86](https://github.com/ron-rs/ron/pull/86))
|
||||
- Add unicode support for chars ([#80](https://github.com/ron-rs/ron/pull/80))
|
||||
- Add support for hex, oct and bin numbers ([#78](https://github.com/ron-rs/ron/pull/78))
|
||||
- Allow implicit Some ([#75](https://github.com/ron-rs/ron/pull/75))
|
||||
- Add grammar specification ([#73](https://github.com/ron-rs/ron/pull/73))
|
||||
- Add extension support and first extension, unwrap_newtypes ([#72](https://github.com/ron-rs/ron/pull/72))
|
||||
### Fixes
|
||||
- Directly serialize `f32` ([#81](https://github.com/ron-rs/ron/pull/81))
|
||||
|
||||
## [0.1.6] - 2018-01-24
|
||||
### Additions
|
||||
- Implement sequence indexing ([#87](https://github.com/ron-rs/ron/pull/87))
|
||||
### Fixes
|
||||
- Remove ident variable from Sublime syntax ([#71](https://github.com/ron-rs/ron/pull/71))
|
||||
|
||||
## [0.1.5] - 2017-12-27
|
||||
### Additions
|
||||
- Allow creating a new serializer ([#70](https://github.com/ron-rs/ron/pull/70))
|
||||
- Sublime syntax highlighter ([#67](https://github.com/ron-rs/ron/pull/67))
|
||||
- Add support for integers ([#65](https://github.com/ron-rs/ron/pull/65))
|
||||
- Implement `Deserializer` for `Value` ([#64](https://github.com/ron-rs/ron/pull/64))
|
||||
|
||||
## [0.1.4] - 2017-10-12
|
||||
### Additions
|
||||
- Add `PrettyConfig` ([#61](https://github.com/ron-rs/ron/pull/61))
|
||||
- impl `deserialize_ignored_any` for `id` ([#60](https://github.com/ron-rs/ron/pull/60))
|
||||
### Fixes
|
||||
- Fix deserializing of ignored fields ([#62](https://github.com/ron-rs/ron/pull/62))
|
||||
|
||||
## [0.1.3] - 2017-10-06
|
||||
### Fixes
|
||||
- Removed indentation from tuple variant pretty encoder ([#57](https://github.com/ron-rs/ron/pull/57))
|
||||
|
||||
## [0.1.2] - 2017-10-06
|
||||
### Fixes
|
||||
- Fix decoding of string literals ([#56](https://github.com/ron-rs/ron/pull/56))
|
||||
- Add `Value` and implement `deserialize_any` ([#53](https://github.com/ron-rs/ron/pull/53))
|
||||
|
||||
## [0.1.1] - 2017-08-07
|
||||
### Fixes
|
||||
- Be more permissive wrt whitespace decoding ([#41](https://github.com/ron-rs/ron/pull/41))
|
||||
### Additions
|
||||
- Add utility function to deserialize from `std::io::Read` ([#42](https://github.com/ron-rs/ron/pull/42))
|
||||
|
||||
## [0.1.0] - 2015-08-04
|
||||
### Changes
|
||||
- Reorganize deserialization modules ([#30](https://github.com/ron-rs/ron/pull/30))
|
||||
- Rework deserializer not to require `pom` crate [#27](https://github.com/ron-rs/ron/pull/27), ([#38](https://github.com/ron-rs/ron/pull/38))
|
||||
- Dual license under Apache 2.0 and MIT ([#26](https://github.com/ron-rs/ron/pull/26))
|
||||
### Fixes
|
||||
- Use CRLF for serializatio on Windows ([#32](https://github.com/ron-rs/ron/pull/32))
|
||||
- Fix bors-ng to work with travis ([#31](https://github.com/ron-rs/ron/pull/31))
|
||||
- Handle escapes ([#23](https://github.com/ron-rs/ron/pull/23))
|
||||
### Additions
|
||||
- Improve error reporting ([#29](https://github.com/ron-rs/ron/pull/29))
|
||||
- Allow decoding of comments ([#28](https://github.com/ron-rs/ron/pull/28))
|
||||
- Add `pretty` option to serializer ([#25](https://github.com/ron-rs/ron/pull/25))
|
||||
- Add roundtrip tests ([#24](https://github.com/ron-rs/ron/pull/24))
|
||||
|
||||
## [0.0.1] - 2015-07-30
|
||||
Initial release
|
|
@ -0,0 +1,130 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.6.2"
|
||||
dependencies = [
|
||||
"base64 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_bytes 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum base64 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
|
||||
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
|
||||
"checksum proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
|
||||
"checksum quote 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4c1f4b0efa5fc5e8ceb705136bfee52cfdb6a4e3509f770b478cd6ed434232a7"
|
||||
"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
|
||||
"checksum serde_bytes 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3bf487fbf5c6239d7ea2ff8b10cb6b811cd4b5080d1c2aeed1dec18753c06e10"
|
||||
"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
|
||||
"checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1"
|
||||
"checksum syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
|
@ -13,8 +13,8 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "ron"
|
||||
version = "0.5.1"
|
||||
authors = ["Dzmitry Malyshau <kvarkus@gmail.com>", "Thomas Schaller <torkleyy@gmail.com>"]
|
||||
version = "0.6.2"
|
||||
authors = ["Christopher Durham <cad97@cad97.com>", "Dzmitry Malyshau <kvarkus@gmail.com>", "Thomas Schaller <torkleyy@gmail.com>"]
|
||||
exclude = ["bors.toml", ".travis.yml"]
|
||||
description = "Rusty Object Notation"
|
||||
homepage = "https://github.com/ron-rs/ron"
|
||||
|
@ -28,16 +28,21 @@ repository = "https://github.com/ron-rs/ron"
|
|||
[lib]
|
||||
name = "ron"
|
||||
[dependencies.base64]
|
||||
version = "0.10"
|
||||
version = "0.12"
|
||||
|
||||
[dependencies.bitflags]
|
||||
version = "1"
|
||||
version = "1.0.4"
|
||||
|
||||
[dependencies.indexmap]
|
||||
version = "1.0.2"
|
||||
features = ["serde-1"]
|
||||
optional = true
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1"
|
||||
version = "1.0.60"
|
||||
features = ["serde_derive"]
|
||||
[dev-dependencies.serde_bytes]
|
||||
version = "0.10"
|
||||
version = "0.11"
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1"
|
||||
|
|
|
@ -11,7 +11,7 @@ structs, enums, tuples, arrays, generic maps, and primitive values.
|
|||
|
||||
## Example
|
||||
|
||||
```
|
||||
```rust
|
||||
GameConfig( // optional struct name
|
||||
window_size: (800, 600),
|
||||
window_title: "PAC-MAN",
|
||||
|
@ -69,12 +69,12 @@ GameConfig( // optional struct name
|
|||
|
||||
Notice these issues:
|
||||
1. Struct and maps are the same
|
||||
- random order of exported fields
|
||||
- annoying and inconvenient for reading
|
||||
- doesn't work well with version control
|
||||
- quoted field names
|
||||
- too verbose
|
||||
- no support for enums
|
||||
- random order of exported fields
|
||||
- annoying and inconvenient for reading
|
||||
- doesn't work well with version control
|
||||
- quoted field names
|
||||
- too verbose
|
||||
- no support for enums
|
||||
2. No trailing comma allowed
|
||||
3. No comments allowed
|
||||
|
||||
|
@ -141,8 +141,14 @@ Why not XXX?
|
|||
|
||||
## Tooling
|
||||
|
||||
IntelliJ: https://vultix.github.io/intellij-ron-plugin/
|
||||
|
||||
VS Code: https://github.com/a5huynh/vscode-ron
|
||||
|
||||
Sublime Text: https://packagecontrol.io/packages/RON
|
||||
|
||||
Atom: https://atom.io/packages/language-ron
|
||||
|
||||
Vim: https://github.com/ron-rs/ron.vim
|
||||
|
||||
## License
|
||||
|
|
|
@ -18,7 +18,7 @@ RON = [extensions], ws, value, ws;
|
|||
```ebnf
|
||||
ws = { ws_single, comment };
|
||||
ws_single = "\n" | "\t" | "\r" | " ";
|
||||
comment = ["//", { no_newline }, "\n"];
|
||||
comment = ["//", { no_newline }, "\n"] | ["/*", { ? any character ? }, "*/"];
|
||||
```
|
||||
|
||||
## Commas
|
||||
|
@ -46,7 +46,9 @@ value = unsigned | signed | float | string | char | bool | option | list | map |
|
|||
|
||||
```ebnf
|
||||
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
||||
unsigned = ["0", ("x" | "b" | "o")], digit, { digit | '_' };
|
||||
hex_digit = "A" | "a" | "B" | "b" | "C" | "c" | "D" | "d" | "E" | "e" | "F" | "f";
|
||||
unsigned = (["0", ("b" | "o")], digit, { digit | '_' } |
|
||||
"0x", (digit | hex_digit), { digit | hex_digit | '_' });
|
||||
signed = ["+" | "-"], unsigned;
|
||||
float = float_std | float_frac;
|
||||
float_std = ["+" | "-"], digit, { digit }, ".", {digit}, [float_exp];
|
||||
|
@ -60,18 +62,23 @@ float_exp = ("e" | "E"), digit, {digit};
|
|||
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, "#") | "\"", { unicode_non_greedy }, "\"";
|
||||
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 `#` and a quotation mark
|
||||
> 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 `#`.
|
||||
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 (\)!"##
|
||||
```
|
||||
I don't know any sane way to write this out in EBNF, if you do, let me know.
|
||||
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
|
||||
|
||||
|
|
|
@ -39,12 +39,10 @@ fn main() {
|
|||
array: vec![(); 3],
|
||||
};
|
||||
|
||||
let pretty = PrettyConfig {
|
||||
depth_limit: 2,
|
||||
separate_tuple_members: true,
|
||||
enumerate_arrays: true,
|
||||
..PrettyConfig::default()
|
||||
};
|
||||
let pretty = PrettyConfig::new()
|
||||
.with_depth_limit(2)
|
||||
.with_separate_tuple_members(true)
|
||||
.with_enumerate_arrays(true);
|
||||
let s = to_string_pretty(&data, pretty).expect("Serialization failed");
|
||||
|
||||
println!("{}", s);
|
||||
|
|
|
@ -25,7 +25,7 @@ fn main() {
|
|||
)
|
||||
"#;
|
||||
|
||||
let value = Value::from_str(data).expect("Failed to deserialize");
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
hard_tabs = false
|
||||
merge_imports = true
|
||||
reorder_impl_items = true
|
||||
use_field_init_shorthand = true
|
||||
use_try_shorthand = true
|
||||
format_doc_comments = true
|
||||
wrap_comments = true
|
||||
edition = "2018"
|
||||
version = "Two"
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
use serde::de;
|
||||
use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
|
||||
|
||||
use crate::parse::Position;
|
||||
|
||||
/// Deserialization result.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
IoError(String),
|
||||
Message(String),
|
||||
Parser(ParseError, Position),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ParseError {
|
||||
Base64Error(base64::DecodeError),
|
||||
Eof,
|
||||
ExpectedArray,
|
||||
ExpectedArrayEnd,
|
||||
ExpectedAttribute,
|
||||
ExpectedAttributeEnd,
|
||||
ExpectedBoolean,
|
||||
ExpectedComma,
|
||||
ExpectedEnum,
|
||||
ExpectedChar,
|
||||
ExpectedFloat,
|
||||
ExpectedInteger,
|
||||
ExpectedOption,
|
||||
ExpectedOptionEnd,
|
||||
ExpectedMap,
|
||||
ExpectedMapColon,
|
||||
ExpectedMapEnd,
|
||||
ExpectedStruct,
|
||||
ExpectedStructEnd,
|
||||
ExpectedUnit,
|
||||
ExpectedStructName,
|
||||
ExpectedString,
|
||||
ExpectedStringEnd,
|
||||
ExpectedIdentifier,
|
||||
|
||||
InvalidEscape(&'static str),
|
||||
|
||||
NoSuchExtension(String),
|
||||
|
||||
UnclosedBlockComment,
|
||||
UnderscoreAtBeginning,
|
||||
UnexpectedByte(char),
|
||||
|
||||
Utf8Error(Utf8Error),
|
||||
TrailingCharacters,
|
||||
|
||||
#[doc(hidden)]
|
||||
__NonExhaustive,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Error::IoError(ref s) => write!(f, "{}", s),
|
||||
Error::Message(ref s) => write!(f, "{}", s),
|
||||
Error::Parser(_, pos) => write!(f, "{}: {}", pos, self.description()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T: fmt::Display>(msg: T) -> Self {
|
||||
Error::Message(msg.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::IoError(ref s) => s,
|
||||
Error::Message(ref e) => e,
|
||||
Error::Parser(ref kind, _) => match *kind {
|
||||
ParseError::Base64Error(ref e) => e.description(),
|
||||
ParseError::Eof => "Unexpected end of file",
|
||||
ParseError::ExpectedArray => "Expected array",
|
||||
ParseError::ExpectedArrayEnd => "Expected end of array",
|
||||
ParseError::ExpectedAttribute => "Expected an enable attribute",
|
||||
ParseError::ExpectedAttributeEnd => {
|
||||
"Expected closing `)` and `]` after the attribute"
|
||||
}
|
||||
ParseError::ExpectedBoolean => "Expected boolean",
|
||||
ParseError::ExpectedComma => "Expected comma",
|
||||
ParseError::ExpectedEnum => "Expected enum",
|
||||
ParseError::ExpectedChar => "Expected char",
|
||||
ParseError::ExpectedFloat => "Expected float",
|
||||
ParseError::ExpectedInteger => "Expected integer",
|
||||
ParseError::ExpectedOption => "Expected option",
|
||||
ParseError::ExpectedOptionEnd => "Expected end of option",
|
||||
ParseError::ExpectedMap => "Expected map",
|
||||
ParseError::ExpectedMapColon => "Expected colon",
|
||||
ParseError::ExpectedMapEnd => "Expected end of map",
|
||||
ParseError::ExpectedStruct => "Expected struct",
|
||||
ParseError::ExpectedStructEnd => "Expected end of struct",
|
||||
ParseError::ExpectedUnit => "Expected unit",
|
||||
ParseError::ExpectedStructName => "Expected struct name",
|
||||
ParseError::ExpectedString => "Expected string",
|
||||
ParseError::ExpectedStringEnd => "Expected string end",
|
||||
ParseError::ExpectedIdentifier => "Expected identifier",
|
||||
|
||||
ParseError::InvalidEscape(_) => "Invalid escape sequence",
|
||||
|
||||
ParseError::NoSuchExtension(_) => "No such RON extension",
|
||||
|
||||
ParseError::Utf8Error(ref e) => e.description(),
|
||||
ParseError::UnclosedBlockComment => "Unclosed block comment",
|
||||
ParseError::UnderscoreAtBeginning => "Found underscore at the beginning",
|
||||
ParseError::UnexpectedByte(_) => "Unexpected byte",
|
||||
ParseError::TrailingCharacters => "Non-whitespace trailing characters",
|
||||
|
||||
ParseError::__NonExhaustive => unimplemented!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Utf8Error> for ParseError {
|
||||
fn from(e: Utf8Error) -> Self {
|
||||
ParseError::Utf8Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FromUtf8Error> for ParseError {
|
||||
fn from(e: FromUtf8Error) -> Self {
|
||||
ParseError::Utf8Error(e.utf8_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Utf8Error> for Error {
|
||||
fn from(e: Utf8Error) -> Self {
|
||||
Error::Parser(ParseError::Utf8Error(e), Position { line: 0, col: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Error::IoError(e.description().to_string())
|
||||
}
|
||||
}
|
|
@ -22,6 +22,13 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, '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>,
|
||||
|
@ -64,6 +71,13 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
|
|||
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||
}
|
||||
|
||||
fn deserialize_i128<V>(self, _: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, _: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
|
@ -92,6 +106,13 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
|
|||
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||
}
|
||||
|
||||
fn deserialize_u128<V>(self, _: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, _: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
|
@ -113,13 +134,6 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
|
|||
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||
}
|
||||
|
||||
fn deserialize_str<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>,
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
/// Deserialization module.
|
||||
pub use self::error::{Error, ParseError, Result};
|
||||
pub use crate::error::{Error, ErrorCode, Result};
|
||||
pub use crate::parse::Position;
|
||||
|
||||
use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
|
||||
use std::{borrow::Cow, io, str};
|
||||
|
||||
use self::id::IdDeserializer;
|
||||
use crate::parse::{Bytes, Extensions, ParsedStr};
|
||||
use self::{id::IdDeserializer, tag::TagDeserializer};
|
||||
use crate::{
|
||||
extensions::Extensions,
|
||||
parse::{AnyNum, Bytes, ParsedStr},
|
||||
};
|
||||
|
||||
mod error;
|
||||
mod id;
|
||||
mod tag;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod value;
|
||||
|
@ -23,6 +26,8 @@ pub struct Deserializer<'de> {
|
|||
}
|
||||
|
||||
impl<'de> Deserializer<'de> {
|
||||
// Cannot implement trait here since output is tied to input lifetime 'de.
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn from_str(input: &'de str) -> Result<Self> {
|
||||
Deserializer::from_bytes(input.as_bytes())
|
||||
}
|
||||
|
@ -83,11 +88,11 @@ impl<'de> Deserializer<'de> {
|
|||
if self.bytes.bytes().is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
self.bytes.err(ParseError::TrailingCharacters)
|
||||
self.bytes.err(ErrorCode::TrailingCharacters)
|
||||
}
|
||||
}
|
||||
|
||||
/// Called from `deserialze_any` when a struct was detected. Decides if
|
||||
/// Called from `deserialize_any` when a struct was detected. Decides if
|
||||
/// there is a unit, tuple or usual struct and deserializes it
|
||||
/// accordingly.
|
||||
///
|
||||
|
@ -99,18 +104,18 @@ impl<'de> Deserializer<'de> {
|
|||
// Create a working copy
|
||||
let mut bytes = self.bytes;
|
||||
|
||||
match bytes.consume("(") {
|
||||
true => {
|
||||
bytes.skip_ws()?;
|
||||
if bytes.consume("(") {
|
||||
bytes.skip_ws()?;
|
||||
|
||||
match bytes.check_tuple_struct()? {
|
||||
// first argument is technically incorrect, but ignored anyway
|
||||
true => self.deserialize_tuple(0, visitor),
|
||||
// first two arguments are technically incorrect, but ignored anyway
|
||||
false => self.deserialize_struct("", &[], visitor),
|
||||
}
|
||||
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)
|
||||
}
|
||||
false => visitor.visit_unit(),
|
||||
} else {
|
||||
visitor.visit_unit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +137,12 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
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
|
||||
|
@ -148,16 +159,27 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
b'[' => self.deserialize_seq(visitor),
|
||||
b'{' => self.deserialize_map(visitor),
|
||||
b'0'..=b'9' | b'+' | b'-' => {
|
||||
if self.bytes.next_bytes_is_float() {
|
||||
self.deserialize_f64(visitor)
|
||||
} else {
|
||||
self.deserialize_i64(visitor)
|
||||
let any_num: AnyNum = self.bytes.any_num()?;
|
||||
|
||||
match any_num {
|
||||
AnyNum::F32(x) => visitor.visit_f32(x),
|
||||
AnyNum::F64(x) => visitor.visit_f64(x),
|
||||
AnyNum::I8(x) => visitor.visit_i8(x),
|
||||
AnyNum::U8(x) => visitor.visit_u8(x),
|
||||
AnyNum::I16(x) => visitor.visit_i16(x),
|
||||
AnyNum::U16(x) => visitor.visit_u16(x),
|
||||
AnyNum::I32(x) => visitor.visit_i32(x),
|
||||
AnyNum::U32(x) => visitor.visit_u32(x),
|
||||
AnyNum::I64(x) => visitor.visit_i64(x),
|
||||
AnyNum::U64(x) => visitor.visit_u64(x),
|
||||
AnyNum::I128(x) => visitor.visit_i128(x),
|
||||
AnyNum::U128(x) => visitor.visit_u128(x),
|
||||
}
|
||||
}
|
||||
b'.' => self.deserialize_f64(visitor),
|
||||
b'"' | b'r' => self.deserialize_string(visitor),
|
||||
b'\'' => self.deserialize_char(visitor),
|
||||
other => self.bytes.err(ParseError::UnexpectedByte(other as char)),
|
||||
other => self.bytes.err(ErrorCode::UnexpectedByte(other as char)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,6 +218,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
visitor.visit_i64(self.bytes.signed_integer()?)
|
||||
}
|
||||
|
||||
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i128(self.bytes.signed_integer()?)
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
|
@ -224,6 +253,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
visitor.visit_u64(self.bytes.unsigned_integer()?)
|
||||
}
|
||||
|
||||
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u128(self.bytes.unsigned_integer()?)
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
|
@ -251,7 +287,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
{
|
||||
match self.bytes.string()? {
|
||||
ParsedStr::Allocated(s) => visitor.visit_string(s),
|
||||
ParsedStr::Slice(s) => visitor.visit_str(s),
|
||||
ParsedStr::Slice(s) => visitor.visit_borrowed_str(s),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +320,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
|
||||
match res {
|
||||
Ok(byte_buf) => visitor.visit_byte_buf(byte_buf),
|
||||
Err(err) => self.bytes.err(ParseError::Base64Error(err)),
|
||||
Err(err) => self.bytes.err(ErrorCode::Base64Error(err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,10 +345,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
if self.bytes.consume(")") {
|
||||
Ok(v)
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedOptionEnd)
|
||||
self.bytes.err(ErrorCode::ExpectedOptionEnd)
|
||||
}
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedOption)
|
||||
self.bytes.err(ErrorCode::ExpectedOption)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,7 +360,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
if self.bytes.consume("()") {
|
||||
visitor.visit_unit()
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedUnit)
|
||||
self.bytes.err(ErrorCode::ExpectedUnit)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,10 +395,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
if self.bytes.consume(")") {
|
||||
Ok(value)
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedStructEnd)
|
||||
self.bytes.err(ErrorCode::ExpectedStructEnd)
|
||||
}
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedStruct)
|
||||
self.bytes.err(ErrorCode::ExpectedStruct)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,10 +413,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
if self.bytes.consume("]") {
|
||||
Ok(value)
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedArrayEnd)
|
||||
self.bytes.err(ErrorCode::ExpectedArrayEnd)
|
||||
}
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedArray)
|
||||
self.bytes.err(ErrorCode::ExpectedArray)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,10 +431,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
if self.bytes.consume(")") {
|
||||
Ok(value)
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedArrayEnd)
|
||||
self.bytes.err(ErrorCode::ExpectedArrayEnd)
|
||||
}
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedArray)
|
||||
self.bytes.err(ErrorCode::ExpectedArray)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,10 +462,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
if self.bytes.consume("}") {
|
||||
Ok(value)
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedMapEnd)
|
||||
self.bytes.err(ErrorCode::ExpectedMapEnd)
|
||||
}
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedMap)
|
||||
self.bytes.err(ErrorCode::ExpectedMap)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,10 +489,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
if self.bytes.consume(")") {
|
||||
Ok(value)
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedStructEnd)
|
||||
self.bytes.err(ErrorCode::ExpectedStructEnd)
|
||||
}
|
||||
} else {
|
||||
self.bytes.err(ParseError::ExpectedStruct)
|
||||
self.bytes.err(ErrorCode::ExpectedStruct)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -504,7 +540,7 @@ impl<'a, 'de> CommaSeparated<'a, 'de> {
|
|||
}
|
||||
}
|
||||
|
||||
fn err<T>(&self, kind: ParseError) -> Result<T> {
|
||||
fn err<T>(&self, kind: ErrorCode) -> Result<T> {
|
||||
self.de.bytes.err(kind)
|
||||
}
|
||||
|
||||
|
@ -562,13 +598,13 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
|
|||
if self.de.bytes.consume(":") {
|
||||
self.de.bytes.skip_ws()?;
|
||||
|
||||
let res = seed.deserialize(&mut *self.de)?;
|
||||
let res = seed.deserialize(&mut TagDeserializer::new(&mut *self.de))?;
|
||||
|
||||
self.had_comma = self.de.bytes.comma()?;
|
||||
|
||||
Ok(res)
|
||||
} else {
|
||||
self.err(ParseError::ExpectedMapColon)
|
||||
self.err(ErrorCode::ExpectedMapColon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -622,10 +658,10 @@ impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
|
|||
if self.de.bytes.consume(")") {
|
||||
Ok(val)
|
||||
} else {
|
||||
self.de.bytes.err(ParseError::ExpectedStructEnd)
|
||||
self.de.bytes.err(ErrorCode::ExpectedStructEnd)
|
||||
}
|
||||
} else {
|
||||
self.de.bytes.err(ParseError::ExpectedStruct)
|
||||
self.de.bytes.err(ErrorCode::ExpectedStruct)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
use serde::de::{self, Visitor};
|
||||
|
||||
use super::{Deserializer, Error, Result};
|
||||
|
||||
pub struct TagDeserializer<'a, 'b: 'a> {
|
||||
d: &'a mut Deserializer<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a> TagDeserializer<'a, 'b> {
|
||||
pub fn new(d: &'a mut Deserializer<'b>) -> Self {
|
||||
TagDeserializer { d }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut TagDeserializer<'a, 'b> {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_any(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_bool(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_i8(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_i16(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_i32(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_i128(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_u8(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_u16(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_u32(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_u64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_u128(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_f32(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_f64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_char(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_string(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_bytes(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_byte_buf(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_option(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_unit(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_unit_struct(name, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_newtype_struct(name, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_tuple(len, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_tuple_struct(name, len, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_struct(name, fields, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_enum(name, variants, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'b>,
|
||||
{
|
||||
self.d.deserialize_ignored_any(visitor)
|
||||
}
|
||||
}
|
|
@ -149,15 +149,16 @@ y: 2.0 // 2!
|
|||
);
|
||||
}
|
||||
|
||||
fn err<T>(kind: ParseError, line: usize, col: usize) -> Result<T> {
|
||||
use crate::parse::Position;
|
||||
|
||||
Err(Error::Parser(kind, Position { line, col }))
|
||||
fn err<T>(kind: ErrorCode, line: usize, col: usize) -> Result<T> {
|
||||
Err(Error {
|
||||
code: kind,
|
||||
position: Position { line, col },
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_err_wrong_value() {
|
||||
use self::ParseError::*;
|
||||
use self::ErrorCode::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
assert_eq!(from_str::<f32>("'c'"), err(ExpectedFloat, 1, 1));
|
||||
|
@ -206,7 +207,10 @@ fn forgot_apostrophes() {
|
|||
let de: Result<(i32, String)> = from_str("(4, \"Hello)");
|
||||
|
||||
assert!(match de {
|
||||
Err(Error::Parser(ParseError::ExpectedStringEnd, _)) => true,
|
||||
Err(Error {
|
||||
code: ErrorCode::ExpectedStringEnd,
|
||||
position: _,
|
||||
}) => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
@ -215,14 +219,14 @@ fn forgot_apostrophes() {
|
|||
fn expected_attribute() {
|
||||
let de: Result<String> = from_str("#\"Hello\"");
|
||||
|
||||
assert_eq!(de, err(ParseError::ExpectedAttribute, 1, 2));
|
||||
assert_eq!(de, err(ErrorCode::ExpectedAttribute, 1, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expected_attribute_end() {
|
||||
let de: Result<String> = from_str("#![enable(unwrap_newtypes) \"Hello\"");
|
||||
|
||||
assert_eq!(de, err(ParseError::ExpectedAttributeEnd, 1, 28));
|
||||
assert_eq!(de, err(ErrorCode::ExpectedAttributeEnd, 1, 28));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -231,7 +235,7 @@ fn invalid_attribute() {
|
|||
|
||||
assert_eq!(
|
||||
de,
|
||||
err(ParseError::NoSuchExtension("invalid".to_string()), 1, 18)
|
||||
err(ErrorCode::NoSuchExtension("invalid".to_string()), 1, 18)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -305,3 +309,20 @@ fn test_numbers() {
|
|||
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));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::BTreeMap, fmt};
|
||||
use std::fmt;
|
||||
|
||||
use serde::{
|
||||
de::{Error, MapAccess, SeqAccess, Visitor},
|
||||
|
@ -7,12 +7,14 @@ use serde::{
|
|||
|
||||
use crate::{
|
||||
de,
|
||||
value::{Number, Value},
|
||||
value::{Map, Number, Value},
|
||||
};
|
||||
|
||||
impl Value {
|
||||
impl std::str::FromStr for Value {
|
||||
type Err = de::Error;
|
||||
|
||||
/// Creates a value from a string reference.
|
||||
pub fn from_str(s: &str) -> de::Result<Self> {
|
||||
fn from_str(s: &str) -> de::Result<Self> {
|
||||
let mut de = super::Deserializer::from_str(s)?;
|
||||
|
||||
let val = Value::deserialize(&mut de)?;
|
||||
|
@ -48,6 +50,13 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||
}
|
||||
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Number(Number::new(v)))
|
||||
}
|
||||
|
||||
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
|
@ -55,6 +64,13 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||
}
|
||||
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Number(Number::new(v)))
|
||||
}
|
||||
|
||||
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
|
@ -153,7 +169,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
let mut res: BTreeMap<Value, Value> = BTreeMap::new();
|
||||
let mut res: Map = Map::new();
|
||||
|
||||
while let Some(entry) = map.next_entry()? {
|
||||
res.insert(entry.0, entry.1);
|
||||
|
@ -166,9 +182,10 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn eval(s: &str) -> Value {
|
||||
Value::from_str(s).expect("Failed to parse")
|
||||
s.parse().expect("Failed to parse")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -188,9 +205,9 @@ mod tests {
|
|||
#[test]
|
||||
fn test_tuples_basic() {
|
||||
assert_eq!(
|
||||
eval("(3, 4, 5)"),
|
||||
eval("(3, 4.0, 5.0)"),
|
||||
Value::Seq(vec![
|
||||
Value::Number(Number::new(3.0)),
|
||||
Value::Number(Number::new(3)),
|
||||
Value::Number(Number::new(4.0)),
|
||||
Value::Number(Number::new(5.0)),
|
||||
],),
|
||||
|
@ -200,11 +217,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_tuples_ident() {
|
||||
assert_eq!(
|
||||
eval("(true, 3, 4, 5)"),
|
||||
eval("(true, 3, 4, 5.0)"),
|
||||
Value::Seq(vec![
|
||||
Value::Bool(true),
|
||||
Value::Number(Number::new(3.0)),
|
||||
Value::Number(Number::new(4.0)),
|
||||
Value::Number(Number::new(3)),
|
||||
Value::Number(Number::new(4)),
|
||||
Value::Number(Number::new(5.0)),
|
||||
]),
|
||||
);
|
||||
|
@ -212,11 +229,26 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_tuples_error() {
|
||||
use crate::de::{Error, ParseError, Position};
|
||||
use crate::de::{Error, ErrorCode, Position};
|
||||
|
||||
assert_eq!(
|
||||
Value::from_str("Foo:").unwrap_err(),
|
||||
Error::Parser(ParseError::TrailingCharacters, Position { col: 4, line: 1 }),
|
||||
Error {
|
||||
code: ErrorCode::TrailingCharacters,
|
||||
position: Position { col: 4, line: 1 }
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_floats() {
|
||||
assert_eq!(
|
||||
eval("(inf, -inf, NaN)"),
|
||||
Value::Seq(vec![
|
||||
Value::Number(Number::new(std::f64::INFINITY)),
|
||||
Value::Number(Number::new(std::f64::NEG_INFINITY)),
|
||||
Value::Number(Number::new(std::f64::NAN)),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -228,8 +260,8 @@ mod tests {
|
|||
Room ( width: 20, height: 5, name: \"The Room\" ),
|
||||
|
||||
(
|
||||
width: 10,
|
||||
height: 10,
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
name: \"Another room\",
|
||||
enemy_levels: {
|
||||
\"Enemy1\": 3,
|
||||
|
@ -244,11 +276,11 @@ mod tests {
|
|||
vec![
|
||||
(
|
||||
Value::String("width".to_owned()),
|
||||
Value::Number(Number::new(20.0)),
|
||||
Value::Number(Number::new(20)),
|
||||
),
|
||||
(
|
||||
Value::String("height".to_owned()),
|
||||
Value::Number(Number::new(5.0)),
|
||||
Value::Number(Number::new(5)),
|
||||
),
|
||||
(
|
||||
Value::String("name".to_owned()),
|
||||
|
@ -278,15 +310,15 @@ mod tests {
|
|||
vec![
|
||||
(
|
||||
Value::String("Enemy1".to_owned()),
|
||||
Value::Number(Number::new(3.0)),
|
||||
Value::Number(Number::new(3)),
|
||||
),
|
||||
(
|
||||
Value::String("Enemy2".to_owned()),
|
||||
Value::Number(Number::new(5.0)),
|
||||
Value::Number(Number::new(5)),
|
||||
),
|
||||
(
|
||||
Value::String("Enemy3".to_owned()),
|
||||
Value::Number(Number::new(7.0)),
|
||||
Value::Number(Number::new(7)),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
use serde::{de, ser};
|
||||
use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
|
||||
|
||||
pub use crate::parse::Position;
|
||||
|
||||
/// This type represents all possible errors that can occur when
|
||||
/// serializing or deserializing RON data.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Error {
|
||||
pub code: ErrorCode,
|
||||
pub position: Position,
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ErrorCode {
|
||||
Io(String),
|
||||
Message(String),
|
||||
Base64Error(base64::DecodeError),
|
||||
Eof,
|
||||
ExpectedArray,
|
||||
ExpectedArrayEnd,
|
||||
ExpectedAttribute,
|
||||
ExpectedAttributeEnd,
|
||||
ExpectedBoolean,
|
||||
ExpectedComma,
|
||||
// ExpectedEnum,
|
||||
ExpectedChar,
|
||||
ExpectedFloat,
|
||||
ExpectedInteger,
|
||||
ExpectedOption,
|
||||
ExpectedOptionEnd,
|
||||
ExpectedMap,
|
||||
ExpectedMapColon,
|
||||
ExpectedMapEnd,
|
||||
ExpectedStruct,
|
||||
ExpectedStructEnd,
|
||||
ExpectedUnit,
|
||||
// ExpectedStructName,
|
||||
ExpectedString,
|
||||
ExpectedStringEnd,
|
||||
ExpectedIdentifier,
|
||||
|
||||
InvalidEscape(&'static str),
|
||||
|
||||
IntegerOutOfBounds,
|
||||
|
||||
NoSuchExtension(String),
|
||||
|
||||
UnclosedBlockComment,
|
||||
UnderscoreAtBeginning,
|
||||
UnexpectedByte(char),
|
||||
|
||||
Utf8Error(Utf8Error),
|
||||
TrailingCharacters,
|
||||
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if (self.position == Position { line: 0, col: 0 }) {
|
||||
write!(f, "{}", self.code)
|
||||
} else {
|
||||
write!(f, "{}: {}", self.position, self.code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ErrorCode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ErrorCode::Io(ref s) => f.write_str(s),
|
||||
ErrorCode::Message(ref s) => f.write_str(s),
|
||||
ErrorCode::Base64Error(ref e) => fmt::Display::fmt(e, f),
|
||||
ErrorCode::Eof => f.write_str("Unexpected end of file"),
|
||||
ErrorCode::ExpectedArray => f.write_str("Expected array"),
|
||||
ErrorCode::ExpectedArrayEnd => f.write_str("Expected end of array"),
|
||||
ErrorCode::ExpectedAttribute => f.write_str("Expected an enable attribute"),
|
||||
ErrorCode::ExpectedAttributeEnd => {
|
||||
f.write_str("Expected closing `)` and `]` after the attribute")
|
||||
}
|
||||
ErrorCode::ExpectedBoolean => f.write_str("Expected boolean"),
|
||||
ErrorCode::ExpectedComma => f.write_str("Expected comma"),
|
||||
// ErrorCode::ExpectedEnum => f.write_str("Expected enum"),
|
||||
ErrorCode::ExpectedChar => f.write_str("Expected char"),
|
||||
ErrorCode::ExpectedFloat => f.write_str("Expected float"),
|
||||
ErrorCode::ExpectedInteger => f.write_str("Expected integer"),
|
||||
ErrorCode::ExpectedOption => f.write_str("Expected option"),
|
||||
ErrorCode::ExpectedOptionEnd => f.write_str("Expected end of option"),
|
||||
ErrorCode::ExpectedMap => f.write_str("Expected map"),
|
||||
ErrorCode::ExpectedMapColon => f.write_str("Expected colon"),
|
||||
ErrorCode::ExpectedMapEnd => f.write_str("Expected end of map"),
|
||||
ErrorCode::ExpectedStruct => f.write_str("Expected struct"),
|
||||
ErrorCode::ExpectedStructEnd => f.write_str("Expected end of struct"),
|
||||
ErrorCode::ExpectedUnit => f.write_str("Expected unit"),
|
||||
// ErrorCode::ExpectedStructName => f.write_str("Expected struct name"),
|
||||
ErrorCode::ExpectedString => f.write_str("Expected string"),
|
||||
ErrorCode::ExpectedStringEnd => f.write_str("Expected string end"),
|
||||
ErrorCode::ExpectedIdentifier => f.write_str("Expected identifier"),
|
||||
ErrorCode::InvalidEscape(_) => f.write_str("Invalid escape sequence"),
|
||||
ErrorCode::IntegerOutOfBounds => f.write_str("Integer is out of bounds"),
|
||||
ErrorCode::NoSuchExtension(_) => f.write_str("No such RON extension"),
|
||||
ErrorCode::Utf8Error(ref e) => fmt::Display::fmt(e, f),
|
||||
ErrorCode::UnclosedBlockComment => f.write_str("Unclosed block comment"),
|
||||
ErrorCode::UnderscoreAtBeginning => f.write_str("Found underscore at the beginning"),
|
||||
ErrorCode::UnexpectedByte(_) => f.write_str("Unexpected byte"),
|
||||
ErrorCode::TrailingCharacters => f.write_str("Non-whitespace trailing characters"),
|
||||
_ => f.write_str("Unknown ErrorCode"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T: fmt::Display>(msg: T) -> Self {
|
||||
Error {
|
||||
code: ErrorCode::Message(msg.to_string()),
|
||||
position: Position { line: 0, col: 0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T: fmt::Display>(msg: T) -> Self {
|
||||
Error {
|
||||
code: ErrorCode::Message(msg.to_string()),
|
||||
position: Position { line: 0, col: 0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {}
|
||||
|
||||
impl From<Utf8Error> for ErrorCode {
|
||||
fn from(e: Utf8Error) -> Self {
|
||||
ErrorCode::Utf8Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FromUtf8Error> for ErrorCode {
|
||||
fn from(e: FromUtf8Error) -> Self {
|
||||
ErrorCode::Utf8Error(e.utf8_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Utf8Error> for Error {
|
||||
fn from(e: Utf8Error) -> Self {
|
||||
Error {
|
||||
code: ErrorCode::Utf8Error(e),
|
||||
position: Position { line: 0, col: 0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Error {
|
||||
code: ErrorCode::Io(e.to_string()),
|
||||
position: Position { line: 0, col: 0 },
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Extensions: usize {
|
||||
const UNWRAP_NEWTYPES = 0x1;
|
||||
const IMPLICIT_SOME = 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
impl Extensions {
|
||||
/// Creates an extension flag from an ident.
|
||||
pub fn from_ident(ident: &[u8]) -> Option<Extensions> {
|
||||
match ident {
|
||||
b"unwrap_newtypes" => Some(Extensions::UNWRAP_NEWTYPES),
|
||||
b"implicit_some" => Some(Extensions::IMPLICIT_SOME),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Extensions {
|
||||
fn default() -> Self {
|
||||
Extensions::empty()
|
||||
}
|
||||
}
|
|
@ -57,9 +57,19 @@ Serializing / Deserializing is as simple as calling `to_string` / `from_str`.
|
|||
|
||||
!*/
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/ron/0.6.0")]
|
||||
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
|
||||
pub mod error;
|
||||
pub mod value;
|
||||
pub use crate::value::Value;
|
||||
|
||||
pub mod extensions;
|
||||
|
||||
pub use de::{from_str, Deserializer};
|
||||
pub use error::{Error, Result};
|
||||
pub use ser::{to_string, Serializer};
|
||||
pub use value::{Map, Number, Value};
|
||||
|
||||
mod parse;
|
||||
|
|
|
@ -1,19 +1,99 @@
|
|||
use bitflags::bitflags;
|
||||
use std::{
|
||||
char::from_u32 as char_from_u32,
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
ops::Neg,
|
||||
result::Result as StdResult,
|
||||
str::{from_utf8, from_utf8_unchecked, FromStr},
|
||||
};
|
||||
|
||||
use crate::de::{Error, ParseError, Result};
|
||||
use crate::{
|
||||
error::{Error, ErrorCode, Result},
|
||||
extensions::Extensions,
|
||||
};
|
||||
|
||||
const DIGITS: &[u8] = b"0123456789ABCDEFabcdef_";
|
||||
const FLOAT_CHARS: &[u8] = b"0123456789.+-eE";
|
||||
const IDENT_FIRST: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
|
||||
const IDENT_CHAR: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789";
|
||||
const WHITE_SPACE: &[u8] = b"\n\t\r ";
|
||||
// We have the following char categories.
|
||||
const INT_CHAR: u8 = 1 << 0; // [0-9A-Fa-f_]
|
||||
const FLOAT_CHAR: u8 = 1 << 1; // [0-9\.Ee+-]
|
||||
const IDENT_FIRST_CHAR: u8 = 1 << 2; // [A-Za-z_]
|
||||
const IDENT_OTHER_CHAR: u8 = 1 << 3; // [A-Za-z_0-9]
|
||||
const WHITESPACE_CHAR: u8 = 1 << 4; // [\n\t\r ]
|
||||
|
||||
// We encode each char as belonging to some number of these categories.
|
||||
const DIGIT: u8 = INT_CHAR | FLOAT_CHAR | IDENT_OTHER_CHAR; // [0-9]
|
||||
const ABCDF: u8 = INT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [ABCDFabcdf]
|
||||
const UNDER: u8 = INT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [_]
|
||||
const E____: u8 = INT_CHAR | FLOAT_CHAR | IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [Ee]
|
||||
const G2Z__: u8 = IDENT_FIRST_CHAR | IDENT_OTHER_CHAR; // [G-Zg-z]
|
||||
const PUNCT: u8 = FLOAT_CHAR; // [\.+-]
|
||||
const WS___: u8 = WHITESPACE_CHAR; // [\t\n\r ]
|
||||
const _____: u8 = 0; // everything else
|
||||
|
||||
// Table of encodings, for fast predicates. (Non-ASCII and special chars are
|
||||
// shown with '·' in the comment.)
|
||||
#[rustfmt::skip]
|
||||
const ENCODINGS: [u8; 256] = [
|
||||
/* 0 1 2 3 4 5 6 7 8 9 */
|
||||
/* 0+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, WS___,
|
||||
/* 10+: ·········· */ WS___, _____, _____, WS___, _____, _____, _____, _____, _____, _____,
|
||||
/* 20+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 30+: ·· !"#$%&' */ _____, _____, WS___, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 40+: ()*+,-./01 */ _____, _____, _____, PUNCT, _____, PUNCT, PUNCT, _____, DIGIT, DIGIT,
|
||||
/* 50+: 23456789:; */ DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, _____, _____,
|
||||
/* 60+: <=>?@ABCDE */ _____, _____, _____, _____, _____, ABCDF, ABCDF, ABCDF, ABCDF, E____,
|
||||
/* 70+: FGHIJKLMNO */ ABCDF, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
|
||||
/* 80+: PQRSTUVWZY */ G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
|
||||
/* 90+: Z[\]^_`abc */ G2Z__, _____, _____, _____, _____, UNDER, _____, ABCDF, ABCDF, ABCDF,
|
||||
/* 100+: defghijklm */ ABCDF, E____, ABCDF, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
|
||||
/* 110+: nopqrstuvw */ G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__, G2Z__,
|
||||
/* 120+: xyz{|}~··· */ G2Z__, G2Z__, G2Z__, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 130+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 140+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 150+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 160+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 170+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 180+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 190+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 200+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 210+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 220+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 230+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 240+: ·········· */ _____, _____, _____, _____, _____, _____, _____, _____, _____, _____,
|
||||
/* 250+: ·········· */ _____, _____, _____, _____, _____, _____
|
||||
];
|
||||
|
||||
const fn is_int_char(c: u8) -> bool {
|
||||
ENCODINGS[c as usize] & INT_CHAR != 0
|
||||
}
|
||||
|
||||
const fn is_float_char(c: u8) -> bool {
|
||||
ENCODINGS[c as usize] & FLOAT_CHAR != 0
|
||||
}
|
||||
|
||||
const fn is_ident_first_char(c: u8) -> bool {
|
||||
ENCODINGS[c as usize] & IDENT_FIRST_CHAR != 0
|
||||
}
|
||||
|
||||
const fn is_ident_other_char(c: u8) -> bool {
|
||||
ENCODINGS[c as usize] & IDENT_OTHER_CHAR != 0
|
||||
}
|
||||
|
||||
const fn is_whitespace_char(c: u8) -> bool {
|
||||
ENCODINGS[c as usize] & WHITESPACE_CHAR != 0
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum AnyNum {
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
I8(i8),
|
||||
U8(u8),
|
||||
I16(i16),
|
||||
U16(u16),
|
||||
I32(i32),
|
||||
U32(u32),
|
||||
I64(i64),
|
||||
U64(u64),
|
||||
I128(i128),
|
||||
U128(u128),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Bytes<'a> {
|
||||
|
@ -70,13 +150,168 @@ impl<'a> Bytes<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn any_integer<T: Num>(&mut self, sign: i8) -> Result<T> {
|
||||
let base = if self.peek() == Some(b'0') {
|
||||
match self.bytes.get(1).cloned() {
|
||||
Some(b'x') => 16,
|
||||
Some(b'b') => 2,
|
||||
Some(b'o') => 8,
|
||||
_ => 10,
|
||||
}
|
||||
} else {
|
||||
10
|
||||
};
|
||||
|
||||
if base != 10 {
|
||||
// If we have `0x45A` for example,
|
||||
// cut it to `45A`.
|
||||
let _ = self.advance(2);
|
||||
}
|
||||
|
||||
let num_bytes = self.next_bytes_contained_in(is_int_char);
|
||||
|
||||
if num_bytes == 0 {
|
||||
return self.err(ErrorCode::ExpectedInteger);
|
||||
}
|
||||
|
||||
let s = unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) };
|
||||
|
||||
if s.as_bytes()[0] == b'_' {
|
||||
return self.err(ErrorCode::UnderscoreAtBeginning);
|
||||
}
|
||||
|
||||
fn calc_num<T: Num>(
|
||||
bytes: &Bytes,
|
||||
s: &str,
|
||||
base: u8,
|
||||
mut f: impl FnMut(&mut T, u8) -> bool,
|
||||
) -> Result<T> {
|
||||
let mut num_acc = T::from_u8(0);
|
||||
|
||||
for &byte in s.as_bytes() {
|
||||
if byte == b'_' {
|
||||
continue;
|
||||
}
|
||||
|
||||
if num_acc.checked_mul_ext(base) {
|
||||
return bytes.err(ErrorCode::IntegerOutOfBounds);
|
||||
}
|
||||
|
||||
let digit = bytes.decode_hex(byte)?;
|
||||
|
||||
if digit >= base {
|
||||
return bytes.err(ErrorCode::ExpectedInteger);
|
||||
}
|
||||
|
||||
if f(&mut num_acc, digit) {
|
||||
return bytes.err(ErrorCode::IntegerOutOfBounds);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(num_acc)
|
||||
};
|
||||
|
||||
let res = if sign > 0 {
|
||||
calc_num(&*self, s, base, T::checked_add_ext)
|
||||
} else {
|
||||
calc_num(&*self, s, base, T::checked_sub_ext)
|
||||
};
|
||||
|
||||
let _ = self.advance(num_bytes);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn any_num(&mut self) -> Result<AnyNum> {
|
||||
// We are not doing float comparisons here in the traditional sense.
|
||||
// Instead, this code checks if a f64 fits inside an f32.
|
||||
#[allow(clippy::float_cmp)]
|
||||
fn any_float(f: f64) -> Result<AnyNum> {
|
||||
if f == f as f32 as f64 {
|
||||
Ok(AnyNum::F32(f as f32))
|
||||
} else {
|
||||
Ok(AnyNum::F64(f))
|
||||
}
|
||||
}
|
||||
|
||||
let bytes_backup = self.bytes;
|
||||
|
||||
let first_byte = self.peek_or_eof()?;
|
||||
let is_signed = first_byte == b'-' || first_byte == b'+';
|
||||
let is_float = self.next_bytes_is_float();
|
||||
|
||||
if is_float {
|
||||
let f = self.float::<f64>()?;
|
||||
|
||||
any_float(f)
|
||||
} else {
|
||||
let max_u8 = std::u8::MAX as u128;
|
||||
let max_u16 = std::u16::MAX as u128;
|
||||
let max_u32 = std::u32::MAX as u128;
|
||||
let max_u64 = std::u64::MAX as u128;
|
||||
|
||||
let min_i8 = std::i8::MIN as i128;
|
||||
let max_i8 = std::i8::MAX as i128;
|
||||
let min_i16 = std::i16::MIN as i128;
|
||||
let max_i16 = std::i16::MAX as i128;
|
||||
let min_i32 = std::i32::MIN as i128;
|
||||
let max_i32 = std::i32::MAX as i128;
|
||||
let min_i64 = std::i64::MIN as i128;
|
||||
let max_i64 = std::i64::MAX as i128;
|
||||
|
||||
if is_signed {
|
||||
match self.signed_integer::<i128>() {
|
||||
Ok(x) => {
|
||||
if x >= min_i8 && x <= max_i8 {
|
||||
Ok(AnyNum::I8(x as i8))
|
||||
} else if x >= min_i16 && x <= max_i16 {
|
||||
Ok(AnyNum::I16(x as i16))
|
||||
} else if x >= min_i32 && x <= max_i32 {
|
||||
Ok(AnyNum::I32(x as i32))
|
||||
} else if x >= min_i64 && x <= max_i64 {
|
||||
Ok(AnyNum::I64(x as i64))
|
||||
} else {
|
||||
Ok(AnyNum::I128(x))
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
self.bytes = bytes_backup;
|
||||
|
||||
any_float(self.float::<f64>()?)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match self.unsigned_integer::<u128>() {
|
||||
Ok(x) => {
|
||||
if x <= max_u8 {
|
||||
Ok(AnyNum::U8(x as u8))
|
||||
} else if x <= max_u16 {
|
||||
Ok(AnyNum::U16(x as u16))
|
||||
} else if x <= max_u32 {
|
||||
Ok(AnyNum::U32(x as u32))
|
||||
} else if x <= max_u64 {
|
||||
Ok(AnyNum::U64(x as u64))
|
||||
} else {
|
||||
Ok(AnyNum::U128(x))
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
self.bytes = bytes_backup;
|
||||
|
||||
any_float(self.float::<f64>()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool(&mut self) -> Result<bool> {
|
||||
if self.consume("true") {
|
||||
Ok(true)
|
||||
} else if self.consume("false") {
|
||||
Ok(false)
|
||||
} else {
|
||||
self.err(ParseError::ExpectedBoolean)
|
||||
self.err(ErrorCode::ExpectedBoolean)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +321,7 @@ impl<'a> Bytes<'a> {
|
|||
|
||||
pub fn char(&mut self) -> Result<char> {
|
||||
if !self.consume("'") {
|
||||
return self.err(ParseError::ExpectedChar);
|
||||
return self.err(ErrorCode::ExpectedChar);
|
||||
}
|
||||
|
||||
let c = self.peek_or_eof()?;
|
||||
|
@ -103,15 +338,15 @@ impl<'a> Bytes<'a> {
|
|||
let pos: usize = self.bytes[..max]
|
||||
.iter()
|
||||
.position(|&x| x == b'\'')
|
||||
.ok_or_else(|| self.error(ParseError::ExpectedChar))?;
|
||||
.ok_or_else(|| self.error(ErrorCode::ExpectedChar))?;
|
||||
let s = from_utf8(&self.bytes[0..pos]).map_err(|e| self.error(e.into()))?;
|
||||
let mut chars = s.chars();
|
||||
|
||||
let first = chars
|
||||
.next()
|
||||
.ok_or_else(|| self.error(ParseError::ExpectedChar))?;
|
||||
.ok_or_else(|| self.error(ErrorCode::ExpectedChar))?;
|
||||
if chars.next().is_some() {
|
||||
return self.err(ParseError::ExpectedChar);
|
||||
return self.err(ErrorCode::ExpectedChar);
|
||||
}
|
||||
|
||||
let _ = self.advance(pos);
|
||||
|
@ -120,7 +355,7 @@ impl<'a> Bytes<'a> {
|
|||
};
|
||||
|
||||
if !self.consume("'") {
|
||||
return self.err(ParseError::ExpectedChar);
|
||||
return self.err(ErrorCode::ExpectedChar);
|
||||
}
|
||||
|
||||
Ok(c)
|
||||
|
@ -141,13 +376,13 @@ impl<'a> Bytes<'a> {
|
|||
/// 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_char(ident.len())
|
||||
self.test_for(ident) && !self.check_ident_other_char(ident.len())
|
||||
}
|
||||
|
||||
fn check_ident_char(&self, index: usize) -> bool {
|
||||
fn check_ident_other_char(&self, index: usize) -> bool {
|
||||
self.bytes
|
||||
.get(index)
|
||||
.map_or(false, |b| IDENT_CHAR.contains(b))
|
||||
.map_or(false, |&b| is_ident_other_char(b))
|
||||
}
|
||||
|
||||
/// Should only be used on a working copy
|
||||
|
@ -206,25 +441,23 @@ impl<'a> Bytes<'a> {
|
|||
Ok(peek)
|
||||
}
|
||||
|
||||
pub fn err<T>(&self, kind: ParseError) -> Result<T> {
|
||||
pub fn err<T>(&self, kind: ErrorCode) -> Result<T> {
|
||||
Err(self.error(kind))
|
||||
}
|
||||
|
||||
pub fn error(&self, kind: ParseError) -> Error {
|
||||
Error::Parser(
|
||||
kind,
|
||||
Position {
|
||||
pub fn error(&self, kind: ErrorCode) -> Error {
|
||||
Error {
|
||||
code: kind,
|
||||
position: Position {
|
||||
line: self.line,
|
||||
col: self.column,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_byte(&mut self, byte: u8, error: ParseError) -> Result<()> {
|
||||
self.eat_byte().and_then(|b| match b == byte {
|
||||
true => Ok(()),
|
||||
false => self.err(error),
|
||||
})
|
||||
pub fn expect_byte(&mut self, byte: u8, error: ErrorCode) -> Result<()> {
|
||||
self.eat_byte()
|
||||
.and_then(|b| if b == byte { Ok(()) } else { self.err(error) })
|
||||
}
|
||||
|
||||
/// Returns the extensions bit mask.
|
||||
|
@ -234,7 +467,7 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
|
||||
if !self.consume_all(&["#", "!", "[", "enable", "("])? {
|
||||
return self.err(ParseError::ExpectedAttribute);
|
||||
return self.err(ErrorCode::ExpectedAttribute);
|
||||
}
|
||||
|
||||
self.skip_ws()?;
|
||||
|
@ -243,7 +476,7 @@ impl<'a> Bytes<'a> {
|
|||
loop {
|
||||
let ident = self.identifier()?;
|
||||
let extension = Extensions::from_ident(ident).ok_or_else(|| {
|
||||
self.error(ParseError::NoSuchExtension(
|
||||
self.error(ErrorCode::NoSuchExtension(
|
||||
from_utf8(ident).unwrap().to_owned(),
|
||||
))
|
||||
})?;
|
||||
|
@ -253,23 +486,24 @@ impl<'a> Bytes<'a> {
|
|||
let comma = self.comma()?;
|
||||
|
||||
// If we have no comma but another item, return an error
|
||||
if !comma && self.check_ident_char(0) {
|
||||
return self.err(ParseError::ExpectedComma);
|
||||
if !comma && self.check_ident_other_char(0) {
|
||||
return self.err(ErrorCode::ExpectedComma);
|
||||
}
|
||||
|
||||
// If there's no comma, assume the list ended.
|
||||
// If there is, it might be a trailing one, thus we only
|
||||
// continue the loop if we get an ident char.
|
||||
if !comma || !self.check_ident_char(0) {
|
||||
if !comma || !self.check_ident_other_char(0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.skip_ws()?;
|
||||
|
||||
match self.consume_all(&[")", "]"])? {
|
||||
true => Ok(extensions),
|
||||
false => Err(self.error(ParseError::ExpectedAttributeEnd)),
|
||||
if self.consume_all(&[")", "]"])? {
|
||||
Ok(extensions)
|
||||
} else {
|
||||
Err(self.error(ErrorCode::ExpectedAttributeEnd))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,10 +511,16 @@ impl<'a> Bytes<'a> {
|
|||
where
|
||||
T: FromStr,
|
||||
{
|
||||
let num_bytes = self.next_bytes_contained_in(FLOAT_CHARS);
|
||||
for literal in &["inf", "-inf", "NaN"] {
|
||||
if self.consume_ident(literal) {
|
||||
return FromStr::from_str(literal).map_err(|_| unreachable!()); // must not fail
|
||||
}
|
||||
}
|
||||
|
||||
let num_bytes = self.next_bytes_contained_in(is_float_char);
|
||||
|
||||
let s = unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) };
|
||||
let res = FromStr::from_str(s).map_err(|_| self.error(ParseError::ExpectedFloat));
|
||||
let res = FromStr::from_str(s).map_err(|_| self.error(ErrorCode::ExpectedFloat));
|
||||
|
||||
let _ = self.advance(num_bytes);
|
||||
|
||||
|
@ -297,32 +537,29 @@ impl<'a> Bytes<'a> {
|
|||
|
||||
pub fn identifier_len(&self) -> Result<usize> {
|
||||
let next = self.peek_or_eof()?;
|
||||
if IDENT_FIRST.contains(&next) {
|
||||
if is_ident_first_char(next) {
|
||||
// If the next two bytes signify the start of a raw string literal,
|
||||
// return an error.
|
||||
if next == b'r' {
|
||||
let second = self
|
||||
.bytes
|
||||
.get(1)
|
||||
.ok_or_else(|| self.error(ParseError::Eof))?;
|
||||
.ok_or_else(|| self.error(ErrorCode::Eof))?;
|
||||
if *second == b'"' || *second == b'#' {
|
||||
return self.err(ParseError::ExpectedIdentifier);
|
||||
return self.err(ErrorCode::ExpectedIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
let bytes = self.next_bytes_contained_in(IDENT_CHAR);
|
||||
let bytes = self.next_bytes_contained_in(is_ident_other_char);
|
||||
|
||||
Ok(bytes)
|
||||
} else {
|
||||
self.err(ParseError::ExpectedIdentifier)
|
||||
self.err(ErrorCode::ExpectedIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_bytes_contained_in(&self, allowed: &[u8]) -> usize {
|
||||
self.bytes
|
||||
.iter()
|
||||
.take_while(|b| allowed.contains(b))
|
||||
.count()
|
||||
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 {
|
||||
|
@ -335,13 +572,13 @@ impl<'a> Bytes<'a> {
|
|||
.bytes
|
||||
.iter()
|
||||
.skip(skip)
|
||||
.take_while(|b| FLOAT_CHARS.contains(b))
|
||||
.take_while(|&&b| is_float_char(b))
|
||||
.count();
|
||||
let ilen = self
|
||||
.bytes
|
||||
.iter()
|
||||
.skip(skip)
|
||||
.take_while(|b| DIGITS.contains(b))
|
||||
.take_while(|&&b| is_int_char(b))
|
||||
.count();
|
||||
flen > ilen
|
||||
} else {
|
||||
|
@ -350,7 +587,7 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
|
||||
pub fn skip_ws(&mut self) -> Result<()> {
|
||||
while self.peek().map_or(false, |c| WHITE_SPACE.contains(&c)) {
|
||||
while self.peek().map_or(false, |c| is_whitespace_char(c)) {
|
||||
let _ = self.advance_single();
|
||||
}
|
||||
|
||||
|
@ -369,39 +606,39 @@ impl<'a> Bytes<'a> {
|
|||
self.bytes
|
||||
.get(0)
|
||||
.cloned()
|
||||
.ok_or_else(|| self.error(ParseError::Eof))
|
||||
.ok_or_else(|| self.error(ErrorCode::Eof))
|
||||
}
|
||||
|
||||
pub fn signed_integer<T>(&mut self) -> Result<T>
|
||||
where
|
||||
T: Neg<Output = T> + Num,
|
||||
T: Num,
|
||||
{
|
||||
match self.peek_or_eof()? {
|
||||
b'+' => {
|
||||
let _ = self.advance_single();
|
||||
|
||||
self.unsigned_integer()
|
||||
self.any_integer(1)
|
||||
}
|
||||
b'-' => {
|
||||
let _ = self.advance_single();
|
||||
|
||||
self.unsigned_integer::<T>().map(Neg::neg)
|
||||
self.any_integer(-1)
|
||||
}
|
||||
_ => self.unsigned_integer(),
|
||||
_ => self.any_integer(1),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string(&mut self) -> Result<ParsedStr<'_>> {
|
||||
pub fn string(&mut self) -> Result<ParsedStr<'a>> {
|
||||
if self.consume("\"") {
|
||||
self.escaped_string()
|
||||
} else if self.consume("r") {
|
||||
self.raw_string()
|
||||
} else {
|
||||
self.err(ParseError::ExpectedString)
|
||||
self.err(ErrorCode::ExpectedString)
|
||||
}
|
||||
}
|
||||
|
||||
fn escaped_string(&mut self) -> Result<ParsedStr<'_>> {
|
||||
fn escaped_string(&mut self) -> Result<ParsedStr<'a>> {
|
||||
use std::iter::repeat;
|
||||
|
||||
let (i, end_or_escape) = self
|
||||
|
@ -409,7 +646,7 @@ impl<'a> Bytes<'a> {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, &b)| b == b'\\' || b == b'"')
|
||||
.ok_or_else(|| self.error(ParseError::ExpectedStringEnd))?;
|
||||
.ok_or_else(|| self.error(ErrorCode::ExpectedStringEnd))?;
|
||||
|
||||
if *end_or_escape == b'"' {
|
||||
let s = from_utf8(&self.bytes[..i]).map_err(|e| self.error(e.into()))?;
|
||||
|
@ -440,7 +677,7 @@ impl<'a> Bytes<'a> {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, &b)| b == b'\\' || b == b'"')
|
||||
.ok_or(ParseError::Eof)
|
||||
.ok_or(ErrorCode::Eof)
|
||||
.map_err(|e| self.error(e))?;
|
||||
|
||||
i = new_i;
|
||||
|
@ -456,13 +693,13 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn raw_string(&mut self) -> Result<ParsedStr<'_>> {
|
||||
fn raw_string(&mut self) -> Result<ParsedStr<'a>> {
|
||||
let num_hashes = self.bytes.iter().take_while(|&&b| b == b'#').count();
|
||||
let hashes = &self.bytes[..num_hashes];
|
||||
let _ = self.advance(num_hashes);
|
||||
|
||||
if !self.consume("\"") {
|
||||
return self.err(ParseError::ExpectedString);
|
||||
return self.err(ErrorCode::ExpectedString);
|
||||
}
|
||||
|
||||
let ending = [&[b'"'], hashes].concat();
|
||||
|
@ -470,7 +707,7 @@ impl<'a> Bytes<'a> {
|
|||
.bytes
|
||||
.windows(num_hashes + 1)
|
||||
.position(|window| window == ending.as_slice())
|
||||
.ok_or_else(|| self.error(ParseError::ExpectedStringEnd))?;
|
||||
.ok_or_else(|| self.error(ErrorCode::ExpectedStringEnd))?;
|
||||
|
||||
let s = from_utf8(&self.bytes[..i]).map_err(|e| self.error(e.into()))?;
|
||||
|
||||
|
@ -488,46 +725,7 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
|
||||
pub fn unsigned_integer<T: Num>(&mut self) -> 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(DIGITS);
|
||||
|
||||
if num_bytes == 0 {
|
||||
return self.err(ParseError::ExpectedInteger);
|
||||
}
|
||||
|
||||
let tmp;
|
||||
let mut s = unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) };
|
||||
|
||||
if s.as_bytes()[0] == b'_' {
|
||||
return self.err(ParseError::UnderscoreAtBeginning);
|
||||
}
|
||||
|
||||
if s.contains('_') {
|
||||
tmp = s.replace('_', "");
|
||||
s = &tmp;
|
||||
}
|
||||
|
||||
let res = Num::from_str(s, base).map_err(|_| self.error(ParseError::ExpectedInteger));
|
||||
|
||||
let _ = self.advance(num_bytes);
|
||||
|
||||
res
|
||||
self.any_integer(1)
|
||||
}
|
||||
|
||||
fn decode_ascii_escape(&mut self) -> Result<u8> {
|
||||
|
@ -542,12 +740,13 @@ impl<'a> Bytes<'a> {
|
|||
Ok(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_hex(&self, c: u8) -> Result<u8> {
|
||||
match c {
|
||||
c @ b'0'..=b'9' => Ok(c - b'0'),
|
||||
c @ b'a'..=b'f' => Ok(10 + c - b'a'),
|
||||
c @ b'A'..=b'F' => Ok(10 + c - b'A'),
|
||||
_ => self.err(ParseError::InvalidEscape("Non-hex digit found")),
|
||||
_ => self.err(ErrorCode::InvalidEscape("Non-hex digit found")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,7 +760,7 @@ impl<'a> Bytes<'a> {
|
|||
b't' => '\t',
|
||||
b'x' => self.decode_ascii_escape()? as char,
|
||||
b'u' => {
|
||||
self.expect_byte(b'{', ParseError::InvalidEscape("Missing {"))?;
|
||||
self.expect_byte(b'{', ErrorCode::InvalidEscape("Missing {"))?;
|
||||
|
||||
let mut bytes: u32 = 0;
|
||||
let mut num_digits = 0;
|
||||
|
@ -583,18 +782,17 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
|
||||
if num_digits == 0 {
|
||||
return self.err(ParseError::InvalidEscape(
|
||||
return self.err(ErrorCode::InvalidEscape(
|
||||
"Expected 1-6 digits, got 0 digits",
|
||||
));
|
||||
}
|
||||
|
||||
self.expect_byte(b'}', ParseError::InvalidEscape("No } at the end"))?;
|
||||
let character = char_from_u32(bytes)
|
||||
.ok_or_else(|| self.error(ParseError::InvalidEscape("Not a valid char")))?;
|
||||
character
|
||||
self.expect_byte(b'}', ErrorCode::InvalidEscape("No } at the end"))?;
|
||||
char_from_u32(bytes)
|
||||
.ok_or_else(|| self.error(ErrorCode::InvalidEscape("Not a valid char")))?
|
||||
}
|
||||
_ => {
|
||||
return self.err(ParseError::InvalidEscape("Unknown escape character"));
|
||||
return self.err(ErrorCode::InvalidEscape("Unknown escape character"));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -620,7 +818,7 @@ impl<'a> Bytes<'a> {
|
|||
.count();
|
||||
|
||||
if self.bytes.is_empty() {
|
||||
return self.err(ParseError::UnclosedBlockComment);
|
||||
return self.err(ErrorCode::UnclosedBlockComment);
|
||||
}
|
||||
|
||||
let _ = self.advance(bytes);
|
||||
|
@ -632,11 +830,11 @@ impl<'a> Bytes<'a> {
|
|||
level -= 1;
|
||||
} else {
|
||||
self.eat_byte()
|
||||
.map_err(|_| self.error(ParseError::UnclosedBlockComment))?;
|
||||
.map_err(|_| self.error(ErrorCode::UnclosedBlockComment))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
b => return self.err(ParseError::UnexpectedByte(b as char)),
|
||||
b => return self.err(ErrorCode::UnexpectedByte(b as char)),
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
|
@ -646,33 +844,54 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct Extensions: usize {
|
||||
const UNWRAP_NEWTYPES = 0x1;
|
||||
const IMPLICIT_SOME = 0x2;
|
||||
}
|
||||
}
|
||||
pub trait Num {
|
||||
fn from_u8(x: u8) -> Self;
|
||||
|
||||
impl Extensions {
|
||||
/// Creates an extension flag from an ident.
|
||||
pub fn from_ident(ident: &[u8]) -> Option<Extensions> {
|
||||
match ident {
|
||||
b"unwrap_newtypes" => Some(Extensions::UNWRAP_NEWTYPES),
|
||||
b"implicit_some" => Some(Extensions::IMPLICIT_SOME),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Returns `true` on overflow
|
||||
fn checked_mul_ext(&mut self, x: u8) -> bool;
|
||||
|
||||
pub trait Num: Sized {
|
||||
fn from_str(src: &str, radix: u32) -> StdResult<Self, ()>;
|
||||
/// 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_str(src: &str, radix: u32) -> StdResult<Self, ()> {
|
||||
$ty::from_str_radix(src, radix).map_err(|_| ())
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -681,7 +900,7 @@ macro_rules! impl_num {
|
|||
};
|
||||
}
|
||||
|
||||
impl_num!(u8 u16 u32 u64 i8 i16 i32 i64);
|
||||
impl_num!(u8 u16 u32 u64 u128 i8 i16 i32 i64 i128);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ParsedStr<'a> {
|
||||
|
@ -691,8 +910,8 @@ pub enum ParsedStr<'a> {
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Position {
|
||||
pub col: usize,
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
}
|
||||
|
||||
impl Display for Position {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,6 +1,6 @@
|
|||
use serde::ser::{Serialize, Serializer};
|
||||
|
||||
use crate::value::Value;
|
||||
use crate::value::{Number, Value};
|
||||
|
||||
impl Serialize for Value {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
|
@ -11,7 +11,8 @@ impl Serialize for Value {
|
|||
Value::Bool(b) => serializer.serialize_bool(b),
|
||||
Value::Char(c) => serializer.serialize_char(c),
|
||||
Value::Map(ref m) => Serialize::serialize(m, serializer),
|
||||
Value::Number(ref n) => serializer.serialize_f64(n.get()),
|
||||
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),
|
||||
|
|
|
@ -2,32 +2,151 @@
|
|||
|
||||
use serde::{
|
||||
de::{
|
||||
DeserializeOwned, DeserializeSeed, Deserializer, Error as SerdeError, MapAccess, SeqAccess, Visitor,
|
||||
DeserializeOwned, DeserializeSeed, Deserializer, Error as SerdeError, MapAccess, SeqAccess,
|
||||
Visitor,
|
||||
},
|
||||
forward_to_deserialize_any,
|
||||
forward_to_deserialize_any, Deserialize, Serialize,
|
||||
};
|
||||
use std::{
|
||||
cmp::{Eq, Ordering},
|
||||
collections::BTreeMap,
|
||||
hash::{Hash, Hasher},
|
||||
iter::FromIterator,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
use crate::de::{Error as RonError, Result};
|
||||
|
||||
/// A wrapper for `f64` which guarantees that the inner value
|
||||
/// A `Value` to `Value` map.
|
||||
///
|
||||
/// This structure either uses a [BTreeMap](std::collections::BTreeMap) or the
|
||||
/// [IndexMap](indexmap::IndexMap) internally.
|
||||
/// The latter can be used by enabling the `indexmap` feature. This can be used
|
||||
/// to preserve the order of the parsed map.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
pub struct Map(MapInner);
|
||||
|
||||
impl Map {
|
||||
/// Creates a new, empty `Map`.
|
||||
pub fn new() -> Map {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the map.
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if `self.len() == 0`, `false` otherwise.
|
||||
pub fn is_empty(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Inserts a new element, returning the previous element with this `key` if
|
||||
/// there was any.
|
||||
pub fn insert(&mut self, key: Value, value: Value) -> Option<Value> {
|
||||
self.0.insert(key, value)
|
||||
}
|
||||
|
||||
/// Removes an element by its `key`.
|
||||
pub fn remove(&mut self, key: &Value) -> Option<Value> {
|
||||
self.0.remove(key)
|
||||
}
|
||||
|
||||
/// Iterate all key-value pairs.
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&Value, &Value)> + DoubleEndedIterator {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
/// Iterate all key-value pairs mutably.
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Value, &mut Value)> + DoubleEndedIterator {
|
||||
self.0.iter_mut()
|
||||
}
|
||||
|
||||
/// Iterate all keys.
|
||||
pub fn keys(&self) -> impl Iterator<Item = &Value> + DoubleEndedIterator {
|
||||
self.0.keys()
|
||||
}
|
||||
|
||||
/// Iterate all values.
|
||||
pub fn values(&self) -> impl Iterator<Item = &Value> + DoubleEndedIterator {
|
||||
self.0.values()
|
||||
}
|
||||
|
||||
/// Iterate all values mutably.
|
||||
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut Value> + DoubleEndedIterator {
|
||||
self.0.values_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<(Value, Value)> for Map {
|
||||
fn from_iter<T: IntoIterator<Item = (Value, Value)>>(iter: T) -> Self {
|
||||
Map(MapInner::from_iter(iter))
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: equality is only given if both values and order of values match
|
||||
impl Eq for Map {}
|
||||
|
||||
impl Hash for Map {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.iter().for_each(|x| x.hash(state));
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<&Value> for Map {
|
||||
type Output = Value;
|
||||
|
||||
fn index(&self, index: &Value) -> &Self::Output {
|
||||
&self.0[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<&Value> for Map {
|
||||
fn index_mut(&mut self, index: &Value) -> &mut Self::Output {
|
||||
self.0.get_mut(index).expect("no entry found for key")
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Map {
|
||||
fn cmp(&self, other: &Map) -> Ordering {
|
||||
self.iter().cmp(other.iter())
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: equality is only given if both values and order of values match
|
||||
impl PartialEq for Map {
|
||||
fn eq(&self, other: &Map) -> bool {
|
||||
self.iter().zip(other.iter()).all(|(a, b)| a == b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Map {
|
||||
fn partial_cmp(&self, other: &Map) -> Option<Ordering> {
|
||||
self.iter().partial_cmp(other.iter())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "indexmap"))]
|
||||
type MapInner = std::collections::BTreeMap<Value, Value>;
|
||||
#[cfg(feature = "indexmap")]
|
||||
type MapInner = indexmap::IndexMap<Value, Value>;
|
||||
|
||||
/// A wrapper for a number, which can be either `f64` or `i64`.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
|
||||
pub enum Number {
|
||||
Integer(i64),
|
||||
Float(Float),
|
||||
}
|
||||
|
||||
/// A wrapper for `f64`, which guarantees that the inner value
|
||||
/// is finite and thus implements `Eq`, `Hash` and `Ord`.
|
||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||
pub struct Number(f64);
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Float(f64);
|
||||
|
||||
impl Number {
|
||||
/// Panics if `v` is not a real number
|
||||
/// (infinity, NaN, ..).
|
||||
impl Float {
|
||||
/// Construct a new `Float`.
|
||||
pub fn new(v: f64) -> Self {
|
||||
if !v.is_finite() {
|
||||
panic!("Tried to create Number with a NaN / infinity");
|
||||
}
|
||||
|
||||
Number(v)
|
||||
Float(v)
|
||||
}
|
||||
|
||||
/// Returns the wrapped float.
|
||||
|
@ -36,15 +155,160 @@ impl Number {
|
|||
}
|
||||
}
|
||||
|
||||
impl Eq for Number {}
|
||||
impl Number {
|
||||
/// Construct a new number.
|
||||
pub fn new(v: impl Into<Number>) -> Self {
|
||||
v.into()
|
||||
}
|
||||
|
||||
impl Hash for Number {
|
||||
/// Returns the `f64` representation of the number regardless of whether the number is stored
|
||||
/// as a float or integer.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use ron::value::Number;
|
||||
/// let i = Number::new(5);
|
||||
/// let f = Number::new(2.0);
|
||||
/// assert_eq!(i.into_f64(), 5.0);
|
||||
/// assert_eq!(f.into_f64(), 2.0);
|
||||
/// ```
|
||||
pub fn into_f64(self) -> f64 {
|
||||
self.map_to(|i| i as f64, |f| f)
|
||||
}
|
||||
|
||||
/// If the `Number` is a float, return it. Otherwise return `None`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use ron::value::Number;
|
||||
/// let i = Number::new(5);
|
||||
/// let f = Number::new(2.0);
|
||||
/// assert_eq!(i.as_f64(), None);
|
||||
/// assert_eq!(f.as_f64(), Some(2.0));
|
||||
/// ```
|
||||
pub fn as_f64(self) -> Option<f64> {
|
||||
self.map_to(|_| None, Some)
|
||||
}
|
||||
|
||||
/// If the `Number` is an integer, return it. Otherwise return `None`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use ron::value::Number;
|
||||
/// let i = Number::new(5);
|
||||
/// let f = Number::new(2.0);
|
||||
/// assert_eq!(i.as_i64(), Some(5));
|
||||
/// assert_eq!(f.as_i64(), None);
|
||||
/// ```
|
||||
pub fn as_i64(self) -> Option<i64> {
|
||||
self.map_to(Some, |_| None)
|
||||
}
|
||||
|
||||
/// Map this number to a single type using the appropriate closure.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use ron::value::Number;
|
||||
/// let i = Number::new(5);
|
||||
/// let f = Number::new(2.0);
|
||||
/// assert!(i.map_to(|i| i > 3, |f| f > 3.0));
|
||||
/// assert!(!f.map_to(|i| i > 3, |f| f > 3.0));
|
||||
/// ```
|
||||
pub fn map_to<T>(
|
||||
self,
|
||||
integer_fn: impl FnOnce(i64) -> T,
|
||||
float_fn: impl FnOnce(f64) -> T,
|
||||
) -> T {
|
||||
match self {
|
||||
Number::Integer(i) => integer_fn(i),
|
||||
Number::Float(Float(f)) => float_fn(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Number {
|
||||
fn from(f: f64) -> Number {
|
||||
Number::Float(Float(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Number {
|
||||
fn from(i: i64) -> Number {
|
||||
Number::Integer(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Number {
|
||||
fn from(i: i32) -> Number {
|
||||
Number::Integer(i as i64)
|
||||
}
|
||||
}
|
||||
|
||||
// The following number conversion checks if the integer fits losslessly into an i64, before
|
||||
// constructing a Number::Integer variant. If not, the conversion defaults to float.
|
||||
|
||||
impl From<u64> for Number {
|
||||
fn from(i: u64) -> Number {
|
||||
if i as i64 as u64 == i {
|
||||
Number::Integer(i as i64)
|
||||
} else {
|
||||
Number::new(i as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Partial equality comparison
|
||||
/// In order to be able to use `Number` as a mapping key, NaN floating values
|
||||
/// wrapped in `Float` are equals to each other. It is not the case for
|
||||
/// underlying `f64` values itself.
|
||||
impl PartialEq for Float {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.is_nan() && other.0.is_nan() || self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Equality comparison
|
||||
/// In order to be able to use `Float` as a mapping key, NaN floating values
|
||||
/// wrapped in `Float` are equals to each other. It is not the case for
|
||||
/// underlying `f64` values itself.
|
||||
impl Eq for Float {}
|
||||
|
||||
impl Hash for Float {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
state.write_u64(self.0 as u64);
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Number {
|
||||
/// 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")
|
||||
}
|
||||
|
@ -54,7 +318,7 @@ impl Ord for Number {
|
|||
pub enum Value {
|
||||
Bool(bool),
|
||||
Char(char),
|
||||
Map(BTreeMap<Value, Value>),
|
||||
Map(Map),
|
||||
Number(Number),
|
||||
Option(Option<Box<Value>>),
|
||||
String(String),
|
||||
|
@ -90,11 +354,12 @@ impl<'de> Deserializer<'de> for Value {
|
|||
match self {
|
||||
Value::Bool(b) => visitor.visit_bool(b),
|
||||
Value::Char(c) => visitor.visit_char(c),
|
||||
Value::Map(m) => visitor.visit_map(Map {
|
||||
Value::Map(m) => visitor.visit_map(MapAccessor {
|
||||
keys: m.keys().cloned().rev().collect(),
|
||||
values: m.values().cloned().rev().collect(),
|
||||
}),
|
||||
Value::Number(n) => visitor.visit_f64(n.get()),
|
||||
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),
|
||||
|
@ -132,7 +397,7 @@ impl<'de> Deserializer<'de> for Value {
|
|||
V: Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Value::Number(n) => visitor.visit_i64(n.get() as i64),
|
||||
Value::Number(Number::Integer(i)) => visitor.visit_i64(i),
|
||||
v => Err(RonError::custom(format!("Expected a number, got {:?}", v))),
|
||||
}
|
||||
}
|
||||
|
@ -163,18 +428,18 @@ impl<'de> Deserializer<'de> for Value {
|
|||
V: Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Value::Number(n) => visitor.visit_u64(n.get() as u64),
|
||||
Value::Number(Number::Integer(i)) => visitor.visit_u64(i as u64),
|
||||
v => Err(RonError::custom(format!("Expected a number, got {:?}", v))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Map {
|
||||
struct MapAccessor {
|
||||
keys: Vec<Value>,
|
||||
values: Vec<Value>,
|
||||
}
|
||||
|
||||
impl<'de> MapAccess<'de> for Map {
|
||||
impl<'de> MapAccess<'de> for MapAccessor {
|
||||
type Error = RonError;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
|
||||
|
@ -221,7 +486,7 @@ impl<'de> SeqAccess<'de> for Seq {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use serde::Deserialize;
|
||||
use std::fmt::Debug;
|
||||
use std::{collections::BTreeMap, fmt::Debug};
|
||||
|
||||
fn assert_same<'de, T>(s: &'de str)
|
||||
where
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#[cfg(feature = "indexmap")]
|
||||
use ron::{de::from_str, Value};
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "indexmap")]
|
||||
fn test_order_preserved() {
|
||||
let file = r#"(
|
||||
tasks: {
|
||||
"debug message": Dbg(
|
||||
msg: "test message. some text after it."
|
||||
),
|
||||
"shell command": Shell(
|
||||
command: "ls",
|
||||
args: Some([
|
||||
"-l",
|
||||
"-h",
|
||||
]),
|
||||
ch_dir: Some("/"),
|
||||
),
|
||||
},
|
||||
)
|
||||
"#;
|
||||
|
||||
let value: Value = from_str(file).unwrap();
|
||||
match value {
|
||||
Value::Map(map) => match &map[&Value::String("tasks".to_owned())] {
|
||||
Value::Map(map) => {
|
||||
assert_eq!(
|
||||
*map.keys().next().unwrap(),
|
||||
Value::String("debug message".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
*map.keys().skip(1).next().unwrap(),
|
||||
Value::String("shell command".to_string())
|
||||
);
|
||||
}
|
||||
_ => panic!(),
|
||||
},
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
let file = r#"(
|
||||
tasks: {
|
||||
"shell command": Shell(
|
||||
command: "ls",
|
||||
args: Some([
|
||||
"-l",
|
||||
"-h",
|
||||
]),
|
||||
ch_dir: Some("/")
|
||||
),
|
||||
"debug message": Dbg(
|
||||
msg: "test message. some text after it."
|
||||
),
|
||||
}
|
||||
)
|
||||
"#;
|
||||
|
||||
let value: Value = from_str(file).unwrap();
|
||||
match value {
|
||||
Value::Map(map) => match &map[&Value::String("tasks".to_owned())] {
|
||||
Value::Map(map) => {
|
||||
assert_eq!(
|
||||
*map.keys().next().unwrap(),
|
||||
Value::String("shell command".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
*map.keys().skip(1).next().unwrap(),
|
||||
Value::String("debug message".to_string())
|
||||
);
|
||||
}
|
||||
_ => panic!(),
|
||||
},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
|
@ -41,10 +41,9 @@ fn empty_sets_arrays() {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
let pretty = ron::ser::PrettyConfig {
|
||||
enumerate_arrays: true,
|
||||
..Default::default()
|
||||
};
|
||||
let pretty = ron::ser::PrettyConfig::new()
|
||||
.with_enumerate_arrays(true)
|
||||
.with_new_line("\n".to_string());
|
||||
let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
|
||||
|
||||
println!("Serialized: {}", serial);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
use ron::ser::{to_string_pretty, PrettyConfig};
|
||||
|
||||
#[test]
|
||||
fn small_array() {
|
||||
let arr = &[(), (), ()][..];
|
||||
assert_eq!(
|
||||
to_string_pretty(&arr, PrettyConfig::new().with_new_line("\n".to_string())).unwrap(),
|
||||
"[
|
||||
(),
|
||||
(),
|
||||
(),
|
||||
]"
|
||||
);
|
||||
}
|
|
@ -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" })
|
||||
);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use ron::de::{from_str, Error as RonErr, ParseError, Position};
|
||||
use ron::de::{from_str, Error as RonErr, ErrorCode, Position};
|
||||
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
|
@ -44,9 +44,9 @@ fn test_unclosed() {
|
|||
\"THE VALUE (which is invalid)\"
|
||||
"
|
||||
),
|
||||
Err(RonErr::Parser(
|
||||
ParseError::UnclosedBlockComment,
|
||||
Position { col: 1, line: 9 }
|
||||
))
|
||||
Err(RonErr {
|
||||
code: ErrorCode::UnclosedBlockComment,
|
||||
position: Position { col: 1, line: 9 }
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,12 +26,12 @@ struct Nested {
|
|||
}
|
||||
|
||||
const EXPECTED: &str = "(
|
||||
float: (2.18,-1.1,),
|
||||
tuple: ((),false,),
|
||||
map: {8:'1',},
|
||||
nested: (a:\"a\",b:'b',),
|
||||
var: A(255,\"\",),
|
||||
array: [(),(),(),],
|
||||
float: (2.18,-1.1),
|
||||
tuple: ((),false),
|
||||
map: {8:'1'},
|
||||
nested: (a:\"a\",b:'b'),
|
||||
var: A(255,\"\"),
|
||||
array: [(),(),()],
|
||||
)";
|
||||
|
||||
#[test]
|
||||
|
@ -48,12 +48,11 @@ fn depth_limit() {
|
|||
array: vec![(); 3],
|
||||
};
|
||||
|
||||
let pretty = ron::ser::PrettyConfig {
|
||||
depth_limit: 2,
|
||||
separate_tuple_members: true,
|
||||
enumerate_arrays: true,
|
||||
..Default::default()
|
||||
};
|
||||
let pretty = ron::ser::PrettyConfig::new()
|
||||
.with_depth_limit(1)
|
||||
.with_separate_tuple_members(true)
|
||||
.with_enumerate_arrays(true)
|
||||
.with_new_line("\n".to_string());
|
||||
let s = ron::ser::to_string_pretty(&data, pretty);
|
||||
|
||||
assert_eq!(s, Ok(EXPECTED.to_string()));
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
use ron::{
|
||||
de::from_str,
|
||||
ser::{to_string_pretty, PrettyConfig},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_inf_and_nan() {
|
||||
assert_eq!(from_str("inf"), Ok(std::f64::INFINITY));
|
||||
assert_eq!(from_str("-inf"), Ok(std::f64::NEG_INFINITY));
|
||||
assert_eq!(from_str::<f64>("NaN").map(|n| n.is_nan()), Ok(true))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decimal_floats() {
|
||||
let pretty = PrettyConfig::new().with_decimal_floats(false);
|
||||
let without_decimal = to_string_pretty(&1.0, pretty).unwrap();
|
||||
assert_eq!(without_decimal, "1");
|
||||
|
||||
let pretty = PrettyConfig::new().with_decimal_floats(false);
|
||||
let without_decimal = to_string_pretty(&1.1, pretty).unwrap();
|
||||
assert_eq!(without_decimal, "1.1");
|
||||
|
||||
let pretty = PrettyConfig::new().with_decimal_floats(true);
|
||||
let with_decimal = to_string_pretty(&1.0, pretty).unwrap();
|
||||
assert_eq!(with_decimal, "1.0");
|
||||
|
||||
let pretty = PrettyConfig::new().with_decimal_floats(true);
|
||||
let with_decimal = to_string_pretty(&1.1, pretty).unwrap();
|
||||
assert_eq!(with_decimal, "1.1");
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
use ron::value::Number;
|
||||
|
||||
#[test]
|
||||
fn test_large_number() {
|
||||
use ron::value::Value;
|
||||
let test_var = Value::Number(Number::new(10000000000000000000000.0f64));
|
||||
let test_ser = ron::ser::to_string(&test_var).unwrap();
|
||||
let test_deser = ron::de::from_str::<Value>(&test_ser);
|
||||
|
||||
assert_eq!(
|
||||
test_deser.unwrap(),
|
||||
Value::Number(Number::new(10000000000000000000000.0))
|
||||
);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
use ron::{de::*, ser::*};
|
||||
|
||||
#[test]
|
||||
fn test_i32_min() {
|
||||
assert_eq!(
|
||||
std::i32::MIN,
|
||||
from_str(&to_string(&std::i32::MIN).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i32_max() {
|
||||
assert_eq!(
|
||||
std::i32::MAX,
|
||||
from_str(&to_string(&std::i32::MAX).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i64_min() {
|
||||
assert_eq!(
|
||||
std::i64::MIN,
|
||||
from_str(&to_string(&std::i64::MIN).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i64_max() {
|
||||
assert_eq!(
|
||||
std::i64::MAX,
|
||||
from_str(&to_string(&std::i64::MAX).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i128_min() {
|
||||
assert_eq!(
|
||||
std::i128::MIN,
|
||||
from_str(&to_string(&std::i128::MIN).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i128_max() {
|
||||
assert_eq!(
|
||||
std::i128::MAX,
|
||||
from_str(&to_string(&std::i128::MAX).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u128_min() {
|
||||
assert_eq!(
|
||||
std::u128::MIN,
|
||||
from_str(&to_string(&std::u128::MIN).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u128_max() {
|
||||
assert_eq!(
|
||||
std::u128::MAX,
|
||||
from_str(&to_string(&std::u128::MAX).unwrap()).unwrap()
|
||||
);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
use ron::{
|
||||
de::from_str,
|
||||
ser::{to_string_pretty, PrettyConfig},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Config {
|
||||
boolean: bool,
|
||||
float: f32,
|
||||
map: BTreeMap<u8, char>,
|
||||
nested: Nested,
|
||||
tuple: (u32, u32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Nested {
|
||||
a: String,
|
||||
b: char,
|
||||
}
|
||||
|
||||
fn read_original(source: &str) -> String {
|
||||
source.to_string().replace("\r\n", "\n")
|
||||
}
|
||||
|
||||
fn make_roundtrip(source: &str) -> String {
|
||||
let config: Config = match from_str(source) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
println!("Failed to load config: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
let pretty = PrettyConfig::new()
|
||||
.with_depth_limit(3)
|
||||
.with_separate_tuple_members(true)
|
||||
.with_enumerate_arrays(true)
|
||||
.with_new_line("\n".into());
|
||||
to_string_pretty(&config, pretty).expect("Serialization failed")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequence_ex1() {
|
||||
let file = include_str!("preserve_sequence_ex1.ron");
|
||||
assert_eq!(read_original(file), make_roundtrip(file));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequence_ex2() {
|
||||
let file = include_str!("preserve_sequence_ex2.ron");
|
||||
assert_eq!(read_original(file), make_roundtrip(file));
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
(
|
||||
boolean: true,
|
||||
float: 8.2,
|
||||
map: {
|
||||
1: '1',
|
||||
},
|
||||
nested: (
|
||||
a: "Decode me!",
|
||||
b: 'z',
|
||||
),
|
||||
tuple: (
|
||||
3,
|
||||
7,
|
||||
),
|
||||
)
|
|
@ -1,6 +1,8 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ron::extensions::Extensions;
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||
struct UnitStruct;
|
||||
|
||||
|
@ -66,10 +68,9 @@ fn roundtrip_pretty() {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
let pretty = ron::ser::PrettyConfig {
|
||||
enumerate_arrays: true,
|
||||
..Default::default()
|
||||
};
|
||||
let pretty = ron::ser::PrettyConfig::new()
|
||||
.with_enumerate_arrays(true)
|
||||
.with_extensions(Extensions::IMPLICIT_SOME);
|
||||
let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
|
||||
|
||||
println!("Serialized: {}", serial);
|
||||
|
@ -109,13 +110,7 @@ fn roundtrip_sep_tuple_members() {
|
|||
|
||||
let value = Both { a, b };
|
||||
|
||||
let pretty = ron::ser::PrettyConfig {
|
||||
depth_limit: !0,
|
||||
new_line: "\n".to_owned(),
|
||||
indentor: " ".to_owned(),
|
||||
separate_tuple_members: true,
|
||||
enumerate_arrays: false,
|
||||
};
|
||||
let pretty = ron::ser::PrettyConfig::new().with_separate_tuple_members(true);
|
||||
let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
|
||||
|
||||
println!("Serialized: {}", serial);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
struct S {
|
||||
a: i8,
|
||||
b: i16,
|
||||
c: i32,
|
||||
d: i64,
|
||||
e: i128,
|
||||
f: u8,
|
||||
g: u16,
|
||||
h: u32,
|
||||
i: u64,
|
||||
j: u128,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip() {
|
||||
let s = S {
|
||||
a: std::i8::MIN,
|
||||
b: std::i16::MIN,
|
||||
c: std::i32::MIN,
|
||||
d: std::i64::MIN,
|
||||
e: std::i128::MIN,
|
||||
f: std::u8::MAX,
|
||||
g: std::u16::MAX,
|
||||
h: std::u32::MAX,
|
||||
i: std::u64::MAX,
|
||||
j: std::u128::MAX,
|
||||
};
|
||||
let serialized = ron::ser::to_string(&s).unwrap();
|
||||
dbg!(&serialized);
|
||||
let deserialized = ron::de::from_str(&serialized).unwrap();
|
||||
assert_eq!(s, deserialized,);
|
||||
}
|
|
@ -1,64 +1,57 @@
|
|||
use ron::value::{Number, Value};
|
||||
use ron::value::{Map, Number, Value};
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
fn bool() {
|
||||
assert_eq!(Value::from_str("true"), Ok(Value::Bool(true)));
|
||||
assert_eq!(Value::from_str("false"), Ok(Value::Bool(false)));
|
||||
assert_eq!("true".parse(), Ok(Value::Bool(true)));
|
||||
assert_eq!("false".parse(), Ok(Value::Bool(false)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char() {
|
||||
assert_eq!(Value::from_str("'a'"), Ok(Value::Char('a')));
|
||||
assert_eq!("'a'".parse(), Ok(Value::Char('a')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map() {
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(Value::Char('a'), Value::Number(Number::new(1f64)));
|
||||
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!(Value::from_str("{ 'a': 1, 'b': 2 }"), Ok(Value::Map(map)));
|
||||
assert_eq!("{ 'a': 1, 'b': 2.0 }".parse(), Ok(Value::Map(map)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn number() {
|
||||
assert_eq!(Value::from_str("42"), Ok(Value::Number(Number::new(42f64))));
|
||||
assert_eq!(
|
||||
Value::from_str("3.1415"),
|
||||
Ok(Value::Number(Number::new(3.1415f64)))
|
||||
);
|
||||
assert_eq!("42".parse(), Ok(Value::Number(Number::new(42))));
|
||||
assert_eq!("3.1415".parse(), Ok(Value::Number(Number::new(3.1415f64))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
let opt = Some(Box::new(Value::Char('c')));
|
||||
assert_eq!(Value::from_str("Some('c')"), Ok(Value::Option(opt)));
|
||||
assert_eq!("Some('c')".parse(), Ok(Value::Option(opt)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string() {
|
||||
let normal = "\"String\"";
|
||||
assert_eq!(Value::from_str(normal), Ok(Value::String("String".into())));
|
||||
assert_eq!(normal.parse(), Ok(Value::String("String".into())));
|
||||
|
||||
let raw = "r\"Raw String\"";
|
||||
assert_eq!(Value::from_str(raw), Ok(Value::String("Raw String".into())));
|
||||
assert_eq!(raw.parse(), Ok(Value::String("Raw String".into())));
|
||||
|
||||
let raw_hashes = "r#\"Raw String\"#";
|
||||
assert_eq!(
|
||||
Value::from_str(raw_hashes),
|
||||
Ok(Value::String("Raw String".into()))
|
||||
);
|
||||
assert_eq!(raw_hashes.parse(), Ok(Value::String("Raw String".into())));
|
||||
|
||||
let raw_escaped = "r##\"Contains \"#\"##";
|
||||
assert_eq!(
|
||||
Value::from_str(raw_escaped),
|
||||
raw_escaped.parse(),
|
||||
Ok(Value::String("Contains \"#".into()))
|
||||
);
|
||||
|
||||
let raw_multi_line = "r\"Multi\nLine\"";
|
||||
assert_eq!(
|
||||
Value::from_str(raw_multi_line),
|
||||
raw_multi_line.parse(),
|
||||
Ok(Value::String("Multi\nLine".into()))
|
||||
);
|
||||
}
|
||||
|
@ -66,22 +59,25 @@ fn string() {
|
|||
#[test]
|
||||
fn seq() {
|
||||
let seq = vec![
|
||||
Value::Number(Number::new(1f64)),
|
||||
Value::Number(Number::new(1)),
|
||||
Value::Number(Number::new(2f64)),
|
||||
];
|
||||
assert_eq!(Value::from_str("[1, 2]"), Ok(Value::Seq(seq)));
|
||||
assert_eq!("[1, 2.0]".parse(), Ok(Value::Seq(seq)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
use ron::de::{Error, ParseError, Position};
|
||||
use ron::error::{Error, ErrorCode, Position};
|
||||
|
||||
assert_eq!(Value::from_str("()"), Ok(Value::Unit));
|
||||
assert_eq!(Value::from_str("Foo"), Ok(Value::Unit));
|
||||
assert_eq!("()".parse(), Ok(Value::Unit));
|
||||
assert_eq!("Foo".parse(), Ok(Value::Unit));
|
||||
|
||||
assert_eq!(
|
||||
Value::from_str(""),
|
||||
Err(Error::Parser(ParseError::Eof, Position { col: 1, line: 1 }))
|
||||
"".parse::<Value>(),
|
||||
Err(Error {
|
||||
code: ErrorCode::Eof,
|
||||
position: Position { col: 1, line: 1 }
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче