зеркало из https://github.com/mozilla/gecko-dev.git
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 : ca3b49695926adb5ec2ae0eb4cdfd4335a740467
This commit is contained in:
Родитель
a654712c9c
Коммит
a16730c92c
|
@ -806,6 +806,7 @@ dependencies = [
|
|||
name = "geckodriver"
|
||||
version = "0.21.0"
|
||||
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)",
|
||||
"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)",
|
||||
|
@ -815,7 +816,9 @@ dependencies = [
|
|||
"mozrunner 0.7.0",
|
||||
"mozversion 0.1.3",
|
||||
"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)",
|
||||
"webdriver 0.36.0",
|
||||
"zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1837,11 +1840,6 @@ name = "rustc-demangle"
|
|||
version = "0.1.8"
|
||||
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]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.1"
|
||||
|
@ -1850,6 +1848,11 @@ dependencies = [
|
|||
"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]]
|
||||
name = "safemem"
|
||||
version = "0.2.0"
|
||||
|
@ -1929,6 +1932,16 @@ dependencies = [
|
|||
"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]]
|
||||
name = "servo_arc"
|
||||
version = "0.1.1"
|
||||
|
@ -2414,11 +2427,15 @@ dependencies = [
|
|||
name = "webdriver"
|
||||
version = "0.36.0"
|
||||
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)",
|
||||
"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)",
|
||||
"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)",
|
||||
"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)",
|
||||
|
@ -2797,8 +2814,8 @@ dependencies = [
|
|||
"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 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 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 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"
|
||||
|
@ -2808,6 +2825,7 @@ dependencies = [
|
|||
"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_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 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"
|
||||
|
|
|
@ -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"}
|
|
@ -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
|
|
@ -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"
|
|
@ -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;
|
||||
```
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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); });
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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::*;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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"}
|
|
@ -0,0 +1,13 @@
|
|||
language: rust
|
||||
|
||||
rust:
|
||||
- nightly
|
||||
- beta
|
||||
- stable
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- rust: 1.15.0
|
||||
script:
|
||||
- cargo build
|
||||
- cargo build --features small
|
|
@ -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"
|
|
@ -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.
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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 {}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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),
|
||||
];
|
|
@ -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),
|
||||
)
|
||||
}
|
|
@ -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";
|
|
@ -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)
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)));
|
||||
};
|
||||
}
|
|
@ -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"}
|
|
@ -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"
|
|
@ -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
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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 {
|
||||
() => {};
|
||||
}
|
|
@ -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);
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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]
|
||||
}
|
|
@ -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())
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче