зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1634439 - Update RON dependency to 0.5 r=aosmond
Differential Revision: https://phabricator.services.mozilla.com/D73291
This commit is contained in:
Родитель
795e06301c
Коммит
5fd43ff44d
|
@ -3884,10 +3884,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ron"
|
name = "ron"
|
||||||
version = "0.1.7"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
|
checksum = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64 0.10.1",
|
||||||
|
"bitflags",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1323,9 +1323,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ron"
|
name = "ron"
|
||||||
version = "0.1.7"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64 0.10.1 (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)",
|
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1590,7 +1592,7 @@ name = "tileview"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.106 (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 0.61.0",
|
||||||
"webrender_api 0.61.0",
|
"webrender_api 0.61.0",
|
||||||
|
@ -1775,7 +1777,7 @@ dependencies = [
|
||||||
"png 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.106 (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)",
|
"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)",
|
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1933,7 +1935,7 @@ dependencies = [
|
||||||
"mozangle 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mozangle 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)",
|
"osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)",
|
||||||
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.106 (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)",
|
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2157,7 +2159,7 @@ dependencies = [
|
||||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
"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 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 regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||||
"checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
|
"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
|
||||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
"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 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"
|
"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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ron = "0.1.7"
|
ron = "0.5"
|
||||||
serde = {version = "1.0.88", features = ["derive"] }
|
serde = {version = "1.0.88", features = ["derive"] }
|
||||||
webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler","no_static_freetype", "leak_checks"]}
|
webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler","no_static_freetype", "leak_checks"]}
|
||||||
webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]}
|
webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]}
|
||||||
|
|
|
@ -43,7 +43,7 @@ num-traits = "0.2"
|
||||||
plane-split = "0.15"
|
plane-split = "0.15"
|
||||||
png = { optional = true, version = "0.16" }
|
png = { optional = true, version = "0.16" }
|
||||||
rayon = "1"
|
rayon = "1"
|
||||||
ron = { optional = true, version = "0.1.7" }
|
ron = { optional = true, version = "0.5" }
|
||||||
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
|
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
|
||||||
serde_json = { optional = true, version = "1.0" }
|
serde_json = { optional = true, version = "1.0" }
|
||||||
smallvec = "1"
|
smallvec = "1"
|
||||||
|
|
|
@ -19,7 +19,7 @@ clap = { version = "2", features = ["yaml"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
yaml-rust = "0.4"
|
yaml-rust = "0.4"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
ron = "0.1.5"
|
ron = "0.5"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
chrono = "0.2"
|
chrono = "0.2"
|
||||||
crossbeam = "0.2"
|
crossbeam = "0.2"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"3084630437ca5b2ff223cc0aa4e6329250ccc599723cf0711c89979165a52721","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"fa0598d520497731445a5bc89a2b3d47896d95568bd2be255b7bc43d771b9994","README.md":"87cac8cd8c6d9ceb66802f9c810df6583762942567eff7baf71d4ad700df93ec","examples/decode.rs":"70e1eacea082e17dd57ce731c6963c8166aa161445857c1032819d87d89ce067","examples/decode_file.rs":"d046edcee9339855e3fca0d81cb75bf227a0f12a836faa46ee5420f78df14e51","examples/encode.rs":"502f79332a47950bcc172295e50665ff87d57dc68707d497a4dd9ccb5fcd298f","examples/example.ron":"c3355fcb6ee48f32da62ff56040dc69a69730c24f55e7744e235a28aa66a560e","examples/transcode.rs":"5cae0549acf44d522a1f93d41c72901bc52f640a393b55b25bfc735a3395dff4","highlight/RON.sublime-syntax":"3b44ac654381f86a48ecd294a116d645afc8b1b285ac54a98fdfe0ef44922ad8","src/de/error.rs":"354213757a5edadd2bb1cfb524aff4ab519abe126329372947cb5f1cd9042ce9","src/de/id.rs":"52f7890e13c451d3614e14cf1e41ff0006906af57c7a6d0151bfdf1431c6dd7d","src/de/mod.rs":"08b27a38cf0534f8b5831af3913570b1013663bb3d1a1e1dd8ab19d61e251d91","src/de/tests.rs":"319f4a0c04d351d1fc55b92a7b1f08462ac62760258d64a10f098b65cc7cb452","src/de/value.rs":"6195d0ed6db65c7c2c9cdff40502da3514f0510e59f2ad0c0ad0ad8c3bb5b4ff","src/lib.rs":"558446d7acc431ee04bbb1f54e31cd83a5457d04c0e5619dc2cbf47ec97b28d8","src/parse.rs":"168f02b2e3865cb4448c5b9991a65765a9c9c78b7edb1aa238b329715289200a","src/ser/mod.rs":"0b837bceb1f3c4bda47f6217f7abb07c8a39db26f91000adeaf6ed7e1edd56d6","src/ser/pretty.rs":"b1da2210842fae2f69f76e1429fdc91337805ec21f5e46e8d4fbf6b5ba01b3c5","src/ser/value.rs":"b3616892a500a67f1e14bc21d2b80c11e37387de9d58f877f30c443d0a372328","src/value.rs":"5a6102a111358c3c1f7bb55551ff1a1fd352383dc31e973c85ffe01cb06f38f9","tests/big_struct.rs":"04c78b4e5a707cb359ac01607769b3a9ee272a407e4f5c225bb801d432655254","tests/numbers.rs":"70fd0d8718b364e5512ced9ed8beffd3a3ef5a87109cfef7895bd2209be0929b","tests/roundtrip.rs":"d20e3c28c44ad7e6372e5a64afaf24a6d8db190acbdfde77d22f532ac2a7d1eb"},"package":"da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"}
|
{"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"}
|
|
@ -3,7 +3,7 @@
|
||||||
# When uploading crates to the registry Cargo will automatically
|
# When uploading crates to the registry Cargo will automatically
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
# with all versions of Cargo and also rewrite `path` dependencies
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
# to registry (e.g. crates.io) dependencies
|
# to registry (e.g., crates.io) dependencies
|
||||||
#
|
#
|
||||||
# If you believe there's an error in this file please file an
|
# If you believe there's an error in this file please file an
|
||||||
# issue against the rust-lang/cargo repository. If you're
|
# issue against the rust-lang/cargo repository. If you're
|
||||||
|
@ -11,13 +11,15 @@
|
||||||
# will likely look very different (and much more reasonable)
|
# will likely look very different (and much more reasonable)
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
|
edition = "2018"
|
||||||
name = "ron"
|
name = "ron"
|
||||||
version = "0.1.7"
|
version = "0.5.1"
|
||||||
authors = ["Dzmitry Malyshau <kvarkus@gmail.com>", "Thomas Schaller <torkleyy@gmail.com>"]
|
authors = ["Dzmitry Malyshau <kvarkus@gmail.com>", "Thomas Schaller <torkleyy@gmail.com>"]
|
||||||
exclude = ["bors.toml", ".travis.yml"]
|
exclude = ["bors.toml", ".travis.yml"]
|
||||||
description = "Rusty Object Notation"
|
description = "Rusty Object Notation"
|
||||||
homepage = "https://github.com/ron-rs/ron"
|
homepage = "https://github.com/ron-rs/ron"
|
||||||
documentation = "https://docs.rs/ron/"
|
documentation = "https://docs.rs/ron/"
|
||||||
|
readme = "README.md"
|
||||||
keywords = ["parser", "serde", "serialization"]
|
keywords = ["parser", "serde", "serialization"]
|
||||||
categories = ["encoding"]
|
categories = ["encoding"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
|
@ -25,8 +27,17 @@ repository = "https://github.com/ron-rs/ron"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "ron"
|
name = "ron"
|
||||||
|
[dependencies.base64]
|
||||||
|
version = "0.10"
|
||||||
|
|
||||||
|
[dependencies.bitflags]
|
||||||
|
version = "1"
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1"
|
version = "1"
|
||||||
features = ["serde_derive"]
|
features = ["serde_derive"]
|
||||||
|
[dev-dependencies.serde_bytes]
|
||||||
|
version = "0.10"
|
||||||
|
|
||||||
[dev-dependencies.serde_json]
|
[dev-dependencies.serde_json]
|
||||||
version = "1"
|
version = "1"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
## Rusty Object Notation
|
# Rusty Object Notation
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/ron-rs/ron.png?branch=master)](https://travis-ci.org/ron-rs/ron)
|
[![Build Status](https://travis-ci.org/ron-rs/ron.svg?branch=master)](https://travis-ci.org/ron-rs/ron)
|
||||||
[![Crates.io](https://img.shields.io/crates/v/ron.svg)](https://crates.io/crates/ron)
|
[![Crates.io](https://img.shields.io/crates/v/ron.svg)](https://crates.io/crates/ron)
|
||||||
[![Docs](https://docs.rs/ron/badge.svg)](https://docs.rs/ron)
|
[![Docs](https://docs.rs/ron/badge.svg)](https://docs.rs/ron)
|
||||||
[![Gitter](https://badges.gitter.im/ron-rs/ron.svg)](https://gitter.im/ron-rs/ron)
|
[![Gitter](https://badges.gitter.im/ron-rs/ron.svg)](https://gitter.im/ron-rs/ron)
|
||||||
|
@ -9,6 +9,39 @@ RON is a simple readable data serialization format that looks similar to Rust sy
|
||||||
It's designed to support all of [Serde's data model](https://serde.rs/data-model.html), so
|
It's designed to support all of [Serde's data model](https://serde.rs/data-model.html), so
|
||||||
structs, enums, tuples, arrays, generic maps, and primitive values.
|
structs, enums, tuples, arrays, generic maps, and primitive values.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```
|
||||||
|
GameConfig( // optional struct name
|
||||||
|
window_size: (800, 600),
|
||||||
|
window_title: "PAC-MAN",
|
||||||
|
fullscreen: false,
|
||||||
|
|
||||||
|
mouse_sensitivity: 1.4,
|
||||||
|
key_bindings: {
|
||||||
|
"up": Up,
|
||||||
|
"down": Down,
|
||||||
|
"left": Left,
|
||||||
|
"right": Right,
|
||||||
|
|
||||||
|
// Uncomment to enable WASD controls
|
||||||
|
/*
|
||||||
|
"W": Up,
|
||||||
|
"A": Down,
|
||||||
|
"S": Left,
|
||||||
|
"D": Right,
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
|
||||||
|
difficulty_options: (
|
||||||
|
start_difficulty: Easy,
|
||||||
|
adaptive: false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why RON?
|
||||||
|
|
||||||
### Example in JSON
|
### Example in JSON
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -27,7 +60,7 @@ structs, enums, tuples, arrays, generic maps, and primitive values.
|
||||||
"material": "metal"
|
"material": "metal"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "moster",
|
"name": "monster",
|
||||||
"material": "plastic"
|
"material": "plastic"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -86,7 +119,8 @@ Here are the general rules to parse the heterogeneous structures:
|
||||||
### Specification
|
### Specification
|
||||||
|
|
||||||
There is a very basic, work in progress specification available on
|
There is a very basic, work in progress specification available on
|
||||||
[the wiki page](https://github.com/kvark/ron/wiki/Specification).
|
[the wiki page](https://github.com/ron-rs/ron/wiki/Specification).
|
||||||
|
A more formal and complete grammar is available [here](docs/grammar.md).
|
||||||
|
|
||||||
### Appendix
|
### Appendix
|
||||||
|
|
||||||
|
@ -95,7 +129,7 @@ Why not XML?
|
||||||
- unclear how to treat attributes vs contents
|
- unclear how to treat attributes vs contents
|
||||||
|
|
||||||
Why not YAML?
|
Why not YAML?
|
||||||
- significant white-space
|
- significant white-space
|
||||||
- specification is too big
|
- specification is too big
|
||||||
|
|
||||||
Why not TOML?
|
Why not TOML?
|
||||||
|
@ -105,6 +139,12 @@ Why not TOML?
|
||||||
Why not XXX?
|
Why not XXX?
|
||||||
- if you know a better format, tell me!
|
- if you know a better format, tell me!
|
||||||
|
|
||||||
|
## Tooling
|
||||||
|
|
||||||
|
Sublime Text: https://packagecontrol.io/packages/RON
|
||||||
|
|
||||||
|
Vim: https://github.com/ron-rs/ron.vim
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
RON is dual-licensed under Apache-2.0 and MIT.
|
RON is dual-licensed under Apache-2.0 and MIT.
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
## RON extensions
|
||||||
|
|
||||||
|
RON has extensions that can be enabled by adding the following attribute at the top of your RON document:
|
||||||
|
|
||||||
|
`#![enable(...)]`
|
||||||
|
|
||||||
|
# unwrap_newtypes
|
||||||
|
|
||||||
|
You can add this extension by adding the following attribute at the top of your RON document:
|
||||||
|
|
||||||
|
`#![enable(unwrap_newtypes)]`
|
||||||
|
|
||||||
|
This feature enables RON to automatically unwrap simple tuples.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct NewType(u32);
|
||||||
|
struct Object {
|
||||||
|
pub new_type: NewType,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Without `unwrap_newtypes`, because the value `5` can not be saved into `NewType(u32)`, your RON document would look like this:
|
||||||
|
|
||||||
|
``` ron
|
||||||
|
(
|
||||||
|
new_type: (5),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
With the `unwrap_newtypes` extension, this coercion is done automatically. So `5` will be interpreted as `(5)`.
|
||||||
|
|
||||||
|
``` ron
|
||||||
|
#![enable(unwrap_newtypes)]
|
||||||
|
(
|
||||||
|
new_type: 5,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
# implicit_some
|
||||||
|
|
||||||
|
You can add this extension by adding the following attribute at the top of your RON document:
|
||||||
|
|
||||||
|
`#![enable(implicit_some)]`
|
||||||
|
|
||||||
|
This feature enables RON to automatically convert any value to `Some(value)` if the deserialized struct requires it.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Object {
|
||||||
|
pub value: Option<u32>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Without this feature, you would have to write this RON document.
|
||||||
|
|
||||||
|
```ron
|
||||||
|
(
|
||||||
|
value: Some(5),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Enabling the feature would automatically infer `Some(x)` if `x` is given. In this case, RON automatically casts this `5` into a `Some(5)`.
|
||||||
|
|
||||||
|
```ron
|
||||||
|
(
|
||||||
|
value: 5,
|
||||||
|
)
|
||||||
|
```
|
|
@ -0,0 +1,130 @@
|
||||||
|
# RON grammar
|
||||||
|
|
||||||
|
This file describes the structure of a RON file in [EBNF notation][ebnf].
|
||||||
|
If extensions are enabled, some rules will be replaced. For that, see the
|
||||||
|
[extensions document][exts] which describes all extensions and what they override.
|
||||||
|
|
||||||
|
[ebnf]: https://en.wikipedia.org/wiki/Extended_Backus–Naur_form
|
||||||
|
[exts]: ./extensions.md
|
||||||
|
|
||||||
|
## RON file
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
RON = [extensions], ws, value, ws;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Whitespace and comments
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
ws = { ws_single, comment };
|
||||||
|
ws_single = "\n" | "\t" | "\r" | " ";
|
||||||
|
comment = ["//", { no_newline }, "\n"];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commas
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
comma = ws, ",", ws;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extensions
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
extensions = { "#", ws, "!", ws, "[", ws, extensions_inner, ws, "]", ws };
|
||||||
|
extensions_inner = "enable", ws, "(", extension_name, { comma, extension_name }, [comma], ws, ")";
|
||||||
|
```
|
||||||
|
|
||||||
|
For the extension names see the [`extensions.md`][exts] document.
|
||||||
|
|
||||||
|
## Value
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
value = unsigned | signed | float | string | char | bool | option | list | map | tuple | struct | enum_variant;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Numbers
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
||||||
|
unsigned = ["0", ("x" | "b" | "o")], digit, { digit | '_' };
|
||||||
|
signed = ["+" | "-"], unsigned;
|
||||||
|
float = float_std | float_frac;
|
||||||
|
float_std = ["+" | "-"], digit, { digit }, ".", {digit}, [float_exp];
|
||||||
|
float_frac = ".", digit, {digit}, [float_exp];
|
||||||
|
float_exp = ("e" | "E"), digit, {digit};
|
||||||
|
```
|
||||||
|
|
||||||
|
## String
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
string = string_std | string_raw;
|
||||||
|
string_std = "\"", { no_double_quotation_marks | string_escape }, "\"";
|
||||||
|
string_escape = "\\", ("\"" | "\\" | "b" | "f" | "n" | "r" | "t" | ("u", unicode_hex));
|
||||||
|
string_raw = ("r#", string_raw, "#") | "\"", { unicode_non_greedy }, "\"";
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: Raw strings start with an `r`, followed by n `#` 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 `#`.
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Char
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
char = "'", (no_apostrophe | "\\\\" | "\\'"), "'";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Boolean
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
bool = "true" | "false";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optional
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
option = "Some", ws, "(", ws, value, ws, ")";
|
||||||
|
```
|
||||||
|
|
||||||
|
## List
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
list = "[", [value, { comma, value }, [comma]], "]";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Map
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
map = "{", [map_entry, { comma, map_entry }, [comma]], "}";
|
||||||
|
map_entry = value, ws, ":", ws, value;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tuple
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
tuple = "(", [value, { comma, value }, [comma]], ")";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Struct
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
struct = unit_struct | tuple_struct | named_struct;
|
||||||
|
unit_struct = ident | "()";
|
||||||
|
tuple_struct = [ident], ws, tuple;
|
||||||
|
named_struct = [ident], ws, "(", [named_field, { comma, named_field }, [comma]], ")";
|
||||||
|
named_field = ident, ws, ":", value;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Enum
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
enum_variant = enum_variant_unit | enum_variant_tuple | enum_variant_named;
|
||||||
|
enum_variant_unit = ident;
|
||||||
|
enum_variant_tuple = ident, ws, tuple;
|
||||||
|
enum_variant_named = ident, ws, "(", [named_field, { comma, named_field }, [comma]], ")";
|
||||||
|
```
|
|
@ -1,10 +1,6 @@
|
||||||
extern crate ron;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use ron::de::from_str;
|
use ron::de::from_str;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
|
@ -12,6 +8,7 @@ struct Config {
|
||||||
float: f32,
|
float: f32,
|
||||||
map: HashMap<u8, char>,
|
map: HashMap<u8, char>,
|
||||||
nested: Nested,
|
nested: Nested,
|
||||||
|
option: Option<String>,
|
||||||
tuple: (u32, u32),
|
tuple: (u32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +18,21 @@ struct Nested {
|
||||||
b: char,
|
b: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONFIG: &str = "(
|
const CONFIG: &str = "
|
||||||
|
/*
|
||||||
|
* RON now has multi-line (C-style) block comments!
|
||||||
|
* They can be freely nested:
|
||||||
|
* /* This is a nested comment */
|
||||||
|
* If you just want a single-line comment,
|
||||||
|
* do it like here:
|
||||||
|
// Just put two slashes before the comment and the rest of the line
|
||||||
|
// can be used freely!
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Note that block comments can not be started in a line comment
|
||||||
|
// (Putting a /* here will have no effect)
|
||||||
|
|
||||||
|
(
|
||||||
boolean: true,
|
boolean: true,
|
||||||
float: 8.2,
|
float: 8.2,
|
||||||
map: {
|
map: {
|
||||||
|
@ -36,7 +47,8 @@ const CONFIG: &str = "(
|
||||||
a: \"Decode me!\",
|
a: \"Decode me!\",
|
||||||
b: 'z',
|
b: 'z',
|
||||||
),
|
),
|
||||||
tuple: (3, 7),
|
option: Some(\t \"Weird formatting!\" \n\n ),
|
||||||
|
tuple: (3 /*(2 + 1)*/, 7 /*(2 * 5 - 3)*/),
|
||||||
)";
|
)";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -45,8 +57,8 @@ fn main() {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to load config: {}", e);
|
println!("Failed to load config: {}", e);
|
||||||
|
|
||||||
::std::process::exit(1);
|
std::process::exit(1);
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Config: {:?}", &config);
|
println!("Config: {:?}", &config);
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
extern crate ron;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use ron::de::from_reader;
|
use ron::de::from_reader;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::{collections::HashMap, fs::File};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
|
@ -23,16 +18,15 @@ struct Nested {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input_path = format!("{}/examples/example.ron",
|
let input_path = format!("{}/examples/example.ron", env!("CARGO_MANIFEST_DIR"));
|
||||||
env!("CARGO_MANIFEST_DIR"));
|
|
||||||
let f = File::open(&input_path).expect("Failed opening file");
|
let f = File::open(&input_path).expect("Failed opening file");
|
||||||
let config: Config = match from_reader(f) {
|
let config: Config = match from_reader(f) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to load config: {}", e);
|
println!("Failed to load config: {}", e);
|
||||||
|
|
||||||
::std::process::exit(1);
|
std::process::exit(1);
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Config: {:?}", &config);
|
println!("Config: {:?}", &config);
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
extern crate ron;
|
use ron::ser::{to_string_pretty, PrettyConfig};
|
||||||
#[macro_use]
|
use serde::Serialize;
|
||||||
extern crate serde;
|
use std::{collections::HashMap, iter::FromIterator};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::default::Default;
|
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use ron::ser::{PrettyConfig, to_string_pretty};
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
|
@ -33,11 +27,6 @@ struct Nested {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
use std::io::Write;
|
|
||||||
use std::iter::FromIterator;
|
|
||||||
|
|
||||||
let mut file = File::create("config.ron").expect("Failed to create file");
|
|
||||||
|
|
||||||
let data = Config {
|
let data = Config {
|
||||||
float: (2.18, -1.1),
|
float: (2.18, -1.1),
|
||||||
tuple: TupleStruct((), false),
|
tuple: TupleStruct((), false),
|
||||||
|
@ -51,11 +40,12 @@ fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let pretty = PrettyConfig {
|
let pretty = PrettyConfig {
|
||||||
|
depth_limit: 2,
|
||||||
separate_tuple_members: true,
|
separate_tuple_members: true,
|
||||||
enumerate_arrays: true,
|
enumerate_arrays: true,
|
||||||
..PrettyConfig::default()
|
..PrettyConfig::default()
|
||||||
};
|
};
|
||||||
let s = to_string_pretty(&data, pretty).expect("Serialization failed");
|
let s = to_string_pretty(&data, pretty).expect("Serialization failed");
|
||||||
|
|
||||||
file.write(s.as_bytes()).expect("Failed to write data to file");
|
println!("{}", s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
extern crate ron;
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
use ron::value::Value;
|
use ron::value::Value;
|
||||||
use serde::ser::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let data = r#"
|
let data = r#"
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
%YAML 1.2
|
|
||||||
---
|
|
||||||
name: RON
|
|
||||||
file_extensions:
|
|
||||||
- ron
|
|
||||||
scope: source.ron
|
|
||||||
contexts:
|
|
||||||
main:
|
|
||||||
- include: value
|
|
||||||
array:
|
|
||||||
- match: '\['
|
|
||||||
scope: punctuation.section.array.begin.ron
|
|
||||||
push:
|
|
||||||
- meta_scope: meta.structure.array.ron
|
|
||||||
- match: '\]'
|
|
||||||
scope: punctuation.section.array.end.ron
|
|
||||||
pop: true
|
|
||||||
- include: value
|
|
||||||
- match: ','
|
|
||||||
scope: punctuation.separator.array.ron
|
|
||||||
- match: '[^\s\]]'
|
|
||||||
scope: invalid.illegal.expected-array-separator.ron
|
|
||||||
comments:
|
|
||||||
- match: /\*\*(?!/)
|
|
||||||
scope: punctuation.definition.comment.ron
|
|
||||||
push:
|
|
||||||
- meta_scope: comment.block.documentation.ron
|
|
||||||
- match: \*/
|
|
||||||
pop: true
|
|
||||||
- match: /\*
|
|
||||||
scope: punctuation.definition.comment.ron
|
|
||||||
push:
|
|
||||||
- meta_scope: comment.block.ron
|
|
||||||
- match: \*/
|
|
||||||
pop: true
|
|
||||||
- match: (//).*$\n?
|
|
||||||
scope: comment.line.double-slash.js
|
|
||||||
captures:
|
|
||||||
1: punctuation.definition.comment.ron
|
|
||||||
constant:
|
|
||||||
- match: \b(true|false)\b
|
|
||||||
scope: constant.language.ron
|
|
||||||
number:
|
|
||||||
# handles integer and decimal numbers
|
|
||||||
- match: |-
|
|
||||||
(?x: # turn on extended mode
|
|
||||||
-? # an optional minus
|
|
||||||
(?:
|
|
||||||
0 # a zero
|
|
||||||
| # ...or...
|
|
||||||
[1-9] # a 1-9 character
|
|
||||||
\d* # followed by zero or more digits
|
|
||||||
)
|
|
||||||
(?:
|
|
||||||
(?:
|
|
||||||
\. # a period
|
|
||||||
\d+ # followed by one or more digits
|
|
||||||
)?
|
|
||||||
(?:
|
|
||||||
[eE] # an e character
|
|
||||||
[+-]? # followed by an option +/-
|
|
||||||
\d+ # followed by one or more digits
|
|
||||||
)? # make exponent optional
|
|
||||||
)? # make decimal portion optional
|
|
||||||
)
|
|
||||||
scope: constant.numeric.ron
|
|
||||||
object:
|
|
||||||
- match: '[A-Za-z_][A-Za-z_0-9]*'
|
|
||||||
scope: entity.name.class.ron
|
|
||||||
- match: '\('
|
|
||||||
scope: punctuation.section.dictionary.begin.ron
|
|
||||||
push:
|
|
||||||
- meta_scope: meta.structure.entity.ron
|
|
||||||
- match: '\)'
|
|
||||||
scope: punctuation.section.dictionary.end.ron
|
|
||||||
pop: true
|
|
||||||
- match: '[a-z_][A-Za-z_0-9]*'
|
|
||||||
scope: entity.name.tag.ron
|
|
||||||
- match: '\:'
|
|
||||||
scope: punctuation.separator.dictionary.key-value.ron
|
|
||||||
- include: value
|
|
||||||
- match: ','
|
|
||||||
scope: punctuation.separator.dictionary.ron
|
|
||||||
dictionary:
|
|
||||||
- match: '\{'
|
|
||||||
scope: punctuation.section.dictionary.begin.ron
|
|
||||||
push:
|
|
||||||
- meta_scope: meta.structure.dictionary.ron
|
|
||||||
- match: '\}'
|
|
||||||
scope: punctuation.section.dictionary.end.ron
|
|
||||||
pop: true
|
|
||||||
- include: value
|
|
||||||
- match: ':'
|
|
||||||
scope: punctuation.separator.dictionary.key-value.ron
|
|
||||||
- include: value
|
|
||||||
- match: ','
|
|
||||||
scope: punctuation.separator.dictionary.ron
|
|
||||||
string:
|
|
||||||
- match: '"'
|
|
||||||
scope: punctuation.definition.string.begin.ron
|
|
||||||
push: inside-string
|
|
||||||
inside-string:
|
|
||||||
- meta_scope: string.quoted.double.ron
|
|
||||||
- match: '"'
|
|
||||||
scope: punctuation.definition.string.end.ron
|
|
||||||
pop: true
|
|
||||||
- include: string-escape
|
|
||||||
- match: $\n?
|
|
||||||
scope: invalid.illegal.unclosed-string.ron
|
|
||||||
pop: true
|
|
||||||
string-escape:
|
|
||||||
- match: |-
|
|
||||||
(?x: # turn on extended mode
|
|
||||||
\\ # a literal backslash
|
|
||||||
(?: # ...followed by...
|
|
||||||
["\\/bfnrt] # one of these characters
|
|
||||||
| # ...or...
|
|
||||||
u # a u
|
|
||||||
[0-9a-fA-F]{4} # and four hex digits
|
|
||||||
)
|
|
||||||
)
|
|
||||||
scope: constant.character.escape.ron
|
|
||||||
- match: \\.
|
|
||||||
scope: invalid.illegal.unrecognized-string-escape.ron
|
|
||||||
value:
|
|
||||||
- include: constant
|
|
||||||
- include: number
|
|
||||||
- include: string
|
|
||||||
- include: array
|
|
||||||
- include: dictionary
|
|
||||||
- include: object
|
|
||||||
- include: comments
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
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,15 +1,10 @@
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::fmt;
|
|
||||||
use std::str::Utf8Error;
|
|
||||||
use std::io;
|
|
||||||
use std::string::FromUtf8Error;
|
|
||||||
|
|
||||||
use serde::de;
|
use serde::de;
|
||||||
|
use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
|
||||||
|
|
||||||
use parse::Position;
|
use crate::parse::Position;
|
||||||
|
|
||||||
/// Deserialization result.
|
/// Deserialization result.
|
||||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -20,9 +15,12 @@ pub enum Error {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
|
Base64Error(base64::DecodeError),
|
||||||
Eof,
|
Eof,
|
||||||
ExpectedArray,
|
ExpectedArray,
|
||||||
ExpectedArrayEnd,
|
ExpectedArrayEnd,
|
||||||
|
ExpectedAttribute,
|
||||||
|
ExpectedAttributeEnd,
|
||||||
ExpectedBoolean,
|
ExpectedBoolean,
|
||||||
ExpectedComma,
|
ExpectedComma,
|
||||||
ExpectedEnum,
|
ExpectedEnum,
|
||||||
|
@ -42,8 +40,12 @@ pub enum ParseError {
|
||||||
ExpectedStringEnd,
|
ExpectedStringEnd,
|
||||||
ExpectedIdentifier,
|
ExpectedIdentifier,
|
||||||
|
|
||||||
InvalidEscape,
|
InvalidEscape(&'static str),
|
||||||
|
|
||||||
|
NoSuchExtension(String),
|
||||||
|
|
||||||
|
UnclosedBlockComment,
|
||||||
|
UnderscoreAtBeginning,
|
||||||
UnexpectedByte(char),
|
UnexpectedByte(char),
|
||||||
|
|
||||||
Utf8Error(Utf8Error),
|
Utf8Error(Utf8Error),
|
||||||
|
@ -54,7 +56,7 @@ pub enum ParseError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::IoError(ref s) => write!(f, "{}", s),
|
Error::IoError(ref s) => write!(f, "{}", s),
|
||||||
Error::Message(ref s) => write!(f, "{}", s),
|
Error::Message(ref s) => write!(f, "{}", s),
|
||||||
|
@ -75,9 +77,14 @@ impl StdError for Error {
|
||||||
Error::IoError(ref s) => s,
|
Error::IoError(ref s) => s,
|
||||||
Error::Message(ref e) => e,
|
Error::Message(ref e) => e,
|
||||||
Error::Parser(ref kind, _) => match *kind {
|
Error::Parser(ref kind, _) => match *kind {
|
||||||
|
ParseError::Base64Error(ref e) => e.description(),
|
||||||
ParseError::Eof => "Unexpected end of file",
|
ParseError::Eof => "Unexpected end of file",
|
||||||
ParseError::ExpectedArray => "Expected array",
|
ParseError::ExpectedArray => "Expected array",
|
||||||
ParseError::ExpectedArrayEnd => "Expected end of 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::ExpectedBoolean => "Expected boolean",
|
||||||
ParseError::ExpectedComma => "Expected comma",
|
ParseError::ExpectedComma => "Expected comma",
|
||||||
ParseError::ExpectedEnum => "Expected enum",
|
ParseError::ExpectedEnum => "Expected enum",
|
||||||
|
@ -94,15 +101,21 @@ impl StdError for Error {
|
||||||
ParseError::ExpectedUnit => "Expected unit",
|
ParseError::ExpectedUnit => "Expected unit",
|
||||||
ParseError::ExpectedStructName => "Expected struct name",
|
ParseError::ExpectedStructName => "Expected struct name",
|
||||||
ParseError::ExpectedString => "Expected string",
|
ParseError::ExpectedString => "Expected string",
|
||||||
|
ParseError::ExpectedStringEnd => "Expected string end",
|
||||||
ParseError::ExpectedIdentifier => "Expected identifier",
|
ParseError::ExpectedIdentifier => "Expected identifier",
|
||||||
|
|
||||||
ParseError::InvalidEscape => "Invalid escape sequence",
|
ParseError::InvalidEscape(_) => "Invalid escape sequence",
|
||||||
|
|
||||||
|
ParseError::NoSuchExtension(_) => "No such RON extension",
|
||||||
|
|
||||||
ParseError::Utf8Error(ref e) => e.description(),
|
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::TrailingCharacters => "Non-whitespace trailing characters",
|
||||||
|
|
||||||
_ => unimplemented!(),
|
ParseError::__NonExhaustive => unimplemented!(),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +134,7 @@ impl From<FromUtf8Error> for ParseError {
|
||||||
|
|
||||||
impl From<Utf8Error> for Error {
|
impl From<Utf8Error> for Error {
|
||||||
fn from(e: Utf8Error) -> Self {
|
fn from(e: Utf8Error) -> Self {
|
||||||
Error::Parser(ParseError::Utf8Error(e), Position { line : 0, col : 0})
|
Error::Parser(ParseError::Utf8Error(e), Position { line: 0, col: 0 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,4 +142,4 @@ impl From<io::Error> for Error {
|
||||||
fn from(e: io::Error) -> Self {
|
fn from(e: io::Error) -> Self {
|
||||||
Error::IoError(e.description().to_string())
|
Error::IoError(e.description().to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,187 +8,191 @@ pub struct IdDeserializer<'a, 'b: 'a> {
|
||||||
|
|
||||||
impl<'a, 'b: 'a> IdDeserializer<'a, 'b> {
|
impl<'a, 'b: 'a> IdDeserializer<'a, 'b> {
|
||||||
pub fn new(d: &'a mut Deserializer<'b>) -> Self {
|
pub fn new(d: &'a mut Deserializer<'b>) -> Self {
|
||||||
IdDeserializer {
|
IdDeserializer { d }
|
||||||
d
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
|
impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize_identifier<V>(
|
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
visitor: V
|
V: Visitor<'b>,
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'b>
|
|
||||||
{
|
{
|
||||||
self.d.deserialize_identifier(visitor)
|
self.d.deserialize_identifier(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
self.deserialize_identifier(visitor)
|
self.deserialize_identifier(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_bool<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_bool<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i8<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_i8<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i16<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_i16<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i32<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_i32<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i64<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_i64<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u8<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_u8<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u16<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_u16<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u32<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_u32<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u64<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_u64<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f32<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_f32<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f64<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_f64<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_char<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_char<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_str<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_str<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_string<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_string<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_bytes<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_bytes<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_option<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_option<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_unit<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit_struct<V>(
|
fn deserialize_unit_struct<V>(self, _: &'static str, _: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
_: &'static str,
|
V: Visitor<'b>,
|
||||||
_: V
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'b>
|
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_newtype_struct<V>(
|
fn deserialize_newtype_struct<V>(self, _: &'static str, _: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
_: &'static str,
|
V: Visitor<'b>,
|
||||||
_: V
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'b>
|
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_seq<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_seq<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_tuple<V>(
|
fn deserialize_tuple<V>(self, _: usize, _: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
_: usize,
|
V: Visitor<'b>,
|
||||||
_: V
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'b>
|
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_tuple_struct<V>(
|
fn deserialize_tuple_struct<V>(self, _: &'static str, _: usize, _: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
_: &'static str,
|
V: Visitor<'b>,
|
||||||
_: usize,
|
|
||||||
_: V
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'b>
|
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_map<V>(self, _: V) -> Result<V::Value>
|
fn deserialize_map<V>(self, _: V) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
@ -197,9 +201,10 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
|
||||||
self,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: &'static [&'static str],
|
_: &'static [&'static str],
|
||||||
_: V
|
_: V,
|
||||||
) -> Result<V::Value>
|
) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
@ -208,18 +213,17 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
|
||||||
self,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: &'static [&'static str],
|
_: &'static [&'static str],
|
||||||
_: V
|
_: V,
|
||||||
) -> Result<V::Value>
|
) -> Result<V::Value>
|
||||||
where V: Visitor<'b>
|
where
|
||||||
|
V: Visitor<'b>,
|
||||||
{
|
{
|
||||||
unimplemented!("IdDeserializer may only be used for identifiers")
|
unimplemented!("IdDeserializer may only be used for identifiers")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_ignored_any<V>(
|
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
visitor: V
|
V: Visitor<'b>,
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'b>
|
|
||||||
{
|
{
|
||||||
self.deserialize_any(visitor)
|
self.deserialize_any(visitor)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
/// Deserialization module.
|
/// Deserialization module.
|
||||||
///
|
|
||||||
|
|
||||||
pub use self::error::{Error, ParseError, Result};
|
pub use self::error::{Error, ParseError, Result};
|
||||||
|
pub use crate::parse::Position;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
|
||||||
use std::io;
|
use std::{borrow::Cow, io, str};
|
||||||
use std::str;
|
|
||||||
|
|
||||||
use serde::de::{self, Deserializer as Deserializer_, DeserializeSeed, Visitor};
|
|
||||||
|
|
||||||
use parse::Bytes;
|
|
||||||
use self::id::IdDeserializer;
|
use self::id::IdDeserializer;
|
||||||
|
use crate::parse::{Bytes, Extensions, ParsedStr};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod id;
|
mod id;
|
||||||
|
@ -27,41 +23,50 @@ pub struct Deserializer<'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserializer<'de> {
|
impl<'de> Deserializer<'de> {
|
||||||
pub fn from_str(input: &'de str) -> Self {
|
pub fn from_str(input: &'de str) -> Result<Self> {
|
||||||
Deserializer {
|
Deserializer::from_bytes(input.as_bytes())
|
||||||
bytes: Bytes::new(input.as_bytes()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(input: &'de [u8]) -> Self {
|
pub fn from_bytes(input: &'de [u8]) -> Result<Self> {
|
||||||
Deserializer {
|
Ok(Deserializer {
|
||||||
bytes: Bytes::new(input),
|
bytes: Bytes::new(input)?,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remainder(&self) -> Cow<str> {
|
pub fn remainder(&self) -> Cow<'_, str> {
|
||||||
String::from_utf8_lossy(&self.bytes.bytes())
|
String::from_utf8_lossy(&self.bytes.bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience function for reading data from a reader
|
/// A convenience function for reading data from a reader
|
||||||
/// and feeding into a deserializer
|
/// and feeding into a deserializer.
|
||||||
pub fn from_reader<R, T>(mut rdr: R) -> Result<T>
|
pub fn from_reader<R, T>(mut rdr: R) -> Result<T>
|
||||||
where R: io::Read,
|
where
|
||||||
T: de::DeserializeOwned
|
R: io::Read,
|
||||||
|
T: de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
rdr.read_to_end(&mut bytes)?;
|
rdr.read_to_end(&mut bytes)?;
|
||||||
let s = str::from_utf8(&bytes)?;
|
|
||||||
from_str(s)
|
from_bytes(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience function for building a deserializer
|
/// A convenience function for building a deserializer
|
||||||
/// and deserializing a value of type `T`.
|
/// and deserializing a value of type `T` from a string.
|
||||||
pub fn from_str<'a, T>(s: &'a str) -> Result<T>
|
pub fn from_str<'a, T>(s: &'a str) -> Result<T>
|
||||||
where T: de::Deserialize<'a>
|
where
|
||||||
|
T: de::Deserialize<'a>,
|
||||||
{
|
{
|
||||||
let mut deserializer = Deserializer::from_str(s);
|
from_bytes(s.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A convenience function for building a deserializer
|
||||||
|
/// and deserializing a value of type `T` from bytes.
|
||||||
|
pub fn from_bytes<'a, T>(s: &'a [u8]) -> Result<T>
|
||||||
|
where
|
||||||
|
T: de::Deserialize<'a>,
|
||||||
|
{
|
||||||
|
let mut deserializer = Deserializer::from_bytes(s)?;
|
||||||
let t = T::deserialize(&mut deserializer)?;
|
let t = T::deserialize(&mut deserializer)?;
|
||||||
|
|
||||||
deserializer.end()?;
|
deserializer.end()?;
|
||||||
|
@ -73,7 +78,7 @@ impl<'de> Deserializer<'de> {
|
||||||
/// Check if the remaining bytes are whitespace only,
|
/// Check if the remaining bytes are whitespace only,
|
||||||
/// otherwise return an error.
|
/// otherwise return an error.
|
||||||
pub fn end(&mut self) -> Result<()> {
|
pub fn end(&mut self) -> Result<()> {
|
||||||
self.bytes.skip_ws();
|
self.bytes.skip_ws()?;
|
||||||
|
|
||||||
if self.bytes.bytes().is_empty() {
|
if self.bytes.bytes().is_empty() {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -81,13 +86,41 @@ impl<'de> Deserializer<'de> {
|
||||||
self.bytes.err(ParseError::TrailingCharacters)
|
self.bytes.err(ParseError::TrailingCharacters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called from `deserialze_any` when a struct was detected. Decides if
|
||||||
|
/// there is a unit, tuple or usual struct and deserializes it
|
||||||
|
/// accordingly.
|
||||||
|
///
|
||||||
|
/// This method assumes there is no identifier left.
|
||||||
|
fn handle_any_struct<V>(&mut self, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
// Create a working copy
|
||||||
|
let mut bytes = self.bytes;
|
||||||
|
|
||||||
|
match bytes.consume("(") {
|
||||||
|
true => {
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => visitor.visit_unit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.bytes.consume_ident("true") {
|
if self.bytes.consume_ident("true") {
|
||||||
return visitor.visit_bool(true);
|
return visitor.visit_bool(true);
|
||||||
|
@ -101,100 +134,121 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
return visitor.visit_unit();
|
return visitor.visit_unit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.bytes.identifier().is_ok() {
|
// `identifier` does not change state if it fails
|
||||||
self.bytes.skip_ws();
|
let ident = self.bytes.identifier().ok();
|
||||||
|
|
||||||
return self.deserialize_struct("", &[], visitor);
|
if ident.is_some() {
|
||||||
|
self.bytes.skip_ws()?;
|
||||||
|
|
||||||
|
return self.handle_any_struct(visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.bytes.peek_or_eof()? {
|
match self.bytes.peek_or_eof()? {
|
||||||
b'(' => self.deserialize_struct("", &[], visitor),
|
b'(' => self.handle_any_struct(visitor),
|
||||||
b'[' => self.deserialize_seq(visitor),
|
b'[' => self.deserialize_seq(visitor),
|
||||||
b'{' => self.deserialize_map(visitor),
|
b'{' => self.deserialize_map(visitor),
|
||||||
b'0' ... b'9' | b'+' | b'-' | b'.' => self.deserialize_f64(visitor),
|
b'0'..=b'9' | b'+' | b'-' => {
|
||||||
b'"' => self.deserialize_string(visitor),
|
if self.bytes.next_bytes_is_float() {
|
||||||
|
self.deserialize_f64(visitor)
|
||||||
|
} else {
|
||||||
|
self.deserialize_i64(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b'.' => self.deserialize_f64(visitor),
|
||||||
|
b'"' | b'r' => self.deserialize_string(visitor),
|
||||||
b'\'' => self.deserialize_char(visitor),
|
b'\'' => self.deserialize_char(visitor),
|
||||||
other => self.bytes.err(ParseError::UnexpectedByte(other as char)),
|
other => self.bytes.err(ParseError::UnexpectedByte(other as char)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_bool(self.bytes.bool()?)
|
visitor.visit_bool(self.bytes.bool()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i8(self.bytes.signed_integer()?)
|
visitor.visit_i8(self.bytes.signed_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i16(self.bytes.signed_integer()?)
|
visitor.visit_i16(self.bytes.signed_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i32(self.bytes.signed_integer()?)
|
visitor.visit_i32(self.bytes.signed_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i64(self.bytes.signed_integer()?)
|
visitor.visit_i64(self.bytes.signed_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u8(self.bytes.unsigned_integer()?)
|
visitor.visit_u8(self.bytes.unsigned_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u16(self.bytes.unsigned_integer()?)
|
visitor.visit_u16(self.bytes.unsigned_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u32(self.bytes.unsigned_integer()?)
|
visitor.visit_u32(self.bytes.unsigned_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u64(self.bytes.unsigned_integer()?)
|
visitor.visit_u64(self.bytes.unsigned_integer()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_f32(self.bytes.float()?)
|
visitor.visit_f32(self.bytes.float()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_f64(self.bytes.float()?)
|
visitor.visit_f64(self.bytes.float()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_char(self.bytes.char()?)
|
visitor.visit_char(self.bytes.char()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
use parse::ParsedStr;
|
|
||||||
|
|
||||||
match self.bytes.string()? {
|
match self.bytes.string()? {
|
||||||
ParsedStr::Allocated(s) => visitor.visit_string(s),
|
ParsedStr::Allocated(s) => visitor.visit_string(s),
|
||||||
ParsedStr::Slice(s) => visitor.visit_str(s),
|
ParsedStr::Slice(s) => visitor.visit_str(s),
|
||||||
|
@ -202,41 +256,61 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.deserialize_str(visitor)
|
self.deserialize_str(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.deserialize_seq(visitor)
|
self.deserialize_byte_buf(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.deserialize_seq(visitor)
|
let res = {
|
||||||
|
let string = self.bytes.string()?;
|
||||||
|
let base64_str = match string {
|
||||||
|
ParsedStr::Allocated(ref s) => s.as_str(),
|
||||||
|
ParsedStr::Slice(ref s) => s,
|
||||||
|
};
|
||||||
|
base64::decode(base64_str)
|
||||||
|
};
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(byte_buf) => visitor.visit_byte_buf(byte_buf),
|
||||||
|
Err(err) => self.bytes.err(ParseError::Base64Error(err)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.bytes.consume("Some") && { self.bytes.skip_ws(); self.bytes.consume("(") } {
|
if self.bytes.consume("None") {
|
||||||
self.bytes.skip_ws();
|
visitor.visit_none()
|
||||||
|
} else if self.bytes.exts.contains(Extensions::IMPLICIT_SOME) {
|
||||||
|
visitor.visit_some(&mut *self)
|
||||||
|
} else if self.bytes.consume("Some") && {
|
||||||
|
self.bytes.skip_ws()?;
|
||||||
|
self.bytes.consume("(")
|
||||||
|
} {
|
||||||
|
self.bytes.skip_ws()?;
|
||||||
|
|
||||||
let v = visitor.visit_some(&mut *self)?;
|
let v = visitor.visit_some(&mut *self)?;
|
||||||
|
|
||||||
self.bytes.skip_ws();
|
self.bytes.skip_ws()?;
|
||||||
|
|
||||||
if self.bytes.consume(")") {
|
if self.bytes.consume(")") {
|
||||||
Ok(v)
|
Ok(v)
|
||||||
} else {
|
} else {
|
||||||
self.bytes.err(ParseError::ExpectedOptionEnd)
|
self.bytes.err(ParseError::ExpectedOptionEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if self.bytes.consume("None") {
|
|
||||||
visitor.visit_none()
|
|
||||||
} else {
|
} else {
|
||||||
self.bytes.err(ParseError::ExpectedOption)
|
self.bytes.err(ParseError::ExpectedOption)
|
||||||
}
|
}
|
||||||
|
@ -244,7 +318,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
|
|
||||||
// In Serde, unit means an anonymous value containing no data.
|
// In Serde, unit means an anonymous value containing no data.
|
||||||
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.bytes.consume("()") {
|
if self.bytes.consume("()") {
|
||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
|
@ -253,12 +328,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit_struct<V>(
|
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
name: &'static str,
|
V: Visitor<'de>,
|
||||||
visitor: V
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'de>
|
|
||||||
{
|
{
|
||||||
if self.bytes.consume(name) {
|
if self.bytes.consume(name) {
|
||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
|
@ -267,20 +339,22 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_newtype_struct<V>(
|
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
name: &'static str,
|
V: Visitor<'de>,
|
||||||
visitor: V
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'de>
|
|
||||||
{
|
{
|
||||||
|
if self.bytes.exts.contains(Extensions::UNWRAP_NEWTYPES) {
|
||||||
|
return visitor.visit_newtype_struct(&mut *self);
|
||||||
|
}
|
||||||
|
|
||||||
self.bytes.consume(name);
|
self.bytes.consume(name);
|
||||||
|
|
||||||
self.bytes.skip_ws();
|
self.bytes.skip_ws()?;
|
||||||
|
|
||||||
if self.bytes.consume("(") {
|
if self.bytes.consume("(") {
|
||||||
|
self.bytes.skip_ws()?;
|
||||||
let value = visitor.visit_newtype_struct(&mut *self)?;
|
let value = visitor.visit_newtype_struct(&mut *self)?;
|
||||||
self.bytes.comma();
|
self.bytes.comma()?;
|
||||||
|
|
||||||
if self.bytes.consume(")") {
|
if self.bytes.consume(")") {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -293,11 +367,12 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value>
|
fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.bytes.consume("[") {
|
if self.bytes.consume("[") {
|
||||||
let value = visitor.visit_seq(CommaSeparated::new(b']', &mut self))?;
|
let value = visitor.visit_seq(CommaSeparated::new(b']', &mut self))?;
|
||||||
self.bytes.comma();
|
self.bytes.comma()?;
|
||||||
|
|
||||||
if self.bytes.consume("]") {
|
if self.bytes.consume("]") {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -309,22 +384,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tuples look just like sequences in JSON. Some formats may be able to
|
fn deserialize_tuple<V>(mut self, _len: usize, visitor: V) -> Result<V::Value>
|
||||||
// represent tuples more efficiently.
|
where
|
||||||
//
|
V: Visitor<'de>,
|
||||||
// As indicated by the length parameter, the `Deserialize` implementation
|
|
||||||
// for a tuple in the Serde data model is required to know the length of the
|
|
||||||
// tuple before even looking at the input data.
|
|
||||||
fn deserialize_tuple<V>(
|
|
||||||
mut self,
|
|
||||||
_len: usize,
|
|
||||||
visitor: V
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'de>
|
|
||||||
{
|
{
|
||||||
if self.bytes.consume("(") {
|
if self.bytes.consume("(") {
|
||||||
let value = visitor.visit_seq(CommaSeparated::new(b')', &mut self))?;
|
let value = visitor.visit_seq(CommaSeparated::new(b')', &mut self))?;
|
||||||
self.bytes.comma();
|
self.bytes.comma()?;
|
||||||
|
|
||||||
if self.bytes.consume(")") {
|
if self.bytes.consume(")") {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -340,20 +406,22 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
self,
|
self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
len: usize,
|
len: usize,
|
||||||
visitor: V
|
visitor: V,
|
||||||
) -> Result<V::Value>
|
) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.bytes.consume(name);
|
self.bytes.consume(name);
|
||||||
self.deserialize_tuple(len, visitor)
|
self.deserialize_tuple(len, visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value>
|
fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.bytes.consume("{") {
|
if self.bytes.consume("{") {
|
||||||
let value = visitor.visit_map(CommaSeparated::new(b'}', &mut self))?;
|
let value = visitor.visit_map(CommaSeparated::new(b'}', &mut self))?;
|
||||||
self.bytes.comma();
|
self.bytes.comma()?;
|
||||||
|
|
||||||
if self.bytes.consume("}") {
|
if self.bytes.consume("}") {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -369,17 +437,18 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
mut self,
|
mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
_fields: &'static [&'static str],
|
_fields: &'static [&'static str],
|
||||||
visitor: V
|
visitor: V,
|
||||||
) -> Result<V::Value>
|
) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.bytes.consume(name);
|
self.bytes.consume(name);
|
||||||
|
|
||||||
self.bytes.skip_ws();
|
self.bytes.skip_ws()?;
|
||||||
|
|
||||||
if self.bytes.consume("(") {
|
if self.bytes.consume("(") {
|
||||||
let value = visitor.visit_map(CommaSeparated::new(b')', &mut self))?;
|
let value = visitor.visit_map(CommaSeparated::new(b')', &mut self))?;
|
||||||
self.bytes.comma();
|
self.bytes.comma()?;
|
||||||
|
|
||||||
if self.bytes.consume(")") {
|
if self.bytes.consume(")") {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -395,27 +464,26 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variants: &'static [&'static str],
|
_variants: &'static [&'static str],
|
||||||
visitor: V
|
visitor: V,
|
||||||
) -> Result<V::Value>
|
) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_enum(Enum::new(self))
|
visitor.visit_enum(Enum::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_identifier<V>(
|
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
visitor: V
|
V: Visitor<'de>,
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'de>
|
|
||||||
{
|
{
|
||||||
visitor.visit_bytes(self.bytes.identifier()?)
|
visitor.visit_str(
|
||||||
|
str::from_utf8(self.bytes.identifier()?).map_err(|e| self.bytes.error(e.into()))?,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_ignored_any<V>(
|
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
visitor: V
|
V: Visitor<'de>,
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'de>
|
|
||||||
{
|
{
|
||||||
self.deserialize_any(visitor)
|
self.deserialize_any(visitor)
|
||||||
}
|
}
|
||||||
|
@ -429,7 +497,11 @@ struct CommaSeparated<'a, 'de: 'a> {
|
||||||
|
|
||||||
impl<'a, 'de> CommaSeparated<'a, 'de> {
|
impl<'a, 'de> CommaSeparated<'a, 'de> {
|
||||||
fn new(terminator: u8, de: &'a mut Deserializer<'de>) -> Self {
|
fn new(terminator: u8, de: &'a mut Deserializer<'de>) -> Self {
|
||||||
CommaSeparated { de, terminator, had_comma: true }
|
CommaSeparated {
|
||||||
|
de,
|
||||||
|
terminator,
|
||||||
|
had_comma: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn err<T>(&self, kind: ParseError) -> Result<T> {
|
fn err<T>(&self, kind: ParseError) -> Result<T> {
|
||||||
|
@ -437,10 +509,9 @@ impl<'a, 'de> CommaSeparated<'a, 'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_element(&mut self) -> Result<bool> {
|
fn has_element(&mut self) -> Result<bool> {
|
||||||
self.de.bytes.skip_ws();
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
Ok(self.had_comma &&
|
Ok(self.had_comma && self.de.bytes.peek_or_eof()? != self.terminator)
|
||||||
self.de.bytes.peek_or_eof()? != self.terminator)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,12 +519,13 @@ impl<'de, 'a> de::SeqAccess<'de> for CommaSeparated<'a, 'de> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
|
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
|
||||||
where T: DeserializeSeed<'de>
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
if self.has_element()? {
|
if self.has_element()? {
|
||||||
let res = seed.deserialize(&mut *self.de)?;
|
let res = seed.deserialize(&mut *self.de)?;
|
||||||
|
|
||||||
self.had_comma = self.de.bytes.comma();
|
self.had_comma = self.de.bytes.comma()?;
|
||||||
|
|
||||||
Ok(Some(res))
|
Ok(Some(res))
|
||||||
} else {
|
} else {
|
||||||
|
@ -466,11 +538,13 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
|
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
|
||||||
where K: DeserializeSeed<'de>
|
where
|
||||||
|
K: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
if self.has_element()? {
|
if self.has_element()? {
|
||||||
if self.terminator == b')' {
|
if self.terminator == b')' {
|
||||||
seed.deserialize(&mut IdDeserializer::new(&mut *self.de)).map(Some)
|
seed.deserialize(&mut IdDeserializer::new(&mut *self.de))
|
||||||
|
.map(Some)
|
||||||
} else {
|
} else {
|
||||||
seed.deserialize(&mut *self.de).map(Some)
|
seed.deserialize(&mut *self.de).map(Some)
|
||||||
}
|
}
|
||||||
|
@ -480,16 +554,17 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
|
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
|
||||||
where V: DeserializeSeed<'de>
|
where
|
||||||
|
V: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
self.de.bytes.skip_ws();
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
if self.de.bytes.consume(":") {
|
if self.de.bytes.consume(":") {
|
||||||
self.de.bytes.skip_ws();
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
let res = seed.deserialize(&mut *self.de)?;
|
let res = seed.deserialize(&mut *self.de)?;
|
||||||
|
|
||||||
self.had_comma = self.de.bytes.comma();
|
self.had_comma = self.de.bytes.comma()?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
} else {
|
} else {
|
||||||
|
@ -513,8 +588,11 @@ impl<'de, 'a> de::EnumAccess<'de> for Enum<'a, 'de> {
|
||||||
type Variant = Self;
|
type Variant = Self;
|
||||||
|
|
||||||
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
|
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
|
||||||
where V: DeserializeSeed<'de>
|
where
|
||||||
|
V: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
let value = seed.deserialize(&mut *self.de)?;
|
let value = seed.deserialize(&mut *self.de)?;
|
||||||
|
|
||||||
Ok((value, self))
|
Ok((value, self))
|
||||||
|
@ -529,14 +607,17 @@ impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
|
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
|
||||||
where T: DeserializeSeed<'de>
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
self.de.bytes.skip_ws();
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
if self.de.bytes.consume("(") {
|
if self.de.bytes.consume("(") {
|
||||||
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
let val = seed.deserialize(&mut *self.de)?;
|
let val = seed.deserialize(&mut *self.de)?;
|
||||||
|
|
||||||
self.de.bytes.comma();
|
self.de.bytes.comma()?;
|
||||||
|
|
||||||
if self.de.bytes.consume(")") {
|
if self.de.bytes.consume(")") {
|
||||||
Ok(val)
|
Ok(val)
|
||||||
|
@ -549,21 +630,19 @@ impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
|
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
|
||||||
where V: Visitor<'de>
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.de.bytes.skip_ws();
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
self.de.deserialize_tuple(len, visitor)
|
self.de.deserialize_tuple(len, visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_variant<V>(
|
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
|
||||||
self,
|
where
|
||||||
fields: &'static [&'static str],
|
V: Visitor<'de>,
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value>
|
|
||||||
where V: Visitor<'de>
|
|
||||||
{
|
{
|
||||||
self.de.bytes.skip_ws();
|
self.de.bytes.skip_ws()?;
|
||||||
|
|
||||||
self.de.deserialize_struct("", fields, visitor)
|
self.de.deserialize_struct("", fields, visitor)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_bytes;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
@ -7,14 +10,24 @@ struct EmptyStruct1;
|
||||||
struct EmptyStruct2 {}
|
struct EmptyStruct2 {}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
|
||||||
struct MyStruct { x: f32, y: f32 }
|
struct MyStruct {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
|
||||||
enum MyEnum {
|
enum MyEnum {
|
||||||
A,
|
A,
|
||||||
B(bool),
|
B(bool),
|
||||||
C(bool, f32),
|
C(bool, f32),
|
||||||
D { a: i32, b: i32 }
|
D { a: i32, b: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
struct BytesStruct {
|
||||||
|
small: Vec<u8>,
|
||||||
|
#[serde(with = "serde_bytes")]
|
||||||
|
large: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -23,7 +36,6 @@ fn test_empty_struct() {
|
||||||
assert_eq!(Ok(EmptyStruct2 {}), from_str("EmptyStruct2()"));
|
assert_eq!(Ok(EmptyStruct2 {}), from_str("EmptyStruct2()"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_struct() {
|
fn test_struct() {
|
||||||
let my_struct = MyStruct { x: 4.0, y: 7.0 };
|
let my_struct = MyStruct { x: 4.0, y: 7.0 };
|
||||||
|
@ -44,7 +56,6 @@ fn test_struct() {
|
||||||
assert_eq!(Ok(TupleStruct(3.0, 4.0)), from_str("(3,4)"));
|
assert_eq!(Ok(TupleStruct(3.0, 4.0)), from_str("(3,4)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_option() {
|
fn test_option() {
|
||||||
assert_eq!(Ok(Some(1u8)), from_str("Some(1)"));
|
assert_eq!(Ok(Some(1u8)), from_str("Some(1)"));
|
||||||
|
@ -67,7 +78,7 @@ fn test_array() {
|
||||||
assert_eq!(Ok(empty_array), from_str("[]"));
|
assert_eq!(Ok(empty_array), from_str("[]"));
|
||||||
|
|
||||||
assert_eq!(Ok([2, 3, 4i32]), from_str("(2,3,4,)"));
|
assert_eq!(Ok([2, 3, 4i32]), from_str("(2,3,4,)"));
|
||||||
assert_eq!(Ok(([2, 3, 4i32].to_vec())), from_str("[2,3,4,]"));
|
assert_eq!(Ok([2, 3, 4i32].to_vec()), from_str("[2,3,4,]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -78,17 +89,33 @@ fn test_map() {
|
||||||
map.insert((true, false), 4);
|
map.insert((true, false), 4);
|
||||||
map.insert((false, false), 123);
|
map.insert((false, false), 123);
|
||||||
|
|
||||||
assert_eq!(Ok(map), from_str("{
|
assert_eq!(
|
||||||
|
Ok(map),
|
||||||
|
from_str(
|
||||||
|
"{
|
||||||
(true,false,):4,
|
(true,false,):4,
|
||||||
(false,false,):123,
|
(false,false,):123,
|
||||||
}"));
|
}"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_string() {
|
fn test_string() {
|
||||||
let s: String = from_str("\"String\"").unwrap();
|
let s: String = from_str("\"String\"").unwrap();
|
||||||
|
|
||||||
assert_eq!("String", s);
|
assert_eq!("String", s);
|
||||||
|
|
||||||
|
let raw: String = from_str("r\"String\"").unwrap();
|
||||||
|
assert_eq!("String", raw);
|
||||||
|
|
||||||
|
let raw_hashes: String = from_str("r#\"String\"#").unwrap();
|
||||||
|
assert_eq!("String", raw_hashes);
|
||||||
|
|
||||||
|
let raw_hashes_multiline: String = from_str("r#\"String with\nmultiple\nlines\n\"#").unwrap();
|
||||||
|
assert_eq!("String with\nmultiple\nlines\n", raw_hashes_multiline);
|
||||||
|
|
||||||
|
let raw_hashes_quote: String = from_str("r##\"String with \"#\"##").unwrap();
|
||||||
|
assert_eq!("String with \"#", raw_hashes_quote);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -108,16 +135,22 @@ fn test_escape() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_comment() {
|
fn test_comment() {
|
||||||
assert_eq!(MyStruct { x: 1.0, y: 2.0 }, from_str("(
|
assert_eq!(
|
||||||
|
MyStruct { x: 1.0, y: 2.0 },
|
||||||
|
from_str(
|
||||||
|
"(
|
||||||
x: 1.0, // x is just 1
|
x: 1.0, // x is just 1
|
||||||
// There is another comment in the very next line..
|
// There is another comment in the very next line..
|
||||||
// And y is indeed
|
// And y is indeed
|
||||||
y: 2.0 // 2!
|
y: 2.0 // 2!
|
||||||
)").unwrap());
|
)"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn err<T>(kind: ParseError, line: usize, col: usize) -> Result<T> {
|
fn err<T>(kind: ParseError, line: usize, col: usize) -> Result<T> {
|
||||||
use parse::Position;
|
use crate::parse::Position;
|
||||||
|
|
||||||
Err(Error::Parser(kind, Position { line, col }))
|
Err(Error::Parser(kind, Position { line, col }))
|
||||||
}
|
}
|
||||||
|
@ -137,15 +170,22 @@ fn test_err_wrong_value() {
|
||||||
assert_eq!(from_str::<(u8, bool)>("'c'"), err(ExpectedArray, 1, 1));
|
assert_eq!(from_str::<(u8, bool)>("'c'"), err(ExpectedArray, 1, 1));
|
||||||
assert_eq!(from_str::<bool>("notabool"), err(ExpectedBoolean, 1, 1));
|
assert_eq!(from_str::<bool>("notabool"), err(ExpectedBoolean, 1, 1));
|
||||||
|
|
||||||
assert_eq!(from_str::<MyStruct>("MyStruct(\n x: true)"), err(ExpectedFloat, 2, 8));
|
assert_eq!(
|
||||||
assert_eq!(from_str::<MyStruct>("MyStruct(\n x: 3.5, \n y:)"),
|
from_str::<MyStruct>("MyStruct(\n x: true)"),
|
||||||
err(ExpectedFloat, 3, 7));
|
err(ExpectedFloat, 2, 8)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
from_str::<MyStruct>("MyStruct(\n x: 3.5, \n y:)"),
|
||||||
|
err(ExpectedFloat, 3, 7)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_perm_ws() {
|
fn test_perm_ws() {
|
||||||
assert_eq!(from_str::<MyStruct>("\nMyStruct \t ( \n x : 3.5 , \t y\n: 4.5 \n ) \t\n"),
|
assert_eq!(
|
||||||
Ok(MyStruct { x: 3.5, y: 4.5 }));
|
from_str::<MyStruct>("\nMyStruct \t ( \n x : 3.5 , \t y\n: 4.5 \n ) \t\n"),
|
||||||
|
Ok(MyStruct { x: 3.5, y: 4.5 })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -158,6 +198,7 @@ fn untagged() {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(from_str::<Untagged>("true").unwrap(), Untagged::Bool(true));
|
assert_eq!(from_str::<Untagged>("true").unwrap(), Untagged::Bool(true));
|
||||||
|
assert_eq!(from_str::<Untagged>("8").unwrap(), Untagged::U8(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -169,3 +210,98 @@ fn forgot_apostrophes() {
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expected_attribute() {
|
||||||
|
let de: Result<String> = from_str("#\"Hello\"");
|
||||||
|
|
||||||
|
assert_eq!(de, err(ParseError::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));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_attribute() {
|
||||||
|
let de: Result<String> = from_str("#![enable(invalid)] \"Hello\"");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
de,
|
||||||
|
err(ParseError::NoSuchExtension("invalid".to_string()), 1, 18)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiple_attributes() {
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
struct New(String);
|
||||||
|
let de: Result<New> =
|
||||||
|
from_str("#![enable(unwrap_newtypes)] #![enable(unwrap_newtypes)] \"Hello\"");
|
||||||
|
|
||||||
|
assert_eq!(de, Ok(New("Hello".to_owned())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uglified_attribute() {
|
||||||
|
let de: Result<()> = from_str(
|
||||||
|
"# !\
|
||||||
|
// We definitely want to add a comment here
|
||||||
|
[\t\tenable( // best style ever
|
||||||
|
unwrap_newtypes ) ] ()",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(de, Ok(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn implicit_some() {
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
|
fn de<T: DeserializeOwned>(s: &str) -> Option<T> {
|
||||||
|
let enable = "#![enable(implicit_some)]\n".to_string();
|
||||||
|
|
||||||
|
from_str::<Option<T>>(&(enable + s)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(de("'c'"), Some('c'));
|
||||||
|
assert_eq!(de("5"), Some(5));
|
||||||
|
assert_eq!(de("\"Hello\""), Some("Hello".to_owned()));
|
||||||
|
assert_eq!(de("false"), Some(false));
|
||||||
|
assert_eq!(
|
||||||
|
de("MyStruct(x: .4, y: .5)"),
|
||||||
|
Some(MyStruct { x: 0.4, y: 0.5 })
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(de::<char>("None"), None);
|
||||||
|
|
||||||
|
// Not concise
|
||||||
|
assert_eq!(de::<Option<Option<char>>>("None"), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ws_tuple_newtype_variant() {
|
||||||
|
assert_eq!(Ok(MyEnum::B(true)), from_str("B ( \n true \n ) "));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_byte_stream() {
|
||||||
|
assert_eq!(
|
||||||
|
Ok(BytesStruct {
|
||||||
|
small: vec![1, 2],
|
||||||
|
large: vec![1, 2, 3, 4]
|
||||||
|
}),
|
||||||
|
from_str("BytesStruct( small:[1, 2], large:\"AQIDBA==\" )"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_numbers() {
|
||||||
|
assert_eq!(
|
||||||
|
Ok(vec![1234, 12345, 123456, 1234567, 555_555]),
|
||||||
|
from_str("[1_234, 12_345, 1_2_3_4_5_6, 1_234_567, 5_55_55_5]"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,31 @@
|
||||||
use std::collections::BTreeMap;
|
use std::{collections::BTreeMap, fmt};
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
|
use serde::{
|
||||||
use serde::{Deserialize, Deserializer};
|
de::{Error, MapAccess, SeqAccess, Visitor},
|
||||||
|
Deserialize, Deserializer,
|
||||||
|
};
|
||||||
|
|
||||||
use de;
|
use crate::{
|
||||||
use value::{Number, Value};
|
de,
|
||||||
|
value::{Number, Value},
|
||||||
|
};
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
/// Creates a value from a string reference.
|
/// Creates a value from a string reference.
|
||||||
pub fn from_str(s: &str) -> de::Result<Self> {
|
pub fn from_str(s: &str) -> de::Result<Self> {
|
||||||
Self::deserialize(&mut super::Deserializer::from_str(s))
|
let mut de = super::Deserializer::from_str(s)?;
|
||||||
|
|
||||||
|
let val = Value::deserialize(&mut de)?;
|
||||||
|
de.end()?;
|
||||||
|
|
||||||
|
Ok(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Value {
|
impl<'de> Deserialize<'de> for Value {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where D: Deserializer<'de>
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
deserializer.deserialize_any(ValueVisitor)
|
deserializer.deserialize_any(ValueVisitor)
|
||||||
}
|
}
|
||||||
|
@ -27,91 +36,106 @@ struct ValueVisitor;
|
||||||
impl<'de> Visitor<'de> for ValueVisitor {
|
impl<'de> Visitor<'de> for ValueVisitor {
|
||||||
type Value = Value;
|
type Value = Value;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "A RON value")
|
write!(f, "a RON value")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
Ok(Value::Bool(v))
|
Ok(Value::Bool(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||||
where E: Error,
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
self.visit_f64(v as f64)
|
self.visit_f64(v as f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
self.visit_f64(v as f64)
|
self.visit_f64(v as f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
|
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
Ok(Value::Number(Number::new(v)))
|
Ok(Value::Number(Number::new(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
|
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
Ok(Value::Char(v))
|
Ok(Value::Char(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
self.visit_string(v.to_owned())
|
self.visit_string(v.to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
Ok(Value::String(v))
|
Ok(Value::String(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
self.visit_byte_buf(v.to_vec())
|
self.visit_byte_buf(v.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
self.visit_string(String::from_utf8(v)
|
self.visit_string(String::from_utf8(v).map_err(|e| Error::custom(format!("{}", e)))?)
|
||||||
.map_err(|e| Error::custom(format!("{}", e)))?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_none<E>(self) -> Result<Self::Value, E>
|
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
Ok(Value::Option(None))
|
Ok(Value::Option(None))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
where D: Deserializer<'de>,
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
Ok(Value::Option(Some(Box::new(deserializer.deserialize_any(ValueVisitor)?))))
|
Ok(Value::Option(Some(Box::new(
|
||||||
|
deserializer.deserialize_any(ValueVisitor)?,
|
||||||
|
))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||||
where E: Error
|
where
|
||||||
|
E: Error,
|
||||||
{
|
{
|
||||||
Ok(Value::Unit)
|
Ok(Value::Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
where D: Deserializer<'de>
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
deserializer.deserialize_any(ValueVisitor)
|
deserializer.deserialize_any(ValueVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
where A: SeqAccess<'de>
|
where
|
||||||
|
A: SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
if let Some(cap) = seq.size_hint() {
|
if let Some(cap) = seq.size_hint() {
|
||||||
|
@ -126,7 +150,8 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
where A: MapAccess<'de>
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut res: BTreeMap<Value, Value> = BTreeMap::new();
|
let mut res: BTreeMap<Value, Value> = BTreeMap::new();
|
||||||
|
|
||||||
|
@ -154,12 +179,52 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_some() {
|
fn test_some() {
|
||||||
assert_eq!(eval("Some(())"), Value::Option(Some(Box::new(Value::Unit))));
|
assert_eq!(eval("Some(())"), Value::Option(Some(Box::new(Value::Unit))));
|
||||||
assert_eq!(eval("Some ( () )"), Value::Option(Some(Box::new(Value::Unit))));
|
assert_eq!(
|
||||||
|
eval("Some ( () )"),
|
||||||
|
Value::Option(Some(Box::new(Value::Unit)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuples_basic() {
|
||||||
|
assert_eq!(
|
||||||
|
eval("(3, 4, 5)"),
|
||||||
|
Value::Seq(vec![
|
||||||
|
Value::Number(Number::new(3.0)),
|
||||||
|
Value::Number(Number::new(4.0)),
|
||||||
|
Value::Number(Number::new(5.0)),
|
||||||
|
],),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuples_ident() {
|
||||||
|
assert_eq!(
|
||||||
|
eval("(true, 3, 4, 5)"),
|
||||||
|
Value::Seq(vec![
|
||||||
|
Value::Bool(true),
|
||||||
|
Value::Number(Number::new(3.0)),
|
||||||
|
Value::Number(Number::new(4.0)),
|
||||||
|
Value::Number(Number::new(5.0)),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuples_error() {
|
||||||
|
use crate::de::{Error, ParseError, Position};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Value::from_str("Foo:").unwrap_err(),
|
||||||
|
Error::Parser(ParseError::TrailingCharacters, Position { col: 4, line: 1 }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complex() {
|
fn test_complex() {
|
||||||
assert_eq!(eval("Some([
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"Some([
|
||||||
Room ( width: 20, height: 5, name: \"The Room\" ),
|
Room ( width: 20, height: 5, name: \"The Room\" ),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -172,27 +237,67 @@ mod tests {
|
||||||
\"Enemy3\": 7,
|
\"Enemy3\": 7,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
])"),
|
])"
|
||||||
Value::Option(Some(Box::new(Value::Seq(
|
),
|
||||||
vec![
|
Value::Option(Some(Box::new(Value::Seq(vec![
|
||||||
Value::Map(vec![
|
Value::Map(
|
||||||
(Value::String("width".to_owned()), Value::Number(Number::new(20.0))),
|
vec![
|
||||||
(Value::String("height".to_owned()), Value::Number(Number::new(5.0))),
|
(
|
||||||
(Value::String("name".to_owned()), Value::String("The Room".to_owned())),
|
Value::String("width".to_owned()),
|
||||||
].into_iter().collect()),
|
Value::Number(Number::new(20.0)),
|
||||||
Value::Map(vec![
|
),
|
||||||
(Value::String("width".to_owned()), Value::Number(Number::new(10.0))),
|
(
|
||||||
(Value::String("height".to_owned()), Value::Number(Number::new(10.0))),
|
Value::String("height".to_owned()),
|
||||||
(Value::String("name".to_owned()), Value::String("Another room".to_owned())),
|
Value::Number(Number::new(5.0)),
|
||||||
(Value::String("enemy_levels".to_owned()), Value::Map(
|
),
|
||||||
vec![
|
(
|
||||||
(Value::String("Enemy1".to_owned()), Value::Number(Number::new(3.0))),
|
Value::String("name".to_owned()),
|
||||||
(Value::String("Enemy2".to_owned()), Value::Number(Number::new(5.0))),
|
Value::String("The Room".to_owned()),
|
||||||
(Value::String("Enemy3".to_owned()), Value::Number(Number::new(7.0))),
|
),
|
||||||
].into_iter().collect()
|
]
|
||||||
)),
|
.into_iter()
|
||||||
].into_iter().collect()),
|
.collect(),
|
||||||
]
|
),
|
||||||
)))));
|
Value::Map(
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Value::String("width".to_owned()),
|
||||||
|
Value::Number(Number::new(10.0)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Value::String("height".to_owned()),
|
||||||
|
Value::Number(Number::new(10.0)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Value::String("name".to_owned()),
|
||||||
|
Value::String("Another room".to_owned()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Value::String("enemy_levels".to_owned()),
|
||||||
|
Value::Map(
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Value::String("Enemy1".to_owned()),
|
||||||
|
Value::Number(Number::new(3.0)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Value::String("Enemy2".to_owned()),
|
||||||
|
Value::Number(Number::new(5.0)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Value::String("Enemy3".to_owned()),
|
||||||
|
Value::Number(Number::new(7.0)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
]))))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,11 +57,9 @@ Serializing / Deserializing is as simple as calling `to_string` / `from_str`.
|
||||||
|
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
pub mod de;
|
pub mod de;
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
pub use crate::value::Value;
|
||||||
|
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
use bitflags::bitflags;
|
||||||
use std::ops::Neg;
|
use std::{
|
||||||
use std::result::Result as StdResult;
|
char::from_u32 as char_from_u32,
|
||||||
use std::str::{FromStr, from_utf8, from_utf8_unchecked};
|
fmt::{Display, Formatter, Result as FmtResult},
|
||||||
|
ops::Neg,
|
||||||
|
result::Result as StdResult,
|
||||||
|
str::{from_utf8, from_utf8_unchecked, FromStr},
|
||||||
|
};
|
||||||
|
|
||||||
use de::{Error, ParseError, Result};
|
use crate::de::{Error, ParseError, Result};
|
||||||
|
|
||||||
const DIGITS: &[u8] = b"0123456789ABCDEFabcdef";
|
const DIGITS: &[u8] = b"0123456789ABCDEFabcdef_";
|
||||||
const FLOAT_CHARS: &[u8] = b"0123456789.+-eE";
|
const FLOAT_CHARS: &[u8] = b"0123456789.+-eE";
|
||||||
const IDENT_FIRST: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
|
const IDENT_FIRST: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
|
||||||
const IDENT_CHAR: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789";
|
const IDENT_CHAR: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789";
|
||||||
|
@ -13,22 +17,36 @@ const WHITE_SPACE: &[u8] = b"\n\t\r ";
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Bytes<'a> {
|
pub struct Bytes<'a> {
|
||||||
|
/// Bits set according to `Extension` enum.
|
||||||
|
pub exts: Extensions,
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
column: usize,
|
column: usize,
|
||||||
line: usize,
|
line: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Bytes<'a> {
|
impl<'a> Bytes<'a> {
|
||||||
pub fn new(bytes: &'a [u8]) -> Self {
|
pub fn new(bytes: &'a [u8]) -> Result<Self> {
|
||||||
let mut b = Bytes {
|
let mut b = Bytes {
|
||||||
bytes,
|
bytes,
|
||||||
column: 1,
|
column: 1,
|
||||||
|
exts: Extensions::empty(),
|
||||||
line: 1,
|
line: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
b.skip_ws();
|
b.skip_ws()?;
|
||||||
|
// Loop over all extensions attributes
|
||||||
|
loop {
|
||||||
|
let attribute = b.extensions()?;
|
||||||
|
|
||||||
b
|
if attribute.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.exts |= attribute;
|
||||||
|
b.skip_ws()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn advance(&mut self, bytes: usize) -> Result<()> {
|
pub fn advance(&mut self, bytes: usize) -> Result<()> {
|
||||||
|
@ -71,36 +89,52 @@ impl<'a> Bytes<'a> {
|
||||||
return self.err(ParseError::ExpectedChar);
|
return self.err(ParseError::ExpectedChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
let c = self.eat_byte()?;
|
let c = self.peek_or_eof()?;
|
||||||
|
|
||||||
let c = if c == b'\\' {
|
let c = if c == b'\\' {
|
||||||
let c = self.eat_byte()?;
|
let _ = self.advance(1);
|
||||||
|
|
||||||
if c != b'\\' && c != b'\'' {
|
self.parse_escape()?
|
||||||
return self.err(ParseError::InvalidEscape);
|
} else {
|
||||||
|
// Check where the end of the char (') is and try to
|
||||||
|
// interpret the rest as UTF-8
|
||||||
|
|
||||||
|
let max = self.bytes.len().min(5);
|
||||||
|
let pos: usize = self.bytes[..max]
|
||||||
|
.iter()
|
||||||
|
.position(|&x| x == b'\'')
|
||||||
|
.ok_or_else(|| self.error(ParseError::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))?;
|
||||||
|
if chars.next().is_some() {
|
||||||
|
return self.err(ParseError::ExpectedChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
c
|
let _ = self.advance(pos);
|
||||||
} else {
|
|
||||||
c
|
first
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.consume("'") {
|
if !self.consume("'") {
|
||||||
return self.err(ParseError::ExpectedChar);
|
return self.err(ParseError::ExpectedChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(c as char)
|
Ok(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn comma(&mut self) -> bool {
|
pub fn comma(&mut self) -> Result<bool> {
|
||||||
self.skip_ws();
|
self.skip_ws()?;
|
||||||
|
|
||||||
if self.consume(",") {
|
if self.consume(",") {
|
||||||
self.skip_ws();
|
self.skip_ws()?;
|
||||||
|
|
||||||
true
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
false
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +145,22 @@ impl<'a> Bytes<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_ident_char(&self, index: usize) -> bool {
|
fn check_ident_char(&self, index: usize) -> bool {
|
||||||
self.bytes.get(index).map(|b| IDENT_CHAR.contains(b)).unwrap_or(false)
|
self.bytes
|
||||||
|
.get(index)
|
||||||
|
.map_or(false, |b| IDENT_CHAR.contains(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should only be used on a working copy
|
||||||
|
pub fn check_tuple_struct(mut self) -> Result<bool> {
|
||||||
|
if self.identifier().is_err() {
|
||||||
|
// if there's no field ident, this is a tuple struct
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.skip_ws()?;
|
||||||
|
|
||||||
|
// if there is no colon after the ident, this can only be a unit struct
|
||||||
|
self.eat_byte().map(|c| c != b':')
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only returns true if the char after `ident` cannot belong
|
/// Only returns true if the char after `ident` cannot belong
|
||||||
|
@ -136,6 +185,20 @@ impl<'a> Bytes<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consume_all(&mut self, all: &[&str]) -> Result<bool> {
|
||||||
|
all.iter()
|
||||||
|
.map(|elem| {
|
||||||
|
if self.consume(elem) {
|
||||||
|
self.skip_ws()?;
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fold(Ok(true), |acc, x| acc.and_then(|val| x.map(|x| x && val)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eat_byte(&mut self) -> Result<u8> {
|
pub fn eat_byte(&mut self) -> Result<u8> {
|
||||||
let peek = self.peek_or_eof()?;
|
let peek = self.peek_or_eof()?;
|
||||||
let _ = self.advance_single();
|
let _ = self.advance_single();
|
||||||
|
@ -148,11 +211,71 @@ impl<'a> Bytes<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(&self, kind: ParseError) -> Error {
|
pub fn error(&self, kind: ParseError) -> Error {
|
||||||
Error::Parser(kind, Position { line: self.line, col: self.column })
|
Error::Parser(
|
||||||
|
kind,
|
||||||
|
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),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the extensions bit mask.
|
||||||
|
fn extensions(&mut self) -> Result<Extensions> {
|
||||||
|
if self.peek() != Some(b'#') {
|
||||||
|
return Ok(Extensions::empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.consume_all(&["#", "!", "[", "enable", "("])? {
|
||||||
|
return self.err(ParseError::ExpectedAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.skip_ws()?;
|
||||||
|
let mut extensions = Extensions::empty();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let ident = self.identifier()?;
|
||||||
|
let extension = Extensions::from_ident(ident).ok_or_else(|| {
|
||||||
|
self.error(ParseError::NoSuchExtension(
|
||||||
|
from_utf8(ident).unwrap().to_owned(),
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
extensions |= extension;
|
||||||
|
|
||||||
|
let comma = self.comma()?;
|
||||||
|
|
||||||
|
// If we have no comma but another item, return an error
|
||||||
|
if !comma && self.check_ident_char(0) {
|
||||||
|
return self.err(ParseError::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) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.skip_ws()?;
|
||||||
|
|
||||||
|
match self.consume_all(&[")", "]"])? {
|
||||||
|
true => Ok(extensions),
|
||||||
|
false => Err(self.error(ParseError::ExpectedAttributeEnd)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn float<T>(&mut self) -> Result<T>
|
pub fn float<T>(&mut self) -> Result<T>
|
||||||
where T: FromStr
|
where
|
||||||
|
T: FromStr,
|
||||||
{
|
{
|
||||||
let num_bytes = self.next_bytes_contained_in(FLOAT_CHARS);
|
let num_bytes = self.next_bytes_contained_in(FLOAT_CHARS);
|
||||||
|
|
||||||
|
@ -164,14 +287,32 @@ impl<'a> Bytes<'a> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identifier(&mut self) -> Result<&[u8]> {
|
pub fn identifier(&mut self) -> Result<&'a [u8]> {
|
||||||
if IDENT_FIRST.contains(&self.peek_or_eof()?) {
|
let bytes = self.identifier_len()?;
|
||||||
|
let ident = &self.bytes[..bytes];
|
||||||
|
let _ = self.advance(bytes);
|
||||||
|
|
||||||
|
Ok(ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn identifier_len(&self) -> Result<usize> {
|
||||||
|
let next = self.peek_or_eof()?;
|
||||||
|
if IDENT_FIRST.contains(&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))?;
|
||||||
|
if *second == b'"' || *second == b'#' {
|
||||||
|
return self.err(ParseError::ExpectedIdentifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let bytes = self.next_bytes_contained_in(IDENT_CHAR);
|
let bytes = self.next_bytes_contained_in(IDENT_CHAR);
|
||||||
|
|
||||||
let ident = &self.bytes[..bytes];
|
Ok(bytes)
|
||||||
let _ = self.advance(bytes);
|
|
||||||
|
|
||||||
Ok(ident)
|
|
||||||
} else {
|
} else {
|
||||||
self.err(ParseError::ExpectedIdentifier)
|
self.err(ParseError::ExpectedIdentifier)
|
||||||
}
|
}
|
||||||
|
@ -181,29 +322,59 @@ impl<'a> Bytes<'a> {
|
||||||
self.bytes
|
self.bytes
|
||||||
.iter()
|
.iter()
|
||||||
.take_while(|b| allowed.contains(b))
|
.take_while(|b| allowed.contains(b))
|
||||||
.fold(0, |acc, _| acc + 1)
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_ws(&mut self) {
|
pub fn next_bytes_is_float(&self) -> bool {
|
||||||
while self.peek().map(|c| WHITE_SPACE.contains(&c)).unwrap_or(false) {
|
if let Some(byte) = self.peek() {
|
||||||
|
let skip = match byte {
|
||||||
|
b'+' | b'-' => 1,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
let flen = self
|
||||||
|
.bytes
|
||||||
|
.iter()
|
||||||
|
.skip(skip)
|
||||||
|
.take_while(|b| FLOAT_CHARS.contains(b))
|
||||||
|
.count();
|
||||||
|
let ilen = self
|
||||||
|
.bytes
|
||||||
|
.iter()
|
||||||
|
.skip(skip)
|
||||||
|
.take_while(|b| DIGITS.contains(b))
|
||||||
|
.count();
|
||||||
|
flen > ilen
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skip_ws(&mut self) -> Result<()> {
|
||||||
|
while self.peek().map_or(false, |c| WHITE_SPACE.contains(&c)) {
|
||||||
let _ = self.advance_single();
|
let _ = self.advance_single();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.skip_comment() {
|
if self.skip_comment()? {
|
||||||
self.skip_ws();
|
self.skip_ws()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(&self) -> Option<u8> {
|
pub fn peek(&self) -> Option<u8> {
|
||||||
self.bytes.get(0).map(|b| *b)
|
self.bytes.get(0).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_or_eof(&self) -> Result<u8> {
|
pub fn peek_or_eof(&self) -> Result<u8> {
|
||||||
self.bytes.get(0).map(|b| *b).ok_or(self.error(ParseError::Eof))
|
self.bytes
|
||||||
|
.get(0)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| self.error(ParseError::Eof))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signed_integer<T>(&mut self) -> Result<T>
|
pub fn signed_integer<T>(&mut self) -> Result<T>
|
||||||
where T: Neg<Output=T> + Num,
|
where
|
||||||
|
T: Neg<Output = T> + Num,
|
||||||
{
|
{
|
||||||
match self.peek_or_eof()? {
|
match self.peek_or_eof()? {
|
||||||
b'+' => {
|
b'+' => {
|
||||||
|
@ -220,16 +391,25 @@ impl<'a> Bytes<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string(&mut self) -> Result<ParsedStr> {
|
pub fn string(&mut self) -> Result<ParsedStr<'_>> {
|
||||||
if !self.consume("\"") {
|
if self.consume("\"") {
|
||||||
return self.err(ParseError::ExpectedString);
|
self.escaped_string()
|
||||||
|
} else if self.consume("r") {
|
||||||
|
self.raw_string()
|
||||||
|
} else {
|
||||||
|
self.err(ParseError::ExpectedString)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (i, end_or_escape) = self.bytes
|
fn escaped_string(&mut self) -> Result<ParsedStr<'_>> {
|
||||||
|
use std::iter::repeat;
|
||||||
|
|
||||||
|
let (i, end_or_escape) = self
|
||||||
|
.bytes
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|&(_, &b)| b == b'\\' || b == b'"')
|
.find(|&(_, &b)| b == b'\\' || b == b'"')
|
||||||
.ok_or(self.error(ParseError::ExpectedStringEnd))?;
|
.ok_or_else(|| self.error(ParseError::ExpectedStringEnd))?;
|
||||||
|
|
||||||
if *end_or_escape == b'"' {
|
if *end_or_escape == b'"' {
|
||||||
let s = from_utf8(&self.bytes[..i]).map_err(|e| self.error(e.into()))?;
|
let s = from_utf8(&self.bytes[..i]).map_err(|e| self.error(e.into()))?;
|
||||||
|
@ -245,9 +425,18 @@ impl<'a> Bytes<'a> {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let _ = self.advance(i + 1);
|
let _ = self.advance(i + 1);
|
||||||
self.parse_str_escape(&mut s)?;
|
let character = self.parse_escape()?;
|
||||||
|
match character.len_utf8() {
|
||||||
|
1 => s.push(character as u8),
|
||||||
|
len => {
|
||||||
|
let start = s.len();
|
||||||
|
s.extend(repeat(0).take(len));
|
||||||
|
character.encode_utf8(&mut s[start..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (new_i, end_or_escape) = self.bytes
|
let (new_i, end_or_escape) = self
|
||||||
|
.bytes
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|&(_, &b)| b == b'\\' || b == b'"')
|
.find(|&(_, &b)| b == b'\\' || b == b'"')
|
||||||
|
@ -260,15 +449,42 @@ impl<'a> Bytes<'a> {
|
||||||
if *end_or_escape == b'"' {
|
if *end_or_escape == b'"' {
|
||||||
let _ = self.advance(i + 1);
|
let _ = self.advance(i + 1);
|
||||||
|
|
||||||
break Ok(ParsedStr::Allocated(String::from_utf8(s)
|
let s = String::from_utf8(s).map_err(|e| self.error(e.into()))?;
|
||||||
.map_err(|e| self.error(e.into()))?));
|
break Ok(ParsedStr::Allocated(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn raw_string(&mut self) -> Result<ParsedStr<'_>> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ending = [&[b'"'], hashes].concat();
|
||||||
|
let i = self
|
||||||
|
.bytes
|
||||||
|
.windows(num_hashes + 1)
|
||||||
|
.position(|window| window == ending.as_slice())
|
||||||
|
.ok_or_else(|| self.error(ParseError::ExpectedStringEnd))?;
|
||||||
|
|
||||||
|
let s = from_utf8(&self.bytes[..i]).map_err(|e| self.error(e.into()))?;
|
||||||
|
|
||||||
|
// Advance by the number of bytes of the string
|
||||||
|
// + `num_hashes` + 1 for the `"`.
|
||||||
|
let _ = self.advance(i + num_hashes + 1);
|
||||||
|
|
||||||
|
Ok(ParsedStr::Slice(s))
|
||||||
|
}
|
||||||
|
|
||||||
fn test_for(&self, s: &str) -> bool {
|
fn test_for(&self, s: &str) -> bool {
|
||||||
s.bytes().enumerate().all(|(i, b)| self.bytes.get(i).map(|t| *t == b).unwrap_or(false))
|
s.bytes()
|
||||||
|
.enumerate()
|
||||||
|
.all(|(i, b)| self.bytes.get(i).map_or(false, |t| *t == b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unsigned_integer<T: Num>(&mut self) -> Result<T> {
|
pub fn unsigned_integer<T: Num>(&mut self) -> Result<T> {
|
||||||
|
@ -292,110 +508,158 @@ impl<'a> Bytes<'a> {
|
||||||
let num_bytes = self.next_bytes_contained_in(DIGITS);
|
let num_bytes = self.next_bytes_contained_in(DIGITS);
|
||||||
|
|
||||||
if num_bytes == 0 {
|
if num_bytes == 0 {
|
||||||
return self.err(ParseError::Eof);
|
return self.err(ParseError::ExpectedInteger);
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = Num::from_str(unsafe { from_utf8_unchecked(&self.bytes[0..num_bytes]) }, base)
|
let tmp;
|
||||||
.map_err(|_| self.error(ParseError::ExpectedInteger));
|
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);
|
let _ = self.advance(num_bytes);
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_hex_escape(&mut self) -> Result<u16> {
|
fn decode_ascii_escape(&mut self) -> Result<u8> {
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
for _ in 0..4 {
|
for _ in 0..2 {
|
||||||
n = match self.eat_byte()? {
|
n <<= 4;
|
||||||
c @ b'0' ... b'9' => n * 16_u16 + ((c as u16) - (b'0' as u16)),
|
let byte = self.eat_byte()?;
|
||||||
b'a' | b'A' => n * 16_u16 + 10_u16,
|
let decoded = self.decode_hex(byte)?;
|
||||||
b'b' | b'B' => n * 16_u16 + 11_u16,
|
n |= decoded;
|
||||||
b'c' | b'C' => n * 16_u16 + 12_u16,
|
|
||||||
b'd' | b'D' => n * 16_u16 + 13_u16,
|
|
||||||
b'e' | b'E' => n * 16_u16 + 14_u16,
|
|
||||||
b'f' | b'F' => n * 16_u16 + 15_u16,
|
|
||||||
_ => {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(n)
|
Ok(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_str_escape(&mut self, store: &mut Vec<u8>) -> Result<()> {
|
fn decode_hex(&self, c: u8) -> Result<u8> {
|
||||||
use std::iter::repeat;
|
match c {
|
||||||
|
c @ b'0'..=b'9' => Ok(c - b'0'),
|
||||||
match self.eat_byte()? {
|
c @ b'a'..=b'f' => Ok(10 + c - b'a'),
|
||||||
b'"' => store.push(b'"'),
|
c @ b'A'..=b'F' => Ok(10 + c - b'A'),
|
||||||
b'\\' => store.push(b'\\'),
|
_ => self.err(ParseError::InvalidEscape("Non-hex digit found")),
|
||||||
b'b' => store.push(b'\x08'),
|
|
||||||
b'f' => store.push(b'\x0c'),
|
|
||||||
b'n' => store.push(b'\n'),
|
|
||||||
b'r' => store.push(b'\r'),
|
|
||||||
b't' => store.push(b'\t'),
|
|
||||||
b'u' => {
|
|
||||||
let c: char = match self.decode_hex_escape()? {
|
|
||||||
0xDC00 ... 0xDFFF => {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
|
|
||||||
n1 @ 0xD800 ... 0xDBFF => {
|
|
||||||
if self.eat_byte()? != b'\\' {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.eat_byte()? != b'u' {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
|
|
||||||
let n2 = self.decode_hex_escape()?;
|
|
||||||
|
|
||||||
if n2 < 0xDC00 || n2 > 0xDFFF {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000;
|
|
||||||
|
|
||||||
match ::std::char::from_u32(n as u32) {
|
|
||||||
Some(c) => c,
|
|
||||||
None => {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n => {
|
|
||||||
match ::std::char::from_u32(n as u32) {
|
|
||||||
Some(c) => c,
|
|
||||||
None => {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let char_start = store.len();
|
|
||||||
store.extend(repeat(0).take(c.len_utf8()));
|
|
||||||
c.encode_utf8(&mut store[char_start..]);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return self.err(ParseError::InvalidEscape);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_comment(&mut self) -> bool {
|
fn parse_escape(&mut self) -> Result<char> {
|
||||||
if self.consume("//") {
|
let c = match self.eat_byte()? {
|
||||||
let bytes = self.bytes.iter().take_while(|&&b| b != b'\n').count();
|
b'\'' => '\'',
|
||||||
|
b'"' => '"',
|
||||||
|
b'\\' => '\\',
|
||||||
|
b'n' => '\n',
|
||||||
|
b'r' => '\r',
|
||||||
|
b't' => '\t',
|
||||||
|
b'x' => self.decode_ascii_escape()? as char,
|
||||||
|
b'u' => {
|
||||||
|
self.expect_byte(b'{', ParseError::InvalidEscape("Missing {"))?;
|
||||||
|
|
||||||
let _ = self.advance(bytes);
|
let mut bytes: u32 = 0;
|
||||||
|
let mut num_digits = 0;
|
||||||
|
|
||||||
true
|
while num_digits < 6 {
|
||||||
|
let byte = self.peek_or_eof()?;
|
||||||
|
|
||||||
|
if byte == b'}' {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.advance_single()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let byte = self.decode_hex(byte)?;
|
||||||
|
bytes <<= 4;
|
||||||
|
bytes |= byte as u32;
|
||||||
|
|
||||||
|
num_digits += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if num_digits == 0 {
|
||||||
|
return self.err(ParseError::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
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return self.err(ParseError::InvalidEscape("Unknown escape character"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_comment(&mut self) -> Result<bool> {
|
||||||
|
if self.consume("/") {
|
||||||
|
match self.eat_byte()? {
|
||||||
|
b'/' => {
|
||||||
|
let bytes = self.bytes.iter().take_while(|&&b| b != b'\n').count();
|
||||||
|
|
||||||
|
let _ = self.advance(bytes);
|
||||||
|
}
|
||||||
|
b'*' => {
|
||||||
|
let mut level = 1;
|
||||||
|
|
||||||
|
while level > 0 {
|
||||||
|
let bytes = self
|
||||||
|
.bytes
|
||||||
|
.iter()
|
||||||
|
.take_while(|&&b| b != b'/' && b != b'*')
|
||||||
|
.count();
|
||||||
|
|
||||||
|
if self.bytes.is_empty() {
|
||||||
|
return self.err(ParseError::UnclosedBlockComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = self.advance(bytes);
|
||||||
|
|
||||||
|
// check whether / or * and take action
|
||||||
|
if self.consume("/*") {
|
||||||
|
level += 1;
|
||||||
|
} else if self.consume("*/") {
|
||||||
|
level -= 1;
|
||||||
|
} else {
|
||||||
|
self.eat_byte()
|
||||||
|
.map_err(|_| self.error(ParseError::UnclosedBlockComment))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b => return self.err(ParseError::UnexpectedByte(b as char)),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
false
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,7 +696,18 @@ pub struct Position {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Position {
|
impl Display for Position {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
write!(f, "{}:{}", self.line, self.col)
|
write!(f, "{}:{}", self.line, self.col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_x10() {
|
||||||
|
let mut bytes = Bytes::new(b"10").unwrap();
|
||||||
|
assert_eq!(bytes.decode_ascii_escape(), Ok(0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
use std::error::Error as StdError;
|
use serde::{ser, Deserialize, Serialize};
|
||||||
use std::fmt::{Display, Formatter, Write, Result as FmtResult};
|
use std::{
|
||||||
use std::result::Result as StdResult;
|
error::Error as StdError,
|
||||||
|
fmt::{Display, Formatter, Result as FmtResult, Write},
|
||||||
|
};
|
||||||
|
|
||||||
use serde::ser::{self, Serialize};
|
|
||||||
|
|
||||||
#[deprecated(since="0.1.4", note="please use `to_string_pretty` with `PrettyConfig::default()` instead")]
|
|
||||||
pub mod pretty;
|
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
/// Serializes `value` and returns it as string.
|
/// Serializes `value` and returns it as string.
|
||||||
///
|
///
|
||||||
/// This function does not generate any newlines or nice formatting;
|
/// This function does not generate any newlines or nice formatting;
|
||||||
/// if you want that, you can use `pretty::to_string` instead.
|
/// if you want that, you can use `to_string_pretty` instead.
|
||||||
pub fn to_string<T>(value: &T) -> Result<String>
|
pub fn to_string<T>(value: &T) -> Result<String>
|
||||||
where T: Serialize
|
where
|
||||||
|
T: Serialize,
|
||||||
{
|
{
|
||||||
let mut s = Serializer {
|
let mut s = Serializer {
|
||||||
output: String::new(),
|
output: String::new(),
|
||||||
pretty: None,
|
pretty: None,
|
||||||
struct_names: false,
|
struct_names: false,
|
||||||
|
is_empty: None,
|
||||||
};
|
};
|
||||||
value.serialize(&mut s)?;
|
value.serialize(&mut s)?;
|
||||||
Ok(s.output)
|
Ok(s.output)
|
||||||
|
@ -26,19 +26,27 @@ pub fn to_string<T>(value: &T) -> Result<String>
|
||||||
|
|
||||||
/// Serializes `value` in the recommended RON layout in a pretty way.
|
/// Serializes `value` in the recommended RON layout in a pretty way.
|
||||||
pub fn to_string_pretty<T>(value: &T, config: PrettyConfig) -> Result<String>
|
pub fn to_string_pretty<T>(value: &T, config: PrettyConfig) -> Result<String>
|
||||||
where T: Serialize
|
where
|
||||||
|
T: Serialize,
|
||||||
{
|
{
|
||||||
let mut s = Serializer {
|
let mut s = Serializer {
|
||||||
output: String::new(),
|
output: String::new(),
|
||||||
pretty: Some((config, Pretty { indent: 0, sequence_index: Vec::new() })),
|
pretty: Some((
|
||||||
|
config,
|
||||||
|
Pretty {
|
||||||
|
indent: 0,
|
||||||
|
sequence_index: Vec::new(),
|
||||||
|
},
|
||||||
|
)),
|
||||||
struct_names: false,
|
struct_names: false,
|
||||||
|
is_empty: None,
|
||||||
};
|
};
|
||||||
value.serialize(&mut s)?;
|
value.serialize(&mut s)?;
|
||||||
Ok(s.output)
|
Ok(s.output)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialization result.
|
/// Serialization result.
|
||||||
pub type Result<T> = StdResult<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
/// Serialization error.
|
/// Serialization error.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -48,7 +56,7 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Message(ref e) => write!(f, "Custom message: {}", e),
|
Error::Message(ref e) => write!(f, "Custom message: {}", e),
|
||||||
}
|
}
|
||||||
|
@ -78,6 +86,8 @@ struct Pretty {
|
||||||
/// Pretty serializer configuration
|
/// Pretty serializer configuration
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct PrettyConfig {
|
pub struct PrettyConfig {
|
||||||
|
/// Limit the pretty-ness up to the given depth.
|
||||||
|
pub depth_limit: usize,
|
||||||
/// New line string
|
/// New line string
|
||||||
pub new_line: String,
|
pub new_line: String,
|
||||||
/// Indentation string
|
/// Indentation string
|
||||||
|
@ -91,6 +101,7 @@ pub struct PrettyConfig {
|
||||||
impl Default for PrettyConfig {
|
impl Default for PrettyConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
PrettyConfig {
|
PrettyConfig {
|
||||||
|
depth_limit: !0,
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
new_line: "\n".to_string(),
|
new_line: "\n".to_string(),
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
@ -110,6 +121,7 @@ pub struct Serializer {
|
||||||
output: String,
|
output: String,
|
||||||
pretty: Option<(PrettyConfig, Pretty)>,
|
pretty: Option<(PrettyConfig, Pretty)>,
|
||||||
struct_names: bool,
|
struct_names: bool,
|
||||||
|
is_empty: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serializer {
|
impl Serializer {
|
||||||
|
@ -119,8 +131,17 @@ impl Serializer {
|
||||||
pub fn new(config: Option<PrettyConfig>, struct_names: bool) -> Self {
|
pub fn new(config: Option<PrettyConfig>, struct_names: bool) -> Self {
|
||||||
Serializer {
|
Serializer {
|
||||||
output: String::new(),
|
output: String::new(),
|
||||||
pretty: config.map(|conf| (conf, Pretty { indent: 0, sequence_index: Vec::new() })),
|
pretty: config.map(|conf| {
|
||||||
|
(
|
||||||
|
conf,
|
||||||
|
Pretty {
|
||||||
|
indent: 0,
|
||||||
|
sequence_index: Vec::new(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}),
|
||||||
struct_names,
|
struct_names,
|
||||||
|
is_empty: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,44 +150,75 @@ impl Serializer {
|
||||||
self.output
|
self.output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_pretty(&self) -> bool {
|
||||||
|
match self.pretty {
|
||||||
|
Some((ref config, ref pretty)) => pretty.indent < config.depth_limit,
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn separate_tuple_members(&self) -> bool {
|
fn separate_tuple_members(&self) -> bool {
|
||||||
self.pretty.as_ref()
|
self.pretty
|
||||||
.map(|&(ref config, _)| config.separate_tuple_members)
|
.as_ref()
|
||||||
.unwrap_or(false)
|
.map_or(false, |&(ref config, _)| config.separate_tuple_members)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_indent(&mut self) {
|
fn start_indent(&mut self) {
|
||||||
if let Some((ref config, ref mut pretty)) = self.pretty {
|
if let Some((ref config, ref mut pretty)) = self.pretty {
|
||||||
pretty.indent += 1;
|
pretty.indent += 1;
|
||||||
self.output += &config.new_line;
|
if pretty.indent < config.depth_limit {
|
||||||
|
let is_empty = self.is_empty.unwrap_or(false);
|
||||||
|
|
||||||
|
if !is_empty {
|
||||||
|
self.output += &config.new_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn indent(&mut self) {
|
fn indent(&mut self) {
|
||||||
if let Some((ref config, ref pretty)) = self.pretty {
|
if let Some((ref config, ref pretty)) = self.pretty {
|
||||||
self.output.extend((0..pretty.indent).map(|_| config.indentor.as_str()));
|
if pretty.indent < config.depth_limit {
|
||||||
|
self.output
|
||||||
|
.extend((0..pretty.indent).map(|_| config.indentor.as_str()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_indent(&mut self) {
|
fn end_indent(&mut self) {
|
||||||
if let Some((ref config, ref mut pretty)) = self.pretty {
|
if let Some((ref config, ref mut pretty)) = self.pretty {
|
||||||
|
if pretty.indent < config.depth_limit {
|
||||||
|
let is_empty = self.is_empty.unwrap_or(false);
|
||||||
|
|
||||||
|
if !is_empty {
|
||||||
|
self.output
|
||||||
|
.extend((1..pretty.indent).map(|_| config.indentor.as_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
pretty.indent -= 1;
|
pretty.indent -= 1;
|
||||||
self.output.extend((0..pretty.indent).map(|_| config.indentor.as_str()));
|
|
||||||
|
self.is_empty = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_escaped_str(&mut self, value: &str) {
|
||||||
|
let value = value.chars().flat_map(|c| c.escape_debug());
|
||||||
|
self.output += "\"";
|
||||||
|
self.output.extend(value);
|
||||||
|
self.output += "\"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::Serializer for &'a mut Serializer {
|
impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
type SerializeMap = Self;
|
||||||
type SerializeSeq = Self;
|
type SerializeSeq = Self;
|
||||||
|
type SerializeStruct = Self;
|
||||||
|
type SerializeStructVariant = Self;
|
||||||
type SerializeTuple = Self;
|
type SerializeTuple = Self;
|
||||||
type SerializeTupleStruct = Self;
|
type SerializeTupleStruct = Self;
|
||||||
type SerializeTupleVariant = Self;
|
type SerializeTupleVariant = Self;
|
||||||
type SerializeMap = Self;
|
|
||||||
type SerializeStruct = Self;
|
|
||||||
type SerializeStructVariant = Self;
|
|
||||||
|
|
||||||
fn serialize_bool(self, v: bool) -> Result<()> {
|
fn serialize_bool(self, v: bool) -> Result<()> {
|
||||||
self.output += if v { "true" } else { "false" };
|
self.output += if v { "true" } else { "false" };
|
||||||
|
@ -209,7 +261,8 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_f32(self, v: f32) -> Result<()> {
|
fn serialize_f32(self, v: f32) -> Result<()> {
|
||||||
self.serialize_f64(v as f64)
|
self.output += &v.to_string();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_f64(self, v: f64) -> Result<()> {
|
fn serialize_f64(self, v: f64) -> Result<()> {
|
||||||
|
@ -228,25 +281,13 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_str(self, v: &str) -> Result<()> {
|
fn serialize_str(self, v: &str) -> Result<()> {
|
||||||
self.output += "\"";
|
self.serialize_escaped_str(v);
|
||||||
for char in v.chars() {
|
|
||||||
if char == '\\' || char == '"' {
|
|
||||||
self.output.push('\\');
|
|
||||||
}
|
|
||||||
self.output.push(char);
|
|
||||||
}
|
|
||||||
self.output += "\"";
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_bytes(self, v: &[u8]) -> Result<()> {
|
fn serialize_bytes(self, v: &[u8]) -> Result<()> {
|
||||||
use serde::ser::SerializeSeq;
|
self.serialize_str(base64::encode(v).as_str())
|
||||||
//TODO: shorter version? e.g. base64 encoding in a single line
|
|
||||||
let mut seq = self.serialize_seq(Some(v.len()))?;
|
|
||||||
for byte in v {
|
|
||||||
seq.serialize_element(byte)?;
|
|
||||||
}
|
|
||||||
seq.end()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_none(self) -> Result<()> {
|
fn serialize_none(self) -> Result<()> {
|
||||||
|
@ -256,7 +297,8 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_some<T>(self, value: &T) -> Result<()>
|
fn serialize_some<T>(self, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.output += "Some(";
|
self.output += "Some(";
|
||||||
value.serialize(&mut *self)?;
|
value.serialize(&mut *self)?;
|
||||||
|
@ -281,19 +323,15 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
fn serialize_unit_variant(self, _: &'static str, _: u32, variant: &'static str) -> Result<()> {
|
||||||
self,
|
|
||||||
_: &'static str,
|
|
||||||
_: u32,
|
|
||||||
variant: &'static str
|
|
||||||
) -> Result<()> {
|
|
||||||
self.output += variant;
|
self.output += variant;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<()>
|
fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
if self.struct_names {
|
if self.struct_names {
|
||||||
self.output += name;
|
self.output += name;
|
||||||
|
@ -310,9 +348,10 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: u32,
|
_: u32,
|
||||||
variant: &'static str,
|
variant: &'static str,
|
||||||
value: &T
|
value: &T,
|
||||||
) -> Result<()>
|
) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.output += variant;
|
self.output += variant;
|
||||||
self.output += "(";
|
self.output += "(";
|
||||||
|
@ -323,9 +362,13 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq> {
|
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
|
||||||
self.output += "[";
|
self.output += "[";
|
||||||
|
|
||||||
|
if let Some(len) = len {
|
||||||
|
self.is_empty = Some(len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
self.start_indent();
|
self.start_indent();
|
||||||
|
|
||||||
if let Some((_, ref mut pretty)) = self.pretty {
|
if let Some((_, ref mut pretty)) = self.pretty {
|
||||||
|
@ -335,10 +378,12 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple> {
|
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
|
||||||
self.output += "(";
|
self.output += "(";
|
||||||
|
|
||||||
if self.separate_tuple_members() {
|
if self.separate_tuple_members() {
|
||||||
|
self.is_empty = Some(len == 0);
|
||||||
|
|
||||||
self.start_indent();
|
self.start_indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +393,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
fn serialize_tuple_struct(
|
fn serialize_tuple_struct(
|
||||||
self,
|
self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
len: usize
|
len: usize,
|
||||||
) -> Result<Self::SerializeTupleStruct> {
|
) -> Result<Self::SerializeTupleStruct> {
|
||||||
if self.struct_names {
|
if self.struct_names {
|
||||||
self.output += name;
|
self.output += name;
|
||||||
|
@ -362,36 +407,39 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: u32,
|
_: u32,
|
||||||
variant: &'static str,
|
variant: &'static str,
|
||||||
_: usize
|
len: usize,
|
||||||
) -> Result<Self::SerializeTupleVariant> {
|
) -> Result<Self::SerializeTupleVariant> {
|
||||||
self.output += variant;
|
self.output += variant;
|
||||||
self.output += "(";
|
self.output += "(";
|
||||||
|
|
||||||
if self.separate_tuple_members() {
|
if self.separate_tuple_members() {
|
||||||
|
self.is_empty = Some(len == 0);
|
||||||
|
|
||||||
self.start_indent();
|
self.start_indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
|
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
|
||||||
self.output += "{";
|
self.output += "{";
|
||||||
|
|
||||||
|
if let Some(len) = len {
|
||||||
|
self.is_empty = Some(len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
self.start_indent();
|
self.start_indent();
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct(
|
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
_: usize
|
|
||||||
) -> Result<Self::SerializeStruct> {
|
|
||||||
if self.struct_names {
|
if self.struct_names {
|
||||||
self.output += name;
|
self.output += name;
|
||||||
}
|
}
|
||||||
self.output += "(";
|
self.output += "(";
|
||||||
|
|
||||||
|
self.is_empty = Some(len == 0);
|
||||||
self.start_indent();
|
self.start_indent();
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
@ -402,11 +450,12 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: u32,
|
_: u32,
|
||||||
variant: &'static str,
|
variant: &'static str,
|
||||||
_: usize
|
len: usize,
|
||||||
) -> Result<Self::SerializeStructVariant> {
|
) -> Result<Self::SerializeStructVariant> {
|
||||||
self.output += variant;
|
self.output += variant;
|
||||||
self.output += "(";
|
self.output += "(";
|
||||||
|
|
||||||
|
self.is_empty = Some(len == 0);
|
||||||
self.start_indent();
|
self.start_indent();
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
@ -414,11 +463,12 @@ impl<'a> ser::Serializer for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::SerializeSeq for &'a mut Serializer {
|
impl<'a> ser::SerializeSeq for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
|
||||||
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.indent();
|
self.indent();
|
||||||
|
|
||||||
|
@ -426,15 +476,17 @@ impl<'a> ser::SerializeSeq for &'a mut Serializer {
|
||||||
self.output += ",";
|
self.output += ",";
|
||||||
|
|
||||||
if let Some((ref config, ref mut pretty)) = self.pretty {
|
if let Some((ref config, ref mut pretty)) = self.pretty {
|
||||||
if config.enumerate_arrays {
|
if pretty.indent < config.depth_limit {
|
||||||
assert!(config.new_line.contains('\n'));
|
if config.enumerate_arrays {
|
||||||
let index = pretty.sequence_index.last_mut().unwrap();
|
assert!(config.new_line.contains('\n'));
|
||||||
//TODO: when /**/ comments are supported, prepend the index
|
let index = pretty.sequence_index.last_mut().unwrap();
|
||||||
// to an element instead of appending it.
|
//TODO: when /**/ comments are supported, prepend the index
|
||||||
write!(self.output, "// [{}]", index).unwrap();
|
// to an element instead of appending it.
|
||||||
*index += 1;
|
write!(self.output, "// [{}]", index).unwrap();
|
||||||
|
*index += 1;
|
||||||
|
}
|
||||||
|
self.output += &config.new_line;
|
||||||
}
|
}
|
||||||
self.output += &config.new_line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -453,11 +505,12 @@ impl<'a> ser::SerializeSeq for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::SerializeTuple for &'a mut Serializer {
|
impl<'a> ser::SerializeTuple for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
|
||||||
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
if self.separate_tuple_members() {
|
if self.separate_tuple_members() {
|
||||||
self.indent();
|
self.indent();
|
||||||
|
@ -466,21 +519,25 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer {
|
||||||
value.serialize(&mut **self)?;
|
value.serialize(&mut **self)?;
|
||||||
self.output += ",";
|
self.output += ",";
|
||||||
|
|
||||||
if let Some((ref config, _)) = self.pretty {
|
if let Some((ref config, ref pretty)) = self.pretty {
|
||||||
self.output += if self.separate_tuple_members() { &config.new_line } else { " " };
|
if pretty.indent < config.depth_limit {
|
||||||
|
self.output += if self.separate_tuple_members() {
|
||||||
|
&config.new_line
|
||||||
|
} else {
|
||||||
|
" "
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<()> {
|
fn end(self) -> Result<()> {
|
||||||
if self.pretty.is_some() {
|
if self.separate_tuple_members() {
|
||||||
if self.separate_tuple_members() {
|
self.end_indent();
|
||||||
self.end_indent();
|
} else if self.is_pretty() {
|
||||||
} else {
|
self.output.pop();
|
||||||
self.output.pop();
|
self.output.pop();
|
||||||
self.output.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.output += ")";
|
self.output += ")";
|
||||||
|
@ -491,11 +548,12 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer {
|
||||||
|
|
||||||
// Same thing but for tuple structs.
|
// Same thing but for tuple structs.
|
||||||
impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
|
impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
ser::SerializeTuple::serialize_element(self, value)
|
ser::SerializeTuple::serialize_element(self, value)
|
||||||
}
|
}
|
||||||
|
@ -506,11 +564,12 @@ impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {
|
impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
ser::SerializeTuple::serialize_element(self, value)
|
ser::SerializeTuple::serialize_element(self, value)
|
||||||
}
|
}
|
||||||
|
@ -521,11 +580,12 @@ impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::SerializeMap for &'a mut Serializer {
|
impl<'a> ser::SerializeMap for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
|
||||||
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
|
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.indent();
|
self.indent();
|
||||||
|
|
||||||
|
@ -533,19 +593,22 @@ impl<'a> ser::SerializeMap for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.output += ":";
|
self.output += ":";
|
||||||
|
|
||||||
if self.pretty.is_some() {
|
if self.is_pretty() {
|
||||||
self.output += " ";
|
self.output += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
value.serialize(&mut **self)?;
|
value.serialize(&mut **self)?;
|
||||||
self.output += ",";
|
self.output += ",";
|
||||||
|
|
||||||
if let Some((ref config, _)) = self.pretty {
|
if let Some((ref config, ref pretty)) = self.pretty {
|
||||||
self.output += &config.new_line;
|
if pretty.indent < config.depth_limit {
|
||||||
|
self.output += &config.new_line;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -560,26 +623,29 @@ impl<'a> ser::SerializeMap for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::SerializeStruct for &'a mut Serializer {
|
impl<'a> ser::SerializeStruct for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.indent();
|
self.indent();
|
||||||
|
|
||||||
self.output += key;
|
self.output += key;
|
||||||
self.output += ":";
|
self.output += ":";
|
||||||
|
|
||||||
if self.pretty.is_some() {
|
if self.is_pretty() {
|
||||||
self.output += " ";
|
self.output += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
value.serialize(&mut **self)?;
|
value.serialize(&mut **self)?;
|
||||||
self.output += ",";
|
self.output += ",";
|
||||||
|
|
||||||
if let Some((ref config, _)) = self.pretty {
|
if let Some((ref config, ref pretty)) = self.pretty {
|
||||||
self.output += &config.new_line;
|
if pretty.indent < config.depth_limit {
|
||||||
|
self.output += &config.new_line;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -594,11 +660,12 @@ impl<'a> ser::SerializeStruct for &'a mut Serializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::SerializeStructVariant for &'a mut Serializer {
|
impl<'a> ser::SerializeStructVariant for &'a mut Serializer {
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Ok = ();
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
||||||
where T: ?Sized + Serialize
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
ser::SerializeStruct::serialize_field(self, key, value)
|
ser::SerializeStruct::serialize_field(self, key, value)
|
||||||
}
|
}
|
||||||
|
@ -619,14 +686,17 @@ mod tests {
|
||||||
struct EmptyStruct2 {}
|
struct EmptyStruct2 {}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct MyStruct { x: f32, y: f32 }
|
struct MyStruct {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
enum MyEnum {
|
enum MyEnum {
|
||||||
A,
|
A,
|
||||||
B(bool),
|
B(bool),
|
||||||
C(bool, f32),
|
C(bool, f32),
|
||||||
D { a: i32, b: i32 }
|
D { a: i32, b: i32 },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -641,7 +711,6 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(to_string(&my_struct).unwrap(), "(x:4,y:7,)");
|
assert_eq!(to_string(&my_struct).unwrap(), "(x:4,y:7,)");
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct NewType(i32);
|
struct NewType(i32);
|
||||||
|
|
||||||
|
@ -707,4 +776,25 @@ mod tests {
|
||||||
fn test_escape() {
|
fn test_escape() {
|
||||||
assert_eq!(to_string(&r#""Quoted""#).unwrap(), r#""\"Quoted\"""#);
|
assert_eq!(to_string(&r#""Quoted""#).unwrap(), r#""\"Quoted\"""#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_byte_stream() {
|
||||||
|
use serde_bytes;
|
||||||
|
|
||||||
|
let small: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||||
|
assert_eq!(
|
||||||
|
to_string(&small).unwrap(),
|
||||||
|
"(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,)"
|
||||||
|
);
|
||||||
|
|
||||||
|
let large = vec![255u8; 64];
|
||||||
|
let large = serde_bytes::Bytes::new(&large);
|
||||||
|
assert_eq!(
|
||||||
|
to_string(&large).unwrap(),
|
||||||
|
concat!(
|
||||||
|
"\"/////////////////////////////////////////",
|
||||||
|
"////////////////////////////////////////////w==\""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
//! Provides default pretty serialization with `to_string`.
|
|
||||||
|
|
||||||
use super::{Result, to_string_pretty};
|
|
||||||
|
|
||||||
use serde::ser::Serialize;
|
|
||||||
use std::default::Default;
|
|
||||||
|
|
||||||
/// Serializes `value` in the recommended RON layout with
|
|
||||||
/// default pretty configuration.
|
|
||||||
pub fn to_string<T>(value: &T) -> Result<String>
|
|
||||||
where T: Serialize
|
|
||||||
{
|
|
||||||
to_string_pretty(value, Default::default())
|
|
||||||
}
|
|
|
@ -1,11 +1,11 @@
|
||||||
use serde::ser::{Serialize, Serializer};
|
use serde::ser::{Serialize, Serializer};
|
||||||
|
|
||||||
use value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
impl Serialize for Value {
|
impl Serialize for Value {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer
|
S: Serializer,
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
Value::Bool(b) => serializer.serialize_bool(b),
|
Value::Bool(b) => serializer.serialize_bool(b),
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
//! Value module.
|
//! Value module.
|
||||||
|
|
||||||
use std::cmp::{Eq, Ordering};
|
use serde::{
|
||||||
use std::collections::BTreeMap;
|
de::{
|
||||||
use std::hash::{Hash, Hasher};
|
DeserializeOwned, DeserializeSeed, Deserializer, Error as SerdeError, MapAccess, SeqAccess, Visitor,
|
||||||
|
},
|
||||||
|
forward_to_deserialize_any,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
cmp::{Eq, Ordering},
|
||||||
|
collections::BTreeMap,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
use serde::de::{DeserializeSeed, Deserializer, Error as SerdeErr, MapAccess, SeqAccess, Visitor};
|
use crate::de::{Error as RonError, Result};
|
||||||
|
|
||||||
use de::{Error as RonError, Result};
|
|
||||||
|
|
||||||
/// A wrapper for `f64` which guarantees that the inner value
|
/// A wrapper for `f64` which guarantees that the inner value
|
||||||
/// is finite and thus implements `Eq`, `Hash` and `Ord`.
|
/// is finite and thus implements `Eq`, `Hash` and `Ord`.
|
||||||
|
@ -25,7 +31,7 @@ impl Number {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the wrapped float.
|
/// Returns the wrapped float.
|
||||||
pub fn get(&self) -> f64 {
|
pub fn get(self) -> f64 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,11 +62,27 @@ pub enum Value {
|
||||||
Unit,
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
/// Tries to deserialize this `Value` into `T`.
|
||||||
|
pub fn into_rust<T>(self) -> Result<T>
|
||||||
|
where
|
||||||
|
T: DeserializeOwned,
|
||||||
|
{
|
||||||
|
T::deserialize(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserializer implementation for RON `Value`.
|
/// Deserializer implementation for RON `Value`.
|
||||||
/// This does not support enums (because `Value` doesn't store them).
|
/// This does not support enums (because `Value` doesn't store them).
|
||||||
impl<'de> Deserializer<'de> for Value {
|
impl<'de> Deserializer<'de> for Value {
|
||||||
type Error = RonError;
|
type Error = RonError;
|
||||||
|
|
||||||
|
forward_to_deserialize_any! {
|
||||||
|
bool f32 f64 char str string bytes
|
||||||
|
byte_buf option unit unit_struct newtype_struct seq tuple
|
||||||
|
tuple_struct map struct enum identifier ignored_any
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
|
@ -78,7 +100,6 @@ impl<'de> Deserializer<'de> for Value {
|
||||||
Value::String(s) => visitor.visit_string(s),
|
Value::String(s) => visitor.visit_string(s),
|
||||||
Value::Seq(mut seq) => {
|
Value::Seq(mut seq) => {
|
||||||
seq.reverse();
|
seq.reverse();
|
||||||
|
|
||||||
visitor.visit_seq(Seq { seq })
|
visitor.visit_seq(Seq { seq })
|
||||||
}
|
}
|
||||||
Value::Unit => visitor.visit_unit(),
|
Value::Unit => visitor.visit_unit(),
|
||||||
|
@ -146,12 +167,6 @@ impl<'de> Deserializer<'de> for Value {
|
||||||
v => Err(RonError::custom(format!("Expected a number, got {:?}", v))),
|
v => Err(RonError::custom(format!("Expected a number, got {:?}", v))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forward_to_deserialize_any! {
|
|
||||||
bool f32 f64 char str string bytes
|
|
||||||
byte_buf option unit unit_struct newtype_struct seq tuple
|
|
||||||
tuple_struct map struct enum identifier ignored_any
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Map {
|
struct Map {
|
||||||
|
@ -204,15 +219,15 @@ impl<'de> SeqAccess<'de> for Seq {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::fmt::Debug;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
fn assert_same<'de, T>(s: &'de str)
|
fn assert_same<'de, T>(s: &'de str)
|
||||||
where
|
where
|
||||||
T: Debug + Deserialize<'de> + PartialEq,
|
T: Debug + Deserialize<'de> + PartialEq,
|
||||||
{
|
{
|
||||||
use de::from_str;
|
use crate::de::from_str;
|
||||||
|
|
||||||
let direct: T = from_str(s).unwrap();
|
let direct: T = from_str(s).unwrap();
|
||||||
let value: Value = from_str(s).unwrap();
|
let value: Value = from_str(s).unwrap();
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct UnitStruct;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct NewType(f32);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct TupleStruct(UnitStruct, i8);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
struct Key(u32);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
enum Enum {
|
||||||
|
Unit,
|
||||||
|
Bool(bool),
|
||||||
|
Chars(char, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct Struct {
|
||||||
|
tuple: ((), NewType, TupleStruct),
|
||||||
|
vec: Vec<Option<UnitStruct>>,
|
||||||
|
map: HashMap<Key, Enum>,
|
||||||
|
deep_vec: HashMap<Key, Vec<()>>,
|
||||||
|
deep_map: HashMap<Key, HashMap<Key, Enum>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_sets_arrays() {
|
||||||
|
let value = Struct {
|
||||||
|
tuple: ((), NewType(0.5), TupleStruct(UnitStruct, -5)),
|
||||||
|
vec: vec![],
|
||||||
|
map: vec![].into_iter().collect(),
|
||||||
|
deep_vec: vec![(Key(0), vec![])].into_iter().collect(),
|
||||||
|
deep_map: vec![(Key(0), vec![].into_iter().collect())]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pretty = ron::ser::PrettyConfig {
|
||||||
|
enumerate_arrays: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
|
||||||
|
|
||||||
|
println!("Serialized: {}", serial);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
"(
|
||||||
|
tuple: ((), (0.5), ((), -5)),
|
||||||
|
vec: [],
|
||||||
|
map: {},
|
||||||
|
deep_vec: {
|
||||||
|
(0): [],
|
||||||
|
},
|
||||||
|
deep_map: {
|
||||||
|
(0): {},
|
||||||
|
},
|
||||||
|
)",
|
||||||
|
serial
|
||||||
|
);
|
||||||
|
|
||||||
|
let deserial = ron::de::from_str(&serial);
|
||||||
|
|
||||||
|
assert_eq!(Ok(value), deserial);
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
extern crate ron;
|
use serde::{Deserialize, Serialize};
|
||||||
#[macro_use]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ImVec2 {
|
pub struct ImVec2 {
|
||||||
|
@ -39,8 +37,12 @@ pub struct ImGuiStyleSave {
|
||||||
pub anti_aliased_shapes: bool,
|
pub anti_aliased_shapes: bool,
|
||||||
pub curve_tessellation_tol: f32,
|
pub curve_tessellation_tol: f32,
|
||||||
pub colors: ImColorsSave,
|
pub colors: ImColorsSave,
|
||||||
|
pub new_type: NewType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct NewType(i32);
|
||||||
|
|
||||||
const CONFIG: &str = "(
|
const CONFIG: &str = "(
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
window_padding: (x: 8, y: 8),
|
window_padding: (x: 8, y: 8),
|
||||||
|
@ -66,6 +68,7 @@ const CONFIG: &str = "(
|
||||||
anti_aliased_shapes: true,
|
anti_aliased_shapes: true,
|
||||||
curve_tessellation_tol: 1.25,
|
curve_tessellation_tol: 1.25,
|
||||||
colors: (text: 4),
|
colors: (text: 4),
|
||||||
|
new_type: NewType( 1 ),
|
||||||
|
|
||||||
ignored_field: \"Totally ignored, not causing a panic. Hopefully.\",
|
ignored_field: \"Totally ignored, not causing a panic. Hopefully.\",
|
||||||
)";
|
)";
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
use ron::de::{from_str, Error as RonErr, ParseError, Position};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_simple() {
|
||||||
|
assert_eq!(
|
||||||
|
from_str(
|
||||||
|
"/*
|
||||||
|
* We got a hexadecimal number here!
|
||||||
|
*
|
||||||
|
*/0x507"
|
||||||
|
),
|
||||||
|
Ok(0x507)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested() {
|
||||||
|
assert_eq!(
|
||||||
|
from_str(
|
||||||
|
"/*
|
||||||
|
/* quite * some * nesting * going * on * /* here /* (yeah, maybe a bit too much) */ */ */
|
||||||
|
*/
|
||||||
|
// The actual value comes.. /*
|
||||||
|
// very soon, these are just checks that */
|
||||||
|
// multi-line comments don't trigger in line comments /*
|
||||||
|
\"THE VALUE\" /* This is the value /* :) */ */
|
||||||
|
"
|
||||||
|
),
|
||||||
|
Ok("THE VALUE".to_owned())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unclosed() {
|
||||||
|
assert_eq!(
|
||||||
|
from_str::<String>(
|
||||||
|
"/*
|
||||||
|
/* quite * some * nesting * going * on * /* here /* (yeah, maybe a bit too much) */ */ */
|
||||||
|
*/
|
||||||
|
// The actual value comes.. /*
|
||||||
|
// very soon, these are just checks that */
|
||||||
|
// multi-line comments don't trigger in line comments /*
|
||||||
|
/* Unfortunately, this comment won't get closed :(
|
||||||
|
\"THE VALUE (which is invalid)\"
|
||||||
|
"
|
||||||
|
),
|
||||||
|
Err(RonErr::Parser(
|
||||||
|
ParseError::UnclosedBlockComment,
|
||||||
|
Position { col: 1, line: 9 }
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Config {
|
||||||
|
float: (f32, f64),
|
||||||
|
tuple: TupleStruct,
|
||||||
|
map: HashMap<u8, char>,
|
||||||
|
nested: Nested,
|
||||||
|
var: Variant,
|
||||||
|
array: Vec<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct TupleStruct((), bool);
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
enum Variant {
|
||||||
|
A(u8, &'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Nested {
|
||||||
|
a: String,
|
||||||
|
b: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
const EXPECTED: &str = "(
|
||||||
|
float: (2.18,-1.1,),
|
||||||
|
tuple: ((),false,),
|
||||||
|
map: {8:'1',},
|
||||||
|
nested: (a:\"a\",b:'b',),
|
||||||
|
var: A(255,\"\",),
|
||||||
|
array: [(),(),(),],
|
||||||
|
)";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn depth_limit() {
|
||||||
|
let data = Config {
|
||||||
|
float: (2.18, -1.1),
|
||||||
|
tuple: TupleStruct((), false),
|
||||||
|
map: vec![(8, '1')].into_iter().collect(),
|
||||||
|
nested: Nested {
|
||||||
|
a: "a".to_owned(),
|
||||||
|
b: 'b',
|
||||||
|
},
|
||||||
|
var: Variant::A(!0, ""),
|
||||||
|
array: vec![(); 3],
|
||||||
|
};
|
||||||
|
|
||||||
|
let pretty = ron::ser::PrettyConfig {
|
||||||
|
depth_limit: 2,
|
||||||
|
separate_tuple_members: true,
|
||||||
|
enumerate_arrays: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let s = ron::ser::to_string_pretty(&data, pretty);
|
||||||
|
|
||||||
|
assert_eq!(s, Ok(EXPECTED.to_string()));
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
use ron::{de::from_str, ser::to_string};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{char::from_u32, fmt::Debug};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_escape_basic() {
|
||||||
|
assert_eq!(to_string(&"\x07").unwrap(), "\"\\u{7}\"");
|
||||||
|
|
||||||
|
assert_eq!(from_str::<String>("\"\\x07\"").unwrap(), "\x07");
|
||||||
|
assert_eq!(from_str::<String>("\"\\u{7}\"").unwrap(), "\x07");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_same<T>(t: T)
|
||||||
|
where
|
||||||
|
T: Debug + for<'a> Deserialize<'a> + PartialEq + Serialize,
|
||||||
|
{
|
||||||
|
let s: String = to_string(&t).unwrap();
|
||||||
|
|
||||||
|
println!("Serialized: \n\n{}\n\n", s);
|
||||||
|
|
||||||
|
assert_eq!(from_str(&s), Ok(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ascii_10() {
|
||||||
|
check_same("\u{10}".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ascii_chars() {
|
||||||
|
(1..128).into_iter().flat_map(from_u32).for_each(check_same)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ascii_string() {
|
||||||
|
let s: String = (1..128).into_iter().flat_map(from_u32).collect();
|
||||||
|
|
||||||
|
check_same(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_non_ascii() {
|
||||||
|
assert_eq!(to_string(&"♠").unwrap(), "\"♠\"");
|
||||||
|
assert_eq!(to_string(&"ß").unwrap(), "\"ß\"");
|
||||||
|
assert_eq!(to_string(&"ä").unwrap(), "\"ä\"");
|
||||||
|
assert_eq!(to_string(&"ö").unwrap(), "\"ö\"");
|
||||||
|
assert_eq!(to_string(&"ü").unwrap(), "\"ü\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_chars() {
|
||||||
|
assert_eq!(to_string(&'♠').unwrap(), "'♠'");
|
||||||
|
assert_eq!(to_string(&'ß').unwrap(), "'ß'");
|
||||||
|
assert_eq!(to_string(&'ä').unwrap(), "'ä'");
|
||||||
|
assert_eq!(to_string(&'ö').unwrap(), "'ö'");
|
||||||
|
assert_eq!(to_string(&'ü').unwrap(), "'ü'");
|
||||||
|
assert_eq!(to_string(&'\u{715}').unwrap(), "'\u{715}'");
|
||||||
|
assert_eq!(
|
||||||
|
from_str::<char>("'\u{715}'").unwrap(),
|
||||||
|
from_str("'\\u{715}'").unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nul_in_string() {
|
||||||
|
check_same("Hello\0World!".to_owned());
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct UnitStruct;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct NewType(f32);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct TupleStruct(UnitStruct, i8);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
struct Key(u32);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
enum Enum {
|
||||||
|
Unit,
|
||||||
|
Bool(bool),
|
||||||
|
Chars(char, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
struct Struct {
|
||||||
|
tuple: ((), NewType, TupleStruct),
|
||||||
|
vec: Vec<Option<UnitStruct>>,
|
||||||
|
map: HashMap<Key, Enum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CONFIG_U_NT: &str = "
|
||||||
|
#![enable(unwrap_newtypes)]
|
||||||
|
|
||||||
|
(
|
||||||
|
tuple: ((), 0.5, ((), -5)),
|
||||||
|
vec: [
|
||||||
|
None,
|
||||||
|
Some(()),
|
||||||
|
],
|
||||||
|
map: {
|
||||||
|
7: Bool(true),
|
||||||
|
9: Chars('x', \"\"),
|
||||||
|
6: Bool(false),
|
||||||
|
5: Unit,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unwrap_newtypes() {
|
||||||
|
let d: Struct = ron::de::from_str(&CONFIG_U_NT).expect("Failed to deserialize");
|
||||||
|
|
||||||
|
println!("unwrap_newtypes: {:#?}", d);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CONFIG_I_S: &str = "
|
||||||
|
#![enable(implicit_some)]
|
||||||
|
|
||||||
|
(
|
||||||
|
tuple: ((), (0.5), ((), -5)),
|
||||||
|
vec: [
|
||||||
|
None,
|
||||||
|
(),
|
||||||
|
UnitStruct,
|
||||||
|
None,
|
||||||
|
(),
|
||||||
|
],
|
||||||
|
map: {
|
||||||
|
(7): Bool(true),
|
||||||
|
(9): Chars('x', \"\"),
|
||||||
|
(6): Bool(false),
|
||||||
|
(5): Unit,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn implicit_some() {
|
||||||
|
let d: Struct = ron::de::from_str(&CONFIG_I_S).expect("Failed to deserialize");
|
||||||
|
|
||||||
|
println!("implicit_some: {:#?}", d);
|
||||||
|
}
|
|
@ -1,22 +1,22 @@
|
||||||
extern crate ron;
|
use ron::de::from_str;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hex() {
|
fn test_hex() {
|
||||||
assert_eq!(ron::de::from_str("0x507"), Ok(0x507));
|
assert_eq!(from_str("0x507"), Ok(0x507));
|
||||||
assert_eq!(ron::de::from_str("0x1A5"), Ok(0x1A5));
|
assert_eq!(from_str("0x1A5"), Ok(0x1A5));
|
||||||
assert_eq!(ron::de::from_str("0x53C537"), Ok(0x53C537));
|
assert_eq!(from_str("0x53C537"), Ok(0x53C537));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bin() {
|
fn test_bin() {
|
||||||
assert_eq!(ron::de::from_str("0b101"), Ok(0b101));
|
assert_eq!(from_str("0b101"), Ok(0b101));
|
||||||
assert_eq!(ron::de::from_str("0b001"), Ok(0b001));
|
assert_eq!(from_str("0b001"), Ok(0b001));
|
||||||
assert_eq!(ron::de::from_str("0b100100"), Ok(0b100100));
|
assert_eq!(from_str("0b100100"), Ok(0b100100));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_oct() {
|
fn test_oct() {
|
||||||
assert_eq!(ron::de::from_str("0o1461"), Ok(0o1461));
|
assert_eq!(from_str("0o1461"), Ok(0o1461));
|
||||||
assert_eq!(ron::de::from_str("0o051"), Ok(0o051));
|
assert_eq!(from_str("0o051"), Ok(0o051));
|
||||||
assert_eq!(ron::de::from_str("0o150700"), Ok(0o150700));
|
assert_eq!(from_str("0o150700"), Ok(0o150700));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
extern crate ron;
|
use serde::{Deserialize, Serialize};
|
||||||
#[macro_use]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
@ -40,7 +37,9 @@ fn roundtrip() {
|
||||||
(Key(6), Enum::Bool(false)),
|
(Key(6), Enum::Bool(false)),
|
||||||
(Key(7), Enum::Bool(true)),
|
(Key(7), Enum::Bool(true)),
|
||||||
(Key(9), Enum::Chars('x', "".to_string())),
|
(Key(9), Enum::Chars('x', "".to_string())),
|
||||||
].into_iter().collect()
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let serial = ron::ser::to_string(&value).unwrap();
|
let serial = ron::ser::to_string(&value).unwrap();
|
||||||
|
@ -62,13 +61,60 @@ fn roundtrip_pretty() {
|
||||||
(Key(6), Enum::Bool(false)),
|
(Key(6), Enum::Bool(false)),
|
||||||
(Key(7), Enum::Bool(true)),
|
(Key(7), Enum::Bool(true)),
|
||||||
(Key(9), Enum::Chars('x', "".to_string())),
|
(Key(9), Enum::Chars('x', "".to_string())),
|
||||||
].into_iter()
|
]
|
||||||
.collect(),
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let pretty = ron::ser::PrettyConfig {
|
let pretty = ron::ser::PrettyConfig {
|
||||||
enumerate_arrays: true,
|
enumerate_arrays: true,
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
|
};
|
||||||
|
let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
|
||||||
|
|
||||||
|
println!("Serialized: {}", serial);
|
||||||
|
|
||||||
|
let deserial = ron::de::from_str(&serial);
|
||||||
|
|
||||||
|
assert_eq!(Ok(value), deserial);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn roundtrip_sep_tuple_members() {
|
||||||
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
pub enum FileOrMem {
|
||||||
|
File(String),
|
||||||
|
Memory,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
struct Both {
|
||||||
|
a: Struct,
|
||||||
|
b: FileOrMem,
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = Struct {
|
||||||
|
tuple: ((), NewType(0.5), TupleStruct(UnitStruct, -5)),
|
||||||
|
vec: vec![None, Some(UnitStruct)],
|
||||||
|
map: vec![
|
||||||
|
(Key(5), Enum::Unit),
|
||||||
|
(Key(6), Enum::Bool(false)),
|
||||||
|
(Key(7), Enum::Bool(true)),
|
||||||
|
(Key(9), Enum::Chars('x', "".to_string())),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
let b = FileOrMem::File("foo".to_owned());
|
||||||
|
|
||||||
|
let value = Both { a, b };
|
||||||
|
|
||||||
|
let pretty = ron::ser::PrettyConfig {
|
||||||
|
depth_limit: !0,
|
||||||
|
new_line: "\n".to_owned(),
|
||||||
|
indentor: " ".to_owned(),
|
||||||
|
separate_tuple_members: true,
|
||||||
|
enumerate_arrays: false,
|
||||||
};
|
};
|
||||||
let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
|
let serial = ron::ser::to_string_pretty(&value, pretty).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
use ron::de::from_str;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_char() {
|
||||||
|
let de: char = from_str("'Փ'").unwrap();
|
||||||
|
assert_eq!(de, 'Փ');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string() {
|
||||||
|
let de: String = from_str("\"My string: ऄ\"").unwrap();
|
||||||
|
assert_eq!(de, "My string: ऄ");
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
use ron::value::{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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn char() {
|
||||||
|
assert_eq!(Value::from_str("'a'"), Ok(Value::Char('a')));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map() {
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
map.insert(Value::Char('a'), Value::Number(Number::new(1f64)));
|
||||||
|
map.insert(Value::Char('b'), Value::Number(Number::new(2f64)));
|
||||||
|
assert_eq!(Value::from_str("{ 'a': 1, 'b': 2 }"), 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)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn option() {
|
||||||
|
let opt = Some(Box::new(Value::Char('c')));
|
||||||
|
assert_eq!(Value::from_str("Some('c')"), Ok(Value::Option(opt)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string() {
|
||||||
|
let normal = "\"String\"";
|
||||||
|
assert_eq!(Value::from_str(normal), Ok(Value::String("String".into())));
|
||||||
|
|
||||||
|
let raw = "r\"Raw String\"";
|
||||||
|
assert_eq!(Value::from_str(raw), 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()))
|
||||||
|
);
|
||||||
|
|
||||||
|
let raw_escaped = "r##\"Contains \"#\"##";
|
||||||
|
assert_eq!(
|
||||||
|
Value::from_str(raw_escaped),
|
||||||
|
Ok(Value::String("Contains \"#".into()))
|
||||||
|
);
|
||||||
|
|
||||||
|
let raw_multi_line = "r\"Multi\nLine\"";
|
||||||
|
assert_eq!(
|
||||||
|
Value::from_str(raw_multi_line),
|
||||||
|
Ok(Value::String("Multi\nLine".into()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq() {
|
||||||
|
let seq = vec![
|
||||||
|
Value::Number(Number::new(1f64)),
|
||||||
|
Value::Number(Number::new(2f64)),
|
||||||
|
];
|
||||||
|
assert_eq!(Value::from_str("[1, 2]"), Ok(Value::Seq(seq)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unit() {
|
||||||
|
use ron::de::{Error, ParseError, Position};
|
||||||
|
|
||||||
|
assert_eq!(Value::from_str("()"), Ok(Value::Unit));
|
||||||
|
assert_eq!(Value::from_str("Foo"), Ok(Value::Unit));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Value::from_str(""),
|
||||||
|
Err(Error::Parser(ParseError::Eof, Position { col: 1, line: 1 }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Scene(Option<(u32, u32)>);
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Scene2 {
|
||||||
|
foo: Option<(u32, u32)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn roundtrip() {
|
||||||
|
use ron::{de::from_str, ser::to_string};
|
||||||
|
|
||||||
|
{
|
||||||
|
let s = to_string(&Scene2 {
|
||||||
|
foo: Some((122, 13)),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
println!("{}", s);
|
||||||
|
let scene: Value = from_str(&s).unwrap();
|
||||||
|
println!("{:?}", scene);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let s = to_string(&Scene(Some((13, 122)))).unwrap();
|
||||||
|
println!("{}", s);
|
||||||
|
let scene: Value = from_str(&s).unwrap();
|
||||||
|
println!("{:?}", scene);
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче