mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1396821 - Update vendored Rust crates. r=ato
MozReview-Commit-ID: D8W2mtdAmpb --HG-- rename : third_party/rust/rustc-serialize/LICENSE-APACHE => third_party/rust/serde_json/LICENSE-APACHE rename : third_party/rust/rustc-serialize/LICENSE-MIT => third_party/rust/serde_json/LICENSE-MIT extra : rebase_source : 5e5054596543e501434ecde199c055548fd62271
This commit is contained in:
parent
1fc0887dc1
commit
0be64a7b29
34
Cargo.lock
generated
34
Cargo.lock
generated
@ -806,6 +806,7 @@ dependencies = [
|
|||||||
name = "geckodriver"
|
name = "geckodriver"
|
||||||
version = "0.21.0"
|
version = "0.21.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -815,7 +816,9 @@ dependencies = [
|
|||||||
"mozrunner 0.7.0",
|
"mozrunner 0.7.0",
|
||||||
"mozversion 0.1.3",
|
"mozversion 0.1.3",
|
||||||
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_derive 1.0.66 (git+https://github.com/servo/serde?branch=deserialize_from_enums8)",
|
||||||
|
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"webdriver 0.36.0",
|
"webdriver 0.36.0",
|
||||||
"zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1836,11 +1839,6 @@ name = "rustc-demangle"
|
|||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-serialize"
|
|
||||||
version = "0.3.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -1849,6 +1847,11 @@ dependencies = [
|
|||||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "safemem"
|
name = "safemem"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1928,6 +1931,16 @@ dependencies = [
|
|||||||
"syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo_arc"
|
name = "servo_arc"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -2412,11 +2425,15 @@ dependencies = [
|
|||||||
name = "webdriver"
|
name = "webdriver"
|
||||||
version = "0.36.0"
|
version = "0.36.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_derive 1.0.66 (git+https://github.com/servo/serde?branch=deserialize_from_enums8)",
|
||||||
|
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -2795,8 +2812,8 @@ dependencies = [
|
|||||||
"checksum runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d79b4b604167921892e84afbbaad9d5ad74e091bf6c511d9dbfb0593f09fabd"
|
"checksum runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d79b4b604167921892e84afbbaad9d5ad74e091bf6c511d9dbfb0593f09fabd"
|
||||||
"checksum rust-ini 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263"
|
"checksum rust-ini 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263"
|
||||||
"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
|
"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
|
||||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
|
||||||
"checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69"
|
"checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69"
|
||||||
|
"checksum ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0568787116e13c652377b6846f5931454a363a8fdf8ae50463ee40935b278b"
|
||||||
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
||||||
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
|
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
|
||||||
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
|
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
|
||||||
@ -2806,6 +2823,7 @@ dependencies = [
|
|||||||
"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95"
|
"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95"
|
||||||
"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"
|
"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"
|
||||||
"checksum serde_derive 1.0.66 (git+https://github.com/servo/serde?branch=deserialize_from_enums8)" = "<none>"
|
"checksum serde_derive 1.0.66 (git+https://github.com/servo/serde?branch=deserialize_from_enums8)" = "<none>"
|
||||||
|
"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"
|
||||||
"checksum simd 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3686dd9418ebcc3a26a0c0ae56deab0681e53fe899af91f5bbcee667ebffb1"
|
"checksum simd 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3686dd9418ebcc3a26a0c0ae56deab0681e53fe899af91f5bbcee667ebffb1"
|
||||||
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
|
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
|
||||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||||
|
@ -1 +0,0 @@
|
|||||||
{"files":{".travis.yml":"03dcea6dcd54625b42d91176e86718626dfd911744a343dee3edefa001e87dc5","Cargo.toml":"01199fa6ca6337a7513e9ef8951268b8882347e5affaa50e710ac4960d9c65e0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"0aebc3beb6fc32d6073582d5fea170761689a2c83cddb5436aa26e57b7d04e7b","appveyor.yml":"da991211b72fa6f231af7adb84c9fb72f5a9131d1c0a3d47b8ceffe5a82c8542","benches/base64.rs":"96f7d0c7d260362e41b8cefb4839f1e1b3c18c2f10344f6ccafac7c434f99ca9","benches/hex.rs":"057821307b4b7de02f2c267f9248457386035382916c5afe4b72d6f2e905062c","benches/json.rs":"659f2ae2e1ad5ed022fafce6418d17dfe09c3dcb3f054857dce0effc907da850","src/base64.rs":"57649c590c1fba643ff955910f1d4427feda43414bb0863cd279bea56c3ff178","src/collection_impls.rs":"8ae6bc0d61a4777d834c2b24fa987550cb13c570e1564f87ee32eceff3cb2d5b","src/hex.rs":"a2ba86cf47035b5d9cbf4adf8dc3e941d4e0a6ce1a61a29cbb14ea1fdabac6bb","src/json.rs":"75a788a46612c73bfd14af20fb48855dc8c930747c5255a288d2d09de25ea960","src/lib.rs":"a0e4a368a609f019434e7584f54448cf33ebf3e37e3fb1dd5537d300088184b1","src/serialize.rs":"7ddcc3c32843850e30d05b82a8cda8ae63ec0016e2b0bfbcc46a03ea3ea986e8"},"package":"dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"}
|
|
24
third_party/rust/rustc-serialize/.travis.yml
vendored
24
third_party/rust/rustc-serialize/.travis.yml
vendored
@ -1,24 +0,0 @@
|
|||||||
language: rust
|
|
||||||
rust:
|
|
||||||
- 1.0.0
|
|
||||||
- stable
|
|
||||||
- beta
|
|
||||||
- nightly
|
|
||||||
sudo: false
|
|
||||||
before_script:
|
|
||||||
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
|
||||||
script:
|
|
||||||
- cargo build --verbose
|
|
||||||
- cargo test --verbose
|
|
||||||
- cargo doc --no-deps
|
|
||||||
after_success:
|
|
||||||
- travis-cargo --only nightly doc-upload
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
secure: "kJnqqAXRl0C7Afx0c8Y3vA6TAEZsxlasu7eIZMdCbNS4N1+Rwh0jNTa2jy2D3CQCrzW5OCefnkpkPTu8mADrAjedM4p/9X5UXZi0sgg2lzCgfGwrRzitTnyPDkdYidiu4QeC/r0WPC8lYZKHkJXYhF8bZgchB9ypnZ6LAHCcDkA="
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
on_success: never
|
|
18
third_party/rust/rustc-serialize/Cargo.toml
vendored
18
third_party/rust/rustc-serialize/Cargo.toml
vendored
@ -1,18 +0,0 @@
|
|||||||
[package]
|
|
||||||
|
|
||||||
name = "rustc-serialize"
|
|
||||||
version = "0.3.24"
|
|
||||||
authors = ["The Rust Project Developers"]
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
readme = "README.md"
|
|
||||||
repository = "https://github.com/rust-lang/rustc-serialize"
|
|
||||||
homepage = "https://github.com/rust-lang/rustc-serialize"
|
|
||||||
documentation = "https://doc.rust-lang.org/rustc-serialize"
|
|
||||||
description = """
|
|
||||||
Generic serialization/deserialization support corresponding to the
|
|
||||||
`derive(RustcEncodable, RustcDecodable)` mode in the compiler. Also includes
|
|
||||||
support for hex, base64, and json encoding and decoding.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
rand = "0.3"
|
|
31
third_party/rust/rustc-serialize/README.md
vendored
31
third_party/rust/rustc-serialize/README.md
vendored
@ -1,31 +0,0 @@
|
|||||||
# rustc-serialize
|
|
||||||
|
|
||||||
> **NOTE**: This crate is deprecated in favor of [`serde`]. No new feature
|
|
||||||
> development will happen in this crate, although bug fixes proposed through PRs
|
|
||||||
> will still be merged. It is very highly recommended by the Rust Library Team
|
|
||||||
> that you use [`serde`], not this crate.
|
|
||||||
|
|
||||||
[`serde`]: https://serde.rs
|
|
||||||
|
|
||||||
Serialization and deserialization support provided by the compiler in the form
|
|
||||||
of `derive(RustcEncodable, RustcDecodable)`.
|
|
||||||
|
|
||||||
[![Linux Build Status](https://travis-ci.org/rust-lang-nursery/rustc-serialize.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustc-serialize)
|
|
||||||
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/ka194de75aapwpft?svg=true)](https://ci.appveyor.com/project/alexcrichton/rustc-serialize)
|
|
||||||
|
|
||||||
[Documentation](https://doc.rust-lang.org/rustc-serialize)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Add this to your `Cargo.toml`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
rustc-serialize = "0.3"
|
|
||||||
```
|
|
||||||
|
|
||||||
and this to your crate root:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
extern crate rustc_serialize;
|
|
||||||
```
|
|
17
third_party/rust/rustc-serialize/appveyor.yml
vendored
17
third_party/rust/rustc-serialize/appveyor.yml
vendored
@ -1,17 +0,0 @@
|
|||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- TARGET: x86_64-pc-windows-msvc
|
|
||||||
- TARGET: i686-pc-windows-msvc
|
|
||||||
- TARGET: i686-pc-windows-gnu
|
|
||||||
install:
|
|
||||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
|
|
||||||
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
|
||||||
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
|
||||||
- SET PATH=%PATH%;C:\MinGW\bin
|
|
||||||
- rustc -V
|
|
||||||
- cargo -V
|
|
||||||
|
|
||||||
build: false
|
|
||||||
|
|
||||||
test_script:
|
|
||||||
- cargo test --verbose
|
|
@ -1,48 +0,0 @@
|
|||||||
#![feature(test)]
|
|
||||||
|
|
||||||
extern crate test;
|
|
||||||
extern crate rustc_serialize;
|
|
||||||
|
|
||||||
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_to_base64(b: &mut Bencher) {
|
|
||||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
|
||||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
|
||||||
b.iter(|| {
|
|
||||||
s.as_bytes().to_base64(STANDARD);
|
|
||||||
});
|
|
||||||
b.bytes = s.len() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_from_base64(b: &mut Bencher) {
|
|
||||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
|
||||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
|
||||||
let sb = s.as_bytes().to_base64(STANDARD);
|
|
||||||
b.iter(|| {
|
|
||||||
sb.from_base64().unwrap();
|
|
||||||
});
|
|
||||||
b.bytes = sb.len() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_to_base64_large(b: &mut Bencher) {
|
|
||||||
let s: Vec<_> = (0..10000).map(|i| ((i as u32 * 12345) % 256) as u8).collect();
|
|
||||||
b.iter(|| {
|
|
||||||
s.to_base64(STANDARD);
|
|
||||||
});
|
|
||||||
b.bytes = s.len() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_from_base64_large(b: &mut Bencher) {
|
|
||||||
let s: Vec<_> = (0..10000).map(|i| ((i as u32 * 12345) % 256) as u8).collect();
|
|
||||||
let sb = s.to_base64(STANDARD);
|
|
||||||
b.iter(|| {
|
|
||||||
sb.from_base64().unwrap();
|
|
||||||
});
|
|
||||||
b.bytes = sb.len() as u64;
|
|
||||||
}
|
|
28
third_party/rust/rustc-serialize/benches/hex.rs
vendored
28
third_party/rust/rustc-serialize/benches/hex.rs
vendored
@ -1,28 +0,0 @@
|
|||||||
#![feature(test)]
|
|
||||||
|
|
||||||
extern crate test;
|
|
||||||
extern crate rustc_serialize;
|
|
||||||
|
|
||||||
use test::Bencher;
|
|
||||||
use rustc_serialize::hex::{FromHex, ToHex};
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_to_hex(b: &mut Bencher) {
|
|
||||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
|
||||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
|
||||||
b.iter(|| {
|
|
||||||
s.as_bytes().to_hex();
|
|
||||||
});
|
|
||||||
b.bytes = s.len() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_from_hex(b: &mut Bencher) {
|
|
||||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
|
||||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
|
||||||
let sb = s.as_bytes().to_hex();
|
|
||||||
b.iter(|| {
|
|
||||||
sb.from_hex().unwrap();
|
|
||||||
});
|
|
||||||
b.bytes = sb.len() as u64;
|
|
||||||
}
|
|
84
third_party/rust/rustc-serialize/benches/json.rs
vendored
84
third_party/rust/rustc-serialize/benches/json.rs
vendored
@ -1,84 +0,0 @@
|
|||||||
#![feature(test)]
|
|
||||||
|
|
||||||
extern crate test;
|
|
||||||
extern crate rustc_serialize;
|
|
||||||
|
|
||||||
use std::string;
|
|
||||||
use rustc_serialize::json::{Json, Parser};
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_streaming_small(b: &mut Bencher) {
|
|
||||||
b.iter( || {
|
|
||||||
let mut parser = Parser::new(
|
|
||||||
r#"{
|
|
||||||
"a": 1.0,
|
|
||||||
"b": [
|
|
||||||
true,
|
|
||||||
"foo\nbar",
|
|
||||||
{ "c": {"d": null} }
|
|
||||||
]
|
|
||||||
}"#.chars()
|
|
||||||
);
|
|
||||||
loop {
|
|
||||||
match parser.next() {
|
|
||||||
None => return,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#[bench]
|
|
||||||
fn bench_small(b: &mut Bencher) {
|
|
||||||
b.iter( || {
|
|
||||||
let _ = Json::from_str(r#"{
|
|
||||||
"a": 1.0,
|
|
||||||
"b": [
|
|
||||||
true,
|
|
||||||
"foo\nbar",
|
|
||||||
{ "c": {"d": null} }
|
|
||||||
]
|
|
||||||
}"#);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_decode_hex_escape(b: &mut Bencher) {
|
|
||||||
let mut src = "\"".to_string();
|
|
||||||
for _ in 0..10 {
|
|
||||||
src.push_str("\\uF975\\uf9bc\\uF9A0\\uF9C4\\uF975\\uf9bc\\uF9A0\\uF9C4");
|
|
||||||
}
|
|
||||||
src.push_str("\"");
|
|
||||||
b.iter( || {
|
|
||||||
let _ = Json::from_str(&src);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn big_json() -> string::String {
|
|
||||||
let mut src = "[\n".to_string();
|
|
||||||
for _ in 0..500 {
|
|
||||||
src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
|
|
||||||
[1,2,3]},"#);
|
|
||||||
}
|
|
||||||
src.push_str("{}]");
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_streaming_large(b: &mut Bencher) {
|
|
||||||
let src = big_json();
|
|
||||||
b.iter( || {
|
|
||||||
let mut parser = Parser::new(src.chars());
|
|
||||||
loop {
|
|
||||||
match parser.next() {
|
|
||||||
None => return,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#[bench]
|
|
||||||
fn bench_large(b: &mut Bencher) {
|
|
||||||
let src = big_json();
|
|
||||||
b.iter( || { let _ = Json::from_str(&src); });
|
|
||||||
}
|
|
489
third_party/rust/rustc-serialize/src/base64.rs
vendored
489
third_party/rust/rustc-serialize/src/base64.rs
vendored
@ -1,489 +0,0 @@
|
|||||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
//
|
|
||||||
// ignore-lexer-test FIXME #15679
|
|
||||||
|
|
||||||
//! Base64 binary-to-text encoding
|
|
||||||
|
|
||||||
pub use self::FromBase64Error::*;
|
|
||||||
pub use self::CharacterSet::*;
|
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::error;
|
|
||||||
|
|
||||||
/// Available encoding character sets
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum CharacterSet {
|
|
||||||
/// The standard character set (uses `+` and `/`)
|
|
||||||
Standard,
|
|
||||||
/// The URL safe character set (uses `-` and `_`)
|
|
||||||
UrlSafe
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Available newline types
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum Newline {
|
|
||||||
/// A linefeed (i.e. Unix-style newline)
|
|
||||||
LF,
|
|
||||||
/// A carriage return and a linefeed (i.e. Windows-style newline)
|
|
||||||
CRLF
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contains configuration parameters for `to_base64`.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct Config {
|
|
||||||
/// Character set to use
|
|
||||||
pub char_set: CharacterSet,
|
|
||||||
/// Newline to use
|
|
||||||
pub newline: Newline,
|
|
||||||
/// True to pad output with `=` characters
|
|
||||||
pub pad: bool,
|
|
||||||
/// `Some(len)` to wrap lines at `len`, `None` to disable line wrapping
|
|
||||||
pub line_length: Option<usize>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configuration for RFC 4648 standard base64 encoding
|
|
||||||
pub static STANDARD: Config =
|
|
||||||
Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: None};
|
|
||||||
|
|
||||||
/// Configuration for RFC 4648 base64url encoding
|
|
||||||
pub static URL_SAFE: Config =
|
|
||||||
Config {char_set: UrlSafe, newline: Newline::CRLF, pad: false, line_length: None};
|
|
||||||
|
|
||||||
/// Configuration for RFC 2045 MIME base64 encoding
|
|
||||||
pub static MIME: Config =
|
|
||||||
Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: Some(76)};
|
|
||||||
|
|
||||||
static STANDARD_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
|
||||||
abcdefghijklmnopqrstuvwxyz\
|
|
||||||
0123456789+/";
|
|
||||||
|
|
||||||
static URLSAFE_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
|
||||||
abcdefghijklmnopqrstuvwxyz\
|
|
||||||
0123456789-_";
|
|
||||||
|
|
||||||
/// A trait for converting a value to base64 encoding.
|
|
||||||
pub trait ToBase64 {
|
|
||||||
/// Converts the value of `self` to a base64 value following the specified
|
|
||||||
/// format configuration, returning the owned string.
|
|
||||||
fn to_base64(&self, config: Config) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToBase64 for [u8] {
|
|
||||||
/// Turn a vector of `u8` bytes into a base64 string.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate rustc_serialize;
|
|
||||||
/// use rustc_serialize::base64::{ToBase64, STANDARD};
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let str = [52,32].to_base64(STANDARD);
|
|
||||||
/// println!("base 64 output: {:?}", str);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn to_base64(&self, config: Config) -> String {
|
|
||||||
let bytes = match config.char_set {
|
|
||||||
Standard => STANDARD_CHARS,
|
|
||||||
UrlSafe => URLSAFE_CHARS
|
|
||||||
};
|
|
||||||
|
|
||||||
let len = self.len();
|
|
||||||
let newline = match config.newline {
|
|
||||||
Newline::LF => "\n",
|
|
||||||
Newline::CRLF => "\r\n",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Preallocate memory.
|
|
||||||
let mut prealloc_len = (len + 2) / 3 * 4;
|
|
||||||
if let Some(line_length) = config.line_length {
|
|
||||||
let num_lines = match prealloc_len {
|
|
||||||
0 => 0,
|
|
||||||
n => (n - 1) / line_length
|
|
||||||
};
|
|
||||||
prealloc_len += num_lines * newline.bytes().count();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut out_bytes = vec![b'='; prealloc_len];
|
|
||||||
|
|
||||||
// Deal with padding bytes
|
|
||||||
let mod_len = len % 3;
|
|
||||||
|
|
||||||
// Use iterators to reduce branching
|
|
||||||
{
|
|
||||||
let mut cur_length = 0;
|
|
||||||
|
|
||||||
let mut s_in = self[..len - mod_len].iter().map(|&x| x as u32);
|
|
||||||
let mut s_out = out_bytes.iter_mut();
|
|
||||||
|
|
||||||
// Convenient shorthand
|
|
||||||
let enc = |val| bytes[val as usize];
|
|
||||||
let mut write = |val| *s_out.next().unwrap() = val;
|
|
||||||
|
|
||||||
// Iterate though blocks of 4
|
|
||||||
while let (Some(first), Some(second), Some(third)) =
|
|
||||||
(s_in.next(), s_in.next(), s_in.next()) {
|
|
||||||
|
|
||||||
// Line break if needed
|
|
||||||
if let Some(line_length) = config.line_length {
|
|
||||||
if cur_length >= line_length {
|
|
||||||
for b in newline.bytes() { write(b) };
|
|
||||||
cur_length = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = first << 16 | second << 8 | third;
|
|
||||||
|
|
||||||
// This 24-bit number gets separated into four 6-bit numbers.
|
|
||||||
write(enc((n >> 18) & 63));
|
|
||||||
write(enc((n >> 12) & 63));
|
|
||||||
write(enc((n >> 6 ) & 63));
|
|
||||||
write(enc((n >> 0 ) & 63));
|
|
||||||
|
|
||||||
cur_length += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Line break only needed if padding is required
|
|
||||||
if mod_len != 0 {
|
|
||||||
if let Some(line_length) = config.line_length {
|
|
||||||
if cur_length >= line_length {
|
|
||||||
for b in newline.bytes() { write(b) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Heh, would be cool if we knew this was exhaustive
|
|
||||||
// (the dream of bounded integer types)
|
|
||||||
match mod_len {
|
|
||||||
0 => (),
|
|
||||||
1 => {
|
|
||||||
let n = (self[len-1] as u32) << 16;
|
|
||||||
write(enc((n >> 18) & 63));
|
|
||||||
write(enc((n >> 12) & 63));
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let n = (self[len-2] as u32) << 16 |
|
|
||||||
(self[len-1] as u32) << 8;
|
|
||||||
write(enc((n >> 18) & 63));
|
|
||||||
write(enc((n >> 12) & 63));
|
|
||||||
write(enc((n >> 6 ) & 63));
|
|
||||||
}
|
|
||||||
_ => panic!("Algebra is broken, please alert the math police")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We get padding for "free", so only have to drop it if unwanted.
|
|
||||||
if !config.pad {
|
|
||||||
while let Some(&b'=') = out_bytes.last() {
|
|
||||||
out_bytes.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { String::from_utf8_unchecked(out_bytes) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: ?Sized + ToBase64> ToBase64 for &'a T {
|
|
||||||
fn to_base64(&self, config: Config) -> String {
|
|
||||||
(**self).to_base64(config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for converting from base64 encoded values.
|
|
||||||
pub trait FromBase64 {
|
|
||||||
/// Converts the value of `self`, interpreted as base64 encoded data, into
|
|
||||||
/// an owned vector of bytes, returning the vector.
|
|
||||||
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Errors that can occur when decoding a base64 encoded string
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum FromBase64Error {
|
|
||||||
/// The input contained a character not part of the base64 format
|
|
||||||
InvalidBase64Byte(u8, usize),
|
|
||||||
/// The input had an invalid length
|
|
||||||
InvalidBase64Length,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for FromBase64Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
InvalidBase64Byte(ch, idx) =>
|
|
||||||
write!(f, "Invalid character '{}' at position {}", ch, idx),
|
|
||||||
InvalidBase64Length => write!(f, "Invalid length"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for FromBase64Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
InvalidBase64Byte(_, _) => "invalid character",
|
|
||||||
InvalidBase64Length => "invalid length",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FromBase64Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
fmt::Debug::fmt(&self, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromBase64 for str {
|
|
||||||
/// Convert any base64 encoded string (literal, `@`, `&`, or `~`)
|
|
||||||
/// to the byte values it encodes.
|
|
||||||
///
|
|
||||||
/// You can use the `String::from_utf8` function to turn a `Vec<u8>` into a
|
|
||||||
/// string with characters corresponding to those values.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// This converts a string literal to base64 and back.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate rustc_serialize;
|
|
||||||
/// use rustc_serialize::base64::{ToBase64, FromBase64, STANDARD};
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let hello_str = b"Hello, World".to_base64(STANDARD);
|
|
||||||
/// println!("base64 output: {}", hello_str);
|
|
||||||
/// let res = hello_str.from_base64();
|
|
||||||
/// if res.is_ok() {
|
|
||||||
/// let opt_bytes = String::from_utf8(res.unwrap());
|
|
||||||
/// if opt_bytes.is_ok() {
|
|
||||||
/// println!("decoded from base64: {:?}", opt_bytes.unwrap());
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error> {
|
|
||||||
self.as_bytes().from_base64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromBase64 for [u8] {
|
|
||||||
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error> {
|
|
||||||
let mut r = Vec::with_capacity(self.len());
|
|
||||||
let mut buf: u32 = 0;
|
|
||||||
let mut modulus = 0;
|
|
||||||
|
|
||||||
let mut it = self.iter();
|
|
||||||
for byte in it.by_ref() {
|
|
||||||
let code = DECODE_TABLE[*byte as usize];
|
|
||||||
if code >= SPECIAL_CODES_START {
|
|
||||||
match code {
|
|
||||||
NEWLINE_CODE => continue,
|
|
||||||
EQUALS_CODE => break,
|
|
||||||
INVALID_CODE => return Err(InvalidBase64Byte(
|
|
||||||
*byte, (byte as *const _ as usize) - self.as_ptr() as usize)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf = (buf | code as u32) << 6;
|
|
||||||
modulus += 1;
|
|
||||||
if modulus == 4 {
|
|
||||||
modulus = 0;
|
|
||||||
r.push((buf >> 22) as u8);
|
|
||||||
r.push((buf >> 14) as u8);
|
|
||||||
r.push((buf >> 6 ) as u8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for byte in it {
|
|
||||||
match *byte {
|
|
||||||
b'=' | b'\r' | b'\n' => continue,
|
|
||||||
_ => return Err(InvalidBase64Byte(
|
|
||||||
*byte, (byte as *const _ as usize) - self.as_ptr() as usize)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match modulus {
|
|
||||||
2 => {
|
|
||||||
r.push((buf >> 10) as u8);
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
r.push((buf >> 16) as u8);
|
|
||||||
r.push((buf >> 8 ) as u8);
|
|
||||||
}
|
|
||||||
0 => (),
|
|
||||||
_ => return Err(InvalidBase64Length),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: ?Sized + FromBase64> FromBase64 for &'a T {
|
|
||||||
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error> {
|
|
||||||
(**self).from_base64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Base64 decoding lookup table, generated using:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let mut ch = 0u8;
|
|
||||||
/// for ch in 0..255 {
|
|
||||||
/// let mut ch = ch as u8;
|
|
||||||
/// let code = match ch {
|
|
||||||
/// b'A'...b'Z' => ch - 0x41,
|
|
||||||
/// b'a'...b'z' => ch - 0x47,
|
|
||||||
/// b'0'...b'9' => ch + 0x04,
|
|
||||||
/// b'+' | b'-' => 0x3E,
|
|
||||||
/// b'/' | b'_' => 0x3F,
|
|
||||||
/// b'=' => 0xFE,
|
|
||||||
/// b'\r' | b'\n' => 0xFD,
|
|
||||||
/// _ => 0xFF,
|
|
||||||
/// };
|
|
||||||
/// print!("0x{:02X}, ", code);
|
|
||||||
/// if ch % 16 == 15 { println!(""); }
|
|
||||||
/// else if ch == 0xFF { break; }
|
|
||||||
/// ch += 1;
|
|
||||||
/// }
|
|
||||||
/// println!("");
|
|
||||||
/// ```
|
|
||||||
const DECODE_TABLE: [u8; 256] = [
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0x3E, 0xFF, 0x3F,
|
|
||||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
|
|
||||||
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
|
||||||
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F,
|
|
||||||
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
|
||||||
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
];
|
|
||||||
const INVALID_CODE: u8 = 0xFF;
|
|
||||||
const EQUALS_CODE: u8 = 0xFE;
|
|
||||||
const NEWLINE_CODE: u8 = 0xFD;
|
|
||||||
const SPECIAL_CODES_START: u8 = NEWLINE_CODE;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use base64::{Config, Newline, FromBase64, ToBase64, STANDARD, URL_SAFE};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_base64_basic() {
|
|
||||||
assert_eq!("".as_bytes().to_base64(STANDARD), "");
|
|
||||||
assert_eq!("f".as_bytes().to_base64(STANDARD), "Zg==");
|
|
||||||
assert_eq!("fo".as_bytes().to_base64(STANDARD), "Zm8=");
|
|
||||||
assert_eq!("foo".as_bytes().to_base64(STANDARD), "Zm9v");
|
|
||||||
assert_eq!("foob".as_bytes().to_base64(STANDARD), "Zm9vYg==");
|
|
||||||
assert_eq!("fooba".as_bytes().to_base64(STANDARD), "Zm9vYmE=");
|
|
||||||
assert_eq!("foobar".as_bytes().to_base64(STANDARD), "Zm9vYmFy");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_base64_crlf_line_break() {
|
|
||||||
assert!(![0; 1000].to_base64(Config {line_length: None, ..STANDARD})
|
|
||||||
.contains("\r\n"));
|
|
||||||
assert_eq!(b"foobar".to_base64(Config {line_length: Some(4),
|
|
||||||
..STANDARD}),
|
|
||||||
"Zm9v\r\nYmFy");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_base64_lf_line_break() {
|
|
||||||
assert!(![0; 1000].to_base64(Config {line_length: None,
|
|
||||||
newline: Newline::LF,
|
|
||||||
..STANDARD})
|
|
||||||
.contains("\n"));
|
|
||||||
assert_eq!(b"foobar".to_base64(Config {line_length: Some(4),
|
|
||||||
newline: Newline::LF,
|
|
||||||
..STANDARD}),
|
|
||||||
"Zm9v\nYmFy");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_base64_padding() {
|
|
||||||
assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zg");
|
|
||||||
assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zm8");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_base64_url_safe() {
|
|
||||||
assert_eq!([251, 255].to_base64(URL_SAFE), "-_8");
|
|
||||||
assert_eq!([251, 255].to_base64(STANDARD), "+/8=");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_base64_empty_line_length() {
|
|
||||||
[].to_base64(Config {line_length: Some(72), ..STANDARD});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_base64_basic() {
|
|
||||||
assert_eq!("".from_base64().unwrap(), b"");
|
|
||||||
assert_eq!("Zg==".from_base64().unwrap(), b"f");
|
|
||||||
assert_eq!("Zm8=".from_base64().unwrap(), b"fo");
|
|
||||||
assert_eq!("Zm9v".from_base64().unwrap(), b"foo");
|
|
||||||
assert_eq!("Zm9vYg==".from_base64().unwrap(), b"foob");
|
|
||||||
assert_eq!("Zm9vYmE=".from_base64().unwrap(), b"fooba");
|
|
||||||
assert_eq!("Zm9vYmFy".from_base64().unwrap(), b"foobar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_base64_bytes() {
|
|
||||||
assert_eq!(b"Zm9vYmFy".from_base64().unwrap(), b"foobar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_base64_newlines() {
|
|
||||||
assert_eq!("Zm9v\r\nYmFy".from_base64().unwrap(),
|
|
||||||
b"foobar");
|
|
||||||
assert_eq!("Zm9vYg==\r\n".from_base64().unwrap(),
|
|
||||||
b"foob");
|
|
||||||
assert_eq!("Zm9v\nYmFy".from_base64().unwrap(),
|
|
||||||
b"foobar");
|
|
||||||
assert_eq!("Zm9vYg==\n".from_base64().unwrap(),
|
|
||||||
b"foob");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_base64_urlsafe() {
|
|
||||||
assert_eq!("-_8".from_base64().unwrap(), "+/8=".from_base64().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_base64_invalid_char() {
|
|
||||||
assert!("Zm$=".from_base64().is_err());
|
|
||||||
assert!("Zg==$".from_base64().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_base64_invalid_padding() {
|
|
||||||
assert!("Z===".from_base64().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_base64_random() {
|
|
||||||
use rand::{thread_rng, Rng};
|
|
||||||
|
|
||||||
for _ in 0..1000 {
|
|
||||||
let times = thread_rng().gen_range(1, 100);
|
|
||||||
let v = thread_rng().gen_iter::<u8>().take(times)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(v.to_base64(STANDARD)
|
|
||||||
.from_base64()
|
|
||||||
.unwrap(),
|
|
||||||
v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,186 +0,0 @@
|
|||||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Implementations of serialization for structures found in libcollections
|
|
||||||
|
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
use {Decodable, Encodable, Decoder, Encoder, cap_capacity};
|
|
||||||
use std::collections::{LinkedList, VecDeque, BTreeMap, BTreeSet, HashMap, HashSet};
|
|
||||||
|
|
||||||
impl<
|
|
||||||
T: Encodable
|
|
||||||
> Encodable for LinkedList<T> {
|
|
||||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
|
||||||
s.emit_seq(self.len(), |s| {
|
|
||||||
for (i, e) in self.iter().enumerate() {
|
|
||||||
try!(s.emit_seq_elt(i, |s| e.encode(s)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Decodable> Decodable for LinkedList<T> {
|
|
||||||
fn decode<D: Decoder>(d: &mut D) -> Result<LinkedList<T>, D::Error> {
|
|
||||||
d.read_seq(|d, len| {
|
|
||||||
let mut list = LinkedList::new();
|
|
||||||
for i in 0..len {
|
|
||||||
list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
|
|
||||||
}
|
|
||||||
Ok(list)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Encodable> Encodable for VecDeque<T> {
|
|
||||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
|
||||||
s.emit_seq(self.len(), |s| {
|
|
||||||
for (i, e) in self.iter().enumerate() {
|
|
||||||
try!(s.emit_seq_elt(i, |s| e.encode(s)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Decodable> Decodable for VecDeque<T> {
|
|
||||||
fn decode<D: Decoder>(d: &mut D) -> Result<VecDeque<T>, D::Error> {
|
|
||||||
d.read_seq(|d, len| {
|
|
||||||
let mut deque: VecDeque<T> = VecDeque::new();
|
|
||||||
for i in 0..len {
|
|
||||||
deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
|
|
||||||
}
|
|
||||||
Ok(deque)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
|
||||||
K: Encodable + Ord,
|
|
||||||
V: Encodable
|
|
||||||
> Encodable for BTreeMap<K, V> {
|
|
||||||
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
|
|
||||||
e.emit_map(self.len(), |e| {
|
|
||||||
let mut i = 0;
|
|
||||||
for (key, val) in self.iter() {
|
|
||||||
try!(e.emit_map_elt_key(i, |e| key.encode(e)));
|
|
||||||
try!(e.emit_map_elt_val(i, |e| val.encode(e)));
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
|
||||||
K: Decodable + Ord,
|
|
||||||
V: Decodable
|
|
||||||
> Decodable for BTreeMap<K, V> {
|
|
||||||
fn decode<D: Decoder>(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
|
|
||||||
d.read_map(|d, len| {
|
|
||||||
let mut map = BTreeMap::new();
|
|
||||||
for i in 0..len {
|
|
||||||
let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
|
|
||||||
let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
|
|
||||||
map.insert(key, val);
|
|
||||||
}
|
|
||||||
Ok(map)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
|
||||||
T: Encodable + Ord
|
|
||||||
> Encodable for BTreeSet<T> {
|
|
||||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
|
||||||
s.emit_seq(self.len(), |s| {
|
|
||||||
let mut i = 0;
|
|
||||||
for e in self.iter() {
|
|
||||||
try!(s.emit_seq_elt(i, |s| e.encode(s)));
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
|
||||||
T: Decodable + Ord
|
|
||||||
> Decodable for BTreeSet<T> {
|
|
||||||
fn decode<D: Decoder>(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
|
|
||||||
d.read_seq(|d, len| {
|
|
||||||
let mut set = BTreeSet::new();
|
|
||||||
for i in 0..len {
|
|
||||||
set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
|
|
||||||
}
|
|
||||||
Ok(set)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K, V> Encodable for HashMap<K, V>
|
|
||||||
where K: Encodable + Hash + Eq,
|
|
||||||
V: Encodable,
|
|
||||||
{
|
|
||||||
fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
|
|
||||||
e.emit_map(self.len(), |e| {
|
|
||||||
let mut i = 0;
|
|
||||||
for (key, val) in self.iter() {
|
|
||||||
try!(e.emit_map_elt_key(i, |e| key.encode(e)));
|
|
||||||
try!(e.emit_map_elt_val(i, |e| val.encode(e)));
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K, V> Decodable for HashMap<K, V>
|
|
||||||
where K: Decodable + Hash + Eq,
|
|
||||||
V: Decodable,
|
|
||||||
{
|
|
||||||
fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V>, D::Error> {
|
|
||||||
d.read_map(|d, len| {
|
|
||||||
let mut map = HashMap::with_capacity(cap_capacity::<(K, V)>(len));
|
|
||||||
for i in 0..len {
|
|
||||||
let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
|
|
||||||
let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
|
|
||||||
map.insert(key, val);
|
|
||||||
}
|
|
||||||
Ok(map)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Encodable for HashSet<T> where T: Encodable + Hash + Eq {
|
|
||||||
fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
|
|
||||||
s.emit_seq(self.len(), |s| {
|
|
||||||
let mut i = 0;
|
|
||||||
for e in self.iter() {
|
|
||||||
try!(s.emit_seq_elt(i, |s| e.encode(s)));
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Decodable for HashSet<T> where T: Decodable + Hash + Eq, {
|
|
||||||
fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T>, D::Error> {
|
|
||||||
d.read_seq(|d, len| {
|
|
||||||
let mut set = HashSet::with_capacity(cap_capacity::<T>(len));
|
|
||||||
for i in 0..len {
|
|
||||||
set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
|
|
||||||
}
|
|
||||||
Ok(set)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
221
third_party/rust/rustc-serialize/src/hex.rs
vendored
221
third_party/rust/rustc-serialize/src/hex.rs
vendored
@ -1,221 +0,0 @@
|
|||||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
//
|
|
||||||
// ignore-lexer-test FIXME #15679
|
|
||||||
|
|
||||||
//! Hex binary-to-text encoding
|
|
||||||
|
|
||||||
pub use self::FromHexError::*;
|
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::error;
|
|
||||||
|
|
||||||
/// A trait for converting a value to hexadecimal encoding
|
|
||||||
pub trait ToHex {
|
|
||||||
/// Converts the value of `self` to a hex value, returning the owned
|
|
||||||
/// string.
|
|
||||||
fn to_hex(&self) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CHARS: &'static[u8] = b"0123456789abcdef";
|
|
||||||
|
|
||||||
impl ToHex for [u8] {
|
|
||||||
/// Turn a vector of `u8` bytes into a hexadecimal string.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate rustc_serialize;
|
|
||||||
/// use rustc_serialize::hex::ToHex;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let str = [52,32].to_hex();
|
|
||||||
/// println!("{}", str);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn to_hex(&self) -> String {
|
|
||||||
let mut v = Vec::with_capacity(self.len() * 2);
|
|
||||||
for &byte in self.iter() {
|
|
||||||
v.push(CHARS[(byte >> 4) as usize]);
|
|
||||||
v.push(CHARS[(byte & 0xf) as usize]);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
String::from_utf8_unchecked(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: ?Sized + ToHex> ToHex for &'a T {
|
|
||||||
fn to_hex(&self) -> String {
|
|
||||||
(**self).to_hex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for converting hexadecimal encoded values
|
|
||||||
pub trait FromHex {
|
|
||||||
/// Converts the value of `self`, interpreted as hexadecimal encoded data,
|
|
||||||
/// into an owned vector of bytes, returning the vector.
|
|
||||||
fn from_hex(&self) -> Result<Vec<u8>, FromHexError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Errors that can occur when decoding a hex encoded string
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum FromHexError {
|
|
||||||
/// The input contained a character not part of the hex format
|
|
||||||
InvalidHexCharacter(char, usize),
|
|
||||||
/// The input had an invalid length
|
|
||||||
InvalidHexLength,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for FromHexError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
InvalidHexCharacter(ch, idx) =>
|
|
||||||
write!(f, "Invalid character '{}' at position {}", ch, idx),
|
|
||||||
InvalidHexLength => write!(f, "Invalid input length"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for FromHexError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
InvalidHexCharacter(_, _) => "invalid character",
|
|
||||||
InvalidHexLength => "invalid length",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FromHexError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
fmt::Debug::fmt(&self, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromHex for str {
|
|
||||||
/// Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
|
|
||||||
/// to the byte values it encodes.
|
|
||||||
///
|
|
||||||
/// You can use the `String::from_utf8` function to turn a
|
|
||||||
/// `Vec<u8>` into a string with characters corresponding to those values.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// This converts a string literal to hexadecimal and back.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate rustc_serialize;
|
|
||||||
/// use rustc_serialize::hex::{FromHex, ToHex};
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let hello_str = "Hello, World".as_bytes().to_hex();
|
|
||||||
/// println!("{}", hello_str);
|
|
||||||
/// let bytes = hello_str.from_hex().unwrap();
|
|
||||||
/// println!("{:?}", bytes);
|
|
||||||
/// let result_str = String::from_utf8(bytes).unwrap();
|
|
||||||
/// println!("{}", result_str);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn from_hex(&self) -> Result<Vec<u8>, FromHexError> {
|
|
||||||
// This may be an overestimate if there is any whitespace
|
|
||||||
let mut b = Vec::with_capacity(self.len() / 2);
|
|
||||||
let mut modulus = 0;
|
|
||||||
let mut buf = 0;
|
|
||||||
|
|
||||||
for (idx, byte) in self.bytes().enumerate() {
|
|
||||||
buf <<= 4;
|
|
||||||
|
|
||||||
match byte {
|
|
||||||
b'A'...b'F' => buf |= byte - b'A' + 10,
|
|
||||||
b'a'...b'f' => buf |= byte - b'a' + 10,
|
|
||||||
b'0'...b'9' => buf |= byte - b'0',
|
|
||||||
b' '|b'\r'|b'\n'|b'\t' => {
|
|
||||||
buf >>= 4;
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let ch = self[idx..].chars().next().unwrap();
|
|
||||||
return Err(InvalidHexCharacter(ch, idx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modulus += 1;
|
|
||||||
if modulus == 2 {
|
|
||||||
modulus = 0;
|
|
||||||
b.push(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match modulus {
|
|
||||||
0 => Ok(b.into_iter().collect()),
|
|
||||||
_ => Err(InvalidHexLength),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: ?Sized + FromHex> FromHex for &'a T {
|
|
||||||
fn from_hex(&self) -> Result<Vec<u8>, FromHexError> {
|
|
||||||
(**self).from_hex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use hex::{FromHex, ToHex};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_to_hex() {
|
|
||||||
assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_hex_okay() {
|
|
||||||
assert_eq!("666f6f626172".from_hex().unwrap(),
|
|
||||||
b"foobar");
|
|
||||||
assert_eq!("666F6F626172".from_hex().unwrap(),
|
|
||||||
b"foobar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_hex_odd_len() {
|
|
||||||
assert!("666".from_hex().is_err());
|
|
||||||
assert!("66 6".from_hex().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_hex_invalid_char() {
|
|
||||||
assert!("66y6".from_hex().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_hex_ignores_whitespace() {
|
|
||||||
assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(),
|
|
||||||
b"foobar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_to_hex_all_bytes() {
|
|
||||||
for i in 0..256 {
|
|
||||||
assert_eq!([i as u8].to_hex(), format!("{:02x}", i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_hex_all_bytes() {
|
|
||||||
for i in 0..256 {
|
|
||||||
let ii: &[u8] = &[i as u8];
|
|
||||||
assert_eq!(format!("{:02x}", i).from_hex().unwrap(),
|
|
||||||
ii);
|
|
||||||
assert_eq!(format!("{:02X}", i).from_hex().unwrap(),
|
|
||||||
ii);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
3999
third_party/rust/rustc-serialize/src/json.rs
vendored
3999
third_party/rust/rustc-serialize/src/json.rs
vendored
File diff suppressed because it is too large
Load Diff
79
third_party/rust/rustc-serialize/src/lib.rs
vendored
79
third_party/rust/rustc-serialize/src/lib.rs
vendored
@ -1,79 +0,0 @@
|
|||||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Support code for encoding and decoding types.
|
|
||||||
//!
|
|
||||||
//! > **NOTE**: This crate is deprecated in favor of [`serde`]. No new feature
|
|
||||||
//! > development will happen in this crate, although bug fixes proposed through
|
|
||||||
//! > PRs will still be merged. It is very highly recommended by the Rust
|
|
||||||
//! > Library Team that you use [`serde`], not this crate.
|
|
||||||
//!
|
|
||||||
//! [`serde`]: https://serde.rs
|
|
||||||
//!
|
|
||||||
//! # Usage
|
|
||||||
//!
|
|
||||||
//! This crate is [on crates.io](https://crates.io/crates/rustc-serialize) and
|
|
||||||
//! can be used by adding `rustc-serialize` to the dependencies in your
|
|
||||||
//! project's `Cargo.toml`.
|
|
||||||
//!
|
|
||||||
//! ```toml
|
|
||||||
//! [dependencies]
|
|
||||||
//! rustc-serialize = "0.3"
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! and this to your crate root:
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! extern crate rustc_serialize;
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
#![cfg_attr(rustbuild, feature(staged_api, rustc_private))]
|
|
||||||
#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))]
|
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
|
||||||
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
|
|
||||||
html_root_url = "https://doc.rust-lang.org/rustc-serialize/")]
|
|
||||||
#![cfg_attr(test, deny(warnings))]
|
|
||||||
#![allow(trivial_numeric_casts)]
|
|
||||||
#![cfg_attr(rust_build, feature(staged_api))]
|
|
||||||
#![cfg_attr(rust_build, staged_api)]
|
|
||||||
#![cfg_attr(rust_build,
|
|
||||||
unstable(feature = "rustc_private",
|
|
||||||
reason = "use the crates.io `rustc-serialize` library instead"))]
|
|
||||||
|
|
||||||
#[cfg(test)] extern crate rand;
|
|
||||||
|
|
||||||
pub use self::serialize::{Decoder, Encoder, Decodable, Encodable,
|
|
||||||
DecoderHelpers, EncoderHelpers};
|
|
||||||
|
|
||||||
|
|
||||||
// Limit collections from allocating more than
|
|
||||||
// 1 MB for calls to `with_capacity`.
|
|
||||||
fn cap_capacity<T>(given_len: usize) -> usize {
|
|
||||||
use std::cmp::min;
|
|
||||||
use std::mem::size_of;
|
|
||||||
const PRE_ALLOCATE_CAP: usize = 0x100000;
|
|
||||||
|
|
||||||
match size_of::<T>() {
|
|
||||||
0 => min(given_len, PRE_ALLOCATE_CAP),
|
|
||||||
n => min(given_len, PRE_ALLOCATE_CAP / n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod serialize;
|
|
||||||
mod collection_impls;
|
|
||||||
|
|
||||||
pub mod base64;
|
|
||||||
pub mod hex;
|
|
||||||
pub mod json;
|
|
||||||
|
|
||||||
mod rustc_serialize {
|
|
||||||
pub use serialize::*;
|
|
||||||
}
|
|
1671
third_party/rust/rustc-serialize/src/serialize.rs
vendored
1671
third_party/rust/rustc-serialize/src/serialize.rs
vendored
File diff suppressed because it is too large
Load Diff
1
third_party/rust/ryu/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/ryu/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"files":{".travis.yml":"f73b83dfd8c84e2af27d780e93441a071507c8c2d981a73844558fe72717448e","Cargo.toml":"a97493cb1e3f170d30a5f8d92ae65185103083baf408eb5c0bd8f64a7ffdf007","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","README.md":"d150ab564033cacab1e6e806b13e78bb241818e950ffa4bf2623e6bd3bc64fb3","benchmark/benchmark.rs":"5ee2d5f68f6fa93f24e3828c9e8e269c22ce3ea96c0804def61b0b3026ad021f","build.rs":"96e9308d3a7a23a4c222892be8f29f45b13bffaed751f2e5b0b247230b65f360","src/buffer/mod.rs":"bcdc3db1c97b36c04c4445c4a7fba768be7a8b16e0f8bc7bab86ac06256a9750","src/common.rs":"f165881b718867b7801044bd29fa7f4322ebfc63d45d462d4a703253f8812a3e","src/d2s.rs":"35e0982e83d8c46f4304148d0454957b62be5f17480ad417d893521d578ad86e","src/d2s_full_table.rs":"7f7e475c54ae69d834574603bde9dcbe9f0d7cb09cfc3cda025319c903996bf8","src/d2s_small_table.rs":"f1bc5b328be636f100315ba818545e7d3c125cacec8487ed12f59f50d70b945e","src/digit_table.rs":"02351ca54cb8cb3679f635115dd094f32fd91750e9f66103c1ee9ec3db507072","src/f2s.rs":"2a59cc3ea57244ef4e926d98284a33363fb67452e20f24141395312173698e32","src/lib.rs":"268d75e445101f1edc0ced93852941ab9b150f1faea642490a03e8a613a33589","src/mulshift128.rs":"b539411c08b7cde489b876addc346a061e3594ed707fe577a3cdff6d26b0e1f8","src/pretty/exponent.rs":"15fd163fdb81573d331f24fda37f5403931512ffb08715a2695f0a0256b69b84","src/pretty/mantissa.rs":"7b0ea97069ee597f3bc0c8f2f3354c75be93d01c6a8135104ae82cd83df318e0","src/pretty/mod.rs":"f691267e66ce6f13d6db17ca6b93065e50a669e73916cbd22c8bfb3e33ad85fe","tests/d2s_table_test.rs":"57b541dc08c54c83979f18a20f8895daac3ad32628b140c66b09f42bce7f2691","tests/d2s_test.rs":"9abea253a30d96815688a34f20e2b3eff40c9d8b9a1209d7e927ba5a63efd74a","tests/exhaustive.rs":"0e01491936cb6b5ae68d92e50b6f7cebb26362774e860df103695ecc1f71fa7b","tests/f2s_test.rs":"7fa9dd515ed42947f570243a6d0656b6e2861c1399f679d96317dc109018d59b","tests/macros/mod.rs":"45eed20e9a3d8d9b673f504e8194f762223346adec46a6fbf1e0717eaeee85bc"},"package":"fd0568787116e13c652377b6846f5931454a363a8fdf8ae50463ee40935b278b"}
|
13
third_party/rust/ryu/.travis.yml
vendored
Normal file
13
third_party/rust/ryu/.travis.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
language: rust
|
||||||
|
|
||||||
|
rust:
|
||||||
|
- nightly
|
||||||
|
- beta
|
||||||
|
- stable
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- rust: 1.15.0
|
||||||
|
script:
|
||||||
|
- cargo build
|
||||||
|
- cargo build --features small
|
39
third_party/rust/ryu/Cargo.toml
vendored
Normal file
39
third_party/rust/ryu/Cargo.toml
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g. crates.io) dependencies
|
||||||
|
#
|
||||||
|
# If you believe there's an error in this file please file an
|
||||||
|
# issue against the rust-lang/cargo repository. If you're
|
||||||
|
# editing this file be aware that the upstream Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable)
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "ryu"
|
||||||
|
version = "0.2.4"
|
||||||
|
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||||
|
build = "build.rs"
|
||||||
|
description = "Fast floating point to string conversion"
|
||||||
|
documentation = "https://docs.rs/ryu"
|
||||||
|
readme = "README.md"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
repository = "https://github.com/dtolnay/ryu"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "benchmark"
|
||||||
|
path = "benchmark/benchmark.rs"
|
||||||
|
[dependencies.no-panic]
|
||||||
|
version = "0.1"
|
||||||
|
optional = true
|
||||||
|
[dev-dependencies.num_cpus]
|
||||||
|
version = "1.8"
|
||||||
|
|
||||||
|
[dev-dependencies.rand]
|
||||||
|
version = "0.5"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
small = []
|
||||||
|
[badges.travis-ci]
|
||||||
|
repository = "dtolnay/ryu"
|
201
third_party/rust/ryu/LICENSE-APACHE
vendored
Normal file
201
third_party/rust/ryu/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
74
third_party/rust/ryu/README.md
vendored
Normal file
74
third_party/rust/ryu/README.md
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Ryū
|
||||||
|
|
||||||
|
[![Build Status](https://api.travis-ci.org/dtolnay/ryu.svg?branch=master)](https://travis-ci.org/dtolnay/ryu)
|
||||||
|
[![Latest Version](https://img.shields.io/crates/v/ryu.svg)](https://crates.io/crates/ryu)
|
||||||
|
[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/ryu)
|
||||||
|
[![Rustc Version 1.15+](https://img.shields.io/badge/rustc-1.15+-lightgray.svg)](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html)
|
||||||
|
|
||||||
|
Pure Rust implementation of Ryū, an algorithm to quickly convert floating point
|
||||||
|
numbers to decimal strings.
|
||||||
|
|
||||||
|
The PLDI'18 paper [*Ryū: fast float-to-string conversion*][paper] by Ulf Adams
|
||||||
|
includes a complete correctness proof of the algorithm. The paper is available
|
||||||
|
under the creative commons CC-BY-SA license.
|
||||||
|
|
||||||
|
This Rust implementation is a line-by-line port of Ulf Adams' implementation in
|
||||||
|
C, [https://github.com/ulfjack/ryu][upstream]. The `ryu::raw` module exposes
|
||||||
|
exactly the API and formatting of the C implementation as unsafe pure Rust
|
||||||
|
functions. There is additionally a safe API as demonstrated in the example code
|
||||||
|
below. The safe API uses the same underlying Ryū algorithm but diverges from the
|
||||||
|
formatting of the C implementation to produce more human-readable output, for
|
||||||
|
example `0.3` rather than `3E-1`.
|
||||||
|
|
||||||
|
*Requirements: this crate supports any compiler version back to rustc 1.15; it
|
||||||
|
uses nothing from the Rust standard library so is usable from no_std crates.*
|
||||||
|
|
||||||
|
[paper]: https://dl.acm.org/citation.cfm?id=3192369
|
||||||
|
[upstream]: https://github.com/ulfjack/ryu/tree/4ffc2b759e4b0a431b35dbfbfd6e0e85fdd15a69
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
ryu = "0.2"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate ryu;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut buffer = ryu::Buffer::new();
|
||||||
|
let printed = buffer.format(1.234);
|
||||||
|
assert_eq!(printed, "1.234");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
You can run upstream's benchmarks with:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ git clone https://github.com/ulfjack/ryu c-ryu
|
||||||
|
$ cd c-ryu
|
||||||
|
$ bazel run -c opt //ryu/benchmark
|
||||||
|
```
|
||||||
|
|
||||||
|
And our benchmarks with:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ git clone https://github.com/ulfjack/ryu rust-ryu
|
||||||
|
$ cd rust-ryu
|
||||||
|
$ cargo run --example benchmark --release
|
||||||
|
```
|
||||||
|
|
||||||
|
These benchmarks measure the average time to print a 32-bit float and average
|
||||||
|
time to print a 64-bit float, where the inputs are distributed as uniform random
|
||||||
|
bit patterns 32 and 64 bits wide.
|
||||||
|
|
||||||
|
The upstream C code, the unsafe direct Rust port, and the safe pretty Rust API
|
||||||
|
all perform the same, taking around 21 nanoseconds to format a 32-bit float and
|
||||||
|
31 nanoseconds to format a 64-bit float.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
86
third_party/rust/ryu/benchmark/benchmark.rs
vendored
Normal file
86
third_party/rust/ryu/benchmark/benchmark.rs
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
extern crate rand;
|
||||||
|
extern crate ryu;
|
||||||
|
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
|
||||||
|
const SAMPLES: usize = 10000;
|
||||||
|
const ITERATIONS: usize = 1000;
|
||||||
|
|
||||||
|
struct MeanAndVariance {
|
||||||
|
n: i64,
|
||||||
|
mean: f64,
|
||||||
|
m2: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MeanAndVariance {
|
||||||
|
fn new() -> Self {
|
||||||
|
MeanAndVariance {
|
||||||
|
n: 0,
|
||||||
|
mean: 0.0,
|
||||||
|
m2: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, x: f64) {
|
||||||
|
self.n += 1;
|
||||||
|
let d = x - self.mean;
|
||||||
|
self.mean += d / self.n as f64;
|
||||||
|
let d2 = x - self.mean;
|
||||||
|
self.m2 += d * d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn variance(&self) -> f64 {
|
||||||
|
self.m2 / (self.n - 1) as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stddev(&self) -> f64 {
|
||||||
|
self.variance().sqrt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! benchmark {
|
||||||
|
($name:ident, $ty:ident) => {
|
||||||
|
fn $name() -> usize {
|
||||||
|
let mut rng = rand::prng::XorShiftRng::from_seed([123u8; 16]);
|
||||||
|
let mut mv = MeanAndVariance::new();
|
||||||
|
let mut throwaway = 0;
|
||||||
|
for _ in 0..SAMPLES {
|
||||||
|
let f = loop {
|
||||||
|
let f = $ty::from_bits(rng.gen());
|
||||||
|
if f.is_finite() {
|
||||||
|
break f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let t1 = std::time::SystemTime::now();
|
||||||
|
for _ in 0..ITERATIONS {
|
||||||
|
throwaway += ryu::Buffer::new().format(f).len();
|
||||||
|
}
|
||||||
|
let duration = t1.elapsed().unwrap();
|
||||||
|
let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64;
|
||||||
|
mv.update(nanos as f64 / ITERATIONS as f64);
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"{:12} {:8.3} {:8.3}",
|
||||||
|
concat!(stringify!($name), ":"),
|
||||||
|
mv.mean,
|
||||||
|
mv.stddev(),
|
||||||
|
);
|
||||||
|
throwaway
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
benchmark!(pretty32, f32);
|
||||||
|
benchmark!(pretty64, f64);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{:>20}{:>9}", "Average", "Stddev");
|
||||||
|
let mut throwaway = 0;
|
||||||
|
throwaway += pretty32();
|
||||||
|
throwaway += pretty64();
|
||||||
|
if std::env::var_os("ryu-benchmark").is_some() {
|
||||||
|
// Prevent the compiler from optimizing the code away.
|
||||||
|
println!("{}", throwaway);
|
||||||
|
}
|
||||||
|
}
|
54
third_party/rust/ryu/build.rs
vendored
Normal file
54
third_party/rust/ryu/build.rs
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str::{self, FromStr};
|
||||||
|
|
||||||
|
// The rustc-cfg strings below are *not* public API. Please let us know by
|
||||||
|
// opening a GitHub issue if your build environment requires some way to enable
|
||||||
|
// these cfgs other than by executing our build script.
|
||||||
|
fn main() {
|
||||||
|
let minor = match rustc_minor_version() {
|
||||||
|
Some(minor) => minor,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 128-bit integers stabilized in Rust 1.26:
|
||||||
|
// https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
|
||||||
|
if minor >= 26 {
|
||||||
|
println!("cargo:rustc-cfg=integer128");
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[must_use] on functions stabilized in Rust 1.27:
|
||||||
|
// https://blog.rust-lang.org/2018/06/21/Rust-1.27.html
|
||||||
|
if minor >= 27 {
|
||||||
|
println!("cargo:rustc-cfg=must_use_return");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rustc_minor_version() -> Option<u32> {
|
||||||
|
let rustc = match env::var_os("RUSTC") {
|
||||||
|
Some(rustc) => rustc,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = match Command::new(rustc).arg("--version").output() {
|
||||||
|
Ok(output) => output,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = match str::from_utf8(&output.stdout) {
|
||||||
|
Ok(version) => version,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut pieces = version.split('.');
|
||||||
|
if pieces.next() != Some("rustc 1") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next = match pieces.next() {
|
||||||
|
Some(next) => next,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
u32::from_str(next).ok()
|
||||||
|
}
|
97
third_party/rust/ryu/src/buffer/mod.rs
vendored
Normal file
97
third_party/rust/ryu/src/buffer/mod.rs
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
use core::{mem, slice, str};
|
||||||
|
|
||||||
|
use pretty;
|
||||||
|
|
||||||
|
#[cfg(feature = "no-panic")]
|
||||||
|
use no_panic::no_panic;
|
||||||
|
|
||||||
|
/// Safe API for formatting floating point numbers to text.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let mut buffer = ryu::Buffer::new();
|
||||||
|
/// let printed = buffer.format(1.234);
|
||||||
|
/// assert_eq!(printed, "1.234");
|
||||||
|
/// ```
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Buffer {
|
||||||
|
bytes: [u8; 24],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Buffer {
|
||||||
|
/// This is a cheap operation; you don't need to worry about reusing buffers
|
||||||
|
/// for efficiency.
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Buffer {
|
||||||
|
bytes: unsafe { mem::uninitialized() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print a floating point number into this buffer and return a reference to
|
||||||
|
/// its string representation within the buffer.
|
||||||
|
///
|
||||||
|
/// # Special cases
|
||||||
|
///
|
||||||
|
/// This function **does not** check for NaN or infinity. If the input
|
||||||
|
/// number is not a finite float, the printed representation will be some
|
||||||
|
/// correctly formatted but unspecified numerical value.
|
||||||
|
///
|
||||||
|
/// Please check [`is_finite`] yourself before calling this function, or
|
||||||
|
/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
|
||||||
|
///
|
||||||
|
/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite
|
||||||
|
/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan
|
||||||
|
/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub fn format<F: Float>(&mut self, f: F) -> &str {
|
||||||
|
unsafe {
|
||||||
|
let n = f.write_to_ryu_buffer(&mut self.bytes[0]);
|
||||||
|
debug_assert!(n <= self.bytes.len());
|
||||||
|
let slice = slice::from_raw_parts(&self.bytes[0], n);
|
||||||
|
str::from_utf8_unchecked(slice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Buffer {
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn default() -> Self {
|
||||||
|
Buffer::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A floating point number, f32 or f64, that can be written into a
|
||||||
|
/// [`ryu::Buffer`][Buffer].
|
||||||
|
///
|
||||||
|
/// This trait is sealed and cannot be implemented for types outside of the
|
||||||
|
/// `ryu` crate.
|
||||||
|
pub trait Float: Sealed {
|
||||||
|
// Not public API.
|
||||||
|
#[doc(hidden)]
|
||||||
|
unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Float for f32 {
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize {
|
||||||
|
pretty::f2s_buffered_n(self, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Float for f64 {
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize {
|
||||||
|
pretty::d2s_buffered_n(self, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Sealed {}
|
||||||
|
impl Sealed for f32 {}
|
||||||
|
impl Sealed for f64 {}
|
72
third_party/rust/ryu/src/common.rs
vendored
Normal file
72
third_party/rust/ryu/src/common.rs
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
// Returns e == 0 ? 1 : ceil(log_2(5^e)).
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn pow5bits(e: i32) -> u32 {
|
||||||
|
// This approximation works up to the point that the multiplication overflows at e = 3529.
|
||||||
|
// If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater
|
||||||
|
// than 2^9297.
|
||||||
|
debug_assert!(e >= 0);
|
||||||
|
debug_assert!(e <= 3528);
|
||||||
|
((e as u32 * 1217359) >> 19) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns floor(log_10(2^e)).
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn log10_pow2(e: i32) -> i32 {
|
||||||
|
// The first value this approximation fails for is 2^1651 which is just greater than 10^297.
|
||||||
|
debug_assert!(e >= 0);
|
||||||
|
debug_assert!(e <= 1650);
|
||||||
|
((e as u32 * 78913) >> 18) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns floor(log_10(5^e)).
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn log10_pow5(e: i32) -> i32 {
|
||||||
|
// The first value this approximation fails for is 5^2621 which is just greater than 10^1832.
|
||||||
|
debug_assert!(e >= 0);
|
||||||
|
debug_assert!(e <= 2620);
|
||||||
|
((e as u32 * 732923) >> 20) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn copy_special_str(
|
||||||
|
result: *mut u8,
|
||||||
|
sign: bool,
|
||||||
|
exponent: bool,
|
||||||
|
mantissa: bool,
|
||||||
|
) -> usize {
|
||||||
|
if mantissa {
|
||||||
|
ptr::copy_nonoverlapping(b"NaN".as_ptr(), result, 3);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if sign {
|
||||||
|
*result = b'-';
|
||||||
|
}
|
||||||
|
if exponent {
|
||||||
|
ptr::copy_nonoverlapping(b"Infinity".as_ptr(), result.offset(sign as isize), 8);
|
||||||
|
return sign as usize + 8;
|
||||||
|
}
|
||||||
|
ptr::copy_nonoverlapping(b"0E0".as_ptr(), result.offset(sign as isize), 3);
|
||||||
|
sign as usize + 3
|
||||||
|
}
|
553
third_party/rust/ryu/src/d2s.rs
vendored
Normal file
553
third_party/rust/ryu/src/d2s.rs
vendored
Normal file
@ -0,0 +1,553 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
use core::{mem, ptr};
|
||||||
|
|
||||||
|
use common::*;
|
||||||
|
#[cfg(not(feature = "small"))]
|
||||||
|
use d2s_full_table::*;
|
||||||
|
#[cfg(feature = "small")]
|
||||||
|
use d2s_small_table::*;
|
||||||
|
use digit_table::*;
|
||||||
|
#[cfg(not(integer128))]
|
||||||
|
use mulshift128::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "no-panic")]
|
||||||
|
use no_panic::no_panic;
|
||||||
|
|
||||||
|
pub const DOUBLE_MANTISSA_BITS: u32 = 52;
|
||||||
|
pub const DOUBLE_EXPONENT_BITS: u32 = 11;
|
||||||
|
|
||||||
|
const DOUBLE_POW5_INV_BITCOUNT: i32 = 122;
|
||||||
|
const DOUBLE_POW5_BITCOUNT: i32 = 121;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn pow5_factor(mut value: u64) -> u32 {
|
||||||
|
let mut count = 0u32;
|
||||||
|
loop {
|
||||||
|
debug_assert!(value != 0);
|
||||||
|
let q = value / 5;
|
||||||
|
let r = value % 5;
|
||||||
|
if r != 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = q;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if value is divisible by 5^p.
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn multiple_of_power_of_5(value: u64, p: u32) -> bool {
|
||||||
|
// I tried a case distinction on p, but there was no performance difference.
|
||||||
|
pow5_factor(value) >= p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if value is divisible by 2^p.
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn multiple_of_power_of_2(value: u64, p: u32) -> bool {
|
||||||
|
// return __builtin_ctzll(value) >= p;
|
||||||
|
(value & ((1u64 << p) - 1)) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(integer128)]
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn mul_shift(m: u64, mul: &(u64, u64), j: u32) -> u64 {
|
||||||
|
let b0 = m as u128 * mul.0 as u128;
|
||||||
|
let b2 = m as u128 * mul.1 as u128;
|
||||||
|
(((b0 >> 64) + b2) >> (j - 64)) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(integer128)]
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn mul_shift_all(
|
||||||
|
m: u64,
|
||||||
|
mul: &(u64, u64),
|
||||||
|
j: u32,
|
||||||
|
vp: &mut u64,
|
||||||
|
vm: &mut u64,
|
||||||
|
mm_shift: u32,
|
||||||
|
) -> u64 {
|
||||||
|
*vp = mul_shift(4 * m + 2, mul, j);
|
||||||
|
*vm = mul_shift(4 * m - 1 - mm_shift as u64, mul, j);
|
||||||
|
mul_shift(4 * m, mul, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(integer128))]
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn mul_shift_all(
|
||||||
|
mut m: u64,
|
||||||
|
mul: &(u64, u64),
|
||||||
|
j: u32,
|
||||||
|
vp: &mut u64,
|
||||||
|
vm: &mut u64,
|
||||||
|
mm_shift: u32,
|
||||||
|
) -> u64 {
|
||||||
|
m <<= 1;
|
||||||
|
// m is maximum 55 bits
|
||||||
|
let (lo, tmp) = umul128(m, mul.0);
|
||||||
|
let (mut mid, mut hi) = umul128(m, mul.1);
|
||||||
|
mid = mid.wrapping_add(tmp);
|
||||||
|
hi = hi.wrapping_add((mid < tmp) as u64); // overflow into hi
|
||||||
|
|
||||||
|
let lo2 = lo.wrapping_add(mul.0);
|
||||||
|
let mid2 = mid.wrapping_add(mul.1).wrapping_add((lo2 < lo) as u64);
|
||||||
|
let hi2 = hi.wrapping_add((mid2 < mid) as u64);
|
||||||
|
*vp = shiftright128(mid2, hi2, j - 64 - 1);
|
||||||
|
|
||||||
|
if mm_shift == 1 {
|
||||||
|
let lo3 = lo.wrapping_sub(mul.0);
|
||||||
|
let mid3 = mid.wrapping_sub(mul.1).wrapping_sub((lo3 > lo) as u64);
|
||||||
|
let hi3 = hi.wrapping_sub((mid3 > mid) as u64);
|
||||||
|
*vm = shiftright128(mid3, hi3, j - 64 - 1);
|
||||||
|
} else {
|
||||||
|
let lo3 = lo + lo;
|
||||||
|
let mid3 = mid.wrapping_add(mid).wrapping_add((lo3 < lo) as u64);
|
||||||
|
let hi3 = hi.wrapping_add(hi).wrapping_add((mid3 < mid) as u64);
|
||||||
|
let lo4 = lo3.wrapping_sub(mul.0);
|
||||||
|
let mid4 = mid3.wrapping_sub(mul.1).wrapping_sub((lo4 > lo3) as u64);
|
||||||
|
let hi4 = hi3.wrapping_sub((mid4 > mid3) as u64);
|
||||||
|
*vm = shiftright128(mid4, hi4, j - 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
shiftright128(mid, hi, j - 64 - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn decimal_length(v: u64) -> u32 {
|
||||||
|
// This is slightly faster than a loop.
|
||||||
|
// The average output length is 16.38 digits, so we check high-to-low.
|
||||||
|
// Function precondition: v is not an 18, 19, or 20-digit number.
|
||||||
|
// (17 digits are sufficient for round-tripping.)
|
||||||
|
debug_assert!(v < 100000000000000000);
|
||||||
|
|
||||||
|
if v >= 10000000000000000 {
|
||||||
|
17
|
||||||
|
} else if v >= 1000000000000000 {
|
||||||
|
16
|
||||||
|
} else if v >= 100000000000000 {
|
||||||
|
15
|
||||||
|
} else if v >= 10000000000000 {
|
||||||
|
14
|
||||||
|
} else if v >= 1000000000000 {
|
||||||
|
13
|
||||||
|
} else if v >= 100000000000 {
|
||||||
|
12
|
||||||
|
} else if v >= 10000000000 {
|
||||||
|
11
|
||||||
|
} else if v >= 1000000000 {
|
||||||
|
10
|
||||||
|
} else if v >= 100000000 {
|
||||||
|
9
|
||||||
|
} else if v >= 10000000 {
|
||||||
|
8
|
||||||
|
} else if v >= 1000000 {
|
||||||
|
7
|
||||||
|
} else if v >= 100000 {
|
||||||
|
6
|
||||||
|
} else if v >= 10000 {
|
||||||
|
5
|
||||||
|
} else if v >= 1000 {
|
||||||
|
4
|
||||||
|
} else if v >= 100 {
|
||||||
|
3
|
||||||
|
} else if v >= 10 {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A floating decimal representing m * 10^e.
|
||||||
|
pub struct FloatingDecimal64 {
|
||||||
|
pub mantissa: u64,
|
||||||
|
pub exponent: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
|
||||||
|
let bias = (1u32 << (DOUBLE_EXPONENT_BITS - 1)) - 1;
|
||||||
|
|
||||||
|
let (e2, m2) = if ieee_exponent == 0 {
|
||||||
|
(
|
||||||
|
// We subtract 2 so that the bounds computation has 2 additional bits.
|
||||||
|
1 - bias as i32 - DOUBLE_MANTISSA_BITS as i32 - 2,
|
||||||
|
ieee_mantissa,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
ieee_exponent as i32 - bias as i32 - DOUBLE_MANTISSA_BITS as i32 - 2,
|
||||||
|
(1u64 << DOUBLE_MANTISSA_BITS) | ieee_mantissa,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let even = (m2 & 1) == 0;
|
||||||
|
let accept_bounds = even;
|
||||||
|
|
||||||
|
// Step 2: Determine the interval of legal decimal representations.
|
||||||
|
let mv = 4 * m2;
|
||||||
|
// Implicit bool -> int conversion. True is 1, false is 0.
|
||||||
|
let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32;
|
||||||
|
// We would compute mp and mm like this:
|
||||||
|
// uint64_t mp = 4 * m2 + 2;
|
||||||
|
// uint64_t mm = mv - 1 - mm_shift;
|
||||||
|
|
||||||
|
// Step 3: Convert to a decimal power base using 128-bit arithmetic.
|
||||||
|
let mut vr: u64;
|
||||||
|
let mut vp: u64 = unsafe { mem::uninitialized() };
|
||||||
|
let mut vm: u64 = unsafe { mem::uninitialized() };
|
||||||
|
let e10: i32;
|
||||||
|
let mut vm_is_trailing_zeros = false;
|
||||||
|
let mut vr_is_trailing_zeros = false;
|
||||||
|
if e2 >= 0 {
|
||||||
|
// I tried special-casing q == 0, but there was no effect on performance.
|
||||||
|
// This expression is slightly faster than max(0, log10_pow2(e2) - 1).
|
||||||
|
let q = (log10_pow2(e2) - (e2 > 3) as i32) as u32;
|
||||||
|
e10 = q as i32;
|
||||||
|
let k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q as i32) as i32 - 1;
|
||||||
|
let i = -e2 + q as i32 + k;
|
||||||
|
vr = mul_shift_all(
|
||||||
|
m2,
|
||||||
|
#[cfg(feature = "small")]
|
||||||
|
unsafe {
|
||||||
|
&compute_inv_pow5(q)
|
||||||
|
},
|
||||||
|
#[cfg(not(feature = "small"))]
|
||||||
|
unsafe {
|
||||||
|
debug_assert!(q < DOUBLE_POW5_INV_SPLIT.len() as u32);
|
||||||
|
DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize)
|
||||||
|
},
|
||||||
|
i as u32,
|
||||||
|
&mut vp,
|
||||||
|
&mut vm,
|
||||||
|
mm_shift,
|
||||||
|
);
|
||||||
|
if q <= 21 {
|
||||||
|
// This should use q <= 22, but I think 21 is also safe. Smaller values
|
||||||
|
// may still be safe, but it's more difficult to reason about them.
|
||||||
|
// Only one of mp, mv, and mm can be a multiple of 5, if any.
|
||||||
|
if mv % 5 == 0 {
|
||||||
|
vr_is_trailing_zeros = multiple_of_power_of_5(mv, q);
|
||||||
|
} else if accept_bounds {
|
||||||
|
// Same as min(e2 + (~mm & 1), pow5_factor(mm)) >= q
|
||||||
|
// <=> e2 + (~mm & 1) >= q && pow5_factor(mm) >= q
|
||||||
|
// <=> true && pow5_factor(mm) >= q, since e2 >= q.
|
||||||
|
vm_is_trailing_zeros = multiple_of_power_of_5(mv - 1 - mm_shift as u64, q);
|
||||||
|
} else {
|
||||||
|
// Same as min(e2 + 1, pow5_factor(mp)) >= q.
|
||||||
|
vp -= multiple_of_power_of_5(mv + 2, q) as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This expression is slightly faster than max(0, log10_pow5(-e2) - 1).
|
||||||
|
let q = (log10_pow5(-e2) - (-e2 > 1) as i32) as u32;
|
||||||
|
e10 = q as i32 + e2;
|
||||||
|
let i = -e2 - q as i32;
|
||||||
|
let k = pow5bits(i) as i32 - DOUBLE_POW5_BITCOUNT;
|
||||||
|
let j = q as i32 - k;
|
||||||
|
vr = mul_shift_all(
|
||||||
|
m2,
|
||||||
|
#[cfg(feature = "small")]
|
||||||
|
unsafe {
|
||||||
|
&compute_pow5(i as u32)
|
||||||
|
},
|
||||||
|
#[cfg(not(feature = "small"))]
|
||||||
|
unsafe {
|
||||||
|
debug_assert!(i < DOUBLE_POW5_SPLIT.len() as i32);
|
||||||
|
DOUBLE_POW5_SPLIT.get_unchecked(i as usize)
|
||||||
|
},
|
||||||
|
j as u32,
|
||||||
|
&mut vp,
|
||||||
|
&mut vm,
|
||||||
|
mm_shift,
|
||||||
|
);
|
||||||
|
if q <= 1 {
|
||||||
|
// {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
|
||||||
|
// mv = 4 * m2, so it always has at least two trailing 0 bits.
|
||||||
|
vr_is_trailing_zeros = true;
|
||||||
|
if accept_bounds {
|
||||||
|
// mm = mv - 1 - mm_shift, so it has 1 trailing 0 bit iff mm_shift == 1.
|
||||||
|
vm_is_trailing_zeros = mm_shift == 1;
|
||||||
|
} else {
|
||||||
|
// mp = mv + 2, so it always has at least one trailing 0 bit.
|
||||||
|
vp -= 1;
|
||||||
|
}
|
||||||
|
} else if q < 63 {
|
||||||
|
// TODO(ulfjack): Use a tighter bound here.
|
||||||
|
// We need to compute min(ntz(mv), pow5_factor(mv) - e2) >= q - 1
|
||||||
|
// <=> ntz(mv) >= q - 1 && pow5_factor(mv) - e2 >= q - 1
|
||||||
|
// <=> ntz(mv) >= q - 1 (e2 is negative and -e2 >= q)
|
||||||
|
// <=> (mv & ((1 << (q - 1)) - 1)) == 0
|
||||||
|
// We also need to make sure that the left shift does not overflow.
|
||||||
|
vr_is_trailing_zeros = multiple_of_power_of_2(mv, q - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Find the shortest decimal representation in the interval of legal representations.
|
||||||
|
let mut removed = 0u32;
|
||||||
|
let mut last_removed_digit = 0u8;
|
||||||
|
// On average, we remove ~2 digits.
|
||||||
|
let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
|
||||||
|
// General case, which happens rarely (~0.7%).
|
||||||
|
while vp / 10 > vm / 10 {
|
||||||
|
vm_is_trailing_zeros &= vm - (vm / 10) * 10 == 0;
|
||||||
|
vr_is_trailing_zeros &= last_removed_digit == 0;
|
||||||
|
last_removed_digit = (vr % 10) as u8;
|
||||||
|
vr /= 10;
|
||||||
|
vp /= 10;
|
||||||
|
vm /= 10;
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
if vm_is_trailing_zeros {
|
||||||
|
while vm % 10 == 0 {
|
||||||
|
vr_is_trailing_zeros &= last_removed_digit == 0;
|
||||||
|
last_removed_digit = (vr % 10) as u8;
|
||||||
|
vr /= 10;
|
||||||
|
vp /= 10;
|
||||||
|
vm /= 10;
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
|
||||||
|
// Round even if the exact number is .....50..0.
|
||||||
|
last_removed_digit = 4;
|
||||||
|
}
|
||||||
|
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||||
|
vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5)
|
||||||
|
as u64
|
||||||
|
} else {
|
||||||
|
// Specialized for the common case (~99.3%). Percentages below are relative to this.
|
||||||
|
let mut round_up = false;
|
||||||
|
// Optimization: remove two digits at a time (~86.2%).
|
||||||
|
if vp / 100 > vm / 100 {
|
||||||
|
round_up = vr % 100 >= 50;
|
||||||
|
vr /= 100;
|
||||||
|
vp /= 100;
|
||||||
|
vm /= 100;
|
||||||
|
removed += 2;
|
||||||
|
}
|
||||||
|
// Loop iterations below (approximately), without optimization above:
|
||||||
|
// 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
|
||||||
|
// Loop iterations below (approximately), with optimization above:
|
||||||
|
// 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
|
||||||
|
while vp / 10 > vm / 10 {
|
||||||
|
round_up = vr % 10 >= 5;
|
||||||
|
vr /= 10;
|
||||||
|
vp /= 10;
|
||||||
|
vm /= 10;
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||||
|
vr + (vr == vm || round_up) as u64
|
||||||
|
};
|
||||||
|
let exp = e10 + removed as i32;
|
||||||
|
|
||||||
|
FloatingDecimal64 {
|
||||||
|
exponent: exp,
|
||||||
|
mantissa: output,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
unsafe fn to_chars(v: FloatingDecimal64, sign: bool, result: *mut u8) -> usize {
|
||||||
|
// Step 5: Print the decimal representation.
|
||||||
|
let mut index = 0isize;
|
||||||
|
if sign {
|
||||||
|
*result.offset(index) = b'-';
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = v.mantissa;
|
||||||
|
let olength = decimal_length(output);
|
||||||
|
|
||||||
|
// Print the decimal digits.
|
||||||
|
// The following code is equivalent to:
|
||||||
|
// for (uint32_t i = 0; i < olength - 1; ++i) {
|
||||||
|
// const uint32_t c = output % 10; output /= 10;
|
||||||
|
// result[index + olength - i] = (char) ('0' + c);
|
||||||
|
// }
|
||||||
|
// result[index] = '0' + output % 10;
|
||||||
|
|
||||||
|
let mut i = 0isize;
|
||||||
|
// We prefer 32-bit operations, even on 64-bit platforms.
|
||||||
|
// We have at most 17 digits, and uint32_t can store 9 digits.
|
||||||
|
// If output doesn't fit into uint32_t, we cut off 8 digits,
|
||||||
|
// so the rest will fit into uint32_t.
|
||||||
|
if (output >> 32) != 0 {
|
||||||
|
// Expensive 64-bit division.
|
||||||
|
let mut output2 = (output - 100000000 * (output / 100000000)) as u32;
|
||||||
|
output /= 100000000;
|
||||||
|
|
||||||
|
let c = output2 % 10000;
|
||||||
|
output2 /= 10000;
|
||||||
|
let d = output2 % 10000;
|
||||||
|
let c0 = (c % 100) << 1;
|
||||||
|
let c1 = (c / 100) << 1;
|
||||||
|
let d0 = (d % 100) << 1;
|
||||||
|
let d1 = (d / 100) << 1;
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c0 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 1),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c1 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 3),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(d0 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 5),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(d1 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 7),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
i += 8;
|
||||||
|
}
|
||||||
|
let mut output2 = output as u32;
|
||||||
|
while output2 >= 10000 {
|
||||||
|
let c = (output2 - 10000 * (output2 / 10000)) as u32;
|
||||||
|
output2 /= 10000;
|
||||||
|
let c0 = (c % 100) << 1;
|
||||||
|
let c1 = (c / 100) << 1;
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c0 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 1),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c1 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 3),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
if output2 >= 100 {
|
||||||
|
let c = ((output2 % 100) << 1) as u32;
|
||||||
|
output2 /= 100;
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c as usize),
|
||||||
|
result.offset(index + olength as isize - i - 1),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
if output2 >= 10 {
|
||||||
|
let c = (output2 << 1) as u32;
|
||||||
|
// We can't use memcpy here: the decimal dot goes between these two digits.
|
||||||
|
*result.offset(index + olength as isize - i) = *DIGIT_TABLE.get_unchecked(c as usize + 1);
|
||||||
|
*result.offset(index) = *DIGIT_TABLE.get_unchecked(c as usize);
|
||||||
|
} else {
|
||||||
|
*result.offset(index) = b'0' + output2 as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print decimal point if needed.
|
||||||
|
if olength > 1 {
|
||||||
|
*result.offset(index + 1) = b'.';
|
||||||
|
index += olength as isize + 1;
|
||||||
|
} else {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the exponent.
|
||||||
|
*result.offset(index) = b'E';
|
||||||
|
index += 1;
|
||||||
|
let mut exp = v.exponent as i32 + olength as i32 - 1;
|
||||||
|
if exp < 0 {
|
||||||
|
*result.offset(index) = b'-';
|
||||||
|
index += 1;
|
||||||
|
exp = -exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp >= 100 {
|
||||||
|
let c = exp % 10;
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked((2 * (exp / 10)) as usize),
|
||||||
|
result.offset(index),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
*result.offset(index + 2) = b'0' + c as u8;
|
||||||
|
index += 3;
|
||||||
|
} else if exp >= 10 {
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked((2 * exp) as usize),
|
||||||
|
result.offset(index),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
index += 2;
|
||||||
|
} else {
|
||||||
|
*result.offset(index) = b'0' + exp as u8;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(index <= 24);
|
||||||
|
index as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print f64 to the given buffer and return number of bytes written.
|
||||||
|
///
|
||||||
|
/// At most 24 bytes will be written.
|
||||||
|
///
|
||||||
|
/// ## Special cases
|
||||||
|
///
|
||||||
|
/// This function represents any NaN as `NaN`, positive infinity as `Infinity`,
|
||||||
|
/// and negative infinity as `-Infinity`.
|
||||||
|
///
|
||||||
|
/// ## Safety
|
||||||
|
///
|
||||||
|
/// The `result` pointer argument must point to sufficiently many writable bytes
|
||||||
|
/// to hold Ryū's representation of `f`.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let f = 1.234f64;
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// let mut buffer: [u8; 24] = std::mem::uninitialized();
|
||||||
|
/// let n = ryu::raw::d2s_buffered_n(f, &mut buffer[0]);
|
||||||
|
/// let s = std::str::from_utf8_unchecked(&buffer[..n]);
|
||||||
|
/// assert_eq!(s, "1.234E0");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg_attr(must_use_return, must_use)]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub unsafe fn d2s_buffered_n(f: f64, result: *mut u8) -> usize {
|
||||||
|
// Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
|
||||||
|
let bits = mem::transmute::<f64, u64>(f);
|
||||||
|
|
||||||
|
// Decode bits into sign, mantissa, and exponent.
|
||||||
|
let ieee_sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
|
||||||
|
let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1);
|
||||||
|
let ieee_exponent =
|
||||||
|
(bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);
|
||||||
|
// Case distinction; exit early for the easy cases.
|
||||||
|
if ieee_exponent == ((1u32 << DOUBLE_EXPONENT_BITS) - 1)
|
||||||
|
|| (ieee_exponent == 0 && ieee_mantissa == 0)
|
||||||
|
{
|
||||||
|
return copy_special_str(result, ieee_sign, ieee_exponent != 0, ieee_mantissa != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = d2d(ieee_mantissa, ieee_exponent);
|
||||||
|
to_chars(v, ieee_sign, result)
|
||||||
|
}
|
643
third_party/rust/ryu/src/d2s_full_table.rs
vendored
Normal file
643
third_party/rust/ryu/src/d2s_full_table.rs
vendored
Normal file
@ -0,0 +1,643 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
pub static DOUBLE_POW5_INV_SPLIT: [(u64, u64); 292] = [
|
||||||
|
(1, 288230376151711744),
|
||||||
|
(3689348814741910324, 230584300921369395),
|
||||||
|
(2951479051793528259, 184467440737095516),
|
||||||
|
(17118578500402463900, 147573952589676412),
|
||||||
|
(12632330341676300947, 236118324143482260),
|
||||||
|
(10105864273341040758, 188894659314785808),
|
||||||
|
(15463389048156653253, 151115727451828646),
|
||||||
|
(17362724847566824558, 241785163922925834),
|
||||||
|
(17579528692795369969, 193428131138340667),
|
||||||
|
(6684925324752475329, 154742504910672534),
|
||||||
|
(18074578149087781173, 247588007857076054),
|
||||||
|
(18149011334012135262, 198070406285660843),
|
||||||
|
(3451162622983977240, 158456325028528675),
|
||||||
|
(5521860196774363583, 253530120045645880),
|
||||||
|
(4417488157419490867, 202824096036516704),
|
||||||
|
(7223339340677503017, 162259276829213363),
|
||||||
|
(7867994130342094503, 259614842926741381),
|
||||||
|
(2605046489531765280, 207691874341393105),
|
||||||
|
(2084037191625412224, 166153499473114484),
|
||||||
|
(10713157136084480204, 265845599156983174),
|
||||||
|
(12259874523609494487, 212676479325586539),
|
||||||
|
(13497248433629505913, 170141183460469231),
|
||||||
|
(14216899864323388813, 272225893536750770),
|
||||||
|
(11373519891458711051, 217780714829400616),
|
||||||
|
(5409467098425058518, 174224571863520493),
|
||||||
|
(4965798542738183305, 278759314981632789),
|
||||||
|
(7661987648932456967, 223007451985306231),
|
||||||
|
(2440241304404055250, 178405961588244985),
|
||||||
|
(3904386087046488400, 285449538541191976),
|
||||||
|
(17880904128604832013, 228359630832953580),
|
||||||
|
(14304723302883865611, 182687704666362864),
|
||||||
|
(15133127457049002812, 146150163733090291),
|
||||||
|
(16834306301794583852, 233840261972944466),
|
||||||
|
(9778096226693756759, 187072209578355573),
|
||||||
|
(15201174610838826053, 149657767662684458),
|
||||||
|
(2185786488890659746, 239452428260295134),
|
||||||
|
(5437978005854438120, 191561942608236107),
|
||||||
|
(15418428848909281466, 153249554086588885),
|
||||||
|
(6222742084545298729, 245199286538542217),
|
||||||
|
(16046240111861969953, 196159429230833773),
|
||||||
|
(1768945645263844993, 156927543384667019),
|
||||||
|
(10209010661905972635, 251084069415467230),
|
||||||
|
(8167208529524778108, 200867255532373784),
|
||||||
|
(10223115638361732810, 160693804425899027),
|
||||||
|
(1599589762411131202, 257110087081438444),
|
||||||
|
(4969020624670815285, 205688069665150755),
|
||||||
|
(3975216499736652228, 164550455732120604),
|
||||||
|
(13739044029062464211, 263280729171392966),
|
||||||
|
(7301886408508061046, 210624583337114373),
|
||||||
|
(13220206756290269483, 168499666669691498),
|
||||||
|
(17462981995322520850, 269599466671506397),
|
||||||
|
(6591687966774196033, 215679573337205118),
|
||||||
|
(12652048002903177473, 172543658669764094),
|
||||||
|
(9175230360419352987, 276069853871622551),
|
||||||
|
(3650835473593572067, 220855883097298041),
|
||||||
|
(17678063637842498946, 176684706477838432),
|
||||||
|
(13527506561580357021, 282695530364541492),
|
||||||
|
(3443307619780464970, 226156424291633194),
|
||||||
|
(6443994910566282300, 180925139433306555),
|
||||||
|
(5155195928453025840, 144740111546645244),
|
||||||
|
(15627011115008661990, 231584178474632390),
|
||||||
|
(12501608892006929592, 185267342779705912),
|
||||||
|
(2622589484121723027, 148213874223764730),
|
||||||
|
(4196143174594756843, 237142198758023568),
|
||||||
|
(10735612169159626121, 189713759006418854),
|
||||||
|
(12277838550069611220, 151771007205135083),
|
||||||
|
(15955192865369467629, 242833611528216133),
|
||||||
|
(1696107848069843133, 194266889222572907),
|
||||||
|
(12424932722681605476, 155413511378058325),
|
||||||
|
(1433148282581017146, 248661618204893321),
|
||||||
|
(15903913885032455010, 198929294563914656),
|
||||||
|
(9033782293284053685, 159143435651131725),
|
||||||
|
(14454051669254485895, 254629497041810760),
|
||||||
|
(11563241335403588716, 203703597633448608),
|
||||||
|
(16629290697806691620, 162962878106758886),
|
||||||
|
(781423413297334329, 260740604970814219),
|
||||||
|
(4314487545379777786, 208592483976651375),
|
||||||
|
(3451590036303822229, 166873987181321100),
|
||||||
|
(5522544058086115566, 266998379490113760),
|
||||||
|
(4418035246468892453, 213598703592091008),
|
||||||
|
(10913125826658934609, 170878962873672806),
|
||||||
|
(10082303693170474728, 273406340597876490),
|
||||||
|
(8065842954536379782, 218725072478301192),
|
||||||
|
(17520720807854834795, 174980057982640953),
|
||||||
|
(5897060404116273733, 279968092772225526),
|
||||||
|
(1028299508551108663, 223974474217780421),
|
||||||
|
(15580034865808528224, 179179579374224336),
|
||||||
|
(17549358155809824511, 286687326998758938),
|
||||||
|
(2971440080422128639, 229349861599007151),
|
||||||
|
(17134547323305344204, 183479889279205720),
|
||||||
|
(13707637858644275364, 146783911423364576),
|
||||||
|
(14553522944347019935, 234854258277383322),
|
||||||
|
(4264120725993795302, 187883406621906658),
|
||||||
|
(10789994210278856888, 150306725297525326),
|
||||||
|
(9885293106962350374, 240490760476040522),
|
||||||
|
(529536856086059653, 192392608380832418),
|
||||||
|
(7802327114352668369, 153914086704665934),
|
||||||
|
(1415676938738538420, 246262538727465495),
|
||||||
|
(1132541550990830736, 197010030981972396),
|
||||||
|
(15663428499760305882, 157608024785577916),
|
||||||
|
(17682787970132668764, 252172839656924666),
|
||||||
|
(10456881561364224688, 201738271725539733),
|
||||||
|
(15744202878575200397, 161390617380431786),
|
||||||
|
(17812026976236499989, 258224987808690858),
|
||||||
|
(3181575136763469022, 206579990246952687),
|
||||||
|
(13613306553636506187, 165263992197562149),
|
||||||
|
(10713244041592678929, 264422387516099439),
|
||||||
|
(12259944048016053467, 211537910012879551),
|
||||||
|
(6118606423670932450, 169230328010303641),
|
||||||
|
(2411072648389671274, 270768524816485826),
|
||||||
|
(16686253377679378312, 216614819853188660),
|
||||||
|
(13349002702143502650, 173291855882550928),
|
||||||
|
(17669055508687693916, 277266969412081485),
|
||||||
|
(14135244406950155133, 221813575529665188),
|
||||||
|
(240149081334393137, 177450860423732151),
|
||||||
|
(11452284974360759988, 283921376677971441),
|
||||||
|
(5472479164746697667, 227137101342377153),
|
||||||
|
(11756680961281178780, 181709681073901722),
|
||||||
|
(2026647139541122378, 145367744859121378),
|
||||||
|
(18000030682233437097, 232588391774594204),
|
||||||
|
(18089373360528660001, 186070713419675363),
|
||||||
|
(3403452244197197031, 148856570735740291),
|
||||||
|
(16513570034941246220, 238170513177184465),
|
||||||
|
(13210856027952996976, 190536410541747572),
|
||||||
|
(3189987192878576934, 152429128433398058),
|
||||||
|
(1414630693863812771, 243886605493436893),
|
||||||
|
(8510402184574870864, 195109284394749514),
|
||||||
|
(10497670562401807014, 156087427515799611),
|
||||||
|
(9417575270359070576, 249739884025279378),
|
||||||
|
(14912757845771077107, 199791907220223502),
|
||||||
|
(4551508647133041040, 159833525776178802),
|
||||||
|
(10971762650154775986, 255733641241886083),
|
||||||
|
(16156107749607641435, 204586912993508866),
|
||||||
|
(9235537384944202825, 163669530394807093),
|
||||||
|
(11087511001168814197, 261871248631691349),
|
||||||
|
(12559357615676961681, 209496998905353079),
|
||||||
|
(13736834907283479668, 167597599124282463),
|
||||||
|
(18289587036911657145, 268156158598851941),
|
||||||
|
(10942320814787415393, 214524926879081553),
|
||||||
|
(16132554281313752961, 171619941503265242),
|
||||||
|
(11054691591134363444, 274591906405224388),
|
||||||
|
(16222450902391311402, 219673525124179510),
|
||||||
|
(12977960721913049122, 175738820099343608),
|
||||||
|
(17075388340318968271, 281182112158949773),
|
||||||
|
(2592264228029443648, 224945689727159819),
|
||||||
|
(5763160197165465241, 179956551781727855),
|
||||||
|
(9221056315464744386, 287930482850764568),
|
||||||
|
(14755542681855616155, 230344386280611654),
|
||||||
|
(15493782960226403247, 184275509024489323),
|
||||||
|
(1326979923955391628, 147420407219591459),
|
||||||
|
(9501865507812447252, 235872651551346334),
|
||||||
|
(11290841220991868125, 188698121241077067),
|
||||||
|
(1653975347309673853, 150958496992861654),
|
||||||
|
(10025058185179298811, 241533595188578646),
|
||||||
|
(4330697733401528726, 193226876150862917),
|
||||||
|
(14532604630946953951, 154581500920690333),
|
||||||
|
(1116074521063664381, 247330401473104534),
|
||||||
|
(4582208431592841828, 197864321178483627),
|
||||||
|
(14733813189500004432, 158291456942786901),
|
||||||
|
(16195403473716186445, 253266331108459042),
|
||||||
|
(5577625149489128510, 202613064886767234),
|
||||||
|
(8151448934333213131, 162090451909413787),
|
||||||
|
(16731667109675051333, 259344723055062059),
|
||||||
|
(17074682502481951390, 207475778444049647),
|
||||||
|
(6281048372501740465, 165980622755239718),
|
||||||
|
(6360328581260874421, 265568996408383549),
|
||||||
|
(8777611679750609860, 212455197126706839),
|
||||||
|
(10711438158542398211, 169964157701365471),
|
||||||
|
(9759603424184016492, 271942652322184754),
|
||||||
|
(11497031554089123517, 217554121857747803),
|
||||||
|
(16576322872755119460, 174043297486198242),
|
||||||
|
(11764721337440549842, 278469275977917188),
|
||||||
|
(16790474699436260520, 222775420782333750),
|
||||||
|
(13432379759549008416, 178220336625867000),
|
||||||
|
(3045063541568861850, 285152538601387201),
|
||||||
|
(17193446092222730773, 228122030881109760),
|
||||||
|
(13754756873778184618, 182497624704887808),
|
||||||
|
(18382503128506368341, 145998099763910246),
|
||||||
|
(3586563302416817083, 233596959622256395),
|
||||||
|
(2869250641933453667, 186877567697805116),
|
||||||
|
(17052795772514404226, 149502054158244092),
|
||||||
|
(12527077977055405469, 239203286653190548),
|
||||||
|
(17400360011128145022, 191362629322552438),
|
||||||
|
(2852241564676785048, 153090103458041951),
|
||||||
|
(15631632947708587046, 244944165532867121),
|
||||||
|
(8815957543424959314, 195955332426293697),
|
||||||
|
(18120812478965698421, 156764265941034957),
|
||||||
|
(14235904707377476180, 250822825505655932),
|
||||||
|
(4010026136418160298, 200658260404524746),
|
||||||
|
(17965416168102169531, 160526608323619796),
|
||||||
|
(2919224165770098987, 256842573317791675),
|
||||||
|
(2335379332616079190, 205474058654233340),
|
||||||
|
(1868303466092863352, 164379246923386672),
|
||||||
|
(6678634360490491686, 263006795077418675),
|
||||||
|
(5342907488392393349, 210405436061934940),
|
||||||
|
(4274325990713914679, 168324348849547952),
|
||||||
|
(10528270399884173809, 269318958159276723),
|
||||||
|
(15801313949391159694, 215455166527421378),
|
||||||
|
(1573004715287196786, 172364133221937103),
|
||||||
|
(17274202803427156150, 275782613155099364),
|
||||||
|
(17508711057483635243, 220626090524079491),
|
||||||
|
(10317620031244997871, 176500872419263593),
|
||||||
|
(12818843235250086271, 282401395870821749),
|
||||||
|
(13944423402941979340, 225921116696657399),
|
||||||
|
(14844887537095493795, 180736893357325919),
|
||||||
|
(15565258844418305359, 144589514685860735),
|
||||||
|
(6457670077359736959, 231343223497377177),
|
||||||
|
(16234182506113520537, 185074578797901741),
|
||||||
|
(9297997190148906106, 148059663038321393),
|
||||||
|
(11187446689496339446, 236895460861314229),
|
||||||
|
(12639306166338981880, 189516368689051383),
|
||||||
|
(17490142562555006151, 151613094951241106),
|
||||||
|
(2158786396894637579, 242580951921985771),
|
||||||
|
(16484424376483351356, 194064761537588616),
|
||||||
|
(9498190686444770762, 155251809230070893),
|
||||||
|
(11507756283569722895, 248402894768113429),
|
||||||
|
(12895553841597688639, 198722315814490743),
|
||||||
|
(17695140702761971558, 158977852651592594),
|
||||||
|
(17244178680193423523, 254364564242548151),
|
||||||
|
(10105994129412828495, 203491651394038521),
|
||||||
|
(4395446488788352473, 162793321115230817),
|
||||||
|
(10722063196803274280, 260469313784369307),
|
||||||
|
(1198952927958798777, 208375451027495446),
|
||||||
|
(15716557601334680315, 166700360821996356),
|
||||||
|
(17767794532651667857, 266720577315194170),
|
||||||
|
(14214235626121334286, 213376461852155336),
|
||||||
|
(7682039686155157106, 170701169481724269),
|
||||||
|
(1223217053622520399, 273121871170758831),
|
||||||
|
(15735968901865657612, 218497496936607064),
|
||||||
|
(16278123936234436413, 174797997549285651),
|
||||||
|
(219556594781725998, 279676796078857043),
|
||||||
|
(7554342905309201445, 223741436863085634),
|
||||||
|
(9732823138989271479, 178993149490468507),
|
||||||
|
(815121763415193074, 286389039184749612),
|
||||||
|
(11720143854957885429, 229111231347799689),
|
||||||
|
(13065463898708218666, 183288985078239751),
|
||||||
|
(6763022304224664610, 146631188062591801),
|
||||||
|
(3442138057275642729, 234609900900146882),
|
||||||
|
(13821756890046245153, 187687920720117505),
|
||||||
|
(11057405512036996122, 150150336576094004),
|
||||||
|
(6623802375033462826, 240240538521750407),
|
||||||
|
(16367088344252501231, 192192430817400325),
|
||||||
|
(13093670675402000985, 153753944653920260),
|
||||||
|
(2503129006933649959, 246006311446272417),
|
||||||
|
(13070549649772650937, 196805049157017933),
|
||||||
|
(17835137349301941396, 157444039325614346),
|
||||||
|
(2710778055689733971, 251910462920982955),
|
||||||
|
(2168622444551787177, 201528370336786364),
|
||||||
|
(5424246770383340065, 161222696269429091),
|
||||||
|
(1300097203129523457, 257956314031086546),
|
||||||
|
(15797473021471260058, 206365051224869236),
|
||||||
|
(8948629602435097724, 165092040979895389),
|
||||||
|
(3249760919670425388, 264147265567832623),
|
||||||
|
(9978506365220160957, 211317812454266098),
|
||||||
|
(15361502721659949412, 169054249963412878),
|
||||||
|
(2442311466204457120, 270486799941460606),
|
||||||
|
(16711244431931206989, 216389439953168484),
|
||||||
|
(17058344360286875914, 173111551962534787),
|
||||||
|
(12535955717491360170, 276978483140055660),
|
||||||
|
(10028764573993088136, 221582786512044528),
|
||||||
|
(15401709288678291155, 177266229209635622),
|
||||||
|
(9885339602917624555, 283625966735416996),
|
||||||
|
(4218922867592189321, 226900773388333597),
|
||||||
|
(14443184738299482427, 181520618710666877),
|
||||||
|
(4175850161155765295, 145216494968533502),
|
||||||
|
(10370709072591134795, 232346391949653603),
|
||||||
|
(15675264887556728482, 185877113559722882),
|
||||||
|
(5161514280561562140, 148701690847778306),
|
||||||
|
(879725219414678777, 237922705356445290),
|
||||||
|
(703780175531743021, 190338164285156232),
|
||||||
|
(11631070584651125387, 152270531428124985),
|
||||||
|
(162968861732249003, 243632850284999977),
|
||||||
|
(11198421533611530172, 194906280227999981),
|
||||||
|
(5269388412147313814, 155925024182399985),
|
||||||
|
(8431021459435702103, 249480038691839976),
|
||||||
|
(3055468352806651359, 199584030953471981),
|
||||||
|
(17201769941212962380, 159667224762777584),
|
||||||
|
(16454785461715008838, 255467559620444135),
|
||||||
|
(13163828369372007071, 204374047696355308),
|
||||||
|
(17909760324981426303, 163499238157084246),
|
||||||
|
(2830174816776909822, 261598781051334795),
|
||||||
|
(2264139853421527858, 209279024841067836),
|
||||||
|
(16568707141704863579, 167423219872854268),
|
||||||
|
(4373838538276319787, 267877151796566830),
|
||||||
|
(3499070830621055830, 214301721437253464),
|
||||||
|
(6488605479238754987, 171441377149802771),
|
||||||
|
(3003071137298187333, 274306203439684434),
|
||||||
|
(6091805724580460189, 219444962751747547),
|
||||||
|
(15941491023890099121, 175555970201398037),
|
||||||
|
(10748990379256517301, 280889552322236860),
|
||||||
|
(8599192303405213841, 224711641857789488),
|
||||||
|
(14258051472207991719, 179769313486231590),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static DOUBLE_POW5_SPLIT: [(u64, u64); 326] = [
|
||||||
|
(0, 72057594037927936),
|
||||||
|
(0, 90071992547409920),
|
||||||
|
(0, 112589990684262400),
|
||||||
|
(0, 140737488355328000),
|
||||||
|
(0, 87960930222080000),
|
||||||
|
(0, 109951162777600000),
|
||||||
|
(0, 137438953472000000),
|
||||||
|
(0, 85899345920000000),
|
||||||
|
(0, 107374182400000000),
|
||||||
|
(0, 134217728000000000),
|
||||||
|
(0, 83886080000000000),
|
||||||
|
(0, 104857600000000000),
|
||||||
|
(0, 131072000000000000),
|
||||||
|
(0, 81920000000000000),
|
||||||
|
(0, 102400000000000000),
|
||||||
|
(0, 128000000000000000),
|
||||||
|
(0, 80000000000000000),
|
||||||
|
(0, 100000000000000000),
|
||||||
|
(0, 125000000000000000),
|
||||||
|
(0, 78125000000000000),
|
||||||
|
(0, 97656250000000000),
|
||||||
|
(0, 122070312500000000),
|
||||||
|
(0, 76293945312500000),
|
||||||
|
(0, 95367431640625000),
|
||||||
|
(0, 119209289550781250),
|
||||||
|
(4611686018427387904, 74505805969238281),
|
||||||
|
(10376293541461622784, 93132257461547851),
|
||||||
|
(8358680908399640576, 116415321826934814),
|
||||||
|
(612489549322387456, 72759576141834259),
|
||||||
|
(14600669991935148032, 90949470177292823),
|
||||||
|
(13639151471491547136, 113686837721616029),
|
||||||
|
(3213881284082270208, 142108547152020037),
|
||||||
|
(4314518811765112832, 88817841970012523),
|
||||||
|
(781462496279003136, 111022302462515654),
|
||||||
|
(10200200157203529728, 138777878078144567),
|
||||||
|
(13292654125893287936, 86736173798840354),
|
||||||
|
(7392445620511834112, 108420217248550443),
|
||||||
|
(4628871007212404736, 135525271560688054),
|
||||||
|
(16728102434789916672, 84703294725430033),
|
||||||
|
(7075069988205232128, 105879118406787542),
|
||||||
|
(18067209522111315968, 132348898008484427),
|
||||||
|
(8986162942105878528, 82718061255302767),
|
||||||
|
(6621017659204960256, 103397576569128459),
|
||||||
|
(3664586055578812416, 129246970711410574),
|
||||||
|
(16125424340018921472, 80779356694631608),
|
||||||
|
(1710036351314100224, 100974195868289511),
|
||||||
|
(15972603494424788992, 126217744835361888),
|
||||||
|
(9982877184015493120, 78886090522101180),
|
||||||
|
(12478596480019366400, 98607613152626475),
|
||||||
|
(10986559581596820096, 123259516440783094),
|
||||||
|
(2254913720070624656, 77037197775489434),
|
||||||
|
(12042014186943056628, 96296497219361792),
|
||||||
|
(15052517733678820785, 120370621524202240),
|
||||||
|
(9407823583549262990, 75231638452626400),
|
||||||
|
(11759779479436578738, 94039548065783000),
|
||||||
|
(14699724349295723422, 117549435082228750),
|
||||||
|
(4575641699882439235, 73468396926392969),
|
||||||
|
(10331238143280436948, 91835496157991211),
|
||||||
|
(8302361660673158281, 114794370197489014),
|
||||||
|
(1154580038986672043, 143492962746861268),
|
||||||
|
(9944984561221445835, 89683101716788292),
|
||||||
|
(12431230701526807293, 112103877145985365),
|
||||||
|
(1703980321626345405, 140129846432481707),
|
||||||
|
(17205888765512323542, 87581154020301066),
|
||||||
|
(12283988920035628619, 109476442525376333),
|
||||||
|
(1519928094762372062, 136845553156720417),
|
||||||
|
(12479170105294952299, 85528470722950260),
|
||||||
|
(15598962631618690374, 106910588403687825),
|
||||||
|
(5663645234241199255, 133638235504609782),
|
||||||
|
(17374836326682913246, 83523897190381113),
|
||||||
|
(7883487353071477846, 104404871487976392),
|
||||||
|
(9854359191339347308, 130506089359970490),
|
||||||
|
(10770660513014479971, 81566305849981556),
|
||||||
|
(13463325641268099964, 101957882312476945),
|
||||||
|
(2994098996302961243, 127447352890596182),
|
||||||
|
(15706369927971514489, 79654595556622613),
|
||||||
|
(5797904354682229399, 99568244445778267),
|
||||||
|
(2635694424925398845, 124460305557222834),
|
||||||
|
(6258995034005762182, 77787690973264271),
|
||||||
|
(3212057774079814824, 97234613716580339),
|
||||||
|
(17850130272881932242, 121543267145725423),
|
||||||
|
(18073860448192289507, 75964541966078389),
|
||||||
|
(8757267504958198172, 94955677457597987),
|
||||||
|
(6334898362770359811, 118694596821997484),
|
||||||
|
(13182683513586250689, 74184123013748427),
|
||||||
|
(11866668373555425458, 92730153767185534),
|
||||||
|
(5609963430089506015, 115912692208981918),
|
||||||
|
(17341285199088104971, 72445432630613698),
|
||||||
|
(12453234462005355406, 90556790788267123),
|
||||||
|
(10954857059079306353, 113195988485333904),
|
||||||
|
(13693571323849132942, 141494985606667380),
|
||||||
|
(17781854114260483896, 88434366004167112),
|
||||||
|
(3780573569116053255, 110542957505208891),
|
||||||
|
(114030942967678664, 138178696881511114),
|
||||||
|
(4682955357782187069, 86361685550944446),
|
||||||
|
(15077066234082509644, 107952106938680557),
|
||||||
|
(5011274737320973344, 134940133673350697),
|
||||||
|
(14661261756894078100, 84337583545844185),
|
||||||
|
(4491519140835433913, 105421979432305232),
|
||||||
|
(5614398926044292391, 131777474290381540),
|
||||||
|
(12732371365632458552, 82360921431488462),
|
||||||
|
(6692092170185797382, 102951151789360578),
|
||||||
|
(17588487249587022536, 128688939736700722),
|
||||||
|
(15604490549419276989, 80430587335437951),
|
||||||
|
(14893927168346708332, 100538234169297439),
|
||||||
|
(14005722942005997511, 125672792711621799),
|
||||||
|
(15671105866394830300, 78545495444763624),
|
||||||
|
(1142138259283986260, 98181869305954531),
|
||||||
|
(15262730879387146537, 122727336632443163),
|
||||||
|
(7233363790403272633, 76704585395276977),
|
||||||
|
(13653390756431478696, 95880731744096221),
|
||||||
|
(3231680390257184658, 119850914680120277),
|
||||||
|
(4325643253124434363, 74906821675075173),
|
||||||
|
(10018740084832930858, 93633527093843966),
|
||||||
|
(3300053069186387764, 117041908867304958),
|
||||||
|
(15897591223523656064, 73151193042065598),
|
||||||
|
(10648616992549794273, 91438991302581998),
|
||||||
|
(4087399203832467033, 114298739128227498),
|
||||||
|
(14332621041645359599, 142873423910284372),
|
||||||
|
(18181260187883125557, 89295889943927732),
|
||||||
|
(4279831161144355331, 111619862429909666),
|
||||||
|
(14573160988285219972, 139524828037387082),
|
||||||
|
(13719911636105650386, 87203017523366926),
|
||||||
|
(7926517508277287175, 109003771904208658),
|
||||||
|
(684774848491833161, 136254714880260823),
|
||||||
|
(7345513307948477581, 85159196800163014),
|
||||||
|
(18405263671790372785, 106448996000203767),
|
||||||
|
(18394893571310578077, 133061245000254709),
|
||||||
|
(13802651491282805250, 83163278125159193),
|
||||||
|
(3418256308821342851, 103954097656448992),
|
||||||
|
(4272820386026678563, 129942622070561240),
|
||||||
|
(2670512741266674102, 81214138794100775),
|
||||||
|
(17173198981865506339, 101517673492625968),
|
||||||
|
(3019754653622331308, 126897091865782461),
|
||||||
|
(4193189667727651020, 79310682416114038),
|
||||||
|
(14464859121514339583, 99138353020142547),
|
||||||
|
(13469387883465536574, 123922941275178184),
|
||||||
|
(8418367427165960359, 77451838296986365),
|
||||||
|
(15134645302384838353, 96814797871232956),
|
||||||
|
(471562554271496325, 121018497339041196),
|
||||||
|
(9518098633274461011, 75636560836900747),
|
||||||
|
(7285937273165688360, 94545701046125934),
|
||||||
|
(18330793628311886258, 118182126307657417),
|
||||||
|
(4539216990053847055, 73863828942285886),
|
||||||
|
(14897393274422084627, 92329786177857357),
|
||||||
|
(4786683537745442072, 115412232722321697),
|
||||||
|
(14520892257159371055, 72132645451451060),
|
||||||
|
(18151115321449213818, 90165806814313825),
|
||||||
|
(8853836096529353561, 112707258517892282),
|
||||||
|
(1843923083806916143, 140884073147365353),
|
||||||
|
(12681666973447792349, 88052545717103345),
|
||||||
|
(2017025661527576725, 110065682146379182),
|
||||||
|
(11744654113764246714, 137582102682973977),
|
||||||
|
(422879793461572340, 85988814176858736),
|
||||||
|
(528599741826965425, 107486017721073420),
|
||||||
|
(660749677283706782, 134357522151341775),
|
||||||
|
(7330497575943398595, 83973451344588609),
|
||||||
|
(13774807988356636147, 104966814180735761),
|
||||||
|
(3383451930163631472, 131208517725919702),
|
||||||
|
(15949715511634433382, 82005323578699813),
|
||||||
|
(6102086334260878016, 102506654473374767),
|
||||||
|
(3015921899398709616, 128133318091718459),
|
||||||
|
(18025852251620051174, 80083323807324036),
|
||||||
|
(4085571240815512351, 100104154759155046),
|
||||||
|
(14330336087874166247, 125130193448943807),
|
||||||
|
(15873989082562435760, 78206370905589879),
|
||||||
|
(15230800334775656796, 97757963631987349),
|
||||||
|
(5203442363187407284, 122197454539984187),
|
||||||
|
(946308467778435600, 76373409087490117),
|
||||||
|
(5794571603150432404, 95466761359362646),
|
||||||
|
(16466586540792816313, 119333451699203307),
|
||||||
|
(7985773578781816244, 74583407312002067),
|
||||||
|
(5370530955049882401, 93229259140002584),
|
||||||
|
(6713163693812353001, 116536573925003230),
|
||||||
|
(18030785363914884337, 72835358703127018),
|
||||||
|
(13315109668038829614, 91044198378908773),
|
||||||
|
(2808829029766373305, 113805247973635967),
|
||||||
|
(17346094342490130344, 142256559967044958),
|
||||||
|
(6229622945628943561, 88910349979403099),
|
||||||
|
(3175342663608791547, 111137937474253874),
|
||||||
|
(13192550366365765242, 138922421842817342),
|
||||||
|
(3633657960551215372, 86826513651760839),
|
||||||
|
(18377130505971182927, 108533142064701048),
|
||||||
|
(4524669058754427043, 135666427580876311),
|
||||||
|
(9745447189362598758, 84791517238047694),
|
||||||
|
(2958436949848472639, 105989396547559618),
|
||||||
|
(12921418224165366607, 132486745684449522),
|
||||||
|
(12687572408530742033, 82804216052780951),
|
||||||
|
(11247779492236039638, 103505270065976189),
|
||||||
|
(224666310012885835, 129381587582470237),
|
||||||
|
(2446259452971747599, 80863492239043898),
|
||||||
|
(12281196353069460307, 101079365298804872),
|
||||||
|
(15351495441336825384, 126349206623506090),
|
||||||
|
(14206370669262903769, 78968254139691306),
|
||||||
|
(8534591299723853903, 98710317674614133),
|
||||||
|
(15279925143082205283, 123387897093267666),
|
||||||
|
(14161639232853766206, 77117435683292291),
|
||||||
|
(13090363022639819853, 96396794604115364),
|
||||||
|
(16362953778299774816, 120495993255144205),
|
||||||
|
(12532689120651053212, 75309995784465128),
|
||||||
|
(15665861400813816515, 94137494730581410),
|
||||||
|
(10358954714162494836, 117671868413226763),
|
||||||
|
(4168503687137865320, 73544917758266727),
|
||||||
|
(598943590494943747, 91931147197833409),
|
||||||
|
(5360365506546067587, 114913933997291761),
|
||||||
|
(11312142901609972388, 143642417496614701),
|
||||||
|
(9375932322719926695, 89776510935384188),
|
||||||
|
(11719915403399908368, 112220638669230235),
|
||||||
|
(10038208235822497557, 140275798336537794),
|
||||||
|
(10885566165816448877, 87672373960336121),
|
||||||
|
(18218643725697949000, 109590467450420151),
|
||||||
|
(18161618638695048346, 136988084313025189),
|
||||||
|
(13656854658398099168, 85617552695640743),
|
||||||
|
(12459382304570236056, 107021940869550929),
|
||||||
|
(1739169825430631358, 133777426086938662),
|
||||||
|
(14922039196176308311, 83610891304336663),
|
||||||
|
(14040862976792997485, 104513614130420829),
|
||||||
|
(3716020665709083144, 130642017663026037),
|
||||||
|
(4628355925281870917, 81651261039391273),
|
||||||
|
(10397130925029726550, 102064076299239091),
|
||||||
|
(8384727637859770284, 127580095374048864),
|
||||||
|
(5240454773662356427, 79737559608780540),
|
||||||
|
(6550568467077945534, 99671949510975675),
|
||||||
|
(3576524565420044014, 124589936888719594),
|
||||||
|
(6847013871814915412, 77868710555449746),
|
||||||
|
(17782139376623420074, 97335888194312182),
|
||||||
|
(13004302183924499284, 121669860242890228),
|
||||||
|
(17351060901807587860, 76043662651806392),
|
||||||
|
(3242082053549933210, 95054578314757991),
|
||||||
|
(17887660622219580224, 118818222893447488),
|
||||||
|
(11179787888887237640, 74261389308404680),
|
||||||
|
(13974734861109047050, 92826736635505850),
|
||||||
|
(8245046539531533005, 116033420794382313),
|
||||||
|
(16682369133275677888, 72520887996488945),
|
||||||
|
(7017903361312433648, 90651109995611182),
|
||||||
|
(17995751238495317868, 113313887494513977),
|
||||||
|
(8659630992836983623, 141642359368142472),
|
||||||
|
(5412269370523114764, 88526474605089045),
|
||||||
|
(11377022731581281359, 110658093256361306),
|
||||||
|
(4997906377621825891, 138322616570451633),
|
||||||
|
(14652906532082110942, 86451635356532270),
|
||||||
|
(9092761128247862869, 108064544195665338),
|
||||||
|
(2142579373455052779, 135080680244581673),
|
||||||
|
(12868327154477877747, 84425425152863545),
|
||||||
|
(2250350887815183471, 105531781441079432),
|
||||||
|
(2812938609768979339, 131914726801349290),
|
||||||
|
(6369772649532999991, 82446704250843306),
|
||||||
|
(17185587848771025797, 103058380313554132),
|
||||||
|
(3035240737254230630, 128822975391942666),
|
||||||
|
(6508711479211282048, 80514359619964166),
|
||||||
|
(17359261385868878368, 100642949524955207),
|
||||||
|
(17087390713908710056, 125803686906194009),
|
||||||
|
(3762090168551861929, 78627304316371256),
|
||||||
|
(4702612710689827411, 98284130395464070),
|
||||||
|
(15101637925217060072, 122855162994330087),
|
||||||
|
(16356052730901744401, 76784476871456304),
|
||||||
|
(1998321839917628885, 95980596089320381),
|
||||||
|
(7109588318324424010, 119975745111650476),
|
||||||
|
(13666864735807540814, 74984840694781547),
|
||||||
|
(12471894901332038114, 93731050868476934),
|
||||||
|
(6366496589810271835, 117163813585596168),
|
||||||
|
(3979060368631419896, 73227383490997605),
|
||||||
|
(9585511479216662775, 91534229363747006),
|
||||||
|
(2758517312166052660, 114417786704683758),
|
||||||
|
(12671518677062341634, 143022233380854697),
|
||||||
|
(1002170145522881665, 89388895863034186),
|
||||||
|
(10476084718758377889, 111736119828792732),
|
||||||
|
(13095105898447972362, 139670149785990915),
|
||||||
|
(5878598177316288774, 87293843616244322),
|
||||||
|
(16571619758500136775, 109117304520305402),
|
||||||
|
(11491152661270395161, 136396630650381753),
|
||||||
|
(264441385652915120, 85247894156488596),
|
||||||
|
(330551732066143900, 106559867695610745),
|
||||||
|
(5024875683510067779, 133199834619513431),
|
||||||
|
(10058076329834874218, 83249896637195894),
|
||||||
|
(3349223375438816964, 104062370796494868),
|
||||||
|
(4186529219298521205, 130077963495618585),
|
||||||
|
(14145795808130045513, 81298727184761615),
|
||||||
|
(13070558741735168987, 101623408980952019),
|
||||||
|
(11726512408741573330, 127029261226190024),
|
||||||
|
(7329070255463483331, 79393288266368765),
|
||||||
|
(13773023837756742068, 99241610332960956),
|
||||||
|
(17216279797195927585, 124052012916201195),
|
||||||
|
(8454331864033760789, 77532508072625747),
|
||||||
|
(5956228811614813082, 96915635090782184),
|
||||||
|
(7445286014518516353, 121144543863477730),
|
||||||
|
(9264989777501460624, 75715339914673581),
|
||||||
|
(16192923240304213684, 94644174893341976),
|
||||||
|
(1794409976670715490, 118305218616677471),
|
||||||
|
(8039035263060279037, 73940761635423419),
|
||||||
|
(5437108060397960892, 92425952044279274),
|
||||||
|
(16019757112352226923, 115532440055349092),
|
||||||
|
(788976158365366019, 72207775034593183),
|
||||||
|
(14821278253238871236, 90259718793241478),
|
||||||
|
(9303225779693813237, 112824648491551848),
|
||||||
|
(11629032224617266546, 141030810614439810),
|
||||||
|
(11879831158813179495, 88144256634024881),
|
||||||
|
(1014730893234310657, 110180320792531102),
|
||||||
|
(10491785653397664129, 137725400990663877),
|
||||||
|
(8863209042587234033, 86078375619164923),
|
||||||
|
(6467325284806654637, 107597969523956154),
|
||||||
|
(17307528642863094104, 134497461904945192),
|
||||||
|
(10817205401789433815, 84060913690590745),
|
||||||
|
(18133192770664180173, 105076142113238431),
|
||||||
|
(18054804944902837312, 131345177641548039),
|
||||||
|
(18201782118205355176, 82090736025967524),
|
||||||
|
(4305483574047142354, 102613420032459406),
|
||||||
|
(14605226504413703751, 128266775040574257),
|
||||||
|
(2210737537617482988, 80166734400358911),
|
||||||
|
(16598479977304017447, 100208418000448638),
|
||||||
|
(11524727934775246001, 125260522500560798),
|
||||||
|
(2591268940807140847, 78287826562850499),
|
||||||
|
(17074144231291089770, 97859783203563123),
|
||||||
|
(16730994270686474309, 122324729004453904),
|
||||||
|
(10456871419179046443, 76452955627783690),
|
||||||
|
(3847717237119032246, 95566194534729613),
|
||||||
|
(9421332564826178211, 119457743168412016),
|
||||||
|
(5888332853016361382, 74661089480257510),
|
||||||
|
(16583788103125227536, 93326361850321887),
|
||||||
|
(16118049110479146516, 116657952312902359),
|
||||||
|
(16991309721690548428, 72911220195563974),
|
||||||
|
(12015765115258409727, 91139025244454968),
|
||||||
|
(15019706394073012159, 113923781555568710),
|
||||||
|
(9551260955736489391, 142404726944460888),
|
||||||
|
(5969538097335305869, 89002954340288055),
|
||||||
|
(2850236603241744433, 111253692925360069),
|
||||||
|
];
|
206
third_party/rust/ryu/src/d2s_small_table.rs
vendored
Normal file
206
third_party/rust/ryu/src/d2s_small_table.rs
vendored
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
use common::*;
|
||||||
|
#[cfg(not(integer128))]
|
||||||
|
use mulshift128::*;
|
||||||
|
|
||||||
|
pub static DOUBLE_POW5_TABLE: [u64; 26] = [
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
25,
|
||||||
|
125,
|
||||||
|
625,
|
||||||
|
3125,
|
||||||
|
15625,
|
||||||
|
78125,
|
||||||
|
390625,
|
||||||
|
1953125,
|
||||||
|
9765625,
|
||||||
|
48828125,
|
||||||
|
244140625,
|
||||||
|
1220703125,
|
||||||
|
6103515625,
|
||||||
|
30517578125,
|
||||||
|
152587890625,
|
||||||
|
762939453125,
|
||||||
|
3814697265625,
|
||||||
|
19073486328125,
|
||||||
|
95367431640625,
|
||||||
|
476837158203125,
|
||||||
|
2384185791015625,
|
||||||
|
11920928955078125,
|
||||||
|
59604644775390625,
|
||||||
|
298023223876953125,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static DOUBLE_POW5_SPLIT2: [(u64, u64); 13] = [
|
||||||
|
(0, 72057594037927936),
|
||||||
|
(10376293541461622784, 93132257461547851),
|
||||||
|
(15052517733678820785, 120370621524202240),
|
||||||
|
(6258995034005762182, 77787690973264271),
|
||||||
|
(14893927168346708332, 100538234169297439),
|
||||||
|
(4272820386026678563, 129942622070561240),
|
||||||
|
(7330497575943398595, 83973451344588609),
|
||||||
|
(18377130505971182927, 108533142064701048),
|
||||||
|
(10038208235822497557, 140275798336537794),
|
||||||
|
(7017903361312433648, 90651109995611182),
|
||||||
|
(6366496589810271835, 117163813585596168),
|
||||||
|
(9264989777501460624, 75715339914673581),
|
||||||
|
(17074144231291089770, 97859783203563123),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Unfortunately, the results are sometimes off by one. We use an additional
|
||||||
|
// lookup table to store those cases and adjust the result.
|
||||||
|
pub static POW5_OFFSETS: [u32; 13] = [
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x033c55be, 0x03db77d8, 0x0265ffb2, 0x00000800, 0x01a8ff56,
|
||||||
|
0x00000000, 0x0037a200, 0x00004000, 0x03fffffc, 0x00003ffe,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 13] = [
|
||||||
|
(1, 288230376151711744),
|
||||||
|
(7661987648932456967, 223007451985306231),
|
||||||
|
(12652048002903177473, 172543658669764094),
|
||||||
|
(5522544058086115566, 266998379490113760),
|
||||||
|
(3181575136763469022, 206579990246952687),
|
||||||
|
(4551508647133041040, 159833525776178802),
|
||||||
|
(1116074521063664381, 247330401473104534),
|
||||||
|
(17400360011128145022, 191362629322552438),
|
||||||
|
(9297997190148906106, 148059663038321393),
|
||||||
|
(11720143854957885429, 229111231347799689),
|
||||||
|
(15401709288678291155, 177266229209635622),
|
||||||
|
(3003071137298187333, 274306203439684434),
|
||||||
|
(17516772882021341108, 212234145163966538),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static POW5_INV_OFFSETS: [u32; 20] = [
|
||||||
|
0x51505404, 0x55054514, 0x45555545, 0x05511411, 0x00505010, 0x00000004, 0x00000000, 0x00000000,
|
||||||
|
0x55555040, 0x00505051, 0x00050040, 0x55554000, 0x51659559, 0x00001000, 0x15000010, 0x55455555,
|
||||||
|
0x41404051, 0x00001010, 0x00000014, 0x00000000,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Computes 5^i in the form required by Ryu.
|
||||||
|
#[cfg(integer128)]
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn compute_pow5(i: u32) -> (u64, u64) {
|
||||||
|
let base = i / DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let base2 = base * DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let offset = i - base2;
|
||||||
|
debug_assert!(base < DOUBLE_POW5_SPLIT2.len() as u32);
|
||||||
|
let mul = *DOUBLE_POW5_SPLIT2.get_unchecked(base as usize);
|
||||||
|
if offset == 0 {
|
||||||
|
return mul;
|
||||||
|
}
|
||||||
|
debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32);
|
||||||
|
let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize);
|
||||||
|
let b0 = m as u128 * mul.0 as u128;
|
||||||
|
let b2 = m as u128 * mul.1 as u128;
|
||||||
|
let delta = pow5bits(i as i32) - pow5bits(base2 as i32);
|
||||||
|
debug_assert!(base < POW5_OFFSETS.len() as u32);
|
||||||
|
let shifted_sum = (b0 >> delta)
|
||||||
|
+ (b2 << (64 - delta))
|
||||||
|
+ ((*POW5_OFFSETS.get_unchecked(base as usize) >> offset) & 1) as u128;
|
||||||
|
(shifted_sum as u64, (shifted_sum >> 64) as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes 5^-i in the form required by Ryu.
|
||||||
|
#[cfg(integer128)]
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) {
|
||||||
|
let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let base2 = base * DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let offset = base2 - i;
|
||||||
|
debug_assert!(base < DOUBLE_POW5_INV_SPLIT2.len() as u32);
|
||||||
|
let mul = *DOUBLE_POW5_INV_SPLIT2.get_unchecked(base as usize); // 1/5^base2
|
||||||
|
if offset == 0 {
|
||||||
|
return mul;
|
||||||
|
}
|
||||||
|
debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32);
|
||||||
|
let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); // 5^offset
|
||||||
|
let b0 = m as u128 * (mul.0 - 1) as u128;
|
||||||
|
let b2 = m as u128 * mul.1 as u128; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i
|
||||||
|
let delta = pow5bits(base2 as i32) - pow5bits(i as i32);
|
||||||
|
debug_assert!(base < POW5_INV_OFFSETS.len() as u32);
|
||||||
|
let shifted_sum = ((b0 >> delta) + (b2 << (64 - delta)))
|
||||||
|
+ 1
|
||||||
|
+ ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u128;
|
||||||
|
(shifted_sum as u64, (shifted_sum >> 64) as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes 5^i in the form required by Ryu, and stores it in the given pointer.
|
||||||
|
#[cfg(not(integer128))]
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn compute_pow5(i: u32) -> (u64, u64) {
|
||||||
|
let base = i / DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let base2 = base * DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let offset = i - base2;
|
||||||
|
debug_assert!(base < DOUBLE_POW5_SPLIT2.len() as u32);
|
||||||
|
let mul = *DOUBLE_POW5_SPLIT2.get_unchecked(base as usize);
|
||||||
|
if offset == 0 {
|
||||||
|
return mul;
|
||||||
|
}
|
||||||
|
debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32);
|
||||||
|
let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize);
|
||||||
|
let (low1, mut high1) = umul128(m, mul.1);
|
||||||
|
let (low0, high0) = umul128(m, mul.0);
|
||||||
|
let sum = high0 + low1;
|
||||||
|
if sum < high0 {
|
||||||
|
high1 += 1; // overflow into high1
|
||||||
|
}
|
||||||
|
// high1 | sum | low0
|
||||||
|
let delta = pow5bits(i as i32) - pow5bits(base2 as i32);
|
||||||
|
debug_assert!(base < POW5_OFFSETS.len() as u32);
|
||||||
|
(
|
||||||
|
shiftright128(low0, sum, delta)
|
||||||
|
+ ((*POW5_OFFSETS.get_unchecked(base as usize) >> offset) & 1) as u64,
|
||||||
|
shiftright128(sum, high1, delta),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes 5^-i in the form required by Ryu, and stores it in the given pointer.
|
||||||
|
#[cfg(not(integer128))]
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) {
|
||||||
|
let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let base2 = base * DOUBLE_POW5_TABLE.len() as u32;
|
||||||
|
let offset = base2 - i;
|
||||||
|
debug_assert!(base < DOUBLE_POW5_INV_SPLIT2.len() as u32);
|
||||||
|
let mul = *DOUBLE_POW5_INV_SPLIT2.get_unchecked(base as usize); // 1/5^base2
|
||||||
|
if offset == 0 {
|
||||||
|
return mul;
|
||||||
|
}
|
||||||
|
debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32);
|
||||||
|
let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize);
|
||||||
|
let (low1, mut high1) = umul128(m, mul.1);
|
||||||
|
let (low0, high0) = umul128(m, mul.0 - 1);
|
||||||
|
let sum = high0 + low1;
|
||||||
|
if sum < high0 {
|
||||||
|
high1 += 1; // overflow into high1
|
||||||
|
}
|
||||||
|
// high1 | sum | low0
|
||||||
|
let delta = pow5bits(base2 as i32) - pow5bits(i as i32);
|
||||||
|
debug_assert!(base < POW5_INV_OFFSETS.len() as u32);
|
||||||
|
(
|
||||||
|
shiftright128(low0, sum, delta)
|
||||||
|
+ 1
|
||||||
|
+ ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u64,
|
||||||
|
shiftright128(sum, high1, delta),
|
||||||
|
)
|
||||||
|
}
|
28
third_party/rust/ryu/src/digit_table.rs
vendored
Normal file
28
third_party/rust/ryu/src/digit_table.rs
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
// A table of all two-digit numbers. This is used to speed up decimal digit
|
||||||
|
// generation by copying pairs of digits into the final output.
|
||||||
|
pub static DIGIT_TABLE: [u8; 200] = *b"\
|
||||||
|
0001020304050607080910111213141516171819\
|
||||||
|
2021222324252627282930313233343536373839\
|
||||||
|
4041424344454647484950515253545556575859\
|
||||||
|
6061626364656667686970717273747576777879\
|
||||||
|
8081828384858687888990919293949596979899";
|
494
third_party/rust/ryu/src/f2s.rs
vendored
Normal file
494
third_party/rust/ryu/src/f2s.rs
vendored
Normal file
@ -0,0 +1,494 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
use core::{mem, ptr};
|
||||||
|
|
||||||
|
use common::*;
|
||||||
|
use digit_table::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "no-panic")]
|
||||||
|
use no_panic::no_panic;
|
||||||
|
|
||||||
|
pub const FLOAT_MANTISSA_BITS: u32 = 23;
|
||||||
|
pub const FLOAT_EXPONENT_BITS: u32 = 8;
|
||||||
|
|
||||||
|
const FLOAT_POW5_INV_BITCOUNT: i32 = 59;
|
||||||
|
const FLOAT_POW5_BITCOUNT: i32 = 61;
|
||||||
|
|
||||||
|
// This table is generated by PrintFloatLookupTable.
|
||||||
|
static FLOAT_POW5_INV_SPLIT: [u64; 32] = [
|
||||||
|
576460752303423489,
|
||||||
|
461168601842738791,
|
||||||
|
368934881474191033,
|
||||||
|
295147905179352826,
|
||||||
|
472236648286964522,
|
||||||
|
377789318629571618,
|
||||||
|
302231454903657294,
|
||||||
|
483570327845851670,
|
||||||
|
386856262276681336,
|
||||||
|
309485009821345069,
|
||||||
|
495176015714152110,
|
||||||
|
396140812571321688,
|
||||||
|
316912650057057351,
|
||||||
|
507060240091291761,
|
||||||
|
405648192073033409,
|
||||||
|
324518553658426727,
|
||||||
|
519229685853482763,
|
||||||
|
415383748682786211,
|
||||||
|
332306998946228969,
|
||||||
|
531691198313966350,
|
||||||
|
425352958651173080,
|
||||||
|
340282366920938464,
|
||||||
|
544451787073501542,
|
||||||
|
435561429658801234,
|
||||||
|
348449143727040987,
|
||||||
|
557518629963265579,
|
||||||
|
446014903970612463,
|
||||||
|
356811923176489971,
|
||||||
|
570899077082383953,
|
||||||
|
456719261665907162,
|
||||||
|
365375409332725730,
|
||||||
|
1 << 63,
|
||||||
|
];
|
||||||
|
|
||||||
|
static FLOAT_POW5_SPLIT: [u64; 47] = [
|
||||||
|
1152921504606846976,
|
||||||
|
1441151880758558720,
|
||||||
|
1801439850948198400,
|
||||||
|
2251799813685248000,
|
||||||
|
1407374883553280000,
|
||||||
|
1759218604441600000,
|
||||||
|
2199023255552000000,
|
||||||
|
1374389534720000000,
|
||||||
|
1717986918400000000,
|
||||||
|
2147483648000000000,
|
||||||
|
1342177280000000000,
|
||||||
|
1677721600000000000,
|
||||||
|
2097152000000000000,
|
||||||
|
1310720000000000000,
|
||||||
|
1638400000000000000,
|
||||||
|
2048000000000000000,
|
||||||
|
1280000000000000000,
|
||||||
|
1600000000000000000,
|
||||||
|
2000000000000000000,
|
||||||
|
1250000000000000000,
|
||||||
|
1562500000000000000,
|
||||||
|
1953125000000000000,
|
||||||
|
1220703125000000000,
|
||||||
|
1525878906250000000,
|
||||||
|
1907348632812500000,
|
||||||
|
1192092895507812500,
|
||||||
|
1490116119384765625,
|
||||||
|
1862645149230957031,
|
||||||
|
1164153218269348144,
|
||||||
|
1455191522836685180,
|
||||||
|
1818989403545856475,
|
||||||
|
2273736754432320594,
|
||||||
|
1421085471520200371,
|
||||||
|
1776356839400250464,
|
||||||
|
2220446049250313080,
|
||||||
|
1387778780781445675,
|
||||||
|
1734723475976807094,
|
||||||
|
2168404344971008868,
|
||||||
|
1355252715606880542,
|
||||||
|
1694065894508600678,
|
||||||
|
2117582368135750847,
|
||||||
|
1323488980084844279,
|
||||||
|
1654361225106055349,
|
||||||
|
2067951531382569187,
|
||||||
|
1292469707114105741,
|
||||||
|
1615587133892632177,
|
||||||
|
2019483917365790221,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn pow5_factor(mut value: u32) -> u32 {
|
||||||
|
let mut count = 0u32;
|
||||||
|
loop {
|
||||||
|
debug_assert!(value != 0);
|
||||||
|
let q = value / 5;
|
||||||
|
let r = value % 5;
|
||||||
|
if r != 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = q;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if value is divisible by 5^p.
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn multiple_of_power_of_5(value: u32, p: u32) -> bool {
|
||||||
|
pow5_factor(value) >= p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if value is divisible by 2^p.
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn multiple_of_power_of_2(value: u32, p: u32) -> bool {
|
||||||
|
// return __builtin_ctz(value) >= p;
|
||||||
|
(value & ((1u32 << p) - 1)) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// It seems to be slightly faster to avoid uint128_t here, although the
|
||||||
|
// generated code for uint128_t looks slightly nicer.
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn mul_shift(m: u32, factor: u64, shift: i32) -> u32 {
|
||||||
|
debug_assert!(shift > 32);
|
||||||
|
|
||||||
|
// The casts here help MSVC to avoid calls to the __allmul library
|
||||||
|
// function.
|
||||||
|
let factor_lo = factor as u32;
|
||||||
|
let factor_hi = (factor >> 32) as u32;
|
||||||
|
let bits0 = m as u64 * factor_lo as u64;
|
||||||
|
let bits1 = m as u64 * factor_hi as u64;
|
||||||
|
|
||||||
|
let sum = (bits0 >> 32) + bits1;
|
||||||
|
let shifted_sum = sum >> (shift - 32);
|
||||||
|
debug_assert!(shifted_sum <= u32::max_value() as u64);
|
||||||
|
shifted_sum as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn mul_pow5_inv_div_pow2(m: u32, q: u32, j: i32) -> u32 {
|
||||||
|
debug_assert!(q < FLOAT_POW5_INV_SPLIT.len() as u32);
|
||||||
|
unsafe { mul_shift(m, *FLOAT_POW5_INV_SPLIT.get_unchecked(q as usize), j) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
fn mul_pow5_div_pow2(m: u32, i: u32, j: i32) -> u32 {
|
||||||
|
debug_assert!(i < FLOAT_POW5_SPLIT.len() as u32);
|
||||||
|
unsafe { mul_shift(m, *FLOAT_POW5_SPLIT.get_unchecked(i as usize), j) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn decimal_length(v: u32) -> u32 {
|
||||||
|
// Function precondition: v is not a 10-digit number.
|
||||||
|
// (9 digits are sufficient for round-tripping.)
|
||||||
|
debug_assert!(v < 1000000000);
|
||||||
|
|
||||||
|
if v >= 100000000 {
|
||||||
|
9
|
||||||
|
} else if v >= 10000000 {
|
||||||
|
8
|
||||||
|
} else if v >= 1000000 {
|
||||||
|
7
|
||||||
|
} else if v >= 100000 {
|
||||||
|
6
|
||||||
|
} else if v >= 10000 {
|
||||||
|
5
|
||||||
|
} else if v >= 1000 {
|
||||||
|
4
|
||||||
|
} else if v >= 100 {
|
||||||
|
3
|
||||||
|
} else if v >= 10 {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A floating decimal representing m * 10^e.
|
||||||
|
pub struct FloatingDecimal32 {
|
||||||
|
pub mantissa: u32,
|
||||||
|
pub exponent: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
|
||||||
|
let bias = (1u32 << (FLOAT_EXPONENT_BITS - 1)) - 1;
|
||||||
|
|
||||||
|
let (e2, m2) = if ieee_exponent == 0 {
|
||||||
|
(
|
||||||
|
// We subtract 2 so that the bounds computation has 2 additional bits.
|
||||||
|
1 - bias as i32 - FLOAT_MANTISSA_BITS as i32 - 2,
|
||||||
|
ieee_mantissa,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
ieee_exponent as i32 - bias as i32 - FLOAT_MANTISSA_BITS as i32 - 2,
|
||||||
|
(1u32 << FLOAT_MANTISSA_BITS) | ieee_mantissa,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let even = (m2 & 1) == 0;
|
||||||
|
let accept_bounds = even;
|
||||||
|
|
||||||
|
// Step 2: Determine the interval of legal decimal representations.
|
||||||
|
let mv = 4 * m2;
|
||||||
|
let mp = 4 * m2 + 2;
|
||||||
|
// Implicit bool -> int conversion. True is 1, false is 0.
|
||||||
|
let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32;
|
||||||
|
let mm = 4 * m2 - 1 - mm_shift;
|
||||||
|
|
||||||
|
// Step 3: Convert to a decimal power base using 64-bit arithmetic.
|
||||||
|
let mut vr: u32;
|
||||||
|
let mut vp: u32;
|
||||||
|
let mut vm: u32;
|
||||||
|
let e10: i32;
|
||||||
|
let mut vm_is_trailing_zeros = false;
|
||||||
|
let mut vr_is_trailing_zeros = false;
|
||||||
|
let mut last_removed_digit = 0u8;
|
||||||
|
if e2 >= 0 {
|
||||||
|
let q = log10_pow2(e2) as u32;
|
||||||
|
e10 = q as i32;
|
||||||
|
let k = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32) as i32 - 1;
|
||||||
|
let i = -e2 + q as i32 + k;
|
||||||
|
vr = mul_pow5_inv_div_pow2(mv, q, i);
|
||||||
|
vp = mul_pow5_inv_div_pow2(mp, q, i);
|
||||||
|
vm = mul_pow5_inv_div_pow2(mm, q, i);
|
||||||
|
if q != 0 && (vp - 1) / 10 <= vm / 10 {
|
||||||
|
// We need to know one removed digit even if we are not going to loop below. We could use
|
||||||
|
// q = X - 1 above, except that would require 33 bits for the result, and we've found that
|
||||||
|
// 32-bit arithmetic is faster even on 64-bit machines.
|
||||||
|
let l = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32 - 1) as i32 - 1;
|
||||||
|
last_removed_digit =
|
||||||
|
(mul_pow5_inv_div_pow2(mv, q - 1, -e2 + q as i32 - 1 + l) % 10) as u8;
|
||||||
|
}
|
||||||
|
if q <= 9 {
|
||||||
|
// The largest power of 5 that fits in 24 bits is 5^10, but q <= 9 seems to be safe as well.
|
||||||
|
// Only one of mp, mv, and mm can be a multiple of 5, if any.
|
||||||
|
if mv % 5 == 0 {
|
||||||
|
vr_is_trailing_zeros = multiple_of_power_of_5(mv, q);
|
||||||
|
} else if accept_bounds {
|
||||||
|
vm_is_trailing_zeros = multiple_of_power_of_5(mm, q);
|
||||||
|
} else {
|
||||||
|
vp -= multiple_of_power_of_5(mp, q) as u32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let q = log10_pow5(-e2) as u32;
|
||||||
|
e10 = q as i32 + e2;
|
||||||
|
let i = -e2 - q as i32;
|
||||||
|
let k = pow5bits(i) as i32 - FLOAT_POW5_BITCOUNT;
|
||||||
|
let mut j = q as i32 - k;
|
||||||
|
vr = mul_pow5_div_pow2(mv, i as u32, j);
|
||||||
|
vp = mul_pow5_div_pow2(mp, i as u32, j);
|
||||||
|
vm = mul_pow5_div_pow2(mm, i as u32, j);
|
||||||
|
if q != 0 && (vp - 1) / 10 <= vm / 10 {
|
||||||
|
j = q as i32 - 1 - (pow5bits(i + 1) as i32 - FLOAT_POW5_BITCOUNT);
|
||||||
|
last_removed_digit = (mul_pow5_div_pow2(mv, (i + 1) as u32, j) % 10) as u8;
|
||||||
|
}
|
||||||
|
if q <= 1 {
|
||||||
|
// {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
|
||||||
|
// mv = 4 * m2, so it always has at least two trailing 0 bits.
|
||||||
|
vr_is_trailing_zeros = true;
|
||||||
|
if accept_bounds {
|
||||||
|
// mm = mv - 1 - mm_shift, so it has 1 trailing 0 bit iff mm_shift == 1.
|
||||||
|
vm_is_trailing_zeros = mm_shift == 1;
|
||||||
|
} else {
|
||||||
|
// mp = mv + 2, so it always has at least one trailing 0 bit.
|
||||||
|
vp -= 1;
|
||||||
|
}
|
||||||
|
} else if q < 31 {
|
||||||
|
// TODO(ulfjack): Use a tighter bound here.
|
||||||
|
vr_is_trailing_zeros = multiple_of_power_of_2(mv, q - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Find the shortest decimal representation in the interval of legal representations.
|
||||||
|
let mut removed = 0u32;
|
||||||
|
let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
|
||||||
|
// General case, which happens rarely (~4.0%).
|
||||||
|
while vp / 10 > vm / 10 {
|
||||||
|
vm_is_trailing_zeros &= vm - (vm / 10) * 10 == 0;
|
||||||
|
vr_is_trailing_zeros &= last_removed_digit == 0;
|
||||||
|
last_removed_digit = (vr % 10) as u8;
|
||||||
|
vr /= 10;
|
||||||
|
vp /= 10;
|
||||||
|
vm /= 10;
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
if vm_is_trailing_zeros {
|
||||||
|
while vm % 10 == 0 {
|
||||||
|
vr_is_trailing_zeros &= last_removed_digit == 0;
|
||||||
|
last_removed_digit = (vr % 10) as u8;
|
||||||
|
vr /= 10;
|
||||||
|
vp /= 10;
|
||||||
|
vm /= 10;
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
|
||||||
|
// Round even if the exact number is .....50..0.
|
||||||
|
last_removed_digit = 4;
|
||||||
|
}
|
||||||
|
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||||
|
vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5)
|
||||||
|
as u32
|
||||||
|
} else {
|
||||||
|
// Specialized for the common case (~96.0%). Percentages below are relative to this.
|
||||||
|
// Loop iterations below (approximately):
|
||||||
|
// 0: 13.6%, 1: 70.7%, 2: 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01%
|
||||||
|
while vp / 10 > vm / 10 {
|
||||||
|
last_removed_digit = (vr % 10) as u8;
|
||||||
|
vr /= 10;
|
||||||
|
vp /= 10;
|
||||||
|
vm /= 10;
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||||
|
vr + (vr == vm || last_removed_digit >= 5) as u32
|
||||||
|
};
|
||||||
|
let exp = e10 + removed as i32;
|
||||||
|
|
||||||
|
FloatingDecimal32 {
|
||||||
|
exponent: exp,
|
||||||
|
mantissa: output,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
unsafe fn to_chars(v: FloatingDecimal32, sign: bool, result: *mut u8) -> usize {
|
||||||
|
// Step 5: Print the decimal representation.
|
||||||
|
let mut index = 0isize;
|
||||||
|
if sign {
|
||||||
|
*result.offset(index) = b'-';
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = v.mantissa;
|
||||||
|
let olength = decimal_length(output);
|
||||||
|
|
||||||
|
// Print the decimal digits.
|
||||||
|
// The following code is equivalent to:
|
||||||
|
// for (uint32_t i = 0; i < olength - 1; ++i) {
|
||||||
|
// const uint32_t c = output % 10; output /= 10;
|
||||||
|
// result[index + olength - i] = (char) ('0' + c);
|
||||||
|
// }
|
||||||
|
// result[index] = '0' + output % 10;
|
||||||
|
let mut i = 0isize;
|
||||||
|
while output >= 10000 {
|
||||||
|
let c = output - 10000 * (output / 10000);
|
||||||
|
output /= 10000;
|
||||||
|
let c0 = (c % 100) << 1;
|
||||||
|
let c1 = (c / 100) << 1;
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c0 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 1),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c1 as usize),
|
||||||
|
result.offset(index + olength as isize - i - 3),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
if output >= 100 {
|
||||||
|
let c = (output % 100) << 1;
|
||||||
|
output /= 100;
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked(c as usize),
|
||||||
|
result.offset(index + olength as isize - i - 1),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
if output >= 10 {
|
||||||
|
let c = output << 1;
|
||||||
|
// We can't use memcpy here: the decimal dot goes between these two digits.
|
||||||
|
*result.offset(index + olength as isize - i) = *DIGIT_TABLE.get_unchecked(c as usize + 1);
|
||||||
|
*result.offset(index) = *DIGIT_TABLE.get_unchecked(c as usize);
|
||||||
|
} else {
|
||||||
|
*result.offset(index) = b'0' + output as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print decimal point if needed.
|
||||||
|
if olength > 1 {
|
||||||
|
*result.offset(index + 1) = b'.';
|
||||||
|
index += olength as isize + 1;
|
||||||
|
} else {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the exponent.
|
||||||
|
*result.offset(index) = b'E';
|
||||||
|
index += 1;
|
||||||
|
let mut exp = v.exponent + olength as i32 - 1;
|
||||||
|
if exp < 0 {
|
||||||
|
*result.offset(index) = b'-';
|
||||||
|
index += 1;
|
||||||
|
exp = -exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp >= 10 {
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
DIGIT_TABLE.get_unchecked((2 * exp) as usize),
|
||||||
|
result.offset(index),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
index += 2;
|
||||||
|
} else {
|
||||||
|
*result.offset(index) = b'0' + exp as u8;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(index <= 15);
|
||||||
|
index as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print f32 to the given buffer and return number of bytes written.
|
||||||
|
///
|
||||||
|
/// At most 15 bytes will be written.
|
||||||
|
///
|
||||||
|
/// ## Special cases
|
||||||
|
///
|
||||||
|
/// This function represents any NaN as `NaN`, positive infinity as `Infinity`,
|
||||||
|
/// and negative infinity as `-Infinity`.
|
||||||
|
///
|
||||||
|
/// ## Safety
|
||||||
|
///
|
||||||
|
/// The `result` pointer argument must point to sufficiently many writable bytes
|
||||||
|
/// to hold Ryū's representation of `f`.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let f = 1.234f32;
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// let mut buffer: [u8; 15] = std::mem::uninitialized();
|
||||||
|
/// let n = ryu::raw::f2s_buffered_n(f, &mut buffer[0]);
|
||||||
|
/// let s = std::str::from_utf8_unchecked(&buffer[..n]);
|
||||||
|
/// assert_eq!(s, "1.234E0");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg_attr(must_use_return, must_use)]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub unsafe fn f2s_buffered_n(f: f32, result: *mut u8) -> usize {
|
||||||
|
// Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
|
||||||
|
let bits = mem::transmute::<f32, u32>(f);
|
||||||
|
|
||||||
|
// Decode bits into sign, mantissa, and exponent.
|
||||||
|
let ieee_sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
|
||||||
|
let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1);
|
||||||
|
let ieee_exponent =
|
||||||
|
((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32;
|
||||||
|
|
||||||
|
// Case distinction; exit early for the easy cases.
|
||||||
|
if ieee_exponent == ((1u32 << FLOAT_EXPONENT_BITS) - 1)
|
||||||
|
|| (ieee_exponent == 0 && ieee_mantissa == 0)
|
||||||
|
{
|
||||||
|
return copy_special_str(result, ieee_sign, ieee_exponent != 0, ieee_mantissa != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = f2d(ieee_mantissa, ieee_exponent);
|
||||||
|
to_chars(v, ieee_sign, result)
|
||||||
|
}
|
68
third_party/rust/ryu/src/lib.rs
vendored
Normal file
68
third_party/rust/ryu/src/lib.rs
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//! Pure Rust implementation of Ryū, an algorithm to quickly convert floating
|
||||||
|
//! point numbers to decimal strings.
|
||||||
|
//!
|
||||||
|
//! The PLDI'18 paper [*Ryū: fast float-to-string conversion*][paper] by Ulf
|
||||||
|
//! Adams includes a complete correctness proof of the algorithm. The paper is
|
||||||
|
//! available under the creative commons CC-BY-SA license.
|
||||||
|
//!
|
||||||
|
//! This Rust implementation is a line-by-line port of Ulf Adams' implementation
|
||||||
|
//! in C, [https://github.com/ulfjack/ryu][upstream]. The [`ryu::raw`][raw]
|
||||||
|
//! module exposes exactly the API and formatting of the C implementation as
|
||||||
|
//! unsafe pure Rust functions. There is additionally a safe API as demonstrated
|
||||||
|
//! in the example code below. The safe API uses the same underlying Ryū
|
||||||
|
//! algorithm but diverges from the formatting of the C implementation to
|
||||||
|
//! produce more human-readable output, for example `0.3` rather than `3E-1`.
|
||||||
|
//!
|
||||||
|
//! [paper]: https://dl.acm.org/citation.cfm?id=3192369
|
||||||
|
//! [upstream]: https://github.com/ulfjack/ryu
|
||||||
|
//! [raw]: raw/index.html
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! extern crate ryu;
|
||||||
|
//!
|
||||||
|
//! fn main() {
|
||||||
|
//! let mut buffer = ryu::Buffer::new();
|
||||||
|
//! let printed = buffer.format(1.234);
|
||||||
|
//! assert_eq!(printed, "1.234");
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![doc(html_root_url = "https://docs.rs/ryu/0.2.4")]
|
||||||
|
#![cfg_attr(feature = "no-panic", feature(use_extern_macros))]
|
||||||
|
#![cfg_attr(
|
||||||
|
feature = "cargo-clippy",
|
||||||
|
allow(
|
||||||
|
cast_lossless,
|
||||||
|
cyclomatic_complexity,
|
||||||
|
many_single_char_names,
|
||||||
|
needless_pass_by_value,
|
||||||
|
unreadable_literal,
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
|
||||||
|
#[cfg(feature = "no-panic")]
|
||||||
|
extern crate no_panic;
|
||||||
|
|
||||||
|
mod buffer;
|
||||||
|
mod common;
|
||||||
|
mod d2s;
|
||||||
|
#[cfg(not(feature = "small"))]
|
||||||
|
mod d2s_full_table;
|
||||||
|
#[cfg(feature = "small")]
|
||||||
|
mod d2s_small_table;
|
||||||
|
mod digit_table;
|
||||||
|
mod f2s;
|
||||||
|
#[cfg(not(integer128))]
|
||||||
|
mod mulshift128;
|
||||||
|
mod pretty;
|
||||||
|
|
||||||
|
pub use buffer::{Buffer, Float};
|
||||||
|
|
||||||
|
/// Unsafe functions that exactly mirror the API of the C implementation of Ryū.
|
||||||
|
pub mod raw {
|
||||||
|
pub use d2s::d2s_buffered_n;
|
||||||
|
pub use f2s::f2s_buffered_n;
|
||||||
|
}
|
57
third_party/rust/ryu/src/mulshift128.rs
vendored
Normal file
57
third_party/rust/ryu/src/mulshift128.rs
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
// Returns (lo, hi).
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn umul128(a: u64, b: u64) -> (u64, u64) {
|
||||||
|
let a_lo = a as u32;
|
||||||
|
let a_hi = (a >> 32) as u32;
|
||||||
|
let b_lo = b as u32;
|
||||||
|
let b_hi = (b >> 32) as u32;
|
||||||
|
|
||||||
|
let b00 = a_lo as u64 * b_lo as u64;
|
||||||
|
let b01 = a_lo as u64 * b_hi as u64;
|
||||||
|
let b10 = a_hi as u64 * b_lo as u64;
|
||||||
|
let b11 = a_hi as u64 * b_hi as u64;
|
||||||
|
|
||||||
|
let b00_lo = b00 as u32;
|
||||||
|
let b00_hi = (b00 >> 32) as u32;
|
||||||
|
|
||||||
|
let mid1 = b10 + b00_hi as u64;
|
||||||
|
let mid1_lo = mid1 as u32;
|
||||||
|
let mid1_hi = (mid1 >> 32) as u32;
|
||||||
|
|
||||||
|
let mid2 = b01 + mid1_lo as u64;
|
||||||
|
let mid2_lo = mid2 as u32;
|
||||||
|
let mid2_hi = (mid2 >> 32) as u32;
|
||||||
|
|
||||||
|
let p_hi = b11 + mid1_hi as u64 + mid2_hi as u64;
|
||||||
|
let p_lo = ((mid2_lo as u64) << 32) + b00_lo as u64;
|
||||||
|
|
||||||
|
(p_lo, p_hi)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub fn shiftright128(lo: u64, hi: u64, dist: u32) -> u64 {
|
||||||
|
// We don't need to handle the case dist >= 64 here (see above).
|
||||||
|
debug_assert!(dist > 0);
|
||||||
|
debug_assert!(dist < 64);
|
||||||
|
(hi << (64 - dist)) | (lo >> dist)
|
||||||
|
}
|
49
third_party/rust/ryu/src/pretty/exponent.rs
vendored
Normal file
49
third_party/rust/ryu/src/pretty/exponent.rs
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
use digit_table::*;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn write_exponent3(mut k: isize, mut result: *mut u8) -> usize {
|
||||||
|
let sign = k < 0;
|
||||||
|
if sign {
|
||||||
|
*result = b'-';
|
||||||
|
result = result.offset(1);
|
||||||
|
k = -k;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(k < 1000);
|
||||||
|
if k >= 100 {
|
||||||
|
*result = b'0' + (k / 100) as u8;
|
||||||
|
k %= 100;
|
||||||
|
let d = DIGIT_TABLE.get_unchecked(k as usize * 2);
|
||||||
|
ptr::copy_nonoverlapping(d, result.offset(1), 2);
|
||||||
|
sign as usize + 3
|
||||||
|
} else if k >= 10 {
|
||||||
|
let d = DIGIT_TABLE.get_unchecked(k as usize * 2);
|
||||||
|
ptr::copy_nonoverlapping(d, result, 2);
|
||||||
|
sign as usize + 2
|
||||||
|
} else {
|
||||||
|
*result = b'0' + k as u8;
|
||||||
|
sign as usize + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn write_exponent2(mut k: isize, mut result: *mut u8) -> usize {
|
||||||
|
let sign = k < 0;
|
||||||
|
if sign {
|
||||||
|
*result = b'-';
|
||||||
|
result = result.offset(1);
|
||||||
|
k = -k;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(k < 100);
|
||||||
|
if k >= 10 {
|
||||||
|
let d = DIGIT_TABLE.get_unchecked(k as usize * 2);
|
||||||
|
ptr::copy_nonoverlapping(d, result, 2);
|
||||||
|
sign as usize + 2
|
||||||
|
} else {
|
||||||
|
*result = b'0' + k as u8;
|
||||||
|
sign as usize + 1
|
||||||
|
}
|
||||||
|
}
|
51
third_party/rust/ryu/src/pretty/mantissa.rs
vendored
Normal file
51
third_party/rust/ryu/src/pretty/mantissa.rs
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
use digit_table::*;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn write_mantissa_long(mut output: u64, mut result: *mut u8) {
|
||||||
|
if (output >> 32) != 0 {
|
||||||
|
// One expensive 64-bit division.
|
||||||
|
let mut output2 = (output - 100_000_000 * (output / 100_000_000)) as u32;
|
||||||
|
output /= 100_000_000;
|
||||||
|
|
||||||
|
let c = output2 % 10_000;
|
||||||
|
output2 /= 10_000;
|
||||||
|
let d = output2 % 10_000;
|
||||||
|
let c0 = (c % 100) << 1;
|
||||||
|
let c1 = (c / 100) << 1;
|
||||||
|
let d0 = (d % 100) << 1;
|
||||||
|
let d1 = (d / 100) << 1;
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2);
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2);
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d0 as usize), result.offset(-6), 2);
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d1 as usize), result.offset(-8), 2);
|
||||||
|
result = result.offset(-8);
|
||||||
|
}
|
||||||
|
write_mantissa(output as u32, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "no-panic", inline)]
|
||||||
|
pub unsafe fn write_mantissa(mut output: u32, mut result: *mut u8) {
|
||||||
|
while output >= 10_000 {
|
||||||
|
let c = (output - 10_000 * (output / 10_000)) as u32;
|
||||||
|
output /= 10_000;
|
||||||
|
let c0 = (c % 100) << 1;
|
||||||
|
let c1 = (c / 100) << 1;
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2);
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2);
|
||||||
|
result = result.offset(-4);
|
||||||
|
}
|
||||||
|
if output >= 100 {
|
||||||
|
let c = ((output % 100) << 1) as u32;
|
||||||
|
output /= 100;
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2);
|
||||||
|
result = result.offset(-2);
|
||||||
|
}
|
||||||
|
if output >= 10 {
|
||||||
|
let c = (output << 1) as u32;
|
||||||
|
ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2);
|
||||||
|
} else {
|
||||||
|
*result.offset(-1) = b'0' + output as u8;
|
||||||
|
}
|
||||||
|
}
|
154
third_party/rust/ryu/src/pretty/mod.rs
vendored
Normal file
154
third_party/rust/ryu/src/pretty/mod.rs
vendored
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
mod exponent;
|
||||||
|
mod mantissa;
|
||||||
|
|
||||||
|
use core::{mem, ptr};
|
||||||
|
|
||||||
|
use self::exponent::*;
|
||||||
|
use self::mantissa::*;
|
||||||
|
use d2s;
|
||||||
|
use d2s::*;
|
||||||
|
use f2s;
|
||||||
|
use f2s::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "no-panic")]
|
||||||
|
use no_panic::no_panic;
|
||||||
|
|
||||||
|
#[cfg_attr(must_use_return, must_use)]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub unsafe fn d2s_buffered_n(f: f64, result: *mut u8) -> usize {
|
||||||
|
let bits = mem::transmute::<f64, u64>(f);
|
||||||
|
let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
|
||||||
|
let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1);
|
||||||
|
let ieee_exponent =
|
||||||
|
(bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);
|
||||||
|
|
||||||
|
let mut index = 0isize;
|
||||||
|
if sign {
|
||||||
|
*result = b'-';
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ieee_exponent == 0 && ieee_mantissa == 0 {
|
||||||
|
ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
|
||||||
|
return sign as usize + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = d2d(ieee_mantissa, ieee_exponent);
|
||||||
|
|
||||||
|
let length = d2s::decimal_length(v.mantissa) as isize;
|
||||||
|
let k = v.exponent as isize;
|
||||||
|
let kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||||
|
debug_assert!(k >= -324);
|
||||||
|
|
||||||
|
if 0 <= k && kk <= 16 {
|
||||||
|
// 1234e7 -> 12340000000.0
|
||||||
|
write_mantissa_long(v.mantissa, result.offset(index + length));
|
||||||
|
for i in length..kk {
|
||||||
|
*result.offset(index + i) = b'0';
|
||||||
|
}
|
||||||
|
*result.offset(index + kk) = b'.';
|
||||||
|
*result.offset(index + kk + 1) = b'0';
|
||||||
|
index as usize + kk as usize + 2
|
||||||
|
} else if 0 < kk && kk <= 16 {
|
||||||
|
// 1234e-2 -> 12.34
|
||||||
|
write_mantissa_long(v.mantissa, result.offset(index + length + 1));
|
||||||
|
ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
|
||||||
|
*result.offset(index + kk) = b'.';
|
||||||
|
index as usize + length as usize + 1
|
||||||
|
} else if -5 < kk && kk <= 0 {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
*result.offset(index) = b'0';
|
||||||
|
*result.offset(index + 1) = b'.';
|
||||||
|
let offset = 2 - kk;
|
||||||
|
for i in 2..offset {
|
||||||
|
*result.offset(index + i) = b'0';
|
||||||
|
}
|
||||||
|
write_mantissa_long(v.mantissa, result.offset(index + length + offset));
|
||||||
|
index as usize + length as usize + offset as usize
|
||||||
|
} else if length == 1 {
|
||||||
|
// 1e30
|
||||||
|
*result.offset(index) = b'0' + v.mantissa as u8;
|
||||||
|
*result.offset(index + 1) = b'e';
|
||||||
|
index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2))
|
||||||
|
} else {
|
||||||
|
// 1234e30 -> 1.234e33
|
||||||
|
write_mantissa_long(v.mantissa, result.offset(index + length + 1));
|
||||||
|
*result.offset(index) = *result.offset(index + 1);
|
||||||
|
*result.offset(index + 1) = b'.';
|
||||||
|
*result.offset(index + length + 1) = b'e';
|
||||||
|
index as usize
|
||||||
|
+ length as usize
|
||||||
|
+ 2
|
||||||
|
+ write_exponent3(kk - 1, result.offset(index + length + 2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(must_use_return, must_use)]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub unsafe fn f2s_buffered_n(f: f32, result: *mut u8) -> usize {
|
||||||
|
let bits = mem::transmute::<f32, u32>(f);
|
||||||
|
let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
|
||||||
|
let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1);
|
||||||
|
let ieee_exponent =
|
||||||
|
((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32;
|
||||||
|
|
||||||
|
let mut index = 0isize;
|
||||||
|
if sign {
|
||||||
|
*result = b'-';
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ieee_exponent == 0 && ieee_mantissa == 0 {
|
||||||
|
ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
|
||||||
|
return sign as usize + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = f2d(ieee_mantissa, ieee_exponent);
|
||||||
|
|
||||||
|
let length = f2s::decimal_length(v.mantissa) as isize;
|
||||||
|
let k = v.exponent as isize;
|
||||||
|
let kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||||
|
debug_assert!(k >= -45);
|
||||||
|
|
||||||
|
if 0 <= k && kk <= 13 {
|
||||||
|
// 1234e7 -> 12340000000.0
|
||||||
|
write_mantissa(v.mantissa, result.offset(index + length));
|
||||||
|
for i in length..kk {
|
||||||
|
*result.offset(index + i) = b'0';
|
||||||
|
}
|
||||||
|
*result.offset(index + kk) = b'.';
|
||||||
|
*result.offset(index + kk + 1) = b'0';
|
||||||
|
index as usize + kk as usize + 2
|
||||||
|
} else if 0 < kk && kk <= 13 {
|
||||||
|
// 1234e-2 -> 12.34
|
||||||
|
write_mantissa(v.mantissa, result.offset(index + length + 1));
|
||||||
|
ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
|
||||||
|
*result.offset(index + kk) = b'.';
|
||||||
|
index as usize + length as usize + 1
|
||||||
|
} else if -6 < kk && kk <= 0 {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
*result.offset(index) = b'0';
|
||||||
|
*result.offset(index + 1) = b'.';
|
||||||
|
let offset = 2 - kk;
|
||||||
|
for i in 2..offset {
|
||||||
|
*result.offset(index + i) = b'0';
|
||||||
|
}
|
||||||
|
write_mantissa(v.mantissa, result.offset(index + length + offset));
|
||||||
|
index as usize + length as usize + offset as usize
|
||||||
|
} else if length == 1 {
|
||||||
|
// 1e30
|
||||||
|
*result.offset(index) = b'0' + v.mantissa as u8;
|
||||||
|
*result.offset(index + 1) = b'e';
|
||||||
|
index as usize + 2 + write_exponent2(kk - 1, result.offset(index + 2))
|
||||||
|
} else {
|
||||||
|
// 1234e30 -> 1.234e33
|
||||||
|
write_mantissa(v.mantissa, result.offset(index + length + 1));
|
||||||
|
*result.offset(index) = *result.offset(index + 1);
|
||||||
|
*result.offset(index + 1) = b'.';
|
||||||
|
*result.offset(index + length + 1) = b'e';
|
||||||
|
index as usize
|
||||||
|
+ length as usize
|
||||||
|
+ 2
|
||||||
|
+ write_exponent2(kk - 1, result.offset(index + length + 2))
|
||||||
|
}
|
||||||
|
}
|
52
third_party/rust/ryu/tests/d2s_table_test.rs
vendored
Normal file
52
third_party/rust/ryu/tests/d2s_table_test.rs
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
#[path = "../src/common.rs"]
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[path = "../src/d2s_full_table.rs"]
|
||||||
|
mod d2s_full_table;
|
||||||
|
|
||||||
|
#[path = "../src/d2s_small_table.rs"]
|
||||||
|
mod d2s_small_table;
|
||||||
|
|
||||||
|
#[path = "../src/mulshift128.rs"]
|
||||||
|
mod mulshift128;
|
||||||
|
|
||||||
|
use d2s_full_table::*;
|
||||||
|
use d2s_small_table::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compute_pow5() {
|
||||||
|
for (i, entry) in DOUBLE_POW5_SPLIT.iter().enumerate() {
|
||||||
|
assert_eq!(*entry, unsafe { compute_pow5(i as u32) }, "entry {}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compute_inv_pow5() {
|
||||||
|
for (i, entry) in DOUBLE_POW5_INV_SPLIT.iter().enumerate() {
|
||||||
|
assert_eq!(*entry, unsafe { compute_inv_pow5(i as u32) }, "entry {}", i);
|
||||||
|
}
|
||||||
|
}
|
154
third_party/rust/ryu/tests/d2s_test.rs
vendored
Normal file
154
third_party/rust/ryu/tests/d2s_test.rs
vendored
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
extern crate rand;
|
||||||
|
extern crate ryu;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
|
use std::{f64, str};
|
||||||
|
|
||||||
|
fn print(f: f64) -> String {
|
||||||
|
let mut bytes = [0u8; 24];
|
||||||
|
let n = unsafe { ryu::raw::d2s_buffered_n(f, &mut bytes[0]) };
|
||||||
|
let s = str::from_utf8(&bytes[..n]).unwrap();
|
||||||
|
s.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty(f: f64) -> String {
|
||||||
|
ryu::Buffer::new().format(f).to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ryu() {
|
||||||
|
check!(3E-1, 0.3);
|
||||||
|
check!(1.234E15, 1234000000000000.0);
|
||||||
|
check!(1.234E16, 1.234e16);
|
||||||
|
check!(2.71828E0, 2.71828);
|
||||||
|
check!(1.1E128, 1.1e128);
|
||||||
|
check!(1.1E-64, 1.1e-64);
|
||||||
|
check!(2.718281828459045E0, 2.718281828459045);
|
||||||
|
check!(5E-324, 5e-324);
|
||||||
|
check!(1.7976931348623157E308, 1.7976931348623157e308);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_random() {
|
||||||
|
let mut bytes = [0u8; 24];
|
||||||
|
let mut buffer = ryu::Buffer::new();
|
||||||
|
for _ in 0..1000000 {
|
||||||
|
let f = rand::random();
|
||||||
|
let n = unsafe { ryu::raw::d2s_buffered_n(f, &mut bytes[0]) };
|
||||||
|
assert_eq!(f, str::from_utf8(&bytes[..n]).unwrap().parse().unwrap());
|
||||||
|
assert_eq!(f, buffer.format(f).parse().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_non_finite() {
|
||||||
|
for i in 0u64..1 << 23 {
|
||||||
|
let f = f64::from_bits((((1 << 11) - 1) << 52) + (i << 29));
|
||||||
|
assert!(!f.is_finite(), "f={}", f);
|
||||||
|
ryu::Buffer::new().format(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_basic() {
|
||||||
|
check!(0E0, 0.0);
|
||||||
|
check!(-0E0, -0.0);
|
||||||
|
check!(1E0, 1.0);
|
||||||
|
check!(-1E0, -1.0);
|
||||||
|
assert_eq!(print(f64::NAN), "NaN");
|
||||||
|
assert_eq!(print(f64::INFINITY), "Infinity");
|
||||||
|
assert_eq!(print(f64::NEG_INFINITY), "-Infinity");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_switch_to_subnormal() {
|
||||||
|
check!(2.2250738585072014E-308, 2.2250738585072014e-308);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_min_and_max() {
|
||||||
|
assert_eq!(f64::from_bits(0x7fefffffffffffff), 1.7976931348623157e308);
|
||||||
|
check!(1.7976931348623157E308, 1.7976931348623157e308);
|
||||||
|
assert_eq!(f64::from_bits(1), 5e-324);
|
||||||
|
check!(5E-324, 5e-324);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lots_of_trailing_zeros() {
|
||||||
|
check!(2.9802322387695312E-8, 2.9802322387695312e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_regression() {
|
||||||
|
check!(-2.109808898695963E16, -2.109808898695963e16);
|
||||||
|
check!(4.940656E-318, 4.940656e-318);
|
||||||
|
check!(1.18575755E-316, 1.18575755e-316);
|
||||||
|
check!(2.989102097996E-312, 2.989102097996e-312);
|
||||||
|
check!(9.0608011534336E15, 9060801153433600.0);
|
||||||
|
check!(4.708356024711512E18, 4.708356024711512e18);
|
||||||
|
check!(9.409340012568248E18, 9.409340012568248e18);
|
||||||
|
check!(1.2345678E0, 1.2345678);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_looks_like_pow5() {
|
||||||
|
// These numbers have a mantissa that is a multiple of the largest power of
|
||||||
|
// 5 that fits, and an exponent that causes the computation for q to result
|
||||||
|
// in 22, which is a corner case for Ryu.
|
||||||
|
assert_eq!(f64::from_bits(0x4830F0CF064DD592), 5.764607523034235e39);
|
||||||
|
check!(5.764607523034235E39, 5.764607523034235e39);
|
||||||
|
assert_eq!(f64::from_bits(0x4840F0CF064DD592), 1.152921504606847e40);
|
||||||
|
check!(1.152921504606847E40, 1.152921504606847e40);
|
||||||
|
assert_eq!(f64::from_bits(0x4850F0CF064DD592), 2.305843009213694e40);
|
||||||
|
check!(2.305843009213694E40, 2.305843009213694e40);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_output_length() {
|
||||||
|
check!(1E0, 1.0); // already tested in Basic
|
||||||
|
check!(1.2E0, 1.2);
|
||||||
|
check!(1.23E0, 1.23);
|
||||||
|
check!(1.234E0, 1.234);
|
||||||
|
check!(1.2345E0, 1.2345);
|
||||||
|
check!(1.23456E0, 1.23456);
|
||||||
|
check!(1.234567E0, 1.234567);
|
||||||
|
check!(1.2345678E0, 1.2345678); // already tested in Regression
|
||||||
|
check!(1.23456789E0, 1.23456789);
|
||||||
|
check!(1.234567895E0, 1.234567895); // 1.234567890 would be trimmed
|
||||||
|
check!(1.2345678901E0, 1.2345678901);
|
||||||
|
check!(1.23456789012E0, 1.23456789012);
|
||||||
|
check!(1.234567890123E0, 1.234567890123);
|
||||||
|
check!(1.2345678901234E0, 1.2345678901234);
|
||||||
|
check!(1.23456789012345E0, 1.23456789012345);
|
||||||
|
check!(1.234567890123456E0, 1.234567890123456);
|
||||||
|
check!(1.2345678901234567E0, 1.2345678901234567);
|
||||||
|
|
||||||
|
// Test 32-bit chunking
|
||||||
|
check!(4.294967294E0, 4.294967294); // 2^32 - 2
|
||||||
|
check!(4.294967295E0, 4.294967295); // 2^32 - 1
|
||||||
|
check!(4.294967296E0, 4.294967296); // 2^32
|
||||||
|
check!(4.294967297E0, 4.294967297); // 2^32 + 1
|
||||||
|
check!(4.294967298E0, 4.294967298); // 2^32 + 2
|
||||||
|
}
|
55
third_party/rust/ryu/tests/exhaustive.rs
vendored
Normal file
55
third_party/rust/ryu/tests/exhaustive.rs
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#![cfg(exhaustive)]
|
||||||
|
|
||||||
|
extern crate num_cpus;
|
||||||
|
extern crate ryu;
|
||||||
|
|
||||||
|
use std::str;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exhaustive() {
|
||||||
|
const BATCH_SIZE: u32 = 1_000_000;
|
||||||
|
let counter = Arc::new(AtomicUsize::new(0));
|
||||||
|
let finished = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
|
let mut workers = Vec::new();
|
||||||
|
for _ in 0..num_cpus::get() {
|
||||||
|
let counter = counter.clone();
|
||||||
|
let finished = finished.clone();
|
||||||
|
workers.push(thread::spawn(move || loop {
|
||||||
|
let batch = counter.fetch_add(1, Ordering::SeqCst) as u32;
|
||||||
|
if batch > u32::max_value() / BATCH_SIZE {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let min = batch * BATCH_SIZE;
|
||||||
|
let max = if batch == u32::max_value() / BATCH_SIZE {
|
||||||
|
u32::max_value()
|
||||||
|
} else {
|
||||||
|
min + BATCH_SIZE - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut bytes = [0u8; 24];
|
||||||
|
let mut buffer = ryu::Buffer::new();
|
||||||
|
for u in min..=max {
|
||||||
|
let f = f32::from_bits(u);
|
||||||
|
if !f.is_finite() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let n = unsafe { ryu::raw::f2s_buffered_n(f, &mut bytes[0]) };
|
||||||
|
assert_eq!(Ok(Ok(f)), str::from_utf8(&bytes[..n]).map(str::parse));
|
||||||
|
assert_eq!(Ok(f), buffer.format(f).parse());
|
||||||
|
}
|
||||||
|
|
||||||
|
let increment = (max - min + 1) as usize;
|
||||||
|
let update = finished.fetch_add(increment, Ordering::SeqCst);
|
||||||
|
println!("{}", update + increment);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for w in workers {
|
||||||
|
w.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
183
third_party/rust/ryu/tests/f2s_test.rs
vendored
Normal file
183
third_party/rust/ryu/tests/f2s_test.rs
vendored
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
// Translated from C to Rust. The original C code can be found at
|
||||||
|
// https://github.com/ulfjack/ryu and carries the following license:
|
||||||
|
//
|
||||||
|
// Copyright 2018 Ulf Adams
|
||||||
|
//
|
||||||
|
// The contents of this file may be used under the terms of the Apache License,
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// (See accompanying file LICENSE-Apache or copy at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
//
|
||||||
|
// Alternatively, the contents of this file may be used under the terms of
|
||||||
|
// the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE-Boost or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, this software
|
||||||
|
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied.
|
||||||
|
|
||||||
|
extern crate rand;
|
||||||
|
extern crate ryu;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
|
use std::{f32, str};
|
||||||
|
|
||||||
|
fn print(f: f32) -> String {
|
||||||
|
let mut bytes = [0u8; 24];
|
||||||
|
let n = unsafe { ryu::raw::f2s_buffered_n(f, &mut bytes[0]) };
|
||||||
|
let s = str::from_utf8(&bytes[..n]).unwrap();
|
||||||
|
s.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty(f: f32) -> String {
|
||||||
|
ryu::Buffer::new().format(f).to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ryu() {
|
||||||
|
check!(3E-1, 0.3);
|
||||||
|
check!(1.234E12, 1234000000000.0);
|
||||||
|
check!(1.234E13, 1.234e13);
|
||||||
|
check!(2.71828E0, 2.71828);
|
||||||
|
check!(1.1E32, 1.1e32);
|
||||||
|
check!(1.1E-32, 1.1e-32);
|
||||||
|
check!(2.7182817E0, 2.7182817);
|
||||||
|
check!(1E-45, 1e-45);
|
||||||
|
check!(3.4028235E38, 3.4028235e38);
|
||||||
|
check!(-1.234E-3, -0.001234);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_random() {
|
||||||
|
let mut bytes = [0u8; 24];
|
||||||
|
let mut buffer = ryu::Buffer::new();
|
||||||
|
for _ in 0..1000000 {
|
||||||
|
let f = rand::random();
|
||||||
|
let n = unsafe { ryu::raw::f2s_buffered_n(f, &mut bytes[0]) };
|
||||||
|
assert_eq!(f, str::from_utf8(&bytes[..n]).unwrap().parse().unwrap());
|
||||||
|
assert_eq!(f, buffer.format(f).parse().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_non_finite() {
|
||||||
|
for i in 0u32..1 << 23 {
|
||||||
|
let f = f32::from_bits((((1 << 8) - 1) << 23) + i);
|
||||||
|
assert!(!f.is_finite(), "f={}", f);
|
||||||
|
ryu::Buffer::new().format(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_basic() {
|
||||||
|
check!(0E0, 0.0);
|
||||||
|
check!(-0E0, -0.0);
|
||||||
|
check!(1E0, 1.0);
|
||||||
|
check!(-1E0, -1.0);
|
||||||
|
assert_eq!(print(f32::NAN), "NaN");
|
||||||
|
assert_eq!(print(f32::INFINITY), "Infinity");
|
||||||
|
assert_eq!(print(f32::NEG_INFINITY), "-Infinity");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_switch_to_subnormal() {
|
||||||
|
check!(1.1754944E-38, 1.1754944e-38);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_min_and_max() {
|
||||||
|
assert_eq!(f32::from_bits(0x7f7fffff), 3.4028235e38);
|
||||||
|
check!(3.4028235E38, 3.4028235e38);
|
||||||
|
assert_eq!(f32::from_bits(1), 1e-45);
|
||||||
|
check!(1E-45, 1e-45);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we return the exact boundary if it is the shortest
|
||||||
|
// representation, but only if the original floating point number is even.
|
||||||
|
#[test]
|
||||||
|
fn test_boundary_round_even() {
|
||||||
|
check!(3.355445E7, 33554450.0);
|
||||||
|
check!(9E9, 9000000000.0);
|
||||||
|
check!(3.436672E10, 34366720000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the exact value is exactly halfway between two shortest representations,
|
||||||
|
// then we round to even. It seems like this only makes a difference if the
|
||||||
|
// last two digits are ...2|5 or ...7|5, and we cut off the 5.
|
||||||
|
#[test]
|
||||||
|
fn test_exact_value_round_even() {
|
||||||
|
check!(3.0540412E5, 305404.12);
|
||||||
|
check!(8.0990312E3, 8099.0312);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lots_of_trailing_zeros() {
|
||||||
|
// Pattern for the first test: 00111001100000000000000000000000
|
||||||
|
check!(2.4414062E-4, 0.00024414062);
|
||||||
|
check!(2.4414062E-3, 0.0024414062);
|
||||||
|
check!(4.3945312E-3, 0.0043945312);
|
||||||
|
check!(6.3476562E-3, 0.0063476562);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_regression() {
|
||||||
|
check!(4.7223665E21, 4.7223665e21);
|
||||||
|
check!(8.388608E6, 8388608.0);
|
||||||
|
check!(1.6777216E7, 16777216.0);
|
||||||
|
check!(3.3554436E7, 33554436.0);
|
||||||
|
check!(6.7131496E7, 67131496.0);
|
||||||
|
check!(1.9310392E-38, 1.9310392e-38);
|
||||||
|
check!(-2.47E-43, -2.47e-43);
|
||||||
|
check!(1.993244E-38, 1.993244e-38);
|
||||||
|
check!(4.1039004E3, 4103.9004);
|
||||||
|
check!(5.3399997E9, 5339999700.0);
|
||||||
|
check!(6.0898E-39, 6.0898e-39);
|
||||||
|
check!(1.0310042E-3, 0.0010310042);
|
||||||
|
check!(2.882326E17, 2.882326e17);
|
||||||
|
check!(7.038531E-26, 7.038531e-26);
|
||||||
|
check!(9.223404E17, 9.223404e17);
|
||||||
|
check!(6.710887E7, 67108870.0);
|
||||||
|
check!(1E-44, 1e-44);
|
||||||
|
check!(2.816025E14, 2.816025e14);
|
||||||
|
check!(9.223372E18, 9.223372e18);
|
||||||
|
check!(1.5846086E29, 1.5846086e29);
|
||||||
|
check!(1.1811161E19, 1.1811161e19);
|
||||||
|
check!(5.368709E18, 5.368709e18);
|
||||||
|
check!(4.6143166E18, 4.6143166e18);
|
||||||
|
check!(7.812537E-3, 0.007812537);
|
||||||
|
check!(1E-45, 1e-45);
|
||||||
|
check!(1.18697725E20, 1.18697725e20);
|
||||||
|
check!(1.00014165E-36, 1.00014165e-36);
|
||||||
|
check!(2E2, 200.0);
|
||||||
|
check!(3.3554432E7, 33554432.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_looks_like_pow5() {
|
||||||
|
// These numbers have a mantissa that is the largest power of 5 that fits,
|
||||||
|
// and an exponent that causes the computation for q to result in 10, which
|
||||||
|
// is a corner case for Ryu.
|
||||||
|
assert_eq!(f32::from_bits(0x5D1502F9), 6.7108864e17);
|
||||||
|
check!(6.7108864E17, 6.7108864e17);
|
||||||
|
assert_eq!(f32::from_bits(0x5D9502F9), 1.3421773e18);
|
||||||
|
check!(1.3421773E18, 1.3421773e18);
|
||||||
|
assert_eq!(f32::from_bits(0x5E1502F9), 2.6843546e18);
|
||||||
|
check!(2.6843546E18, 2.6843546e18);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_output_length() {
|
||||||
|
check!(1E0, 1.0); // already tested in Basic
|
||||||
|
check!(1.2E0, 1.2);
|
||||||
|
check!(1.23E0, 1.23);
|
||||||
|
check!(1.234E0, 1.234);
|
||||||
|
check!(1.2345E0, 1.2345);
|
||||||
|
check!(1.23456E0, 1.23456);
|
||||||
|
check!(1.234567E0, 1.234567);
|
||||||
|
check!(1.2345678E0, 1.2345678);
|
||||||
|
check!(1.23456735E-36, 1.23456735e-36);
|
||||||
|
}
|
12
third_party/rust/ryu/tests/macros/mod.rs
vendored
Normal file
12
third_party/rust/ryu/tests/macros/mod.rs
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
macro_rules! check {
|
||||||
|
($ryu:tt, $pretty:tt) => {
|
||||||
|
assert_eq!($ryu, $pretty);
|
||||||
|
assert_eq!(print($ryu), stringify!($ryu));
|
||||||
|
assert_eq!(pretty($pretty), stringify!($pretty));
|
||||||
|
};
|
||||||
|
(-$ryu:tt, -$pretty:tt) => {
|
||||||
|
assert_eq!(-$ryu, -$pretty);
|
||||||
|
assert_eq!(print(-$ryu), concat!("-", stringify!($ryu)));
|
||||||
|
assert_eq!(pretty(-$pretty), concat!("-", stringify!($pretty)));
|
||||||
|
};
|
||||||
|
}
|
1
third_party/rust/serde_json/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/serde_json/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"files":{"Cargo.toml":"0265066945da4da5957f3446cef6f2a52e81254be3a9c4e678cc2c1e1160118b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"c4d8690cd2aa2db200ecdf2f2113fc8e3f4ccc88f3dc96da22189f45136932d0","src/de.rs":"42d7aa8cf85baa1b3851180e32af883c11ca2889df6f4eb306670f360af46d3e","src/error.rs":"8ac6d4c861891c133b3359b2a14fccb8a6d463a4b2c13f0d658884c1972186ce","src/iter.rs":"b5c77c5482e45bed1e63bd36a0f991a08f732811546a163228be48303e7f1b4d","src/lib.rs":"698af0adc583d8b5a22f510bb33fbdb35552dd6e0775e038f7ed50f6680580d8","src/macros.rs":"0d9850832f53c8aca337395b2536f1cdaf2d2d2699adc09c9a2001544106a4fc","src/map.rs":"724205f934003c879fb3e48a84b21c54e273e968beec97b85617042911ca88d7","src/number.rs":"47bf5416ca4f8299e98f008bd1bcf7e7311f00d0ce282536a17310fa73788def","src/read.rs":"832bc530dd35ee24df59c1cf648cfbbffc4c2e72e86104b0e186582ae0de545a","src/ser.rs":"d2050d362c23e988141e6c5d08590152b3412ee3464e1a3026b83dda7de0c985","src/value/de.rs":"b25d9192f179f84c0ecb2226216ff663c39ebdde524179f7118718f3202243cf","src/value/from.rs":"13a6c7b0b327f23c2fd899c8390e8ddfd8907bfcfc362e80834b9ae7ddb698e9","src/value/index.rs":"b9a8cc6f37e2a079a5e4ab1bf25fa9ff076c514870e0756a0c88af3ffa0f51a8","src/value/mod.rs":"8d0ac56fcd12aee1c645afdfe0df62b10527cab21d16284fe9f0bd6768457002","src/value/partial_eq.rs":"5924e245408afc8075e2bb9dda479c938c6c8cdd3c18b54697aa2b33fffda57b","src/value/ser.rs":"4bbc3ad0f646464f1e9b9a2c2e48df799d02ef658eacadc35971b897cfe7cd02"},"package":"44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"}
|
54
third_party/rust/serde_json/Cargo.toml
vendored
Normal file
54
third_party/rust/serde_json/Cargo.toml
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g. crates.io) dependencies
|
||||||
|
#
|
||||||
|
# If you believe there's an error in this file please file an
|
||||||
|
# issue against the rust-lang/cargo repository. If you're
|
||||||
|
# editing this file be aware that the upstream Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable)
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.26"
|
||||||
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
|
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||||
|
description = "A JSON serialization file format"
|
||||||
|
documentation = "http://docs.serde.rs/serde_json/"
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = ["json", "serde", "serialization"]
|
||||||
|
categories = ["encoding"]
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
repository = "https://github.com/serde-rs/json"
|
||||||
|
[dependencies.indexmap]
|
||||||
|
version = "1.0"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[dependencies.itoa]
|
||||||
|
version = "0.4"
|
||||||
|
|
||||||
|
[dependencies.ryu]
|
||||||
|
version = "0.2"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0.60"
|
||||||
|
[dev-dependencies.compiletest_rs]
|
||||||
|
version = "0.3"
|
||||||
|
|
||||||
|
[dev-dependencies.serde_bytes]
|
||||||
|
version = "0.10"
|
||||||
|
|
||||||
|
[dev-dependencies.serde_derive]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
arbitrary_precision = []
|
||||||
|
default = []
|
||||||
|
preserve_order = ["indexmap"]
|
||||||
|
[badges.appveyor]
|
||||||
|
repository = "serde-rs/json"
|
||||||
|
|
||||||
|
[badges.travis-ci]
|
||||||
|
repository = "serde-rs/json"
|
365
third_party/rust/serde_json/README.md
vendored
Normal file
365
third_party/rust/serde_json/README.md
vendored
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
# Serde JSON   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.15+]][rustc]
|
||||||
|
|
||||||
|
[Build Status]: https://api.travis-ci.org/serde-rs/json.svg?branch=master
|
||||||
|
[travis]: https://travis-ci.org/serde-rs/json
|
||||||
|
[Latest Version]: https://img.shields.io/crates/v/serde_json.svg
|
||||||
|
[crates.io]: https://crates.io/crates/serde\_json
|
||||||
|
[Rustc Version 1.15+]: https://img.shields.io/badge/rustc-1.15+-lightgray.svg
|
||||||
|
[rustc]: https://blog.rust-lang.org/2017/02/02/Rust-1.15.html
|
||||||
|
|
||||||
|
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
serde_json = "1.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
You may be looking for:
|
||||||
|
|
||||||
|
- [JSON API documentation](https://docs.serde.rs/serde_json/)
|
||||||
|
- [Serde API documentation](https://docs.serde.rs/serde/)
|
||||||
|
- [Detailed documentation about Serde](https://serde.rs/)
|
||||||
|
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html)
|
||||||
|
- [Release notes](https://github.com/serde-rs/json/releases)
|
||||||
|
|
||||||
|
JSON is a ubiquitous open-standard format that uses human-readable text to
|
||||||
|
transmit data objects consisting of key-value pairs.
|
||||||
|
|
||||||
|
```json,ignore
|
||||||
|
{
|
||||||
|
"name": "John Doe",
|
||||||
|
"age": 43,
|
||||||
|
"address": {
|
||||||
|
"street": "10 Downing Street",
|
||||||
|
"city": "London"
|
||||||
|
},
|
||||||
|
"phones": [
|
||||||
|
"+44 1234567",
|
||||||
|
"+44 2345678"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
There are three common ways that you might find yourself needing to work
|
||||||
|
with JSON data in Rust.
|
||||||
|
|
||||||
|
- **As text data.** An unprocessed string of JSON data that you receive on
|
||||||
|
an HTTP endpoint, read from a file, or prepare to send to a remote
|
||||||
|
server.
|
||||||
|
- **As an untyped or loosely typed representation.** Maybe you want to
|
||||||
|
check that some JSON data is valid before passing it on, but without
|
||||||
|
knowing the structure of what it contains. Or you want to do very basic
|
||||||
|
manipulations like insert a key in a particular spot.
|
||||||
|
- **As a strongly typed Rust data structure.** When you expect all or most
|
||||||
|
of your data to conform to a particular structure and want to get real
|
||||||
|
work done without JSON's loosey-goosey nature tripping you up.
|
||||||
|
|
||||||
|
Serde JSON provides efficient, flexible, safe ways of converting data
|
||||||
|
between each of these representations.
|
||||||
|
|
||||||
|
## Operating on untyped JSON values
|
||||||
|
|
||||||
|
Any valid JSON data can be manipulated in the following recursive enum
|
||||||
|
representation. This data structure is [`serde_json::Value`][value].
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
enum Value {
|
||||||
|
Null,
|
||||||
|
Bool(bool),
|
||||||
|
Number(Number),
|
||||||
|
String(String),
|
||||||
|
Array(Vec<Value>),
|
||||||
|
Object(Map<String, Value>),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A string of JSON data can be parsed into a `serde_json::Value` by the
|
||||||
|
[`serde_json::from_str`][from_str] function. There is also
|
||||||
|
[`from_slice`][from_slice] for parsing from a byte slice &[u8] and
|
||||||
|
[`from_reader`][from_reader] for parsing from any `io::Read` like a File or
|
||||||
|
a TCP stream.
|
||||||
|
|
||||||
|
<a href="http://play.integer32.com/?gist=a266662bc71712e080efbf25ce30f306" target="_blank">
|
||||||
|
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use serde_json::{Value, Error};
|
||||||
|
|
||||||
|
fn untyped_example() -> Result<(), Error> {
|
||||||
|
// Some JSON input data as a &str. Maybe this comes from the user.
|
||||||
|
let data = r#"{
|
||||||
|
"name": "John Doe",
|
||||||
|
"age": 43,
|
||||||
|
"phones": [
|
||||||
|
"+44 1234567",
|
||||||
|
"+44 2345678"
|
||||||
|
]
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
// Parse the string of data into serde_json::Value.
|
||||||
|
let v: Value = serde_json::from_str(data)?;
|
||||||
|
|
||||||
|
// Access parts of the data by indexing with square brackets.
|
||||||
|
println!("Please call {} at the number {}", v["name"], v["phones"][0]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The result of square bracket indexing like `v["name"]` is a borrow of the data
|
||||||
|
at that index, so the type is `&Value`. A JSON map can be indexed with string
|
||||||
|
keys, while a JSON array can be indexed with integer keys. If the type of the
|
||||||
|
data is not right for the type with which it is being indexed, or if a map does
|
||||||
|
not contain the key being indexed, or if the index into a vector is out of
|
||||||
|
bounds, the returned element is `Value::Null`.
|
||||||
|
|
||||||
|
When a `Value` is printed, it is printed as a JSON string. So in the code above,
|
||||||
|
the output looks like `Please call "John Doe" at the number "+44 1234567"`. The
|
||||||
|
quotation marks appear because `v["name"]` is a `&Value` containing a JSON
|
||||||
|
string and its JSON representation is `"John Doe"`. Printing as a plain string
|
||||||
|
without quotation marks involves converting from a JSON string to a Rust string
|
||||||
|
with [`as_str()`] or avoiding the use of `Value` as described in the following
|
||||||
|
section.
|
||||||
|
|
||||||
|
[`as_str()`]: https://docs.serde.rs/serde_json/enum.Value.html#method.as_str
|
||||||
|
|
||||||
|
The `Value` representation is sufficient for very basic tasks but can be tedious
|
||||||
|
to work with for anything more significant. Error handling is verbose to
|
||||||
|
implement correctly, for example imagine trying to detect the presence of
|
||||||
|
unrecognized fields in the input data. The compiler is powerless to help you
|
||||||
|
when you make a mistake, for example imagine typoing `v["name"]` as `v["nmae"]`
|
||||||
|
in one of the dozens of places it is used in your code.
|
||||||
|
|
||||||
|
## Parsing JSON as strongly typed data structures
|
||||||
|
|
||||||
|
Serde provides a powerful way of mapping JSON data into Rust data structures
|
||||||
|
largely automatically.
|
||||||
|
|
||||||
|
<a href="http://play.integer32.com/?gist=cff572b80d3f078c942a2151e6020adc" target="_blank">
|
||||||
|
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
use serde_json::Error;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Person {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
phones: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typed_example() -> Result<(), Error> {
|
||||||
|
// Some JSON input data as a &str. Maybe this comes from the user.
|
||||||
|
let data = r#"{
|
||||||
|
"name": "John Doe",
|
||||||
|
"age": 43,
|
||||||
|
"phones": [
|
||||||
|
"+44 1234567",
|
||||||
|
"+44 2345678"
|
||||||
|
]
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
// Parse the string of data into a Person object. This is exactly the
|
||||||
|
// same function as the one that produced serde_json::Value above, but
|
||||||
|
// now we are asking it for a Person as output.
|
||||||
|
let p: Person = serde_json::from_str(data)?;
|
||||||
|
|
||||||
|
// Do things just like with any other Rust data structure.
|
||||||
|
println!("Please call {} at the number {}", p.name, p.phones[0]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the same `serde_json::from_str` function as before, but this time we
|
||||||
|
assign the return value to a variable of type `Person` so Serde will
|
||||||
|
automatically interpret the input data as a `Person` and produce informative
|
||||||
|
error messages if the layout does not conform to what a `Person` is expected
|
||||||
|
to look like.
|
||||||
|
|
||||||
|
Any type that implements Serde's `Deserialize` trait can be deserialized
|
||||||
|
this way. This includes built-in Rust standard library types like `Vec<T>`
|
||||||
|
and `HashMap<K, V>`, as well as any structs or enums annotated with
|
||||||
|
`#[derive(Deserialize)]`.
|
||||||
|
|
||||||
|
Once we have `p` of type `Person`, our IDE and the Rust compiler can help us
|
||||||
|
use it correctly like they do for any other Rust code. The IDE can
|
||||||
|
autocomplete field names to prevent typos, which was impossible in the
|
||||||
|
`serde_json::Value` representation. And the Rust compiler can check that
|
||||||
|
when we write `p.phones[0]`, then `p.phones` is guaranteed to be a
|
||||||
|
`Vec<String>` so indexing into it makes sense and produces a `String`.
|
||||||
|
|
||||||
|
## Constructing JSON values
|
||||||
|
|
||||||
|
Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value`
|
||||||
|
objects with very natural JSON syntax. In order to use this macro,
|
||||||
|
`serde_json` needs to be imported with the `#[macro_use]` attribute.
|
||||||
|
|
||||||
|
<a href="http://play.integer32.com/?gist=c216d6beabd9429a6ac13b8f88938dfe" target="_blank">
|
||||||
|
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// The type of `john` is `serde_json::Value`
|
||||||
|
let john = json!({
|
||||||
|
"name": "John Doe",
|
||||||
|
"age": 43,
|
||||||
|
"phones": [
|
||||||
|
"+44 1234567",
|
||||||
|
"+44 2345678"
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("first phone number: {}", john["phones"][0]);
|
||||||
|
|
||||||
|
// Convert to a string of JSON and print it out
|
||||||
|
println!("{}", john.to_string());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Value::to_string()` function converts a `serde_json::Value` into a
|
||||||
|
`String` of JSON text.
|
||||||
|
|
||||||
|
One neat thing about the `json!` macro is that variables and expressions can
|
||||||
|
be interpolated directly into the JSON value as you are building it. Serde
|
||||||
|
will check at compile time that the value you are interpolating is able to
|
||||||
|
be represented as JSON.
|
||||||
|
|
||||||
|
<a href="http://play.integer32.com/?gist=aae3af4d274bd249d1c8a947076355f2" target="_blank">
|
||||||
|
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let full_name = "John Doe";
|
||||||
|
let age_last_year = 42;
|
||||||
|
|
||||||
|
// The type of `john` is `serde_json::Value`
|
||||||
|
let john = json!({
|
||||||
|
"name": full_name,
|
||||||
|
"age": age_last_year + 1,
|
||||||
|
"phones": [
|
||||||
|
format!("+44 {}", random_phone())
|
||||||
|
]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This is amazingly convenient but we have the problem we had before with
|
||||||
|
`Value` which is that the IDE and Rust compiler cannot help us if we get it
|
||||||
|
wrong. Serde JSON provides a better way of serializing strongly-typed data
|
||||||
|
structures into JSON text.
|
||||||
|
|
||||||
|
## Creating JSON by serializing data structures
|
||||||
|
|
||||||
|
A data structure can be converted to a JSON string by
|
||||||
|
[`serde_json::to_string`][to_string]. There is also
|
||||||
|
[`serde_json::to_vec`][to_vec] which serializes to a `Vec<u8>` and
|
||||||
|
[`serde_json::to_writer`][to_writer] which serializes to any `io::Write`
|
||||||
|
such as a File or a TCP stream.
|
||||||
|
|
||||||
|
<a href="http://play.integer32.com/?gist=40967ece79921c77fd78ebc8f177c063" target="_blank">
|
||||||
|
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
use serde_json::Error;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Address {
|
||||||
|
street: String,
|
||||||
|
city: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_an_address() -> Result<(), Error> {
|
||||||
|
// Some data structure.
|
||||||
|
let address = Address {
|
||||||
|
street: "10 Downing Street".to_owned(),
|
||||||
|
city: "London".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Serialize it to a JSON string.
|
||||||
|
let j = serde_json::to_string(&address)?;
|
||||||
|
|
||||||
|
// Print, write to a file, or send to an HTTP server.
|
||||||
|
println!("{}", j);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Any type that implements Serde's `Serialize` trait can be serialized this
|
||||||
|
way. This includes built-in Rust standard library types like `Vec<T>` and
|
||||||
|
`HashMap<K, V>`, as well as any structs or enums annotated with
|
||||||
|
`#[derive(Serialize)]`.
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
It is fast. You should expect in the ballpark of 500 to 1000 megabytes per
|
||||||
|
second deserialization and 600 to 900 megabytes per second serialization,
|
||||||
|
depending on the characteristics of your data. This is competitive with the
|
||||||
|
fastest C and C++ JSON libraries or even 30% faster for many use cases.
|
||||||
|
Benchmarks live in the [serde-rs/json-benchmark] repo.
|
||||||
|
|
||||||
|
[serde-rs/json-benchmark]: https://github.com/serde-rs/json-benchmark
|
||||||
|
|
||||||
|
## Getting help
|
||||||
|
|
||||||
|
Serde developers live in the #serde channel on
|
||||||
|
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC). The #rust channel is also a
|
||||||
|
good resource with generally faster response time but less specific knowledge
|
||||||
|
about Serde. If IRC is not your thing, we are happy to respond to [GitHub
|
||||||
|
issues](https://github.com/serde-rs/json/issues/new) as well.
|
||||||
|
|
||||||
|
## No-std support
|
||||||
|
|
||||||
|
This crate currently requires the Rust standard library. For JSON support in
|
||||||
|
Serde without a standard library, please see the [`serde-json-core`] crate.
|
||||||
|
|
||||||
|
[`serde-json-core`]: https://japaric.github.io/serde-json-core/serde_json_core/
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Serde JSON is licensed under either of
|
||||||
|
|
||||||
|
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||||
|
http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||||
|
for inclusion in Serde JSON by you, as defined in the Apache-2.0 license, shall
|
||||||
|
be dual licensed as above, without any additional terms or conditions.
|
||||||
|
|
||||||
|
[value]: https://docs.serde.rs/serde_json/value/enum.Value.html
|
||||||
|
[from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html
|
||||||
|
[from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html
|
||||||
|
[from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html
|
||||||
|
[to_string]: https://docs.serde.rs/serde_json/ser/fn.to_string.html
|
||||||
|
[to_vec]: https://docs.serde.rs/serde_json/ser/fn.to_vec.html
|
||||||
|
[to_writer]: https://docs.serde.rs/serde_json/ser/fn.to_writer.html
|
||||||
|
[macro]: https://docs.serde.rs/serde_json/macro.json.html
|
2265
third_party/rust/serde_json/src/de.rs
vendored
Normal file
2265
third_party/rust/serde_json/src/de.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
429
third_party/rust/serde_json/src/error.rs
vendored
Normal file
429
third_party/rust/serde_json/src/error.rs
vendored
Normal file
@ -0,0 +1,429 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! When serializing or deserializing JSON goes wrong.
|
||||||
|
|
||||||
|
use std::error;
|
||||||
|
use std::fmt::{self, Debug, Display};
|
||||||
|
use std::io;
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
use serde::de;
|
||||||
|
use serde::ser;
|
||||||
|
|
||||||
|
/// This type represents all possible errors that can occur when serializing or
|
||||||
|
/// deserializing JSON data.
|
||||||
|
pub struct Error {
|
||||||
|
/// This `Box` allows us to keep the size of `Error` as small as possible. A
|
||||||
|
/// larger `Error` type was substantially slower due to all the functions
|
||||||
|
/// that pass around `Result<T, Error>`.
|
||||||
|
err: Box<ErrorImpl>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alias for a `Result` with the error type `serde_json::Error`.
|
||||||
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
/// One-based line number at which the error was detected.
|
||||||
|
///
|
||||||
|
/// Characters in the first line of the input (before the first newline
|
||||||
|
/// character) are in line 1.
|
||||||
|
pub fn line(&self) -> usize {
|
||||||
|
self.err.line
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One-based column number at which the error was detected.
|
||||||
|
///
|
||||||
|
/// The first character in the input and any characters immediately
|
||||||
|
/// following a newline character are in column 1.
|
||||||
|
///
|
||||||
|
/// Note that errors may occur in column 0, for example if a read from an IO
|
||||||
|
/// stream fails immediately following a previously read newline character.
|
||||||
|
pub fn column(&self) -> usize {
|
||||||
|
self.err.column
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Categorizes the cause of this error.
|
||||||
|
///
|
||||||
|
/// - `Category::Io` - failure to read or write bytes on an IO stream
|
||||||
|
/// - `Category::Syntax` - input that is not syntactically valid JSON
|
||||||
|
/// - `Category::Data` - input data that is semantically incorrect
|
||||||
|
/// - `Category::Eof` - unexpected end of the input data
|
||||||
|
pub fn classify(&self) -> Category {
|
||||||
|
match self.err.code {
|
||||||
|
ErrorCode::Message(_) => Category::Data,
|
||||||
|
ErrorCode::Io(_) => Category::Io,
|
||||||
|
ErrorCode::EofWhileParsingList
|
||||||
|
| ErrorCode::EofWhileParsingObject
|
||||||
|
| ErrorCode::EofWhileParsingString
|
||||||
|
| ErrorCode::EofWhileParsingValue => Category::Eof,
|
||||||
|
ErrorCode::ExpectedColon
|
||||||
|
| ErrorCode::ExpectedListCommaOrEnd
|
||||||
|
| ErrorCode::ExpectedObjectCommaOrEnd
|
||||||
|
| ErrorCode::ExpectedObjectOrArray
|
||||||
|
| ErrorCode::ExpectedSomeIdent
|
||||||
|
| ErrorCode::ExpectedSomeValue
|
||||||
|
| ErrorCode::ExpectedSomeString
|
||||||
|
| ErrorCode::InvalidEscape
|
||||||
|
| ErrorCode::InvalidNumber
|
||||||
|
| ErrorCode::NumberOutOfRange
|
||||||
|
| ErrorCode::InvalidUnicodeCodePoint
|
||||||
|
| ErrorCode::ControlCharacterWhileParsingString
|
||||||
|
| ErrorCode::KeyMustBeAString
|
||||||
|
| ErrorCode::LoneLeadingSurrogateInHexEscape
|
||||||
|
| ErrorCode::TrailingComma
|
||||||
|
| ErrorCode::TrailingCharacters
|
||||||
|
| ErrorCode::UnexpectedEndOfHexEscape
|
||||||
|
| ErrorCode::RecursionLimitExceeded => Category::Syntax,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this error was caused by a failure to read or write
|
||||||
|
/// bytes on an IO stream.
|
||||||
|
pub fn is_io(&self) -> bool {
|
||||||
|
self.classify() == Category::Io
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this error was caused by input that was not
|
||||||
|
/// syntactically valid JSON.
|
||||||
|
pub fn is_syntax(&self) -> bool {
|
||||||
|
self.classify() == Category::Syntax
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this error was caused by input data that was
|
||||||
|
/// semantically incorrect.
|
||||||
|
///
|
||||||
|
/// For example, JSON containing a number is semantically incorrect when the
|
||||||
|
/// type being deserialized into holds a String.
|
||||||
|
pub fn is_data(&self) -> bool {
|
||||||
|
self.classify() == Category::Data
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this error was caused by prematurely reaching the end of
|
||||||
|
/// the input data.
|
||||||
|
///
|
||||||
|
/// Callers that process streaming input may be interested in retrying the
|
||||||
|
/// deserialization once more data is available.
|
||||||
|
pub fn is_eof(&self) -> bool {
|
||||||
|
self.classify() == Category::Eof
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Categorizes the cause of a `serde_json::Error`.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum Category {
|
||||||
|
/// The error was caused by a failure to read or write bytes on an IO
|
||||||
|
/// stream.
|
||||||
|
Io,
|
||||||
|
|
||||||
|
/// The error was caused by input that was not syntactically valid JSON.
|
||||||
|
Syntax,
|
||||||
|
|
||||||
|
/// The error was caused by input data that was semantically incorrect.
|
||||||
|
///
|
||||||
|
/// For example, JSON containing a number is semantically incorrect when the
|
||||||
|
/// type being deserialized into holds a String.
|
||||||
|
Data,
|
||||||
|
|
||||||
|
/// The error was caused by prematurely reaching the end of the input data.
|
||||||
|
///
|
||||||
|
/// Callers that process streaming input may be interested in retrying the
|
||||||
|
/// deserialization once more data is available.
|
||||||
|
Eof,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
|
||||||
|
impl From<Error> for io::Error {
|
||||||
|
/// Convert a `serde_json::Error` into an `io::Error`.
|
||||||
|
///
|
||||||
|
/// JSON syntax and data errors are turned into `InvalidData` IO errors.
|
||||||
|
/// EOF errors are turned into `UnexpectedEof` IO errors.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// enum MyError {
|
||||||
|
/// Io(io::Error),
|
||||||
|
/// Json(serde_json::Error),
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl From<serde_json::Error> for MyError {
|
||||||
|
/// fn from(err: serde_json::Error) -> MyError {
|
||||||
|
/// use serde_json::error::Category;
|
||||||
|
/// match err.classify() {
|
||||||
|
/// Category::Io => {
|
||||||
|
/// MyError::Io(err.into())
|
||||||
|
/// }
|
||||||
|
/// Category::Syntax | Category::Data | Category::Eof => {
|
||||||
|
/// MyError::Json(err)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn from(j: Error) -> Self {
|
||||||
|
if let ErrorCode::Io(err) = j.err.code {
|
||||||
|
err
|
||||||
|
} else {
|
||||||
|
match j.classify() {
|
||||||
|
Category::Io => unreachable!(),
|
||||||
|
Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
|
||||||
|
Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ErrorImpl {
|
||||||
|
code: ErrorCode,
|
||||||
|
line: usize,
|
||||||
|
column: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub enum ErrorCode {
|
||||||
|
/// Catchall for syntax error messages
|
||||||
|
Message(Box<str>),
|
||||||
|
|
||||||
|
/// Some IO error occurred while serializing or deserializing.
|
||||||
|
Io(io::Error),
|
||||||
|
|
||||||
|
/// EOF while parsing a list.
|
||||||
|
EofWhileParsingList,
|
||||||
|
|
||||||
|
/// EOF while parsing an object.
|
||||||
|
EofWhileParsingObject,
|
||||||
|
|
||||||
|
/// EOF while parsing a string.
|
||||||
|
EofWhileParsingString,
|
||||||
|
|
||||||
|
/// EOF while parsing a JSON value.
|
||||||
|
EofWhileParsingValue,
|
||||||
|
|
||||||
|
/// Expected this character to be a `':'`.
|
||||||
|
ExpectedColon,
|
||||||
|
|
||||||
|
/// Expected this character to be either a `','` or a `']'`.
|
||||||
|
ExpectedListCommaOrEnd,
|
||||||
|
|
||||||
|
/// Expected this character to be either a `','` or a `'}'`.
|
||||||
|
ExpectedObjectCommaOrEnd,
|
||||||
|
|
||||||
|
/// Expected this character to be either a `'{'` or a `'['`.
|
||||||
|
ExpectedObjectOrArray,
|
||||||
|
|
||||||
|
/// Expected to parse either a `true`, `false`, or a `null`.
|
||||||
|
ExpectedSomeIdent,
|
||||||
|
|
||||||
|
/// Expected this character to start a JSON value.
|
||||||
|
ExpectedSomeValue,
|
||||||
|
|
||||||
|
/// Expected this character to start a JSON string.
|
||||||
|
ExpectedSomeString,
|
||||||
|
|
||||||
|
/// Invalid hex escape code.
|
||||||
|
InvalidEscape,
|
||||||
|
|
||||||
|
/// Invalid number.
|
||||||
|
InvalidNumber,
|
||||||
|
|
||||||
|
/// Number is bigger than the maximum value of its type.
|
||||||
|
NumberOutOfRange,
|
||||||
|
|
||||||
|
/// Invalid unicode code point.
|
||||||
|
InvalidUnicodeCodePoint,
|
||||||
|
|
||||||
|
/// Control character found while parsing a string.
|
||||||
|
ControlCharacterWhileParsingString,
|
||||||
|
|
||||||
|
/// Object key is not a string.
|
||||||
|
KeyMustBeAString,
|
||||||
|
|
||||||
|
/// Lone leading surrogate in hex escape.
|
||||||
|
LoneLeadingSurrogateInHexEscape,
|
||||||
|
|
||||||
|
/// JSON has a comma after the last value in an array or map.
|
||||||
|
TrailingComma,
|
||||||
|
|
||||||
|
/// JSON has non-whitespace trailing characters after the value.
|
||||||
|
TrailingCharacters,
|
||||||
|
|
||||||
|
/// Unexpected end of hex excape.
|
||||||
|
UnexpectedEndOfHexEscape,
|
||||||
|
|
||||||
|
/// Encountered nesting of JSON maps and arrays more than 128 layers deep.
|
||||||
|
RecursionLimitExceeded,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cold]
|
||||||
|
pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
|
||||||
|
Error {
|
||||||
|
err: Box::new(ErrorImpl {
|
||||||
|
code: code,
|
||||||
|
line: line,
|
||||||
|
column: column,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not public API. Should be pub(crate).
|
||||||
|
//
|
||||||
|
// Update `eager_json` crate when this function changes.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cold]
|
||||||
|
pub fn io(error: io::Error) -> Self {
|
||||||
|
Error {
|
||||||
|
err: Box::new(ErrorImpl {
|
||||||
|
code: ErrorCode::Io(error),
|
||||||
|
line: 0,
|
||||||
|
column: 0,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cold]
|
||||||
|
pub fn fix_position<F>(self, f: F) -> Self
|
||||||
|
where
|
||||||
|
F: FnOnce(ErrorCode) -> Error,
|
||||||
|
{
|
||||||
|
if self.err.line == 0 {
|
||||||
|
f(self.err.code)
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ErrorCode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
ErrorCode::Message(ref msg) => f.write_str(msg),
|
||||||
|
ErrorCode::Io(ref err) => Display::fmt(err, f),
|
||||||
|
ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
|
||||||
|
ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
|
||||||
|
ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
|
||||||
|
ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
|
||||||
|
ErrorCode::ExpectedColon => f.write_str("expected `:`"),
|
||||||
|
ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
|
||||||
|
ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
|
||||||
|
ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
|
||||||
|
ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
|
||||||
|
ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
|
||||||
|
ErrorCode::ExpectedSomeString => f.write_str("expected string"),
|
||||||
|
ErrorCode::InvalidEscape => f.write_str("invalid escape"),
|
||||||
|
ErrorCode::InvalidNumber => f.write_str("invalid number"),
|
||||||
|
ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
|
||||||
|
ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
|
||||||
|
ErrorCode::ControlCharacterWhileParsingString => {
|
||||||
|
f.write_str("control character (\\u0000-\\u001F) found while parsing a string")
|
||||||
|
}
|
||||||
|
ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
|
||||||
|
ErrorCode::LoneLeadingSurrogateInHexEscape => {
|
||||||
|
f.write_str("lone leading surrogate in hex escape")
|
||||||
|
}
|
||||||
|
ErrorCode::TrailingComma => f.write_str("trailing comma"),
|
||||||
|
ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
|
||||||
|
ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
|
||||||
|
ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match self.err.code {
|
||||||
|
ErrorCode::Io(ref err) => error::Error::description(err),
|
||||||
|
_ => {
|
||||||
|
// If you want a better message, use Display::fmt or to_string().
|
||||||
|
"JSON error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cause(&self) -> Option<&error::Error> {
|
||||||
|
match self.err.code {
|
||||||
|
ErrorCode::Io(ref err) => Some(err),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
Display::fmt(&*self.err, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ErrorImpl {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.line == 0 {
|
||||||
|
Display::fmt(&self.code, f)
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} at line {} column {}",
|
||||||
|
self.code, self.line, self.column
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove two layers of verbosity from the debug representation. Humans often
|
||||||
|
// end up seeing this representation because it is what unwrap() shows.
|
||||||
|
impl Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Error({:?}, line: {}, column: {})",
|
||||||
|
self.err.code.to_string(),
|
||||||
|
self.err.line,
|
||||||
|
self.err.column
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl de::Error for Error {
|
||||||
|
#[cold]
|
||||||
|
fn custom<T: Display>(msg: T) -> Error {
|
||||||
|
Error {
|
||||||
|
err: Box::new(ErrorImpl {
|
||||||
|
code: ErrorCode::Message(msg.to_string().into_boxed_str()),
|
||||||
|
line: 0,
|
||||||
|
column: 0,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
fn invalid_type(unexp: de::Unexpected, exp: &de::Expected) -> Self {
|
||||||
|
if let de::Unexpected::Unit = unexp {
|
||||||
|
Error::custom(format_args!("invalid type: null, expected {}", exp))
|
||||||
|
} else {
|
||||||
|
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ser::Error for Error {
|
||||||
|
#[cold]
|
||||||
|
fn custom<T: Display>(msg: T) -> Error {
|
||||||
|
Error {
|
||||||
|
err: Box::new(ErrorImpl {
|
||||||
|
code: ErrorCode::Message(msg.to_string().into_boxed_str()),
|
||||||
|
line: 0,
|
||||||
|
column: 0,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
third_party/rust/serde_json/src/iter.rs
vendored
Normal file
78
third_party/rust/serde_json/src/iter.rs
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub struct LineColIterator<I> {
|
||||||
|
iter: I,
|
||||||
|
|
||||||
|
/// Index of the current line. Characters in the first line of the input
|
||||||
|
/// (before the first newline character) are in line 1.
|
||||||
|
line: usize,
|
||||||
|
|
||||||
|
/// Index of the current column. The first character in the input and any
|
||||||
|
/// characters immediately following a newline character are in column 1.
|
||||||
|
/// The column is 0 immediately after a newline character has been read.
|
||||||
|
col: usize,
|
||||||
|
|
||||||
|
/// Byte offset of the start of the current line. This is the sum of lenghts
|
||||||
|
/// of all previous lines. Keeping track of things this way allows efficient
|
||||||
|
/// computation of the current line, column, and byte offset while only
|
||||||
|
/// updating one of the counters in `next()` in the common case.
|
||||||
|
start_of_line: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> LineColIterator<I>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = io::Result<u8>>,
|
||||||
|
{
|
||||||
|
pub fn new(iter: I) -> LineColIterator<I> {
|
||||||
|
LineColIterator {
|
||||||
|
iter: iter,
|
||||||
|
line: 1,
|
||||||
|
col: 0,
|
||||||
|
start_of_line: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn line(&self) -> usize {
|
||||||
|
self.line
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn col(&self) -> usize {
|
||||||
|
self.col
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn byte_offset(&self) -> usize {
|
||||||
|
self.start_of_line + self.col
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> Iterator for LineColIterator<I>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = io::Result<u8>>,
|
||||||
|
{
|
||||||
|
type Item = io::Result<u8>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<io::Result<u8>> {
|
||||||
|
match self.iter.next() {
|
||||||
|
None => None,
|
||||||
|
Some(Ok(b'\n')) => {
|
||||||
|
self.start_of_line += self.col + 1;
|
||||||
|
self.line += 1;
|
||||||
|
self.col = 0;
|
||||||
|
Some(Ok(b'\n'))
|
||||||
|
}
|
||||||
|
Some(Ok(c)) => {
|
||||||
|
self.col += 1;
|
||||||
|
Some(Ok(c))
|
||||||
|
}
|
||||||
|
Some(Err(e)) => Some(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
391
third_party/rust/serde_json/src/lib.rs
vendored
Normal file
391
third_party/rust/serde_json/src/lib.rs
vendored
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! # Serde JSON
|
||||||
|
//!
|
||||||
|
//! JSON is a ubiquitous open-standard format that uses human-readable text to
|
||||||
|
//! transmit data objects consisting of key-value pairs.
|
||||||
|
//!
|
||||||
|
//! ```json,ignore
|
||||||
|
//! {
|
||||||
|
//! "name": "John Doe",
|
||||||
|
//! "age": 43,
|
||||||
|
//! "address": {
|
||||||
|
//! "street": "10 Downing Street",
|
||||||
|
//! "city": "London"
|
||||||
|
//! },
|
||||||
|
//! "phones": [
|
||||||
|
//! "+44 1234567",
|
||||||
|
//! "+44 2345678"
|
||||||
|
//! ]
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! There are three common ways that you might find yourself needing to work
|
||||||
|
//! with JSON data in Rust.
|
||||||
|
//!
|
||||||
|
//! - **As text data.** An unprocessed string of JSON data that you receive on
|
||||||
|
//! an HTTP endpoint, read from a file, or prepare to send to a remote
|
||||||
|
//! server.
|
||||||
|
//! - **As an untyped or loosely typed representation.** Maybe you want to
|
||||||
|
//! check that some JSON data is valid before passing it on, but without
|
||||||
|
//! knowing the structure of what it contains. Or you want to do very basic
|
||||||
|
//! manipulations like insert a key in a particular spot.
|
||||||
|
//! - **As a strongly typed Rust data structure.** When you expect all or most
|
||||||
|
//! of your data to conform to a particular structure and want to get real
|
||||||
|
//! work done without JSON's loosey-goosey nature tripping you up.
|
||||||
|
//!
|
||||||
|
//! Serde JSON provides efficient, flexible, safe ways of converting data
|
||||||
|
//! between each of these representations.
|
||||||
|
//!
|
||||||
|
//! # Operating on untyped JSON values
|
||||||
|
//!
|
||||||
|
//! Any valid JSON data can be manipulated in the following recursive enum
|
||||||
|
//! representation. This data structure is [`serde_json::Value`][value].
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # use serde_json::{Number, Map};
|
||||||
|
//! #
|
||||||
|
//! # #[allow(dead_code)]
|
||||||
|
//! enum Value {
|
||||||
|
//! Null,
|
||||||
|
//! Bool(bool),
|
||||||
|
//! Number(Number),
|
||||||
|
//! String(String),
|
||||||
|
//! Array(Vec<Value>),
|
||||||
|
//! Object(Map<String, Value>),
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! A string of JSON data can be parsed into a `serde_json::Value` by the
|
||||||
|
//! [`serde_json::from_str`][from_str] function. There is also
|
||||||
|
//! [`from_slice`][from_slice] for parsing from a byte slice &[u8] and
|
||||||
|
//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or
|
||||||
|
//! a TCP stream.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! extern crate serde_json;
|
||||||
|
//!
|
||||||
|
//! use serde_json::{Value, Error};
|
||||||
|
//!
|
||||||
|
//! fn untyped_example() -> Result<(), Error> {
|
||||||
|
//! // Some JSON input data as a &str. Maybe this comes from the user.
|
||||||
|
//! let data = r#"{
|
||||||
|
//! "name": "John Doe",
|
||||||
|
//! "age": 43,
|
||||||
|
//! "phones": [
|
||||||
|
//! "+44 1234567",
|
||||||
|
//! "+44 2345678"
|
||||||
|
//! ]
|
||||||
|
//! }"#;
|
||||||
|
//!
|
||||||
|
//! // Parse the string of data into serde_json::Value.
|
||||||
|
//! let v: Value = serde_json::from_str(data)?;
|
||||||
|
//!
|
||||||
|
//! // Access parts of the data by indexing with square brackets.
|
||||||
|
//! println!("Please call {} at the number {}", v["name"], v["phones"][0]);
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! # untyped_example().unwrap();
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The result of square bracket indexing like `v["name"]` is a borrow of the
|
||||||
|
//! data at that index, so the type is `&Value`. A JSON map can be indexed with
|
||||||
|
//! string keys, while a JSON array can be indexed with integer keys. If the
|
||||||
|
//! type of the data is not right for the type with which it is being indexed,
|
||||||
|
//! or if a map does not contain the key being indexed, or if the index into a
|
||||||
|
//! vector is out of bounds, the returned element is `Value::Null`.
|
||||||
|
//!
|
||||||
|
//! When a `Value` is printed, it is printed as a JSON string. So in the code
|
||||||
|
//! above, the output looks like `Please call "John Doe" at the number "+44
|
||||||
|
//! 1234567"`. The quotation marks appear because `v["name"]` is a `&Value`
|
||||||
|
//! containing a JSON string and its JSON representation is `"John Doe"`.
|
||||||
|
//! Printing as a plain string without quotation marks involves converting from
|
||||||
|
//! a JSON string to a Rust string with [`as_str()`] or avoiding the use of
|
||||||
|
//! `Value` as described in the following section.
|
||||||
|
//!
|
||||||
|
//! [`as_str()`]: https://docs.serde.rs/serde_json/enum.Value.html#method.as_str
|
||||||
|
//!
|
||||||
|
//! The `Value` representation is sufficient for very basic tasks but can be
|
||||||
|
//! tedious to work with for anything more significant. Error handling is
|
||||||
|
//! verbose to implement correctly, for example imagine trying to detect the
|
||||||
|
//! presence of unrecognized fields in the input data. The compiler is powerless
|
||||||
|
//! to help you when you make a mistake, for example imagine typoing `v["name"]`
|
||||||
|
//! as `v["nmae"]` in one of the dozens of places it is used in your code.
|
||||||
|
//!
|
||||||
|
//! # Parsing JSON as strongly typed data structures
|
||||||
|
//!
|
||||||
|
//! Serde provides a powerful way of mapping JSON data into Rust data structures
|
||||||
|
//! largely automatically.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! extern crate serde;
|
||||||
|
//! extern crate serde_json;
|
||||||
|
//!
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate serde_derive;
|
||||||
|
//!
|
||||||
|
//! use serde_json::Error;
|
||||||
|
//!
|
||||||
|
//! #[derive(Serialize, Deserialize)]
|
||||||
|
//! struct Person {
|
||||||
|
//! name: String,
|
||||||
|
//! age: u8,
|
||||||
|
//! phones: Vec<String>,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn typed_example() -> Result<(), Error> {
|
||||||
|
//! // Some JSON input data as a &str. Maybe this comes from the user.
|
||||||
|
//! let data = r#"{
|
||||||
|
//! "name": "John Doe",
|
||||||
|
//! "age": 43,
|
||||||
|
//! "phones": [
|
||||||
|
//! "+44 1234567",
|
||||||
|
//! "+44 2345678"
|
||||||
|
//! ]
|
||||||
|
//! }"#;
|
||||||
|
//!
|
||||||
|
//! // Parse the string of data into a Person object. This is exactly the
|
||||||
|
//! // same function as the one that produced serde_json::Value above, but
|
||||||
|
//! // now we are asking it for a Person as output.
|
||||||
|
//! let p: Person = serde_json::from_str(data)?;
|
||||||
|
//!
|
||||||
|
//! // Do things just like with any other Rust data structure.
|
||||||
|
//! println!("Please call {} at the number {}", p.name, p.phones[0]);
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! # typed_example().unwrap();
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! This is the same `serde_json::from_str` function as before, but this time we
|
||||||
|
//! assign the return value to a variable of type `Person` so Serde will
|
||||||
|
//! automatically interpret the input data as a `Person` and produce informative
|
||||||
|
//! error messages if the layout does not conform to what a `Person` is expected
|
||||||
|
//! to look like.
|
||||||
|
//!
|
||||||
|
//! Any type that implements Serde's `Deserialize` trait can be deserialized
|
||||||
|
//! this way. This includes built-in Rust standard library types like `Vec<T>`
|
||||||
|
//! and `HashMap<K, V>`, as well as any structs or enums annotated with
|
||||||
|
//! `#[derive(Deserialize)]`.
|
||||||
|
//!
|
||||||
|
//! Once we have `p` of type `Person`, our IDE and the Rust compiler can help us
|
||||||
|
//! use it correctly like they do for any other Rust code. The IDE can
|
||||||
|
//! autocomplete field names to prevent typos, which was impossible in the
|
||||||
|
//! `serde_json::Value` representation. And the Rust compiler can check that
|
||||||
|
//! when we write `p.phones[0]`, then `p.phones` is guaranteed to be a
|
||||||
|
//! `Vec<String>` so indexing into it makes sense and produces a `String`.
|
||||||
|
//!
|
||||||
|
//! # Constructing JSON values
|
||||||
|
//!
|
||||||
|
//! Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value`
|
||||||
|
//! objects with very natural JSON syntax. In order to use this macro,
|
||||||
|
//! `serde_json` needs to be imported with the `#[macro_use]` attribute.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate serde_json;
|
||||||
|
//!
|
||||||
|
//! fn main() {
|
||||||
|
//! // The type of `john` is `serde_json::Value`
|
||||||
|
//! let john = json!({
|
||||||
|
//! "name": "John Doe",
|
||||||
|
//! "age": 43,
|
||||||
|
//! "phones": [
|
||||||
|
//! "+44 1234567",
|
||||||
|
//! "+44 2345678"
|
||||||
|
//! ]
|
||||||
|
//! });
|
||||||
|
//!
|
||||||
|
//! println!("first phone number: {}", john["phones"][0]);
|
||||||
|
//!
|
||||||
|
//! // Convert to a string of JSON and print it out
|
||||||
|
//! println!("{}", john.to_string());
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The `Value::to_string()` function converts a `serde_json::Value` into a
|
||||||
|
//! `String` of JSON text.
|
||||||
|
//!
|
||||||
|
//! One neat thing about the `json!` macro is that variables and expressions can
|
||||||
|
//! be interpolated directly into the JSON value as you are building it. Serde
|
||||||
|
//! will check at compile time that the value you are interpolating is able to
|
||||||
|
//! be represented as JSON.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # #[macro_use]
|
||||||
|
//! # extern crate serde_json;
|
||||||
|
//! #
|
||||||
|
//! # fn random_phone() -> u16 { 0 }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! let full_name = "John Doe";
|
||||||
|
//! let age_last_year = 42;
|
||||||
|
//!
|
||||||
|
//! // The type of `john` is `serde_json::Value`
|
||||||
|
//! let john = json!({
|
||||||
|
//! "name": full_name,
|
||||||
|
//! "age": age_last_year + 1,
|
||||||
|
//! "phones": [
|
||||||
|
//! format!("+44 {}", random_phone())
|
||||||
|
//! ]
|
||||||
|
//! });
|
||||||
|
//! # let _ = john;
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! This is amazingly convenient but we have the problem we had before with
|
||||||
|
//! `Value` which is that the IDE and Rust compiler cannot help us if we get it
|
||||||
|
//! wrong. Serde JSON provides a better way of serializing strongly-typed data
|
||||||
|
//! structures into JSON text.
|
||||||
|
//!
|
||||||
|
//! # Creating JSON by serializing data structures
|
||||||
|
//!
|
||||||
|
//! A data structure can be converted to a JSON string by
|
||||||
|
//! [`serde_json::to_string`][to_string]. There is also
|
||||||
|
//! [`serde_json::to_vec`][to_vec] which serializes to a `Vec<u8>` and
|
||||||
|
//! [`serde_json::to_writer`][to_writer] which serializes to any `io::Write`
|
||||||
|
//! such as a File or a TCP stream.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! extern crate serde;
|
||||||
|
//! extern crate serde_json;
|
||||||
|
//!
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate serde_derive;
|
||||||
|
//!
|
||||||
|
//! use serde_json::Error;
|
||||||
|
//!
|
||||||
|
//! #[derive(Serialize, Deserialize)]
|
||||||
|
//! struct Address {
|
||||||
|
//! street: String,
|
||||||
|
//! city: String,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn print_an_address() -> Result<(), Error> {
|
||||||
|
//! // Some data structure.
|
||||||
|
//! let address = Address {
|
||||||
|
//! street: "10 Downing Street".to_owned(),
|
||||||
|
//! city: "London".to_owned(),
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! // Serialize it to a JSON string.
|
||||||
|
//! let j = serde_json::to_string(&address)?;
|
||||||
|
//!
|
||||||
|
//! // Print, write to a file, or send to an HTTP server.
|
||||||
|
//! println!("{}", j);
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! # print_an_address().unwrap();
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Any type that implements Serde's `Serialize` trait can be serialized this
|
||||||
|
//! way. This includes built-in Rust standard library types like `Vec<T>` and
|
||||||
|
//! `HashMap<K, V>`, as well as any structs or enums annotated with
|
||||||
|
//! `#[derive(Serialize)]`.
|
||||||
|
//!
|
||||||
|
//! # No-std support
|
||||||
|
//!
|
||||||
|
//! This crate currently requires the Rust standard library. For JSON support in
|
||||||
|
//! Serde without a standard library, please see the [`serde-json-core`] crate.
|
||||||
|
//!
|
||||||
|
//! [value]: https://docs.serde.rs/serde_json/value/enum.Value.html
|
||||||
|
//! [from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html
|
||||||
|
//! [from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html
|
||||||
|
//! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html
|
||||||
|
//! [to_string]: https://docs.serde.rs/serde_json/ser/fn.to_string.html
|
||||||
|
//! [to_vec]: https://docs.serde.rs/serde_json/ser/fn.to_vec.html
|
||||||
|
//! [to_writer]: https://docs.serde.rs/serde_json/ser/fn.to_writer.html
|
||||||
|
//! [macro]: https://docs.serde.rs/serde_json/macro.json.html
|
||||||
|
//! [`serde-json-core`]: https://japaric.github.io/serde-json-core/serde_json_core/
|
||||||
|
|
||||||
|
#![doc(html_root_url = "https://docs.rs/serde_json/1.0.26")]
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||||
|
// Whitelisted clippy lints
|
||||||
|
#![cfg_attr(
|
||||||
|
feature = "cargo-clippy",
|
||||||
|
allow(doc_markdown, needless_pass_by_value)
|
||||||
|
)]
|
||||||
|
// Whitelisted clippy_pedantic lints
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||||
|
// Deserializer::from_str, into_iter
|
||||||
|
should_implement_trait,
|
||||||
|
// integer and float ser/de requires these sorts of casts
|
||||||
|
cast_possible_truncation,
|
||||||
|
cast_possible_wrap,
|
||||||
|
cast_precision_loss,
|
||||||
|
cast_sign_loss,
|
||||||
|
// string ser/de uses indexing and slicing
|
||||||
|
indexing_slicing,
|
||||||
|
// things are often more readable this way
|
||||||
|
cast_lossless,
|
||||||
|
shadow_reuse,
|
||||||
|
shadow_unrelated,
|
||||||
|
single_match_else,
|
||||||
|
stutter,
|
||||||
|
use_self,
|
||||||
|
// not practical
|
||||||
|
missing_docs_in_private_items,
|
||||||
|
similar_names,
|
||||||
|
// we support older compilers
|
||||||
|
redundant_field_names,
|
||||||
|
))]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde;
|
||||||
|
extern crate ryu;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
extern crate indexmap;
|
||||||
|
extern crate itoa;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use self::de::{from_reader, from_slice, from_str, Deserializer, StreamDeserializer};
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use self::error::{Error, Result};
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use self::ser::{
|
||||||
|
to_string, to_string_pretty, to_vec, to_vec_pretty, to_writer, to_writer_pretty, Serializer,
|
||||||
|
};
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use self::value::{from_value, to_value, Map, Number, Value};
|
||||||
|
|
||||||
|
// We only use our own error type; no need for From conversions provided by the
|
||||||
|
// standard library's try! macro. This reduces lines of LLVM IR by 4%.
|
||||||
|
macro_rules! try {
|
||||||
|
($e:expr) => {
|
||||||
|
match $e {
|
||||||
|
::std::result::Result::Ok(val) => val,
|
||||||
|
::std::result::Result::Err(err) => return ::std::result::Result::Err(err),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
|
pub mod de;
|
||||||
|
pub mod error;
|
||||||
|
pub mod map;
|
||||||
|
pub mod ser;
|
||||||
|
pub mod value;
|
||||||
|
|
||||||
|
mod iter;
|
||||||
|
mod number;
|
||||||
|
mod read;
|
309
third_party/rust/serde_json/src/macros.rs
vendored
Normal file
309
third_party/rust/serde_json/src/macros.rs
vendored
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
/// Construct a `serde_json::Value` from a JSON literal.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let value = json!({
|
||||||
|
/// "code": 200,
|
||||||
|
/// "success": true,
|
||||||
|
/// "payload": {
|
||||||
|
/// "features": [
|
||||||
|
/// "serde",
|
||||||
|
/// "json"
|
||||||
|
/// ]
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Variables or expressions can be interpolated into the JSON literal. Any type
|
||||||
|
/// interpolated into an array element or object value must implement Serde's
|
||||||
|
/// `Serialize` trait, while any type interpolated into a object key must
|
||||||
|
/// implement `Into<String>`. If the `Serialize` implementation of the
|
||||||
|
/// interpolated type decides to fail, or if the interpolated type contains a
|
||||||
|
/// map with non-string keys, the `json!` macro will panic.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let code = 200;
|
||||||
|
/// let features = vec!["serde", "json"];
|
||||||
|
///
|
||||||
|
/// let value = json!({
|
||||||
|
/// "code": code,
|
||||||
|
/// "success": code == 200,
|
||||||
|
/// "payload": {
|
||||||
|
/// features[0]: features[1]
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Trailing commas are allowed inside both arrays and objects.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let value = json!([
|
||||||
|
/// "notice",
|
||||||
|
/// "the",
|
||||||
|
/// "trailing",
|
||||||
|
/// "comma -->",
|
||||||
|
/// ]);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[macro_export(local_inner_macros)]
|
||||||
|
macro_rules! json {
|
||||||
|
// Hide distracting implementation details from the generated rustdoc.
|
||||||
|
($($json:tt)+) => {
|
||||||
|
json_internal!($($json)+)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rocket relies on this because they export their own `json!` with a different
|
||||||
|
// doc comment than ours, and various Rust bugs prevent them from calling our
|
||||||
|
// `json!` from their `json!` so they call `json_internal!` directly. Check with
|
||||||
|
// @SergioBenitez before making breaking changes to this macro.
|
||||||
|
//
|
||||||
|
// Changes are fine as long as `json_internal!` does not call any new helper
|
||||||
|
// macros and can still be invoked as `json_internal!($($json)+)`.
|
||||||
|
#[macro_export(local_inner_macros)]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! json_internal {
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// TT muncher for parsing the inside of an array [...]. Produces a vec![...]
|
||||||
|
// of the elements.
|
||||||
|
//
|
||||||
|
// Must be invoked as: json_internal!(@array [] $($tt)*)
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Done with trailing comma.
|
||||||
|
(@array [$($elems:expr,)*]) => {
|
||||||
|
json_internal_vec![$($elems,)*]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Done without trailing comma.
|
||||||
|
(@array [$($elems:expr),*]) => {
|
||||||
|
json_internal_vec![$($elems),*]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next element is `null`.
|
||||||
|
(@array [$($elems:expr,)*] null $($rest:tt)*) => {
|
||||||
|
json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next element is `true`.
|
||||||
|
(@array [$($elems:expr,)*] true $($rest:tt)*) => {
|
||||||
|
json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next element is `false`.
|
||||||
|
(@array [$($elems:expr,)*] false $($rest:tt)*) => {
|
||||||
|
json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next element is an array.
|
||||||
|
(@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
|
||||||
|
json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next element is a map.
|
||||||
|
(@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
|
||||||
|
json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next element is an expression followed by comma.
|
||||||
|
(@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
|
||||||
|
json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Last element is an expression with no trailing comma.
|
||||||
|
(@array [$($elems:expr,)*] $last:expr) => {
|
||||||
|
json_internal!(@array [$($elems,)* json_internal!($last)])
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comma after the most recent element.
|
||||||
|
(@array [$($elems:expr),*] , $($rest:tt)*) => {
|
||||||
|
json_internal!(@array [$($elems,)*] $($rest)*)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unexpected token after most recent element.
|
||||||
|
(@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
|
||||||
|
json_unexpected!($unexpected)
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// TT muncher for parsing the inside of an object {...}. Each entry is
|
||||||
|
// inserted into the given map variable.
|
||||||
|
//
|
||||||
|
// Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*))
|
||||||
|
//
|
||||||
|
// We require two copies of the input tokens so that we can match on one
|
||||||
|
// copy and trigger errors on the other copy.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Done.
|
||||||
|
(@object $object:ident () () ()) => {};
|
||||||
|
|
||||||
|
// Insert the current entry followed by trailing comma.
|
||||||
|
(@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
|
||||||
|
let _ = $object.insert(($($key)+).into(), $value);
|
||||||
|
json_internal!(@object $object () ($($rest)*) ($($rest)*));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Current entry followed by unexpected token.
|
||||||
|
(@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
|
||||||
|
json_unexpected!($unexpected);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert the last entry without trailing comma.
|
||||||
|
(@object $object:ident [$($key:tt)+] ($value:expr)) => {
|
||||||
|
let _ = $object.insert(($($key)+).into(), $value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next value is `null`.
|
||||||
|
(@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next value is `true`.
|
||||||
|
(@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next value is `false`.
|
||||||
|
(@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next value is an array.
|
||||||
|
(@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next value is a map.
|
||||||
|
(@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Next value is an expression followed by comma.
|
||||||
|
(@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Last value is an expression with no trailing comma.
|
||||||
|
(@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
|
||||||
|
json_internal!(@object $object [$($key)+] (json_internal!($value)));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Missing value for last entry. Trigger a reasonable error message.
|
||||||
|
(@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
|
||||||
|
// "unexpected end of macro invocation"
|
||||||
|
json_internal!();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Missing colon and value for last entry. Trigger a reasonable error
|
||||||
|
// message.
|
||||||
|
(@object $object:ident ($($key:tt)+) () $copy:tt) => {
|
||||||
|
// "unexpected end of macro invocation"
|
||||||
|
json_internal!();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Misplaced colon. Trigger a reasonable error message.
|
||||||
|
(@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
|
||||||
|
// Takes no arguments so "no rules expected the token `:`".
|
||||||
|
json_unexpected!($colon);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Found a comma inside a key. Trigger a reasonable error message.
|
||||||
|
(@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
|
||||||
|
// Takes no arguments so "no rules expected the token `,`".
|
||||||
|
json_unexpected!($comma);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Key is fully parenthesized. This avoids clippy double_parens false
|
||||||
|
// positives because the parenthesization may be necessary here.
|
||||||
|
(@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Munch a token into the current key.
|
||||||
|
(@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
|
||||||
|
json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*));
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// The main implementation.
|
||||||
|
//
|
||||||
|
// Must be invoked as: json_internal!($($json)+)
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
(null) => {
|
||||||
|
$crate::Value::Null
|
||||||
|
};
|
||||||
|
|
||||||
|
(true) => {
|
||||||
|
$crate::Value::Bool(true)
|
||||||
|
};
|
||||||
|
|
||||||
|
(false) => {
|
||||||
|
$crate::Value::Bool(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
([]) => {
|
||||||
|
$crate::Value::Array(json_internal_vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
([ $($tt:tt)+ ]) => {
|
||||||
|
$crate::Value::Array(json_internal!(@array [] $($tt)+))
|
||||||
|
};
|
||||||
|
|
||||||
|
({}) => {
|
||||||
|
$crate::Value::Object($crate::Map::new())
|
||||||
|
};
|
||||||
|
|
||||||
|
({ $($tt:tt)+ }) => {
|
||||||
|
$crate::Value::Object({
|
||||||
|
let mut object = $crate::Map::new();
|
||||||
|
json_internal!(@object object () ($($tt)+) ($($tt)+));
|
||||||
|
object
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Any Serialize type: numbers, strings, struct literals, variables etc.
|
||||||
|
// Must be below every other rule.
|
||||||
|
($other:expr) => {
|
||||||
|
$crate::to_value(&$other).unwrap()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The json_internal macro above cannot invoke vec directly because it uses
|
||||||
|
// local_inner_macros. A vec invocation there would resolve to $crate::vec.
|
||||||
|
// Instead invoke vec here outside of local_inner_macros.
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! json_internal_vec {
|
||||||
|
($($content:tt)*) => {
|
||||||
|
vec![$($content)*]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! json_unexpected {
|
||||||
|
() => {};
|
||||||
|
}
|
852
third_party/rust/serde_json/src/map.rs
vendored
Normal file
852
third_party/rust/serde_json/src/map.rs
vendored
Normal file
@ -0,0 +1,852 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! A map of String to serde_json::Value.
|
||||||
|
//!
|
||||||
|
//! By default the map is backed by a [`BTreeMap`]. Enable the `preserve_order`
|
||||||
|
//! feature of serde_json to use [`IndexMap`] instead.
|
||||||
|
//!
|
||||||
|
//! [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
|
||||||
|
//! [`IndexMap`]: https://docs.rs/indexmap/*/indexmap/map/struct.IndexMap.html
|
||||||
|
|
||||||
|
use serde::{de, ser};
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use std::ops;
|
||||||
|
use value::Value;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
use std::collections::{btree_map, BTreeMap};
|
||||||
|
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
use indexmap::{self, IndexMap};
|
||||||
|
|
||||||
|
/// Represents a JSON key/value type.
|
||||||
|
pub struct Map<K, V> {
|
||||||
|
map: MapImpl<K, V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type MapImpl<K, V> = BTreeMap<K, V>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type MapImpl<K, V> = IndexMap<K, V>;
|
||||||
|
|
||||||
|
impl Map<String, Value> {
|
||||||
|
/// Makes a new empty Map.
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Map {
|
||||||
|
map: MapImpl::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
/// Makes a new empty Map with the given initial capacity.
|
||||||
|
#[inline]
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
// does not support with_capacity
|
||||||
|
let _ = capacity;
|
||||||
|
Map {
|
||||||
|
map: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
/// Makes a new empty Map with the given initial capacity.
|
||||||
|
#[inline]
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Map {
|
||||||
|
map: IndexMap::with_capacity(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the map, removing all values.
|
||||||
|
#[inline]
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.map.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the value corresponding to the key.
|
||||||
|
///
|
||||||
|
/// The key may be any borrowed form of the map's key type, but the ordering
|
||||||
|
/// on the borrowed form *must* match the ordering on the key type.
|
||||||
|
#[inline]
|
||||||
|
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&Value>
|
||||||
|
where
|
||||||
|
String: Borrow<Q>,
|
||||||
|
Q: Ord + Eq + Hash,
|
||||||
|
{
|
||||||
|
self.map.get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the map contains a value for the specified key.
|
||||||
|
///
|
||||||
|
/// The key may be any borrowed form of the map's key type, but the ordering
|
||||||
|
/// on the borrowed form *must* match the ordering on the key type.
|
||||||
|
#[inline]
|
||||||
|
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
|
||||||
|
where
|
||||||
|
String: Borrow<Q>,
|
||||||
|
Q: Ord + Eq + Hash,
|
||||||
|
{
|
||||||
|
self.map.contains_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the value corresponding to the key.
|
||||||
|
///
|
||||||
|
/// The key may be any borrowed form of the map's key type, but the ordering
|
||||||
|
/// on the borrowed form *must* match the ordering on the key type.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut Value>
|
||||||
|
where
|
||||||
|
String: Borrow<Q>,
|
||||||
|
Q: Ord + Eq + Hash,
|
||||||
|
{
|
||||||
|
self.map.get_mut(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts a key-value pair into the map.
|
||||||
|
///
|
||||||
|
/// If the map did not have this key present, `None` is returned.
|
||||||
|
///
|
||||||
|
/// If the map did have this key present, the value is updated, and the old
|
||||||
|
/// value is returned.
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, k: String, v: Value) -> Option<Value> {
|
||||||
|
self.map.insert(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes a key from the map, returning the value at the key if the key
|
||||||
|
/// was previously in the map.
|
||||||
|
///
|
||||||
|
/// The key may be any borrowed form of the map's key type, but the ordering
|
||||||
|
/// on the borrowed form *must* match the ordering on the key type.
|
||||||
|
#[inline]
|
||||||
|
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<Value>
|
||||||
|
where
|
||||||
|
String: Borrow<Q>,
|
||||||
|
Q: Ord + Eq + Hash,
|
||||||
|
{
|
||||||
|
self.map.remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the given key's corresponding entry in the map for in-place
|
||||||
|
/// manipulation.
|
||||||
|
pub fn entry<S>(&mut self, key: S) -> Entry
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
use indexmap::map::Entry as EntryImpl;
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
use std::collections::btree_map::Entry as EntryImpl;
|
||||||
|
|
||||||
|
match self.map.entry(key.into()) {
|
||||||
|
EntryImpl::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant: vacant }),
|
||||||
|
EntryImpl::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied: occupied }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of elements in the map.
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.map.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the map contains no elements.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.map.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an iterator over the entries of the map.
|
||||||
|
#[inline]
|
||||||
|
pub fn iter(&self) -> Iter {
|
||||||
|
Iter {
|
||||||
|
iter: self.map.iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable iterator over the entries of the map.
|
||||||
|
#[inline]
|
||||||
|
pub fn iter_mut(&mut self) -> IterMut {
|
||||||
|
IterMut {
|
||||||
|
iter: self.map.iter_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an iterator over the keys of the map.
|
||||||
|
#[inline]
|
||||||
|
pub fn keys(&self) -> Keys {
|
||||||
|
Keys {
|
||||||
|
iter: self.map.keys(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an iterator over the values of the map.
|
||||||
|
#[inline]
|
||||||
|
pub fn values(&self) -> Values {
|
||||||
|
Values {
|
||||||
|
iter: self.map.values(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an iterator over mutable values of the map.
|
||||||
|
#[inline]
|
||||||
|
pub fn values_mut(&mut self) -> ValuesMut {
|
||||||
|
ValuesMut {
|
||||||
|
iter: self.map.values_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Map<String, Value> {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Map {
|
||||||
|
map: MapImpl::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Map<String, Value> {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Map {
|
||||||
|
map: self.map.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Map<String, Value> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
if cfg!(feature = "preserve_order") {
|
||||||
|
if self.len() != other.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iter()
|
||||||
|
.all(|(key, value)| other.get(key).map_or(false, |v| *value == *v))
|
||||||
|
} else {
|
||||||
|
self.map.eq(&other.map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access an element of this map. Panics if the given key is not present in the
|
||||||
|
/// map.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use serde_json::Value;
|
||||||
|
/// #
|
||||||
|
/// # let val = &Value::String("".to_owned());
|
||||||
|
/// # let _ =
|
||||||
|
/// match *val {
|
||||||
|
/// Value::String(ref s) => Some(s.as_str()),
|
||||||
|
/// Value::Array(ref arr) => arr[0].as_str(),
|
||||||
|
/// Value::Object(ref map) => map["type"].as_str(),
|
||||||
|
/// _ => None,
|
||||||
|
/// }
|
||||||
|
/// # ;
|
||||||
|
/// ```
|
||||||
|
impl<'a, Q: ?Sized> ops::Index<&'a Q> for Map<String, Value>
|
||||||
|
where
|
||||||
|
String: Borrow<Q>,
|
||||||
|
Q: Ord + Eq + Hash,
|
||||||
|
{
|
||||||
|
type Output = Value;
|
||||||
|
|
||||||
|
fn index(&self, index: &Q) -> &Value {
|
||||||
|
self.map.index(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutably access an element of this map. Panics if the given key is not
|
||||||
|
/// present in the map.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// # let mut map = serde_json::Map::new();
|
||||||
|
/// # map.insert("key".to_owned(), serde_json::Value::Null);
|
||||||
|
/// #
|
||||||
|
/// map["key"] = json!("value");
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
impl<'a, Q: ?Sized> ops::IndexMut<&'a Q> for Map<String, Value>
|
||||||
|
where
|
||||||
|
String: Borrow<Q>,
|
||||||
|
Q: Ord + Eq + Hash,
|
||||||
|
{
|
||||||
|
fn index_mut(&mut self, index: &Q) -> &mut Value {
|
||||||
|
self.map.get_mut(index).expect("no entry found for key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Map<String, Value> {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
self.map.fmt(formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ser::Serialize for Map<String, Value> {
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: ser::Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeMap;
|
||||||
|
let mut map = try!(serializer.serialize_map(Some(self.len())));
|
||||||
|
for (k, v) in self {
|
||||||
|
try!(map.serialize_key(k));
|
||||||
|
try!(map.serialize_value(v));
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> de::Deserialize<'de> for Map<String, Value> {
|
||||||
|
#[inline]
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct Visitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for Visitor {
|
||||||
|
type Value = Map<String, Value>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a map")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(Map::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||||
|
where
|
||||||
|
V: de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut values = Map::new();
|
||||||
|
|
||||||
|
while let Some((key, value)) = try!(visitor.next_entry()) {
|
||||||
|
values.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_map(Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromIterator<(String, Value)> for Map<String, Value> {
|
||||||
|
fn from_iter<T>(iter: T) -> Self
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = (String, Value)>,
|
||||||
|
{
|
||||||
|
Map {
|
||||||
|
map: FromIterator::from_iter(iter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Extend<(String, Value)> for Map<String, Value> {
|
||||||
|
fn extend<T>(&mut self, iter: T)
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = (String, Value)>,
|
||||||
|
{
|
||||||
|
self.map.extend(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! delegate_iterator {
|
||||||
|
(($name:ident $($generics:tt)*) => $item:ty) => {
|
||||||
|
impl $($generics)* Iterator for $name $($generics)* {
|
||||||
|
type Item = $item;
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.iter.next()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.iter.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $($generics)* DoubleEndedIterator for $name $($generics)* {
|
||||||
|
#[inline]
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.iter.next_back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $($generics)* ExactSizeIterator for $name $($generics)* {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.iter.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// A view into a single entry in a map, which may either be vacant or occupied.
|
||||||
|
/// This enum is constructed from the [`entry`] method on [`Map`].
|
||||||
|
///
|
||||||
|
/// [`entry`]: struct.Map.html#method.entry
|
||||||
|
/// [`Map`]: struct.Map.html
|
||||||
|
pub enum Entry<'a> {
|
||||||
|
/// A vacant Entry.
|
||||||
|
Vacant(VacantEntry<'a>),
|
||||||
|
/// An occupied Entry.
|
||||||
|
Occupied(OccupiedEntry<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A vacant Entry. It is part of the [`Entry`] enum.
|
||||||
|
///
|
||||||
|
/// [`Entry`]: enum.Entry.html
|
||||||
|
pub struct VacantEntry<'a> {
|
||||||
|
vacant: VacantEntryImpl<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An occupied Entry. It is part of the [`Entry`] enum.
|
||||||
|
///
|
||||||
|
/// [`Entry`]: enum.Entry.html
|
||||||
|
pub struct OccupiedEntry<'a> {
|
||||||
|
occupied: OccupiedEntryImpl<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type VacantEntryImpl<'a> = btree_map::VacantEntry<'a, String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type VacantEntryImpl<'a> = indexmap::map::VacantEntry<'a, String, Value>;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type OccupiedEntryImpl<'a> = btree_map::OccupiedEntry<'a, String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type OccupiedEntryImpl<'a> = indexmap::map::OccupiedEntry<'a, String, Value>;
|
||||||
|
|
||||||
|
impl<'a> Entry<'a> {
|
||||||
|
/// Returns a reference to this entry's key.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// assert_eq!(map.entry("serde").key(), &"serde");
|
||||||
|
/// ```
|
||||||
|
pub fn key(&self) -> &String {
|
||||||
|
match *self {
|
||||||
|
Entry::Vacant(ref e) => e.key(),
|
||||||
|
Entry::Occupied(ref e) => e.key(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures a value is in the entry by inserting the default if empty, and
|
||||||
|
/// returns a mutable reference to the value in the entry.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.entry("serde").or_insert(json!(12));
|
||||||
|
///
|
||||||
|
/// assert_eq!(map["serde"], 12);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn or_insert(self, default: Value) -> &'a mut Value {
|
||||||
|
match self {
|
||||||
|
Entry::Vacant(entry) => entry.insert(default),
|
||||||
|
Entry::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures a value is in the entry by inserting the result of the default
|
||||||
|
/// function if empty, and returns a mutable reference to the value in the
|
||||||
|
/// entry.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.entry("serde").or_insert_with(|| json!("hoho"));
|
||||||
|
///
|
||||||
|
/// assert_eq!(map["serde"], "hoho".to_owned());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn or_insert_with<F>(self, default: F) -> &'a mut Value
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Value,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Entry::Vacant(entry) => entry.insert(default()),
|
||||||
|
Entry::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VacantEntry<'a> {
|
||||||
|
/// Gets a reference to the key that would be used when inserting a value
|
||||||
|
/// through the VacantEntry.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Vacant(vacant) => {
|
||||||
|
/// assert_eq!(vacant.key(), &"serde");
|
||||||
|
/// }
|
||||||
|
/// Entry::Occupied(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn key(&self) -> &String {
|
||||||
|
self.vacant.key()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the value of the entry with the VacantEntry's key, and returns a
|
||||||
|
/// mutable reference to it.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Vacant(vacant) => {
|
||||||
|
/// vacant.insert(json!("hoho"));
|
||||||
|
/// }
|
||||||
|
/// Entry::Occupied(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(self, value: Value) -> &'a mut Value {
|
||||||
|
self.vacant.insert(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> OccupiedEntry<'a> {
|
||||||
|
/// Gets a reference to the key in the entry.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.insert("serde".to_owned(), json!(12));
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Occupied(occupied) => {
|
||||||
|
/// assert_eq!(occupied.key(), &"serde");
|
||||||
|
/// }
|
||||||
|
/// Entry::Vacant(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn key(&self) -> &String {
|
||||||
|
self.occupied.key()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a reference to the value in the entry.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.insert("serde".to_owned(), json!(12));
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Occupied(occupied) => {
|
||||||
|
/// assert_eq!(occupied.get(), 12);
|
||||||
|
/// }
|
||||||
|
/// Entry::Vacant(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn get(&self) -> &Value {
|
||||||
|
self.occupied.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable reference to the value in the entry.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.insert("serde".to_owned(), json!([1, 2, 3]));
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Occupied(mut occupied) => {
|
||||||
|
/// occupied.get_mut().as_array_mut().unwrap().push(json!(4));
|
||||||
|
/// }
|
||||||
|
/// Entry::Vacant(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(map["serde"].as_array().unwrap().len(), 4);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mut(&mut self) -> &mut Value {
|
||||||
|
self.occupied.get_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the entry into a mutable reference to its value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.insert("serde".to_owned(), json!([1, 2, 3]));
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Occupied(mut occupied) => {
|
||||||
|
/// occupied.into_mut().as_array_mut().unwrap().push(json!(4));
|
||||||
|
/// }
|
||||||
|
/// Entry::Vacant(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(map["serde"].as_array().unwrap().len(), 4);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn into_mut(self) -> &'a mut Value {
|
||||||
|
self.occupied.into_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the value of the entry with the `OccupiedEntry`'s key, and returns
|
||||||
|
/// the entry's old value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.insert("serde".to_owned(), json!(12));
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Occupied(mut occupied) => {
|
||||||
|
/// assert_eq!(occupied.insert(json!(13)), 12);
|
||||||
|
/// assert_eq!(occupied.get(), 13);
|
||||||
|
/// }
|
||||||
|
/// Entry::Vacant(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, value: Value) -> Value {
|
||||||
|
self.occupied.insert(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the value of the entry out of the map, and returns it.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut map = serde_json::Map::new();
|
||||||
|
/// map.insert("serde".to_owned(), json!(12));
|
||||||
|
///
|
||||||
|
/// match map.entry("serde") {
|
||||||
|
/// Entry::Occupied(occupied) => {
|
||||||
|
/// assert_eq!(occupied.remove(), 12);
|
||||||
|
/// }
|
||||||
|
/// Entry::Vacant(_) => unimplemented!(),
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn remove(self) -> Value {
|
||||||
|
self.occupied.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a Map<String, Value> {
|
||||||
|
type Item = (&'a String, &'a Value);
|
||||||
|
type IntoIter = Iter<'a>;
|
||||||
|
#[inline]
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
Iter {
|
||||||
|
iter: self.map.iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over a serde_json::Map's entries.
|
||||||
|
pub struct Iter<'a> {
|
||||||
|
iter: IterImpl<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type IterImpl<'a> = btree_map::Iter<'a, String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type IterImpl<'a> = indexmap::map::Iter<'a, String, Value>;
|
||||||
|
|
||||||
|
delegate_iterator!((Iter<'a>) => (&'a String, &'a Value));
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a mut Map<String, Value> {
|
||||||
|
type Item = (&'a String, &'a mut Value);
|
||||||
|
type IntoIter = IterMut<'a>;
|
||||||
|
#[inline]
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
IterMut {
|
||||||
|
iter: self.map.iter_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A mutable iterator over a serde_json::Map's entries.
|
||||||
|
pub struct IterMut<'a> {
|
||||||
|
iter: IterMutImpl<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type IterMutImpl<'a> = btree_map::IterMut<'a, String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type IterMutImpl<'a> = indexmap::map::IterMut<'a, String, Value>;
|
||||||
|
|
||||||
|
delegate_iterator!((IterMut<'a>) => (&'a String, &'a mut Value));
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl IntoIterator for Map<String, Value> {
|
||||||
|
type Item = (String, Value);
|
||||||
|
type IntoIter = IntoIter;
|
||||||
|
#[inline]
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
IntoIter {
|
||||||
|
iter: self.map.into_iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An owning iterator over a serde_json::Map's entries.
|
||||||
|
pub struct IntoIter {
|
||||||
|
iter: IntoIterImpl,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type IntoIterImpl = btree_map::IntoIter<String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type IntoIterImpl = indexmap::map::IntoIter<String, Value>;
|
||||||
|
|
||||||
|
delegate_iterator!((IntoIter) => (String, Value));
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// An iterator over a serde_json::Map's keys.
|
||||||
|
pub struct Keys<'a> {
|
||||||
|
iter: KeysImpl<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type KeysImpl<'a> = btree_map::Keys<'a, String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type KeysImpl<'a> = indexmap::map::Keys<'a, String, Value>;
|
||||||
|
|
||||||
|
delegate_iterator!((Keys<'a>) => &'a String);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// An iterator over a serde_json::Map's values.
|
||||||
|
pub struct Values<'a> {
|
||||||
|
iter: ValuesImpl<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type ValuesImpl<'a> = btree_map::Values<'a, String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type ValuesImpl<'a> = indexmap::map::Values<'a, String, Value>;
|
||||||
|
|
||||||
|
delegate_iterator!((Values<'a>) => &'a Value);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// A mutable iterator over a serde_json::Map's values.
|
||||||
|
pub struct ValuesMut<'a> {
|
||||||
|
iter: ValuesMutImpl<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "preserve_order"))]
|
||||||
|
type ValuesMutImpl<'a> = btree_map::ValuesMut<'a, String, Value>;
|
||||||
|
#[cfg(feature = "preserve_order")]
|
||||||
|
type ValuesMutImpl<'a> = indexmap::map::ValuesMut<'a, String, Value>;
|
||||||
|
|
||||||
|
delegate_iterator!((ValuesMut<'a>) => &'a mut Value);
|
770
third_party/rust/serde_json/src/number.rs
vendored
Normal file
770
third_party/rust/serde_json/src/number.rs
vendored
Normal file
@ -0,0 +1,770 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use error::Error;
|
||||||
|
use serde::de::{self, Unexpected, Visitor};
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use std::fmt::{self, Debug, Display};
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
use ryu;
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
use itoa;
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
use serde::de::{IntoDeserializer, MapAccess};
|
||||||
|
|
||||||
|
use de::ParserNumber;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
use error::ErrorCode;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
/// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const SERDE_STRUCT_FIELD_NAME: &'static str = "$__serde_private_number";
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
/// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const SERDE_STRUCT_NAME: &'static str = "$__serde_private_Number";
|
||||||
|
|
||||||
|
/// Represents a JSON number, whether integer or floating point.
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct Number {
|
||||||
|
n: N,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
enum N {
|
||||||
|
PosInt(u64),
|
||||||
|
/// Always less than zero.
|
||||||
|
NegInt(i64),
|
||||||
|
/// Always finite.
|
||||||
|
Float(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
type N = String;
|
||||||
|
|
||||||
|
impl Number {
|
||||||
|
/// Returns true if the `Number` is an integer between `i64::MIN` and
|
||||||
|
/// `i64::MAX`.
|
||||||
|
///
|
||||||
|
/// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to
|
||||||
|
/// return the integer value.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let big = i64::max_value() as u64 + 10;
|
||||||
|
/// let v = json!({ "a": 64, "b": big, "c": 256.0 });
|
||||||
|
///
|
||||||
|
/// assert!(v["a"].is_i64());
|
||||||
|
///
|
||||||
|
/// // Greater than i64::MAX.
|
||||||
|
/// assert!(!v["b"].is_i64());
|
||||||
|
///
|
||||||
|
/// // Numbers with a decimal point are not considered integers.
|
||||||
|
/// assert!(!v["c"].is_i64());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn is_i64(&self) -> bool {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(v) => v <= i64::max_value() as u64,
|
||||||
|
N::NegInt(_) => true,
|
||||||
|
N::Float(_) => false,
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
self.as_i64().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the `Number` is an integer between zero and `u64::MAX`.
|
||||||
|
///
|
||||||
|
/// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to
|
||||||
|
/// return the integer value.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let v = json!({ "a": 64, "b": -64, "c": 256.0 });
|
||||||
|
///
|
||||||
|
/// assert!(v["a"].is_u64());
|
||||||
|
///
|
||||||
|
/// // Negative integer.
|
||||||
|
/// assert!(!v["b"].is_u64());
|
||||||
|
///
|
||||||
|
/// // Numbers with a decimal point are not considered integers.
|
||||||
|
/// assert!(!v["c"].is_u64());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn is_u64(&self) -> bool {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(_) => true,
|
||||||
|
N::NegInt(_) | N::Float(_) => false,
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
self.as_u64().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the `Number` can be represented by f64.
|
||||||
|
///
|
||||||
|
/// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to
|
||||||
|
/// return the floating point value.
|
||||||
|
///
|
||||||
|
/// Currently this function returns true if and only if both `is_i64` and
|
||||||
|
/// `is_u64` return false but this is not a guarantee in the future.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let v = json!({ "a": 256.0, "b": 64, "c": -64 });
|
||||||
|
///
|
||||||
|
/// assert!(v["a"].is_f64());
|
||||||
|
///
|
||||||
|
/// // Integers.
|
||||||
|
/// assert!(!v["b"].is_f64());
|
||||||
|
/// assert!(!v["c"].is_f64());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn is_f64(&self) -> bool {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
match self.n {
|
||||||
|
N::Float(_) => true,
|
||||||
|
N::PosInt(_) | N::NegInt(_) => false,
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
{
|
||||||
|
for c in self.n.chars() {
|
||||||
|
if c == '.' || c == 'e' || c == 'E' {
|
||||||
|
return self.n.parse::<f64>().ok().map_or(false, |f| f.is_finite());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the `Number` is an integer, represent it as i64 if possible. Returns
|
||||||
|
/// None otherwise.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let big = i64::max_value() as u64 + 10;
|
||||||
|
/// let v = json!({ "a": 64, "b": big, "c": 256.0 });
|
||||||
|
///
|
||||||
|
/// assert_eq!(v["a"].as_i64(), Some(64));
|
||||||
|
/// assert_eq!(v["b"].as_i64(), None);
|
||||||
|
/// assert_eq!(v["c"].as_i64(), None);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn as_i64(&self) -> Option<i64> {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(n) => if n <= i64::max_value() as u64 {
|
||||||
|
Some(n as i64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
N::NegInt(n) => Some(n),
|
||||||
|
N::Float(_) => None,
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
self.n.parse().ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the `Number` is an integer, represent it as u64 if possible. Returns
|
||||||
|
/// None otherwise.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let v = json!({ "a": 64, "b": -64, "c": 256.0 });
|
||||||
|
///
|
||||||
|
/// assert_eq!(v["a"].as_u64(), Some(64));
|
||||||
|
/// assert_eq!(v["b"].as_u64(), None);
|
||||||
|
/// assert_eq!(v["c"].as_u64(), None);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn as_u64(&self) -> Option<u64> {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(n) => Some(n),
|
||||||
|
N::NegInt(_) | N::Float(_) => None,
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
self.n.parse().ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the number as f64 if possible. Returns None otherwise.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let v = json!({ "a": 256.0, "b": 64, "c": -64 });
|
||||||
|
///
|
||||||
|
/// assert_eq!(v["a"].as_f64(), Some(256.0));
|
||||||
|
/// assert_eq!(v["b"].as_f64(), Some(64.0));
|
||||||
|
/// assert_eq!(v["c"].as_f64(), Some(-64.0));
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn as_f64(&self) -> Option<f64> {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(n) => Some(n as f64),
|
||||||
|
N::NegInt(n) => Some(n as f64),
|
||||||
|
N::Float(n) => Some(n),
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
self.n.parse().ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a finite `f64` to a `Number`. Infinite or NaN values are not JSON
|
||||||
|
/// numbers.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use std::f64;
|
||||||
|
/// #
|
||||||
|
/// # use serde_json::Number;
|
||||||
|
/// #
|
||||||
|
/// assert!(Number::from_f64(256.0).is_some());
|
||||||
|
///
|
||||||
|
/// assert!(Number::from_f64(f64::NAN).is_none());
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn from_f64(f: f64) -> Option<Number> {
|
||||||
|
if f.is_finite() {
|
||||||
|
let n = {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
{
|
||||||
|
N::Float(f)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
{
|
||||||
|
ryu::Buffer::new().format(f).to_owned()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(Number { n: n })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
/// Not public API. Only tests use this.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
pub fn from_string_unchecked(n: String) -> Self {
|
||||||
|
Number { n: n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Number {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(u) => Display::fmt(&u, formatter),
|
||||||
|
N::NegInt(i) => Display::fmt(&i, formatter),
|
||||||
|
N::Float(f) => Display::fmt(&f, formatter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
Display::fmt(&self.n, formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Number {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut debug = formatter.debug_tuple("Number");
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(i) => {
|
||||||
|
debug.field(&i);
|
||||||
|
}
|
||||||
|
N::NegInt(i) => {
|
||||||
|
debug.field(&i);
|
||||||
|
}
|
||||||
|
N::Float(f) => {
|
||||||
|
debug.field(&f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "Number({})", &self.n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Number {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(u) => serializer.serialize_u64(u),
|
||||||
|
N::NegInt(i) => serializer.serialize_i64(i),
|
||||||
|
N::Float(f) => serializer.serialize_f64(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
|
||||||
|
let mut s = serializer.serialize_struct(SERDE_STRUCT_NAME, 1)?;
|
||||||
|
s.serialize_field(SERDE_STRUCT_FIELD_NAME, &self.n)?;
|
||||||
|
s.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Number, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct NumberVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for NumberVisitor {
|
||||||
|
type Value = Number;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a JSON number")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_i64<E>(self, value: i64) -> Result<Number, E> {
|
||||||
|
Ok(value.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_u64<E>(self, value: u64) -> Result<Number, E> {
|
||||||
|
Ok(value.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_f64<E>(self, value: f64) -> Result<Number, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Number::from_f64(value).ok_or_else(|| de::Error::custom("not a JSON number"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
#[inline]
|
||||||
|
fn visit_map<V>(self, mut visitor: V) -> Result<Number, V::Error>
|
||||||
|
where
|
||||||
|
V: de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let value = visitor.next_key::<NumberKey>()?;
|
||||||
|
if value.is_none() {
|
||||||
|
return Err(de::Error::invalid_type(Unexpected::Map, &self));
|
||||||
|
}
|
||||||
|
let v: NumberFromString = visitor.next_value()?;
|
||||||
|
Ok(v.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(NumberVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
struct NumberKey;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
impl<'de> de::Deserialize<'de> for NumberKey {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<NumberKey, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct FieldVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for FieldVisitor {
|
||||||
|
type Value = ();
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a valid number field")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<(), E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
if s == SERDE_STRUCT_FIELD_NAME {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(de::Error::custom("expected field with custom name"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_identifier(FieldVisitor)?;
|
||||||
|
Ok(NumberKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
pub struct NumberFromString {
|
||||||
|
pub value: Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
impl<'de> de::Deserialize<'de> for NumberFromString {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<NumberFromString, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct Visitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for Visitor {
|
||||||
|
type Value = NumberFromString;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("string containing a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<NumberFromString, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let n = try!(s.parse().map_err(de::Error::custom));
|
||||||
|
Ok(NumberFromString { value: n })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
fn invalid_number() -> Error {
|
||||||
|
Error::syntax(ErrorCode::InvalidNumber, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! deserialize_any {
|
||||||
|
(@expand [$($num_string:tt)*]) => {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(u) => visitor.visit_u64(u),
|
||||||
|
N::NegInt(i) => visitor.visit_i64(i),
|
||||||
|
N::Float(f) => visitor.visit_f64(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||||
|
where V: Visitor<'de>
|
||||||
|
{
|
||||||
|
if let Some(u) = self.as_u64() {
|
||||||
|
return visitor.visit_u64(u);
|
||||||
|
} else if let Some(i) = self.as_i64() {
|
||||||
|
return visitor.visit_i64(i);
|
||||||
|
} else if let Some(f) = self.as_f64() {
|
||||||
|
if f.to_string() == self.n {
|
||||||
|
return visitor.visit_f64(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor.visit_map(NumberDeserializer {
|
||||||
|
number: Some(self.$($num_string)*),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(owned) => {
|
||||||
|
deserialize_any!(@expand [n]);
|
||||||
|
};
|
||||||
|
|
||||||
|
(ref) => {
|
||||||
|
deserialize_any!(@expand [n.clone()]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! deserialize_number {
|
||||||
|
($deserialize:ident => $visit:ident) => {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
fn $deserialize<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.deserialize_any(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
fn $deserialize<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.$visit(self.n.parse().map_err(|_| invalid_number())?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserializer<'de> for Number {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
deserialize_any!(owned);
|
||||||
|
|
||||||
|
deserialize_number!(deserialize_i8 => visit_i8);
|
||||||
|
deserialize_number!(deserialize_i16 => visit_i16);
|
||||||
|
deserialize_number!(deserialize_i32 => visit_i32);
|
||||||
|
deserialize_number!(deserialize_i64 => visit_i64);
|
||||||
|
deserialize_number!(deserialize_u8 => visit_u8);
|
||||||
|
deserialize_number!(deserialize_u16 => visit_u16);
|
||||||
|
deserialize_number!(deserialize_u32 => visit_u32);
|
||||||
|
deserialize_number!(deserialize_u64 => visit_u64);
|
||||||
|
deserialize_number!(deserialize_f32 => visit_f32);
|
||||||
|
deserialize_number!(deserialize_f64 => visit_f64);
|
||||||
|
|
||||||
|
serde_if_integer128! {
|
||||||
|
deserialize_number!(deserialize_i128 => visit_i128);
|
||||||
|
deserialize_number!(deserialize_u128 => visit_u128);
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_to_deserialize_any! {
|
||||||
|
bool char str string bytes byte_buf option unit unit_struct
|
||||||
|
newtype_struct seq tuple tuple_struct map struct enum identifier
|
||||||
|
ignored_any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, 'a> Deserializer<'de> for &'a Number {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
deserialize_any!(ref);
|
||||||
|
|
||||||
|
deserialize_number!(deserialize_i8 => visit_i8);
|
||||||
|
deserialize_number!(deserialize_i16 => visit_i16);
|
||||||
|
deserialize_number!(deserialize_i32 => visit_i32);
|
||||||
|
deserialize_number!(deserialize_i64 => visit_i64);
|
||||||
|
deserialize_number!(deserialize_u8 => visit_u8);
|
||||||
|
deserialize_number!(deserialize_u16 => visit_u16);
|
||||||
|
deserialize_number!(deserialize_u32 => visit_u32);
|
||||||
|
deserialize_number!(deserialize_u64 => visit_u64);
|
||||||
|
deserialize_number!(deserialize_f32 => visit_f32);
|
||||||
|
deserialize_number!(deserialize_f64 => visit_f64);
|
||||||
|
|
||||||
|
serde_if_integer128! {
|
||||||
|
deserialize_number!(deserialize_i128 => visit_i128);
|
||||||
|
deserialize_number!(deserialize_u128 => visit_u128);
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_to_deserialize_any! {
|
||||||
|
bool char str string bytes byte_buf option unit unit_struct
|
||||||
|
newtype_struct seq tuple tuple_struct map struct enum identifier
|
||||||
|
ignored_any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct NumberDeserializer {
|
||||||
|
pub number: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
impl<'de> MapAccess<'de> for NumberDeserializer {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
|
||||||
|
where
|
||||||
|
K: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
if self.number.is_none() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
seed.deserialize(NumberFieldDeserializer).map(Some)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
|
||||||
|
where
|
||||||
|
V: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
seed.deserialize(self.number.take().unwrap().into_deserializer())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
struct NumberFieldDeserializer;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
impl<'de> Deserializer<'de> for NumberFieldDeserializer {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_borrowed_str(SERDE_STRUCT_FIELD_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_to_deserialize_any! {
|
||||||
|
bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 char str string seq
|
||||||
|
bytes byte_buf map struct option unit newtype_struct ignored_any
|
||||||
|
unit_struct tuple_struct tuple enum identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParserNumber> for Number {
|
||||||
|
fn from(value: ParserNumber) -> Self {
|
||||||
|
let n = match value {
|
||||||
|
ParserNumber::F64(f) => {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
{
|
||||||
|
N::Float(f)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
{
|
||||||
|
f.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParserNumber::U64(u) => {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
{
|
||||||
|
N::PosInt(u)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
{
|
||||||
|
u.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParserNumber::I64(i) => {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
{
|
||||||
|
N::NegInt(i)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
{
|
||||||
|
i.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
ParserNumber::String(s) => s,
|
||||||
|
};
|
||||||
|
Number { n: n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_unsigned {
|
||||||
|
(
|
||||||
|
$($ty:ty),*
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl From<$ty> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn from(u: $ty) -> Self {
|
||||||
|
let n = {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
{ N::PosInt(u as u64) }
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
{
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
itoa::write(&mut buf, u).unwrap();
|
||||||
|
String::from_utf8(buf).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Number { n: n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_signed {
|
||||||
|
(
|
||||||
|
$($ty:ty),*
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl From<$ty> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn from(i: $ty) -> Self {
|
||||||
|
let n = {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
{
|
||||||
|
if i < 0 {
|
||||||
|
N::NegInt(i as i64)
|
||||||
|
} else {
|
||||||
|
N::PosInt(i as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
{
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
itoa::write(&mut buf, i).unwrap();
|
||||||
|
String::from_utf8(buf).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Number { n: n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_unsigned!(u8, u16, u32, u64, usize);
|
||||||
|
impl_from_signed!(i8, i16, i32, i64, isize);
|
||||||
|
|
||||||
|
impl Number {
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cold]
|
||||||
|
pub fn unexpected(&self) -> Unexpected {
|
||||||
|
match self.n {
|
||||||
|
N::PosInt(u) => Unexpected::Unsigned(u),
|
||||||
|
N::NegInt(i) => Unexpected::Signed(i),
|
||||||
|
N::Float(f) => Unexpected::Float(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
// Not public API. Should be pub(crate).
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cold]
|
||||||
|
pub fn unexpected(&self) -> Unexpected {
|
||||||
|
Unexpected::Other("number")
|
||||||
|
}
|
||||||
|
}
|
677
third_party/rust/serde_json/src/read.rs
vendored
Normal file
677
third_party/rust/serde_json/src/read.rs
vendored
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::{char, cmp, io, str};
|
||||||
|
|
||||||
|
use iter::LineColIterator;
|
||||||
|
|
||||||
|
use super::error::{Error, ErrorCode, Result};
|
||||||
|
|
||||||
|
/// Trait used by the deserializer for iterating over input. This is manually
|
||||||
|
/// "specialized" for iterating over &[u8]. Once feature(specialization) is
|
||||||
|
/// stable we can use actual specialization.
|
||||||
|
///
|
||||||
|
/// This trait is sealed and cannot be implemented for types outside of
|
||||||
|
/// `serde_json`.
|
||||||
|
pub trait Read<'de>: private::Sealed {
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn next(&mut self) -> io::Result<Option<u8>>;
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn peek(&mut self) -> io::Result<Option<u8>>;
|
||||||
|
|
||||||
|
/// Only valid after a call to peek(). Discards the peeked byte.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn discard(&mut self);
|
||||||
|
|
||||||
|
/// Position of the most recent call to next().
|
||||||
|
///
|
||||||
|
/// The most recent call was probably next() and not peek(), but this method
|
||||||
|
/// should try to return a sensible result if the most recent call was
|
||||||
|
/// actually peek() because we don't always know.
|
||||||
|
///
|
||||||
|
/// Only called in case of an error, so performance is not important.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn position(&self) -> Position;
|
||||||
|
|
||||||
|
/// Position of the most recent call to peek().
|
||||||
|
///
|
||||||
|
/// The most recent call was probably peek() and not next(), but this method
|
||||||
|
/// should try to return a sensible result if the most recent call was
|
||||||
|
/// actually next() because we don't always know.
|
||||||
|
///
|
||||||
|
/// Only called in case of an error, so performance is not important.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn peek_position(&self) -> Position;
|
||||||
|
|
||||||
|
/// Offset from the beginning of the input to the next byte that would be
|
||||||
|
/// returned by next() or peek().
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn byte_offset(&self) -> usize;
|
||||||
|
|
||||||
|
/// Assumes the previous byte was a quotation mark. Parses a JSON-escaped
|
||||||
|
/// string until the next quotation mark using the given scratch space if
|
||||||
|
/// necessary. The scratch space is initially empty.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'de, 's, str>>;
|
||||||
|
|
||||||
|
/// Assumes the previous byte was a quotation mark. Parses a JSON-escaped
|
||||||
|
/// string until the next quotation mark using the given scratch space if
|
||||||
|
/// necessary. The scratch space is initially empty.
|
||||||
|
///
|
||||||
|
/// This function returns the raw bytes in the string with escape sequences
|
||||||
|
/// expanded but without performing unicode validation.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn parse_str_raw<'s>(
|
||||||
|
&'s mut self,
|
||||||
|
scratch: &'s mut Vec<u8>,
|
||||||
|
) -> Result<Reference<'de, 's, [u8]>>;
|
||||||
|
|
||||||
|
/// Assumes the previous byte was a quotation mark. Parses a JSON-escaped
|
||||||
|
/// string until the next quotation mark but discards the data.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn ignore_str(&mut self) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Position {
|
||||||
|
pub line: usize,
|
||||||
|
pub column: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Reference<'b, 'c, T: ?Sized + 'static> {
|
||||||
|
Borrowed(&'b T),
|
||||||
|
Copied(&'c T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, 'c, T: ?Sized + 'static> Deref for Reference<'b, 'c, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match *self {
|
||||||
|
Reference::Borrowed(b) => b,
|
||||||
|
Reference::Copied(c) => c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JSON input source that reads from a std::io input stream.
|
||||||
|
pub struct IoRead<R>
|
||||||
|
where
|
||||||
|
R: io::Read,
|
||||||
|
{
|
||||||
|
iter: LineColIterator<io::Bytes<R>>,
|
||||||
|
/// Temporary storage of peeked byte.
|
||||||
|
ch: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JSON input source that reads from a slice of bytes.
|
||||||
|
//
|
||||||
|
// This is more efficient than other iterators because peek() can be read-only
|
||||||
|
// and we can compute line/col position only if an error happens.
|
||||||
|
pub struct SliceRead<'a> {
|
||||||
|
slice: &'a [u8],
|
||||||
|
/// Index of the *next* byte that will be returned by next() or peek().
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JSON input source that reads from a UTF-8 string.
|
||||||
|
//
|
||||||
|
// Able to elide UTF-8 checks by assuming that the input is valid UTF-8.
|
||||||
|
pub struct StrRead<'a> {
|
||||||
|
delegate: SliceRead<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent users from implementing the Read trait.
|
||||||
|
mod private {
|
||||||
|
pub trait Sealed {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<R> IoRead<R>
|
||||||
|
where
|
||||||
|
R: io::Read,
|
||||||
|
{
|
||||||
|
/// Create a JSON input source to read from a std::io input stream.
|
||||||
|
pub fn new(reader: R) -> Self {
|
||||||
|
IoRead {
|
||||||
|
iter: LineColIterator::new(reader.bytes()),
|
||||||
|
ch: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> private::Sealed for IoRead<R> where R: io::Read {}
|
||||||
|
|
||||||
|
impl<R> IoRead<R>
|
||||||
|
where
|
||||||
|
R: io::Read,
|
||||||
|
{
|
||||||
|
fn parse_str_bytes<'s, T, F>(
|
||||||
|
&'s mut self,
|
||||||
|
scratch: &'s mut Vec<u8>,
|
||||||
|
validate: bool,
|
||||||
|
result: F,
|
||||||
|
) -> Result<T>
|
||||||
|
where
|
||||||
|
T: 's,
|
||||||
|
F: FnOnce(&'s Self, &'s [u8]) -> Result<T>,
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
let ch = try!(next_or_eof(self));
|
||||||
|
if !ESCAPE[ch as usize] {
|
||||||
|
scratch.push(ch);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match ch {
|
||||||
|
b'"' => {
|
||||||
|
return result(self, scratch);
|
||||||
|
}
|
||||||
|
b'\\' => {
|
||||||
|
try!(parse_escape(self, scratch));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if validate {
|
||||||
|
return error(self, ErrorCode::ControlCharacterWhileParsingString);
|
||||||
|
}
|
||||||
|
scratch.push(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, R> Read<'de> for IoRead<R>
|
||||||
|
where
|
||||||
|
R: io::Read,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> io::Result<Option<u8>> {
|
||||||
|
match self.ch.take() {
|
||||||
|
Some(ch) => Ok(Some(ch)),
|
||||||
|
None => match self.iter.next() {
|
||||||
|
Some(Err(err)) => Err(err),
|
||||||
|
Some(Ok(ch)) => Ok(Some(ch)),
|
||||||
|
None => Ok(None),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn peek(&mut self) -> io::Result<Option<u8>> {
|
||||||
|
match self.ch {
|
||||||
|
Some(ch) => Ok(Some(ch)),
|
||||||
|
None => match self.iter.next() {
|
||||||
|
Some(Err(err)) => Err(err),
|
||||||
|
Some(Ok(ch)) => {
|
||||||
|
self.ch = Some(ch);
|
||||||
|
Ok(self.ch)
|
||||||
|
}
|
||||||
|
None => Ok(None),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn discard(&mut self) {
|
||||||
|
self.ch = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self) -> Position {
|
||||||
|
Position {
|
||||||
|
line: self.iter.line(),
|
||||||
|
column: self.iter.col(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_position(&self) -> Position {
|
||||||
|
// The LineColIterator updates its position during peek() so it has the
|
||||||
|
// right one here.
|
||||||
|
self.position()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn byte_offset(&self) -> usize {
|
||||||
|
match self.ch {
|
||||||
|
Some(_) => self.iter.byte_offset() - 1,
|
||||||
|
None => self.iter.byte_offset(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'de, 's, str>> {
|
||||||
|
self.parse_str_bytes(scratch, true, as_str)
|
||||||
|
.map(Reference::Copied)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_str_raw<'s>(
|
||||||
|
&'s mut self,
|
||||||
|
scratch: &'s mut Vec<u8>,
|
||||||
|
) -> Result<Reference<'de, 's, [u8]>> {
|
||||||
|
self.parse_str_bytes(scratch, false, |_, bytes| Ok(bytes))
|
||||||
|
.map(Reference::Copied)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ignore_str(&mut self) -> Result<()> {
|
||||||
|
loop {
|
||||||
|
let ch = try!(next_or_eof(self));
|
||||||
|
if !ESCAPE[ch as usize] {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match ch {
|
||||||
|
b'"' => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
b'\\' => {
|
||||||
|
try!(ignore_escape(self));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return error(self, ErrorCode::ControlCharacterWhileParsingString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<'a> SliceRead<'a> {
|
||||||
|
/// Create a JSON input source to read from a slice of bytes.
|
||||||
|
pub fn new(slice: &'a [u8]) -> Self {
|
||||||
|
SliceRead {
|
||||||
|
slice: slice,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position_of_index(&self, i: usize) -> Position {
|
||||||
|
let mut position = Position { line: 1, column: 0 };
|
||||||
|
for ch in &self.slice[..i] {
|
||||||
|
match *ch {
|
||||||
|
b'\n' => {
|
||||||
|
position.line += 1;
|
||||||
|
position.column = 0;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
position.column += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
position
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The big optimization here over IoRead is that if the string contains no
|
||||||
|
/// backslash escape sequences, the returned &str is a slice of the raw JSON
|
||||||
|
/// data so we avoid copying into the scratch space.
|
||||||
|
fn parse_str_bytes<'s, T: ?Sized, F>(
|
||||||
|
&'s mut self,
|
||||||
|
scratch: &'s mut Vec<u8>,
|
||||||
|
validate: bool,
|
||||||
|
result: F,
|
||||||
|
) -> Result<Reference<'a, 's, T>>
|
||||||
|
where
|
||||||
|
T: 's,
|
||||||
|
F: for<'f> FnOnce(&'s Self, &'f [u8]) -> Result<&'f T>,
|
||||||
|
{
|
||||||
|
// Index of the first byte not yet copied into the scratch space.
|
||||||
|
let mut start = self.index;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
while self.index < self.slice.len() && !ESCAPE[self.slice[self.index] as usize] {
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
if self.index == self.slice.len() {
|
||||||
|
return error(self, ErrorCode::EofWhileParsingString);
|
||||||
|
}
|
||||||
|
match self.slice[self.index] {
|
||||||
|
b'"' => {
|
||||||
|
if scratch.is_empty() {
|
||||||
|
// Fast path: return a slice of the raw JSON without any
|
||||||
|
// copying.
|
||||||
|
let borrowed = &self.slice[start..self.index];
|
||||||
|
self.index += 1;
|
||||||
|
return result(self, borrowed).map(Reference::Borrowed);
|
||||||
|
} else {
|
||||||
|
scratch.extend_from_slice(&self.slice[start..self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
return result(self, scratch).map(Reference::Copied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b'\\' => {
|
||||||
|
scratch.extend_from_slice(&self.slice[start..self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
try!(parse_escape(self, scratch));
|
||||||
|
start = self.index;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if validate {
|
||||||
|
return error(self, ErrorCode::ControlCharacterWhileParsingString);
|
||||||
|
}
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> private::Sealed for SliceRead<'a> {}
|
||||||
|
|
||||||
|
impl<'a> Read<'a> for SliceRead<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> io::Result<Option<u8>> {
|
||||||
|
// `Ok(self.slice.get(self.index).map(|ch| { self.index += 1; *ch }))`
|
||||||
|
// is about 10% slower.
|
||||||
|
Ok(if self.index < self.slice.len() {
|
||||||
|
let ch = self.slice[self.index];
|
||||||
|
self.index += 1;
|
||||||
|
Some(ch)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn peek(&mut self) -> io::Result<Option<u8>> {
|
||||||
|
// `Ok(self.slice.get(self.index).map(|ch| *ch))` is about 10% slower
|
||||||
|
// for some reason.
|
||||||
|
Ok(if self.index < self.slice.len() {
|
||||||
|
Some(self.slice[self.index])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn discard(&mut self) {
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self) -> Position {
|
||||||
|
self.position_of_index(self.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_position(&self) -> Position {
|
||||||
|
// Cap it at slice.len() just in case the most recent call was next()
|
||||||
|
// and it returned the last byte.
|
||||||
|
self.position_of_index(cmp::min(self.slice.len(), self.index + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn byte_offset(&self) -> usize {
|
||||||
|
self.index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'a, 's, str>> {
|
||||||
|
self.parse_str_bytes(scratch, true, as_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_str_raw<'s>(
|
||||||
|
&'s mut self,
|
||||||
|
scratch: &'s mut Vec<u8>,
|
||||||
|
) -> Result<Reference<'a, 's, [u8]>> {
|
||||||
|
self.parse_str_bytes(scratch, false, |_, bytes| Ok(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ignore_str(&mut self) -> Result<()> {
|
||||||
|
loop {
|
||||||
|
while self.index < self.slice.len() && !ESCAPE[self.slice[self.index] as usize] {
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
if self.index == self.slice.len() {
|
||||||
|
return error(self, ErrorCode::EofWhileParsingString);
|
||||||
|
}
|
||||||
|
match self.slice[self.index] {
|
||||||
|
b'"' => {
|
||||||
|
self.index += 1;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
b'\\' => {
|
||||||
|
self.index += 1;
|
||||||
|
try!(ignore_escape(self));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return error(self, ErrorCode::ControlCharacterWhileParsingString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<'a> StrRead<'a> {
|
||||||
|
/// Create a JSON input source to read from a UTF-8 string.
|
||||||
|
pub fn new(s: &'a str) -> Self {
|
||||||
|
StrRead {
|
||||||
|
delegate: SliceRead::new(s.as_bytes()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> private::Sealed for StrRead<'a> {}
|
||||||
|
|
||||||
|
impl<'a> Read<'a> for StrRead<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> io::Result<Option<u8>> {
|
||||||
|
self.delegate.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn peek(&mut self) -> io::Result<Option<u8>> {
|
||||||
|
self.delegate.peek()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn discard(&mut self) {
|
||||||
|
self.delegate.discard();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self) -> Position {
|
||||||
|
self.delegate.position()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_position(&self) -> Position {
|
||||||
|
self.delegate.peek_position()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn byte_offset(&self) -> usize {
|
||||||
|
self.delegate.byte_offset()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'a, 's, str>> {
|
||||||
|
self.delegate.parse_str_bytes(scratch, true, |_, bytes| {
|
||||||
|
// The input is assumed to be valid UTF-8 and the \u-escapes are
|
||||||
|
// checked along the way, so don't need to check here.
|
||||||
|
Ok(unsafe { str::from_utf8_unchecked(bytes) })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_str_raw<'s>(
|
||||||
|
&'s mut self,
|
||||||
|
scratch: &'s mut Vec<u8>,
|
||||||
|
) -> Result<Reference<'a, 's, [u8]>> {
|
||||||
|
self.delegate.parse_str_raw(scratch)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ignore_str(&mut self) -> Result<()> {
|
||||||
|
self.delegate.ignore_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const CT: bool = true; // control character \x00...\x1F
|
||||||
|
const QU: bool = true; // quote \x22
|
||||||
|
const BS: bool = true; // backslash \x5C
|
||||||
|
const O: bool = false; // allow unescaped
|
||||||
|
|
||||||
|
// Lookup table of bytes that must be escaped. A value of true at index i means
|
||||||
|
// that byte i requires an escape sequence in the input.
|
||||||
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
static ESCAPE: [bool; 256] = [
|
||||||
|
// 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 0
|
||||||
|
CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 1
|
||||||
|
O, O, QU, O, O, O, O, O, O, O, O, O, O, O, O, O, // 2
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // 3
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // 4
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, BS, O, O, O, // 5
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // 6
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // 7
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // 8
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // 9
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // A
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // B
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // C
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // D
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // E
|
||||||
|
O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, // F
|
||||||
|
];
|
||||||
|
|
||||||
|
fn next_or_eof<'de, R: ?Sized + Read<'de>>(read: &mut R) -> Result<u8> {
|
||||||
|
match try!(read.next().map_err(Error::io)) {
|
||||||
|
Some(b) => Ok(b),
|
||||||
|
None => error(read, ErrorCode::EofWhileParsingString),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error<'de, R: ?Sized + Read<'de>, T>(read: &R, reason: ErrorCode) -> Result<T> {
|
||||||
|
let position = read.position();
|
||||||
|
Err(Error::syntax(reason, position.line, position.column))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_str<'de, 's, R: Read<'de>>(read: &R, slice: &'s [u8]) -> Result<&'s str> {
|
||||||
|
str::from_utf8(slice).or_else(|_| error(read, ErrorCode::InvalidUnicodeCodePoint))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a JSON escape sequence and appends it into the scratch space. Assumes
|
||||||
|
/// the previous byte read was a backslash.
|
||||||
|
fn parse_escape<'de, R: Read<'de>>(read: &mut R, scratch: &mut Vec<u8>) -> Result<()> {
|
||||||
|
let ch = try!(next_or_eof(read));
|
||||||
|
|
||||||
|
match ch {
|
||||||
|
b'"' => scratch.push(b'"'),
|
||||||
|
b'\\' => scratch.push(b'\\'),
|
||||||
|
b'/' => scratch.push(b'/'),
|
||||||
|
b'b' => scratch.push(b'\x08'),
|
||||||
|
b'f' => scratch.push(b'\x0c'),
|
||||||
|
b'n' => scratch.push(b'\n'),
|
||||||
|
b'r' => scratch.push(b'\r'),
|
||||||
|
b't' => scratch.push(b'\t'),
|
||||||
|
b'u' => {
|
||||||
|
let c = match try!(decode_hex_escape(read)) {
|
||||||
|
0xDC00...0xDFFF => {
|
||||||
|
return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-BMP characters are encoded as a sequence of
|
||||||
|
// two hex escapes, representing UTF-16 surrogates.
|
||||||
|
n1 @ 0xD800...0xDBFF => {
|
||||||
|
if try!(next_or_eof(read)) != b'\\' {
|
||||||
|
return error(read, ErrorCode::UnexpectedEndOfHexEscape);
|
||||||
|
}
|
||||||
|
if try!(next_or_eof(read)) != b'u' {
|
||||||
|
return error(read, ErrorCode::UnexpectedEndOfHexEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
let n2 = try!(decode_hex_escape(read));
|
||||||
|
|
||||||
|
if n2 < 0xDC00 || n2 > 0xDFFF {
|
||||||
|
return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000;
|
||||||
|
|
||||||
|
match char::from_u32(n) {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
|
return error(read, ErrorCode::InvalidUnicodeCodePoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n => match char::from_u32(n as u32) {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
|
return error(read, ErrorCode::InvalidUnicodeCodePoint);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
scratch.extend_from_slice(c.encode_utf8(&mut [0_u8; 4]).as_bytes());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return error(read, ErrorCode::InvalidEscape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a JSON escape sequence and discards the value. Assumes the previous
|
||||||
|
/// byte read was a backslash.
|
||||||
|
fn ignore_escape<'de, R: ?Sized + Read<'de>>(read: &mut R) -> Result<()> {
|
||||||
|
let ch = try!(next_or_eof(read));
|
||||||
|
|
||||||
|
match ch {
|
||||||
|
b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't' => {}
|
||||||
|
b'u' => {
|
||||||
|
let n = match try!(decode_hex_escape(read)) {
|
||||||
|
0xDC00...0xDFFF => {
|
||||||
|
return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-BMP characters are encoded as a sequence of
|
||||||
|
// two hex escapes, representing UTF-16 surrogates.
|
||||||
|
n1 @ 0xD800...0xDBFF => {
|
||||||
|
if try!(next_or_eof(read)) != b'\\' {
|
||||||
|
return error(read, ErrorCode::UnexpectedEndOfHexEscape);
|
||||||
|
}
|
||||||
|
if try!(next_or_eof(read)) != b'u' {
|
||||||
|
return error(read, ErrorCode::UnexpectedEndOfHexEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
let n2 = try!(decode_hex_escape(read));
|
||||||
|
|
||||||
|
if n2 < 0xDC00 || n2 > 0xDFFF {
|
||||||
|
return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
(((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000
|
||||||
|
}
|
||||||
|
|
||||||
|
n => n as u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
if char::from_u32(n).is_none() {
|
||||||
|
return error(read, ErrorCode::InvalidUnicodeCodePoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return error(read, ErrorCode::InvalidEscape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_hex_escape<'de, R: ?Sized + Read<'de>>(read: &mut R) -> Result<u16> {
|
||||||
|
let mut n = 0;
|
||||||
|
for _ in 0..4 {
|
||||||
|
n = match try!(next_or_eof(read)) {
|
||||||
|
c @ b'0'...b'9' => n * 16_u16 + ((c as u16) - (b'0' as u16)),
|
||||||
|
b'a' | b'A' => n * 16_u16 + 10_u16,
|
||||||
|
b'b' | b'B' => n * 16_u16 + 11_u16,
|
||||||
|
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 error(read, ErrorCode::InvalidEscape);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(n)
|
||||||
|
}
|
2096
third_party/rust/serde_json/src/ser.rs
vendored
Normal file
2096
third_party/rust/serde_json/src/ser.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1376
third_party/rust/serde_json/src/value/de.rs
vendored
Normal file
1376
third_party/rust/serde_json/src/value/de.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
266
third_party/rust/serde_json/src/value/from.rs
vendored
Normal file
266
third_party/rust/serde_json/src/value/from.rs
vendored
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use super::Value;
|
||||||
|
use map::Map;
|
||||||
|
use number::Number;
|
||||||
|
|
||||||
|
macro_rules! from_integer {
|
||||||
|
($($ty:ident)*) => {
|
||||||
|
$(
|
||||||
|
impl From<$ty> for Value {
|
||||||
|
fn from(n: $ty) -> Self {
|
||||||
|
Value::Number(n.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
from_integer! {
|
||||||
|
i8 i16 i32 i64 isize
|
||||||
|
u8 u16 u32 u64 usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f32> for Value {
|
||||||
|
/// Convert 32-bit floating point number to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let f: f32 = 13.37;
|
||||||
|
/// let x: Value = f.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: f32) -> Self {
|
||||||
|
From::from(f as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for Value {
|
||||||
|
/// Convert 64-bit floating point number to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let f: f64 = 13.37;
|
||||||
|
/// let x: Value = f.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: f64) -> Self {
|
||||||
|
Number::from_f64(f).map_or(Value::Null, Value::Number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for Value {
|
||||||
|
/// Convert boolean to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let b = false;
|
||||||
|
/// let x: Value = b.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: bool) -> Self {
|
||||||
|
Value::Bool(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Value {
|
||||||
|
/// Convert `String` to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let s: String = "lorem".to_string();
|
||||||
|
/// let x: Value = s.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: String) -> Self {
|
||||||
|
Value::String(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for Value {
|
||||||
|
/// Convert string slice to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let s: &str = "lorem";
|
||||||
|
/// let x: Value = s.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: &str) -> Self {
|
||||||
|
Value::String(f.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Cow<'a, str>> for Value {
|
||||||
|
/// Convert copy-on-write string to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
/// use std::borrow::Cow;
|
||||||
|
///
|
||||||
|
/// let s: Cow<str> = Cow::Borrowed("lorem");
|
||||||
|
/// let x: Value = s.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
/// use std::borrow::Cow;
|
||||||
|
///
|
||||||
|
/// let s: Cow<str> = Cow::Owned("lorem".to_string());
|
||||||
|
/// let x: Value = s.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: Cow<'a, str>) -> Self {
|
||||||
|
Value::String(f.into_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Map<String, Value>> for Value {
|
||||||
|
/// Convert map (with string keys) to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::{Map, Value};
|
||||||
|
///
|
||||||
|
/// let mut m = Map::new();
|
||||||
|
/// m.insert("Lorem".to_string(), "ipsum".into());
|
||||||
|
/// let x: Value = m.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: Map<String, Value>) -> Self {
|
||||||
|
Value::Object(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Into<Value>> From<Vec<T>> for Value {
|
||||||
|
/// Convert a `Vec` to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let v = vec!["lorem", "ipsum", "dolor"];
|
||||||
|
/// let x: Value = v.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: Vec<T>) -> Self {
|
||||||
|
Value::Array(f.into_iter().map(Into::into).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
|
||||||
|
/// Convert a slice to `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let v: &[&str] = &["lorem", "ipsum", "dolor"];
|
||||||
|
/// let x: Value = v.into();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(f: &'a [T]) -> Self {
|
||||||
|
Value::Array(f.into_iter().cloned().map(Into::into).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Into<Value>> ::std::iter::FromIterator<T> for Value {
|
||||||
|
/// Convert an iteratable type to a `Value`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let v = std::iter::repeat(42).take(5);
|
||||||
|
/// let x: Value = v.collect();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"];
|
||||||
|
/// let x: Value = v.into_iter().collect();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use std::iter::FromIterator;
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||||
|
Value::Array(iter.into_iter().map(Into::into).collect())
|
||||||
|
}
|
||||||
|
}
|
274
third_party/rust/serde_json/src/value/index.rs
vendored
Normal file
274
third_party/rust/serde_json/src/value/index.rs
vendored
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
use super::Value;
|
||||||
|
use map::Map;
|
||||||
|
|
||||||
|
/// A type that can be used to index into a `serde_json::Value`.
|
||||||
|
///
|
||||||
|
/// The [`get`] and [`get_mut`] methods of `Value` accept any type that
|
||||||
|
/// implements `Index`, as does the [square-bracket indexing operator]. This
|
||||||
|
/// trait is implemented for strings which are used as the index into a JSON
|
||||||
|
/// map, and for `usize` which is used as the index into a JSON array.
|
||||||
|
///
|
||||||
|
/// [`get`]: ../enum.Value.html#method.get
|
||||||
|
/// [`get_mut`]: ../enum.Value.html#method.get_mut
|
||||||
|
/// [square-bracket indexing operator]: ../enum.Value.html#impl-Index%3CI%3E
|
||||||
|
///
|
||||||
|
/// This trait is sealed and cannot be implemented for types outside of
|
||||||
|
/// `serde_json`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let data = json!({ "inner": [1, 2, 3] });
|
||||||
|
///
|
||||||
|
/// // Data is a JSON map so it can be indexed with a string.
|
||||||
|
/// let inner = &data["inner"];
|
||||||
|
///
|
||||||
|
/// // Inner is a JSON array so it can be indexed with an integer.
|
||||||
|
/// let first = &inner[0];
|
||||||
|
///
|
||||||
|
/// assert_eq!(first, 1);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub trait Index: private::Sealed {
|
||||||
|
/// Return None if the key is not already in the array or object.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>;
|
||||||
|
|
||||||
|
/// Return None if the key is not already in the array or object.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
|
||||||
|
|
||||||
|
/// Panic if array index out of bounds. If key is not already in the object,
|
||||||
|
/// insert it with a value of null. Panic if Value is a type that cannot be
|
||||||
|
/// indexed into, except if Value is null then it can be treated as an empty
|
||||||
|
/// object.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index for usize {
|
||||||
|
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
|
||||||
|
match *v {
|
||||||
|
Value::Array(ref vec) => vec.get(*self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
|
||||||
|
match *v {
|
||||||
|
Value::Array(ref mut vec) => vec.get_mut(*self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
|
||||||
|
match *v {
|
||||||
|
Value::Array(ref mut vec) => {
|
||||||
|
let len = vec.len();
|
||||||
|
vec.get_mut(*self).unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"cannot access index {} of JSON array of length {}",
|
||||||
|
self, len
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => panic!("cannot access index {} of JSON {}", self, Type(v)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index for str {
|
||||||
|
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
|
||||||
|
match *v {
|
||||||
|
Value::Object(ref map) => map.get(self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
|
||||||
|
match *v {
|
||||||
|
Value::Object(ref mut map) => map.get_mut(self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
|
||||||
|
if let Value::Null = *v {
|
||||||
|
*v = Value::Object(Map::new());
|
||||||
|
}
|
||||||
|
match *v {
|
||||||
|
Value::Object(ref mut map) => map.entry(self.to_owned()).or_insert(Value::Null),
|
||||||
|
_ => panic!("cannot access key {:?} in JSON {}", self, Type(v)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index for String {
|
||||||
|
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
|
||||||
|
self[..].index_into(v)
|
||||||
|
}
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
|
||||||
|
self[..].index_into_mut(v)
|
||||||
|
}
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
|
||||||
|
self[..].index_or_insert(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> Index for &'a T
|
||||||
|
where
|
||||||
|
T: Index,
|
||||||
|
{
|
||||||
|
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
|
||||||
|
(**self).index_into(v)
|
||||||
|
}
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
|
||||||
|
(**self).index_into_mut(v)
|
||||||
|
}
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
|
||||||
|
(**self).index_or_insert(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent users from implementing the Index trait.
|
||||||
|
mod private {
|
||||||
|
pub trait Sealed {}
|
||||||
|
impl Sealed for usize {}
|
||||||
|
impl Sealed for str {}
|
||||||
|
impl Sealed for String {}
|
||||||
|
impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used in panic messages.
|
||||||
|
struct Type<'a>(&'a Value);
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for Type<'a> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self.0 {
|
||||||
|
Value::Null => formatter.write_str("null"),
|
||||||
|
Value::Bool(_) => formatter.write_str("boolean"),
|
||||||
|
Value::Number(_) => formatter.write_str("number"),
|
||||||
|
Value::String(_) => formatter.write_str("string"),
|
||||||
|
Value::Array(_) => formatter.write_str("array"),
|
||||||
|
Value::Object(_) => formatter.write_str("object"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The usual semantics of Index is to panic on invalid indexing.
|
||||||
|
//
|
||||||
|
// That said, the usual semantics are for things like Vec and BTreeMap which
|
||||||
|
// have different use cases than Value. If you are working with a Vec, you know
|
||||||
|
// that you are working with a Vec and you can get the len of the Vec and make
|
||||||
|
// sure your indices are within bounds. The Value use cases are more
|
||||||
|
// loosey-goosey. You got some JSON from an endpoint and you want to pull values
|
||||||
|
// out of it. Outside of this Index impl, you already have the option of using
|
||||||
|
// value.as_array() and working with the Vec directly, or matching on
|
||||||
|
// Value::Array and getting the Vec directly. The Index impl means you can skip
|
||||||
|
// that and index directly into the thing using a concise syntax. You don't have
|
||||||
|
// to check the type, you don't have to check the len, it is all about what you
|
||||||
|
// expect the Value to look like.
|
||||||
|
//
|
||||||
|
// Basically the use cases that would be well served by panicking here are
|
||||||
|
// better served by using one of the other approaches: get and get_mut,
|
||||||
|
// as_array, or match. The value of this impl is that it adds a way of working
|
||||||
|
// with Value that is not well served by the existing approaches: concise and
|
||||||
|
// careless and sometimes that is exactly what you want.
|
||||||
|
impl<I> ops::Index<I> for Value
|
||||||
|
where
|
||||||
|
I: Index,
|
||||||
|
{
|
||||||
|
type Output = Value;
|
||||||
|
|
||||||
|
/// Index into a `serde_json::Value` using the syntax `value[0]` or
|
||||||
|
/// `value["k"]`.
|
||||||
|
///
|
||||||
|
/// Returns `Value::Null` if the type of `self` does not match the type of
|
||||||
|
/// the index, for example if the index is a string and `self` is an array
|
||||||
|
/// or a number. Also returns `Value::Null` if the given key does not exist
|
||||||
|
/// in the map or the given index is not within the bounds of the array.
|
||||||
|
///
|
||||||
|
/// For retrieving deeply nested values, you should have a look at the
|
||||||
|
/// `Value::pointer` method.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let data = json!({
|
||||||
|
/// "x": {
|
||||||
|
/// "y": ["z", "zz"]
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// assert_eq!(data["x"]["y"], json!(["z", "zz"]));
|
||||||
|
/// assert_eq!(data["x"]["y"][0], json!("z"));
|
||||||
|
///
|
||||||
|
/// assert_eq!(data["a"], json!(null)); // returns null for undefined values
|
||||||
|
/// assert_eq!(data["a"]["b"], json!(null)); // does not panic
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn index(&self, index: I) -> &Value {
|
||||||
|
static NULL: Value = Value::Null;
|
||||||
|
index.index_into(self).unwrap_or(&NULL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> ops::IndexMut<I> for Value
|
||||||
|
where
|
||||||
|
I: Index,
|
||||||
|
{
|
||||||
|
/// Write into a `serde_json::Value` using the syntax `value[0] = ...` or
|
||||||
|
/// `value["k"] = ...`.
|
||||||
|
///
|
||||||
|
/// If the index is a number, the value must be an array of length bigger
|
||||||
|
/// than the index. Indexing into a value that is not an array or an array
|
||||||
|
/// that is too small will panic.
|
||||||
|
///
|
||||||
|
/// If the index is a string, the value must be an object or null which is
|
||||||
|
/// treated like an empty object. If the key is not already present in the
|
||||||
|
/// object, it will be inserted with a value of null. Indexing into a value
|
||||||
|
/// that is neither an object nor null will panic.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate serde_json;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// let mut data = json!({ "x": 0 });
|
||||||
|
///
|
||||||
|
/// // replace an existing key
|
||||||
|
/// data["x"] = json!(1);
|
||||||
|
///
|
||||||
|
/// // insert a new key
|
||||||
|
/// data["y"] = json!([false, false, false]);
|
||||||
|
///
|
||||||
|
/// // replace an array value
|
||||||
|
/// data["y"][0] = json!(true);
|
||||||
|
///
|
||||||
|
/// // inserted a deeply nested key
|
||||||
|
/// data["a"]["b"]["c"]["d"] = json!(true);
|
||||||
|
///
|
||||||
|
/// println!("{}", data);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn index_mut(&mut self, index: I) -> &mut Value {
|
||||||
|
index.index_or_insert(self)
|
||||||
|
}
|
||||||
|
}
|
1126
third_party/rust/serde_json/src/value/mod.rs
vendored
Normal file
1126
third_party/rust/serde_json/src/value/mod.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
102
third_party/rust/serde_json/src/value/partial_eq.rs
vendored
Normal file
102
third_party/rust/serde_json/src/value/partial_eq.rs
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use super::Value;
|
||||||
|
|
||||||
|
fn eq_i64(value: &Value, other: i64) -> bool {
|
||||||
|
value.as_i64().map_or(false, |i| i == other)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eq_u64(value: &Value, other: u64) -> bool {
|
||||||
|
value.as_u64().map_or(false, |i| i == other)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eq_f64(value: &Value, other: f64) -> bool {
|
||||||
|
value.as_f64().map_or(false, |i| i == other)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eq_bool(value: &Value, other: bool) -> bool {
|
||||||
|
value.as_bool().map_or(false, |i| i == other)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eq_str(value: &Value, other: &str) -> bool {
|
||||||
|
value.as_str().map_or(false, |i| i == other)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<str> for Value {
|
||||||
|
fn eq(&self, other: &str) -> bool {
|
||||||
|
eq_str(self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq<&'a str> for Value {
|
||||||
|
fn eq(&self, other: &&str) -> bool {
|
||||||
|
eq_str(self, *other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Value> for str {
|
||||||
|
fn eq(&self, other: &Value) -> bool {
|
||||||
|
eq_str(other, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq<Value> for &'a str {
|
||||||
|
fn eq(&self, other: &Value) -> bool {
|
||||||
|
eq_str(other, *self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<String> for Value {
|
||||||
|
fn eq(&self, other: &String) -> bool {
|
||||||
|
eq_str(self, other.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Value> for String {
|
||||||
|
fn eq(&self, other: &Value) -> bool {
|
||||||
|
eq_str(other, self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! partialeq_numeric {
|
||||||
|
($($eq:ident [$($ty:ty)*])*) => {
|
||||||
|
$($(
|
||||||
|
impl PartialEq<$ty> for Value {
|
||||||
|
fn eq(&self, other: &$ty) -> bool {
|
||||||
|
$eq(self, *other as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Value> for $ty {
|
||||||
|
fn eq(&self, other: &Value) -> bool {
|
||||||
|
$eq(other, *self as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq<$ty> for &'a Value {
|
||||||
|
fn eq(&self, other: &$ty) -> bool {
|
||||||
|
$eq(*self, *other as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq<$ty> for &'a mut Value {
|
||||||
|
fn eq(&self, other: &$ty) -> bool {
|
||||||
|
$eq(*self, *other as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partialeq_numeric! {
|
||||||
|
eq_i64[i8 i16 i32 i64 isize]
|
||||||
|
eq_u64[u8 u16 u32 u64 usize]
|
||||||
|
eq_f64[f32 f64]
|
||||||
|
eq_bool[bool]
|
||||||
|
}
|
827
third_party/rust/serde_json/src/value/ser.rs
vendored
Normal file
827
third_party/rust/serde_json/src/value/ser.rs
vendored
Normal file
@ -0,0 +1,827 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use serde::ser::Impossible;
|
||||||
|
use serde::{self, Serialize};
|
||||||
|
|
||||||
|
use error::{Error, ErrorCode};
|
||||||
|
use map::Map;
|
||||||
|
use number::Number;
|
||||||
|
use value::{to_value, Value};
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
use serde::ser;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
use number::{SERDE_STRUCT_FIELD_NAME, SERDE_STRUCT_NAME};
|
||||||
|
|
||||||
|
impl Serialize for Value {
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: ::serde::Serializer,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
Value::Null => serializer.serialize_unit(),
|
||||||
|
Value::Bool(b) => serializer.serialize_bool(b),
|
||||||
|
Value::Number(ref n) => n.serialize(serializer),
|
||||||
|
Value::String(ref s) => serializer.serialize_str(s),
|
||||||
|
Value::Array(ref v) => v.serialize(serializer),
|
||||||
|
Value::Object(ref m) => {
|
||||||
|
use serde::ser::SerializeMap;
|
||||||
|
let mut map = try!(serializer.serialize_map(Some(m.len())));
|
||||||
|
for (k, v) in m {
|
||||||
|
try!(map.serialize_key(k));
|
||||||
|
try!(map.serialize_value(v));
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Serializer;
|
||||||
|
|
||||||
|
impl serde::Serializer for Serializer {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
type SerializeSeq = SerializeVec;
|
||||||
|
type SerializeTuple = SerializeVec;
|
||||||
|
type SerializeTupleStruct = SerializeVec;
|
||||||
|
type SerializeTupleVariant = SerializeTupleVariant;
|
||||||
|
type SerializeMap = SerializeMap;
|
||||||
|
type SerializeStruct = SerializeMap;
|
||||||
|
type SerializeStructVariant = SerializeStructVariant;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_bool(self, value: bool) -> Result<Value, Error> {
|
||||||
|
Ok(Value::Bool(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_i8(self, value: i8) -> Result<Value, Error> {
|
||||||
|
self.serialize_i64(value as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_i16(self, value: i16) -> Result<Value, Error> {
|
||||||
|
self.serialize_i64(value as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_i32(self, value: i32) -> Result<Value, Error> {
|
||||||
|
self.serialize_i64(value as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i64(self, value: i64) -> Result<Value, Error> {
|
||||||
|
Ok(Value::Number(value.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_u8(self, value: u8) -> Result<Value, Error> {
|
||||||
|
self.serialize_u64(value as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_u16(self, value: u16) -> Result<Value, Error> {
|
||||||
|
self.serialize_u64(value as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_u32(self, value: u32) -> Result<Value, Error> {
|
||||||
|
self.serialize_u64(value as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_u64(self, value: u64) -> Result<Value, Error> {
|
||||||
|
Ok(Value::Number(value.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_f32(self, value: f32) -> Result<Value, Error> {
|
||||||
|
self.serialize_f64(value as f64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_f64(self, value: f64) -> Result<Value, Error> {
|
||||||
|
Ok(Number::from_f64(value).map_or(Value::Null, Value::Number))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_char(self, value: char) -> Result<Value, Error> {
|
||||||
|
let mut s = String::new();
|
||||||
|
s.push(value);
|
||||||
|
self.serialize_str(&s)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_str(self, value: &str) -> Result<Value, Error> {
|
||||||
|
Ok(Value::String(value.to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bytes(self, value: &[u8]) -> Result<Value, Error> {
|
||||||
|
let vec = value.iter().map(|&b| Value::Number(b.into())).collect();
|
||||||
|
Ok(Value::Array(vec))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_unit(self) -> Result<Value, Error> {
|
||||||
|
Ok(Value::Null)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_unit_struct(self, _name: &'static str) -> Result<Value, Error> {
|
||||||
|
self.serialize_unit()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_unit_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
|
self.serialize_str(variant)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_newtype_struct<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<Value, Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_variant<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<Value, Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
let mut values = Map::new();
|
||||||
|
values.insert(String::from(variant), try!(to_value(&value)));
|
||||||
|
Ok(Value::Object(values))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_none(self) -> Result<Value, Error> {
|
||||||
|
self.serialize_unit()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Value, Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
|
||||||
|
Ok(SerializeVec {
|
||||||
|
vec: Vec::with_capacity(len.unwrap_or(0)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> {
|
||||||
|
self.serialize_seq(Some(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleStruct, Error> {
|
||||||
|
self.serialize_seq(Some(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleVariant, Error> {
|
||||||
|
Ok(SerializeTupleVariant {
|
||||||
|
name: String::from(variant),
|
||||||
|
vec: Vec::with_capacity(len),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> {
|
||||||
|
Ok(SerializeMap::Map {
|
||||||
|
map: Map::new(),
|
||||||
|
next_key: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "arbitrary_precision"))]
|
||||||
|
fn serialize_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeStruct, Error> {
|
||||||
|
self.serialize_map(Some(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
fn serialize_struct(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeStruct, Error> {
|
||||||
|
if name == SERDE_STRUCT_NAME {
|
||||||
|
Ok(SerializeMap::Number { out_value: None })
|
||||||
|
} else {
|
||||||
|
self.serialize_map(Some(len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeStructVariant, Error> {
|
||||||
|
Ok(SerializeStructVariant {
|
||||||
|
name: String::from(variant),
|
||||||
|
map: Map::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerializeVec {
|
||||||
|
vec: Vec<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerializeTupleVariant {
|
||||||
|
name: String,
|
||||||
|
vec: Vec<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SerializeMap {
|
||||||
|
Map {
|
||||||
|
map: Map<String, Value>,
|
||||||
|
next_key: Option<String>,
|
||||||
|
},
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
Number { out_value: Option<Value> },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerializeStructVariant {
|
||||||
|
name: String,
|
||||||
|
map: Map<String, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeSeq for SerializeVec {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.vec.push(try!(to_value(&value)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
Ok(Value::Array(self.vec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeTuple for SerializeVec {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
serde::ser::SerializeSeq::serialize_element(self, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
serde::ser::SerializeSeq::end(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeTupleStruct for SerializeVec {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
serde::ser::SerializeSeq::serialize_element(self, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
serde::ser::SerializeSeq::end(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.vec.push(try!(to_value(&value)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
let mut object = Map::new();
|
||||||
|
|
||||||
|
object.insert(self.name, Value::Array(self.vec));
|
||||||
|
|
||||||
|
Ok(Value::Object(object))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeMap for SerializeMap {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
SerializeMap::Map {
|
||||||
|
ref mut next_key, ..
|
||||||
|
} => {
|
||||||
|
*next_key = Some(try!(key.serialize(MapKeySerializer)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
SerializeMap::Number { .. } => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
SerializeMap::Map {
|
||||||
|
ref mut map,
|
||||||
|
ref mut next_key,
|
||||||
|
} => {
|
||||||
|
let key = next_key.take();
|
||||||
|
// Panic because this indicates a bug in the program rather than an
|
||||||
|
// expected failure.
|
||||||
|
let key = key.expect("serialize_value called before serialize_key");
|
||||||
|
map.insert(key, try!(to_value(&value)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
SerializeMap::Number { .. } => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
match self {
|
||||||
|
SerializeMap::Map { map, .. } => Ok(Value::Object(map)),
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
SerializeMap::Number { .. } => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MapKeySerializer;
|
||||||
|
|
||||||
|
fn key_must_be_a_string() -> Error {
|
||||||
|
Error::syntax(ErrorCode::KeyMustBeAString, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::Serializer for MapKeySerializer {
|
||||||
|
type Ok = String;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
type SerializeSeq = Impossible<String, Error>;
|
||||||
|
type SerializeTuple = Impossible<String, Error>;
|
||||||
|
type SerializeTupleStruct = Impossible<String, Error>;
|
||||||
|
type SerializeTupleVariant = Impossible<String, Error>;
|
||||||
|
type SerializeMap = Impossible<String, Error>;
|
||||||
|
type SerializeStruct = Impossible<String, Error>;
|
||||||
|
type SerializeStructVariant = Impossible<String, Error>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_unit_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(variant.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_newtype_struct<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i8(self, value: i8) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i16(self, value: i16) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i32(self, value: i32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i64(self, value: i64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok({
|
||||||
|
let mut s = String::new();
|
||||||
|
s.push(value);
|
||||||
|
s
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(value.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_variant<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_value: &T,
|
||||||
|
) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||||
|
Err(key_must_be_a_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeStruct for SerializeMap {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
SerializeMap::Map { .. } => {
|
||||||
|
try!(serde::ser::SerializeMap::serialize_key(self, key));
|
||||||
|
serde::ser::SerializeMap::serialize_value(self, value)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
SerializeMap::Number { ref mut out_value } => {
|
||||||
|
if key == SERDE_STRUCT_FIELD_NAME {
|
||||||
|
*out_value = Some(value.serialize(NumberValueEmitter)?);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
match self {
|
||||||
|
SerializeMap::Map { .. } => serde::ser::SerializeMap::end(self),
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
SerializeMap::Number { out_value, .. } => {
|
||||||
|
Ok(out_value.expect("number value was not emitted"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeStructVariant for SerializeStructVariant {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.map.insert(String::from(key), try!(to_value(&value)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
let mut object = Map::new();
|
||||||
|
|
||||||
|
object.insert(self.name, Value::Object(self.map));
|
||||||
|
|
||||||
|
Ok(Value::Object(object))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
struct NumberValueEmitter;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
fn invalid_number() -> Error {
|
||||||
|
Error::syntax(ErrorCode::InvalidNumber, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary_precision")]
|
||||||
|
impl ser::Serializer for NumberValueEmitter {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
type SerializeSeq = Impossible<Value, Error>;
|
||||||
|
type SerializeTuple = Impossible<Value, Error>;
|
||||||
|
type SerializeTupleStruct = Impossible<Value, Error>;
|
||||||
|
type SerializeTupleVariant = Impossible<Value, Error>;
|
||||||
|
type SerializeMap = Impossible<Value, Error>;
|
||||||
|
type SerializeStruct = Impossible<Value, Error>;
|
||||||
|
type SerializeStructVariant = Impossible<Value, Error>;
|
||||||
|
|
||||||
|
fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
|
||||||
|
let n = try!(value.to_owned().parse());
|
||||||
|
Ok(Value::Number(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_struct<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_value: &T,
|
||||||
|
) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_variant<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_value: &T,
|
||||||
|
) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||||
|
Err(invalid_number())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user